Prechádzať zdrojové kódy

TrueColor in NetDriver now works

Tigger Kindel 2 rokov pred
rodič
commit
293161bca1

+ 10 - 8
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -353,21 +353,23 @@ public abstract class ConsoleDriver {
 	/// <summary>
 	/// Gets whether the <see cref="ConsoleDriver"/> supports TrueColor output.
 	/// </summary>
-	public virtual bool SupportsTrueColor { get => false; }
+	public virtual bool SupportsTrueColor { get => true; }
 
-	private bool _useTrueColor = true;
+	private bool _force16Colors = false;
 
 	// TODO: Make this a ConfiguationManager setting on Application
 	/// <summary>
-	/// Gets or sets whether the <see cref="ConsoleDriver"/> should use TrueColor output.
+	/// Gets or sets whether the <see cref="ConsoleDriver"/> should use 16 colors instead of the default TrueColors.
 	/// </summary>
 	/// <remarks>
-	/// Can only be enabled if <see cref="ConsoleDriver.SupportsTrueColor"/> is true, indicating
-	/// that the <see cref="ConsoleDriver"/> supports it.
+	/// Will be forced to <see langword="true"/> if <see cref="ConsoleDriver.SupportsTrueColor"/> is  <see langword="false"/>, indicating
+	/// that the <see cref="ConsoleDriver"/> cannot support TrueColor.
 	/// </remarks>
-	public bool UseTrueColor {
-		get => _useTrueColor && SupportsTrueColor;
-		set => this._useTrueColor = (value && SupportsTrueColor);
+	public virtual bool Force16Colors {
+		get => _force16Colors || !SupportsTrueColor;
+		set {
+			_force16Colors = (value || !SupportsTrueColor);
+		}
 	}
 
 	Attribute _currentAttribute;

+ 22 - 11
Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs

@@ -447,15 +447,26 @@ public static class EscSeqUtils {
 				escSeqRequests.Remove (terminator);
 				return;
 			}
-			key = GetConsoleKey (terminator [0], values [0], ref mod);
-			if (key != 0 && values.Length > 1) {
-				mod |= GetConsoleModifiers (values [1]);
+			if (!string.IsNullOrEmpty (terminator)) {
+				key = GetConsoleKey (terminator [0], values [0], ref mod);
+				if (key != 0 && values.Length > 1) {
+					mod |= GetConsoleModifiers (values [1]);
+				}
+				newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
+					key,
+					(mod & ConsoleModifiers.Shift) != 0,
+					(mod & ConsoleModifiers.Alt) != 0,
+					(mod & ConsoleModifiers.Control) != 0);
+			} else {
+				// BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/2803
+				// This is caused by NetDriver depending on Console.KeyAvailable?
+				throw new InvalidOperationException ($"CSI response, but there's no terminator");
+				//newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
+				//	key,
+				//	(mod & ConsoleModifiers.Shift) != 0,
+				//	(mod & ConsoleModifiers.Alt) != 0,
+				//	(mod & ConsoleModifiers.Control) != 0);
 			}
-			newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
-				key,
-				(mod & ConsoleModifiers.Shift) != 0,
-				(mod & ConsoleModifiers.Alt) != 0,
-				(mod & ConsoleModifiers.Control) != 0);
 			break;
 		}
 	}
