diff --git a/Core.cs b/Core.cs
index 1bc6c1ec6..58b725b9b 100644
--- a/Core.cs
+++ b/Core.cs
@@ -343,7 +343,7 @@ namespace Terminal {
///
/// Utility function to draw strings that contain a hotkey
///
- /// String to display, the underscoore before a letter flags the next letter as the hotkey.
+ /// String to display, the underscoore before a letter flags the next letter as the hotkey.
/// Hot color.
/// Normal color.
public void DrawHotString (string text, Attribute hotColor, Attribute normalColor)
@@ -359,6 +359,20 @@ namespace Terminal {
}
}
+ ///
+ /// Utility function to draw strings that contains a hotkey using a colorscheme and the "focused" state.
+ ///
+ /// String to display, the underscoore before a letter flags the next letter as the hotkey.
+ /// If set to true this uses the focused colors from the color scheme, otherwise the regular ones.
+ /// The color scheme to use.
+ public void DrawHotString (string text, bool focused, ColorScheme scheme)
+ {
+ if (focused)
+ DrawHotString (text, scheme.HotFocus, scheme.Focus);
+ else
+ DrawHotString (text, scheme.HotNormal, scheme.Normal);
+ }
+
///
/// This moves the cursor to the specified column and row in the view.
///
diff --git a/TODO.md b/TODO.md
index ceca82360..ee0860aad 100644
--- a/TODO.md
+++ b/TODO.md
@@ -29,11 +29,17 @@ Should include another theme, like the TurboPascal 6 theme
Replaces `Colors.Base.Normal` with `Attributes.Normal`, and perhaps attributes
points to the container.
+Widgets should not use Colors.Base or Colors.Dialog, they should likely use
+the colors defined in the toplevel container, so that the Dialog vs Toplevel
+colors are set there only.
+
## Views
Checkbox, ListView, Menu.
Wanted:
+- HotLabels (should be labelsw ith a hotkey that take a focus view as an argument)
+- MessageBox
- Function Bar
- ScrollView
- Multi-line text editing
@@ -43,6 +49,11 @@ Wanted:
- Submenus in menus.
- Popup menus
- Make windows draggable
+- ListView
+- TreeView
+- View + Attribute for SolidFills?
+- Scrollbar
+- Frame container (with label)
High-level widgets:
- Time selector
@@ -50,10 +61,18 @@ High-level widgets:
- File selector
- Masked input
+Graphs:
+- Progress bar
+
+Should Views support Padding/Margin/Border? Would make it simpler for Forms backend and perhaps
+adopt the Forms CSS as-is
+
## Layout manager
Unclear what to do about that right now. Perhaps use Flex?
+Will at least need the protocol for sizing
+
# Unicode
Needs to move to `ustring` from `NStack.Core` to get full Unicode support.
diff --git a/Terminal.csproj b/Terminal.csproj
index f0965ea1e..55a6a60ee 100644
--- a/Terminal.csproj
+++ b/Terminal.csproj
@@ -46,6 +46,7 @@
+
diff --git a/Views/RadioGroup.cs b/Views/RadioGroup.cs
new file mode 100644
index 000000000..be138eb89
--- /dev/null
+++ b/Views/RadioGroup.cs
@@ -0,0 +1,143 @@
+using System;
+namespace Terminal {
+ ///
+ /// Radio group shows a group of 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.
+ ///
+ /// Boundaries for the radio group.
+ /// Radio labels, the strings can contain hotkeys using an undermine before the letter.
+ /// The 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;
+ }
+
+ static Rect MakeRect (int x, int y, string [] radioLabels)
+ {
+ int width = 0;
+
+ foreach (var s in radioLabels)
+ width = Math.Max (radioLabels.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 view frame is computed from the provided radioLabels.
+ ///
+ /// The x coordinate.
+ /// The y coordinate.
+ /// Radio labels, the strings can contain hotkeys using an undermine 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 {
+ radioLabels = value;
+ selected = 0;
+ cursor = 0;
+ SetNeedsDisplay ();
+ }
+ }
+
+ public override void Redraw (Rect region)
+ {
+ base.Redraw (region);
+ for (int i = 0; i < radioLabels.Length; i++) {
+ Move (0, i);
+ Driver.SetAttribute (Colors.Base.Normal);
+ Driver.AddStr (i == selected ? "(o) " : "( ) ");
+ DrawHotString (radioLabels [i], HasFocus && i == cursor, Colors.Base);
+ }
+ }
+
+ 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 ProcessHotKey (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;
+ case Key.CursorDown:
+ if (cursor + 1 < radioLabels.Length) {
+ cursor++;
+ SetNeedsDisplay ();
+ }
+ return true;
+ case Key.Space:
+ Selected = cursor;
+ return true;
+ default:
+
+ return false;
+ }
+ }
+ }
+}
diff --git a/demo.cs b/demo.cs
index 01c5d894d..7149cf385 100644
--- a/demo.cs
+++ b/demo.cs
@@ -18,8 +18,9 @@ class Demo {
new Label (3, 4, "Password: "),
new TextField (14, 4, 40, "") { Secret = true },
new CheckBox (3, 6, "Remember me"),
- new Button (3, 8, "Ok"),
- new Button (10, 8, "Cancel"),
+ new RadioGroup (3, 8, new [] { "_Personal", "_Company" }),
+ new Button (3, 14, "Ok"),
+ new Button (10, 14, "Cancel"),
new Label (3, 18, "Press ESC and 9 to activate the menubar")
);
}