private void OnBeginPrint(object sender, Gtk.BeginPrintArgs args) { Gtk.PrintOperation op = (Gtk.PrintOperation)sender; Gtk.PrintContext context = args.Context; timestamp_footer = CreateTimestampLayout(context); // 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)); 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) { Gtk.TextIter line_end = position; if (!line_end.EndsLine()) { line_end.ForwardToLineEnd(); } 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; } position.ForwardLine(); done = position.Compare(end_iter) >= 0; } } op.NPages = page_breaks.Count + 1; }
private void EllipsizeLayout(int width) { // no room to draw anything if (width < 1) { layout.SetMarkup(""); return; } // plenty of room int lw, lh; layout.GetPixelSize(out lw, out lh); if (width > lw) { return; } // not enough room for ... int ell_w, ell_h; Pango.Layout ell = layout.Copy(); ell.SetMarkup("..."); ell.GetPixelSize(out ell_w, out ell_h); if (width < ell_w) { layout.SetMarkup(""); return; } // subtract ellipses width width -= ell_w; int index, trailing; Pango.LayoutLine line = layout.GetLine(0); if (line.XToIndex(width * 1024, out index, out trailing)) { // Console.WriteLine ("length: {0} index: {1} trailing: {2}", layout.Text.Length, index, trailing); // FIXME: breaks on accented chars if (index < layout.Text.Length) { layout.SetMarkup(layout.Text.Substring(0, index) + "..."); } } }
void DrawTab(Context ctx, DockNotebookTab tab, Gdk.Rectangle allocation, Gdk.Rectangle tabBounds, bool highlight, bool active, bool dragging, Pango.Layout la) { // This logic is stupid to have here, should be in the caller! if (dragging) { tabBounds.X = (int)(tabBounds.X + (dragX - tabBounds.X) * dragXProgress); tabBounds.X = Clamp(tabBounds.X, tabStartX, tabEndX - tabBounds.Width); } double rightPadding = (active ? TabActivePadding.Right : TabPadding.Right) - (LeanWidth / 2); rightPadding = (rightPadding * Math.Min(1.0, Math.Max(0.5, (tabBounds.Width - 30) / 70.0))); double leftPadding = (active ? TabActivePadding.Left : TabPadding.Left) - (LeanWidth / 2); leftPadding = (leftPadding * Math.Min(1.0, Math.Max(0.5, (tabBounds.Width - 30) / 70.0))); double bottomPadding = active ? TabActivePadding.Bottom : TabPadding.Bottom; DrawTabBackground(this, ctx, allocation, tabBounds.Width, tabBounds.X, active); ctx.LineWidth = 1; ctx.NewPath(); // Render Close Button (do this first so we can tell how much text to render) var closeButtonAlloation = new Cairo.Rectangle(tabBounds.Right - rightPadding - (tabCloseImage.Width / 2) - CloseButtonMarginRight, tabBounds.Height - bottomPadding - tabCloseImage.Height - CloseButtonMarginBottom, tabCloseImage.Width, tabCloseImage.Height); tab.CloseButtonActiveArea = closeButtonAlloation.Inflate(2, 2); bool closeButtonHovered = tracker.Hovered && tab.CloseButtonActiveArea.Contains(tracker.MousePosition); bool tabHovered = tracker.Hovered && tab.Allocation.Contains(tracker.MousePosition); bool drawCloseButton = active || tabHovered; if (!closeButtonHovered && tab.DirtyStrength > 0.5) { ctx.DrawImage(this, tabDirtyImage, closeButtonAlloation.X, closeButtonAlloation.Y); drawCloseButton = false; } if (drawCloseButton) { ctx.DrawImage(this, tabCloseImage.WithAlpha((closeButtonHovered ? 1.0 : 0.5) * tab.Opacity), closeButtonAlloation.X, closeButtonAlloation.Y); } // Render Text double tw = tabBounds.Width - (leftPadding + rightPadding); if (drawCloseButton || tab.DirtyStrength > 0.5) { tw -= closeButtonAlloation.Width / 2; } double tx = tabBounds.X + leftPadding; var baseline = la.GetLine(0).Layout.GetPixelBaseline(); double ty = tabBounds.Height - bottomPadding - baseline; ctx.MoveTo(tx, ty); if (!MonoDevelop.Core.Platform.IsMac && !MonoDevelop.Core.Platform.IsWindows) { // This is a work around for a linux specific problem. // A bug in the proprietary ATI driver caused TAB text not to draw. // If that bug get's fixed remove this HACK asap. la.Ellipsize = Pango.EllipsizeMode.End; la.Width = (int)(tw * Pango.Scale.PangoScale); ctx.SetSourceColor((tab.Notify ? Styles.TabBarNotifyTextColor : (active ? Styles.TabBarActiveTextColor : Styles.TabBarInactiveTextColor)).ToCairoColor()); Pango.CairoHelper.ShowLayout(ctx, la.GetLine(0).Layout); } else { // ellipses are for space wasting ..., we cant afford that using (var lg = new LinearGradient(tx + tw - 10, 0, tx + tw, 0)) { var color = (tab.Notify ? Styles.TabBarNotifyTextColor : (active ? Styles.TabBarActiveTextColor : Styles.TabBarInactiveTextColor)).ToCairoColor(); color = color.MultiplyAlpha(tab.Opacity); lg.AddColorStop(0, color); color.A = 0; lg.AddColorStop(1, color); ctx.SetSource(lg); Pango.CairoHelper.ShowLayout(ctx, la.GetLine(0).Layout); } } la.Dispose(); }
void Setup(Pango.Layout layout) { Font.Apply(layout); layout.Width = (int)(MaximumSize.Width * Pango.Scale.PangoScale); #if GTK3 layout.Height = (int)(MaximumSize.Height * Pango.Scale.PangoScale); #endif layout.Ellipsize = Trimming == FormattedTextTrimming.None ? Pango.EllipsizeMode.None : Pango.EllipsizeMode.End; switch (Wrap) { case FormattedTextWrapMode.None: // only draw one line!! layout.Wrap = Pango.WrapMode.Char; #if GTK3 layout.Height = (int)((double)layout.FontDescription.Size / (double)Pango.Scale.PangoScale); #endif break; case FormattedTextWrapMode.Word: layout.Wrap = Pango.WrapMode.Word; break; case FormattedTextWrapMode.Character: layout.Wrap = Pango.WrapMode.Char; break; } switch (Alignment) { case FormattedTextAlignment.Left: layout.Alignment = Pango.Alignment.Left; break; case FormattedTextAlignment.Right: layout.Alignment = Pango.Alignment.Right; break; case FormattedTextAlignment.Center: layout.Alignment = Pango.Alignment.Center; break; case FormattedTextAlignment.Justify: layout.Alignment = Pango.Alignment.Left; layout.Justify = true; break; } layout.SetText(Text); if (Wrap == FormattedTextWrapMode.None && layout.LineCount > 1) { // line includes the full last word so keep shrinking until it isn't wrapped var len = layout.GetLine(0).Length; while (len > 0 && layout.IsWrapped) { layout.SetText(Text.Substring(0, len--)); } } if (Trimming == FormattedTextTrimming.None && layout.LineCount > 1) { layout.GetPixelSize(out _, out var height); while (layout.LineCount > 1 && height > MaximumSize.Height) { var lineCount = layout.LineCount; var line = layout.GetLine(lineCount - 1); var len = line.StartIndex; layout.SetText(Text.Substring(0, len)); if (layout.LineCount == lineCount) { // need to trim off some characters or words from the current line while (layout.LineCount == lineCount && --len > 0) { if (Wrap == FormattedTextWrapMode.Word) { // keep going till whitespace for wrapping. while (len > 0 && !char.IsWhiteSpace(Text[len - 1])) { len--; } } layout.SetText(Text.Substring(0, len)); } } layout.GetPixelSize(out _, out height); } } }
void DrawTab(Context ctx, DockNotebookTab tab, Gdk.Rectangle allocation, Gdk.Rectangle tabBounds, bool highlight, bool active, bool dragging, Pango.Layout la) { // This logic is stupid to have here, should be in the caller! if (dragging) { tabBounds.X = (int)(tabBounds.X + (dragX - tabBounds.X) * dragXProgress); tabBounds.X = Clamp(tabBounds.X, tabStartX, tabEndX - tabBounds.Width); } int padding = LeftRightPadding; padding = (int)(padding * Math.Min(1.0, Math.Max(0.5, (tabBounds.Width - 30) / 70.0))); ctx.LineWidth = 1; LayoutTabBorder(ctx, allocation, tabBounds.Width, tabBounds.X, 0, active); ctx.ClosePath(); using (var gr = new LinearGradient(tabBounds.X, TopBarPadding, tabBounds.X, allocation.Bottom)) { if (active) { gr.AddColorStop(0, Styles.BreadcrumbGradientStartColor.MultiplyAlpha(tab.Opacity)); gr.AddColorStop(1, Styles.BreadcrumbBackgroundColor.MultiplyAlpha(tab.Opacity)); } else { gr.AddColorStop(0, CairoExtensions.ParseColor("f4f4f4").MultiplyAlpha(tab.Opacity)); gr.AddColorStop(1, CairoExtensions.ParseColor("cecece").MultiplyAlpha(tab.Opacity)); } ctx.SetSource(gr); } ctx.Fill(); ctx.SetSourceColor(new Cairo.Color(1, 1, 1, .5).MultiplyAlpha(tab.Opacity)); LayoutTabBorder(ctx, allocation, tabBounds.Width, tabBounds.X, 1, active); ctx.Stroke(); ctx.SetSourceColor(Styles.BreadcrumbBorderColor.MultiplyAlpha(tab.Opacity)); LayoutTabBorder(ctx, allocation, tabBounds.Width, tabBounds.X, 0, active); ctx.StrokePreserve(); if (tab.GlowStrength > 0) { Gdk.Point mouse = tracker.MousePosition; using (var rg = new RadialGradient(mouse.X, tabBounds.Bottom, 0, mouse.X, tabBounds.Bottom, 100)) { rg.AddColorStop(0, new Cairo.Color(1, 1, 1, 0.4 * tab.Opacity * tab.GlowStrength)); rg.AddColorStop(1, new Cairo.Color(1, 1, 1, 0)); ctx.SetSource(rg); ctx.Fill(); } } else { ctx.NewPath(); } // Render Close Button (do this first so we can tell how much text to render) var ch = allocation.Height - TopBarPadding - BottomBarPadding + CloseImageTopOffset; var crect = new Gdk.Rectangle(tabBounds.Right - padding - CloseButtonSize + 3, tabBounds.Y + TopBarPadding + (ch - CloseButtonSize) / 2, CloseButtonSize, CloseButtonSize); tab.CloseButtonAllocation = crect; tab.CloseButtonAllocation.Inflate(2, 2); bool closeButtonHovered = tracker.Hovered && tab.CloseButtonAllocation.Contains(tracker.MousePosition) && tab.WidthModifier >= 1.0f; bool drawCloseButton = tabBounds.Width > 60 || highlight || closeButtonHovered; if (drawCloseButton) { DrawCloseButton(ctx, new Gdk.Point(crect.X + crect.Width / 2, crect.Y + crect.Height / 2), closeButtonHovered, tab.Opacity, tab.DirtyStrength); } // Render Text int w = tabBounds.Width - (padding * 2 + CloseButtonSize); if (!drawCloseButton) { w += CloseButtonSize; } int textStart = tabBounds.X + padding; ctx.MoveTo(textStart, tabBounds.Y + TopPadding + TextOffset + VerticalTextSize); if (!Platform.IsMac && !Platform.IsWindows) { // This is a work around for a linux specific problem. // A bug in the proprietary ATI driver caused TAB text not to draw. // If that bug get's fixed remove this HACK asap. la.Ellipsize = Pango.EllipsizeMode.End; la.Width = (int)(w * Pango.Scale.PangoScale); ctx.SetSourceColor(tab.Notify ? new Cairo.Color(0, 0, 1) : Styles.TabBarActiveTextColor); Pango.CairoHelper.ShowLayoutLine(ctx, la.GetLine(0)); } else { // ellipses are for space wasting ..., we cant afford that using (var lg = new LinearGradient(textStart + w - 5, 0, textStart + w + 3, 0)) { var color = tab.Notify ? new Cairo.Color(0, 0, 1) : Styles.TabBarActiveTextColor; color = color.MultiplyAlpha(tab.Opacity); lg.AddColorStop(0, color); color.A = 0; lg.AddColorStop(1, color); ctx.SetSource(lg); Pango.CairoHelper.ShowLayoutLine(ctx, la.GetLine(0)); } } la.Dispose(); }
public Pango.LayoutLine GetLine(int line) { return(layout.GetLine(line)); }