@@ -579,14 +590,14 @@ public static class EscSeqUtils {
 	/// <summary>
 	/// Gets the <see cref="ConsoleKey"/> depending on terminating and value.
 	/// </summary>
-	/// <param name="terminating">The terminating.</param>
+	/// <param name="terminator">The terminator indicating a reply to <see cref="CSI_SendDeviceAttributes"/> or <see cref="CSI_SendDeviceAttributes2"/>.</param>
 	/// <param name="value">The value.</param>
 	/// <param name="mod">The <see cref="ConsoleModifiers"/> which may changes.</param>
 	/// <returns>The <see cref="ConsoleKey"/> and probably the <see cref="ConsoleModifiers"/>.</returns>
-	public static ConsoleKey GetConsoleKey (char terminating, string value, ref ConsoleModifiers mod)
+	public static ConsoleKey GetConsoleKey (char terminator, string value, ref ConsoleModifiers mod)
 	{
 		ConsoleKey key;
-		switch (terminating) {
+		switch (terminator) {
 		case 'A':
 			key = ConsoleKey.UpArrow;
 			break;

+ 11 - 2
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -554,6 +554,8 @@ internal class NetDriver : ConsoleDriver {
 	const int COLOR_BRIGHT_CYAN = 96;
 	const int COLOR_BRIGHT_WHITE = 97;
 
+	public override bool SupportsTrueColor => Environment.OSVersion.Version.Build >= 14931;
+
 	public NetWinVTConsole NetWinConsole { get; private set; }
 	public bool IsWinPlatform { get; private set; }
 
@@ -719,8 +721,15 @@ internal class NetDriver : ConsoleDriver {
 					// Performance: Only send the escape sequence if the attribute has changed.
 					if (attr != redrawAttr) {
 						redrawAttr = attr;
-						output.Append (EscSeqUtils.CSI_SetGraphicsRendition (
-						    MapColors ((ConsoleColor)attr.Background, false), MapColors ((ConsoleColor)attr.Foreground, true)));
+
+						if (Force16Colors) {
+							output.Append (EscSeqUtils.CSI_SetGraphicsRendition (
+								MapColors ((ConsoleColor)attr.Background, false), MapColors ((ConsoleColor)attr.Foreground, true)));
+						} else {
+							output.Append (EscSeqUtils.CSI_SetForegroundColorRGB (attr.TrueColorForeground.Value.Red, attr.TrueColorForeground.Value.Green, attr.TrueColorForeground.Value.Blue));
+							output.Append (EscSeqUtils.CSI_SetBackgroundColorRGB (attr.TrueColorBackground.Value.Red, attr.TrueColorBackground.Value.Green, attr.TrueColorBackground.Value.Blue));
+						}
+
 					}
 					outputWidth++;
 					var rune = (Rune)Contents [row, col].Runes [0];

+ 46 - 31
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -9,6 +9,7 @@ using System.Linq;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
+using static Unix.Terminal.Curses;
 
 namespace Terminal.Gui;
 
@@ -39,13 +40,13 @@ internal class WindowsConsole {
 
 	CharInfo [] _originalStdOutChars;
 
-	public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord coords, SmallRect window, bool useTrueColor)
+	public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord coords, SmallRect window, bool force16Colors)
 	{
 		if (_screenBuffer == IntPtr.Zero) {
 			ReadFromConsoleOutput (size, coords, ref window);
 		}
 
-		if (!useTrueColor) {
+		if (force16Colors) {
 			int i = 0;
 			CharInfo [] ci = new CharInfo [charInfoBuffer.Length];
 			foreach (ExtendedCharInfo info in charInfoBuffer) {
@@ -55,45 +56,49 @@ internal class WindowsConsole {
 				};
 			}
 			return WriteConsoleOutput (_screenBuffer, ci, coords, new Coord () { X = window.Left, Y = window.Top }, ref window);
-		}
+		} else {
 
+			_stringBuilder.Clear ();
 
-		return WriteConsoleTrueColorOutput (charInfoBuffer);
-	}
-
-	private bool WriteConsoleTrueColorOutput (ExtendedCharInfo [] charInfoBuffer)
-	{
-		_stringBuilder.Clear ();
+			_stringBuilder.Append (EscSeqUtils.CSI_SaveCursorPosition);
+			_stringBuilder.Append (EscSeqUtils.CSI_SetCursorPosition (0, 0));
 
-		_stringBuilder.Append (EscSeqUtils.CSI_SaveCursorPosition);
-		_stringBuilder.Append (EscSeqUtils.CSI_SetCursorPosition (0, 0));
+			Attribute? prev = null;
+			foreach (var info in charInfoBuffer) {
+				var attr = info.Attribute;
 
-		Attribute? prev = null;
-		foreach (var info in charInfoBuffer) {
-			var attr = info.Attribute;
+				if (attr != prev) {
+					prev = attr;
+					if (force16Colors) {
+						//// Assume a 4-bit encoded value for both foreground and background colors.
+						//// GetColors (value, out foreground, out background);
+						//var foreground = (int)attr.TrueColorForeground.Value;
+						//var background = attr.TrueColorForeground.Value;
+						//_stringBuilder.Append (EscSeqUtils.CSI_SetForegroundColor (foreground));
+						//_stringBuilder.Append (EscSeqUtils.CSI_SetBackgroundColor (background));
 
-			if (attr != prev) {
-				prev = attr;
+					} else {
+						_stringBuilder.Append (EscSeqUtils.CSI_SetForegroundColorRGB (attr.TrueColorForeground.Value.Red, attr.TrueColorForeground.Value.Green, attr.TrueColorForeground.Value.Blue));
+						_stringBuilder.Append (EscSeqUtils.CSI_SetBackgroundColorRGB (attr.TrueColorBackground.Value.Red, attr.TrueColorBackground.Value.Green, attr.TrueColorBackground.Value.Blue));
+					}
+				}
 
-				_stringBuilder.Append (EscSeqUtils.CSI_SetForegroundColorRGB (attr.TrueColorForeground.Value.Red, attr.TrueColorForeground.Value.Green, attr.TrueColorForeground.Value.Blue));
-				_stringBuilder.Append (EscSeqUtils.CSI_SetBackgroundColorRGB (attr.TrueColorBackground.Value.Red, attr.TrueColorBackground.Value.Green, attr.TrueColorBackground.Value.Blue));
-			}
+				if (info.Char != '\x1b') {
+					if (!info.Empty) {
+						_stringBuilder.Append (info.Char);
+					}
 
-			if (info.Char != '\x1b') {
-				if (!info.Empty) {
-					_stringBuilder.Append (info.Char);
+				} else {
+					_stringBuilder.Append (' ');
 				}
-
-			} else {
-				_stringBuilder.Append (' ');
 			}
-		}
 
-		_stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition);
+			_stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition);
 
-		string s = _stringBuilder.ToString ();
+			string s = _stringBuilder.ToString ();
 
-		return WriteConsole (_screenBuffer, s, (uint)(s.Length), out uint _, null);
+			return WriteConsole (_screenBuffer, s, (uint)(s.Length), out uint _, null);
+		}
 	}
 
 	public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window)
@@ -769,6 +774,15 @@ internal class WindowsDriver : ConsoleDriver {
 
 	public override bool SupportsTrueColor => Environment.OSVersion.Version.Build >= 14931;
 
+	public override bool Force16Colors {
+		get => base.Force16Colors;
+		set {
+			base.Force16Colors = value;
+			// BUGBUG: This is a hack until we fully support VirtualTerminalSequences
+			WinConsole = new WindowsConsole ();
+		}
+	}
+
 	public WindowsDriver ()
 	{
 		WinConsole = new WindowsConsole ();
@@ -1441,7 +1455,7 @@ internal class WindowsDriver : ConsoleDriver {
 		ClearContents ();
 	}
 
-	public virtual void ResizeScreen ()
+	void ResizeScreen ()
 	{
 		if (WinConsole == null) {
 			return;
@@ -1504,12 +1518,13 @@ internal class WindowsDriver : ConsoleDriver {
 			}
 		}
 
-		WinConsole.WriteToConsole (new Size (Cols, Rows), _outputBuffer, bufferCoords, _damageRegion, UseTrueColor);
+		WinConsole.WriteToConsole (new Size (Cols, Rows), _outputBuffer, bufferCoords, _damageRegion, Force16Colors);
 		WindowsConsole.SmallRect.MakeEmpty (ref _damageRegion);
 	}
 
 	public override void Refresh ()
 	{
+	
 		UpdateScreen ();
 		WinConsole.SetInitialCursorVisibility ();
 		UpdateCursor ();

+ 1 - 0
Terminal.sln.DotSettings

@@ -108,6 +108,7 @@
 	<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">False</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/PreferExplicitDiscardDeclaration/@EntryValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/PreferSeparateDeconstructedVariablesDeclaration/@EntryValue">True</s:Boolean>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
 	<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">False</s:Boolean>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>

+ 2 - 2
UICatalog/Scenarios/Images.cs

@@ -40,10 +40,10 @@ namespace UICatalog.Scenarios {
 			var cbUseTrueColor = new CheckBox ("Use true color") {
 				X = x,
 				Y = y++,
-				Checked = Application.Driver.UseTrueColor,
+				Checked = Application.Driver.Force16Colors,
 				Enabled = canTrueColor,
 			};
-			cbUseTrueColor.Toggled += (_, evt) => Application.Driver.UseTrueColor = evt.NewValue ?? false;
+			cbUseTrueColor.Toggled += (_, evt) => Application.Driver.Force16Colors = evt.NewValue ?? false;
 			Win.Add (cbUseTrueColor);
 
 			var btnOpenImage = new Button ("Open Image") {

+ 6 - 4
UICatalog/Scenarios/TrueColors.cs

@@ -29,13 +29,15 @@ namespace UICatalog.Scenarios {
 			};
 			Win.Add (cbSupportsTrueColor);
 
-			var cbUseTrueColor = new CheckBox ("Use true color") {
+			var cbUseTrueColor = new CheckBox ("Force 16 colors") {
 				X = x,
 				Y = y++,
-				Checked = Application.Driver.UseTrueColor,
+				Checked = Application.Driver.Force16Colors,
 				Enabled = canTrueColor,
 			};
-			cbUseTrueColor.Toggled += (_, evt) => Application.Driver.UseTrueColor = evt.NewValue ?? false;
+			cbUseTrueColor.Toggled += (_, evt) => {
+				Application.Driver.Force16Colors = evt.NewValue ?? false;
+			};
 			Win.Add (cbUseTrueColor);
 
 			y += 2;
@@ -81,8 +83,8 @@ namespace UICatalog.Scenarios {
 			Win.Add (lblBlue);
 
 			Application.RootMouseEvent = (e) => {
-				var normal = e.View.GetNormalColor ();
 				if (e.View != null) {
+					var normal = e.View.GetNormalColor ();
 					lblRed.Text = normal.TrueColorForeground.Value.Red.ToString ();
 					lblGreen.Text = normal.TrueColorForeground.Value.Green.ToString ();
 					lblBlue.Text = normal.TrueColorForeground.Value.Blue.ToString ();

+ 37 - 38
UICatalog/UICatalog.cs

@@ -17,40 +17,38 @@ using static Terminal.Gui.TableView;
 
 
 #nullable enable
-/// <summary>
-/// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the catalog of scenarios.
-/// </summary>
-/// <remarks>
-/// <para>
-///	UI Catalog attempts to satisfy the following goals:
-/// </para>
-/// <para>
-/// <list type="number">
-///	<item>
-///		<description>
-///		Be an easy to use showcase for Terminal.Gui concepts and features.
-///		</description>
-///	</item>
-///	<item>
-///		<description>
-///		Provide sample code that illustrates how to properly implement said concepts & features.
-///		</description>
-///	</item>
-///	<item>
-///		<description>
-///		Make it easy for contributors to add additional samples in a structured way.
-///		</description>
-///	</item>
-/// </list>
-/// </para>	
-/// <para>
-///	See the project README for more details (https://github.com/gui-cs/Terminal.Gui/tree/master/UICatalog/README.md).
-/// </para>	
-/// </remarks>
+
 namespace UICatalog {
 	/// <summary>
-	/// UI Catalog is a comprehensive sample app and scenario library for <see cref="Terminal.Gui"/>
+	/// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the catalog of scenarios.
 	/// </summary>
+	/// <remarks>
+	/// <para>
+	///	UI Catalog attempts to satisfy the following goals:
+	/// </para>
+	/// <para>
+	/// <list type="number">
+	///	<item>
+	///		<description>
+	///		Be an easy to use showcase for Terminal.Gui concepts and features.
+	///		</description>
+	///	</item>
+	///	<item>
+	///		<description>
+	///		Provide sample code that illustrates how to properly implement said concepts & features.
+	///		</description>
+	///	</item>
+	///	<item>
+	///		<description>
+	///		Make it easy for contributors to add additional samples in a structured way.
+	///		</description>
+	///	</item>
+	/// </list>
+	/// </para>	
+	/// <para>
+	///	See the project README for more details (https://github.com/gui-cs/Terminal.Gui/tree/master/UICatalog/README.md).
+	/// </para>	
+	/// </remarks>
 	class UICatalogApp {
 		//[SerializableConfigurationProperty (Scope = typeof (AppScope), OmitClassName = true), JsonPropertyName ("UICatalog.StatusBar")]
 		//public static bool ShowStatusBar { get; set; } = true;
@@ -114,8 +112,7 @@ namespace UICatalog {
 			_aboutMessage.AppendLine (@"");
 			_aboutMessage.AppendLine (@"https://github.com/gui-cs/Terminal.Gui");
 
-			Scenario scenario;
-			while ((scenario = RunUICatalogTopLevel ()) != null) {
+			while (RunUICatalogTopLevel () is { } scenario) {
 				VerifyObjectsWereDisposed ();
 				CM.Themes!.Theme = _cachedTheme!;
 				CM.Apply ();
@@ -187,7 +184,7 @@ namespace UICatalog {
 				return;
 			}
 
-			// TOOD: THis is a hack. Figure out how to ensure that the file is fully written before reading it.
+			// TODO: This is a hack. Figure out how to ensure that the file is fully written before reading it.
 			Thread.Sleep (500);
 			CM.Load ();
 			CM.Apply ();
@@ -272,7 +269,7 @@ namespace UICatalog {
 				_themeMenuBarItem = new MenuBarItem ("_Themes", _themeMenuItems);
 				MenuBar = new MenuBar (new MenuBarItem [] {
 					new MenuBarItem ("_File", new MenuItem [] {
-						new MenuItem ("_Quit", "Quit UI Catalog", () => RequestStop(), null, null)
+						new MenuItem ("_Quit", "Quit UI Catalog", RequestStop, null, null)
 					}),
 					_themeMenuBarItem,
 					new MenuBarItem ("Diag_nostics", CreateDiagnosticMenuItems()),
@@ -484,15 +481,16 @@ namespace UICatalog {
 			{
 				List<MenuItem []> menuItems = new List<MenuItem []> {
 					CreateDiagnosticFlagsMenuItems (),
-					Array.Empty<MenuItem> (),
+					new MenuItem [] { null! },
 					CreateDisabledEnabledMouseItems (),
 					CreateDisabledEnabledMenuBorder (),
 					CreateDisabledEnableUseSubMenusSingleFrame (),
-					CreateKeybindingsMenuItems ()
+					CreateKeyBindingsMenuItems ()
 				};
 				return menuItems;
 			}
 
+			// TODO: This should be an ConfigurationManager setting
 			MenuItem [] CreateDisabledEnableUseSubMenusSingleFrame ()
 			{
 				List<MenuItem> menuItems = new List<MenuItem> ();
@@ -510,6 +508,7 @@ namespace UICatalog {
 				return menuItems.ToArray ();
 			}
 
+			// TODO: This should be an ConfigurationManager setting
 			MenuItem [] CreateDisabledEnabledMenuBorder ()
 			{
 				List<MenuItem> menuItems = new List<MenuItem> ();
@@ -543,7 +542,7 @@ namespace UICatalog {
 				return menuItems.ToArray ();
 			}
 
-			MenuItem [] CreateKeybindingsMenuItems ()
+			MenuItem [] CreateKeyBindingsMenuItems ()
 			{
 				List<MenuItem> menuItems = new List<MenuItem> ();
 				var item = new MenuItem {