Bladeren bron

initial implementation

Charlie Kindel 5 jaren geleden
bovenliggende
commit
17163a76a9

+ 46 - 25
Terminal.Gui/Core/ConsoleDriver.cs

@@ -5,14 +5,11 @@
 //   Miguel de Icaza ([email protected])
 //
 // Define this to enable diagnostics drawing for Window Frames
-//#define DRAW_WINDOW_FRAME_DIAGNOSTICS
 using NStack;
 using System;
 using System.Runtime.CompilerServices;
 
-
 namespace Terminal.Gui {
-
 	/// <summary>
 	/// Basic colors that can be used to set the foreground and background colors in console applications.
 	/// </summary>
@@ -524,9 +521,6 @@ namespace Terminal.Gui {
 			TerminalResized = terminalResized;
 		}
 
-		// Useful for debugging (e.g. change to `*`
-		const char clearChar = ' ';
-
 		/// <summary>
 		/// Draws the title for a Window-style view incorporating padding. 
 		/// </summary>
@@ -550,17 +544,32 @@ namespace Terminal.Gui {
 			}
 		}
 
-#if DRAW_WINDOW_FRAME_DIAGNOSTICS
-		const char leftChar = 'L';
-		const char rightChar = 'R';
-		const char topChar = 'T';
-		const char bottomChar = 'B';
-#else
-		const char leftChar = clearChar;
-		const char rightChar = clearChar;
-		const char topChar = clearChar;
-		const char bottomChar = clearChar;
-#endif
+		/// <summary>
+		/// Enables diagnostic funcions
+		/// </summary>
+		[Flags]
+		public enum DiagnosticFlags : uint { 
+			/// <summary>
+			/// All diagnostics off
+			/// </summary>
+			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,
+			/// <summary>
+			/// When Enabled, <see cref="DrawWindowFrame(Rect, int, int, int, int, bool, bool)"/> will use
+			/// 'L', 'R', 'T', and 'B' for padding instead of ' '.
+			/// </summary>
+			FramePadding = 0b_0000_0010,
+		}
+
+		/// <summary>
+		/// Set flags to enable/disable <see cref="ConsoleDriver"/> diagnostics.
+		/// </summary>
+		public static DiagnosticFlags Diagnostics { get; set; }
+
 		/// <summary>
 		/// Draws a frame for a window with padding and an optional visible border inside the padding. 
 		/// </summary>
