Print support in ScintillaNET

Topics: Developer Forum
Sep 13, 2006 at 1:51 PM
Hi,

Is there already someone working on adding print support to ScintillaNET? Otherwise, I gave it a try and have some pieces of code that I could post here (FormatRange implementation + .NET print support functions).

Michael.
Nov 9, 2006 at 10:25 PM
Hi,

I'm evaluating ScintillaNet and I need print support, so I'd be interested in seeing what you have.

Thanks,
Matt
Nov 10, 2006 at 7:13 AM
Here's the code I have (part of ScintillaControl.cs file). I wrote this code with the 5315 version of the code. It supports normal printing and print preview.

Michael.


public void PrintPreview()
{
PrintPreviewDialog dlg = new PrintPreviewDialog();
dlg.Document = CreatePrintDocument();
dlg.WindowState = FormWindowState.Maximized;
dlg.ShowDialog();
}

public void Print()
{
PrintDialog dlg = new PrintDialog();
dlg.Document = CreatePrintDocument();
if (dlg.ShowDialog() == DialogResult.OK)
dlg.Document.Print();
}

private int lastPrintPosition;
private int currentPrintPage;
protected int CurrentPrintPage
{
get { return currentPrintPage; }
}

public virtual System.Drawing.Printing.PrintDocument CreatePrintDocument()
{
System.Drawing.Printing.PrintDocument doc = new System.Drawing.Printing.PrintDocument();
doc.BeginPrint += new System.Drawing.Printing.PrintEventHandler(this.DocumentBeginPrint);
doc.EndPrint += new System.Drawing.Printing.PrintEventHandler(this.DocumentEndPrint);
doc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.DocumentPrintPage);
return doc;
}

public virtual void DocumentBeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
lastPrintPosition = 0;
currentPrintPage = 1;
}

public virtual void DocumentEndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
}

public virtual void DocumentPrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.Drawing.Printing.PrintDocument doc = (System.Drawing.Printing.PrintDocument)sender;

if (!doc.PrintController.IsPreview)
e.Graphics.TranslateTransform(-e.PageSettings.HardMarginX, -e.PageSettings.HardMarginY);
Rectangle textRect = PrintDecorate(e.MarginBounds, e.Graphics, doc);
if (!doc.PrintController.IsPreview)
textRect.Offset(-(int)e.PageSettings.HardMarginX, -(int)e.PageSettings.HardMarginY);

lastPrintPosition = FormatRange(true, lastPrintPosition, TextLength, e.Graphics, textRect);
currentPrintPage++;
e.HasMorePages = (lastPrintPosition < TextLength);
}

public virtual Rectangle PrintDecorate(Rectangle rect, Graphics graphics, System.Drawing.Printing.PrintDocument doc)
{
Rectangle textRect = rect;
int margin = 10;

textRect.Offset(margin, margin);
textRect.Width -= (2 * margin);
textRect.Height -= (2 * margin);

graphics.DrawRectangle(System.Drawing.Pens.Black, rect);
Rectangle footer = new Rectangle(rect.Left, rect.Bottom-16, rect.Width, 16);
StringFormat format = new StringFormat(StringFormat.GenericDefault);
graphics.DrawRectangle(System.Drawing.Pens.Black, footer);
footer.Offset(2, 0);
footer.Width -= 4;
format.Alignment = StringAlignment.Far;
format.LineAlignment = StringAlignment.Center;
graphics.DrawString(
"Page " + CurrentPrintPage.ToString(),
new Font("Arial", 8),
System.Drawing.Brushes.Black,
footer,
format);
format.Alignment = StringAlignment.Near;
graphics.DrawString(
doc.DocumentName,
new Font("Arial", 8),
System.Drawing.Brushes.Black,
footer,
format);
textRect.Height -= 16;

return textRect;
}

