Add cursor position and selection support to TextEntry
* add properties for cursor position and selection bounds * add SelectedText property (which is writeble to support direct selection changes) * add SelectionChanged event * includes ComboBoxTextEntry support WPF and GTK support is included. Mac has to be added.
This commit is contained in:
Родитель
6f9bfacdf7
Коммит
e515a12d83
|
@ -158,6 +158,75 @@ namespace Xwt.GtkBackend
|
|||
}
|
||||
}
|
||||
|
||||
public int CursorPosition {
|
||||
get {
|
||||
return Widget.Position;
|
||||
}
|
||||
set {
|
||||
Widget.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectionStart {
|
||||
get {
|
||||
int start, end;
|
||||
Widget.GetSelectionBounds (out start, out end);
|
||||
return start;
|
||||
}
|
||||
set {
|
||||
int cacheStart = SelectionStart;
|
||||
int cacheLength = SelectionLength;
|
||||
Widget.GrabFocus ();
|
||||
if (String.IsNullOrEmpty (Text))
|
||||
return;
|
||||
Widget.SelectRegion (value, value + cacheLength);
|
||||
if (cacheStart != value)
|
||||
HandleSelectionChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectionLength {
|
||||
get {
|
||||
int start, end;
|
||||
Widget.GetSelectionBounds (out start, out end);
|
||||
return end - start;
|
||||
}
|
||||
set {
|
||||
int cacheStart = SelectionStart;
|
||||
int cacheLength = SelectionLength;
|
||||
Widget.GrabFocus ();
|
||||
if (String.IsNullOrEmpty (Text))
|
||||
return;
|
||||
Widget.SelectRegion (cacheStart, cacheStart + value);
|
||||
if (cacheLength != value)
|
||||
HandleSelectionChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectedText {
|
||||
get {
|
||||
int start = SelectionStart;
|
||||
int end = start + SelectionLength;
|
||||
if (start == end) return String.Empty;
|
||||
try {
|
||||
return Text.Substring (start, end - start);
|
||||
} catch {
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
set {
|
||||
int cacheSelStart = SelectionStart;
|
||||
int pos = cacheSelStart;
|
||||
if (SelectionLength > 0) {
|
||||
Widget.DeleteSelection ();
|
||||
}
|
||||
Widget.InsertText (value, ref pos);
|
||||
Widget.GrabFocus ();
|
||||
Widget.SelectRegion (cacheSelStart, pos);
|
||||
HandleSelectionChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
public bool MultiLine {
|
||||
get; set;
|
||||
}
|
||||
|
@ -169,6 +238,13 @@ namespace Xwt.GtkBackend
|
|||
switch ((TextEntryEvent)eventId) {
|
||||
case TextEntryEvent.Changed: Widget.Changed += HandleChanged; break;
|
||||
case TextEntryEvent.Activated: Widget.Activated += HandleActivated; break;
|
||||
case TextEntryEvent.SelectionChanged:
|
||||
enableSelectionChangedEvent = true;
|
||||
Widget.MoveCursor += HandleMoveCursor;
|
||||
Widget.ButtonPressEvent += HandleButtonPressEvent;
|
||||
Widget.ButtonReleaseEvent += HandleButtonReleaseEvent;
|
||||
Widget.MotionNotifyEvent += HandleMotionNotifyEvent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +256,13 @@ namespace Xwt.GtkBackend
|
|||
switch ((TextEntryEvent)eventId) {
|
||||
case TextEntryEvent.Changed: Widget.Changed -= HandleChanged; break;
|
||||
case TextEntryEvent.Activated: Widget.Activated -= HandleActivated; break;
|
||||
case TextEntryEvent.SelectionChanged:
|
||||
enableSelectionChangedEvent = false;
|
||||
Widget.MoveCursor -= HandleMoveCursor;
|
||||
Widget.ButtonPressEvent -= HandleButtonPressEvent;
|
||||
Widget.ButtonReleaseEvent -= HandleButtonReleaseEvent;
|
||||
Widget.MotionNotifyEvent -= HandleMotionNotifyEvent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +271,7 @@ namespace Xwt.GtkBackend
|
|||
{
|
||||
ApplicationContext.InvokeUserCode (delegate {
|
||||
EventSink.OnChanged ();
|
||||
EventSink.OnSelectionChanged ();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -198,6 +282,53 @@ namespace Xwt.GtkBackend
|
|||
});
|
||||
}
|
||||
|
||||
bool enableSelectionChangedEvent;
|
||||
void HandleSelectionChanged ()
|
||||
{
|
||||
if (enableSelectionChangedEvent)
|
||||
ApplicationContext.InvokeUserCode (delegate {
|
||||
EventSink.OnSelectionChanged ();
|
||||
});
|
||||
}
|
||||
|
||||
void HandleMoveCursor (object sender, EventArgs e)
|
||||
{
|
||||
HandleSelectionChanged ();
|
||||
}
|
||||
|
||||
int cacheSelectionStart, cacheSelectionLength;
|
||||
bool isMouseSelection;
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
|
||||
{
|
||||
if (args.Event.Button == 1) {
|
||||
HandleSelectionChanged ();
|
||||
cacheSelectionStart = SelectionStart;
|
||||
cacheSelectionLength = SelectionLength;
|
||||
isMouseSelection = true;
|
||||
}
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
void HandleMotionNotifyEvent (object o, Gtk.MotionNotifyEventArgs args)
|
||||
{
|
||||
if (isMouseSelection)
|
||||
if (cacheSelectionStart != SelectionStart || cacheSelectionLength != SelectionLength)
|
||||
HandleSelectionChanged ();
|
||||
cacheSelectionStart = SelectionStart;
|
||||
cacheSelectionLength = SelectionLength;
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
void HandleButtonReleaseEvent (object o, Gtk.ButtonReleaseEventArgs args)
|
||||
{
|
||||
if (args.Event.Button == 1) {
|
||||
isMouseSelection = false;
|
||||
HandleSelectionChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing) {
|
||||
|
|
|
@ -140,6 +140,14 @@ namespace Xwt.Mac
|
|||
}
|
||||
}
|
||||
|
||||
public int CursorPosition { get; set; }
|
||||
|
||||
public int SelectionStart { get; set; }
|
||||
|
||||
public int SelectionLength { get; set; }
|
||||
|
||||
public string SelectedText { get; set; }
|
||||
|
||||
public override void SetFocus ()
|
||||
{
|
||||
Widget.BecomeFirstResponder ();
|
||||
|
|
|
@ -95,6 +95,78 @@ namespace Xwt.WPFBackend
|
|||
}
|
||||
}
|
||||
|
||||
protected TextBox TextBox {
|
||||
get { return combobox.Template.FindName ("PART_EditableTextBox", combobox) as TextBox; }
|
||||
}
|
||||
|
||||
public int CursorPosition {
|
||||
get {
|
||||
if (ReadOnly)
|
||||
return 0;
|
||||
else
|
||||
return TextBox.SelectionStart;
|
||||
}
|
||||
set {
|
||||
if (!ReadOnly) {
|
||||
TextBox.Focus();
|
||||
TextBox.SelectionStart = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectionStart {
|
||||
get {
|
||||
if (ReadOnly)
|
||||
return 0;
|
||||
else
|
||||
return TextBox.SelectionStart;
|
||||
}
|
||||
set {
|
||||
if (!ReadOnly) {
|
||||
int cacheLength = SelectionLength;
|
||||
TextBox.Focus ();
|
||||
TextBox.SelectionStart = value;
|
||||
TextBox.SelectionLength = cacheLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectionLength {
|
||||
get {
|
||||
if (ReadOnly)
|
||||
return this.SelectedText.Length;
|
||||
else
|
||||
return TextBox.SelectionLength;
|
||||
}
|
||||
set {
|
||||
if (!ReadOnly) {
|
||||
int cacheStart = SelectionStart;
|
||||
TextBox.Focus ();
|
||||
TextBox.SelectionLength = value;
|
||||
TextBox.SelectionStart = cacheStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectedText {
|
||||
get {
|
||||
if (ReadOnly)
|
||||
return this.SelectedText;
|
||||
else
|
||||
return TextBox.SelectedText;
|
||||
}
|
||||
set {
|
||||
if (!ReadOnly) {
|
||||
int cacheStart = SelectionStart;
|
||||
int cacheLength = SelectionLength;
|
||||
TextBox.Focus ();
|
||||
TextBox.SelectionStart = cacheStart;
|
||||
TextBox.SelectionLength = cacheLength;
|
||||
TextBox.SelectedText = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool MultiLine { get; set; }
|
||||
|
||||
public override void EnableEvent (object eventId)
|
||||
|
@ -105,10 +177,19 @@ namespace Xwt.WPFBackend
|
|||
case TextEntryEvent.Changed:
|
||||
this.combobox.TextChanged += OnTextChanged;
|
||||
break;
|
||||
case TextEntryEvent.SelectionChanged:
|
||||
combobox.Loaded += HandleLoaded;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleLoaded (object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (TextBox != null)
|
||||
TextBox.SelectionChanged += OnSelectionChanged;
|
||||
}
|
||||
|
||||
public override void DisableEvent (object eventId)
|
||||
{
|
||||
base.DisableEvent (eventId);
|
||||
|
@ -117,6 +198,10 @@ namespace Xwt.WPFBackend
|
|||
case TextEntryEvent.Changed:
|
||||
this.combobox.TextChanged -= OnTextChanged;
|
||||
break;
|
||||
case TextEntryEvent.SelectionChanged:
|
||||
if (TextBox != null)
|
||||
TextBox.SelectionChanged -= OnSelectionChanged;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +218,11 @@ namespace Xwt.WPFBackend
|
|||
Context.InvokeUserCode (TextEntryEventSink.OnChanged);
|
||||
}
|
||||
|
||||
private void OnSelectionChanged (object s, EventArgs e)
|
||||
{
|
||||
Context.InvokeUserCode (TextEntryEventSink.OnSelectionChanged);
|
||||
}
|
||||
|
||||
private void UpdatePlaceholder (string newPlaceholder, bool focused)
|
||||
{
|
||||
if (Text == this.placeholderText)
|
||||
|
|
|
@ -90,6 +90,44 @@ namespace Xwt.WPFBackend
|
|||
set { TextBox.ShowFrame = value; }
|
||||
}
|
||||
|
||||
public int CursorPosition {
|
||||
get {
|
||||
return TextBox.SelectionStart;
|
||||
}
|
||||
set {
|
||||
TextBox.SelectionStart = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectionStart {
|
||||
get {
|
||||
return TextBox.SelectionStart;
|
||||
}
|
||||
set {
|
||||
TextBox.Focus();
|
||||
TextBox.Select(value, SelectionLength);
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectionLength {
|
||||
get {
|
||||
return TextBox.SelectionLength;
|
||||
}
|
||||
set {
|
||||
TextBox.Focus();
|
||||
TextBox.Select(SelectionStart, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectedText {
|
||||
get {
|
||||
return TextBox.SelectedText;
|
||||
}
|
||||
set {
|
||||
TextBox.SelectedText = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MultiLine {
|
||||
get { return multiline; }
|
||||
set {
|
||||
|
@ -123,6 +161,9 @@ namespace Xwt.WPFBackend
|
|||
case TextEntryEvent.Activated:
|
||||
TextBox.KeyDown += OnActivated;
|
||||
break;
|
||||
case TextEntryEvent.SelectionChanged:
|
||||
TextBox.SelectionChanged += OnSelectionChanged;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +182,9 @@ namespace Xwt.WPFBackend
|
|||
case TextEntryEvent.Activated:
|
||||
TextBox.KeyDown -= OnActivated;
|
||||
break;
|
||||
case TextEntryEvent.SelectionChanged:
|
||||
TextBox.SelectionChanged -= OnSelectionChanged;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,5 +208,10 @@ namespace Xwt.WPFBackend
|
|||
{
|
||||
Context.InvokeUserCode (EventSink.OnChanged);
|
||||
}
|
||||
|
||||
private void OnSelectionChanged (object s, EventArgs e)
|
||||
{
|
||||
Context.InvokeUserCode (EventSink.OnSelectionChanged);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,18 +35,24 @@ namespace Xwt.Backends
|
|||
bool ReadOnly { get; set; }
|
||||
bool ShowFrame { get; set; }
|
||||
bool MultiLine { get; set; }
|
||||
int CursorPosition { get; set; }
|
||||
int SelectionStart { get; set; }
|
||||
int SelectionLength { get; set; }
|
||||
string SelectedText { get; set; }
|
||||
}
|
||||
|
||||
public interface ITextEntryEventSink: IWidgetEventSink
|
||||
{
|
||||
void OnChanged ();
|
||||
void OnActivated ();
|
||||
void OnSelectionChanged ();
|
||||
}
|
||||
|
||||
public enum TextEntryEvent
|
||||
{
|
||||
Changed,
|
||||
Activated
|
||||
Activated,
|
||||
SelectionChanged
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,12 +32,13 @@ namespace Xwt
|
|||
[BackendType (typeof(ITextEntryBackend))]
|
||||
public class TextEntry: Widget
|
||||
{
|
||||
EventHandler changed, activated;
|
||||
EventHandler changed, activated, selectionChanged;
|
||||
|
||||
static TextEntry ()
|
||||
{
|
||||
MapEvent (TextEntryEvent.Changed, typeof(TextEntry), "OnChanged");
|
||||
MapEvent (TextEntryEvent.Activated, typeof(TextEntry), "OnActivated");
|
||||
MapEvent (TextEntryEvent.SelectionChanged, typeof(TextEntry), "OnSelectionChanged");
|
||||
}
|
||||
|
||||
protected new class WidgetBackendHost: Widget.WidgetBackendHost, ITextEntryEventSink
|
||||
|
@ -51,6 +52,11 @@ namespace Xwt
|
|||
{
|
||||
((TextEntry)Parent).OnActivated (EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void OnSelectionChanged ()
|
||||
{
|
||||
((TextEntry)Parent).OnSelectionChanged (EventArgs.Empty);
|
||||
}
|
||||
|
||||
public override Size GetDefaultNaturalSize ()
|
||||
{
|
||||
|
@ -99,6 +105,30 @@ namespace Xwt
|
|||
get { return Backend.ShowFrame; }
|
||||
set { Backend.ShowFrame = value; }
|
||||
}
|
||||
|
||||
[DefaultValue (0)]
|
||||
public int CursorPosition {
|
||||
get { return Backend.CursorPosition; }
|
||||
set { Backend.CursorPosition = value; }
|
||||
}
|
||||
|
||||
[DefaultValue (0)]
|
||||
public int SelectionStart {
|
||||
get { return Backend.SelectionStart; }
|
||||
set { Backend.SelectionStart = value; }
|
||||
}
|
||||
|
||||
[DefaultValue (0)]
|
||||
public int SelectionLength {
|
||||
get { return Backend.SelectionLength; }
|
||||
set { Backend.SelectionLength = value; }
|
||||
}
|
||||
|
||||
[DefaultValue ("")]
|
||||
public string SelectedText {
|
||||
get { return Backend.SelectedText; }
|
||||
set { Backend.SelectedText = value; }
|
||||
}
|
||||
|
||||
[DefaultValue (true)]
|
||||
public bool MultiLine {
|
||||
|
@ -123,6 +153,23 @@ namespace Xwt
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual void OnSelectionChanged (EventArgs e)
|
||||
{
|
||||
if (selectionChanged != null)
|
||||
selectionChanged (this, e);
|
||||
}
|
||||
|
||||
public event EventHandler SelectionChanged {
|
||||
add {
|
||||
BackendHost.OnBeforeEventAdd (TextEntryEvent.SelectionChanged, selectionChanged);
|
||||
selectionChanged += value;
|
||||
}
|
||||
remove {
|
||||
selectionChanged -= value;
|
||||
BackendHost.OnAfterEventRemove (TextEntryEvent.SelectionChanged, selectionChanged);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnActivated (EventArgs e)
|
||||
{
|
||||
if (activated != null)
|
||||
|
|
Загрузка…
Ссылка в новой задаче