//
// 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);
}
}
}