Browse Source

RadioButton

Miguel de Icaza 7 years ago
parent
commit
305bfaf135
5 changed files with 181 additions and 3 deletions
  1. 15 1
      Core.cs
  2. 19 0
      TODO.md
  3. 1 0
      Terminal.csproj
  4. 143 0
      Views/RadioGroup.cs
  5. 3 2
      demo.cs

+ 15 - 1
Core.cs

@@ -343,7 +343,7 @@ namespace Terminal {
 		/// <summary>
 		/// Utility function to draw strings that contain a hotkey
 		/// </summary>
-		/// <param name="s">String to display, the underscoore before a letter flags the next letter as the hotkey.</param>
+		/// <param name="text">String to display, the underscoore before a letter flags the next letter as the hotkey.</param>
 		/// <param name="hotColor">Hot color.</param>
 		/// <param name="normalColor">Normal color.</param>
 		public void DrawHotString (string text, Attribute hotColor, Attribute normalColor)
@@ -359,6 +359,20 @@ namespace Terminal {
 			}
 		}
 
+		/// <summary>
+		/// Utility function to draw strings that contains a hotkey using a colorscheme and the "focused" state.
+		/// </summary>
+		/// <param name="text">String to display, the underscoore before a letter flags the next letter as the hotkey.</param>
+		/// <param name="focused">If set to <c>true</c> this uses the focused colors from the color scheme, otherwise the regular ones.</param>
+		/// <param name="scheme">The color scheme to use.</param>
+		public void DrawHotString (string text, bool focused, ColorScheme scheme)
+		{
+			if (focused)
+				DrawHotString (text, scheme.HotFocus, scheme.Focus);
+			else
+				DrawHotString (text, scheme.HotNormal, scheme.Normal);
+		}
+
 		/// <summary>
 		/// This moves the cursor to the specified column and row in the view.
 		/// </summary>

+ 19 - 0
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.

+ 1 - 0
Terminal.csproj

@@ -46,6 +46,7 @@
     <Compile Include="Views\Menu.cs" />
     <Compile Include="Views\ScrollView.cs" />
     <Compile Include="Views\Dialog.cs" />
+    <Compile Include="Views\RadioGroup.cs" />
   </ItemGroup>
   <ItemGroup>
    <Reference Include="mono-curses.dll">

+ 143 - 0
Views/RadioGroup.cs

@@ -0,0 +1,143 @@
+using System;
+namespace Terminal {
+	/// <summary>
+	/// Radio group shows a group of labels, only one of those can be selected at a given time
+	/// </summary>
+	public class RadioGroup : View {
+		int selected, cursor;
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="T:Terminal.RadioGroup"/> class
+		/// setting up the initial set of radio labels and the item that should be selected.
+		/// </summary>
+		/// <param name="rect">Boundaries for the radio group.</param>
+		/// <param name="radioLabels">Radio labels, the strings can contain hotkeys using an undermine before the letter.</param>
+		/// <param name="selected">The item to be selected, the value is clamped to the number of items.</param>
+		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);
+		}
+		/// <summary>
+		/// Initializes a new instance of the <see cref="T:Terminal.RadioGroup"/> 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.
+		/// </summary>
+		/// <param name="x">The x coordinate.</param>
+		/// <param name="y">The y coordinate.</param>
+		/// <param name="radioLabels">Radio labels, the strings can contain hotkeys using an undermine before the letter.</param>
+		/// <param name="selected">The item to be selected, the value is clamped to the number of items.</param>		/// <summary>
+		public RadioGroup (int x, int y, string [] radioLabels, int selected = 0) : this (MakeRect (x, y, radioLabels), radioLabels, selected)
+		{
+		}
+
+		string [] radioLabels;
+
+		/// <summary>
+		/// The radio labels to display
+		/// </summary>
+		/// <value>The radio labels.</value>
+		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<int> SelectionChanged;
+
+		/// <summary>
+		/// The currently selected item from the list of radio labels
+		/// </summary>
+		/// <value>The selected.</value>
+		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;
+			}
+		}
+	}
+}

+ 3 - 2
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")
 		);
 	}