@@ -573,6 +582,20 @@ namespace Terminal.Gui {
 		/// <param name="fill">If set to <c>true</c> it will clear the content area (the area inside the padding) with the current color, otherwise the content area will be left untouched.</param>
 		public virtual void DrawWindowFrame (Rect region, int paddingLeft = 0, int paddingTop = 0, int paddingRight = 0, int paddingBottom = 0, bool border = true, bool fill = false)
 		{
+			char clearChar = ' ';
+			char leftChar = clearChar;
+			char rightChar = clearChar;
+			char topChar = clearChar;
+			char bottomChar = clearChar;
+
+			if ((Diagnostics & DiagnosticFlags.FramePadding) == DiagnosticFlags.FramePadding) {
+				leftChar = 'L';
+				rightChar = 'R';
+				topChar = 'T';
+				bottomChar = 'B';
+				clearChar = 'C';
+			}
+
 			void AddRuneAt (int col, int row, Rune ch)
 			{
 				Move (col, row);
@@ -656,11 +679,10 @@ namespace Terminal.Gui {
 
 					// Frame right
 					if (fright > fleft) {
-#if DRAW_WINDOW_FRAME_DIAGNOSTICS
-						var v = (char)(((int)'0') + ((r - ftop) % 10)); // vLine;
-#else
 						var v = vLine;
-#endif
+						if ((Diagnostics & DiagnosticFlags.FrameRuler) == DiagnosticFlags.FrameRuler) {
+							v = (char)(((int)'0') + ((r - ftop) % 10)); // vLine;
+						}
 						AddRuneAt (fright, r, paddingRight > 0 ? v : rightChar);
 					}
 
@@ -681,11 +703,10 @@ namespace Terminal.Gui {
 				if (fright > fleft) {
 					// Frame bottom
 					for (int c = fleft + 1; c < fright; c++) {
-#if DRAW_WINDOW_FRAME_DIAGNOSTICS
-						var h = (char)(((int)'0') + ((c - fleft) % 10)); // hLine;
-#else
 						var h = hLine;
-#endif	
+						if ((Diagnostics & DiagnosticFlags.FrameRuler) == DiagnosticFlags.FrameRuler) {
+							h = (char)(((int)'0') + ((c - fleft) % 10)); // hLine;
+						}
 						AddRuneAt (c, fbottom, paddingBottom > 0 ? h : bottomChar);
 					}
 

+ 1 - 0
Terminal.Gui/Terminal.Gui.csproj

@@ -172,6 +172,7 @@
     <PackageReference Include="NStack.Core" Version="0.14.0" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Remove="Views\ComboBox.cs" />
   </ItemGroup>
   <!--<ItemGroup>
     <Reference Include="NStack">

+ 197 - 0
UICatalog/Scenarios/AllViewsTester.cs

@@ -0,0 +1,197 @@
+using NStack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Terminal.Gui;
+
+namespace UICatalog {
+	/// <summary>
+	/// This Scenario demonstrates how to use Termina.gui's Dim and Pos Layout System. 
+	/// [x] - Using Dim.Fill to fill a window
+	/// [x] - Using Dim.Fill and Dim.Pos to automatically align controls based on an initial control
+	/// [ ] - ...
+	/// </summary>
+	[ScenarioMetadata (Name: "All Views Tester", Description: "Provides a test UI for all classes derived from View")]
+	[ScenarioCategory ("Layout")]
+	class AllViewsTester : Scenario {
+		private static Window _leftPane;
+		private static ListView _classListView;
+		private static FrameView _settingsPane;
+		private static FrameView _hostPane;
+
+		Dictionary<string, Type> _viewClasses;
+		Type _curClass = null;
+		View _curView = null;
+		StatusItem _currentClassStatusItem;
+
+
+		// Settings
+		CheckBox _computedCheckBox;
+
+
+		public override void Init (Toplevel top)
+		{
+			Application.Init ();
+
+			Top = top;
+			if (Top == null) {
+				Top = Application.Top;
+			}
+
+			//Win = new Window ($"CTRL-Q to Close - Scenario: {GetName ()}") {
+			//	X = 0,
+			//	Y = 0,
+			//	Width = Dim.Fill (),
+			//	Height = Dim.Fill ()
+			//};
+			//Top.Add (Win);
+		}
+
+		public override void Setup ()
+		{
+			_currentClassStatusItem = new StatusItem (Key.Unknown, "Class:", null);
+			var statusBar = new StatusBar (new StatusItem [] {
+				new StatusItem(Key.ControlQ, "~^Q~ Quit", () => Quit()),
+				_currentClassStatusItem,
+			});
+			Top.Add (statusBar);
+
+			_viewClasses = GetAllViewClassesCollection ()
+				.OrderBy (t => t.Name)
+				.Select (t => new KeyValuePair<string, Type> (t.Name, t))
+				.ToDictionary (t => t.Key, t => t.Value);
+
+			_leftPane = new Window ("Classes") {
+				X = 0,
+				Y = 0, // for menu
+				Width = 15,
+				Height = Dim.Fill (),
+				CanFocus = false,
+				ColorScheme = Colors.TopLevel,
+			};
+
+			_classListView = new ListView (_viewClasses.Keys.ToList()) {
+				X = 0,
+				Y = 0,
+				Width = Dim.Fill (0),
+				Height = Dim.Fill (), // for status bar
+				AllowsMarking = false,
+				ColorScheme = Colors.TopLevel,
+			};
+			_classListView.OpenSelectedItem += (o, a) => {
+				Top.SetFocus (_settingsPane);
+			};
+			_classListView.SelectedChanged += (sender, args) => {
+				_curClass = _viewClasses.Values.ToArray()[_classListView.SelectedItem];
+				SetCurrentClass ();
+			};
+			_leftPane.Add (_classListView);
+
+			_settingsPane = new FrameView ("Settings") {
+				X = Pos.Right(_leftPane),
+				Y = 0, // for menu
+				Width = Dim.Fill (),
+				Height = 10,
+				CanFocus = false,
+				ColorScheme = Colors.TopLevel,
+			};
+			_computedCheckBox = new CheckBox ("Computed Layout", true) { X = 0, Y = 0 };
+			_computedCheckBox.Toggled += (sender, previousState) => {
+				if (_curView != null) {
+					_curView.LayoutStyle = previousState ? LayoutStyle.Absolute : LayoutStyle.Computed;
+					_hostPane.LayoutSubviews ();
+				}
+
+			};
+			_settingsPane.Add (_computedCheckBox);
+
+			_hostPane = new FrameView ("") {
+				X = Pos.Right (_leftPane) + 2,
+				Y = Pos.Bottom(_settingsPane) + 2, 
+				Width = Dim.Fill (2),
+				Height = Dim.Fill (3), // + 1 for status bar
+				ColorScheme = Colors.Dialog,
+			};
+
+			Top.Add (_leftPane, _settingsPane, _hostPane);
+
+			_curClass = _viewClasses.First().Value;			
+			SetCurrentClass ();
+		}
+
+		List<Type> GetAllViewClassesCollection ()
+		{
+			List<Type> types = new List<Type> ();
+			foreach (Type type in typeof (View).Assembly.GetTypes ()
+			 .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View)))) {
+				types.Add (type);
+			}
+			return types;
+		}
+
+		void SetCurrentClass ()
+		{
+			_hostPane.Title = _currentClassStatusItem.Title = $"Class: {_curClass.Name}";
+
+			// Remove existing class, if any
+			if (_curView != null) {
+				_hostPane.Remove (_curView);
+				_hostPane.Clear ();
+				_curView = null;
+			}
+
+			// Instantiate view
+			_curView = (View)Activator.CreateInstance (_curClass);
+
+			_curView.X = Pos.Center ();
+			_curView.Y = Pos.Center ();
+			_curView.Width = Dim.Fill (5);
+			_curView.Height = Dim.Fill (5);
+
+			// Set the colorscheme to make it stand out
+			_curView.ColorScheme = Colors.Base;
+
+			// If the view supports a Text property, set it so we have something to look at
+			if (_curClass.GetProperty ("Text") != null) {
+				try {
+					_curView.GetType ().GetProperty ("Text")?.GetSetMethod ()?.Invoke (_curView, new [] { ustring.Make ("Test Text") });
+				}
+				catch (TargetInvocationException e) {
+					MessageBox.ErrorQuery ("Exception", e.InnerException.Message, "Ok");
+					_hostPane.Remove (_curView);
+					_hostPane.Clear ();
+					_curView = null;
+				}
+			}
+
+			if (_curView == null) return;
+
+			// If the view supports a Title property, set it so we have something to look at
+			if (_curClass.GetProperty ("Title") != null) {
+				_curView?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (_curView, new [] { ustring.Make ("Test Title") });
+			}
+
+			// Set Settings
+			_computedCheckBox.Checked = _curView.LayoutStyle == LayoutStyle.Computed;
+
+
+			// Add
+			_hostPane.Add (_curView);
+			_hostPane.LayoutSubviews ();
+			_hostPane.Clear ();
+			_hostPane.SetNeedsDisplay ();
+		}
+
+		public override void Run ()
+		{
+			base.Run ();
+		}
+
+		private void Quit ()
+		{
+			Application.RequestStop ();
+		}
+	}
+}

+ 0 - 96
UICatalog/Scenarios/ComputedLayout.cs

@@ -24,7 +24,6 @@ namespace UICatalog {
 					null,
 					new MenuItem ("_Quit", "", () => Quit()),
 				}),
-				new MenuBarItem ("_All Controls", "Tests all controls", () => DemoAllViewClasses() ),
 			});
 			Top.Add (menu);
 
