Skip to content

Commit 4c99da5

Browse files
authored
Merge pull request #2712 from cwensley/curtis/mac-textarea-scrolltoend-fixes
TextArea.ScrollToStart/End fixes
2 parents 94fcd16 + a88b0c4 commit 4c99da5

File tree

17 files changed

+191
-72
lines changed

17 files changed

+191
-72
lines changed

lib/monomac

src/Eto.Gtk/Forms/Controls/TextAreaHandler.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -371,20 +371,32 @@ public virtual void ScrollTo(Range<int> range)
371371
Control.ScrollToMark(mark, 0, false, 0, 0);
372372
}
373373

374+
double GetScrollX() => Control.Direction switch
375+
{
376+
Gtk.TextDirection.Rtl => Control.Justification switch
377+
{
378+
Gtk.Justification.Right => scroll.Hadjustment.Lower,
379+
Gtk.Justification.Center => (scroll.Hadjustment.Upper - scroll.Hadjustment.Lower - scroll.Hadjustment.PageSize) / 2,
380+
_ => scroll.Hadjustment.Upper,
381+
},
382+
_ => Control.Justification switch
383+
{
384+
Gtk.Justification.Right => scroll.Hadjustment.Upper,
385+
Gtk.Justification.Center => (scroll.Hadjustment.Upper - scroll.Hadjustment.Lower - scroll.Hadjustment.PageSize) / 2,
386+
_ => scroll.Hadjustment.Lower,
387+
},
388+
};
389+
374390
public virtual void ScrollToEnd()
375391
{
376-
var end = Control.Buffer.EndIter;
377-
var mark = Control.Buffer.CreateMark(null, end, false);
378-
Control.ScrollToMark(mark, 0, false, 0, 0);
392+
scroll.Vadjustment.Value = scroll.Vadjustment.Upper - scroll.Vadjustment.PageSize;
393+
scroll.Hadjustment.Value = GetScrollX();
379394
}
380395

381396
public virtual void ScrollToStart()
382397
{
383-
var end = Control.Buffer.StartIter;
384-
var mark = Control.Buffer.CreateMark(null, end, false);
385-
Control.ScrollToMark(mark, 0, false, 0, 0);
386-
}
387-
388-
398+
scroll.Vadjustment.Value = scroll.Vadjustment.Lower;
399+
scroll.Hadjustment.Value = GetScrollX();
400+
}
389401
}
390402
}

src/Eto.Mac/Forms/Controls/TextAreaHandler.cs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,40 @@ public BorderType Border
452452
}
453453

454454
public int TextLength => (int)Control.TextStorage.Length;
455-
456-
public void ScrollTo(Range<int> range) => Control.ScrollRangeToVisible(range.ToNS());
457455

458-
public void ScrollToStart() => ScrollTo(new Range<int>(0));
456+
public void ScrollTo(Range<int> range)
457+
{
458+
var nsRange = range.ToNS();
459+
Control.LayoutManager.EnsureLayoutForCharacterRange(nsRange);
460+
Control.ScrollRangeToVisible(nsRange);
461+
}
462+
463+
public void ScrollToStart()
464+
{
465+
Control.LayoutManager.EnsureLayoutForCharacterRange(new NSRange(0, Control.TextStorage.Length));
466+
Control.ScrollRectToVisible(new CGRect(GetScrollX(), 0, 1, 1));
467+
}
468+
469+
nfloat GetScrollX() => Control.UserInterfaceLayoutDirection switch
470+
{
471+
NSUserInterfaceLayoutDirection.RightToLeft => Control.Alignment switch
472+
{
473+
NSTextAlignment.Right => Control.Bounds.Left,
474+
NSTextAlignment.Center => Control.Bounds.GetMidX() - Scroll.DocumentVisibleRect.Width / 2,
475+
_ => Control.Bounds.Right,
476+
},
477+
_ => Control.Alignment switch
478+
{
479+
NSTextAlignment.Right => Control.Bounds.Right,
480+
NSTextAlignment.Center => Control.Bounds.GetMidX() - Scroll.DocumentVisibleRect.Width / 2,
481+
_ => Control.Bounds.Left,
482+
},
483+
};
459484

460-
public void ScrollToEnd() => ScrollTo(Range.FromLength(TextLength, 0));
485+
public void ScrollToEnd()
486+
{
487+
Control.LayoutManager.EnsureLayoutForCharacterRange(new NSRange(0, Control.TextStorage.Length));
488+
Control.ScrollPoint(new CGPoint(GetScrollX(), Control.Bounds.Bottom));
489+
}
461490
}
462491
}

