Browse Source

Merge pull request #638 from tig/button_scenario_update

Button scenario update
Charlie Kindel 5 years ago
parent
commit
8a42bdb74a

+ 58 - 17
Terminal.Gui/Core/ConsoleDriver.cs

@@ -7,6 +7,8 @@
 // Define this to enable diagnostics drawing for Window Frames
 using NStack;
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Runtime.CompilerServices;
 
 namespace Terminal.Gui {
@@ -317,42 +319,81 @@ namespace Terminal.Gui {
 	/// The default <see cref="ColorScheme"/>s for the application.
 	/// </summary>
 	public static class Colors {
-		static ColorScheme _toplevel;
-		static ColorScheme _base;
-		static ColorScheme _dialog;
-		static ColorScheme _menu;
-		static ColorScheme _error;
+		static Colors ()
+		{
+			// Use reflection to dynamically create the default set of ColorSchemes from the list defiined 
+			// by the class. 
+			ColorSchemes = typeof (Colors).GetProperties ()
+				.Where(p => p.PropertyType == typeof(ColorScheme))
+				.Select (p => new KeyValuePair<string, ColorScheme> (p.Name, new ColorScheme())) // (ColorScheme)p.GetValue (p)))
+				.ToDictionary (t => t.Key, t => t.Value);
+		}
 
 		/// <summary>
 		/// The application toplevel color scheme, for the default toplevel views.
 		/// </summary>
-		public static ColorScheme TopLevel { get { return _toplevel; } set { _toplevel = SetColorScheme (value); } }
+		/// <remarks>
+		/// <para>
+		///	This API will be deprecated in the future. Use <see cref="Colors.ColorSchemes"/> instead (e.g. <c>edit.ColorScheme = Colors.ColorSchemes["TopLevel"];</c>
+		/// </para>
+		/// </remarks>
+		public static ColorScheme TopLevel { get => GetColorScheme (); set => SetColorScheme (value); }
 
 		/// <summary>
 		/// The base color scheme, for the default toplevel views.
 		/// </summary>
-		public static ColorScheme Base { get { return _base; } set { _base = SetColorScheme (value); } }
+		/// <remarks>
+		/// <para>
+		///	This API will be deprecated in the future. Use <see cref="Colors.ColorSchemes"/> instead (e.g. <c>edit.ColorScheme = Colors.ColorSchemes["Base"];</c>
+		/// </para>
+		/// </remarks>
+		public static ColorScheme Base { get => GetColorScheme (); set => SetColorScheme (value); }
 
 		/// <summary>
 		/// The dialog color scheme, for standard popup dialog boxes
 		/// </summary>
-		public static ColorScheme Dialog { get { return _dialog; } set { _dialog = SetColorScheme (value); } }
+		/// <remarks>
+		/// <para>
+		///	This API will be deprecated in the future. Use <see cref="Colors.ColorSchemes"/> instead (e.g. <c>edit.ColorScheme = Colors.ColorSchemes["Dialog"];</c>
+		/// </para>
+		/// </remarks>
+		public static ColorScheme Dialog { get => GetColorScheme (); set => SetColorScheme (value); }
 
 		/// <summary>
 		/// The menu bar color
 		/// </summary>
-		public static ColorScheme Menu { get { return _menu; } set { _menu = SetColorScheme (value); } }
+		/// <remarks>
+		/// <para>
+		///	This API will be deprecated in the future. Use <see cref="Colors.ColorSchemes"/> instead (e.g. <c>edit.ColorScheme = Colors.ColorSchemes["Menu"];</c>
+		/// </para>
+		/// </remarks>
+		public static ColorScheme Menu { get => GetColorScheme (); set => SetColorScheme (value); }
 
 		/// <summary>
 		/// The color scheme for showing errors.
 		/// </summary>
-		public static ColorScheme Error { get { return _error; } set { _error = SetColorScheme (value); } }
+		/// <remarks>
+		/// <para>
+		///	This API will be deprecated in the future. Use <see cref="Colors.ColorSchemes"/> instead (e.g. <c>edit.ColorScheme = Colors.ColorSchemes["Error"];</c>
+		/// </para>
+		/// </remarks>
+		public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value);  }
 
-		static ColorScheme SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string callerMemberName = null)
+		static ColorScheme GetColorScheme([CallerMemberName] string callerMemberName = null)
 		{
+			return ColorSchemes [callerMemberName];
+		}
+
+		static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string callerMemberName = null)
+		{
+			ColorSchemes [callerMemberName] = colorScheme;
 			colorScheme.caller = callerMemberName;
-			return colorScheme;
 		}
