// // Checkbox.cs: Checkbox control // // Authors: // Miguel de Icaza (miguel@gnome.org) // using System; using NStack; namespace Terminal.Gui { /// /// The shows an on/off toggle that the user can set /// public class CheckBox : View { ustring text; Key hotKey = Key.Null; Rune hotKeySpecifier; Rune charChecked; Rune charUnChecked; bool @checked; /// /// 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 Action Toggled; /// /// Called when the property changes. Invokes the event. /// public virtual void OnToggled (bool previousChecked) { Toggled?.Invoke (previousChecked); } /// /// 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 (ustring s, bool is_checked = false) : base () { Initialize (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, ustring 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, ustring s, bool is_checked) : base (new Rect (x, y, s.Length + 4, 1)) { Initialize (s, is_checked); } void Initialize (ustring s, bool is_checked) { charChecked = new Rune (Driver != null ? Driver.Checked : '√'); charUnChecked = new Rune (Driver != null ? Driver.UnChecked : '╴'); Checked = is_checked; HotKeySpecifier = new Rune ('_'); CanFocus = true; AutoSize = true; Text = s; Update (); // 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); } void Update () { switch (TextAlignment) { case TextAlignment.Left: case TextAlignment.Centered: case TextAlignment.Justified: if (Checked) TextFormatter.Text = ustring.Make (charChecked) + " " + GetFormatterText (); else TextFormatter.Text = ustring.Make (charUnChecked) + " " + GetFormatterText (); break; case TextAlignment.Right: if (Checked) TextFormatter.Text = GetFormatterText () + " " + ustring.Make (charChecked); else TextFormatter.Text = GetFormatterText () + " " + ustring.Make (charUnChecked); break; } int w = TextFormatter.Size.Width - (TextFormatter.Text.Contains (HotKeySpecifier) ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0); GetCurrentWidth (out int cWidth); var canSetWidth = SetWidth (w, out int rWidth); if (canSetWidth && (cWidth < rWidth || AutoSize)) { Width = rWidth; w = rWidth; } else if (!canSetWidth || !AutoSize) { w = cWidth; } var layout = LayoutStyle; bool layoutChanged = false; if (!(Height is Dim.DimAbsolute)) { // The height is always equal to 1 and must be Dim.DimAbsolute. layoutChanged = true; LayoutStyle = LayoutStyle.Absolute; } Height = 1; if (layoutChanged) { LayoutStyle = layout; } Frame = new Rect (Frame.Location, new Size (w, 1)); SetNeedsDisplay (); } ustring GetFormatterText () { if (AutoSize || ustring.IsNullOrEmpty (text)) { return text; } return text.RuneSubstring (0, Math.Min (Frame.Width - 2, text.RuneCount)); } /// public override Key HotKey { get => hotKey; set { if (hotKey != value) { var v = value == Key.Unknown ? Key.Null : value; hotKey = v; } } } /// public override Rune HotKeySpecifier { get => hotKeySpecifier; set { hotKeySpecifier = TextFormatter.HotKeySpecifier = value; } } /// public override bool AutoSize { get => base.AutoSize; set { base.AutoSize = value; Update (); } } /// /// The state of the /// public bool Checked { get => @checked; set { @checked = value; Update (); } } /// /// The text displayed by this /// public new ustring Text { get { return text; } set { text = value; TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk); if (hotKey != hk) { HotKey = hk; } Update (); } } /// public override TextAlignment TextAlignment { get => base.TextAlignment; set { base.TextAlignment = value; Update (); } } /// 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; Checked = !Checked; OnToggled (previousChecked); SetNeedsDisplay (); return true; } /// public override bool MouseEvent (MouseEvent me) { if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) || !CanFocus) return false; SetFocus (); var previousChecked = Checked; Checked = !Checked; OnToggled (previousChecked); SetNeedsDisplay (); return true; } /// public override bool OnEnter (View view) { Application.Driver.SetCursorVisibility (CursorVisibility.Invisible); return base.OnEnter (view); } } }