@@ -200,101 +199,6 @@ namespace UICatalog {
 			Win.Add (rightButton);
 		}
 
-		/// <summary>
-		/// Displays a Dialog that uses a wizard (next/prev) idom to step through each class derived from View
-		/// testing various Computed layout scenarios
-		/// </summary>
-		private void DemoAllViewClasses ()
-		{
-			List<Type> GetAllViewClassesCollection ()
-			{
-				List<Type> objects = new List<Type> ();
-				foreach (Type type in typeof (View).Assembly.GetTypes ()
-				 .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View)))) {
-					objects.Add (type);
-				}
-				return objects;
-			}
-
-			var viewClasses = GetAllViewClassesCollection ().OrderByDescending (c => c.Name).ToList ();
-			var curClass = 0;
-
-			var closeBtn = new Button ("_Close") {
-				Clicked = () => {
-					Application.RequestStop ();
-				},
-			};
-			var nextBtn = new Button ("_Next");
-			var prevBtn = new Button ("_Previous");
-			var dialog = new Dialog ("Demoing all View classs", new [] { prevBtn, nextBtn, closeBtn });
-
-			var label = new Label ("Class:") {
-				X = 0,
-				Y = 0,
-			};
-			dialog.Add (label);
-			var currentClassLabel = new Label ("") {
-				X = Pos.Right (label) + 1,
-				Y = Pos.Y (label),
-			};
-			dialog.Add (currentClassLabel);
-
-			View curView = null;
-			void SetCurrentClass ()
-			{
-				currentClassLabel.Text = $"{viewClasses [curClass].Name}";
-
-				// Remove existing class, if any
-				if (curView != null) {
-					dialog.Remove (curView);
-					curView = null;
-				}
-
-				// Instantiate view
-				curView = (View)Activator.CreateInstance (viewClasses [curClass]);
-
-				curView.X = Pos.Center ();
-				curView.Y = Pos.Center ();
-				curView.Width = Dim.Fill (5);
-				curView.Height = Dim.Fill (5);
-
-				// If the view supports a Text property, set it so we have something to look at
-				if (viewClasses [curClass].GetProperty("Text") != null) {
-					curView.GetType ().GetProperty ("Text")?.GetSetMethod ()?.Invoke (curView, new [] { ustring.Make("09/10/1966") });
-				}
-
-				// If the view supports a Title property, set it so we have something to look at
-				if (viewClasses [curClass].GetProperty ("Title") != null) {
-					curView.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (curView, new [] { ustring.Make ("Test Title") });
-				}
-
-
-				dialog.Add (curView);
-				dialog.LayoutSubviews ();
-			}
-
-			nextBtn.Clicked = () => {
-				curClass++;
-				if (curClass >= viewClasses.Count) {
-					curClass = 0;
-				}
-				SetCurrentClass ();
-			};
-
-			prevBtn.Clicked = () => {
-				if (curClass == 0) {
-					curClass = viewClasses.Count - 1;
-				} else {
-					curClass--;
-				}
-				SetCurrentClass ();
-			};
-
-			SetCurrentClass ();
-
-			Application.Run (dialog);
-		}
-
 		public override void Run ()
 		{
 			base.Run ();

+ 10 - 10
UICatalog/Scenarios/Unicode.cs

@@ -35,16 +35,16 @@ namespace UICatalog {
 			var checkBox = new CheckBox (" ~  s  gui.cs   master ↑10") { X = 15, Y = Pos.Y (label), Width = Dim.Percent (50) };
 			Win.Add (checkBox);
 
-			label = new Label ("ComboBox:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
-			Win.Add (label);
-			var comboBox = new ComboBox (1, 1, 30, 5, new List<string> () { "item #1", " ~  s  gui.cs   master ↑10", "Со_хранить" }) {
-				X = 15,
-				Y = Pos.Y (label),
-				Width = 30,
-				ColorScheme = Colors.Error
-			};
-			Win.Add (comboBox);
-			comboBox.Text = " ~  s  gui.cs   master ↑10";
+			//label = new Label ("ComboBox:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
+			//Win.Add (label);
+			//var comboBox = new ComboBox (1, 1, 30, 5, new List<string> () { "item #1", " ~  s  gui.cs   master ↑10", "Со_хранить" }) {
+			//	X = 15,
+			//	Y = Pos.Y (label),
+			//	Width = 30,
+			//	ColorScheme = Colors.Error
+			//};
+			//Win.Add (comboBox);
+			//comboBox.Text = " ~  s  gui.cs   master ↑10";
 
 			label = new Label ("HexView:") { X = Pos.X (label), Y = Pos.Bottom (label) + 2 };
 			Win.Add (label);

+ 39 - 6
UICatalog/UICatalog.cs

@@ -59,7 +59,7 @@ namespace UICatalog {
 
 		private static Scenario _runningScenario = null;
 		private static bool _useSystemConsole = false;
-		private static MenuItem _sysConsoleMenu;
+		private static MenuItem _consoleFramePaddingMenu;
 
 		static void Main (string [] args)
 		{
@@ -124,6 +124,17 @@ namespace UICatalog {
 			return _runningScenario;
 		}
 
+		static MenuItem CheckedMenuMenuItem(ustring menuItem, Action action, Func<bool> checkFunction)
+		{
+			var mi = new MenuItem ();
+			mi.Title = $"[{(checkFunction () ? 'x' : ' ')}] {menuItem}"; 
+			mi.Action = () => {
+				action?.Invoke ();
+				mi.Title = $"[{(checkFunction () ? 'x' : ' ')}] {menuItem}";
+			};
+			return mi;
+		}
+
 
 		/// <summary>
 		/// Create all controls. This gets called once and the controls remain with their state between Sceanrio runs.
@@ -137,18 +148,40 @@ namespace UICatalog {
 			aboutMessage.AppendLine ($"Using Terminal.Gui Version: {typeof (Terminal.Gui.Application).Assembly.GetName ().Version}");
 			aboutMessage.AppendLine ("");
 
-			void HandleSysConsoleMenuChange ()
+
+			var framePaddingMenuText = "Diagnostics: _Frame Padding";
+			void HandleFramePaddingMenuChange ()
 			{
-				_useSystemConsole = !_useSystemConsole;
-				_sysConsoleMenu.Title = $"[{(_useSystemConsole ? 'x' : ' ')}] _Use System Console";
+				ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FramePadding;
+				_consoleFramePaddingMenu.Title = $"[{((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FramePadding) == ConsoleDriver.DiagnosticFlags.FramePadding ? 'x' : ' ')}] {framePaddingMenuText}";
+				_top.SetNeedsDisplay ();
 			}
-			_sysConsoleMenu = new MenuItem ($"[{(_useSystemConsole ? 'x' : ' ')}] _Use System Console", "", () => HandleSysConsoleMenuChange ());
+			_consoleFramePaddingMenu = new MenuItem ($"[{((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FramePadding) == ConsoleDriver.DiagnosticFlags.FramePadding ? 'x' : ' ')}] {framePaddingMenuText}", "", () => HandleFramePaddingMenuChange ());
 
 			_menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {
 					new MenuItem ("_Quit", "", () => Application.RequestStop() )
 				}),
-				new MenuBarItem ("_Settings", new MenuItem [] { _sysConsoleMenu }),
+				new MenuBarItem ("_Settings", new MenuItem [] { 
+					CheckedMenuMenuItem ("Use _System Console", 
+						() => {
+							_useSystemConsole = !_useSystemConsole;
+						},
+						() => _useSystemConsole),
+					CheckedMenuMenuItem ("Diagnostics: _Frame Padding",
+						() => {
+							ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FramePadding;
+							_top.SetNeedsDisplay ();
+						},
+						() => (ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FramePadding) == ConsoleDriver.DiagnosticFlags.FramePadding),
+					CheckedMenuMenuItem ("Diagnostics: Frame _Ruler",
+						() => {
+							ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FrameRuler;
+							_top.SetNeedsDisplay ();
+						},
+						() => (ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler),
+
+				}),
 				new MenuBarItem ("_About...", "About this app", () =>  MessageBox.Query ("About UI Catalog", aboutMessage.ToString(), "Ok")),
 			});
 

+ 4 - 0
UICatalog/UICatalog.csproj

@@ -7,6 +7,10 @@
     <AssemblyVersion>1.0.0.1</AssemblyVersion>
   </PropertyGroup>
 
+  <ItemGroup>
+    <Compile Remove="Scenarios\ListsAndCombos.cs" />
+  </ItemGroup>
+
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
   </ItemGroup>