+
+		/// <summary>
+		/// Provides the defined <see cref="ColorScheme"/>s.
+		/// </summary>
+		public static Dictionary<string, ColorScheme> ColorSchemes { get; }
 	}
 
 	///// <summary>
@@ -535,7 +576,7 @@ namespace Terminal.Gui {
 		public virtual void DrawWindowTitle (Rect region, ustring title, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom, TextAlignment textAlignment = TextAlignment.Left)
 		{
 			var width = region.Width - (paddingLeft + 2) * 2;
-			if (!ustring.IsNullOrEmpty(title) && width > 4 && region.Y + paddingTop <= region.Y + paddingBottom) {
+			if (!ustring.IsNullOrEmpty (title) && width > 4 && region.Y + paddingTop <= region.Y + paddingBottom) {
 				Move (region.X + 1 + paddingLeft, region.Y + paddingTop);
 				AddRune (' ');
 				var str = title.Length >= width ? title [0, width - 2] : title;
@@ -548,16 +589,16 @@ namespace Terminal.Gui {
 		/// Enables diagnostic funcions
 		/// </summary>
 		[Flags]
-		public enum DiagnosticFlags : uint { 
+		public enum DiagnosticFlags : uint {
 			/// <summary>
 			/// All diagnostics off
 			/// </summary>
-			Off		= 0b_0000_0000,
+			Off = 0b_0000_0000,
 			/// <summary>
 			/// When enabled, <see cref="DrawWindowFrame(Rect, int, int, int, int, bool, bool)"/> will draw a 
 			/// ruler in the frame for any side with a padding value greater than 0.
 			/// </summary>
-			FrameRuler	= 0b_0000_0001,
+			FrameRuler = 0b_0000_0001,
 			/// <summary>
 			/// When Enabled, <see cref="DrawWindowFrame(Rect, int, int, int, int, bool, bool)"/> will use
 			/// 'L', 'R', 'T', and 'B' for padding instead of ' '.
@@ -744,7 +785,7 @@ namespace Terminal.Gui {
 		{
 			// DrawFrame assumes the border is always at least one row/col thick
 			// DrawWindowFrame assumes a padding of 0 means NO padding and no frame
-			DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height), 
+			DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height),
 				padding + 1, padding + 1, padding + 1, padding + 1, border: false, fill: fill);
 		}
 

+ 7 - 2
Terminal.Gui/Views/Button.cs

@@ -154,12 +154,17 @@ namespace Terminal.Gui {
 			}
 		}
 
+		Rune _leftBracket = new Rune ('[');
+		Rune _rightBracket = new Rune (']');
+		Rune _leftDefault = new Rune ('<');
+		Rune _rightDefault = new Rune ('>');
+
 		internal void Update ()
 		{
 			if (IsDefault)
-				shown_text = "[< " + text + " >]";
+				shown_text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket);
 			else
-				shown_text = "[ " + text + " ]";
+				shown_text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
 
 			hot_key = (Rune)0;
 			hot_pos = shown_text.IndexOf ('_');

+ 3 - 3
UICatalog/Scenario.cs

@@ -225,11 +225,11 @@ namespace UICatalog {
 		/// Returns an instance of each <see cref="Scenario"/> defined in the project. 
 		/// https://stackoverflow.com/questions/5411694/get-all-inherited-classes-of-an-abstract-class
 		/// </summary>
-		internal static List<Type> GetDerivedClassesCollection ()
+		internal static List<Type> GetDerivedClasses<T> ()
 		{
 			List<Type> objects = new List<Type> ();
-			foreach (Type type in typeof (Scenario).Assembly.GetTypes ()
-			 .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf (typeof (Scenario)))) {
+			foreach (Type type in typeof (T).Assembly.GetTypes ()
+			 .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf (typeof (T)))) {
 				objects.Add (type);
 			}
 			return objects;

+ 141 - 105
UICatalog/Scenarios/Buttons.cs

@@ -1,6 +1,8 @@
 using NStack;
 using System;
 using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
 using Terminal.Gui;
 
 namespace UICatalog {
@@ -16,8 +18,8 @@ namespace UICatalog {
 				Y = 0,
 			};
 			Win.Add (editLabel);
-			// Add a TextField using Absolute layout. Use buttons to move/grow.
-			var edit = new TextField (31, 0, 25, "");
+			// Add a TextField using Absolute layout. 
+			var edit = new TextField (31, 0, 15, "");
 			Win.Add (edit);
 
 			// This is the default button (IsDefault = true); if user presses ENTER in the TextField
@@ -31,142 +33,175 @@ namespace UICatalog {
 			};
 			Win.Add (defaultButton);
 
+			var swapButton = new Button (50, 0, "Swap Default (Absolute Layout)");
+			swapButton.Clicked = () => {
+				defaultButton.IsDefault = !defaultButton.IsDefault;
+				swapButton.IsDefault = !swapButton.IsDefault;
+			};
+			Win.Add (swapButton);
+
 			static void DoMessage (Button button, ustring txt)
 			{
 				button.Clicked = () => {
 					var btnText = button.Text.ToString ();
-					MessageBox.Query (30, 7, "Message", $"Did you click {txt.ToString ()}?", "Yes", "No");
+					MessageBox.Query ("Message", $"Did you click {txt}?", "Yes", "No");
 				};
 			}
 
-			var y = 2;
-			var button = new Button (10, y, "Ba_se Color") {
-				ColorScheme = Colors.Base,
+			var colorButtonsLabel = new Label ("Color Buttons:") {
+				X = 0,
+				Y = Pos.Bottom (editLabel) + 1,
 			};
-			DoMessage (button, button.Text);
-			Win.Add (button);
-
-			y += 2;
-			Win.Add (button = new Button (10, y, "Error Color") {
-				ColorScheme = Colors.Error,
-			});
-			DoMessage (button, button.Text);
-
-			y += 2;
-			Win.Add (button = new Button (10, y, "Dialog Color") {
-				ColorScheme = Colors.Dialog,
-			});
-			DoMessage (button, button.Text);
+			Win.Add (colorButtonsLabel);
+
+			View prev = colorButtonsLabel;
+			foreach (var colorScheme in Colors.ColorSchemes) {
+				var colorButton = new Button ($"{colorScheme.Key}") {
+					ColorScheme = colorScheme.Value,
+					X = Pos.Right (prev) + 2,
+					Y = Pos.Y (colorButtonsLabel),
+				};
+				DoMessage (colorButton, colorButton.Text);
+				Win.Add (colorButton);
+				prev = colorButton;
+			}
+			// BUGBUG: For some reason these buttons don't move to correct locations initially. 
 
-			y += 2;
-			Win.Add (button = new Button (10, y, "Menu Color") {
-				ColorScheme = Colors.Menu,
+			Button button;
+			Win.Add (button = new Button ("A super long _Button that will probably expose a bug in clipping or wrapping of text. Will it?") {
+				X = 2,
+				Y = Pos.Bottom (colorButtonsLabel) + 1,
 			});
 			DoMessage (button, button.Text);
 
-			y += 2;
-			Win.Add (button = new Button (10, y, "TopLevel Color") {
-				ColorScheme = Colors.TopLevel,
+			// Note the 'N' in 'Newline' will be the hotkey
+			Win.Add (button = new Button ("a Newline\nin the button") {
+				X = 2,
+				Y = Pos.Bottom (button) + 1,
+				Clicked = () => MessageBox.Query ("Message", "Question?", "Yes", "No")
 			});
-			DoMessage (button, button.Text);
 
-			y += 2;
-			Win.Add (button = new Button (10, y, "A super long _Button that will probably expose a bug in clipping or wrapping of text. Will it?") {
-			});
-			DoMessage (button, button.Text);
+			var textChanger = new Button ("Te_xt Changer") {
+				X = 2,
+				Y = Pos.Bottom (button) + 1,
+			};
+			Win.Add (textChanger);
+			textChanger.Clicked = () => textChanger.Text += "!";
 
-			y += 2;
-			// Note the 'N' in 'Newline' will be the hotkey
-			Win.Add (new Button (10, y, "a Newline\nin the button") {
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No")
+			Win.Add (button = new Button ("Lets see if this will move as \"Text Changer\" grows") {
+				X = Pos.Right(textChanger) + 2,
+				Y = Pos.Y (textChanger),
 			});
 
-			y += 2;
-			// BUGBUG: Buttons don't support specifying hotkeys with _?!?
-			Win.Add (button = new Button ("Te_xt Changer") {
-				X = 10,
-				Y = y
-			});
+			var removeButton = new Button ("Remove this button") {
+				X = 2,
+				Y = Pos.Bottom (button) + 1,
+				ColorScheme = Colors.Error
+			};
+			Win.Add (removeButton);
+			// This in intresting test case because `moveBtn` and below are laid out relative to this one!
+			removeButton.Clicked = () => Win.Remove (removeButton);
 
-			button.Clicked = () => button.Text += "!";
+			var computedFrame = new FrameView ("Computed Layout") {
+				X = 0,
+				Y = Pos.Bottom (removeButton) + 1,
+				Width = Dim.Percent(50),
+				Height = 5
+			};
+			Win.Add (computedFrame);
 
-			Win.Add (new Button ("Lets see if this will move as \"Text Changer\" grows") {
-				X = Pos.Right (button) + 10,
-				Y = y,
-			});
+			// Demonstrates how changing the View.Frame property can move Views
+			var moveBtn = new Button ("Move This Button via Pos") {
+				X = 0,
+				Y = Pos.Center() - 1,
+				Width = 30,
+				ColorScheme = Colors.Error,
+			};
+			moveBtn.Clicked = () => {
+				moveBtn.X = moveBtn.Frame.X + 5;
+				computedFrame.LayoutSubviews (); // BUGBUG: This call should not be needed. View.X is not causing relayout correctly
+			};
+			computedFrame.Add (moveBtn);
 
-			y += 2;
-			Win.Add (new Button (10, y, "Delete") {
+			// Demonstrates how changing the View.Frame property can SIZE Views (#583)
+			var sizeBtn = new Button ("Size This Button via Pos") {
+				X = 0,
+				Y = Pos.Center () + 1,
+				Width = 30,
 				ColorScheme = Colors.Error,
-				Clicked = () => Win.Remove (button)
-			});
+			};
+			sizeBtn.Clicked = () => {
+				sizeBtn.Width = sizeBtn.Frame.Width + 5;
+				computedFrame.LayoutSubviews (); // BUGBUG: This call should not be needed. View.X is not causing relayout correctly
+			};
+			computedFrame.Add (sizeBtn);
 
-			y += 2;
-			Win.Add (new Button (10, y, "Change Default") {
-				Clicked = () => {
-					defaultButton.IsDefault = !defaultButton.IsDefault;
-					button.IsDefault = !button.IsDefault;
-				},
-			});
+			var absoluteFrame = new FrameView ("Absolute Layout") {
+				X = Pos.Right(computedFrame),
+				Y = Pos.Bottom (removeButton) + 1,
+				Width = Dim.Fill(),
+				Height = 5
+			};
+			Win.Add (absoluteFrame);
 
 			// Demonstrates how changing the View.Frame property can move Views
-			y += 2;
-			var moveBtn = new Button (10, y, "Move This Button via Frame") {
+			var moveBtnA = new Button (0, 0, "Move This Button via Frame") {
 				ColorScheme = Colors.Error,
 			};
-			moveBtn.Clicked = () => {
-				moveBtn.Frame = new Rect (moveBtn.Frame.X + 5, moveBtn.Frame.Y, moveBtn.Frame.Width, moveBtn.Frame.Height);
+			moveBtnA.Clicked = () => {
+				moveBtnA.Frame = new Rect (moveBtnA.Frame.X + 5, moveBtnA.Frame.Y, moveBtnA.Frame.Width, moveBtnA.Frame.Height);
 			};
-			Win.Add (moveBtn);
+			absoluteFrame.Add (moveBtnA);
 
 			// Demonstrates how changing the View.Frame property can SIZE Views (#583)
-			y += 2;
-			var sizeBtn = new Button (10, y, "Size This Button via Frame") {
+			var sizeBtnA = new Button (0, 2, "Size This Button via Frame") {
 				ColorScheme = Colors.Error,
 			};
-			moveBtn.Clicked = () => {
-				sizeBtn.Frame = new Rect (sizeBtn.Frame.X, sizeBtn.Frame.Y, sizeBtn.Frame.Width + 5, sizeBtn.Frame.Height);
+			sizeBtnA.Clicked = () => {
+				sizeBtnA.Frame = new Rect (sizeBtnA.Frame.X, sizeBtnA.Frame.Y, sizeBtnA.Frame.Width + 5, sizeBtnA.Frame.Height);
 			};
-			Win.Add (sizeBtn);
-
-			Win.Add (new Label ("Size This Button via Frame 'Text Alignment'") {
-				X = Pos.Right (moveBtn) + 20,
-				Y = Pos.Top (moveBtn) - 4,
-			});
+			absoluteFrame.Add (sizeBtnA);
 
-			List<string> txtAligs = new List<string> () {
-				"Left",
-				"Right",
-				"Centered",
-				"Justified"
-			};
-
-			var lvTextAlig = new ListView (txtAligs) {
-				X = Pos.Right (moveBtn) + 20,
-				Y = Pos.Top (moveBtn) - 3,
-				Width = 20,
-				Height = 4,
-				ColorScheme = Colors.TopLevel
-			};
-
-			lvTextAlig.SelectedItemChanged += (e) => {
-				switch (e.Value) {
-				case "Left":
-					sizeBtn.TextAlignment = TextAlignment.Left;
-					break;
-				case "Right":
-					sizeBtn.TextAlignment = TextAlignment.Right;
-					break;
-				case "Centered":
-					sizeBtn.TextAlignment = TextAlignment.Centered;
-					break;
-				case "Justified":
-					sizeBtn.TextAlignment = TextAlignment.Justified;
-					break;
+			var label = new Label ("Text Alignment (changes the four buttons above): ") {
+				X = 2,
+				Y = Pos.Bottom (computedFrame) + 1,
+			};
+			Win.Add (label);
+
+			var radioGroup = new RadioGroup (new [] { "Left", "Right", "Centered", "Justified" }) {
+				X = 4,
+				Y = Pos.Bottom (label) + 1,
+				Selected = 2,
+				SelectedItemChanged = (selected) => {
+					switch (selected) {
+					case 0:
+						moveBtn.TextAlignment = TextAlignment.Left;
+						sizeBtn.TextAlignment = TextAlignment.Left;
+						moveBtnA.TextAlignment = TextAlignment.Left;
+						sizeBtnA.TextAlignment = TextAlignment.Left;
+						break;
+					case 1:
+						moveBtn.TextAlignment = TextAlignment.Right;
+						sizeBtn.TextAlignment = TextAlignment.Right;
+						moveBtnA.TextAlignment = TextAlignment.Right;
+						sizeBtnA.TextAlignment = TextAlignment.Right;
+						break;
+					case 2:
+						moveBtn.TextAlignment = TextAlignment.Centered;
+						sizeBtn.TextAlignment = TextAlignment.Centered;
+						moveBtnA.TextAlignment = TextAlignment.Centered;
+						sizeBtnA.TextAlignment = TextAlignment.Centered;
+						break;
+					case 3:
+						moveBtn.TextAlignment = TextAlignment.Justified;
+						sizeBtn.TextAlignment = TextAlignment.Justified;
+						moveBtnA.TextAlignment = TextAlignment.Justified;
+						sizeBtnA.TextAlignment = TextAlignment.Justified;
+						break;
+					}
 				}
 			};
-
-			Win.Add (lvTextAlig);
+			Win.Add (radioGroup);
 
 			// Demo changing hotkey
 			ustring MoveHotkey (ustring txt)
@@ -189,8 +224,9 @@ namespace UICatalog {
 				return txt;
 			}
 
-			y += 2;
-			var moveHotKeyBtn = new Button (10, y, "Click to Change th_is Button's Hotkey") {
+			var moveHotKeyBtn = new Button ("Click to Change th_is Button's Hotkey") {
+				X = 2,
+				Y = Pos.Bottom (radioGroup) + 1,
 				ColorScheme = Colors.TopLevel,
 			};
 			moveHotKeyBtn.Clicked = () => {

+ 1 - 1
UICatalog/UICatalog.cs

@@ -65,7 +65,7 @@ namespace UICatalog {
 			if (Debugger.IsAttached)
 				CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
 
-			_scenarios = Scenario.GetDerivedClassesCollection ().OrderBy (t => Scenario.ScenarioMetadata.GetName (t)).ToList ();
+			_scenarios = Scenario.GetDerivedClasses<Scenario> ().OrderBy (t => Scenario.ScenarioMetadata.GetName (t)).ToList ();
 
 			if (args.Length > 0) {
 				var item = _scenarios.FindIndex (t => Scenario.ScenarioMetadata.GetName (t).Equals (args [0], StringComparison.OrdinalIgnoreCase));