using System; namespace Terminal.Gui { /// /// shows a group of radio labels, only one of those can be selected at a given time /// public class RadioGroup : View { int selected, cursor; /// /// Initializes a new instance of the class /// setting up the initial set of radio labels and the item that should be selected and uses /// an absolute layout for the result. /// /// Boundaries for the radio group. /// The radio labels; an array of strings that can contain hotkeys using an underscore before the letter. /// The index of item to be selected, the value is clamped to the number of items. public RadioGroup (Rect rect, string [] radioLabels, int selected = 0) : base (rect) { this.selected = selected; this.radioLabels = radioLabels; CanFocus = true; } /// /// The location of the cursor in the /// public int Cursor { get => cursor; set { if (cursor < 0 || cursor >= radioLabels.Length) return; cursor = value; SetNeedsDisplay (); } } /// /// Initializes a new instance of the class /// setting up the initial set of radio labels and the item that should be selected. /// /// The radio labels; an array of strings that can contain hotkeys using an underscore before the letter. /// The index of the item to be selected, the value is clamped to the number of items. public RadioGroup (string [] radioLabels, int selected = 0) : base () { SetWidthHeight(radioLabels); this.selected = selected; this.radioLabels = radioLabels; CanFocus = true; } void SetWidthHeight(string[] radioLabels) { var r = MakeRect(0, 0, radioLabels); Width = r.Width; Height = radioLabels.Length; } static Rect MakeRect (int x, int y, string [] radioLabels) { int width = 0; foreach (var s in radioLabels) width = Math.Max (s.Length + 4, width); return new Rect (x, y, width, radioLabels.Length); } /// /// Initializes a new instance of the class /// setting up the initial set of radio labels and the item that should be selected. /// The frame is computed from the provided radio labels. /// /// The x coordinate. /// The y coordinate. /// The radio labels; an array of strings that can contain hotkeys using an underscore before the letter. /// The item to be selected, the value is clamped to the number of items. public RadioGroup (int x, int y, string [] radioLabels, int selected = 0) : this (MakeRect (x, y, radioLabels), radioLabels, selected) { } string [] radioLabels; /// /// The radio labels to display /// /// The radio labels. public string [] RadioLabels { get => radioLabels; set { Update(value); radioLabels = value; selected = 0; cursor = 0; SetNeedsDisplay (); } } void Update(string [] newRadioLabels) { for (int i = 0; i < radioLabels.Length; i++) { Move(0, i); Driver.SetAttribute(ColorScheme.Normal); Driver.AddStr(new string(' ', radioLabels[i].Length + 4)); } if (newRadioLabels.Length != radioLabels.Length) { SetWidthHeight(newRadioLabels); } } /// public override void Redraw (Rect region) { for (int i = 0; i < radioLabels.Length; i++) { Move (0, i); Driver.SetAttribute (ColorScheme.Normal); Driver.AddStr (i == selected ? "(o) " : "( ) "); DrawHotString (radioLabels [i], HasFocus && i == cursor, ColorScheme); } base.Redraw (region); } /// public override void PositionCursor () { Move (1, cursor); } /// public Action SelectionChanged; /// /// The currently selected item from the list of radio labels /// /// The selected. public int Selected { get => selected; set { selected = value; SelectionChanged?.Invoke (selected); SetNeedsDisplay (); } } /// public override bool ProcessColdKey (KeyEvent kb) { var key = kb.KeyValue; if (key < Char.MaxValue && Char.IsLetterOrDigit ((char)key)) { int i = 0; key = Char.ToUpper ((char)key); foreach (var l in radioLabels) { bool nextIsHot = false; foreach (var c in l) { if (c == '_') nextIsHot = true; else { if (nextIsHot && c == key) { Selected = i; cursor = i; if (!HasFocus) SuperView.SetFocus (this); return true; } nextIsHot = false; } } i++; } } return false; } /// public override bool ProcessKey (KeyEvent kb) { switch (kb.Key) { case Key.CursorUp: if (cursor > 0) { cursor--; SetNeedsDisplay (); return true; } break; case Key.CursorDown: if (cursor + 1 < radioLabels.Length) { cursor++; SetNeedsDisplay (); return true; } break; case Key.Space: Selected = cursor; return true; } return base.ProcessKey (kb); } /// public override bool MouseEvent (MouseEvent me) { if (!me.Flags.HasFlag (MouseFlags.Button1Clicked)) return false; SuperView.SetFocus (this); if (me.Y < radioLabels.Length) { cursor = Selected = me.Y; SetNeedsDisplay (); } return true; } } }