|
@@ -9,334 +9,394 @@ using System.Globalization;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
|
|
|
-namespace Terminal.Gui {
|
|
|
+namespace Terminal.Gui;
|
|
|
+/// <summary>
|
|
|
+/// Time editing <see cref="View"/>
|
|
|
+/// </summary>
|
|
|
+/// <remarks>
|
|
|
+/// The <see cref="TimeField"/> <see cref="View"/> provides time editing functionality with mouse support.
|
|
|
+/// </remarks>
|
|
|
+public class TimeField : TextField {
|
|
|
+ TimeSpan _time;
|
|
|
+ bool _isShort;
|
|
|
+
|
|
|
+ int _longFieldLen = 8;
|
|
|
+ int _shortFieldLen = 5;
|
|
|
+ string _sepChar;
|
|
|
+ string _longFormat;
|
|
|
+ string _shortFormat;
|
|
|
+
|
|
|
+ int _fieldLen => _isShort ? _shortFieldLen : _longFieldLen;
|
|
|
+ string _format => _isShort ? _shortFormat : _longFormat;
|
|
|
+
|
|
|
/// <summary>
|
|
|
- /// Time editing <see cref="View"/>
|
|
|
+ /// TimeChanged event, raised when the Date has changed.
|
|
|
/// </summary>
|
|
|
/// <remarks>
|
|
|
- /// The <see cref="TimeField"/> <see cref="View"/> provides time editing functionality with mouse support.
|
|
|
+ /// This event is raised when the <see cref="Time"/> changes.
|
|
|
/// </remarks>
|
|
|
- public class TimeField : TextField {
|
|
|
- TimeSpan time;
|
|
|
- bool isShort;
|
|
|
-
|
|
|
- int longFieldLen = 8;
|
|
|
- int shortFieldLen = 5;
|
|
|
- string sepChar;
|
|
|
- string longFormat;
|
|
|
- string shortFormat;
|
|
|
-
|
|
|
- int fieldLen => isShort ? shortFieldLen : longFieldLen;
|
|
|
- string format => isShort ? shortFormat : longFormat;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// TimeChanged event, raised when the Date has changed.
|
|
|
- /// </summary>
|
|
|
- /// <remarks>
|
|
|
- /// This event is raised when the <see cref="Time"/> changes.
|
|
|
- /// </remarks>
|
|
|
- /// <remarks>
|
|
|
- /// The passed <see cref="EventArgs"/> is a <see cref="DateTimeEventArgs{T}"/> containing the old value, new value, and format string.
|
|
|
- /// </remarks>
|
|
|
- public event EventHandler<DateTimeEventArgs<TimeSpan>> TimeChanged;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Absolute"/> positioning.
|
|
|
- /// </summary>
|
|
|
- /// <param name="x">The x coordinate.</param>
|
|
|
- /// <param name="y">The y coordinate.</param>
|
|
|
- /// <param name="time">Initial time.</param>
|
|
|
- /// <param name="isShort">If true, the seconds are hidden. Sets the <see cref="IsShortFormat"/> property.</param>
|
|
|
- public TimeField (int x, int y, TimeSpan time, bool isShort = false) : base (x, y, isShort ? 7 : 10, "")
|
|
|
- {
|
|
|
- Initialize (time, isShort);
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Computed"/> positioning.
|
|
|
- /// </summary>
|
|
|
- /// <param name="time">Initial time</param>
|
|
|
- public TimeField (TimeSpan time) : base (string.Empty)
|
|
|
- {
|
|
|
- Width = fieldLen + 2;
|
|
|
- Initialize (time);
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Computed"/> positioning.
|
|
|
- /// </summary>
|
|
|
- public TimeField () : this (time: TimeSpan.MinValue) { }
|
|
|
-
|
|
|
- void Initialize (TimeSpan time, bool isShort = false)
|
|
|
- {
|
|
|
- CultureInfo cultureInfo = CultureInfo.CurrentCulture;
|
|
|
- sepChar = cultureInfo.DateTimeFormat.TimeSeparator;
|
|
|
- longFormat = $" hh\\{sepChar}mm\\{sepChar}ss";
|
|
|
- shortFormat = $" hh\\{sepChar}mm";
|
|
|
- this.isShort = isShort;
|
|
|
- Time = time;
|
|
|
- CursorPosition = 1;
|
|
|
- TextChanged += TextField_TextChanged;
|
|
|
-
|
|
|
- // Things this view knows how to do
|
|
|
- AddCommand (Command.DeleteCharRight, () => { DeleteCharRight (); return true; });
|
|
|
- AddCommand (Command.DeleteCharLeft, () => { DeleteCharLeft (false); return true; });
|
|
|
- AddCommand (Command.LeftHome, () => MoveHome ());
|
|
|
- AddCommand (Command.Left, () => MoveLeft ());
|
|
|
- AddCommand (Command.RightEnd, () => MoveEnd ());
|
|
|
- AddCommand (Command.Right, () => MoveRight ());
|
|
|
-
|
|
|
- // Default keybindings for this view
|
|
|
- KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
|
|
|
- KeyBindings.Add (KeyCode.D | KeyCode.CtrlMask, Command.DeleteCharRight);
|
|
|
-
|
|
|
- KeyBindings.Add (KeyCode.Delete, Command.DeleteCharLeft);
|
|
|
- KeyBindings.Add (KeyCode.Backspace, Command.DeleteCharLeft);
|
|
|
-
|
|
|
- KeyBindings.Add (KeyCode.Home, Command.LeftHome);
|
|
|
- KeyBindings.Add (KeyCode.A | KeyCode.CtrlMask, Command.LeftHome);
|
|
|
+ /// <remarks>
|
|
|
+ /// The passed <see cref="EventArgs"/> is a <see cref="DateTimeEventArgs{T}"/> containing the old value, new value, and format string.
|
|
|
+ /// </remarks>
|
|
|
+ public event EventHandler<DateTimeEventArgs<TimeSpan>> TimeChanged;
|
|
|
|
|
|
- KeyBindings.Add (KeyCode.CursorLeft, Command.Left);
|
|
|
- KeyBindings.Add (KeyCode.B | KeyCode.CtrlMask, Command.Left);
|
|
|
+ /// <summary>
|
|
|
+ /// Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Absolute"/> positioning.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="x">The x coordinate.</param>
|
|
|
+ /// <param name="y">The y coordinate.</param>
|
|
|
+ /// <param name="time">Initial time.</param>
|
|
|
+ /// <param name="isShort">If true, the seconds are hidden. Sets the <see cref="IsShortFormat"/> property.</param>
|
|
|
+ public TimeField (int x, int y, TimeSpan time, bool isShort = false) : base (x, y, isShort ? 7 : 10, "")
|
|
|
+ {
|
|
|
+ SetInitialProperties (time, isShort);
|
|
|
+ }
|
|
|
|
|
|
- KeyBindings.Add (KeyCode.End, Command.RightEnd);
|
|
|
- KeyBindings.Add (KeyCode.E | KeyCode.CtrlMask, Command.RightEnd);
|
|
|
+ /// <summary>
|
|
|
+ /// Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Computed"/> positioning.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="time">Initial time</param>
|
|
|
+ public TimeField (TimeSpan time) : base (string.Empty)
|
|
|
+ {
|
|
|
+ Width = _fieldLen + 2;
|
|
|
+ SetInitialProperties (time);
|
|
|
+ }
|
|
|
|
|
|
- KeyBindings.Add (KeyCode.CursorRight, Command.Right);
|
|
|
- KeyBindings.Add (KeyCode.F | KeyCode.CtrlMask, Command.Right);
|
|
|
- }
|
|
|
+ /// <summary>
|
|
|
+ /// Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Computed"/> positioning.
|
|
|
+ /// </summary>
|
|
|
+ public TimeField () : this (time: TimeSpan.MinValue) { }
|
|
|
+
|
|
|
+ void SetInitialProperties (TimeSpan time, bool isShort = false)
|
|
|
+ {
|
|
|
+ CultureInfo cultureInfo = CultureInfo.CurrentCulture;
|
|
|
+ _sepChar = cultureInfo.DateTimeFormat.TimeSeparator;
|
|
|
+ _longFormat = $" hh\\{_sepChar}mm\\{_sepChar}ss";
|
|
|
+ _shortFormat = $" hh\\{_sepChar}mm";
|
|
|
+ this._isShort = isShort;
|
|
|
+ Time = time;
|
|
|
+ CursorPosition = 1;
|
|
|
+ TextChanging += TextField_TextChanging;
|
|
|
+
|
|
|
+ // Things this view knows how to do
|
|
|
+ AddCommand (Command.DeleteCharRight, () => { DeleteCharRight (); return true; });
|
|
|
+ AddCommand (Command.DeleteCharLeft, () => { DeleteCharLeft (false); return true; });
|
|
|
+ AddCommand (Command.LeftHome, () => MoveHome ());
|
|
|
+ AddCommand (Command.Left, () => MoveLeft ());
|
|
|
+ AddCommand (Command.RightEnd, () => MoveEnd ());
|
|
|
+ AddCommand (Command.Right, () => MoveRight ());
|
|
|
+
|
|
|
+ // Default keybindings for this view
|
|
|
+ KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
|
|
|
+ KeyBindings.Add (Key.D.WithCtrl, Command.DeleteCharRight);
|
|
|
+
|
|
|
+ KeyBindings.Add (Key.Backspace, Command.DeleteCharLeft);
|
|
|
+ KeyBindings.Add (Key.D.WithAlt, Command.DeleteCharLeft);
|
|
|
+
|
|
|
+ KeyBindings.Add (Key.Home, Command.LeftHome);
|
|
|
+ KeyBindings.Add (Key.A.WithCtrl, Command.LeftHome);
|
|
|
+
|
|
|
+ KeyBindings.Add (Key.CursorLeft, Command.Left);
|
|
|
+ KeyBindings.Add (Key.B.WithCtrl, Command.Left);
|
|
|
+
|
|
|
+ KeyBindings.Add (Key.End, Command.RightEnd);
|
|
|
+ KeyBindings.Add (Key.E.WithCtrl, Command.RightEnd);
|
|
|
+
|
|
|
+ KeyBindings.Add (Key.CursorRight, Command.Right);
|
|
|
+ KeyBindings.Add (Key.F.WithCtrl, Command.Right);
|
|
|
+ }
|
|
|
|
|
|
- void TextField_TextChanged (object sender, TextChangedEventArgs e)
|
|
|
- {
|
|
|
- try {
|
|
|
- if (!TimeSpan.TryParseExact (Text.Trim (), format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result))
|
|
|
- Text = e.OldValue;
|
|
|
- } catch (Exception) {
|
|
|
- Text = e.OldValue;
|
|
|
+ void TextField_TextChanging (object sender, TextChangingEventArgs e)
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ int spaces = 0;
|
|
|
+ for (int i = 0; i < e.NewText.Length; i++) {
|
|
|
+ if (e.NewText [i] == ' ') {
|
|
|
+ spaces++;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets or sets the time of the <see cref="TimeField"/>.
|
|
|
- /// </summary>
|
|
|
- /// <remarks>
|
|
|
- /// </remarks>
|
|
|
- public TimeSpan Time {
|
|
|
- get {
|
|
|
- return time;
|
|
|
+ spaces += _fieldLen;
|
|
|
+ string trimedText = e.NewText [..spaces];
|
|
|
+ spaces -= _fieldLen;
|
|
|
+ trimedText = trimedText.Replace (new string (' ', spaces), " ");
|
|
|
+ if (trimedText != e.NewText) {
|
|
|
+ e.NewText = trimedText;
|
|
|
}
|
|
|
- set {
|
|
|
- if (ReadOnly)
|
|
|
- return;
|
|
|
-
|
|
|
- var oldTime = time;
|
|
|
- time = value;
|
|
|
- this.Text = " " + value.ToString (format.Trim ());
|
|
|
- var args = new DateTimeEventArgs<TimeSpan> (oldTime, value, format);
|
|
|
- if (oldTime != value) {
|
|
|
- OnTimeChanged (args);
|
|
|
- }
|
|
|
+ if (!TimeSpan.TryParseExact (e.NewText.Trim (), _format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result)) {
|
|
|
+ e.Cancel = true;
|
|
|
}
|
|
|
+ AdjCursorPosition (CursorPosition, true);
|
|
|
+ } catch (Exception) {
|
|
|
+ e.Cancel = true;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Get or sets whether <see cref="TimeField"/> uses the short or long time format.
|
|
|
- /// </summary>
|
|
|
- public bool IsShortFormat {
|
|
|
- get => isShort;
|
|
|
- set {
|
|
|
- isShort = value;
|
|
|
- if (isShort)
|
|
|
- Width = 7;
|
|
|
- else
|
|
|
- Width = 10;
|
|
|
- var ro = ReadOnly;
|
|
|
- if (ro)
|
|
|
- ReadOnly = false;
|
|
|
- SetText (Text);
|
|
|
- ReadOnly = ro;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
+ /// <summary>
|
|
|
+ /// Gets or sets the time of the <see cref="TimeField"/>.
|
|
|
+ /// </summary>
|
|
|
+ /// <remarks>
|
|
|
+ /// </remarks>
|
|
|
+ public TimeSpan Time {
|
|
|
+ get {
|
|
|
+ return _time;
|
|
|
}
|
|
|
+ set {
|
|
|
+ if (ReadOnly)
|
|
|
+ return;
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override int CursorPosition {
|
|
|
- get => base.CursorPosition;
|
|
|
- set {
|
|
|
- base.CursorPosition = Math.Max (Math.Min (value, fieldLen), 1);
|
|
|
+ var oldTime = _time;
|
|
|
+ _time = value;
|
|
|
+ this.Text = " " + value.ToString (_format.Trim ());
|
|
|
+ var args = new DateTimeEventArgs<TimeSpan> (oldTime, value, _format);
|
|
|
+ if (oldTime != value) {
|
|
|
+ OnTimeChanged (args);
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- bool SetText (Rune key)
|
|
|
- {
|
|
|
- var text = Text.EnumerateRunes ().ToList ();
|
|
|
- var newText = text.GetRange (0, CursorPosition);
|
|
|
- newText.Add (key);
|
|
|
- if (CursorPosition < fieldLen)
|
|
|
- newText = newText.Concat (text.GetRange (CursorPosition + 1, text.Count - (CursorPosition + 1))).ToList ();
|
|
|
- return SetText (StringExtensions.ToString (newText));
|
|
|
+ /// <summary>
|
|
|
+ /// Get or sets whether <see cref="TimeField"/> uses the short or long time format.
|
|
|
+ /// </summary>
|
|
|
+ public bool IsShortFormat {
|
|
|
+ get => _isShort;
|
|
|
+ set {
|
|
|
+ _isShort = value;
|
|
|
+ if (_isShort)
|
|
|
+ Width = 7;
|
|
|
+ else
|
|
|
+ Width = 10;
|
|
|
+ var ro = ReadOnly;
|
|
|
+ if (ro)
|
|
|
+ ReadOnly = false;
|
|
|
+ SetText (Text);
|
|
|
+ ReadOnly = ro;
|
|
|
+ SetNeedsDisplay ();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- bool SetText (string text)
|
|
|
- {
|
|
|
- if (string.IsNullOrEmpty (text)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ /// <inheritdoc/>
|
|
|
+ public override int CursorPosition {
|
|
|
+ get => base.CursorPosition;
|
|
|
+ set {
|
|
|
+ base.CursorPosition = Math.Max (Math.Min (value, _fieldLen), 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- string [] vals = text.Split (sepChar);
|
|
|
- bool isValidTime = true;
|
|
|
- int hour = Int32.Parse (vals [0]);
|
|
|
- int minute = Int32.Parse (vals [1]);
|
|
|
- int second = isShort ? 0 : vals.Length > 2 ? Int32.Parse (vals [2].ToString ()) : 0;
|
|
|
- if (hour < 0) {
|
|
|
- isValidTime = false;
|
|
|
- hour = 0;
|
|
|
- vals [0] = "0";
|
|
|
- } else if (hour > 23) {
|
|
|
- isValidTime = false;
|
|
|
- hour = 23;
|
|
|
- vals [0] = "23";
|
|
|
- }
|
|
|
- if (minute < 0) {
|
|
|
- isValidTime = false;
|
|
|
- minute = 0;
|
|
|
- vals [1] = "0";
|
|
|
- } else if (minute > 59) {
|
|
|
- isValidTime = false;
|
|
|
- minute = 59;
|
|
|
- vals [1] = "59";
|
|
|
- }
|
|
|
- if (second < 0) {
|
|
|
- isValidTime = false;
|
|
|
- second = 0;
|
|
|
- vals [2] = "0";
|
|
|
- } else if (second > 59) {
|
|
|
- isValidTime = false;
|
|
|
- second = 59;
|
|
|
- vals [2] = "59";
|
|
|
- }
|
|
|
- string t = isShort ? $" {hour,2:00}{sepChar}{minute,2:00}" : $" {hour,2:00}{sepChar}{minute,2:00}{sepChar}{second,2:00}";
|
|
|
+ bool SetText (Rune key)
|
|
|
+ {
|
|
|
+ var text = Text.EnumerateRunes ().ToList ();
|
|
|
+ var newText = text.GetRange (0, CursorPosition);
|
|
|
+ newText.Add (key);
|
|
|
+ if (CursorPosition < _fieldLen)
|
|
|
+ newText = [.. newText, .. text.GetRange (CursorPosition + 1, text.Count - (CursorPosition + 1))];
|
|
|
+ return SetText (StringExtensions.ToString (newText));
|
|
|
+ }
|
|
|
|
|
|
- if (!TimeSpan.TryParseExact (t.Trim (), format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result) ||
|
|
|
- !isValidTime)
|
|
|
- return false;
|
|
|
- Time = result;
|
|
|
- return true;
|
|
|
+ bool SetText (string text)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty (text)) {
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- void IncCursorPosition ()
|
|
|
- {
|
|
|
- if (CursorPosition == fieldLen)
|
|
|
- return;
|
|
|
- if (Text [++CursorPosition] == sepChar.ToCharArray () [0])
|
|
|
- CursorPosition++;
|
|
|
+ text = NormalizeFormat (text);
|
|
|
+ string [] vals = text.Split (_sepChar);
|
|
|
+ bool isValidTime = true;
|
|
|
+ int hour = Int32.Parse (vals [0]);
|
|
|
+ int minute = Int32.Parse (vals [1]);
|
|
|
+ int second = _isShort ? 0 : vals.Length > 2 ? Int32.Parse (vals [2]) : 0;
|
|
|
+ if (hour < 0) {
|
|
|
+ isValidTime = false;
|
|
|
+ hour = 0;
|
|
|
+ vals [0] = "0";
|
|
|
+ } else if (hour > 23) {
|
|
|
+ isValidTime = false;
|
|
|
+ hour = 23;
|
|
|
+ vals [0] = "23";
|
|
|
}
|
|
|
+ if (minute < 0) {
|
|
|
+ isValidTime = false;
|
|
|
+ minute = 0;
|
|
|
+ vals [1] = "0";
|
|
|
+ } else if (minute > 59) {
|
|
|
+ isValidTime = false;
|
|
|
+ minute = 59;
|
|
|
+ vals [1] = "59";
|
|
|
+ }
|
|
|
+ if (second < 0) {
|
|
|
+ isValidTime = false;
|
|
|
+ second = 0;
|
|
|
+ vals [2] = "0";
|
|
|
+ } else if (second > 59) {
|
|
|
+ isValidTime = false;
|
|
|
+ second = 59;
|
|
|
+ vals [2] = "59";
|
|
|
+ }
|
|
|
+ string t = _isShort ? $" {hour,2:00}{_sepChar}{minute,2:00}" : $" {hour,2:00}{_sepChar}{minute,2:00}{_sepChar}{second,2:00}";
|
|
|
|
|
|
- void DecCursorPosition ()
|
|
|
- {
|
|
|
- if (CursorPosition == 1)
|
|
|
- return;
|
|
|
- if (Text [--CursorPosition] == sepChar.ToCharArray () [0])
|
|
|
- CursorPosition--;
|
|
|
+ if (!TimeSpan.TryParseExact (t.Trim (), _format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result) ||
|
|
|
+ !isValidTime) {
|
|
|
+ return false;
|
|
|
}
|
|
|
+ Time = result;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- void AdjCursorPosition ()
|
|
|
- {
|
|
|
- if (Text [CursorPosition] == sepChar.ToCharArray () [0])
|
|
|
- CursorPosition++;
|
|
|
+ string NormalizeFormat (string text, string fmt = null, string sepChar = null)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty (fmt)) {
|
|
|
+ fmt = _format;
|
|
|
+ }
|
|
|
+ fmt = fmt.Replace ("\\", "");
|
|
|
+ if (string.IsNullOrEmpty (sepChar)) {
|
|
|
+ sepChar = _sepChar;
|
|
|
+ }
|
|
|
+ if (fmt.Length != text.Length) {
|
|
|
+ return text;
|
|
|
}
|
|
|
|
|
|
- ///<inheritdoc/>
|
|
|
- public override bool OnProcessKeyDown (Key a)
|
|
|
- {
|
|
|
- // Ignore non-numeric characters.
|
|
|
- if (a.KeyCode is >= (KeyCode)(int)KeyCode.D0 and <= (KeyCode)(int)KeyCode.D9) {
|
|
|
- if (!ReadOnly) {
|
|
|
- if (SetText ((Rune)a)) {
|
|
|
- IncCursorPosition ();
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
+ var fmtText = text.ToCharArray ();
|
|
|
+ for (int i = 0; i < text.Length; i++) {
|
|
|
+ var c = fmt [i];
|
|
|
+ if (c.ToString () == sepChar && text [i].ToString () != sepChar) {
|
|
|
+ fmtText [i] = c;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (a.IsKeyCodeAtoZ) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
+ return new string (fmtText);
|
|
|
+ }
|
|
|
+
|
|
|
+ void IncCursorPosition ()
|
|
|
+ {
|
|
|
+ if (CursorPosition >= _fieldLen) {
|
|
|
+ CursorPosition = _fieldLen;
|
|
|
+ return;
|
|
|
}
|
|
|
+ CursorPosition++;
|
|
|
+ AdjCursorPosition (CursorPosition);
|
|
|
+ }
|
|
|
|
|
|
- bool MoveRight ()
|
|
|
- {
|
|
|
- IncCursorPosition ();
|
|
|
- return true;
|
|
|
+ void DecCursorPosition ()
|
|
|
+ {
|
|
|
+ if (CursorPosition <= 1) {
|
|
|
+ CursorPosition = 1;
|
|
|
+ return;
|
|
|
}
|
|
|
+ CursorPosition--;
|
|
|
+ AdjCursorPosition (CursorPosition, false);
|
|
|
+ }
|
|
|
|
|
|
- new bool MoveEnd ()
|
|
|
- {
|
|
|
- CursorPosition = fieldLen;
|
|
|
- return true;
|
|
|
+ void AdjCursorPosition (int point, bool increment = true)
|
|
|
+ {
|
|
|
+ var newPoint = point;
|
|
|
+ if (point > _fieldLen) {
|
|
|
+ newPoint = _fieldLen;
|
|
|
+ }
|
|
|
+ if (point < 1) {
|
|
|
+ newPoint = 1;
|
|
|
+ }
|
|
|
+ if (newPoint != point) {
|
|
|
+ CursorPosition = newPoint;
|
|
|
}
|
|
|
|
|
|
- bool MoveLeft ()
|
|
|
- {
|
|
|
- DecCursorPosition ();
|
|
|
- return true;
|
|
|
+ while (Text [CursorPosition] == _sepChar [0]) {
|
|
|
+ if (increment) {
|
|
|
+ CursorPosition++;
|
|
|
+ } else {
|
|
|
+ CursorPosition--;
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- bool MoveHome ()
|
|
|
- {
|
|
|
- // Home, C-A
|
|
|
- CursorPosition = 1;
|
|
|
+ ///<inheritdoc/>
|
|
|
+ public override bool OnProcessKeyDown (Key a)
|
|
|
+ {
|
|
|
+ // Ignore non-numeric characters.
|
|
|
+ if (a.KeyCode is >= (KeyCode)(int)KeyCode.D0 and <= (KeyCode)(int)KeyCode.D9) {
|
|
|
+ if (!ReadOnly) {
|
|
|
+ if (SetText ((Rune)a)) {
|
|
|
+ IncCursorPosition ();
|
|
|
+ }
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override void DeleteCharLeft (bool useOldCursorPos = true)
|
|
|
- {
|
|
|
- if (ReadOnly)
|
|
|
- return;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- SetText ((Rune)'0');
|
|
|
- DecCursorPosition ();
|
|
|
+ bool MoveRight ()
|
|
|
+ {
|
|
|
+ ClearAllSelection ();
|
|
|
+ IncCursorPosition ();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ new bool MoveEnd ()
|
|
|
+ {
|
|
|
+ ClearAllSelection ();
|
|
|
+ CursorPosition = _fieldLen;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool MoveLeft ()
|
|
|
+ {
|
|
|
+ ClearAllSelection ();
|
|
|
+ DecCursorPosition ();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool MoveHome ()
|
|
|
+ {
|
|
|
+ // Home, C-A
|
|
|
+ ClearAllSelection ();
|
|
|
+ CursorPosition = 1;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <inheritdoc/>
|
|
|
+ public override void DeleteCharLeft (bool useOldCursorPos = true)
|
|
|
+ {
|
|
|
+ if (ReadOnly) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override void DeleteCharRight ()
|
|
|
- {
|
|
|
- if (ReadOnly)
|
|
|
- return;
|
|
|
+ ClearAllSelection ();
|
|
|
+ SetText ((Rune)'0');
|
|
|
+ DecCursorPosition ();
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- SetText ((Rune)'0');
|
|
|
+ /// <inheritdoc/>
|
|
|
+ public override void DeleteCharRight ()
|
|
|
+ {
|
|
|
+ if (ReadOnly) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- ///<inheritdoc/>
|
|
|
- public override bool MouseEvent (MouseEvent ev)
|
|
|
- {
|
|
|
- if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked))
|
|
|
- return false;
|
|
|
- if (!HasFocus)
|
|
|
- SetFocus ();
|
|
|
-
|
|
|
- var point = ev.X;
|
|
|
- if (point > fieldLen)
|
|
|
- point = fieldLen;
|
|
|
- if (point < 1)
|
|
|
- point = 1;
|
|
|
- CursorPosition = point;
|
|
|
- AdjCursorPosition ();
|
|
|
- return true;
|
|
|
- }
|
|
|
+ ClearAllSelection ();
|
|
|
+ SetText ((Rune)'0');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ///<inheritdoc/>
|
|
|
+ public override bool MouseEvent (MouseEvent ev)
|
|
|
+ {
|
|
|
+ var result = base.MouseEvent (ev);
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Event firing method that invokes the <see cref="TimeChanged"/> event.
|
|
|
- /// </summary>
|
|
|
- /// <param name="args">The event arguments</param>
|
|
|
- public virtual void OnTimeChanged (DateTimeEventArgs<TimeSpan> args)
|
|
|
- {
|
|
|
- TimeChanged?.Invoke (this, args);
|
|
|
+ if (result && SelectedLength == 0 && ev.Flags.HasFlag (MouseFlags.Button1Pressed)) {
|
|
|
+ int point = ev.X;
|
|
|
+ AdjCursorPosition (point, true);
|
|
|
}
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Event firing method that invokes the <see cref="TimeChanged"/> event.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="args">The event arguments</param>
|
|
|
+ public virtual void OnTimeChanged (DateTimeEventArgs<TimeSpan> args)
|
|
|
+ {
|
|
|
+ TimeChanged?.Invoke (this, args);
|
|
|
}
|
|
|
-}
|
|
|
+}
|