src/Eto.WinForms/Forms/Controls/TextAreaHandler.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,15 @@ public override bool ShouldBubbleEvent(swf.Message msg)
213213
return !intrinsicEvents.Contains((Win32.WM)msg.Msg) && base.ShouldBubbleEvent(msg);
214214
}
215215

216+
TextAlignment _textAlignment;
217+
216218
public TextAlignment TextAlignment
217219
{
218-
get { return Control.SelectionAlignment.ToEto(); }
220+
get => _textAlignment;
219221
set
220222
{
221223
if (value == TextAlignment) return;
224+
_textAlignment = value;
222225
var sel = Selection;
223226
Control.SelectAll();
224227
Control.SelectionAlignment = value.ToSWF();
@@ -277,18 +280,23 @@ public void ScrollTo(Range<int> range)
277280
Win32.SendMessage(Control.Handle, Win32.WM.EM_SETSCROLLPOS, IntPtr.Zero, ref scrollPosition);
278281
}
279282

283+
Win32.SB GetScrollX() => Control.RightToLeft switch
284+
{
285+
swf.RightToLeft.Yes => Win32.SB.RIGHT,
286+
_ => Win32.SB.LEFT
287+
};
288+
280289
public void ScrollToStart()
281290
{
282291
Win32.SendMessage(Control.Handle, Win32.WM.VSCROLL, (IntPtr)Win32.SB.TOP, IntPtr.Zero);
283-
Win32.SendMessage(Control.Handle, Win32.WM.HSCROLL, (IntPtr)Win32.SB.LEFT, IntPtr.Zero);
292+
Win32.SendMessage(Control.Handle, Win32.WM.HSCROLL, (IntPtr)GetScrollX(), IntPtr.Zero);
284293
}
285294

286295
public void ScrollToEnd()
287296
{
288297
Win32.SendMessage(Control.Handle, Win32.WM.VSCROLL, (IntPtr)Win32.SB.BOTTOM, IntPtr.Zero);
289-
Win32.SendMessage(Control.Handle, Win32.WM.HSCROLL, (IntPtr)Win32.SB.LEFT, IntPtr.Zero);
298+
Win32.SendMessage(Control.Handle, Win32.WM.HSCROLL, (IntPtr)GetScrollX(), IntPtr.Zero);
290299
}
291300

292-
293301
}
294302
}

src/Eto.Wpf/Forms/Controls/TextAreaHandler.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,33 @@ public virtual BorderType Border
258258

259259
public abstract void ScrollTo(Range<int> range);
260260

261-
public virtual void ScrollToEnd() => Control.ScrollToEnd();
261+
double GetScrollX() => Control.FlowDirection switch
262+
{
263+
sw.FlowDirection.RightToLeft => Control.HorizontalContentAlignment switch
264+
{
265+
sw.HorizontalAlignment.Right => 0,
266+
sw.HorizontalAlignment.Center => (Control.ExtentWidth - Control.ViewportWidth) / 2,
267+
_ => Control.ExtentWidth,
268+
},
269+
_ => Control.HorizontalContentAlignment switch
270+
{
271+
sw.HorizontalAlignment.Right => Control.ExtentWidth,
272+
sw.HorizontalAlignment.Center => (Control.ExtentWidth - Control.ViewportWidth) / 2,
273+
_ => 0,
274+
},
275+
};
276+
277+
public virtual void ScrollToEnd()
278+
{
279+
Control.ScrollToVerticalOffset(Control.ExtentHeight);
280+
Control.ScrollToHorizontalOffset(GetScrollX());
281+
}
262282

263-
public virtual void ScrollToStart() => Control.ScrollToHome();
283+
public virtual void ScrollToStart()
284+
{
285+
Control.ScrollToVerticalOffset(0);
286+
Control.ScrollToHorizontalOffset(GetScrollX());
287+
}
264288

265289
public abstract int TextLength { get; }
266290

src/Eto/Forms/Controls/TextArea.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,12 +320,12 @@ public void Append(string text, bool scrollToCursor = false)
320320
public void ScrollTo(Range<int> range) => Handler.ScrollTo(range);
321321

322322
/// <summary>
323-
/// Scrolls to the start of the text in the text area.
323+
/// Scrolls to the start of the text aligned on the same horizontal side as <see cref="TextAlignment"/>.
324324
/// </summary>
325325
public void ScrollToStart() => Handler.ScrollToStart();
326326

327327
/// <summary>
328-
/// Scrolls to the end of the text in the text area.
328+
/// Scrolls to the end of the text aligned on the same horizontal side as <see cref="TextAlignment"/>.
329329
/// </summary>
330330
public void ScrollToEnd() => Handler.ScrollToEnd();
331331

test/Eto.Test/Handlers/TabControlHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public TabControlHandler()
3030
},
3131
};
3232

