[tomboy] Rewrote the gtk print support to account for two problems, tracked by bug 572024:
- From: Sanford Armstrong <sharm src gnome org>
- To: svn-commits-list gnome org
- Subject: [tomboy] Rewrote the gtk print support to account for two problems, tracked by bug 572024:
- Date: Sat, 2 May 2009 10:02:55 -0400 (EDT)
commit 42bba093d8cec88961712e96741fb2637b314ad1
Author: Benjamin.Podszun <benjamin podszun gmail com>
Date: Tue Apr 28 17:11:56 2009 +0200
Rewrote the gtk print support to account for two problems, tracked by bug 572024:
1) Very long lines were not wrapped around
2) Paragraphs at the end of any page wouldn't render partially, therefor leaving excess whitespace on the result
Both issues should be resolved.
---
Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs | 409 ++++++++++++-----------
1 files changed, 217 insertions(+), 192 deletions(-)
diff --git a/Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs b/Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs
index 20a883a..160288a 100644
--- a/Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs
+++ b/Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs
@@ -4,37 +4,38 @@ using Mono.Unix;
namespace Tomboy.PrintNotes
{
- // TODO:
- // COMMENT! A lot!
- // Remove magic numbers (margins), turn them into preferences
- // Replace bullet point chars with an image?
- // Split the file if it grows any further
-
- struct PrintMargins
+ public class PageBreak
{
- public int Top;
- public int Left;
- public int Right;
- public int Bottom;
+ private readonly int break_paragraph;
+ private readonly int break_line;
- public int VerticalMargins ()
+ public int Paragraph
+ {
+ get { return break_paragraph; }
+ }
+
+ public int Line
{
- return Top + Bottom;
+ get { return break_line; }
}
- public int HorizontalMargins ()
+ public PageBreak(int paragraph, int line)
{
- return Left + Right;
+ break_paragraph = paragraph;
+ break_line = line;
}
}
-
+
public class PrintNotesNoteAddin : NoteAddin
- {
+ {
private Gtk.ImageMenuItem item;
- private PrintMargins page_margins;
- private Pango.Layout date_time_footer;
- private int footer_offset;
- private List<int> page_breaks;
+ private int margin_top;
+ private int margin_left;
+ private int margin_right;
+ private int margin_bottom;
+
+ private Pango.Layout timestamp_footer;
+ private IList<PageBreak> page_breaks;
public override void Initialize ()
{
@@ -57,10 +58,12 @@ namespace Tomboy.PrintNotes
item.Show ();
AddPluginMenuItem (item);
}
-
+
private void PrintButtonClicked (object sender, EventArgs args)
{
try {
+ page_breaks = new List<PageBreak> ();
+
using (Gtk.PrintOperation print_op = new Gtk.PrintOperation ()) {
print_op.JobName = Note.Title;
@@ -83,12 +86,23 @@ namespace Tomboy.PrintNotes
}
}
+ private static int CmToPixel (double cm, double dpi)
+ {
+ return (int) (cm * dpi / 2.54);
+ }
+
+ private static int InchToPixel (double inch, double dpi)
+ {
+ return (int) (inch * dpi);
+ }
+
private IEnumerable<Pango.Attribute> GetParagraphAttributes (
- Pango.Layout layout, double dpiX, ref PrintMargins margins,
+ Pango.Layout layout, double dpiX, out int indentation,
ref Gtk.TextIter position, Gtk.TextIter limit)
{
IList<Pango.Attribute> attributes = new List<Pango.Attribute> ();
-
+ indentation = 0;
+
Gtk.TextTag [] tags = position.Tags;
position.ForwardToTagToggle (null);
if (position.Compare (limit) > 0) position = limit;
@@ -110,10 +124,10 @@ namespace Tomboy.PrintNotes
layout.Indent = tag.Indent;
}
if (tag.LeftMarginSet) {
- margins.Left = (int) (tag.LeftMargin / screen_dpiX * dpiX);
+ indentation = (int) (tag.LeftMargin / screen_dpiX * dpiX);
}
if (tag.RightMarginSet) {
- margins.Right = (int) (tag.RightMargin / screen_dpiX * dpiX);
+ indentation = (int) (tag.RightMargin / screen_dpiX * dpiX);
}
if (tag.FontDesc != null) {
attributes.Add (new Pango.AttrFontDesc (tag.FontDesc));
@@ -150,27 +164,26 @@ namespace Tomboy.PrintNotes
return attributes;
}
- private Pango.Layout CreateLayoutForParagraph (Gtk.PrintContext context,
+ private Pango.Layout CreateParagraphLayout (Gtk.PrintContext context,
Gtk.TextIter p_start,
Gtk.TextIter p_end,
- out PrintMargins margins)
+ out int indentation)
{
Pango.Layout layout = context.CreatePangoLayout ();
layout.FontDescription = Window.Editor.Style.FontDesc;
int start_index = p_start.LineIndex;
+ indentation = 0;
- margins = new PrintMargins ();
-
+ double dpiX = context.DpiX;
using (Pango.AttrList attr_list = new Pango.AttrList ()) {
Gtk.TextIter segm_start = p_start;
Gtk.TextIter segm_end;
-
- double dpiX = context.DpiX;
+
while (segm_start.Compare (p_end) < 0) {
segm_end = segm_start;
IEnumerable<Pango.Attribute> attrs =
GetParagraphAttributes (
- layout, dpiX, ref margins,
+ layout, dpiX, out indentation,
ref segm_end, p_end);
uint si = (uint) (segm_start.LineIndex - start_index);
@@ -188,222 +201,234 @@ namespace Tomboy.PrintNotes
}
layout.Width = Pango.Units.FromPixels ((int)context.Width -
- margins.HorizontalMargins () -
- page_margins.HorizontalMargins ());
+ margin_left - margin_right - indentation);
+ layout.Wrap = Pango.WrapMode.WordChar;
layout.SetText (Buffer.GetSlice (p_start, p_end, false));
return layout;
}
-
- private Pango.Layout CreateLayoutForPagenumbers (Gtk.PrintContext context, int page_number, int total_pages)
- {
- Pango.Layout layout = context.CreatePangoLayout ();
- layout.FontDescription = Window.Editor.Style.FontDesc;
- layout.Width = Pango.Units.FromPixels ((int) context.Width);
- layout.FontDescription.Style = Pango.Style.Normal;
- layout.FontDescription.Weight = Pango.Weight.Light;
-
- string footer_left = string.Format (Catalog.GetString ("Page {0} of {1}"),
- page_number, total_pages);
- layout.Alignment = Pango.Alignment.Left;
- layout.SetText (footer_left);
-
- return layout;
- }
-
- private Pango.Layout CreateLayoutForTimestamp (Gtk.PrintContext context)
- {
- Pango.Layout layout = context.CreatePangoLayout ();
- layout.FontDescription = Window.Editor.Style.FontDesc;
- layout.Width = Pango.Units.FromPixels ((int) context.Width);
- layout.FontDescription.Style = Pango.Style.Normal;
- layout.FontDescription.Weight = Pango.Weight.Light;
-
- string footer_right = DateTime.Now.ToString (
- /* Translators: Explanation of the date and time format specifications can be found here:
- * http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.aspx */
- Catalog.GetString ("dddd MM/dd/yyyy, hh:mm:ss tt"));
- Logger.Debug (footer_right);
- layout.Alignment = Pango.Alignment.Right;
- layout.SetText (footer_right);
-
- return layout;
- }
-
- public static int CmToPixel (double cm, double dpi)
- {
- return (int) (cm * dpi / 2.54);
+
+ private Pango.Layout CreatePagenumbersLayout (Gtk.PrintContext context,
+ int page_number, int total_pages)
+ {
+ Pango.Layout layout = context.CreatePangoLayout ();
+ layout.FontDescription = Window.Editor.Style.FontDesc;
+ layout.Width = Pango.Units.FromPixels ((int) context.Width);
+ layout.FontDescription.Style = Pango.Style.Normal;
+ layout.FontDescription.Weight = Pango.Weight.Light;
+
+ string footer_left = string.Format (Catalog.GetString ("Page {0} of {1}"),
+ page_number, total_pages);
+ layout.Alignment = Pango.Alignment.Left;
+ layout.SetText (footer_left);
+
+ return layout;
+ }
+
+ private Pango.Layout CreateTimestampLayout (Gtk.PrintContext context)
+ {
+ Pango.Layout layout = context.CreatePangoLayout ();
+ layout.FontDescription = Window.Editor.Style.FontDesc;
+ layout.Width = Pango.Units.FromPixels ((int) context.Width);
+ layout.FontDescription.Style = Pango.Style.Normal;
+ layout.FontDescription.Weight = Pango.Weight.Light;
+
+ string footer_right = DateTime.Now.ToString (
+ /* Translators: Explanation of the date and time format specifications can be found here:
+ * http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.aspx */
+ Catalog.GetString ("dddd MM/dd/yyyy, hh:mm:ss tt"));
+ layout.Alignment = Pango.Alignment.Right;
+ layout.SetText (footer_right);
+
+ return layout;
+ }
+
+ private int ComputeFooterHeight (Gtk.PrintContext context) {
+ using (Pango.Layout layout = CreateTimestampLayout (context)) {
+ Pango.Rectangle ink_rect;
+ Pango.Rectangle logical_rect;
+ layout.GetExtents (out ink_rect, out logical_rect);
+
+ // Compute the footer height, include the space for the horizontal line
+ return Pango.Units.ToPixels (ink_rect.Height) +
+ CmToPixel (0.5, context.DpiY);
+ }
}
private void OnBeginPrint (object sender, Gtk.BeginPrintArgs args)
{
+ Gtk.PrintOperation op = (Gtk.PrintOperation) sender;
Gtk.PrintContext context = args.Context;
-
- // Create and initialize the page margins
- page_margins = new PrintMargins ();
- page_margins.Top = CmToPixel (1.5, context.DpiY);
- page_margins.Left = CmToPixel (1, context.DpiX);
- page_margins.Right = CmToPixel (1, context.DpiX);
- page_margins.Bottom = 0;
-
- // Compute the footer height to define the bottom margin
- date_time_footer = CreateLayoutForTimestamp (context);
- Pango.Rectangle footer_ink_rect;
- Pango.Rectangle footer_logical_rect;
- date_time_footer.GetExtents (
- out footer_ink_rect,
- out footer_logical_rect);
+ timestamp_footer = CreateTimestampLayout (context);
- footer_offset = CmToPixel (0.5, context.DpiY);
+ // FIXME: These should be configurable settings later (UI Change)
+ margin_top = CmToPixel (1.5, context.DpiY);
+ margin_left = CmToPixel (1, context.DpiX);
+ margin_right = CmToPixel (1, context.DpiX);
+ margin_bottom = 0;
+ double max_height = Pango.Units.FromPixels ((int) context.Height -
+ margin_top - margin_bottom - ComputeFooterHeight (context));
- /* Set the bottom margin to the height of the footer + a constant
- * offset for the separation line */
- page_margins.Bottom += Pango.Units.ToPixels (footer_logical_rect.Height) +
- footer_offset;
-
- double height = Pango.Units.FromPixels ((int) context.Height - page_margins.VerticalMargins ());
- double page_height = 0;
-
- page_breaks = new List<int> ();
-
Gtk.TextIter position;
Gtk.TextIter end_iter;
Buffer.GetBounds (out position, out end_iter);
+ double page_height = 0;
bool done = position.Compare (end_iter) >= 0;
while (!done) {
- int line_number = position.Line;
-
Gtk.TextIter line_end = position;
if (!line_end.EndsLine ())
line_end.ForwardToLineEnd ();
-
- PrintMargins margins;
- using (Pango.Layout layout = CreateLayoutForParagraph (
- context, position, line_end, out margins)) {
-
- Pango.Rectangle ink_rect;
- Pango.Rectangle logical_rect;
- layout.GetExtents (out ink_rect, out logical_rect);
-
- if (page_height + logical_rect.Height > height) {
- page_breaks.Add (line_number);
- page_height = 0;
+
+ int paragraph_number = position.Line;
+ int indentation;
+ using (Pango.Layout layout = CreateParagraphLayout (
+ context, position, line_end, out indentation)) {
+
+ Pango.Rectangle ink_rect = Pango.Rectangle.Zero;
+ Pango.Rectangle logical_rect = Pango.Rectangle.Zero;
+ for (int line_in_paragraph = 0; line_in_paragraph < layout.LineCount;
+ line_in_paragraph++) {
+ Pango.LayoutLine line = layout.GetLine (line_in_paragraph);
+ line.GetExtents (ref ink_rect, ref logical_rect);
+
+ if (page_height + logical_rect.Height >= max_height) {
+ PageBreak page_break = new PageBreak (
+ paragraph_number, line_in_paragraph);
+ page_breaks.Add (page_break);
+
+ page_height = 0;
+ }
+ page_height += logical_rect.Height;
}
- page_height += logical_rect.Height;
+ position.ForwardLine ();
+ done = position.Compare (end_iter) >= 0;
}
-
- position.ForwardLine ();
- done = position.Compare (end_iter) >= 0;
}
- Gtk.PrintOperation op = (Gtk.PrintOperation) sender;
op.NPages = page_breaks.Count + 1;
}
- private void PrintFooter (Gtk.DrawPageArgs args)
- {
- int total_height = Pango.Units.FromPixels ((int) args.Context.Height);
- int total_width = Pango.Units.FromPixels ((int) args.Context.Width);
-
- using (Cairo.Context cr = args.Context.CairoContext) {
- cr.MoveTo (CmToPixel (0.5, args.Context.DpiX), Pango.Units.ToPixels (total_height) - page_margins.Bottom + footer_offset);
- cr.LineTo (Pango.Units.ToPixels (total_width) - CmToPixel (0.5, args.Context.DpiX), Pango.Units.ToPixels (total_height) - page_margins.Bottom + footer_offset);
- cr.Stroke ();
-
- Pango.Rectangle ink_rect;
- Pango.Rectangle logical_rect;
- date_time_footer.GetExtents (out ink_rect, out logical_rect);
-
- Cairo.PointD footer_anchor = new Cairo.PointD (
- CmToPixel (0.5, args.Context.DpiX), Pango.Units.ToPixels (total_height) - page_margins.Bottom + footer_offset + Pango.Units.ToPixels (logical_rect.Height));
-
- cr.MoveTo (Pango.Units.ToPixels (total_width - logical_rect.Width) - CmToPixel (0.5, args.Context.DpiX), footer_anchor.Y);
- Pango.CairoHelper.ShowLayoutLine (cr, date_time_footer.Lines [0]);
-
- cr.MoveTo (footer_anchor);
- using (Pango.Layout pages_footer = CreateLayoutForPagenumbers (
- args.Context, args.PageNr + 1, page_breaks.Count + 1)) {
- Pango.CairoHelper.ShowLayoutLine (cr, pages_footer.Lines [0]);
- }
- }
- }
-
public void OnDrawPage (object sender, Gtk.DrawPageArgs args)
{
using (Cairo.Context cr = args.Context.CairoContext) {
- cr.MoveTo (page_margins.Left, page_margins.Top);
-
- int start_line = 0;
- if (args.PageNr != 0)
- start_line = page_breaks [args.PageNr - 1];
-
- int last_line = -1;
- if (page_breaks.Count > args.PageNr)
- last_line = page_breaks [args.PageNr] - 1;
+ cr.MoveTo (margin_left, margin_top);
+
+ PageBreak start;
+ if (args.PageNr == 0) {
+ start = new PageBreak (0, 0);
+ } else {
+ start = page_breaks [args.PageNr - 1];
+ }
+
+ PageBreak end;
+ if (args.PageNr < page_breaks.Count) {
+ end = page_breaks [args.PageNr];
+ } else {
+ end = new PageBreak (-1, -1);
+ }
+ Gtk.PrintContext context = args.Context;
Gtk.TextIter position;
Gtk.TextIter end_iter;
Buffer.GetBounds (out position, out end_iter);
- bool done = position.Compare (end_iter) >= 0;
- int line_number = position.Line;
-
- // Fast-forward to the starting line
- while (!done && line_number < start_line) {
- Gtk.TextIter line_end = position;
- if (!line_end.EndsLine ())
- line_end.ForwardToLineEnd ();
-
+ // Fast-forward to the right starting paragraph
+ while (position.Line < start.Paragraph) {
position.ForwardLine ();
- done = position.Compare (end_iter) >= 0;
- line_number = position.Line;
}
-
- // Print the current page's content
- while (!done && ((last_line == -1) || (line_number < last_line))) {
- line_number = position.Line;
-
+
+ bool done = position.Compare (end_iter) >= 0;
+ while (!done) {
Gtk.TextIter line_end = position;
if (!line_end.EndsLine ())
line_end.ForwardToLineEnd ();
- PrintMargins margins;
- using (Pango.Layout layout =
- CreateLayoutForParagraph (args.Context,
- position, line_end, out margins)) {
- foreach (Pango.LayoutLine line in layout.Lines) {
+ int paragraph_number = position.Line;
+ int indentation;
+ using (Pango.Layout layout = CreateParagraphLayout (
+ context, position, line_end, out indentation)) {
+
+ for (int line_number = 0;
+ line_number < layout.LineCount && !done;
+ line_number++) {
+ // Skip the lines up to the starting line in the
+ // first paragraph on this page
+ if ((paragraph_number == start.Paragraph) &&
+ (line_number < start.Line)) {
+ continue;
+ }
+
+ // Break as soon as we hit the end line
+ if ((paragraph_number == end.Paragraph) &&
+ (line_number == end.Line)) {
+ done = true;
+ break;
+ }
+
+ Pango.LayoutLine line = layout.Lines [line_number];
Pango.Rectangle ink_rect = Pango.Rectangle.Zero;
Pango.Rectangle logical_rect = Pango.Rectangle.Zero;
line.GetExtents (ref ink_rect, ref logical_rect);
-
- cr.MoveTo (
- margins.Left + page_margins.Left,
+
+ cr.MoveTo (margin_left + indentation,
cr.CurrentPoint.Y);
- int line_height = Pango.Units.ToPixels(logical_rect.Height);
+ int line_height = Pango.Units.ToPixels (logical_rect.Height);
+
Cairo.PointD new_line_point = new Cairo.PointD (
- margins.Left + page_margins.Left,
+ margin_left + indentation,
cr.CurrentPoint.Y + line_height);
+
Pango.CairoHelper.ShowLayoutLine (cr, line);
cr.MoveTo (new_line_point);
}
}
-
+
position.ForwardLine ();
- done = position.Compare (end_iter) >= 0;
- }
+ done = done || position.Compare (end_iter) >= 0;
+ }
+
+ int total_height = (int) args.Context.Height;
+ int total_width = (int) args.Context.Width;
+ int footer_height = 0;
- // Print the footer
- PrintFooter (args);
+ Cairo.PointD footer_anchor;
+ using (Pango.Layout pages_footer = CreatePagenumbersLayout (
+ args.Context, args.PageNr + 1, page_breaks.Count + 1)) {
+ Pango.Rectangle ink_footer_rect;
+ Pango.Rectangle logical_footer_rect;
+ pages_footer.GetExtents (out ink_footer_rect, out logical_footer_rect);
+
+ footer_anchor = new Cairo.PointD (
+ CmToPixel (0.5, args.Context.DpiX),
+ total_height - margin_bottom);
+ footer_height = Pango.Units.ToPixels (logical_footer_rect.Height);
+
+ cr.MoveTo (
+ total_width - Pango.Units.ToPixels (logical_footer_rect.Width) -
+ CmToPixel (0.5, args.Context.DpiX),
+ footer_anchor.Y);
+
+ Pango.CairoHelper.ShowLayoutLine (cr, pages_footer.Lines [0]);
+ }
+
+ cr.MoveTo (footer_anchor);
+ Pango.CairoHelper.ShowLayoutLine (cr, timestamp_footer.Lines [0]);
+
+ cr.MoveTo (CmToPixel (0.5, args.Context.DpiX),
+ total_height - margin_bottom - footer_height);
+ cr.LineTo (total_width - CmToPixel (0.5, args.Context.DpiX),
+ total_height - margin_bottom - footer_height);
+ cr.Stroke ();
}
}
private void OnEndPrint (object sender, Gtk.EndPrintArgs args)
{
- if (date_time_footer != null)
- date_time_footer.Dispose ();
- if (page_breaks != null)
- page_breaks.Clear ();
+ if (timestamp_footer != null) {
+ timestamp_footer.Dispose ();
+ timestamp_footer = null;
+ }
}
}
-}
+}
\ No newline at end of file
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]