diff --git a/Cairo/Perspex.Cairo/Media/FormattedTextImpl.cs b/Cairo/Perspex.Cairo/Media/FormattedTextImpl.cs index 7dc670b37a..26dd56363c 100644 --- a/Cairo/Perspex.Cairo/Media/FormattedTextImpl.cs +++ b/Cairo/Perspex.Cairo/Media/FormattedTextImpl.cs @@ -56,6 +56,11 @@ namespace Perspex.Cairo.Media this.Layout.Dispose(); } + public IEnumerable GetLines() + { + return new FormattedTextLine[0]; + } + public TextHitTestResult HitTestPoint(Point point) { int textPosition; diff --git a/Perspex.Controls/TextBox.cs b/Perspex.Controls/TextBox.cs index 1f1c7795e2..b9ae4bf980 100644 --- a/Perspex.Controls/TextBox.cs +++ b/Perspex.Controls/TextBox.cs @@ -137,6 +137,44 @@ namespace Perspex.Controls } } + private void MoveHome(ModifierKeys modifiers) + { + var caretIndex = this.CaretIndex; + + if ((modifiers & ModifierKeys.Control) != 0) + { + caretIndex = 0; + } + else + { + var lines = this.textBoxView.FormattedText.GetLines(); + var pos = 0; + + foreach (var line in lines) + { + if (pos + line.Length > caretIndex) + { + break; + } + + pos += line.Length; + } + + caretIndex = pos; + } + + this.CaretIndex = caretIndex; + + if ((modifiers & ModifierKeys.Shift) != 0) + { + this.SelectionEnd = caretIndex; + } + else + { + this.SelectionStart = this.SelectionEnd = caretIndex; + } + } + private void OnKeyDown(object sender, KeyEventArgs e) { string text = this.Text ?? string.Empty; @@ -162,7 +200,7 @@ namespace Perspex.Controls break; case Key.Home: - this.CaretIndex = 0; + this.MoveHome(e.Device.Modifiers); break; case Key.End: @@ -257,7 +295,8 @@ namespace Perspex.Controls private void OnPointerPressed(object sender, PointerEventArgs e) { var point = e.GetPosition(this.textBoxView); - this.CaretIndex = this.textBoxView.GetCaretIndex(point); + this.CaretIndex = this.SelectionStart = this.SelectionEnd = + this.textBoxView.GetCaretIndex(point); } } } diff --git a/Perspex.Controls/TextBoxView.cs b/Perspex.Controls/TextBoxView.cs index 5536c04e89..8bf1bc024b 100644 --- a/Perspex.Controls/TextBoxView.cs +++ b/Perspex.Controls/TextBoxView.cs @@ -36,6 +36,11 @@ namespace Perspex.Controls parent.GetObservable(TextBox.CaretIndexProperty).Subscribe(_ => this.CaretMoved()); } + public new FormattedText FormattedText + { + get { return base.FormattedText; } + } + public int GetCaretIndex(Point point) { var hit = this.FormattedText.HitTestPoint(point); diff --git a/Perspex.SceneGraph/Media/FormattedText.cs b/Perspex.SceneGraph/Media/FormattedText.cs index 114a480551..af1f9ff030 100644 --- a/Perspex.SceneGraph/Media/FormattedText.cs +++ b/Perspex.SceneGraph/Media/FormattedText.cs @@ -69,6 +69,11 @@ namespace Perspex.Media this.PlatformImpl.Dispose(); } + public IEnumerable GetLines() + { + return this.PlatformImpl.GetLines(); + } + public TextHitTestResult HitTestPoint(Point point) { return this.PlatformImpl.HitTestPoint(point); diff --git a/Perspex.SceneGraph/Media/FormattedTextLine.cs b/Perspex.SceneGraph/Media/FormattedTextLine.cs new file mode 100644 index 0000000000..01c22c2ae2 --- /dev/null +++ b/Perspex.SceneGraph/Media/FormattedTextLine.cs @@ -0,0 +1,21 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Media +{ + public class FormattedTextLine + { + public FormattedTextLine(int length, double height) + { + this.Length = length; + this.Height = height; + } + + public int Length { get; private set; } + + public double Height { get; private set; } + } +} diff --git a/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/Perspex.SceneGraph/Perspex.SceneGraph.csproj index 60bd42f23a..b070c4bef2 100644 --- a/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -46,6 +46,7 @@ + diff --git a/Perspex.SceneGraph/Platform/IFormattedTextImpl.cs b/Perspex.SceneGraph/Platform/IFormattedTextImpl.cs index f6be627172..e69e65858f 100644 --- a/Perspex.SceneGraph/Platform/IFormattedTextImpl.cs +++ b/Perspex.SceneGraph/Platform/IFormattedTextImpl.cs @@ -14,6 +14,8 @@ namespace Perspex.Platform { Size Constraint { get; set; } + IEnumerable GetLines(); + TextHitTestResult HitTestPoint(Point point); Rect HitTestTextPosition(int index); diff --git a/Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs b/Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs index fbd166cb7e..614eaab374 100644 --- a/Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs @@ -57,6 +57,12 @@ namespace Perspex.Direct2D1.Media this.TextLayout.Dispose(); } + public IEnumerable GetLines() + { + var result = this.TextLayout.GetLineMetrics(); + return from line in result select new FormattedTextLine(line.Length, line.Height); + } + public TextHitTestResult HitTestPoint(Point point) { SharpDX.Bool isTrailingHit;