internal unsafe int FormatRange(bool bDraw, RangeToFormat pfr)
{
return (int)SendMessageDirect(2151, (IntPtr)(bDraw ? 1 : 0), (IntPtr)(&pfr));
}

public int FormatRange(bool bDraw, int start, int end, Graphics graphics, Rectangle rect)
{
Point[] pts = {
new Point(rect.Left, rect.Top),
new Point(rect.Right, rect.Bottom)
};
graphics.TransformPoints(
System.Drawing.Drawing2D.CoordinateSpace.Device,
System.Drawing.Drawing2D.CoordinateSpace.Page,
pts);
Rectangle devRect = new Rectangle(
pts0.X, pts0.Y, pts1.X - pts0.X, pts1.Y - pts0.Y);

RangeToFormat rf = new RangeToFormat();
rf.hdc = graphics.GetHdc();
rf.hdcTarget = rf.hdc;
rf.rc = new PRectangle(devRect);
rf.rcPage = new PRectangle(devRect);
rf.chrg.cpMin = start;
rf.chrg.cpMax = end;

return FormatRange(bDraw, rf);
}

Nov 10, 2006 at 4:20 PM
Thanks!

--Matt
Nov 10, 2006 at 7:53 PM
One more thing, I can't seem to find a definition for PRectangle used here:

rf.rc = new PRectangle(devRect);
rf.rcPage = new PRectangle(devRect);

and also RangeToFormat.chrg is not public, though I just changed it to be so. Was there anything else I needed to get your sample to work?

Thanks,
Matt
Nov 15, 2006 at 5:26 PM
I tried this:

StructLayout(LayoutKind.Sequential)
public struct PRectangle
{
public int left;
public int top;
public int right;
public int bottom;
public PRectangle(System.Drawing.Rectangle r)
{
left = r.X;
top = r.Y;
right = left + r.Width;
bottom = top + r.Height;
}

public int Width() { return right - left; }

public int Height() { return bottom - top; }

}

and this usage:

PRectangle prect = new PRectangle(devRect);
PRectangle prect2 = new PRectangle(devRect);
RangeToFormat rf = new RangeToFormat();
rf.hdc = graphics.GetHdc();
rf.hdcTarget = rf.hdc;
rf.rc = new IntPtr(&prect);
rf.rcPage = new IntPtr(&prect2);
rf.chrg.cpMin = start;
rf.chrg.cpMax = end;

But I only get a blank sheet when I print. Any help would be appreciated.
Nov 17, 2006 at 8:43 PM
Here's what I use in Structure.cs:

StructLayout(LayoutKind.Sequential)
public struct PRectangle
{
public int left;
public int top;
public int right;
public int bottom;

public PRectangle(System.Drawing.Rectangle r)
{
left = r.Left;
top = r.Top;
right = r.Right;
bottom = r.Bottom;
}
}

And indeed the chrg field of RangeToFormat must be set public. Note that I don't need the changes you made to the code with IntPtr. I set directly the rc and rcPage field of RangeToFormat structure to the PRectangle objects. It works for me. I think that by adding a IntPtr in between, you add a pointer-reference layer which makes the equivalent C structure incorrect: rc and rcPage are not pointers.
Nov 17, 2006 at 9:49 PM
Thanks Michael! That works great. Just so all the code is here, here is my modified RangeToFormat structure:

StructLayout(LayoutKind.Sequential)
public struct RangeToFormat
{
public IntPtr hdc; // The HDC (device context) we print to
public IntPtr hdcTarget; // The HDC we use for measuring (may be same as hdc)
public PRectangle rc; // Rectangle in which to print
public PRectangle rcPage; // Physically printable page size
public CharacterRange chrg; // Range of characters to print
}

--Matt
Coordinator
Jan 21, 2007 at 4:15 AM
The stuff in this thread is gold! We'll definitely be using this to make an easy to use printing interface.
Coordinator
Feb 5, 2007 at 4:21 AM
This discussion has been copied to Work Item 7964. You may wish to continue further discussion there.