33-
ContentPanel = new Panel { BackgroundColor = Colors.White };
33+
ContentPanel = new Panel { BackgroundColor = SystemColors.ControlBackground };
3434
var layout = new DynamicLayout { Padding = Padding.Empty, Spacing = Size.Empty };
3535
layout.BeginHorizontal();
3636
layout.Add(tabs);

test/Eto.Test/LoremGenerator.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace Eto.Test
7+
{
8+
public static class LoremGenerator
9+
{
10+
private static readonly string[] Words = new[]
11+
{
12+
"lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do",
13+
"eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua", "ut",
14+
"enim", "ad", "minim", "veniam", "quis", "nostrud", "exercitation", "ullamco", "laboris",
15+
"nisi", "ut", "aliquip", "ex", "ea", "commodo", "consequat", "duis", "aute", "irure", "dolor",
16+
"in", "reprehenderit", "in", "voluptate", "velit", "esse", "cillum", "dolore", "eu", "fugiat",
17+
"nulla", "pariatur", "excepteur", "sint", "occaecat", "cupidatat", "non", "proident", "sunt",
18+
"in", "culpa", "qui", "officia", "deserunt", "mollit", "anim", "id", "est", "laborum"
19+
};
20+
21+
public static string Generate(int wordCount, bool randomize = true)
22+
{
23+
var random = new Random();
24+
var result = new List<string>();
25+
26+
for (int i = 0; i < wordCount; i++)
27+
{
28+
var word = Words[randomize ? random.Next(Words.Length) : i % Words.Length];
29+
result.Add(word);
30+
}
31+
32+
return string.Join(" ", result);
33+
}
34+
35+
public static string GenerateLines(int lineCount, int maxWordsPerLine, bool randomize = true)
36+
{
37+
return GenerateLines(lineCount, 0, maxWordsPerLine, randomize);
38+
}
39+
public static string GenerateLines(int lineCount, int minWordsPerLine, int maxWordsPerLine, bool randomize = true)
40+
{
41+
var random = new Random();
42+
var result = new List<string>();
43+
44+
for (int i = 0; i < lineCount; i++)
45+
{
46+
var line = Generate(random.Next(minWordsPerLine, maxWordsPerLine), randomize);
47+
result.Add(line);
48+
}
49+
50+
return string.Join("\n", result);
51+
}
52+
}
53+
}

test/Eto.Test/Sections/Controls/LabelSection.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Control MiddleLabel()
6262
Text = "Middle Center Align",
6363
TextAlignment = TextAlignment.Center,
6464
VerticalAlignment = VerticalAlignment.Center,
65-
BackgroundColor = Colors.AliceBlue
65+
BackgroundColor = Colors.Gray
6666
};
6767
}
6868

@@ -73,7 +73,7 @@ Control BottomLabel()
7373
Text = "Bottom Center Align",
7474
TextAlignment = TextAlignment.Center,
7575
VerticalAlignment = VerticalAlignment.Bottom,
76-
BackgroundColor = Colors.AliceBlue
76+
BackgroundColor = Colors.Gray
7777
};
7878
}
7979

@@ -125,7 +125,7 @@ Control WrapLabel()
125125
{
126126
var label = new Label
127127
{
128-
Text = Utility.LoremTextWithTwoParagraphs
128+
Text = LoremGenerator.GenerateLines(2, 50, 100)
129129
};
130130

131131
var wrapDropDown = new EnumDropDown<WrapMode>();

test/Eto.Test/Sections/Controls/RichTextAreaSection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ public class RichTextAreaSection : Panel
55
{
66
public static string RtfString = "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1343\\cocoasubrtf160\r\n{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;}\r\n{\\colortbl;\\red255\\green255\\blue255;}\r\n\\margl1440\\margr1440\\vieww10800\\viewh8400\\viewkind0\r\n\\pard\\tx566\\tx1133\\tx1700\\tx2267\\tx2834\\tx3401\\tx3968\\tx4535\\tx5102\\tx5669\\tx6236\\tx6803\\pardirnatural\r\n\r\n\\f0\\fs24 \\cf0 This is some \r\n\\b bold\r\n\\b0 , \r\n\\i italic\r\n\\i0 , and \\ul underline\\ulnone text! \\\r\n\\\r\n\\pard\\tx566\\tx1133\\tx1700\\tx2267\\tx2834\\tx3401\\tx3968\\tx4535\\tx5102\\tx5669\\tx6236\\tx6803\\pardirnatural\\qr\r\n\\cf0 Some other text}";
77

8-
static string LastText = Utility.LoremTextWithTwoParagraphs;
8+
static string LastText = LoremGenerator.GenerateLines(4, 50);
99

1010
public RichTextAreaSection()
1111
{

0 commit comments

Comments
 (0)