Browse Source

Merge pull request #850 from BDisp/radiobutton-horizontal

Fixes #351. Added a horizontal display for RadioGroup.
Charlie Kindel 5 years ago
parent
commit
138e54c954
1 changed files with 110 additions and 24 deletions
  1. 110 24
      Terminal.Gui/Views/RadioGroup.cs

+ 110 - 24
Terminal.Gui/Views/RadioGroup.cs

@@ -10,15 +10,18 @@ namespace Terminal.Gui {
 	public class RadioGroup : View {
 		int selected = -1;
 		int cursor;
+		DisplayModeLayout displayMode;
+		int horizontalSpace = 2;
+		List<(int pos, int length)> horizontal;
 
-		void Init(Rect rect, ustring [] radioLabels, int selected)
+		void Init (Rect rect, ustring [] radioLabels, int selected)
 		{
 			if (radioLabels == null) {
 				this.radioLabels = new List<ustring>();
 			} else {
 				this.radioLabels = radioLabels.ToList ();
 			}
-			
+
 			this.selected = selected;
 			SetWidthHeight (this.radioLabels);
 			CanFocus = true;
@@ -59,30 +62,61 @@ namespace Terminal.Gui {
 		/// <param name="y">The y coordinate.</param>
 		/// <param name="radioLabels">The radio labels; an array of strings that can contain hotkeys using an underscore before the letter.</param>
 		/// <param name="selected">The item to be selected, the value is clamped to the number of items.</param>		
-		public RadioGroup (int x, int y, ustring [] radioLabels, int selected = 0) : 
+		public RadioGroup (int x, int y, ustring [] radioLabels, int selected = 0) :
 			this (MakeRect (x, y, radioLabels != null ? radioLabels.ToList() : null), radioLabels, selected) { }
 
 		/// <summary>
-		/// The location of the cursor in the <see cref="RadioGroup"/>
+		/// Gets or sets the <see cref="DisplayModeLayout"/> for this <see cref="RadioGroup"/>.
 		/// </summary>
-		public int Cursor {
-			get => cursor;
+		public DisplayModeLayout DisplayMode {
+			get { return displayMode; }
 			set {
-				if (cursor < 0 || cursor >= radioLabels.Count)
-					return;
-				cursor = value;
-				SetNeedsDisplay ();
+				if (displayMode != value) {
+					displayMode = value;
+					SetWidthHeight (radioLabels);
+					SetNeedsDisplay ();
+				}
+			}
+		}
+
+		/// <summary>
+		/// Gets or sets the horizontal space for this <see cref="RadioGroup"/> if the <see cref="DisplayMode"/> is <see cref="DisplayModeLayout.Horizontal"/>
+		/// </summary>
+		public int HorizontalSpace {
+			get { return horizontalSpace; }
+			set {
+				if (horizontalSpace != value && displayMode == DisplayModeLayout.Horizontal) {
+					horizontalSpace = value;
+					SetWidthHeight (radioLabels);
+					SetNeedsDisplay ();
+				}
 			}
 		}
 
 		void SetWidthHeight (List<ustring> radioLabels)
 		{
-			var r = MakeRect(0, 0, radioLabels);
-			if (LayoutStyle == LayoutStyle.Computed) {
-				Width = r.Width;
-				Height = radioLabels.Count;
-			} else {
-				Frame = new Rect (Frame.Location, new Size (r.Width, radioLabels.Count));
+			switch (displayMode) {
+			case DisplayModeLayout.Vertical:
+				var r = MakeRect (0, 0, radioLabels);
+				if (LayoutStyle == LayoutStyle.Computed) {
+					Width = r.Width;
+					Height = radioLabels.Count;
+				} else {
+					Frame = new Rect (Frame.Location, new Size (r.Width, radioLabels.Count));
+				}
+				break;
+			case DisplayModeLayout.Horizontal:
+				CalculateHorizontalPositions ();
+				var length = 0;
+				foreach (var item in horizontal) {
+					length += item.length;
+				}
+				var hr = new Rect (0, 0, length, 1);
+				if (LayoutStyle == LayoutStyle.Computed) {
+					Width = hr.Width;
+					Height = 1;
+				}
+				break;
 			}
 		}
 
@@ -106,7 +140,7 @@ namespace Terminal.Gui {
 		/// The radio labels to display
 		/// </summary>
 		/// <value>The radio labels.</value>
-		public ustring [] RadioLabels { 
+		public ustring [] RadioLabels {
 			get => radioLabels.ToArray();
 			set {
 				var prevCount = radioLabels.Count;
@@ -120,6 +154,20 @@ namespace Terminal.Gui {
 			}
 		}
 
+		private void CalculateHorizontalPositions ()
+		{
+			if (displayMode == DisplayModeLayout.Horizontal) {
+				horizontal = new List<(int pos, int length)> ();
+				int start = 0;
+				int length = 0;
+				for (int i = 0; i < radioLabels.Count; i++) {
+					start += length;
+					length = radioLabels [i].RuneCount + horizontalSpace;
+					horizontal.Add ((start, length));
+				}
+			}
+		}
+
 		//// Redraws the RadioGroup 
 		//void Update(List<ustring> newRadioLabels)
 		//{
@@ -139,7 +187,14 @@ namespace Terminal.Gui {
 			Driver.SetAttribute (ColorScheme.Normal);
 			Clear ();
 			for (int i = 0; i < radioLabels.Count; i++) {
-				Move (0, i);
+				switch (DisplayMode) {
+				case DisplayModeLayout.Vertical:
+					Move (0, i);
+					break;
+				case DisplayModeLayout.Horizontal:
+					Move (horizontal [i].pos, 0);
+					break;
+				}
 				Driver.SetAttribute (ColorScheme.Normal);
 				Driver.AddStr (ustring.Make(new Rune[] { (i == selected ? Driver.Selected : Driver.UnSelected), ' '}));
 				DrawHotString (radioLabels [i], HasFocus && i == cursor, ColorScheme);
@@ -149,7 +204,14 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override void PositionCursor ()
 		{
-			Move (0, cursor);
+			switch (DisplayMode) {
+			case DisplayModeLayout.Vertical:
+				Move (0, cursor);
+				break;
+			case DisplayModeLayout.Horizontal:
+				Move (horizontal [cursor].pos, 0);
+				break;
+			}
 		}
 
 		// TODO: Make this a global class
@@ -192,6 +254,7 @@ namespace Terminal.Gui {
 			get => selected;
 			set {
 				OnSelectedItemChanged (value, SelectedItem);
+				cursor = selected;
 				SetNeedsDisplay ();
 			}
 		}
@@ -264,16 +327,39 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override bool MouseEvent (MouseEvent me)
 		{
-			if (!me.Flags.HasFlag (MouseFlags.Button1Clicked))
+			if (!me.Flags.HasFlag (MouseFlags.Button1Clicked)) {
 				return false;
-
+			}
+			if (!CanFocus) {
+				return false;
+			}
 			SetFocus ();
 
-			if (me.Y < radioLabels.Count) {
-				cursor = SelectedItem = me.Y;
-				SetNeedsDisplay ();
+			var pos = displayMode == DisplayModeLayout.Horizontal ? me.X : me.Y;
+			var rCount = displayMode == DisplayModeLayout.Horizontal ? horizontal.Last ().pos + horizontal.Last ().length : radioLabels.Count;
+
+			if (pos < rCount) {
+				var c = displayMode == DisplayModeLayout.Horizontal ? horizontal.FindIndex ((x) => x.pos <= me.X && x.pos + x.length - 2 >= me.X) : me.Y;
+				if (c > -1) {
+					cursor = SelectedItem = c;
+					SetNeedsDisplay ();
+				}
 			}
 			return true;
 		}
 	}
+
+	/// <summary>
+	/// Used for choose the display mode of this <see cref="RadioGroup"/>
+	/// </summary>
+	public enum DisplayModeLayout {
+		/// <summary>
+		/// Vertical mode display. It's the default.
+		/// </summary>
+		Vertical,
+		/// <summary>
+		/// Horizontal mode display.
+		/// </summary>
+		Horizontal
+	}
 }