Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[TextLayout] [Gtk,Wpf] WrapMode implemented #354

Open
wants to merge 2 commits into from

3 participants

@lytico

[update] to get a consistent behavoiur, TextLayout has a WrapMode now.
WrapMode.None is like Gtk, WrapMode.Word is like Wpf
[/update]

If TextLayout.Width > 0, Height is -1 and TextLayout.Trimming is WordElipsis, then
Xwt.Gtk draws a one-liner according to Width, and ellipsize this line:
texttrimmingellipsisgtkwrong
[update] this is the behavior with WrapMode==None[/update]
Xwt.Wpf makes soft line breaks according to Width, and ellipsize every line that does't fit into Width:
texttrimmingellipsiswpf
if Layout.Height is set, then the last line should be ellipsized to show that there is more content:
texttrimmingellipsisheigthbreakwpf
[update] this is the behavior with WrapMode==Word [/update]
The same problem appears with TextLayout.GetSize(): if ellipsized, it returns the Heigth of one line.

This commit produces the following output on Xwt.Gtk: [update] and Wpf with WrapMode=Word [/update]

texttrimmingellipsisgtk
texttrimmingellipsisheigthbreakgtk

@slluis
Owner

It doesn't seem you are taking wrapping into account. If wrapping is set to None, the current behavior of gtk is correct.

@lytico

You are right - but only if we assume that wrapping is set to None. Currently we don't have anything like "Wrapping" in TextLayout, or do i miss something??
So it is unclear if Wrapping is true or false, it depends on the implementation.
I suggest to introduce TextLayout.Wrapping : enum {None, Word, Char }
I can do that in the next days (Gtk & Wpf, sorry, no Mac), if you agree.

@lytico lytico changed the title from Xwt.Gtk: if TextLayout.Trimming is WordElipsis, only the first line is drawn to add TextLayout.WrapMode
@lytico

I've added WrapMode to TextLayout to solve the problem.
TextLayout.WrapMode = WrapMode.None shows the Gtk behavior
TextLayout.WrapMode = WrapMode.Word shows the Wpf behavior

