mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-31 02:08:03 +01:00
* Implemented lower and upper bounds to TimeField * Passing old text to the Changed event handler * Change sepChar from char to string in TimeField * Changing comparison from ':' to sepChar.ToCharArray () [0]
212 lines
5.1 KiB
C#
212 lines
5.1 KiB
C#
//
|
|
// TimeField.cs: text entry for time
|
|
//
|
|
// Author: Jörg Preiß
|
|
//
|
|
// Licensed under the MIT license
|
|
//
|
|
using System;
|
|
using System.Globalization;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using NStack;
|
|
|
|
namespace Terminal.Gui {
|
|
|
|
/// <summary>
|
|
/// Time edit widget
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This widget provides time editing functionality, and mouse support.
|
|
/// </remarks>
|
|
public class TimeField : TextField {
|
|
bool isShort;
|
|
|
|
int longFieldLen = 8;
|
|
int shortFieldLen = 5;
|
|
int FieldLen { get { return isShort ? shortFieldLen : longFieldLen; } }
|
|
string sepChar;
|
|
string longFormat;
|
|
string shortFormat;
|
|
string Format { get { return isShort ? shortFormat : longFormat; } }
|
|
|
|
|
|
/// <summary>
|
|
/// Public constructor that creates a time edit field at an absolute position and fixed size.
|
|
/// </summary>
|
|
/// <param name="x">The x coordinate.</param>
|
|
/// <param name="y">The y coordinate.</param>
|
|
/// <param name="time">Initial time contents.</param>
|
|
/// <param name="isShort">If true, the seconds are hidden.</param>
|
|
public TimeField (int x, int y, DateTime time, bool isShort = false) : base (x, y, isShort ? 7 : 10, "")
|
|
{
|
|
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;
|
|
}
|
|
|
|
private void TimeField_Changed (object sender, ustring e)
|
|
{
|
|
if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result))
|
|
Text = e;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the time in the widget.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// </remarks>
|
|
public DateTime Time {
|
|
get {
|
|
if (!DateTime.TryParseExact (Text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result)) return new DateTime ();
|
|
return result;
|
|
}
|
|
set {
|
|
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));
|
|
}
|
|
|
|
bool SetText (ustring text)
|
|
{
|
|
ustring [] vals = text.Split (ustring.Make (sepChar));
|
|
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 ());
|
|
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 time = isShort ? $" {hour,2:00}{sepChar}{minute,2:00}" : $" {hour,2:00}{sepChar}{minute,2:00}{sepChar}{second,2:00}";
|
|
Text = time;
|
|
|
|
if (!DateTime.TryParseExact (text.ToString (), Format, CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result) ||
|
|
!isValidTime)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void IncCursorPosition ()
|
|
{
|
|
if (CursorPosition == FieldLen)
|
|
return;
|
|
if (Text [++CursorPosition] == sepChar.ToCharArray () [0])
|
|
CursorPosition++;
|
|
}
|
|
|
|
void DecCursorPosition ()
|
|
{
|
|
if (CursorPosition == 1)
|
|
return;
|
|
if (Text [--CursorPosition] == sepChar.ToCharArray () [0])
|
|
CursorPosition--;
|
|
}
|
|
|
|
void AdjCursorPosition ()
|
|
{
|
|
if (Text [CursorPosition] == sepChar.ToCharArray () [0])
|
|
CursorPosition++;
|
|
}
|
|
|
|
public override bool ProcessKey (KeyEvent kb)
|
|
{
|
|
switch (kb.Key) {
|
|
case Key.DeleteChar:
|
|
case Key.ControlD:
|
|
SetText ('0');
|
|
break;
|
|
|
|
case Key.Delete:
|
|
case Key.Backspace:
|
|
SetText ('0');
|
|
DecCursorPosition ();
|
|
break;
|
|
|
|
// Home, C-A
|
|
case Key.Home:
|
|
case Key.ControlA:
|
|
CursorPosition = 1;
|
|
break;
|
|
|
|
case Key.CursorLeft:
|
|
case Key.ControlB:
|
|
DecCursorPosition ();
|
|
break;
|
|
|
|
case Key.End:
|
|
case Key.ControlE: // End
|
|
CursorPosition = FieldLen;
|
|
break;
|
|
|
|
case Key.CursorRight:
|
|
case Key.ControlF:
|
|
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 ();
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool MouseEvent (MouseEvent ev)
|
|
{
|
|
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked))
|
|
return false;
|
|
if (!HasFocus)
|
|
SuperView.SetFocus (this);
|
|
|
|
var point = ev.X;
|
|
if (point > FieldLen)
|
|
point = FieldLen;
|
|
if (point < 1)
|
|
point = 1;
|
|
CursorPosition = point;
|
|
AdjCursorPosition ();
|
|
return true;
|
|
}
|
|
}
|
|
} |