diff --git a/Example/demo.cs b/Example/demo.cs
index 9d839b8d0..5c161a3ac 100644
--- a/Example/demo.cs
+++ b/Example/demo.cs
@@ -183,8 +183,8 @@ static class Demo {
scrollView2,
tf,
new Button (10, 19, "Cancel"),
- new TimeField (3, 20, DateTime.Now),
- new TimeField (23, 20, DateTime.Now, true),
+ new TimeField (3, 20, DateTime.Now.TimeOfDay),
+ new TimeField (23, 20, DateTime.Now.TimeOfDay, true),
new DateField (3, 22, DateTime.Now),
new DateField (23, 22, DateTime.Now, true),
progress,
diff --git a/Terminal.Gui/Views/DateField.cs b/Terminal.Gui/Views/DateField.cs
index f857d521d..b2f7df16d 100644
--- a/Terminal.Gui/Views/DateField.cs
+++ b/Terminal.Gui/Views/DateField.cs
@@ -18,6 +18,7 @@ namespace Terminal.Gui {
/// The provides date editing functionality with mouse support.
///
public class DateField : TextField {
+ DateTime date;
bool isShort;
int longFieldLen = 10;
int shortFieldLen = 8;
@@ -28,6 +29,17 @@ namespace Terminal.Gui {
int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } }
string Format { get { return isShort ? shortFormat : longFormat; } }
+ ///
+ /// DateChanged event, raised when the Date has changed.
+ ///
+ ///
+ /// This event is raised when the changes.
+ ///
+ ///
+ /// The passed is a containing the old, new value and format.
+ ///
+ public event Action> DateChanged;
+
///
/// Initializes a new instance of using layout.
///
@@ -70,8 +82,12 @@ namespace Terminal.Gui {
void DateField_Changed (object sender, ustring e)
{
- if (!DateTime.TryParseExact (GetDate (Text).ToString (), GetInvarianteFormat (), CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result))
+ try {
+ if (!DateTime.TryParseExact (GetDate (Text).ToString (), GetInvarianteFormat (), CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result))
+ Text = e;
+ } catch (Exception) {
Text = e;
+ }
}
string GetInvarianteFormat ()
@@ -105,11 +121,19 @@ namespace Terminal.Gui {
///
public DateTime Date {
get {
- if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) return new DateTime ();
- return result;
+ return date;
}
set {
+ if (ReadOnly)
+ return;
+
+ var oldData = date;
+ date = value;
this.Text = value.ToString (Format);
+ var args = new DateTimeEventArgs (oldData, value, Format);
+ if (oldData != value) {
+ OnDateChanged (args);
+ }
}
}
@@ -145,6 +169,10 @@ namespace Terminal.Gui {
bool SetText (ustring text)
{
+ if (text.IsEmpty) {
+ return false;
+ }
+
ustring [] vals = text.Split (ustring.Make (sepChar));
ustring [] frm = ustring.Make (Format).Split (ustring.Make (sepChar));
bool isValidDate = true;
@@ -174,12 +202,12 @@ namespace Terminal.Gui {
vals [idx] = day.ToString ();
} else
day = Int32.Parse (vals [idx].ToString ());
- string date = GetDate (month, day, year, frm);
- Text = date;
+ string d = GetDate (month, day, year, frm);
- if (!DateTime.TryParseExact (date, Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result) ||
+ if (!DateTime.TryParseExact (d, Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result) ||
!isValidDate)
return false;
+ Date = result;
return true;
}
@@ -195,6 +223,8 @@ namespace Terminal.Gui {
if (!isShort && year.ToString ().Length == 2) {
var y = DateTime.Now.Year.ToString ();
date += y.Substring (0, 2) + year.ToString ();
+ } else if (isShort && year.ToString ().Length == 4) {
+ date += $"{year.ToString ().Substring (2, 2)}";
} else {
date += $"{year,2:00}";
}
@@ -270,11 +300,17 @@ namespace Terminal.Gui {
switch (kb.Key) {
case Key.DeleteChar:
case Key.ControlD:
+ if (ReadOnly)
+ return true;
+
SetText ('0');
break;
case Key.Delete:
case Key.Backspace:
+ if (ReadOnly)
+ return true;
+
SetText ('0');
DecCursorPosition ();
break;
@@ -304,6 +340,10 @@ namespace Terminal.Gui {
// Ignore non-numeric characters.
if (kb.Key < (Key)((int)'0') || kb.Key > (Key)((int)'9'))
return false;
+
+ if (ReadOnly)
+ return true;
+
if (SetText (TextModel.ToRunes (ustring.Make ((uint)kb.Key)).First ()))
IncCursorPosition ();
return true;
@@ -328,5 +368,47 @@ namespace Terminal.Gui {
AdjCursorPosition ();
return true;
}
+
+ ///
+ /// Virtual method that will invoke the with a .
+ ///
+ /// The arguments of the
+ public virtual void OnDateChanged (DateTimeEventArgs args)
+ {
+ DateChanged?.Invoke (args);
+ }
+ }
+
+ ///
+ /// Handled the for or events.
+ ///
+ public class DateTimeEventArgs : EventArgs {
+ ///
+ /// The old or value.
+ ///
+ public T OldValue {get;}
+
+ ///
+ /// The new or value.
+ ///
+ public T NewValue { get; }
+
+ ///
+ /// The or format.
+ ///
+ public string Format { get; }
+
+ ///
+ /// Initializes a new instance of
+ ///
+ /// The old or value.
+ /// The new or value.
+ /// The or format.
+ public DateTimeEventArgs (T oldValue, T newValue, string format)
+ {
+ OldValue = oldValue;
+ NewValue = newValue;
+ Format = format;
+ }
}
}
\ No newline at end of file
diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index 6252115e3..f390e2a59 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -132,6 +132,10 @@ namespace Terminal.Gui {
return;
var oldText = ustring.Make (text);
+
+ if (oldText == value)
+ return;
+
text = TextModel.ToRunes (value);
if (!Secret && !isFromHistory) {
if (historyText == null)
diff --git a/Terminal.Gui/Views/TimeField.cs b/Terminal.Gui/Views/TimeField.cs
index 3ac52aecb..af5141fd5 100644
--- a/Terminal.Gui/Views/TimeField.cs
+++ b/Terminal.Gui/Views/TimeField.cs
@@ -17,6 +17,7 @@ namespace Terminal.Gui {
/// The provides time editing functionality with mouse support.
///
public class TimeField : TextField {
+ TimeSpan time;
bool isShort;
int longFieldLen = 8;
@@ -28,6 +29,16 @@ namespace Terminal.Gui {
int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } }
string Format { get { return isShort ? shortFormat : longFormat; } }
+ ///
+ /// TimeChanged event, raised when the Date has changed.
+ ///
+ ///
+ /// This event is raised when the changes.
+ ///
+ ///
+ /// The passed is a containing the old, new value and format.
+ ///
+ public event Action> TimeChanged;
///
/// Initializes a new instance of using positioning.
@@ -36,7 +47,7 @@ namespace Terminal.Gui {
/// The y coordinate.
/// Initial time.
/// If true, the seconds are hidden. Sets the property.
- public TimeField (int x, int y, DateTime time, bool isShort = false) : base (x, y, isShort ? 7 : 10, "")
+ public TimeField (int x, int y, TimeSpan time, bool isShort = false) : base (x, y, isShort ? 7 : 10, "")
{
this.isShort = isShort;
Initialize (time);
@@ -46,7 +57,7 @@ namespace Terminal.Gui {
/// Initializes a new instance of using positioning.
///
/// Initial time
- public TimeField (DateTime time) : base (string.Empty)
+ public TimeField (TimeSpan time) : base (string.Empty)
{
this.isShort = true;
Width = FieldLen + 2;
@@ -56,14 +67,14 @@ namespace Terminal.Gui {
///
/// Initializes a new instance of using positioning.
///
- public TimeField () : this (time: DateTime.MinValue) { }
+ public TimeField () : this (time: TimeSpan.MinValue) { }
- void Initialize (DateTime time)
+ void Initialize (TimeSpan time)
{
CultureInfo cultureInfo = CultureInfo.CurrentCulture;
sepChar = cultureInfo.DateTimeFormat.TimeSeparator;
- longFormat = $" HH{sepChar}mm{sepChar}ss";
- shortFormat = $" HH{sepChar}mm";
+ longFormat = $" hh\\{sepChar}mm\\{sepChar}ss";
+ shortFormat = $" hh\\{sepChar}mm";
CursorPosition = 1;
Time = time;
Changed += TimeField_Changed;
@@ -71,8 +82,12 @@ namespace Terminal.Gui {
void TimeField_Changed (object sender, ustring e)
{
- if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result))
+ try {
+ if (!TimeSpan.TryParseExact (Text.ToString ().Trim (), Format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result))
+ Text = e;
+ } catch (Exception) {
Text = e;
+ }
}
///
@@ -80,13 +95,21 @@ namespace Terminal.Gui {
///
///
///
- public DateTime Time {
+ public TimeSpan Time {
get {
- if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) return new DateTime ();
- return result;
+ return time;
}
set {
- this.Text = value.ToString (Format);
+ if (ReadOnly)
+ return;
+
+ var oldTime = time;
+ time = value;
+ this.Text = " " + value.ToString (Format.Trim ());
+ var args = new DateTimeEventArgs (oldTime, value, Format);
+ if (oldTime != value) {
+ OnTimeChanged (args);
+ }
}
}
@@ -122,6 +145,10 @@ namespace Terminal.Gui {
bool SetText (ustring text)
{
+ if (text.IsEmpty) {
+ return false;
+ }
+
ustring [] vals = text.Split (ustring.Make (sepChar));
bool isValidTime = true;
int hour = Int32.Parse (vals [0].ToString ());
@@ -154,12 +181,12 @@ namespace Terminal.Gui {
second = 59;
vals [2] = "59";
}
- string time = isShort ? $" {hour,2:00}{sepChar}{minute,2:00}" : $" {hour,2:00}{sepChar}{minute,2:00}{sepChar}{second,2:00}";
- Text = time;
+ string t = isShort ? $" {hour,2:00}{sepChar}{minute,2:00}" : $" {hour,2:00}{sepChar}{minute,2:00}{sepChar}{second,2:00}";
- if (!DateTime.TryParseExact (text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result) ||
+ if (!TimeSpan.TryParseExact (t.Trim (), Format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result) ||
!isValidTime)
return false;
+ Time = result;
return true;
}
@@ -191,11 +218,17 @@ namespace Terminal.Gui {
switch (kb.Key) {
case Key.DeleteChar:
case Key.ControlD:
+ if (ReadOnly)
+ return true;
+
SetText ('0');
break;
case Key.Delete:
case Key.Backspace:
+ if (ReadOnly)
+ return true;
+
SetText ('0');
DecCursorPosition ();
break;
@@ -225,6 +258,10 @@ namespace Terminal.Gui {
// Ignore non-numeric characters.
if (kb.Key < (Key)((int)'0') || kb.Key > (Key)((int)'9'))
return false;
+
+ if (ReadOnly)
+ return true;
+
if (SetText (TextModel.ToRunes (ustring.Make ((uint)kb.Key)).First ()))
IncCursorPosition ();
return true;
@@ -249,5 +286,14 @@ namespace Terminal.Gui {
AdjCursorPosition ();
return true;
}
+
+ ///
+ /// Virtual method that will invoke the with a .
+ ///
+ /// The arguments of the
+ public virtual void OnTimeChanged (DateTimeEventArgs args)
+ {
+ TimeChanged?.Invoke (args);
+ }
}
}
\ No newline at end of file
diff --git a/UICatalog/Scenarios/Text.cs b/UICatalog/Scenarios/Text.cs
index a0940c5e2..902106c76 100644
--- a/UICatalog/Scenarios/Text.cs
+++ b/UICatalog/Scenarios/Text.cs
@@ -1,4 +1,5 @@
-using System.Text;
+using System;
+using System.Text;
using Terminal.Gui;
namespace UICatalog {
@@ -45,8 +46,8 @@ namespace UICatalog {
};
Win.Add (dateField);
- var timeField = new TimeField (System.DateTime.Now) {
- X = Pos.Right(dateField) + 5,
+ var timeField = new TimeField (DateTime.Now.TimeOfDay) {
+ X = Pos.Right (dateField) + 5,
Y = Pos.Bottom (hexView) + 1,
Width = Dim.Percent (40),
ColorScheme = Colors.Dialog,
diff --git a/UICatalog/Scenarios/TimeAndDate.cs b/UICatalog/Scenarios/TimeAndDate.cs
index d24aab005..26cd87edd 100644
--- a/UICatalog/Scenarios/TimeAndDate.cs
+++ b/UICatalog/Scenarios/TimeAndDate.cs
@@ -6,22 +6,31 @@ namespace UICatalog {
[ScenarioCategory ("Controls")]
[ScenarioCategory ("Bug Repro")] // Issue #246
class TimeAndDate : Scenario {
+ Label lblOldTime;
+ Label lblNewTime;
+ Label lblTimeFmt;
+ Label lblOldDate;
+ Label lblNewDate;
+ Label lblDateFmt;
+
public override void Setup ()
{
- var longTime = new TimeField (DateTime.Now) {
+ var longTime = new TimeField (DateTime.Now.TimeOfDay) {
X = Pos.Center (),
Y = 2,
IsShortFormat = false,
ReadOnly = false,
};
+ longTime.TimeChanged += TimeChanged;
Win.Add (longTime);
- var shortTime = new TimeField (DateTime.Now) {
+ var shortTime = new TimeField (DateTime.Now.TimeOfDay) {
X = Pos.Center (),
- Y = Pos.Bottom(longTime) + 1,
+ Y = Pos.Bottom (longTime) + 1,
IsShortFormat = true,
ReadOnly = false,
};
+ shortTime.TimeChanged += TimeChanged;
Win.Add (shortTime);
var shortDate = new DateField (DateTime.Now) {
@@ -30,6 +39,7 @@ namespace UICatalog {
IsShortFormat = true,
ReadOnly = true,
};
+ shortDate.DateChanged += DateChanged;
Win.Add (shortDate);
var longDate = new DateField (DateTime.Now) {
@@ -38,8 +48,45 @@ namespace UICatalog {
IsShortFormat = false,
ReadOnly = true,
};
+ longDate.DateChanged += DateChanged;
Win.Add (longDate);
+ lblOldTime = new Label ("Old Time: ") {
+ X = Pos.Center (),
+ Y = Pos.Bottom (longDate) + 1
+ };
+ Win.Add (lblOldTime);
+
+ lblNewTime = new Label ("New Time: ") {
+ X = Pos.Center (),
+ Y = Pos.Bottom (lblOldTime) + 1
+ };
+ Win.Add (lblNewTime);
+
+ lblTimeFmt = new Label ("Time Format: ") {
+ X = Pos.Center (),
+ Y = Pos.Bottom (lblNewTime) + 1
+ };
+ Win.Add (lblTimeFmt);
+
+ lblOldDate = new Label ("Old Date: ") {
+ X = Pos.Center (),
+ Y = Pos.Bottom (lblTimeFmt) + 2
+ };
+ Win.Add (lblOldDate);
+
+ lblNewDate = new Label ("New Date: ") {
+ X = Pos.Center (),
+ Y = Pos.Bottom (lblOldDate) + 1
+ };
+ Win.Add (lblNewDate);
+
+ lblDateFmt = new Label ("Date Format: ") {
+ X = Pos.Center (),
+ Y = Pos.Bottom (lblNewDate) + 1
+ };
+ Win.Add (lblDateFmt);
+
Win.Add (new Button ("Swap Long/Short & Read/Read Only") {
X = Pos.Center (),
Y = Pos.Bottom (Win) - 5,
@@ -58,5 +105,19 @@ namespace UICatalog {
}
});
}
+
+ private void TimeChanged (DateTimeEventArgs e)
+ {
+ lblOldTime.Text = $"Old Time: {e.OldValue}";
+ lblNewTime.Text = $"New Time: {e.NewValue}";
+ lblTimeFmt.Text = $"Time Format: {e.Format}";
+ }
+
+ private void DateChanged (DateTimeEventArgs e)
+ {
+ lblOldDate.Text = $"Old Date: {e.OldValue}";
+ lblNewDate.Text = $"New Date: {e.NewValue}";
+ lblDateFmt.Text = $"Date Format: {e.Format}";
+ }
}
}
\ No newline at end of file