@lytico lytico changed the title from add TextLayout.WrapMode to [TextLayout] [Gtk,Wpf} WrapMode implemented
@lytico lytico changed the title from [TextLayout] [Gtk,Wpf} WrapMode implemented to [TextLayout] [Gtk,Wpf] WrapMode implemented
@sevoku sevoku added the feedback label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
4 Testing/Tests/DrawingTests.cs
@@ -900,13 +900,15 @@ public void TextWordWrap ()
public void TextTrimmingEllipsis ()
{
// Transform is saved
- InitBlank (50, 100);
var la = new TextLayout ();
la.Font = Font.FromName ("Arial 12");
la.Text = "One Two Three Four Five Six Seven Eight Nine";
la.Width = 45;
la.Trimming = TextTrimming.WordElipsis;
+ la.WrapMode = WrapMode.None;
var s = la.GetSize ();
+ InitBlank ((int)(s.Width + 11), (int)(s.Height + 11));
+
context.Rectangle (5.5, 5.5, s.Width, s.Height);
context.SetColor (Colors.Blue);
context.Stroke ();
View
89 Xwt.Gtk/Xwt.CairoBackend/CairoContextBackendHandler.cs
@@ -4,6 +4,7 @@
// Author:
// Lluis Sanchez <lluis@xamarin.com>
// Hywel Thomas <hywel.w.thomas@gmail.com>
+// Lytico (http://www.limada.org)
//
// Copyright (c) 2011 Xamarin Inc
//
@@ -284,26 +285,90 @@ public override void DrawTextLayout (object backend, TextLayout layout, double x
var be = (GtkTextLayoutBackendHandler.PangoBackend)Toolkit.GetBackend (layout);
var pl = be.Layout;
CairoContextBackend ctx = (CairoContextBackend)backend;
- ctx.Context.MoveTo (x, y);
- if (layout.Height <= 0) {
+
+ if (layout.Height <= 0 && layout.Trimming == TextTrimming.Word && layout.WrapMode == WrapMode.None) {
+ ctx.Context.MoveTo (x, y);
Pango.CairoHelper.ShowLayout (ctx.Context, pl);
} else {
+ // disable ellipsize, otherwise pl.LineCount returns always 1
+ var ellipsize = pl.Ellipsize;
+ pl.Ellipsize = Pango.EllipsizeMode.None;
+
var lc = pl.LineCount;
var scale = Pango.Scale.PangoScale;
- double h = 0;
+ var wrap = pl.Wrap;
+
+ var layoutHeight = layout.Height;
+ if (layoutHeight <= 0) {
+ var plw = 0;
+ var plh = 0;
+ pl.GetSize (out plw, out plh);
+ layoutHeight = plh / scale;
+ }
+ var next = default (Pango.LayoutLine);
+ var nextDelta = Size.Zero;
var fe = ctx.Context.FontExtents;
var baseline = fe.Ascent / (fe.Ascent + fe.Descent);
- for (int i=0; i<lc; i++) {
- var line = pl.Lines [i];
- var ext = new Pango.Rectangle ();
- var extl = new Pango.Rectangle ();
- line.GetExtents (ref ext, ref extl);
- h += h == 0 ? (extl.Height / scale * baseline) : (extl.Height / scale);
- if (h > layout.Height)
- break;
- ctx.Context.MoveTo (x, y + h);
+ var sll = default (Pango.Layout); // single line layout; created on demand
+
+ var i = 0;
+
+ Action nextLine = () => {
+ next = pl.Lines [i];
+ var ls = next.GetSize ();
+ nextDelta = new Size (
+ ls.Width,
+ nextDelta.Height + (i == 0 ? ls.Height * baseline : ls.Height)
+ );
+ };
+
+ nextLine ();
+
+ while (i < lc && nextDelta.Height <= layoutHeight) {
+ var delta = nextDelta;
+ var line = next;
+ if (++i < lc)
+ nextLine ();
+
+ // if the next line is not visible, or the line not fully visible,
+ // then the line has to be ellipsize and/or trimmed:
+ if (nextDelta.Height > layoutHeight ||
+ (delta.Width > layout.Width && layout.Width > 0) ||
+ (layout.WrapMode == WrapMode.None && lc > 1)) {
+ if (sll == null) {
+ sll = new Pango.Layout (pl.Context) {
+ FontDescription = pl.FontDescription,
+ Width = pl.Width,
+ Ellipsize = ellipsize,
+ Wrap = pl.Wrap
+ };
+ }
+
+ var lineLen = line.Length - (nextDelta.Height > layoutHeight || layout.WrapMode == WrapMode.None ? 1 : 0);
+ Action setLine = () => {
+ sll.SetText (line.Layout.Text.Substring (line.StartIndex, Math.Max (lineLen, 0)) +
+ (ellipsize != Pango.EllipsizeMode.None ? // Gtk on Linux forgets to ellipsize
+ ((char)0x2026).ToString () : ""));
+ line = sll.Lines [0];
+ };
+
+ setLine ();
+ // fallback, if line's text don't fit into one line:
+ while ((sll.Lines.Length > 1 || line.GetSize ().Width > layout.Width) && lineLen > 1) {
+ lineLen = lineLen - 1;
+ setLine ();
+ }
+ }
+ ctx.Context.MoveTo (x, y + delta.Height);
Pango.CairoHelper.ShowLayoutLine (ctx.Context, line);
+
+ if (layout.WrapMode == WrapMode.None)
+ break;
}
+
+ pl.Ellipsize = ellipsize;
+ if (sll != null)
+ sll.Dispose ();
}
}
View
9 Xwt.Gtk/Xwt.CairoBackend/CairoConversion.cs
@@ -70,6 +70,15 @@ public static void RoundedRectangle(this Cairo.Context cr, double x, double y, d
cr.Arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);
cr.Arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
}
+
+ public static Size GetSize (this Pango.LayoutLine line)
+ {
+ var ext = new Pango.Rectangle ();
+ var extl = new Pango.Rectangle ();
+ var scale = Pango.Scale.PangoScale;
+ line.GetExtents (ref ext, ref extl);
+ return new Size (extl.Width / scale, extl.Height / scale);
+ }
}
}
View
35 Xwt.Gtk/Xwt.GtkBackend/TextLayoutBackendHandler.cs
@@ -3,7 +3,7 @@
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
-// Lytico (http://limada.sourceforge.net)
+// Lytico (http://www.limada.org)
//
// Copyright (c) 2011 Xamarin Inc
//
@@ -131,9 +131,12 @@ public static void DisposeResources ()
public override object Create ()
{
- return new PangoBackend {
+ var layout = new PangoBackend {
Layout = Pango.CairoHelper.CreateLayout (SharedContext)
};
+ SetTrimming (layout, TextTrimming.Word);
+ SetWrapMode (layout, WrapMode.Word);
+ return layout;
}
public override void SetText (object backend, string text)
@@ -169,12 +172,38 @@ public override void SetTrimming (object backend, TextTrimming textTrimming)
tl.Layout.Ellipsize = Pango.EllipsizeMode.None;
}
-
+
+ WrapMode wrapMode;
+
+ public override void SetWrapMode (object backend, WrapMode value)
+ {
+ var tl = (PangoBackend)backend;
+ if (value == WrapMode.Word || value == WrapMode.None)
+ tl.Layout.Wrap = Pango.WrapMode.Word;
+ else if (value == WrapMode.Character)
+ tl.Layout.Wrap = Pango.WrapMode.Char;
+ else if (value == WrapMode.WordAndCharacter)
+ tl.Layout.Wrap = Pango.WrapMode.WordChar;
+ wrapMode = value;
+ }
+
public override Size GetSize (object backend)
{
var tl = (PangoBackend)backend;
int w, h;
+ // disable ellipsize, otherwise GetPixelSize returns the heigth of one line only
+ var ellipsize = tl.Layout.Ellipsize;
+ tl.Layout.Ellipsize = Pango.EllipsizeMode.None;
tl.Layout.GetPixelSize (out w, out h);
+ tl.Layout.Ellipsize = ellipsize;
+ if (wrapMode == WrapMode.None && tl.Layout.LineCount > 0) {
+ var line = tl.Layout.Lines [0];
+ h = (int)(line.GetSize ().Height);
+ }
+ if (ellipsize != Pango.EllipsizeMode.None && tl.Layout.Width > 0)
+ // an ellipsized text doesn't exceed layout's width
+ w = Math.Min (w, (int)(tl.Layout.Width / Pango.Scale.PangoScale));
+
return new Size ((double)w, (double)h);
}
View
7 Xwt.Mac/Xwt.Mac/TextLayoutBackendHandler.cs
@@ -47,6 +47,7 @@ class LayoutInfo
public NSFont Font;
public float? Width, Height;
public TextTrimming TextTrimming;
+ public WrapMode WrapMode;
}
public override object Create ()
@@ -84,6 +85,12 @@ public override void SetTrimming (object backend, TextTrimming value)
li.TextTrimming = value;
}
+ public override void SetSetWrapMode (object backend, WrapMode value)
+ {
+ LayoutInfo li = (LayoutInfo)backend;
+ li.WrapMode = value;
+ }
+
public override Size GetSize (object backend)
{
LayoutInfo li = (LayoutInfo)backend;
View
17 Xwt.WPF/Xwt.WPFBackend/TextLayoutBackendHandler.cs
@@ -3,7 +3,7 @@
//
// Author:
// Eric Maupin <ermau@xamarin.com>
-// Lytico (http://limada.sourceforge.net)
+// Lytico (http://www.limada.org)
//
// Copyright (c) 2012 Xamarin, Inc.
//
@@ -86,6 +86,19 @@ public override void SetTrimming (object backend, Xwt.Drawing.TextTrimming textT
}
}
+ public override void SetWrapMode (object backend, Xwt.WrapMode wrapMode)
+ {
+ var t = (TextLayoutBackend)backend;
+ switch (wrapMode) {
+ case Xwt.WrapMode.None:
+ t.FormattedText.MaxLineCount = 1;
+ break;
+ default:
+ t.FormattedText.MaxLineCount = int.MaxValue;
+ break;
+ }
+ }
+
public override Size GetSize (object backend)
{
var t = (TextLayoutBackend)backend;
@@ -165,6 +178,8 @@ public void Rebuild (string newText = null, bool keepWidth = true, bool keepHeig
formattedText.MaxTextWidth = old.MaxTextWidth;
if (old.MaxTextHeight != 0 && keepHeight)
formattedText.MaxTextHeight = old.MaxTextHeight;
+ formattedText.Trimming = old.Trimming;
+ formattedText.MaxLineCount = old.MaxLineCount;
}
if (Font != null)
SetFont (Font);
View
3  Xwt/Xwt.Backends/TextLayoutBackendHandler.cs
@@ -3,7 +3,7 @@
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
-// Lytico (http://limada.sourceforge.net)
+// Lytico (http://www.limada.org)
//
// Copyright (c) 2011 Xamarin Inc
//
@@ -40,6 +40,7 @@ public abstract class TextLayoutBackendHandler: DisposableResourceBackendHandler
public abstract void SetText (object backend, string text);
public abstract void SetFont (object backend, Font font);
public abstract void SetTrimming (object backend, TextTrimming textTrimming);
+ public abstract void SetWrapMode (object backend, WrapMode wrapMode);
public abstract Size GetSize (object backend);
public abstract int GetIndexFromCoordinates (object backend, double x, double y);
public abstract Point GetCoordinateFromIndex (object backend, int index);
View
21 Xwt/Xwt.Drawing/TextLayout.cs
@@ -3,7 +3,7 @@
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
-// Lytico (http://limada.sourceforge.net)
+// Lytico (http://www.limada.org)
//
// Copyright (c) 2011 Xamarin Inc
//
@@ -40,7 +40,8 @@ public sealed class TextLayout: XwtObject, IDisposable
string text;
double width = -1;
double height = -1;
- TextTrimming textTrimming;
+ TextTrimming textTrimming = TextTrimming.Word;
+ WrapMode wrapMode = WrapMode.Word;
List<TextAttribute> attributes;
public TextLayout ()
@@ -98,6 +99,7 @@ internal TextLayoutData GetData ()
Text = text,
Font = font,
TextTrimming = textTrimming,
+ WrapMode = wrapMode,
Attributes = attributes != null ? new List<TextAttribute> (attributes) : null
};
}
@@ -153,6 +155,11 @@ public Size GetSize ()
set { textTrimming = value; handler.SetTrimming (Backend, value); }
}
+ public WrapMode WrapMode {
+ get { return wrapMode; }
+ set { wrapMode = value; handler.SetWrapMode (Backend, value); }
+ }
+
/// <summary>
/// Converts from a X and Y position within the layout to the character at this position.
/// </summary>
@@ -293,7 +300,8 @@ class TextLayoutData
public double Height = -1;
public string Text;
public Font Font;
- public TextTrimming TextTrimming;
+ public TextTrimming TextTrimming = TextTrimming.Word;
+ public WrapMode WrapMode = WrapMode.Word;
public List<TextAttribute> Attributes;
public void InitLayout (TextLayout la)
@@ -306,8 +314,8 @@ public void InitLayout (TextLayout la)
la.Text = Text;
if (Font != null)
la.Font = Font;
- if (TextTrimming != default(TextTrimming))
- la.Trimming = TextTrimming;
+ la.Trimming = TextTrimming;
+ la.WrapMode = WrapMode;
if (Attributes != null) {
foreach (var at in Attributes)
la.AddAttribute (at);
@@ -316,7 +324,8 @@ public void InitLayout (TextLayout la)
public bool Equals (TextLayoutData other)
{
- if (Width != other.Width || Height != other.Height || Text != other.Text || Font != other.Font || TextTrimming != other.TextTrimming)
+ if (Width != other.Width || Height != other.Height || Text != other.Text || Font != other.Font ||
+ TextTrimming != other.TextTrimming || WrapMode != other.WrapMode)
return false;
if (Attributes == null && other.Attributes == null)
return true;
Something went wrong with that request. Please try again.