Browse Source

Merge branch 'master' of https://github.com/migueldeicaza/gui.cs into combobox_fixes

Ross Ferguson 5 years ago
parent
commit
4279924624

+ 2 - 2
Terminal.Gui/ConsoleDrivers/MockDriver/MockConsole.cs → Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs

@@ -1,5 +1,5 @@
 //
 //
-// MockConsole.cs: A mock .NET Windows Console API implementaiton for unit tests.
+// FakeConsole.cs: A fake .NET Windows Console API implementaiton for unit tests.
 //
 //
 // Authors:
 // Authors:
 //   Charlie Kindel (github.com/tig)
 //   Charlie Kindel (github.com/tig)
@@ -15,7 +15,7 @@ namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
 	/// 
 	/// 
 	/// </summary>
 	/// </summary>
-	public static class MockConsole {
+	public static class FakeConsole {
 
 
 		//
 		//
 		// Summary:
 		// Summary:

+ 25 - 25
Terminal.Gui/ConsoleDrivers/MockDriver/MockDriver.cs → Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -1,5 +1,5 @@
 //
 //
-// MockDriver.cs: A mock ConsoleDriver for unit tests.
+// FakeDriver.cs: A fake ConsoleDriver for unit tests. 
 //
 //
 // Authors:
 // Authors:
 //   Charlie Kindel (github.com/tig)
 //   Charlie Kindel (github.com/tig)
@@ -14,7 +14,7 @@ namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
 	/// Implements a mock ConsoleDriver for unit testing
 	/// Implements a mock ConsoleDriver for unit testing
 	/// </summary>
 	/// </summary>
-	public class MockDriver : ConsoleDriver, IMainLoopDriver {
+	public class FakeDriver : ConsoleDriver, IMainLoopDriver {
 		int cols, rows;
 		int cols, rows;
 		/// <summary>
 		/// <summary>
 		/// 
 		/// 
@@ -52,10 +52,10 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// 
 		/// 
 		/// </summary>
 		/// </summary>
-		public MockDriver ()
+		public FakeDriver ()
 		{
 		{
-			cols = MockConsole.WindowWidth;
-			rows = MockConsole.WindowHeight; // - 1;
+			cols = FakeConsole.WindowWidth;
+			rows = FakeConsole.WindowHeight; // - 1;
 			UpdateOffscreen ();
 			UpdateOffscreen ();
 		}
 		}
 
 
@@ -73,12 +73,12 @@ namespace Terminal.Gui {
 			crow = row;
 			crow = row;
 
 
 			if (Clip.Contains (col, row)) {
 			if (Clip.Contains (col, row)) {
-				MockConsole.CursorTop = row;
-				MockConsole.CursorLeft = col;
+				FakeConsole.CursorTop = row;
+				FakeConsole.CursorLeft = col;
 				needMove = false;
 				needMove = false;
 			} else {
 			} else {
-				MockConsole.CursorTop = Clip.Y;
-				MockConsole.CursorLeft = Clip.X;
+				FakeConsole.CursorTop = Clip.Y;
+				FakeConsole.CursorLeft = Clip.X;
 				needMove = true;
 				needMove = true;
 			}
 			}
 
 
@@ -127,8 +127,8 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public override void End ()
 		public override void End ()
 		{
 		{
-			MockConsole.ResetColor ();
-			MockConsole.Clear ();
+			FakeConsole.ResetColor ();
+			FakeConsole.Clear ();
 		}
 		}
 
 
 		static Attribute MakeColor (ConsoleColor f, ConsoleColor b)
 		static Attribute MakeColor (ConsoleColor f, ConsoleColor b)
@@ -230,10 +230,10 @@ namespace Terminal.Gui {
 			      .OfType<ConsoleColor> ()
 			      .OfType<ConsoleColor> ()
 			      .Select (s => (int)s);
 			      .Select (s => (int)s);
 			if (values.Contains (color & 0xffff)) {
 			if (values.Contains (color & 0xffff)) {
-				MockConsole.BackgroundColor = (ConsoleColor)(color & 0xffff);
+				FakeConsole.BackgroundColor = (ConsoleColor)(color & 0xffff);
 			}
 			}
 			if (values.Contains ((color >> 16) & 0xffff)) {
 			if (values.Contains ((color >> 16) & 0xffff)) {
-				MockConsole.ForegroundColor = (ConsoleColor)((color >> 16) & 0xffff);
+				FakeConsole.ForegroundColor = (ConsoleColor)((color >> 16) & 0xffff);
 			}
 			}
 		}
 		}
 
 
@@ -245,8 +245,8 @@ namespace Terminal.Gui {
 			int rows = Rows;
 			int rows = Rows;
 			int cols = Cols;
 			int cols = Cols;
 
 
-			MockConsole.CursorTop = 0;
-			MockConsole.CursorLeft = 0;
+			FakeConsole.CursorTop = 0;
+			FakeConsole.CursorLeft = 0;
 			for (int row = 0; row < rows; row++) {
 			for (int row = 0; row < rows; row++) {
 				dirtyLine [row] = false;
 				dirtyLine [row] = false;
 				for (int col = 0; col < cols; col++) {
 				for (int col = 0; col < cols; col++) {
@@ -254,7 +254,7 @@ namespace Terminal.Gui {
 					var color = contents [row, col, 1];
 					var color = contents [row, col, 1];
 					if (color != redrawColor)
 					if (color != redrawColor)
 						SetColor (color);
 						SetColor (color);
-					MockConsole.Write ((char)contents [row, col, 0]);
+					FakeConsole.Write ((char)contents [row, col, 0]);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -267,8 +267,8 @@ namespace Terminal.Gui {
 			int rows = Rows;
 			int rows = Rows;
 			int cols = Cols;
 			int cols = Cols;
 
 
-			var savedRow = MockConsole.CursorTop;
-			var savedCol = MockConsole.CursorLeft;
+			var savedRow = FakeConsole.CursorTop;
+			var savedCol = FakeConsole.CursorLeft;
 			for (int row = 0; row < rows; row++) {
 			for (int row = 0; row < rows; row++) {
 				if (!dirtyLine [row])
 				if (!dirtyLine [row])
 					continue;
 					continue;
@@ -277,20 +277,20 @@ namespace Terminal.Gui {
 					if (contents [row, col, 2] != 1)
 					if (contents [row, col, 2] != 1)
 						continue;
 						continue;
 
 
-					MockConsole.CursorTop = row;
-					MockConsole.CursorLeft = col;
+					FakeConsole.CursorTop = row;
+					FakeConsole.CursorLeft = col;
 					for (; col < cols && contents [row, col, 2] == 1; col++) {
 					for (; col < cols && contents [row, col, 2] == 1; col++) {
 						var color = contents [row, col, 1];
 						var color = contents [row, col, 1];
 						if (color != redrawColor)
 						if (color != redrawColor)
 							SetColor (color);
 							SetColor (color);
 
 
-						MockConsole.Write ((char)contents [row, col, 0]);
+						FakeConsole.Write ((char)contents [row, col, 0]);
 						contents [row, col, 2] = 0;
 						contents [row, col, 2] = 0;
 					}
 					}
 				}
 				}
 			}
 			}
-			MockConsole.CursorTop = savedRow;
-			MockConsole.CursorLeft = savedCol;
+			FakeConsole.CursorTop = savedRow;
+			FakeConsole.CursorLeft = savedCol;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -421,7 +421,7 @@ namespace Terminal.Gui {
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		{
 		{
 			// Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
 			// Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
-			(mainLoop.Driver as MockDriver).WindowsKeyPressed = delegate (ConsoleKeyInfo consoleKey) {
+			(mainLoop.Driver as FakeDriver).WindowsKeyPressed = delegate (ConsoleKeyInfo consoleKey) {
 				var map = MapKey (consoleKey);
 				var map = MapKey (consoleKey);
 				if (map == (Key)0xffffffff)
 				if (map == (Key)0xffffffff)
 					return;
 					return;
@@ -478,7 +478,7 @@ namespace Terminal.Gui {
 		{
 		{
 			while (true) {
 			while (true) {
 				waitForProbe.WaitOne ();
 				waitForProbe.WaitOne ();
-				windowsKeyResult = MockConsole.ReadKey (true);
+				windowsKeyResult = FakeConsole.ReadKey (true);
 				keyReady.Set ();
 				keyReady.Set ();
 			}
 			}
 		}
 		}

+ 16 - 5
Terminal.Gui/Core/PosDim.cs

@@ -222,7 +222,7 @@ namespace Terminal.Gui {
 
 
 			public override string ToString ()
 			public override string ToString ()
 			{
 			{
-				return $"Pos.Combine ({left.ToString ()}{(add ? '+' : '-')}{right.ToString ()})";
+				return $"Pos.Combine({left.ToString ()}{(add ? '+' : '-')}{right.ToString ()})";
 			}
 			}
 
 
 		}
 		}
@@ -274,7 +274,7 @@ namespace Terminal.Gui {
 			}
 			}
 			internal override int Anchor (int width)
 			internal override int Anchor (int width)
 			{
 			{
-				switch (side) {
+				switch(side) {
 				case 0: return Target.Frame.X;
 				case 0: return Target.Frame.X;
 				case 1: return Target.Frame.Y;
 				case 1: return Target.Frame.Y;
 				case 2: return Target.Frame.Right;
 				case 2: return Target.Frame.Right;
@@ -287,14 +287,14 @@ namespace Terminal.Gui {
 			public override string ToString ()
 			public override string ToString ()
 			{
 			{
 				string tside;
 				string tside;
-				switch (side) {
+				switch(side) {
 				case 0: tside = "x"; break;
 				case 0: tside = "x"; break;
 				case 1: tside = "y"; break;
 				case 1: tside = "y"; break;
 				case 2: tside = "right"; break;
 				case 2: tside = "right"; break;
 				case 3: tside = "bottom"; break;
 				case 3: tside = "bottom"; break;
 				default: tside = "unknown"; break;
 				default: tside = "unknown"; break;
 				}
 				}
-				return $"Pos.View(side={tside}, target={Target.ToString ()}";
+				return $"Pos.View(side={tside}, target={Target.ToString ()})";
 			}
 			}
 		}
 		}
 
 
@@ -538,9 +538,20 @@ namespace Terminal.Gui {
 				this.side = side;
 				this.side = side;
 			}
 			}
 
 
+			public override string ToString ()
+			{
+				string tside;
+				switch(side) {
+				case 0: tside = "Height"; break;
+				case 1: tside = "Width"; break;
+				default: tside = "unknown"; break;
+				}
+				return $"DimView(side={tside}, target={Target.ToString ()})";
+			}
+
 			internal override int Anchor (int width)
 			internal override int Anchor (int width)
 			{
 			{
-				switch (side) {
+				switch(side) {
 				case 0: return Target.Frame.Height;
 				case 0: return Target.Frame.Height;
 				case 1: return Target.Frame.Width;
 				case 1: return Target.Frame.Width;
 				default:
 				default:

+ 172 - 1
Terminal.Gui/Core/View.cs

@@ -17,6 +17,27 @@ using System.Linq;
 using NStack;
 using NStack;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
+	/// <summary>
+	/// Text alignment enumeration, controls how text is displayed.
+	/// </summary>
+	public enum TextAlignment {
+		/// <summary>
+		/// Aligns the text to the left of the frame.
+		/// </summary>
+		Left,
+		/// <summary>
+		/// Aligns the text to the right side of the frame.
+		/// </summary>
+		Right,
+		/// <summary>
+		/// Centers the text in the frame.
+		/// </summary>
+		Centered,
+		/// <summary>
+		/// Shows the text as justified text in the frame.
+		/// </summary>
+		Justified
+	}
 
 
 	/// <summary>
 	/// <summary>
 	/// Determines the LayoutStyle for a view, if Absolute, during LayoutSubviews, the
 	/// Determines the LayoutStyle for a view, if Absolute, during LayoutSubviews, the
@@ -299,6 +320,7 @@ namespace Terminal.Gui {
 			set {
 			set {
 				x = value;
 				x = value;
 				SetNeedsLayout ();
 				SetNeedsLayout ();
+				SetNeedsDisplay (frame);
 			}
 			}
 		}
 		}
 
 
@@ -314,6 +336,7 @@ namespace Terminal.Gui {
 			set {
 			set {
 				y = value;
 				y = value;
 				SetNeedsLayout ();
 				SetNeedsLayout ();
+				SetNeedsDisplay (frame);
 			}
 			}
 		}
 		}
 
 
@@ -331,6 +354,7 @@ namespace Terminal.Gui {
 			set {
 			set {
 				width = value;
 				width = value;
 				SetNeedsLayout ();
 				SetNeedsLayout ();
+				SetNeedsDisplay (frame);
 			}
 			}
 		}
 		}
 
 
@@ -344,6 +368,7 @@ namespace Terminal.Gui {
 			set {
 			set {
 				height = value;
 				height = value;
 				SetNeedsLayout ();
 				SetNeedsLayout ();
+				SetNeedsDisplay (frame);
 			}
 			}
 		}
 		}
 
 
@@ -1450,6 +1475,153 @@ namespace Terminal.Gui {
 			OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds });
 			OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds });
 		}
 		}
 
 
+		/// <summary>
+		/// A generic virtual method at the level of View to manipulate any hot-keys.
+		/// </summary>
+		/// <param name="text">The text to manipulate.</param>
+		/// <param name="hotKey">The hot-key to look for.</param>
+		/// <param name="hotPos">The returning hot-key position.</param>
+		/// <param name="showHotKey">The character immediately to the right relative to the hot-key position</param>
+		/// <returns>It aims to facilitate the preparation for <see cref="TextAlignment"/> procedures.</returns>
+		public virtual ustring GetTextFromHotKey(ustring text, Rune hotKey, out int hotPos, out Rune showHotKey)
+		{
+			Rune hot_key = (Rune)0;
+			int hot_pos = -1;
+			ustring shown_text = text;
+
+			// Use first hot_key char passed into 'hotKey'.
+			int i = 0;
+			foreach (Rune c in shown_text) {
+				if ((char)c != 0xFFFD) {
+					if (c == hotKey) {
+						hot_pos = i;
+					} else if (hot_pos > -1) {
+						hot_key = c;
+						break;
+					}
+				}
+				i++;
+			}
+
+			if (hot_pos == -1) {
+				// Use first upper-case char if there are no hot-key in the text.
+				i = 0;
+				foreach (Rune c in shown_text) {
+					if ((char)c != 0xFFFD) {
+						if (Rune.IsUpper (c)) {
+							hot_key = c;
+							hot_pos = i;
+							break;
+						}
+					}
+					i++;
+				}
+			} else {
+				// Use char after 'hotKey'
+				ustring start = "";
+				i = 0;
+				foreach (Rune c in shown_text) {
+					start += ustring.Make (c);
+					i++;
+					if (i == hot_pos)
+						break;
+				}
+				var st = shown_text;
+				shown_text = start;
+				i = 0;
+				foreach (Rune c in st) {
+					i++;
+					if (i > hot_pos + 1) {
+						shown_text += ustring.Make (c);
+					}
+				}
+			}
+			hotPos = hot_pos;
+			showHotKey = hot_key;
+			return shown_text;
+		}
+
+		/// <summary>
+		/// A generic virtual method at the level of View to manipulate any hot-keys with <see cref="TextAlignment"/> process.
+		/// </summary>
+		/// <param name="shown_text">The text to manipulate to align.</param>
+		/// <param name="hot_pos">The passed in hot-key position.</param>
+		/// <param name="c_hot_pos">The returning hot-key position.</param>
+		/// <param name="textAlignment">The <see cref="TextAlignment"/> to align to.</param>
+		/// <returns>It performs the <see cref="TextAlignment"/> process to the caller.</returns>
+		public virtual ustring GetTextAlignment (ustring shown_text, int hot_pos, out int c_hot_pos, TextAlignment textAlignment)
+		{
+			int start;
+			var caption = shown_text;
+			c_hot_pos = hot_pos;
+
+			if (Frame.Width > shown_text.Length + 1) {
+				switch (textAlignment) {
+				case TextAlignment.Left:
+					caption += new string (' ', Frame.Width - caption.RuneCount);
+					break;
+				case TextAlignment.Right:
+					start = Frame.Width - caption.RuneCount;
+					caption = $"{new string (' ', Frame.Width - caption.RuneCount)}{caption}";
+					if (c_hot_pos > -1) {
+						c_hot_pos += start;
+					}
+					break;
+				case TextAlignment.Centered:
+					start = Frame.Width / 2 - caption.RuneCount / 2;
+					caption = $"{new string (' ', start)}{caption}{new string (' ', Frame.Width - caption.RuneCount - start)}";
+					if (c_hot_pos > -1) {
+						c_hot_pos += start;
+					}
+					break;
+				case TextAlignment.Justified:
+					var words = caption.Split (" ");
+					var wLen = GetWordsLength (words, c_hot_pos, out int runeCount, out int w_hot_pos);
+					var space = (Frame.Width - runeCount) / (caption.Length - wLen);
+					caption = "";
+					for (int i = 0; i < words.Length; i++) {
+						if (i == words.Length - 1) {
+							caption += new string (' ', Frame.Width - caption.RuneCount - 1);
+							caption += words [i];
+						} else {
+							caption += words [i];
+						}
+						if (i < words.Length - 1) {
+							caption += new string (' ', space);
+						}
+					}
+					if (c_hot_pos > -1) {
+						if (wLen - runeCount == 0) {
+							c_hot_pos += (wLen - runeCount == 0 ? w_hot_pos * (space) - space - w_hot_pos + 1 : space + wLen - runeCount);
+						} else {
+							c_hot_pos += space + wLen - runeCount;
+						}
+					}
+					break;
+				}
+			}
+
+			return caption;
+		}
+
+		int GetWordsLength (ustring [] words, int hotPos, out int runeCount, out int wordHotPos)
+		{
+			int length = 0;
+			int rCount = 0;
+			int wHotPos = -1;
+			for (int i = 0; i < words.Length; i++) {
+				if (wHotPos == -1 && rCount + words [i].RuneCount >= hotPos)
+					wHotPos = i;
+				length += words [i].Length;
+				rCount += words [i].RuneCount;
+			}
+			if (wHotPos == -1 && hotPos > -1)
+				wHotPos = words.Length;
+			runeCount = rCount;
+			wordHotPos = wHotPos;
+			return length;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Pretty prints the View
 		/// Pretty prints the View
 		/// </summary>
 		/// </summary>
@@ -1505,7 +1677,6 @@ namespace Terminal.Gui {
 			return false;
 			return false;
 		}
 		}
 
 
-
 		/// <summary>
 		/// <summary>
 		/// Method invoked when a mouse event is generated
 		/// Method invoked when a mouse event is generated
 		/// </summary>
 		/// </summary>

+ 10 - 85
Terminal.Gui/Views/Button.cs

@@ -137,9 +137,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			set {
 			set {
-				if (text?.Length != value?.Length) {
-					SetWidthHeight (value, is_default);
-				}
+				SetWidthHeight (value, is_default);
 				text = value;
 				text = value;
 				Update ();
 				Update ();
 			}
 			}
@@ -152,14 +150,14 @@ namespace Terminal.Gui {
 			get => textAlignment;
 			get => textAlignment;
 			set {
 			set {
 				textAlignment = value;
 				textAlignment = value;
-				SetNeedsDisplay ();
+				Update ();
 			}
 			}
 		}
 		}
 
 
-		Rune _leftBracket = new Rune ('[');
-		Rune _rightBracket = new Rune (']');
-		Rune _leftDefault = new Rune ('<');
-		Rune _rightDefault = new Rune ('>');
+		Rune _leftBracket = new Rune (Driver.LeftBracket);
+		Rune _rightBracket = new Rune (Driver.RightBracket);
+		Rune _leftDefault = new Rune (Driver.LeftDefaultIndicator);
+		Rune _rightDefault = new Rune (Driver.RightDefaultIndicator);
 
 
 		internal void Update ()
 		internal void Update ()
 		{
 		{
@@ -168,26 +166,7 @@ namespace Terminal.Gui {
 			else
 			else
 				shown_text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
 				shown_text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
 
 
-			hot_key = (Rune)0;
-			hot_pos = shown_text.IndexOf ('_');
-
-			if (hot_pos == -1) {
-				// Use first upper-case char
-				int i = 0;
-				foreach (Rune c in shown_text) {
-					if (Rune.IsUpper (c)) {
-						hot_key = c;
-						hot_pos = i;
-						break;
-					}
-					i++;
-				}
-			} else {
-				// Use char after '_'
-				var start = shown_text [0, hot_pos];
-				shown_text = start + shown_text [hot_pos + 1, shown_text.Length];
-				hot_key = Char.ToUpper((char)shown_text [hot_pos]);
-			}
+			shown_text = GetTextFromHotKey (shown_text, '_', out hot_pos, out hot_key);
 
 
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 		}
 		}
@@ -200,51 +179,8 @@ namespace Terminal.Gui {
 			Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal);
 			Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal);
 			Move (0, 0);
 			Move (0, 0);
 
 
-			var caption = shown_text;
-			c_hot_pos = hot_pos;
-			int start;
-
-			if (Frame.Width > shown_text.Length + 1) {
-				switch (TextAlignment) {
-				case TextAlignment.Left:
-					caption += new string (' ', Frame.Width - caption.Length);
-					break;
-				case TextAlignment.Right:
-					start = Frame.Width - caption.Length;
-					caption = $"{new string (' ', Frame.Width - caption.Length)}{caption}";
-					if (c_hot_pos > -1) {
-						c_hot_pos += start;
-					}
-					break;
-				case TextAlignment.Centered:
-					start = Frame.Width / 2 - caption.Length / 2;
-					caption = $"{new string (' ', start)}{caption}{new string (' ', Frame.Width - caption.Length - start)}";
-					if (c_hot_pos > -1) {
-						c_hot_pos += start;
-					}
-					break;
-				case TextAlignment.Justified:
-					var words = caption.ToString ().Split (new string [] { " " }, StringSplitOptions.RemoveEmptyEntries);
-					var wLen = GetWordsLength (words);
-					var space = (Frame.Width - wLen) / (caption.Length - wLen);
-					caption = "";
-					for (int i = 0; i < words.Length; i++) {
-						if (i == words.Length - 1) {
-							caption += new string (' ', Frame.Width - caption.Length - 1);
-							caption += words [i];
-						} else {
-							caption += words [i];
-						}
-						if (i < words.Length - 1) {
-							caption += new string (' ', space);
-						}
-					}
-					if (c_hot_pos > -1) {
-						c_hot_pos += space - 1;
-					}
-					break;
-				}
-			}
+			var caption = GetTextAlignment (shown_text, hot_pos, out int s_hot_pos, TextAlignment);
+			c_hot_pos = s_hot_pos;
 
 
 			Driver.AddStr (caption);
 			Driver.AddStr (caption);
 
 
@@ -255,17 +191,6 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
-		int GetWordsLength (string[] words)
-		{
-			int length = 0;
-
-			for (int i = 0; i < words.Length; i++) {
-				length += words [i].Length;
-			}
-
-			return length;
-		}
-
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void PositionCursor ()
 		public override void PositionCursor ()
 		{
 		{
@@ -274,7 +199,7 @@ namespace Terminal.Gui {
 
 
 		bool CheckKey (KeyEvent key)
 		bool CheckKey (KeyEvent key)
 		{
 		{
-			if (Char.ToUpper ((char)key.KeyValue) == hot_key) {
+			if ((char)key.KeyValue == hot_key) {
 				this.SuperView.SetFocus (this);
 				this.SuperView.SetFocus (this);
 				Clicked?.Invoke ();
 				Clicked?.Invoke ();
 				return true;
 				return true;

+ 0 - 22
Terminal.Gui/Views/Label.cs

@@ -11,28 +11,6 @@ using System.Linq;
 using NStack;
 using NStack;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
-	/// <summary>
-	/// Text alignment enumeration, controls how text is displayed.
-	/// </summary>
-	public enum TextAlignment {
-		/// <summary>
-		/// Aligns the text to the left of the frame.
-		/// </summary>
-		Left, 
-		/// <summary>
-		/// Aligns the text to the right side of the frame.
-		/// </summary>
-		Right, 
-		/// <summary>
-		/// Centers the text in the frame.
-		/// </summary>
-		Centered, 
-		/// <summary>
-		/// Shows the text as justified text in the frame.
-		/// </summary>
-		Justified
-	}
-
 	/// <summary>
 	/// <summary>
 	/// The Label <see cref="View"/> displays a string at a given position and supports multiple lines separted by newline characters.
 	/// The Label <see cref="View"/> displays a string at a given position and supports multiple lines separted by newline characters.
 	/// </summary>
 	/// </summary>

+ 63 - 38
UICatalog/Scenarios/Buttons.cs

@@ -89,7 +89,7 @@ namespace UICatalog {
 			textChanger.Clicked = () => textChanger.Text += "!";
 			textChanger.Clicked = () => textChanger.Text += "!";
 
 
 			Win.Add (button = new Button ("Lets see if this will move as \"Text Changer\" grows") {
 			Win.Add (button = new Button ("Lets see if this will move as \"Text Changer\" grows") {
-				X = Pos.Right(textChanger) + 2,
+				X = Pos.Right (textChanger) + 2,
 				Y = Pos.Y (textChanger),
 				Y = Pos.Y (textChanger),
 			});
 			});
 
 
@@ -105,7 +105,7 @@ namespace UICatalog {
 			var computedFrame = new FrameView ("Computed Layout") {
 			var computedFrame = new FrameView ("Computed Layout") {
 				X = 0,
 				X = 0,
 				Y = Pos.Bottom (removeButton) + 1,
 				Y = Pos.Bottom (removeButton) + 1,
-				Width = Dim.Percent(50),
+				Width = Dim.Percent (50),
 				Height = 5
 				Height = 5
 			};
 			};
 			Win.Add (computedFrame);
 			Win.Add (computedFrame);
@@ -113,7 +113,7 @@ namespace UICatalog {
 			// Demonstrates how changing the View.Frame property can move Views
 			// Demonstrates how changing the View.Frame property can move Views
 			var moveBtn = new Button ("Move This \u263b Button _via Pos") {
 			var moveBtn = new Button ("Move This \u263b Button _via Pos") {
 				X = 0,
 				X = 0,
-				Y = Pos.Center() - 1,
+				Y = Pos.Center () - 1,
 				Width = 30,
 				Width = 30,
 				ColorScheme = Colors.Error,
 				ColorScheme = Colors.Error,
 			};
 			};
@@ -132,14 +132,14 @@ namespace UICatalog {
 			};
 			};
 			sizeBtn.Clicked = () => {
 			sizeBtn.Clicked = () => {
 				sizeBtn.Width = sizeBtn.Frame.Width + 5;
 				sizeBtn.Width = sizeBtn.Frame.Width + 5;
-				computedFrame.LayoutSubviews (); // BUGBUG: This call should not be needed. View.X is not causing relayout correctly
+				//computedFrame.LayoutSubviews (); // FIXED: This call should not be needed. View.X is not causing relayout correctly
 			};
 			};
 			computedFrame.Add (sizeBtn);
 			computedFrame.Add (sizeBtn);
 
 
 			var absoluteFrame = new FrameView ("Absolute Layout") {
 			var absoluteFrame = new FrameView ("Absolute Layout") {
-				X = Pos.Right(computedFrame),
+				X = Pos.Right (computedFrame),
 				Y = Pos.Bottom (removeButton) + 1,
 				Y = Pos.Bottom (removeButton) + 1,
-				Width = Dim.Fill(),
+				Width = Dim.Fill (),
 				Height = 5
 				Height = 5
 			};
 			};
 			Win.Add (absoluteFrame);
 			Win.Add (absoluteFrame);
@@ -154,7 +154,7 @@ namespace UICatalog {
 			absoluteFrame.Add (moveBtnA);
 			absoluteFrame.Add (moveBtnA);
 
 
 			// Demonstrates how changing the View.Frame property can SIZE Views (#583)
 			// Demonstrates how changing the View.Frame property can SIZE Views (#583)
-			var sizeBtnA = new Button (0, 2, "Size This Button via Frame") {
+			var sizeBtnA = new Button (0, 2, " ~  s  gui.cs   master ↑10 = Со_хранить") {
 				ColorScheme = Colors.Error,
 				ColorScheme = Colors.Error,
 			};
 			};
 			sizeBtnA.Clicked = () => {
 			sizeBtnA.Clicked = () => {
@@ -172,34 +172,6 @@ namespace UICatalog {
 				X = 4,
 				X = 4,
 				Y = Pos.Bottom (label) + 1,
 				Y = Pos.Bottom (label) + 1,
 				SelectedItem = 2,
 				SelectedItem = 2,
-				SelectedItemChanged = (args) => {
-					switch (args.SelectedItem) {
-					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 (radioGroup);
 			Win.Add (radioGroup);
 
 
@@ -208,7 +180,9 @@ namespace UICatalog {
 			{
 			{
 				// Remove the '_'
 				// Remove the '_'
 				var i = txt.IndexOf ('_');
 				var i = txt.IndexOf ('_');
-				var start = txt [0, i];
+				ustring start = "";
+				if (i > -1)
+					start = txt [0, i];
 				txt = start + txt [i + 1, txt.Length];
 				txt = start + txt [i + 1, txt.Length];
 
 
 				// Move over one or go to start
 				// Move over one or go to start
@@ -224,15 +198,66 @@ namespace UICatalog {
 				return txt;
 				return txt;
 			}
 			}
 
 
-			var moveHotKeyBtn = new Button ("Click to Change th_is Button's Hotkey") {
+			var mhkb = "Click to Change th_is Button's Hotkey";
+			var moveHotKeyBtn = new Button (mhkb) {
 				X = 2,
 				X = 2,
 				Y = Pos.Bottom (radioGroup) + 1,
 				Y = Pos.Bottom (radioGroup) + 1,
+				Width = mhkb.Length + 10,
 				ColorScheme = Colors.TopLevel,
 				ColorScheme = Colors.TopLevel,
 			};
 			};
 			moveHotKeyBtn.Clicked = () => {
 			moveHotKeyBtn.Clicked = () => {
 				moveHotKeyBtn.Text = MoveHotkey (moveHotKeyBtn.Text);
 				moveHotKeyBtn.Text = MoveHotkey (moveHotKeyBtn.Text);
 			};
 			};
 			Win.Add (moveHotKeyBtn);
 			Win.Add (moveHotKeyBtn);
+
+			var muhkb = " ~  s  gui.cs   master ↑10 = Сохранить";
+			var moveUnicodeHotKeyBtn = new Button (muhkb) {
+				X = Pos.Right (moveHotKeyBtn) + 6,
+				Y = Pos.Bottom (radioGroup) + 1,
+				Width = muhkb.Length + 30,
+				ColorScheme = Colors.TopLevel,
+			};
+			moveUnicodeHotKeyBtn.Clicked = () => {
+				moveUnicodeHotKeyBtn.Text = MoveHotkey (moveUnicodeHotKeyBtn.Text);
+			};
+			Win.Add (moveUnicodeHotKeyBtn);
+
+			radioGroup.SelectedItemChanged += (args) => {
+				switch (args.SelectedItem) {
+				case 0:
+					moveBtn.TextAlignment = TextAlignment.Left;
+					sizeBtn.TextAlignment = TextAlignment.Left;
+					moveBtnA.TextAlignment = TextAlignment.Left;
+					sizeBtnA.TextAlignment = TextAlignment.Left;
+					moveHotKeyBtn.TextAlignment = TextAlignment.Left;
+					moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Left;
+					break;
+				case 1:
+					moveBtn.TextAlignment = TextAlignment.Right;
+					sizeBtn.TextAlignment = TextAlignment.Right;
+					moveBtnA.TextAlignment = TextAlignment.Right;
+					sizeBtnA.TextAlignment = TextAlignment.Right;
+					moveHotKeyBtn.TextAlignment = TextAlignment.Right;
+					moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Right;
+					break;
+				case 2:
+					moveBtn.TextAlignment = TextAlignment.Centered;
+					sizeBtn.TextAlignment = TextAlignment.Centered;
+					moveBtnA.TextAlignment = TextAlignment.Centered;
+					sizeBtnA.TextAlignment = TextAlignment.Centered;
+					moveHotKeyBtn.TextAlignment = TextAlignment.Centered;
+					moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Centered;
+					break;
+				case 3:
+					moveBtn.TextAlignment = TextAlignment.Justified;
+					sizeBtn.TextAlignment = TextAlignment.Justified;
+					moveBtnA.TextAlignment = TextAlignment.Justified;
+					sizeBtnA.TextAlignment = TextAlignment.Justified;
+					moveHotKeyBtn.TextAlignment = TextAlignment.Justified;
+					moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Justified;
+					break;
+				}
+			};
 		}
 		}
 	}
 	}
-}
+}

+ 12 - 12
UnitTests/ApplicationTests.cs

@@ -5,7 +5,7 @@ using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.MockConsole;
+using Console = Terminal.Gui.FakeConsole;
 
 
 // Since Application is a singleton we can't run tests in parallel
 // Since Application is a singleton we can't run tests in parallel
 [assembly: CollectionBehavior (DisableTestParallelization = true)]
 [assembly: CollectionBehavior (DisableTestParallelization = true)]
@@ -13,7 +13,7 @@ using Console = Terminal.Gui.MockConsole;
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	public class ApplicationTests {
 	public class ApplicationTests {
 		[Fact]
 		[Fact]
-		public void TestInitShutdown ()
+		public void Init_Shutdown_Cleans_Up ()
 		{
 		{
 			Assert.Null (Application.Current);
 			Assert.Null (Application.Current);
 			Assert.Null (Application.CurrentView);
 			Assert.Null (Application.CurrentView);
@@ -21,7 +21,7 @@ namespace Terminal.Gui {
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.Driver);
 			Assert.Null (Application.Driver);
 
 
-			Application.Init (new MockDriver ());
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Current);
 			Assert.NotNull (Application.Current);
 			Assert.NotNull (Application.CurrentView);
 			Assert.NotNull (Application.CurrentView);
 			Assert.NotNull (Application.Top);
 			Assert.NotNull (Application.Top);
@@ -41,7 +41,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestNewRunState ()
+		public void RunState_Dispose_Cleans_Up ()
 		{
 		{
 			var rs = new Application.RunState (null);
 			var rs = new Application.RunState (null);
 			Assert.NotNull (rs);
 			Assert.NotNull (rs);
@@ -58,10 +58,10 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestBeginEnd ()
+		public void Begin_End_Cleana_Up ()
 		{
 		{
 			// Setup Mock driver
 			// Setup Mock driver
-			Application.Init (new MockDriver ());
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 
 
 			// Test null Toplevel
 			// Test null Toplevel
@@ -83,10 +83,10 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestRequestStop ()
+		public void RequestStop_Stops ()
 		{
 		{
 			// Setup Mock driver
 			// Setup Mock driver
-			Application.Init (new MockDriver ());
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 
 
 			var top = new Toplevel ();
 			var top = new Toplevel ();
@@ -109,10 +109,10 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestRunningFalse ()
+		public void RunningFalse_Stops ()
 		{
 		{
 			// Setup Mock driver
 			// Setup Mock driver
-			Application.Init (new MockDriver ());
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 
 
 			var top = new Toplevel ();
 			var top = new Toplevel ();
@@ -136,10 +136,10 @@ namespace Terminal.Gui {
 
 
 
 
 		[Fact]
 		[Fact]
-		public void TestKeyUp ()
+		public void KeyUp_Event ()
 		{
 		{
 			// Setup Mock driver
 			// Setup Mock driver
-			Application.Init (new MockDriver ());
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 
 
 			// Setup some fake kepresses (This)
 			// Setup some fake kepresses (This)

+ 9 - 9
UnitTests/ConsoleDriverTests.cs

@@ -3,14 +3,14 @@ using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.MockConsole;
+using Console = Terminal.Gui.FakeConsole;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	public class ConsoleDriverTests {
 	public class ConsoleDriverTests {
 		[Fact]
 		[Fact]
-		public void TestInit ()
+		public void Init_Inits ()
 		{
 		{
-			var driver = new MockDriver ();
+			var driver = new FakeDriver ();
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			Assert.Equal (80, Console.BufferWidth);
 			Assert.Equal (80, Console.BufferWidth);
@@ -23,15 +23,15 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestEnd ()
+		public void End_Cleans_Up ()
 		{
 		{
-			var driver = new MockDriver ();
+			var driver = new FakeDriver ();
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
-			MockConsole.ForegroundColor = ConsoleColor.Red;
+			FakeConsole.ForegroundColor = ConsoleColor.Red;
 			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
 
 
-			MockConsole.BackgroundColor = ConsoleColor.Green;
+			FakeConsole.BackgroundColor = ConsoleColor.Green;
 			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
 			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
 			driver.Move (2, 3);
 			driver.Move (2, 3);
 			Assert.Equal (2, Console.CursorLeft);
 			Assert.Equal (2, Console.CursorLeft);
@@ -45,9 +45,9 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestSetColors ()
+		public void SetColors_Changes_Colors ()
 		{
 		{
-			var driver = new MockDriver ();
+			var driver = new FakeDriver ();
 			driver.Init (() => { });
 			driver.Init (() => { });
 			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
 			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);

+ 0 - 127
UnitTests/DimPosTests.cs

@@ -1,127 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.IO;
-using System.Linq;
-using Terminal.Gui;
-using Xunit;
-
-// Alais Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.MockConsole;
-
-namespace Terminal.Gui {
-	public class DimPosTests {
-		[Fact]
-		public void TestNew ()
-		{
-			var pos = new Pos ();
-			Assert.Equal ("Terminal.Gui.Pos", pos.ToString ());
-		}
-
-		[Fact]
-		public void TestAnchorEnd ()
-		{
-			var pos = Pos.AnchorEnd ();
-			Assert.Equal ("Pos.AnchorEnd(margin=0)", pos.ToString ());
-
-			pos = Pos.AnchorEnd (5);
-			Assert.Equal ("Pos.AnchorEnd(margin=5)", pos.ToString ());
-		}
-
-		[Fact]
-		public void TestAt ()
-		{
-			var pos = Pos.At (0);
-			Assert.Equal ("Pos.Absolute(0)", pos.ToString ());
-
-			pos = Pos.At (5);
-			Assert.Equal ("Pos.Absolute(5)", pos.ToString ());
-
-			//Assert.Throws<ArgumentException> (() => pos = Pos.At (-1));
-		}
-
-		[Fact]
-		public void TestLeft ()
-		{
-			var pos = Pos.Left (null);
-			Assert.Throws<NullReferenceException> (() => pos.ToString ());
-
-			pos = Pos.Left (new View ());
-			Assert.Equal ("Pos.View(side=x, target=View()({X=0,Y=0,Width=0,Height=0})", pos.ToString ());
-
-			pos = Pos.Left (new View (new Rect (1, 2, 3, 4)));
-			Assert.Equal ("Pos.View(side=x, target=View()({X=1,Y=2,Width=3,Height=4})", pos.ToString ());
-		}
-
-		[Fact]
-		public void TestTop ()
-		{
-			var pos = Pos.Top (null);
-			Assert.Throws<NullReferenceException> (() => pos.ToString ());
-
-			pos = Pos.Top (new View ());
-			Assert.Equal ("Pos.View(side=y, target=View()({X=0,Y=0,Width=0,Height=0})", pos.ToString ());
-
-			pos = Pos.Top (new View (new Rect (1, 2, 3, 4)));
-			Assert.Equal ("Pos.View(side=y, target=View()({X=1,Y=2,Width=3,Height=4})", pos.ToString ());
-		}
-
-		[Fact]
-		public void TestRight ()
-		{
-			var pos = Pos.Right (null);
-			Assert.Throws<NullReferenceException> (() => pos.ToString ());
-
-			pos = Pos.Right (new View ());
-			Assert.Equal ("Pos.View(side=right, target=View()({X=0,Y=0,Width=0,Height=0})", pos.ToString ());
-
-			pos = Pos.Right (new View (new Rect (1, 2, 3, 4)));
-			Assert.Equal ("Pos.View(side=right, target=View()({X=1,Y=2,Width=3,Height=4})", pos.ToString ());
-		}
-
-		[Fact]
-		public void TestBottom ()
-		{
-			var pos = Pos.Bottom (null);
-			Assert.Throws<NullReferenceException> (() => pos.ToString ());
-
-			pos = Pos.Bottom (new View ());
-			Assert.Equal ("Pos.View(side=bottom, target=View()({X=0,Y=0,Width=0,Height=0})", pos.ToString ());
-
-			pos = Pos.Bottom (new View (new Rect (1, 2, 3, 4)));
-			Assert.Equal ("Pos.View(side=bottom, target=View()({X=1,Y=2,Width=3,Height=4})", pos.ToString ());
-
-			//Assert.Throws<ArgumentException> (() => pos = Pos.Bottom (new View (new Rect (0, 0, -3, -4))));
-
-		}
-
-		[Fact]
-		public void TestCenter ()
-		{
-			var pos = Pos.Center ();
-			Assert.Equal ("Pos.Center", pos.ToString ());
-		}
-
-		[Fact]
-		public void TestPercent ()
-		{
-			var pos = Pos.Percent (0);
-			Assert.Equal ("Pos.Factor(0)", pos.ToString ());
-
-			pos = Pos.Percent (0.5F);
-			Assert.Equal ("Pos.Factor(0.005)", pos.ToString ());
-
-			pos = Pos.Percent (100);
-			Assert.Equal ("Pos.Factor(1)", pos.ToString ());
-
-			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (-1));
-			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
-			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (100.0001F));
-			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));
-		}
-
-		// TODO: Test operators
-
-		// TODO: Test Dim
-	}
-}

+ 125 - 0
UnitTests/DimTests.cs

@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using Terminal.Gui;
+using Xunit;
+
+// Alais Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui {
+	public class DimTests {
+		[Fact]
+		public void New_Works ()
+		{
+			var dim = new Dim ();
+			Assert.Equal ("Terminal.Gui.Dim", dim.ToString ());
+		}
+
+		[Fact]
+		public void Sized_SetsValue ()
+		{
+			var dim = Dim.Sized (0);
+			Assert.Equal ("Dim.Absolute(0)", dim.ToString ());
+
+			int testVal = 5;
+			dim = Dim.Sized (testVal);
+			Assert.Equal ($"Dim.Absolute({testVal})", dim.ToString ());
+		}
+
+		// TODO: Other Dim.Sized tests (e.g. Equal?)
+
+		[Fact]
+		public void Width_SetsValue ()
+		{
+			var dim = Dim.Width (null);
+			Assert.Throws<NullReferenceException> (() => dim.ToString ());
+
+			var testVal = Rect.Empty;
+			testVal = Rect.Empty;
+			dim = Dim.Width (new View (testVal));
+			Assert.Equal ($"DimView(side=Width, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", dim.ToString ());
+
+			testVal = new Rect (1, 2, 3, 4);
+			dim = Dim.Width (new View (testVal));
+			Assert.Equal ($"DimView(side=Width, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", dim.ToString ());
+		}
+
+		// TODO: Other Dim.Width tests (e.g. Equal?)
+
+		[Fact]
+		public void Height_SetsValue ()
+		{
+			var dim = Dim.Height (null);
+			Assert.Throws<NullReferenceException> (() => dim.ToString ());
+
+			var testVal = Rect.Empty;
+			testVal = Rect.Empty;
+			dim = Dim.Height (new View (testVal));
+			Assert.Equal ($"DimView(side=Height, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", dim.ToString ());
+
+			testVal = new Rect (1, 2, 3, 4);
+			dim = Dim.Height (new View (testVal));
+			Assert.Equal ($"DimView(side=Height, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", dim.ToString ());
+		}
+
+		// TODO: Other Dim.Height tests (e.g. Equal?)
+
+		[Fact]
+		public void Fill_SetsValue ()
+		{
+			var testMargin = 0;
+			var dim = Dim.Fill ();
+			Assert.Equal ($"Dim.Fill(margin={testMargin})", dim.ToString());
+
+			testMargin = 0;
+			dim = Dim.Fill (testMargin);
+			Assert.Equal ($"Dim.Fill(margin={testMargin})", dim.ToString ());
+
+			testMargin = 5;
+			dim = Dim.Fill (testMargin);
+			Assert.Equal ($"Dim.Fill(margin={testMargin})", dim.ToString ());
+		}
+
+
+		[Fact]
+		public void Fill_Equal()
+		{
+			var margin1 = 0;
+			var margin2 = 0;
+			var dim1 = Dim.Fill (margin1);
+			var dim2 = Dim.Fill (margin2);
+			Assert.Equal (dim1, dim2);
+		}
+
+		[Fact]
+		public void Percent_SetsValue ()
+		{
+			float f = 0;
+			var dim = Dim.Percent (f);
+			Assert.Equal ($"Dim.Factor({f/100:0.###})", dim.ToString ());
+			f = 0.5F;
+			dim = Dim.Percent (f);
+			Assert.Equal ($"Dim.Factor({f/100:0.###})", dim.ToString ());
+			f = 100;
+			dim = Dim.Percent (f);
+			Assert.Equal ($"Dim.Factor({f/100:0.###})", dim.ToString ());
+		}
+
+		// TODO: Other Dim.Percent tests (e.g. Equal?)
+
+		[Fact]
+		public void Percent_ThrowsOnIvalid()
+		{
+			var dim = Dim.Percent (0);
+			Assert.Throws<ArgumentException> (() => dim = Dim.Percent (-1));
+			Assert.Throws<ArgumentException> (() => dim = Dim.Percent (101));
+			Assert.Throws<ArgumentException> (() => dim = Dim.Percent (100.0001F));
+			Assert.Throws<ArgumentException> (() => dim = Dim.Percent (1000001));
+		}
+
+		// TODO: Test operators
+	}
+}

+ 192 - 0
UnitTests/PosTests.cs

@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using Terminal.Gui;
+using Xunit;
+
+// Alais Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui {
+	public class PosTests {
+		[Fact]
+		public void New_Works ()
+		{
+			var pos = new Pos ();
+			Assert.Equal ("Terminal.Gui.Pos", pos.ToString ());
+		}
+
+		[Fact]
+		public void AnchorEnd_SetsValue ()
+		{
+			var n = 0;
+			var pos = Pos.AnchorEnd ();
+			Assert.Equal ($"Pos.AnchorEnd(margin={n})", pos.ToString ());
+
+			n = 5;
+			pos = Pos.AnchorEnd (n);
+			Assert.Equal ($"Pos.AnchorEnd(margin={n})", pos.ToString ());
+		}
+
+		[Fact]
+		public void AnchorEnd_Equal ()
+		{
+			var n1 = 0;
+			var n2 = 0;
+
+			var pos1 = Pos.AnchorEnd (n1);
+			var pos2 = Pos.AnchorEnd (n2);
+			Assert.Equal (pos1, pos2);
+
+			// Test inequality
+			n2 = 5;
+			pos2 = Pos.AnchorEnd (n2);
+			Assert.NotEqual (pos1, pos2);
+		}
+
+		[Fact]
+		public void At_SetsValue ()
+		{
+			var pos = Pos.At (0);
+			Assert.Equal ("Pos.Absolute(0)", pos.ToString ());
+
+			pos = Pos.At (5);
+			Assert.Equal ("Pos.Absolute(5)", pos.ToString ());
+
+			//Assert.Throws<ArgumentException> (() => pos = Pos.At (-1));
+		}
+
+		[Fact]
+		public void At_Equal ()
+		{
+			var n1 = 0;
+			var n2 = 0;
+
+			var pos1 = Pos.At (n1);
+			var pos2 = Pos.At (n2);
+			// BUGBUG: Pos should implement equality and this should change to Equal
+			Assert.NotEqual (pos1, pos2);
+		}
+
+		[Fact]
+		public void Left_SetsValue ()
+		{
+			var pos = Pos.Left (null);
+			Assert.Throws<NullReferenceException> (() => pos.ToString ());
+
+			var testVal = Rect.Empty;
+			pos = Pos.Left (new View ());
+			Assert.Equal ($"Pos.View(side=x, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			pos = Pos.Left (new View (testVal));
+			Assert.Equal ($"Pos.View(side=x, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			testVal = new Rect (1, 2, 3, 4);
+			pos = Pos.Left (new View (testVal));
+			Assert.Equal ($"Pos.View(side=x, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+		}
+
+		// TODO: Test Left, Top, Right bottom Equal
+
+		[Fact]
+		public void Top_SetsValue ()
+		{
+			var pos = Pos.Top (null);
+			Assert.Throws<NullReferenceException> (() => pos.ToString ());
+
+			var testVal = Rect.Empty;
+			pos = Pos.Top (new View ());
+			Assert.Equal ($"Pos.View(side=y, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			testVal = new Rect (1, 2, 3, 4);
+			pos = Pos.Top (new View (testVal));
+			Assert.Equal ($"Pos.View(side=y, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+		}
+
+		[Fact]
+		public void Right_SetsValue ()
+		{
+			var pos = Pos.Right (null);
+			Assert.Throws<NullReferenceException> (() => pos.ToString ());
+
+			var testVal = Rect.Empty;
+			pos = Pos.Right (new View ());
+			Assert.Equal ($"Pos.View(side=right, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			testVal = Rect.Empty;
+			pos = Pos.Right (new View (testVal));
+			Assert.Equal ($"Pos.View(side=right, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			testVal = new Rect (1, 2, 3, 4);
+			pos = Pos.Right (new View (testVal));
+			Assert.Equal ($"Pos.View(side=right, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+		}
+
+		[Fact]
+		public void Bottom_SetsValue ()
+		{
+			var pos = Pos.Bottom (null);
+			Assert.Throws<NullReferenceException> (() => pos.ToString ());
+
+			var testVal = Rect.Empty;
+			pos = Pos.Bottom (new View ());
+			Assert.Equal ($"Pos.View(side=bottom, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			testVal = Rect.Empty;
+			pos = Pos.Bottom (new View (testVal));
+			Assert.Equal ($"Pos.View(side=bottom, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			testVal = new Rect (1, 2, 3, 4);
+			pos = Pos.Bottom (new View (testVal));
+			Assert.Equal ($"Pos.View(side=bottom, target=View()({{X={testVal.X},Y={testVal.Y},Width={testVal.Width},Height={testVal.Height}}}))", pos.ToString ());
+
+			//Assert.Throws<ArgumentException> (() => pos = Pos.Bottom (new View (new Rect (0, 0, -3, -4))));
+		}
+
+		[Fact]
+		public void Center_SetsValue ()
+		{
+			var pos = Pos.Center ();
+			Assert.Equal ("Pos.Center", pos.ToString ());
+		}
+
+		[Fact]
+		public void Percent_SetsValue ()
+		{
+			float f = 0;
+			var pos = Pos.Percent (f);
+			Assert.Equal ($"Pos.Factor({f / 100:0.###})", pos.ToString ());
+			f = 0.5F;
+			pos = Pos.Percent (f);
+			Assert.Equal ($"Pos.Factor({f / 100:0.###})", pos.ToString ());
+			f = 100;
+			pos = Pos.Percent (f);
+			Assert.Equal ($"Pos.Factor({f / 100:0.###})", pos.ToString ());
+		}
+
+		[Fact]
+		public void Percent_Equal ()
+		{
+			var n1 = 0;
+			var n2 = 0;
+			var pos1 = Pos.Percent (n1);
+			var pos2 = Pos.Percent (n2);
+			// BUGBUG: Pos.Percent should support equality 
+			Assert.NotEqual (pos1, pos2);
+		}
+
+		[Fact]
+		public void Percent_ThrowsOnIvalid ()
+		{
+			var pos = Pos.Percent (0);
+			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (-1));
+			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
+			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (100.0001F));
+			Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));
+		}
+
+		// TODO: Test operators
+	}
+}

+ 3 - 3
UnitTests/ResponderTests.cs

@@ -5,12 +5,12 @@ using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.MockConsole;
+using Console = Terminal.Gui.FakeConsole;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	public class ResponderTests {
 	public class ResponderTests {
 		[Fact]
 		[Fact]
-		public void TestNew ()
+		public void New_Initializes ()
 		{
 		{
 			var r = new Responder ();
 			var r = new Responder ();
 			Assert.NotNull (r);
 			Assert.NotNull (r);
@@ -20,7 +20,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestMethods ()
+		public void New_Methods_Return_False ()
 		{
 		{
 			var r = new Responder ();
 			var r = new Responder ();
 
 

+ 3 - 3
UnitTests/ViewTests.cs

@@ -7,12 +7,12 @@ using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.MockConsole;
+using Console = Terminal.Gui.FakeConsole;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	public class ViewTests {
 	public class ViewTests {
 		[Fact]
 		[Fact]
-		public void TestNew ()
+		public void New_Initializes ()
 		{
 		{
 			// Parameterless
 			// Parameterless
 			var r = new View ();
 			var r = new View ();
@@ -90,7 +90,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void TestMethods ()
+		public void New_Methods_Return_False ()
 		{
 		{
 			var r = new View ();
 			var r = new View ();