// // Checkbox.cs: Checkbox control // // Authors: // Miguel de Icaza (miguel@gnome.org) // using System; using System.Text; namespace Terminal.Gui { /// /// The shows an on/off toggle that the user can set /// public class CheckBox : View { Rune charNullChecked; Rune charChecked; Rune charUnChecked; bool? @checked; bool allowNullChecked; /// /// Toggled event, raised when the is toggled. /// /// /// Client code can hook up to this event, it is /// raised when the is activated either with /// the mouse or the keyboard. The passed bool contains the previous state. /// public event EventHandler Toggled; /// /// Called when the property changes. Invokes the event. /// public virtual void OnToggled (ToggleEventArgs e) { Toggled?.Invoke (this, e); } /// /// Initializes a new instance of based on the given text, using layout. /// public CheckBox () : this (string.Empty) { } /// /// Initializes a new instance of based on the given text, using layout. /// /// S. /// If set to true is checked. public CheckBox (string s, bool is_checked = false) : base () { SetInitialProperties (s, is_checked); } /// /// Initializes a new instance of using layout. /// /// /// The size of is computed based on the /// text length. This is not toggled. /// public CheckBox (int x, int y, string s) : this (x, y, s, false) { } /// /// Initializes a new instance of using layout. /// /// /// The size of is computed based on the /// text length. /// public CheckBox (int x, int y, string s, bool is_checked) : base (new Rect (x, y, s.Length, 1)) { SetInitialProperties (s, is_checked); } // TODO: v2 - Remove constructors with parameters /// /// Private helper to set the initial properties of the View that were provided via constructors. /// /// /// void SetInitialProperties (string s, bool is_checked) { charNullChecked = CM.Glyphs.NullChecked; charChecked = CM.Glyphs.Checked; charUnChecked = CM.Glyphs.UnChecked; Checked = is_checked; HotKeySpecifier = (Rune)'_'; CanFocus = true; AutoSize = true; Text = s; OnResizeNeeded (); // Things this view knows how to do AddCommand (Command.ToggleChecked, () => ToggleChecked ()); // Default keybindings for this view AddKeyBinding ((Key)' ', Command.ToggleChecked); AddKeyBinding (Key.Space, Command.ToggleChecked); } /// protected override void UpdateTextFormatterText () { switch (TextAlignment) { case TextAlignment.Left: case TextAlignment.Centered: case TextAlignment.Justified: TextFormatter.Text = $"{GetCheckedState ()} {GetFormatterText ()}"; break; case TextAlignment.Right: TextFormatter.Text = $"{GetFormatterText ()} {GetCheckedState ()}"; break; } } Rune GetCheckedState () { return Checked switch { true => charChecked, false => charUnChecked, var _ => charNullChecked }; } string GetFormatterText () { if (AutoSize || string.IsNullOrEmpty (Text) || Frame.Width <= 2) { return Text; } return Text [..Math.Min (Frame.Width - 2, Text.GetRuneCount ())]; } /// /// The state of the /// public bool? Checked { get => @checked; set { if (value == null && !AllowNullChecked) { return; } @checked = value; UpdateTextFormatterText (); OnResizeNeeded (); } } /// /// If allows to be null, true or false. /// If only allows to be true or false. /// public bool AllowNullChecked { get => allowNullChecked; set { allowNullChecked = value; Checked ??= false; } } /// public override void PositionCursor () { Move (0, 0); } /// public override bool ProcessKey (KeyEvent kb) { var result = InvokeKeybindings (kb); if (result != null) return (bool)result; return base.ProcessKey (kb); } /// public override bool ProcessHotKey (KeyEvent kb) { if (kb.Key == (Key.AltMask | HotKey)) return ToggleChecked (); return false; } bool ToggleChecked () { if (!HasFocus) { SetFocus (); } var previousChecked = Checked; if (AllowNullChecked) { switch (previousChecked) { case null: Checked = true; break; case true: Checked = false; break; case false: Checked = null; break; } } else { Checked = !Checked; } OnToggled (new ToggleEventArgs (previousChecked, Checked)); SetNeedsDisplay (); return true; } /// public override bool MouseEvent (MouseEvent me) { if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) || !CanFocus) return false; ToggleChecked (); return true; } /// public override bool OnEnter (View view) { Application.Driver.SetCursorVisibility (CursorVisibility.Invisible); return base.OnEnter (view); } } }