Skip to content

Commit

Permalink
fix: TextBox positioning and selection on GTK
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Jan 14, 2022
1 parent b295720 commit 85f24f0
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
#nullable enable

using System;
using System.Diagnostics;
using System.Linq;
using Gtk;
using Uno.UI.Xaml.Controls.Extensions;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using GLib;
using Pango;
using Uno.Disposables;
using Uno.UI.Runtime.Skia.GTK.UI.Text;
using GtkWindow = Gtk.Window;
using Object = GLib.Object;
using Scale = Pango.Scale;
using System.Diagnostics;
using Uno.UI.Xaml.Controls.Extensions;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Gdk;
using Point = Windows.Foundation.Point;
using GdkPoint = Gdk.Point;
using Size = Windows.Foundation.Size;
using GdkSize = Gdk.Size;
using GtkWindow = Gtk.Window;
using Point = Windows.Foundation.Point;
using Scale = Pango.Scale;

namespace Uno.UI.Runtime.Skia.GTK.Extensions.UI.Xaml.Controls
{
Expand All @@ -35,6 +32,9 @@ internal class TextBoxViewExtension : ITextBoxViewExtension
private GdkPoint _lastPosition = new GdkPoint(-1, -1);
private GdkSize _lastSize = new GdkSize(-1, -1);

private int? _requestedSelectionStart = null;
private int? _requestedSelectionLength = null;

private readonly SerialDisposable _textChangedDisposable = new SerialDisposable();

public TextBoxViewExtension(TextBoxView owner, GtkWindow window)
Expand All @@ -61,10 +61,17 @@ public void StartEntry()
return;
}

// Selection is now handled by native control
_requestedSelectionStart = null;
_requestedSelectionLength = null;

_contentElement = textBox.ContentElement;
EnsureWidget(textBox);
var textInputLayer = GetWindowTextInputLayer();
textInputLayer.Put(_currentInputWidget!, 0, 0);
if (_currentInputWidget!.Parent != textInputLayer)
{
textInputLayer.Put(_currentInputWidget!, 0, 0);
}
_lastSize = new GdkSize(-1, -1);
_lastPosition = new GdkPoint(-1, -1);
UpdateNativeView();
Expand Down Expand Up @@ -151,7 +158,7 @@ public void UpdateSize()
var width = (int)_contentElement.ActualWidth;
var height = (int)_contentElement.ActualHeight;

if (_lastSize.Width != width && _lastSize.Height != height)
if (_lastSize.Width != width || _lastSize.Height != height)
{
_lastSize = new GdkSize(width, height);
_currentInputWidget?.SetSizeRequest(_lastSize.Width, _lastSize.Height);
Expand All @@ -176,7 +183,7 @@ public void UpdatePosition()
var pointX = point.X;
var pointY = point.Y;

if (_lastPosition.X != pointX && _lastPosition.Y != pointY)
if (_lastPosition.X != pointX || _lastPosition.Y != pointY)
{
_lastPosition = new GdkPoint((int)pointX, (int)pointY);
textInputLayer.Move(_currentInputWidget, _lastPosition.X, _lastPosition.Y);
Expand Down Expand Up @@ -321,14 +328,34 @@ public void Select(int start, int length)
EnsureWidget(textBox);
if (_currentInputWidget is Entry entry)
{
textBox.UpdateFocusState(FocusState.Programmatic);
entry.SelectRegion(start_pos: start, end_pos: start + length);
if (textBox.FocusState == FocusState.Unfocused)
{
// Native control can't handle selection until it is part of visual tree.
// Use managed selection until then.
_requestedSelectionStart = textBox.Text.Length >= start ? start : textBox.Text.Length;
_requestedSelectionLength = textBox.Text.Length >= start + length ? length : textBox.Text.Length - start;
}
else
{
entry.SelectRegion(start_pos: start, end_pos: start + length);
}
}
// TODO: Handle TextView..
}

public int GetSelectionStart()
{
var textBox = _owner.TextBox;
if (textBox == null)
{
return 0;
}

if (textBox.FocusState == FocusState.Unfocused)
{
return _requestedSelectionStart ?? 0;
}

if (_currentInputWidget is Entry entry)
{
entry.GetSelectionBounds(out var start, out _);
Expand All @@ -345,6 +372,17 @@ public int GetSelectionStart()

public int GetSelectionLength()
{
var textBox = _owner.TextBox;
if (textBox == null)
{
return 0;
}

if (textBox.FocusState == FocusState.Unfocused)
{
return _requestedSelectionLength ?? 0;
}

if (_currentInputWidget is Entry entry)
{
entry.GetSelectionBounds(out var start, out var end);
Expand Down
5 changes: 4 additions & 1 deletion src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,10 @@ internal override void UpdateFocusState(FocusState focusState)
{
var oldValue = FocusState;
base.UpdateFocusState(focusState);
OnFocusStateChanged(oldValue, focusState, initial: false);
if (oldValue != focusState)
{
OnFocusStateChanged(oldValue, focusState, initial: false);
}
}

private void OnFocusStateChanged(FocusState oldValue, FocusState newValue, bool initial)
Expand Down

0 comments on commit 85f24f0

Please sign in to comment.