|
@@ -205,61 +205,89 @@ public class RadioGroup : View
|
|
|
// Return labels as a CSV string
|
|
|
return string.Join (",", _radioLabels);
|
|
|
}
|
|
|
- set =>
|
|
|
-
|
|
|
- // Parse as CSV string with spaces trimmed
|
|
|
- RadioLabels = value.Split (',').Select (x => x.Trim ()).ToArray ();
|
|
|
-
|
|
|
+ set
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty (value))
|
|
|
+ {
|
|
|
+ RadioLabels = [];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ RadioLabels = value.Split (',').Select (x => x.Trim ()).ToArray ();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>The currently selected item from the list of radio labels</summary>
|
|
|
/// <value>The selected.</value>
|
|
|
public int SelectedItem
|
|
|
+{
|
|
|
+ get => _selected;
|
|
|
+ set
|
|
|
{
|
|
|
- get => _selected;
|
|
|
- set
|
|
|
- {
|
|
|
- OnSelectedItemChanged (value, SelectedItem);
|
|
|
- _cursor = Math.Max (_selected, 0);
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
+ OnSelectedItemChanged (value, SelectedItem);
|
|
|
+ _cursor = Math.Max (_selected, 0);
|
|
|
+ SetNeedsDisplay ();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override void OnDrawContent (Rectangle viewport)
|
|
|
- {
|
|
|
- base.OnDrawContent (viewport);
|
|
|
+/// <inheritdoc/>
|
|
|
+public override void OnDrawContent (Rectangle viewport)
|
|
|
+{
|
|
|
+ base.OnDrawContent (viewport);
|
|
|
|
|
|
- Driver.SetAttribute (GetNormalColor ());
|
|
|
+ Driver.SetAttribute (GetNormalColor ());
|
|
|
|
|
|
- for (var i = 0; i < _radioLabels.Count; i++)
|
|
|
+ for (var i = 0; i < _radioLabels.Count; i++)
|
|
|
+ {
|
|
|
+ switch (Orientation)
|
|
|
{
|
|
|
- switch (Orientation)
|
|
|
- {
|
|
|
- case Orientation.Vertical:
|
|
|
- Move (0, i);
|
|
|
+ case Orientation.Vertical:
|
|
|
+ Move (0, i);
|
|
|
|
|
|
- break;
|
|
|
- case Orientation.Horizontal:
|
|
|
- Move (_horizontal [i].pos, 0);
|
|
|
+ break;
|
|
|
+ case Orientation.Horizontal:
|
|
|
+ Move (_horizontal [i].pos, 0);
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- string rl = _radioLabels [i];
|
|
|
- Driver.SetAttribute (GetNormalColor ());
|
|
|
- Driver.AddStr ($"{(i == _selected ? Glyphs.Selected : Glyphs.UnSelected)} ");
|
|
|
- TextFormatter.FindHotKey (rl, HotKeySpecifier, out int hotPos, out Key hotKey);
|
|
|
+ string rl = _radioLabels [i];
|
|
|
+ Driver.SetAttribute (GetNormalColor ());
|
|
|
+ Driver.AddStr ($"{(i == _selected ? Glyphs.Selected : Glyphs.UnSelected)} ");
|
|
|
+ TextFormatter.FindHotKey (rl, HotKeySpecifier, out int hotPos, out Key hotKey);
|
|
|
+
|
|
|
+ if (hotPos != -1 && hotKey != Key.Empty)
|
|
|
+ {
|
|
|
+ Rune [] rlRunes = rl.ToRunes ();
|
|
|
|
|
|
- if (hotPos != -1 && hotKey != Key.Empty)
|
|
|
+ for (var j = 0; j < rlRunes.Length; j++)
|
|
|
{
|
|
|
- Rune [] rlRunes = rl.ToRunes ();
|
|
|
+ Rune rune = rlRunes [j];
|
|
|
|
|
|
- for (var j = 0; j < rlRunes.Length; j++)
|
|
|
+ if (j == hotPos && i == _cursor)
|
|
|
{
|
|
|
- Rune rune = rlRunes [j];
|
|
|
+ Application.Driver.SetAttribute (
|
|
|
+ HasFocus
|
|
|
+ ? ColorScheme.HotFocus
|
|
|
+ : GetHotNormalColor ()
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else if (j == hotPos && i != _cursor)
|
|
|
+ {
|
|
|
+ Application.Driver.SetAttribute (GetHotNormalColor ());
|
|
|
+ }
|
|
|
+ else if (HasFocus && i == _cursor)
|
|
|
+ {
|
|
|
+ Application.Driver.SetAttribute (ColorScheme.Focus);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rune == HotKeySpecifier && j + 1 < rlRunes.Length)
|
|
|
+ {
|
|
|
+ j++;
|
|
|
+ rune = rlRunes [j];
|
|
|
|
|
|
- if (j == hotPos && i == _cursor)
|
|
|
+ if (i == _cursor)
|
|
|
{
|
|
|
Application.Driver.SetAttribute (
|
|
|
HasFocus
|
|
@@ -267,206 +295,184 @@ public class RadioGroup : View
|
|
|
: GetHotNormalColor ()
|
|
|
);
|
|
|
}
|
|
|
- else if (j == hotPos && i != _cursor)
|
|
|
+ else if (i != _cursor)
|
|
|
{
|
|
|
Application.Driver.SetAttribute (GetHotNormalColor ());
|
|
|
}
|
|
|
- else if (HasFocus && i == _cursor)
|
|
|
- {
|
|
|
- Application.Driver.SetAttribute (ColorScheme.Focus);
|
|
|
- }
|
|
|
-
|
|
|
- if (rune == HotKeySpecifier && j + 1 < rlRunes.Length)
|
|
|
- {
|
|
|
- j++;
|
|
|
- rune = rlRunes [j];
|
|
|
-
|
|
|
- if (i == _cursor)
|
|
|
- {
|
|
|
- Application.Driver.SetAttribute (
|
|
|
- HasFocus
|
|
|
- ? ColorScheme.HotFocus
|
|
|
- : GetHotNormalColor ()
|
|
|
- );
|
|
|
- }
|
|
|
- else if (i != _cursor)
|
|
|
- {
|
|
|
- Application.Driver.SetAttribute (GetHotNormalColor ());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Application.Driver.AddRune (rune);
|
|
|
- Driver.SetAttribute (GetNormalColor ());
|
|
|
}
|
|
|
+
|
|
|
+ Application.Driver.AddRune (rune);
|
|
|
+ Driver.SetAttribute (GetNormalColor ());
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- DrawHotString (rl, HasFocus && i == _cursor, ColorScheme);
|
|
|
- }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DrawHotString (rl, HasFocus && i == _cursor, ColorScheme);
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override bool? OnInvokingKeyBindings (Key keyEvent)
|
|
|
- {
|
|
|
- // This is a bit of a hack. We want to handle the key bindings for the radio group but
|
|
|
- // InvokeKeyBindings doesn't pass any context so we can't tell if the key binding is for
|
|
|
- // the radio group or for one of the radio buttons. So before we call the base class
|
|
|
- // we set SelectedItem appropriately.
|
|
|
+/// <inheritdoc/>
|
|
|
+public override bool? OnInvokingKeyBindings (Key keyEvent)
|
|
|
+{
|
|
|
+ // This is a bit of a hack. We want to handle the key bindings for the radio group but
|
|
|
+ // InvokeKeyBindings doesn't pass any context so we can't tell if the key binding is for
|
|
|
+ // the radio group or for one of the radio buttons. So before we call the base class
|
|
|
+ // we set SelectedItem appropriately.
|
|
|
|
|
|
- Key key = keyEvent;
|
|
|
+ Key key = keyEvent;
|
|
|
|
|
|
- if (KeyBindings.TryGet (key, out _))
|
|
|
+ if (KeyBindings.TryGet (key, out _))
|
|
|
+ {
|
|
|
+ // Search RadioLabels
|
|
|
+ for (var i = 0; i < _radioLabels.Count; i++)
|
|
|
{
|
|
|
- // Search RadioLabels
|
|
|
- for (var i = 0; i < _radioLabels.Count; i++)
|
|
|
+ if (TextFormatter.FindHotKey (
|
|
|
+ _radioLabels [i],
|
|
|
+ HotKeySpecifier,
|
|
|
+ out _,
|
|
|
+ out Key hotKey,
|
|
|
+ true
|
|
|
+ )
|
|
|
+ && key.NoAlt.NoCtrl.NoShift == hotKey)
|
|
|
{
|
|
|
- if (TextFormatter.FindHotKey (
|
|
|
- _radioLabels [i],
|
|
|
- HotKeySpecifier,
|
|
|
- out _,
|
|
|
- out Key hotKey,
|
|
|
- true
|
|
|
- )
|
|
|
- && key.NoAlt.NoCtrl.NoShift == hotKey)
|
|
|
- {
|
|
|
- SelectedItem = i;
|
|
|
- break;
|
|
|
- }
|
|
|
+ SelectedItem = i;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return base.OnInvokingKeyBindings (keyEvent);
|
|
|
}
|
|
|
|
|
|
- /// <summary>Called when the view orientation has changed. Invokes the <see cref="OrientationChanged"/> event.</summary>
|
|
|
- /// <param name="newOrientation"></param>
|
|
|
- /// <returns>True of the event was cancelled.</returns>
|
|
|
- public virtual bool OnOrientationChanged (Orientation newOrientation)
|
|
|
- {
|
|
|
- var args = new OrientationEventArgs (newOrientation);
|
|
|
- OrientationChanged?.Invoke (this, args);
|
|
|
-
|
|
|
- if (!args.Cancel)
|
|
|
- {
|
|
|
- _orientation = newOrientation;
|
|
|
- SetupKeyBindings ();
|
|
|
- SetContentSize ();
|
|
|
- }
|
|
|
+ return base.OnInvokingKeyBindings (keyEvent);
|
|
|
+}
|
|
|
|
|
|
- return args.Cancel;
|
|
|
- }
|
|
|
+/// <summary>Called when the view orientation has changed. Invokes the <see cref="OrientationChanged"/> event.</summary>
|
|
|
+/// <param name="newOrientation"></param>
|
|
|
+/// <returns>True of the event was cancelled.</returns>
|
|
|
+public virtual bool OnOrientationChanged (Orientation newOrientation)
|
|
|
+{
|
|
|
+ var args = new OrientationEventArgs (newOrientation);
|
|
|
+ OrientationChanged?.Invoke (this, args);
|
|
|
|
|
|
- // TODO: This should be cancelable
|
|
|
- /// <summary>Called whenever the current selected item changes. Invokes the <see cref="SelectedItemChanged"/> event.</summary>
|
|
|
- /// <param name="selectedItem"></param>
|
|
|
- /// <param name="previousSelectedItem"></param>
|
|
|
- public virtual void OnSelectedItemChanged (int selectedItem, int previousSelectedItem)
|
|
|
+ if (!args.Cancel)
|
|
|
{
|
|
|
- _selected = selectedItem;
|
|
|
- SelectedItemChanged?.Invoke (this, new SelectedItemChangedArgs (selectedItem, previousSelectedItem));
|
|
|
+ _orientation = newOrientation;
|
|
|
+ SetupKeyBindings ();
|
|
|
+ SetContentSize ();
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Fired when the view orientation has changed. Can be cancelled by setting
|
|
|
- /// <see cref="OrientationEventArgs.Cancel"/> to true.
|
|
|
- /// </summary>
|
|
|
- public event EventHandler<OrientationEventArgs> OrientationChanged;
|
|
|
+ return args.Cancel;
|
|
|
+}
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override Point? PositionCursor ()
|
|
|
- {
|
|
|
- int x = 0;
|
|
|
- int y = 0;
|
|
|
- switch (Orientation)
|
|
|
- {
|
|
|
- case Orientation.Vertical:
|
|
|
- y = _cursor;
|
|
|
+// TODO: This should be cancelable
|
|
|
+/// <summary>Called whenever the current selected item changes. Invokes the <see cref="SelectedItemChanged"/> event.</summary>
|
|
|
+/// <param name="selectedItem"></param>
|
|
|
+/// <param name="previousSelectedItem"></param>
|
|
|
+public virtual void OnSelectedItemChanged (int selectedItem, int previousSelectedItem)
|
|
|
+{
|
|
|
+ _selected = selectedItem;
|
|
|
+ SelectedItemChanged?.Invoke (this, new SelectedItemChangedArgs (selectedItem, previousSelectedItem));
|
|
|
+}
|
|
|
|
|
|
- break;
|
|
|
- case Orientation.Horizontal:
|
|
|
- x = _horizontal [_cursor].pos;
|
|
|
+/// <summary>
|
|
|
+/// Fired when the view orientation has changed. Can be cancelled by setting
|
|
|
+/// <see cref="OrientationEventArgs.Cancel"/> to true.
|
|
|
+/// </summary>
|
|
|
+public event EventHandler<OrientationEventArgs> OrientationChanged;
|
|
|
|
|
|
- break;
|
|
|
+/// <inheritdoc/>
|
|
|
+public override Point? PositionCursor ()
|
|
|
+{
|
|
|
+ int x = 0;
|
|
|
+ int y = 0;
|
|
|
+ switch (Orientation)
|
|
|
+ {
|
|
|
+ case Orientation.Vertical:
|
|
|
+ y = _cursor;
|
|
|
|
|
|
- default:
|
|
|
- return null;
|
|
|
- }
|
|
|
+ break;
|
|
|
+ case Orientation.Horizontal:
|
|
|
+ x = _horizontal [_cursor].pos;
|
|
|
+
|
|
|
+ break;
|
|
|
|
|
|
- Move (x, y);
|
|
|
- return null; // Don't show the cursor
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
- /// <summary>Allow to invoke the <see cref="SelectedItemChanged"/> after their creation.</summary>
|
|
|
- public void Refresh () { OnSelectedItemChanged (_selected, -1); }
|
|
|
+ Move (x, y);
|
|
|
+ return null; // Don't show the cursor
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>Allow to invoke the <see cref="SelectedItemChanged"/> after their creation.</summary>
|
|
|
+public void Refresh () { OnSelectedItemChanged (_selected, -1); }
|
|
|
|
|
|
- // TODO: This should use StateEventArgs<int> and should be cancelable.
|
|
|
- /// <summary>Invoked when the selected radio label has changed.</summary>
|
|
|
- public event EventHandler<SelectedItemChangedArgs> SelectedItemChanged;
|
|
|
+// TODO: This should use StateEventArgs<int> and should be cancelable.
|
|
|
+/// <summary>Invoked when the selected radio label has changed.</summary>
|
|
|
+public event EventHandler<SelectedItemChangedArgs> SelectedItemChanged;
|
|
|
|
|
|
- private void MoveDownRight ()
|
|
|
+private void MoveDownRight ()
|
|
|
+{
|
|
|
+ if (_cursor + 1 < _radioLabels.Count)
|
|
|
{
|
|
|
- if (_cursor + 1 < _radioLabels.Count)
|
|
|
- {
|
|
|
- _cursor++;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
- else if (_cursor > 0)
|
|
|
- {
|
|
|
- _cursor = 0;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
+ _cursor++;
|
|
|
+ SetNeedsDisplay ();
|
|
|
+ }
|
|
|
+ else if (_cursor > 0)
|
|
|
+ {
|
|
|
+ _cursor = 0;
|
|
|
+ SetNeedsDisplay ();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- private void MoveEnd () { _cursor = Math.Max (_radioLabels.Count - 1, 0); }
|
|
|
- private void MoveHome () { _cursor = 0; }
|
|
|
+private void MoveEnd () { _cursor = Math.Max (_radioLabels.Count - 1, 0); }
|
|
|
+private void MoveHome () { _cursor = 0; }
|
|
|
|
|
|
- private void MoveUpLeft ()
|
|
|
+private void MoveUpLeft ()
|
|
|
+{
|
|
|
+ if (_cursor > 0)
|
|
|
{
|
|
|
- if (_cursor > 0)
|
|
|
- {
|
|
|
- _cursor--;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
- else if (_radioLabels.Count - 1 > 0)
|
|
|
- {
|
|
|
- _cursor = _radioLabels.Count - 1;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
+ _cursor--;
|
|
|
+ SetNeedsDisplay ();
|
|
|
+ }
|
|
|
+ else if (_radioLabels.Count - 1 > 0)
|
|
|
+ {
|
|
|
+ _cursor = _radioLabels.Count - 1;
|
|
|
+ SetNeedsDisplay ();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- private void RadioGroup_LayoutStarted (object sender, EventArgs e) { SetContentSize (); }
|
|
|
- private void SelectItem () { SelectedItem = _cursor; }
|
|
|
+private void RadioGroup_LayoutStarted (object sender, EventArgs e) { SetContentSize (); }
|
|
|
+private void SelectItem () { SelectedItem = _cursor; }
|
|
|
|
|
|
- private void SetContentSize ()
|
|
|
+private void SetContentSize ()
|
|
|
+{
|
|
|
+ switch (_orientation)
|
|
|
{
|
|
|
- switch (_orientation)
|
|
|
- {
|
|
|
- case Orientation.Vertical:
|
|
|
- var width = 0;
|
|
|
+ case Orientation.Vertical:
|
|
|
+ var width = 0;
|
|
|
|
|
|
- foreach (string s in _radioLabels)
|
|
|
- {
|
|
|
- width = Math.Max (s.GetColumns () + 2, width);
|
|
|
- }
|
|
|
+ foreach (string s in _radioLabels)
|
|
|
+ {
|
|
|
+ width = Math.Max (s.GetColumns () + 2, width);
|
|
|
+ }
|
|
|
|
|
|
- SetContentSize (new (width, _radioLabels.Count));
|
|
|
- break;
|
|
|
+ SetContentSize (new (width, _radioLabels.Count));
|
|
|
+ break;
|
|
|
|
|
|
- case Orientation.Horizontal:
|
|
|
- _horizontal = new List<(int pos, int length)> ();
|
|
|
- var start = 0;
|
|
|
- var length = 0;
|
|
|
+ case Orientation.Horizontal:
|
|
|
+ _horizontal = new List<(int pos, int length)> ();
|
|
|
+ var start = 0;
|
|
|
+ var length = 0;
|
|
|
|
|
|
- for (var i = 0; i < _radioLabels.Count; i++)
|
|
|
- {
|
|
|
- start += length;
|
|
|
+ for (var i = 0; i < _radioLabels.Count; i++)
|
|
|
+ {
|
|
|
+ start += length;
|
|
|
|
|
|
- length = _radioLabels [i].GetColumns () + 2 + (i < _radioLabels.Count - 1 ? _horizontalSpace : 0);
|
|
|
- _horizontal.Add ((start, length));
|
|
|
- }
|
|
|
- SetContentSize (new (_horizontal.Sum (item => item.length), 1));
|
|
|
- break;
|
|
|
- }
|
|
|
+ length = _radioLabels [i].GetColumns () + 2 + (i < _radioLabels.Count - 1 ? _horizontalSpace : 0);
|
|
|
+ _horizontal.Add ((start, length));
|
|
|
+ }
|
|
|
+ SetContentSize (new (_horizontal.Sum (item => item.length), 1));
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
+}
|