Browse Source

Fixed Force16Colors; updated UI Catalog to honor

Tigger Kindel 1 year ago
parent
commit
41d6ca884b

+ 25 - 27
Terminal.Gui/Application.cs

@@ -43,9 +43,9 @@ namespace Terminal.Gui {
 	public static partial class Application {
 
 		/// <summary>
-		/// The current <see cref="ConsoleDriver"/> in use.
+		/// Gets the <see cref="ConsoleDriver"/> that has been selected. See also <see cref="UseSystemConsole"/>.
 		/// </summary>
-		public static ConsoleDriver Driver;
+		public static ConsoleDriver Driver { get; internal set; }
 
 		/// <summary>
 		/// If <see langword="true"/>, forces the use of the System.Console-based (see <see cref="NetDriver"/>) driver. The default is <see langword="false"/>.
@@ -53,6 +53,14 @@ namespace Terminal.Gui {
 		[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
 		public static bool UseSystemConsole { get; set; } = false;
 
+		/// <summary>
+		/// Gets or sets whether <see cref="Application.Driver"/> will be forced to output only the 16 colors defined in <see cref="ColorNames"/>.
+		/// The default is <see langword="false"/>, meaning 24-bit (TrueColor) colors will be output as long as the selected <see cref="ConsoleDriver"/>
+		/// supports TrueColor.
+		/// </summary>
+		[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+		public static bool Force16Colors { get; set; } = false;
+
 		// For Unit testing - ignores UseSystemConsole
 		internal static bool _forceFakeConsole;
 
@@ -78,7 +86,6 @@ namespace Terminal.Gui {
 
 			// Return all culture for which satellite folder found with culture code.
 			return culture.Where (cultureInfo =>
-			   assemblyLocation != null &&
 			   Directory.Exists (Path.Combine (assemblyLocation, cultureInfo.Name)) &&
 			   File.Exists (Path.Combine (assemblyLocation, cultureInfo.Name, resourceFilename))
 			).ToList ();
@@ -103,7 +110,7 @@ namespace Terminal.Gui {
 		/// <para>
 		/// The <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver, IMainLoopDriver)"/> function 
 		/// combines <see cref="Init(ConsoleDriver, IMainLoopDriver)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/>
-		/// into a single call. An applciation cam use <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver, IMainLoopDriver)"/> 
+		/// into a single call. An application cam use <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver, IMainLoopDriver)"/> 
 		/// without explicitly calling <see cref="Init(ConsoleDriver, IMainLoopDriver)"/>.
 		/// </para>
 		/// <param name="driver">
@@ -402,10 +409,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// See <see cref="Run(Toplevel, Func{Exception, bool})"/> for more details.
 		/// </remarks>
-		public static void Run (Func<Exception, bool> errorHandler = null)
-		{
-			Run (Top, errorHandler);
-		}
+		public static void Run (Func<Exception, bool> errorHandler = null) => Run (Top, errorHandler);
 
 		/// <summary>
 		/// Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> 
@@ -442,7 +446,7 @@ namespace Terminal.Gui {
 					}
 					Run (top, errorHandler);
 				} else {
-					// This codepath should be impossible because Init(null, null) will select the platform default driver
+					// This code path should be impossible because Init(null, null) will select the platform default driver
 					throw new InvalidOperationException ("Init() completed without a driver being set (this should be impossible); Run<T>() cannot be called.");
 				}
 			} else {
@@ -558,11 +562,11 @@ namespace Terminal.Gui {
 		// users use async/await on their code
 		//
 		class MainLoopSyncContext : SynchronizationContext {
-			readonly MainLoop mainLoop;
+			readonly MainLoop _mainLoop;
 
 			public MainLoopSyncContext (MainLoop mainLoop)
 			{
-				this.mainLoop = mainLoop;
+				this._mainLoop = mainLoop;
 			}
 
 			public override SynchronizationContext CreateCopy ()
@@ -572,11 +576,11 @@ namespace Terminal.Gui {
 
 			public override void Post (SendOrPostCallback d, object state)
 			{
-				mainLoop.AddIdle (() => {
+				_mainLoop.AddIdle (() => {
 					d (state);
 					return false;
 				});
-				//mainLoop.Driver.Wakeup ();
+				//_mainLoop.Driver.Wakeup ();
 			}
 
 			public override void Send (SendOrPostCallback d, object state)
@@ -585,7 +589,7 @@ namespace Terminal.Gui {
 					d (state);
 				} else {
 					var wasExecuted = false;
-					mainLoop.Invoke (() => {
+					_mainLoop.Invoke (() => {
 						d (state);
 						wasExecuted = true;
 					});
@@ -602,12 +606,14 @@ namespace Terminal.Gui {
 		/// <param name="state">The state returned by the <see cref="Begin(Toplevel)"/> method.</param>
 		public static void RunLoop (RunState state)
 		{
-			if (state == null)
+			if (state == null) {
 				throw new ArgumentNullException (nameof (state));
-			if (state.Toplevel == null)
+			}
+			if (state.Toplevel == null) {
 				throw new ObjectDisposedException ("state");
+			}
 
-			bool firstIteration = true;
+			var firstIteration = true;
 			for (state.Toplevel.Running = true; state.Toplevel.Running;) {
 				if (ExitRunLoopAfterFirstIteration && !firstIteration) {
 					return;
@@ -689,14 +695,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		///// <summary>
-		///// Wakes up the <see cref="MainLoop"/> that might be waiting on input; must be thread safe.
-		///// </summary>
-		//public static void DoEvents ()
-		//{
-		//	MainLoop.MainLoopDriver.Wakeup ();
-		//}
-
 		/// <summary>
 		/// Stops running the most recent <see cref="Toplevel"/> or the <paramref name="top"/> if provided.
 		/// </summary>
@@ -1085,7 +1083,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Merely a debugging aid to see the raw mouse events
 		/// </summary>
-		public static Action<MouseEvent> RootMouseEvent;
+		public static Action<MouseEvent> RootMouseEvent { get; set; }
 
 		static View _lastMouseOwnerView;
 
@@ -1312,7 +1310,7 @@ namespace Terminal.Gui {
 		/// </para>
 		/// <para>Return true to suppress the KeyPress event</para>
 		/// </summary>
-		public static Func<KeyEvent, bool> RootKeyEvent;
+		public static Func<KeyEvent, bool> RootKeyEvent { get; set; }
 
 		#endregion Keyboard handling
 	}

+ 5 - 9
Terminal.Gui/Configuration/AttributeJsonConverter.cs

@@ -30,14 +30,14 @@ namespace Terminal.Gui {
 			}
 
 			Attribute attribute = new Attribute ();
-			Color foreground = (Color)(-1);
-			Color background = (Color)(-1);
+			Color foreground = null;
+			Color background = null;
 			while (reader.Read ()) {
 				if (reader.TokenType == JsonTokenType.EndObject) {
-					if (foreground == (Color)(-1) || background == (Color)(-1)) {
+					if (foreground == null || background == null) {
 						throw new JsonException ($"Both Foreground and Background colors must be provided.");
-					}
-					return attribute;
+					} 
+					return new Attribute (foreground, background);
 				}
 
 				if (reader.TokenType != JsonTokenType.PropertyName) {
@@ -80,10 +80,6 @@ namespace Terminal.Gui {
 				default:
 					throw new JsonException ($"Unknown Attribute property {propertyName}.");
 				}
-
-				if (foreground != (Color)(-1) && background != (Color)(-1)) {
-					attribute = new Attribute (foreground, background);
-				}
 			}
 			throw new JsonException ();
 		}

+ 17 - 17
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -365,20 +365,20 @@ public abstract class ConsoleDriver {
 	/// </summary>
 	public virtual bool SupportsTrueColor { get => true; }
 
-	bool _force16Colors = false;
-
-	// TODO: Make this a ConfiguationManager setting on Application
 	/// <summary>
-	/// Gets or sets whether the <see cref="ConsoleDriver"/> should use 16 colors instead of the default TrueColors.
+	/// Gets or sets whether the <see cref="ConsoleDriver"/> should use 16 colors instead of the default TrueColors. See <see cref="Application.Force16Colors"/>
+	/// to change this setting via <see cref="ConfigurationManager"/>.
 	/// </summary>
 	/// <remarks>
+	/// <para>
 	/// 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.
+	/// </para>
 	/// </remarks>
-	public virtual bool Force16Colors {
-		get => _force16Colors || !SupportsTrueColor;
+	internal virtual bool Force16Colors {
+		get => Application.Force16Colors || !SupportsTrueColor;
 		set {
-			_force16Colors = (value || !SupportsTrueColor);
+			Application.Force16Colors = (value || !SupportsTrueColor);
 		}
 	}
 
@@ -430,22 +430,22 @@ public abstract class ConsoleDriver {
 	/// </summary>
 	/// <returns>The current attribute.</returns>
 	public Attribute GetAttribute () => CurrentAttribute;
-
-	/// <summary>
-	/// Makes an <see cref="Attribute"/>.
-	/// </summary>
-	/// <param name="foregroundName">The foreground color.</param>
-	/// <param name="backgroundName">The background color.</param>
-	/// <returns>The attribute for the foreground and background colors.</returns>
-	public abstract Attribute MakeColor (ColorNames foregroundName, ColorNames backgroundName);
-
+	
 	/// <summary>
 	/// Makes an <see cref="Attribute"/>.
 	/// </summary>
 	/// <param name="foreground">The foreground color.</param>
 	/// <param name="background">The background color.</param>
 	/// <returns>The attribute for the foreground and background colors.</returns>
-	public abstract Attribute MakeColor (Color foreground, Color background);
+	public virtual Attribute MakeColor (Color foreground, Color background)
+	{
+		// Encode the colors into the int value.
+		return new Attribute (
+			platformColor: 0, // Not used anymore by anyting but cursesdriver!
+			foreground: foreground,
+			background: background
+		);
+	}
 
 	/// <summary>
 	/// Ensures all <see cref="Attribute"/>s in <see cref="Colors.ColorSchemes"/> are correctly 

+ 2 - 2
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -88,7 +88,7 @@ internal class CursesDriver : ConsoleDriver {
 	/// and the background color is stored in the least significant 4 bits.
 	/// The Terminal.GUi Color values are converted to curses color encoding before being encoded.
 	/// </remarks>
-	public override Attribute MakeColor (ColorNames foregroundName, ColorNames backgroundName)
+	private Attribute MakeColor (ColorNames foregroundName, ColorNames backgroundName)
 	{
 		if (!RunningUnitTests) {
 			return MakeColor (ColorNameToCursesColorNumber (foregroundName), ColorNameToCursesColorNumber (backgroundName));
@@ -244,7 +244,7 @@ internal class CursesDriver : ConsoleDriver {
 					// In unit tests, we don't want to actually write to the screen.
 					continue;
 				}
-				Curses.attrset (Contents [row, col].Attribute.GetValueOrDefault ().Value);
+				Curses.attrset (Contents [row, col].Attribute.GetValueOrDefault ().PlatformColor);
 
 				var rune = Contents [row, col].Runes [0];
 				if (rune.IsBmp) {

+ 17 - 21
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -81,7 +81,7 @@ public class FakeDriver : ConsoleDriver {
 		FakeConsole.Clear ();
 		ResizeScreen ();
 		// Call InitializeColorSchemes before UpdateOffScreen as it references Colors
-		CurrentAttribute = MakeColor (Color.White, Color.Black);
+		CurrentAttribute = new Attribute (Color.White, Color.Black);
 		InitializeColorSchemes ();
 		ClearContents ();
 	}
@@ -134,8 +134,8 @@ public class FakeDriver : ConsoleDriver {
 					// Performance: Only send the escape sequence if the attribute has changed.
 					if (attr != redrawAttr) {
 						redrawAttr = attr;
-						FakeConsole.ForegroundColor = (ConsoleColor)attr.Foreground.Value;
-						FakeConsole.BackgroundColor = (ConsoleColor)attr.Background.Value;
+						FakeConsole.ForegroundColor = (ConsoleColor)attr.Foreground.ColorName;
+						FakeConsole.BackgroundColor = (ConsoleColor)attr.Background.ColorName;
 					}
 					outputWidth++;
 					var rune = (Rune)Contents [row, col].Runes [0];
@@ -187,25 +187,21 @@ public class FakeDriver : ConsoleDriver {
 
 	#region Color Handling
 
-	/// <remarks>
-	/// In the FakeDriver, colors are encoded as an int; same as NetDriver
-	/// However, the foreground color is stored in the most significant 16 bits, 
-	/// and the background color is stored in the least significant 16 bits.
-	/// </remarks>
-	public override Attribute MakeColor (Color foreground, Color background)
-	{
-		// Encode the colors into the int value.
-		return new Attribute (
-			platformColor: ((((int)foreground.ColorName) & 0xffff) << 16) | (((int)background.ColorName) & 0xffff),
-			foreground: foreground,
-			background: background
-		);
-	}
+	///// <remarks>
+	///// In the FakeDriver, colors are encoded as an int; same as NetDriver
+	///// However, the foreground color is stored in the most significant 16 bits, 
+	///// and the background color is stored in the least significant 16 bits.
+	///// </remarks>
+	//public override Attribute MakeColor (Color foreground, Color background)
+	//{
+	//	// Encode the colors into the int value.
+	//	return new Attribute (
+	//		platformColor: 0,//((((int)foreground.ColorName) & 0xffff) << 16) | (((int)background.ColorName) & 0xffff),
+	//		foreground: foreground,
+	//		background: background
+	//	);
+	//}
 
-	public override Attribute MakeColor (ColorNames foreground, ColorNames background)
-	{
-		return MakeColor (new Color (foreground), new Color (background));
-	}
 	#endregion
 
 	public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)

+ 16 - 21
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -695,7 +695,7 @@ internal class NetDriver : ConsoleDriver {
 
 		ResizeScreen ();
 		ClearContents ();
-		CurrentAttribute = MakeColor (Color.White, Color.Black);
+		CurrentAttribute = new Attribute (Color.White, Color.Black);
 		InitializeColorSchemes ();
 
 		StartReportingMouseMoves ();
@@ -793,7 +793,7 @@ internal class NetDriver : ConsoleDriver {
 
 						if (Force16Colors) {
 							output.Append (EscSeqUtils.CSI_SetGraphicsRendition (
-								MapColors ((ConsoleColor)attr.Background.Value, false), MapColors ((ConsoleColor)attr.Foreground.Value, true)));
+								MapColors ((ConsoleColor)attr.Background.ColorName, false), MapColors ((ConsoleColor)attr.Foreground.ColorName, true)));
 						} else {
 							output.Append (EscSeqUtils.CSI_SetForegroundColorRGB (attr.Foreground.R, attr.Foreground.G, attr.Foreground.B));
 							output.Append (EscSeqUtils.CSI_SetBackgroundColorRGB (attr.Background.R, attr.Background.G, attr.Background.B));
@@ -862,25 +862,20 @@ internal class NetDriver : ConsoleDriver {
 		return colorMap.TryGetValue (color, out var colorValue) ? colorValue + (isForeground ? 0 : 10) : 0;
 	}
 
-	/// <remarks>
-	/// In the NetDriver, colors are encoded as an int. 
-	/// However, the foreground color is stored in the most significant 16 bits, 
-	/// and the background color is stored in the least significant 16 bits.
-	/// </remarks>
-	public override Attribute MakeColor (Color foreground, Color background)
-	{
-		// Encode the colors into the int value.
-		return new Attribute (
-			platformColor: ((((int)foreground.ColorName) & 0xffff) << 16) | (((int)background.ColorName) & 0xffff),
-			foreground: foreground,
-			background: background
-		);
-	}
-
-	public override Attribute MakeColor (ColorNames foreground, ColorNames background)
-	{
-		return MakeColor (new Color (foreground), new Color (background));
-	}
+	///// <remarks>
+	///// In the NetDriver, colors are encoded as an int. 
+	///// However, the foreground color is stored in the most significant 16 bits, 
+	///// and the background color is stored in the least significant 16 bits.
+	///// </remarks>
+	//public override Attribute MakeColor (Color foreground, Color background)
+	//{
+	//	// Encode the colors into the int value.
+	//	return new Attribute (
+	//		platformColor: ((((int)foreground.ColorName) & 0xffff) << 16) | (((int)background.ColorName) & 0xffff),
+	//		foreground: foreground,
+	//		background: background
+	//	);
+	//}
 	#endregion
 
 	#region Cursor Handling

+ 3 - 7
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -67,7 +67,7 @@ internal class WindowsConsole {
 			foreach (ExtendedCharInfo info in charInfoBuffer) {
 				ci [i++] = new CharInfo () {
 					Char = new CharUnion () { UnicodeChar = info.Char },
-					Attributes = (ushort)info.Attribute.Value
+					Attributes = (ushort)(((int)info.Attribute.Foreground.ColorName) | ((int)info.Attribute.Background.ColorName << 4))
 				};
 			}
 
@@ -1542,7 +1542,7 @@ internal class WindowsDriver : ConsoleDriver {
 			WinConsole = null;
 		}
 
-		CurrentAttribute = MakeColor (Color.White, Color.Black);
+		CurrentAttribute = new Attribute (Color.White, Color.Black);
 		InitializeColorSchemes ();
 
 		_outputBuffer = new WindowsConsole.ExtendedCharInfo [Rows * Cols];
@@ -1649,15 +1649,11 @@ internal class WindowsDriver : ConsoleDriver {
 	{
 		// Encode the colors into the int value.
 		return new Attribute (
-			platformColor: (((int)foreground.ColorName) | ((int)background.ColorName << 4)),
+			platformColor: 0, // Not used anymore! (((int)foreground.ColorName) | ((int)background.ColorName << 4)),
 			foreground: foreground,
 			background: background
 		);
 	}
-	public override Attribute MakeColor (ColorNames foreground, ColorNames background)
-	{
-		return MakeColor (new Color (foreground), new Color (background));
-	}
 
 	#endregion
 

+ 24 - 11
Terminal.Gui/Drawing/Color.cs

@@ -256,7 +256,7 @@ namespace Terminal.Gui {
 		/// Get returns the <see cref="ColorName"/> of the closest 24-bit color value. Set sets the RGB value using a hard-coded map.
 		/// </remarks>
 		public ColorNames ColorName {
-			get => FindClosestColor (this.Value);
+			get => FindClosestColor (this);
 			set {
 
 				var c = FromColorName (value);
@@ -393,7 +393,7 @@ namespace Terminal.Gui {
 				return true;
 			}
 
-			// rgb(XX,YY,ZZ)
+			// rgb(r,g,b)
 			var match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+)\)");
 			if (match.Success) {
 				var r = int.Parse (match.Groups [1].Value);
@@ -403,7 +403,7 @@ namespace Terminal.Gui {
 				return true;
 			}
 
-			// rgb(AA,XX,YY,ZZ)
+			// rgb(a,r,g,b)
 			match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+),(\d+)\)");
 			if (match.Success) {
 				var a = int.Parse (match.Groups [1].Value);
@@ -464,9 +464,16 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		public static bool operator == (Color left, Color right)
 		{
+			if (left is null && right is null)
+				return true;
+
+			if (left is null || right is null)
+				return false;
+
 			return left.Equals (right);
 		}
 
+
 		/// <summary>
 		/// Inequality operator for two <see cref="Color"/> objects.
 		/// </summary>
@@ -475,6 +482,12 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		public static bool operator != (Color left, Color right)
 		{
+			if (left is null && right is null)
+				return false;
+
+			if (left is null || right is null)
+				return true;
+			
 			return !left.Equals (right);
 		}
 
@@ -587,7 +600,7 @@ namespace Terminal.Gui {
 		/// and the attribute should be re-made before it is used.
 		/// </summary>
 		[JsonIgnore (Condition = JsonIgnoreCondition.Always)]
-		internal int Value { get; }
+		internal int PlatformColor { get; }
 
 		/// <summary>
 		/// The foreground color.
@@ -607,7 +620,7 @@ namespace Terminal.Gui {
 		public Attribute ()
 		{
 			var d = Default;
-			Value = -1;
+			PlatformColor = -1;
 			Foreground = d.Foreground;
 			Background = d.Background;
 		}
@@ -628,7 +641,7 @@ namespace Terminal.Gui {
 		{
 			Foreground = foreground;
 			Background = background;
-			Value = platformColor;
+			PlatformColor = platformColor;
 			Initialized = true;
 		}
 
@@ -653,13 +666,13 @@ namespace Terminal.Gui {
 			if (Application.Driver == null) {
 				// Create the attribute, but show it's not been initialized
 				Initialized = false;
-				Value = -1;
+				PlatformColor = -1;
 				return;
 			}
 
 			var make = Application.Driver.MakeAttribute (foreground, background);
 			Initialized = make.Initialized;
-			Value = make.Value;
+			PlatformColor = make.PlatformColor;
 		}
 
 		/// <summary>
@@ -724,17 +737,17 @@ namespace Terminal.Gui {
 		/// <inheritdoc />
 		public bool Equals (Attribute other)
 		{
-			return Value == other.Value &&
+			return PlatformColor == other.PlatformColor &&
 				Foreground == other.Foreground &&
 				Background == other.Background;
 		}
 
 		/// <inheritdoc />
-		public override int GetHashCode () => HashCode.Combine (Value, Foreground, Background);
+		public override int GetHashCode () => HashCode.Combine (PlatformColor, Foreground, Background);
 
 		/// <summary>
 		/// If <see langword="true"/> the attribute has been initialized by a <see cref="ConsoleDriver"/> and 
-		/// thus has <see cref="Value"/> that is valid for that driver. If <see langword="false"/> the <see cref="Foreground"/>
+		/// thus has <see cref="PlatformColor"/> that is valid for that driver. If <see langword="false"/> the <see cref="Foreground"/>
 		/// and <see cref="Background"/> colors may have been set '-1' but
 		/// the attribute has not been mapped to a <see cref="ConsoleDriver"/> specific color value.
 		/// </summary>

+ 2 - 2
UICatalog/Scenarios/Images.cs

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

+ 2 - 2
UICatalog/Scenarios/TrueColors.cs

@@ -32,11 +32,11 @@ namespace UICatalog.Scenarios {
 			var cbUseTrueColor = new CheckBox ("Force 16 colors") {
 				X = x,
 				Y = y++,
-				Checked = Application.Driver.Force16Colors,
+				Checked = Application.Force16Colors,
 				Enabled = canTrueColor,
 			};
 			cbUseTrueColor.Toggled += (_, evt) => {
-				Application.Driver.Force16Colors = evt.NewValue ?? false;
+				Application.Force16Colors = evt.NewValue ?? false;
 			};
 			Win.Add (cbUseTrueColor);
 

+ 8 - 7
UICatalog/UICatalog.cs

@@ -117,7 +117,6 @@ namespace UICatalog {
 				scenario.Theme = _cachedTheme;
 				scenario.TopLevelColorScheme = _topLevelColorScheme;
 				scenario.Init ();
-				Application.Driver.Force16Colors = _force16Colors;
 				scenario.Setup ();
 				scenario.Run ();
 				scenario.Dispose ();
@@ -232,7 +231,6 @@ namespace UICatalog {
 		static Scenario? _selectedScenario = null;
 
 		static bool _useSystemConsole = false;
-		static bool _force16Colors = false;
 		static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
 		static bool _isFirstRunning = true;
 		static string _topLevelColorScheme = string.Empty;
@@ -483,8 +481,6 @@ namespace UICatalog {
 				List<MenuItem []> menuItems = new List<MenuItem []> {
 					CreateDiagnosticFlagsMenuItems (),
 					new MenuItem [] { null! },
-					CreateForce16ColorItems (),
-					new MenuItem [] { null! },
 					CreateDisabledEnabledMouseItems (),
 					CreateDisabledEnabledMenuBorder (),
 					CreateDisabledEnableUseSubMenusSingleFrame (),
@@ -535,12 +531,13 @@ namespace UICatalog {
 				List<MenuItem> menuItems = new List<MenuItem> ();
 				miForce16Colors = new MenuItem {
 					Title = "Force 16 _Colors",
-					Checked = _force16Colors
+					Checked = Application.Force16Colors,
+					CanExecute = () => (bool)Application.Driver.SupportsTrueColor
 				};
 				miForce16Colors.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miForce16Colors!.Title!.Substring (10, 1) [0];
 				miForce16Colors.CheckType |= MenuItemCheckStyle.Checked;
 				miForce16Colors.Action += () => {
-					miForce16Colors.Checked = _force16Colors = Application.Driver.Force16Colors = (bool)!miForce16Colors.Checked!;
+					miForce16Colors.Checked = Application.Force16Colors = (bool)!miForce16Colors.Checked!;
 					Application.Refresh ();
 				};
 				menuItems.Add (miForce16Colors);
@@ -679,7 +676,9 @@ namespace UICatalog {
 
 			public MenuItem []? CreateThemeMenuItems ()
 			{
-				List<MenuItem> menuItems = new List<MenuItem> ();
+				var menuItems = CreateForce16ColorItems ().ToList();
+				menuItems.Add (null!);
+
 				foreach (var theme in CM.Themes!) {
 					var item = new MenuItem {
 						Title = theme.Key,
@@ -722,6 +721,8 @@ namespace UICatalog {
 
 			public void ConfigChanged ()
 			{
+				miForce16Colors.Checked = Application.Force16Colors;
+
 				if (_topLevelColorScheme == null || !Colors.ColorSchemes.ContainsKey (_topLevelColorScheme)) {
 					_topLevelColorScheme = "Base";
 				}

+ 5 - 5
UnitTests/Drawing/AttributeTests.cs

@@ -17,7 +17,7 @@ public class AttributeTests {
 
 		// Assert
 		Assert.False (attribute.Initialized);
-		Assert.Equal (-1, attribute.Value);
+		Assert.Equal (-1, attribute.PlatformColor);
 		Assert.Equal ((Color)Color.White, attribute.Foreground);
 		Assert.Equal ((Color)Color.Black, attribute.Background);
 
@@ -31,7 +31,7 @@ public class AttributeTests {
 
 		// Assert
 		Assert.True (attribute.Initialized);
-		Assert.Equal (42, attribute.Value);
+		Assert.Equal (42, attribute.PlatformColor);
 		Assert.Equal ((Color)Color.White, attribute.Foreground);
 		Assert.Equal ((Color)Color.Black, attribute.Background);
 	}
@@ -96,7 +96,7 @@ public class AttributeTests {
 		// Test parameterless constructor
 		var attr = new Attribute ();
 
-		Assert.Equal (-1, attr.Value);
+		Assert.Equal (-1, attr.PlatformColor);
 		Assert.Equal ((Color)Color.White, attr.Foreground);
 		Assert.Equal ((Color)Color.Black, attr.Background);
 
@@ -210,10 +210,10 @@ public class AttributeTests {
 
 		// Test conversion to int
 		attr = new Attribute (value, fg, bg);
-		int value_implicit = attr.Value;
+		int value_implicit = attr.PlatformColor;
 		Assert.Equal (value, value_implicit);
 
-		Assert.Equal (value, attr.Value);
+		Assert.Equal (value, attr.PlatformColor);
 
 		driver.End ();
 		Application.Shutdown ();

+ 2 - 2
UnitTests/TestHelpers.cs

@@ -307,7 +307,7 @@ partial class TestHelpers {
 				var match = expectedColors.Where (e => e == val).ToList ();
 				switch (match.Count) {
 				case 0:
-					throw new Exception ($"Unexpected color {val} was used at row {r} and col {c} (indexes start at 0).  Color value was {val} (expected colors were {string.Join (",", expectedColors.Select (c => c.Value.ToString ()))})");
+					throw new Exception ($"Unexpected color {val} was used at row {r} and col {c} (indexes start at 0).  Color value was {val} (expected colors were {string.Join (",", expectedColors.Select (c => c.PlatformColor.ToString ()))})");
 				case > 1:
 					throw new ArgumentException ($"Bad value for expectedColors, {match.Count} Attributes had the same Value");
 				}
@@ -315,7 +315,7 @@ partial class TestHelpers {
 				var colorUsed = Array.IndexOf (expectedColors, match [0]).ToString () [0];
 				var userExpected = line [c];
 
-				if (colorUsed != userExpected) throw new Exception ($"Colors used did not match expected at row {r} and col {c} (indexes start at 0).  Color index used was {colorUsed} ({val}) but test expected {userExpected} ({expectedColors [int.Parse (userExpected.ToString ())].Value}) (these are indexes into the expectedColors array)");
+				if (colorUsed != userExpected) throw new Exception ($"Colors used did not match expected at row {r} and col {c} (indexes start at 0).  Color index used was {colorUsed} ({val}) but test expected {userExpected} ({expectedColors [int.Parse (userExpected.ToString ())].PlatformColor}) (these are indexes into the expectedColors array)");
 			}
 
 			r++;