From d6579b0b2e7e60c5cbb05df8588535a3b418810c Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 23 May 2020 13:14:09 +0100 Subject: [PATCH] Fixes some DateField and TimeField bugs. --- Terminal.Gui/Views/DateField.cs | 169 +++++++++++++++++++------------- Terminal.Gui/Views/TimeField.cs | 39 +++++++- 2 files changed, 139 insertions(+), 69 deletions(-) diff --git a/Terminal.Gui/Views/DateField.cs b/Terminal.Gui/Views/DateField.cs index 2215a56a2..46e9c1231 100644 --- a/Terminal.Gui/Views/DateField.cs +++ b/Terminal.Gui/Views/DateField.cs @@ -19,15 +19,14 @@ namespace Terminal.Gui { /// public class DateField : TextField { bool isShort; - int longFieldLen = 10; int shortFieldLen = 8; - int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } } string sepChar; string longFormat; string shortFormat; - string Format { get { return isShort ? shortFormat : longFormat; } } + int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } } + string Format { get { return isShort ? shortFormat : longFormat; } } /// /// Initializes a new instance of at an absolute position and fixed size. @@ -37,20 +36,32 @@ namespace Terminal.Gui { /// Initial date contents. /// If true, shows only two digits for the year. public DateField (int x, int y, DateTime date, bool isShort = false) : base(x, y, isShort ? 10 : 12, "") + { + this.isShort = isShort; + Initialize (date); + } + + public DateField (DateTime date) : base ("") + { + this.isShort = true; + Width = FieldLen + 2; + Initialize (date); + } + + void Initialize (DateTime date) { CultureInfo cultureInfo = CultureInfo.CurrentCulture; sepChar = cultureInfo.DateTimeFormat.DateSeparator; longFormat = GetLongFormat (cultureInfo.DateTimeFormat.ShortDatePattern); - shortFormat = GetShortFormat(longFormat); - this.isShort = isShort; + shortFormat = GetShortFormat (longFormat); CursorPosition = 1; Date = date; Changed += DateField_Changed; } - void DateField_Changed(object sender, ustring e) + void DateField_Changed (object sender, ustring e) { - if (!DateTime.TryParseExact(Text.ToString(), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) + if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) Text = e; } @@ -70,7 +81,7 @@ namespace Terminal.Gui { string GetShortFormat (string lf) { - return lf.Replace("yyyy", "yy"); + return lf.Replace ("yyyy", "yy"); } /// @@ -80,85 +91,111 @@ namespace Terminal.Gui { /// public DateTime Date { get { - if (!DateTime.TryParseExact(Text.ToString(), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) return new DateTime(); + if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) return new DateTime (); return result; } set { - this.Text = value.ToString(Format); + this.Text = value.ToString (Format); } } - bool SetText(Rune key) - { - var text = TextModel.ToRunes(Text); - 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(ustring.Make(newText)); + /// + /// Get or set the data format for the widget. + /// + public bool IsShortFormat { + get => isShort; + set { + isShort = value; + if (isShort) + Width = 10; + else + Width = 12; + var ro = ReadOnly; + if (ro) + ReadOnly = false; + SetText (Text); + ReadOnly = ro; + SetNeedsDisplay (); + } } - bool SetText(ustring text) + bool SetText (Rune key) { - ustring[] vals = text.Split(ustring.Make(sepChar)); - ustring[] frm = ustring.Make(Format).Split(ustring.Make(sepChar)); + var text = TextModel.ToRunes (Text); + 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 (ustring.Make (newText)); + } + + bool SetText (ustring text) + { + ustring [] vals = text.Split (ustring.Make (sepChar)); + ustring [] frm = ustring.Make (Format).Split (ustring.Make (sepChar)); bool isValidDate = true; - int idx = GetFormatIndex(frm, "y"); - int year = Int32.Parse(vals[idx].ToString()); + int idx = GetFormatIndex (frm, "y"); + int year = Int32.Parse (vals [idx].ToString ()); int month; int day; - idx = GetFormatIndex(frm, "M"); - if (Int32.Parse(vals[idx].ToString()) < 1) { + idx = GetFormatIndex (frm, "M"); + if (Int32.Parse (vals [idx].ToString ()) < 1) { isValidDate = false; month = 1; - vals[idx] = "1"; - } else if (Int32.Parse(vals[idx].ToString()) > 12) { + vals [idx] = "1"; + } else if (Int32.Parse (vals [idx].ToString ()) > 12) { isValidDate = false; month = 12; - vals[idx] = "12"; + vals [idx] = "12"; } else - month = Int32.Parse(vals[idx].ToString()); - idx = GetFormatIndex(frm, "d"); - if (Int32.Parse(vals[idx].ToString()) < 1) { + month = Int32.Parse (vals [idx].ToString ()); + idx = GetFormatIndex (frm, "d"); + if (Int32.Parse (vals [idx].ToString ()) < 1) { isValidDate = false; day = 1; - vals[idx] = "1"; - } else if (Int32.Parse(vals[idx].ToString()) > 31) { + vals [idx] = "1"; + } else if (Int32.Parse (vals [idx].ToString ()) > 31) { isValidDate = false; - day = DateTime.DaysInMonth(year, month); - vals[idx] = day.ToString(); + day = DateTime.DaysInMonth (year, month); + vals [idx] = day.ToString (); } else - day = Int32.Parse(vals[idx].ToString()); - string date = GetData(month, day, year, frm); + day = Int32.Parse (vals [idx].ToString ()); + string date = GetDate (month, day, year, frm); Text = date; - if (!DateTime.TryParseExact(date, Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result) || + if (!DateTime.TryParseExact (date, Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result) || !isValidDate) return false; return true; } - string GetData(int month, int day, int year, ustring[] fm) + string GetDate (int month, int day, int year, ustring [] fm) { - string data = " "; + string date = " "; for (int i = 0; i < fm.Length; i++) { - if (fm[i].Contains("M")) - data += $"{month,2:00}"; - else if (fm[i].Contains("d")) - data += $"{day,2:00}"; - else - data += isShort ? $"{year,2:00}" : $"{year,4:0000}"; + if (fm [i].Contains ("M")) { + date += $"{month,2:00}"; + } else if (fm [i].Contains ("d")) { + date += $"{day,2:00}"; + } else { + if (!isShort && year.ToString ().Length == 2) { + var y = DateTime.Now.Year.ToString (); + date += y.Substring (0, 2) + year.ToString (); + } else { + date += $"{year,2:00}"; + } + } if (i < 2) - data += $"{sepChar}"; + date += $"{sepChar}"; } - return data; + return date; } - int GetFormatIndex(ustring[] fm, string t) + int GetFormatIndex (ustring [] fm, string t) { int idx = -1; for (int i = 0; i < fm.Length; i++) { - if (fm[i].Contains(t)) { + if (fm [i].Contains (t)) { idx = i; break; } @@ -166,25 +203,25 @@ namespace Terminal.Gui { return idx; } - void IncCursorPosition() + void IncCursorPosition () { if (CursorPosition == FieldLen) return; - if (Text[++CursorPosition] == sepChar.ToCharArray()[0]) + if (Text [++CursorPosition] == sepChar.ToCharArray () [0]) CursorPosition++; } - void DecCursorPosition() + void DecCursorPosition () { if (CursorPosition == 1) return; - if (Text[--CursorPosition] == sepChar.ToCharArray()[0]) + if (Text [--CursorPosition] == sepChar.ToCharArray () [0]) CursorPosition--; } - void AdjCursorPosition() + void AdjCursorPosition () { - if (Text[CursorPosition] == sepChar.ToCharArray()[0]) + if (Text [CursorPosition] == sepChar.ToCharArray () [0]) CursorPosition++; } @@ -194,13 +231,13 @@ namespace Terminal.Gui { switch (kb.Key) { case Key.DeleteChar: case Key.ControlD: - SetText('0'); + SetText ('0'); break; case Key.Delete: case Key.Backspace: - SetText('0'); - DecCursorPosition(); + SetText ('0'); + DecCursorPosition (); break; // Home, C-A @@ -211,7 +248,7 @@ namespace Terminal.Gui { case Key.CursorLeft: case Key.ControlB: - DecCursorPosition(); + DecCursorPosition (); break; case Key.End: @@ -221,15 +258,15 @@ namespace Terminal.Gui { case Key.CursorRight: case Key.ControlF: - IncCursorPosition(); + IncCursorPosition (); break; default: // Ignore non-numeric characters. if (kb.Key < (Key)((int)'0') || kb.Key > (Key)((int)'9')) return false; - if (SetText(TextModel.ToRunes(ustring.Make((uint)kb.Key)).First())) - IncCursorPosition(); + if (SetText (TextModel.ToRunes (ustring.Make ((uint)kb.Key)).First ())) + IncCursorPosition (); return true; } return true; @@ -238,10 +275,10 @@ namespace Terminal.Gui { /// public override bool MouseEvent(MouseEvent ev) { - if (!ev.Flags.HasFlag(MouseFlags.Button1Clicked)) + if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked)) return false; if (!HasFocus) - SuperView.SetFocus(this); + SuperView.SetFocus (this); var point = ev.X; if (point > FieldLen) @@ -249,7 +286,7 @@ namespace Terminal.Gui { if (point < 1) point = 1; CursorPosition = point; - AdjCursorPosition(); + AdjCursorPosition (); return true; } } diff --git a/Terminal.Gui/Views/TimeField.cs b/Terminal.Gui/Views/TimeField.cs index 3d59e68b8..49f277204 100644 --- a/Terminal.Gui/Views/TimeField.cs +++ b/Terminal.Gui/Views/TimeField.cs @@ -21,10 +21,11 @@ namespace Terminal.Gui { int longFieldLen = 8; int shortFieldLen = 5; - int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } } string sepChar; string longFormat; string shortFormat; + + int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } } string Format { get { return isShort ? shortFormat : longFormat; } } @@ -36,12 +37,24 @@ namespace Terminal.Gui { /// Initial time contents. /// If true, the seconds are hidden. public TimeField (int x, int y, DateTime time, bool isShort = false) : base (x, y, isShort ? 7 : 10, "") + { + this.isShort = isShort; + Initialize (time); + } + + public TimeField (DateTime time) : base ("") + { + this.isShort = true; + Width = FieldLen + 2; + Initialize (time); + } + + void Initialize (DateTime time) { CultureInfo cultureInfo = CultureInfo.CurrentCulture; sepChar = cultureInfo.DateTimeFormat.TimeSeparator; longFormat = $" HH{sepChar}mm{sepChar}ss"; shortFormat = $" HH{sepChar}mm"; - this.isShort = isShort; CursorPosition = 1; Time = time; Changed += TimeField_Changed; @@ -68,6 +81,26 @@ namespace Terminal.Gui { } } + /// + /// Get or set the data format for the widget. + /// + 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 (Rune key) { var text = TextModel.ToRunes (Text); @@ -84,7 +117,7 @@ namespace Terminal.Gui { bool isValidTime = true; int hour = Int32.Parse (vals [0].ToString ()); int minute = Int32.Parse (vals [1].ToString ()); - int second = isShort ? 0 : Int32.Parse (vals [2].ToString ()); + int second = isShort ? 0 : vals.Length > 2 ? Int32.Parse (vals [2].ToString ()) : 0; if (hour < 0) { isValidTime = false; hour = 0;