Browse Source

Merge branch 'main' of tig:migueldeicaza/gui.cs

Charlie Kindel 4 years ago
parent
commit
0784bc27dc

+ 1 - 1
ReactiveExample/ReactiveExample.csproj

@@ -6,7 +6,7 @@
     <ItemGroup>
         <PackageReference Include="Pharmacist.MsBuild" Version="2.0.8" PrivateAssets="all" />
         <PackageReference Include="Pharmacist.Common" Version="2.0.8" />
-        <PackageReference Include="Terminal.Gui" Version="1.0.0-pre.*" />
+        <PackageReference Include="Terminal.Gui" Version="1.0.0.*" />
         <PackageReference Include="ReactiveUI.Fody" Version="13.2.18" />
         <PackageReference Include="ReactiveUI" Version="13.2.18" />
     </ItemGroup>

+ 13 - 7
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -74,10 +74,10 @@ namespace Terminal.Gui {
 		public override void Refresh ()
 		{
 			Curses.refresh ();
-			if (Curses.CheckWinChange ()) {
-				Clip = new Rect (0, 0, Cols, Rows);
-				TerminalResized?.Invoke ();
-			}
+			//if (Curses.CheckWinChange ()) {
+			//	Clip = new Rect (0, 0, Cols, Rows);
+			//	TerminalResized?.Invoke ();
+			//}
 		}
 
 		public override void UpdateCursor () => Refresh ();
@@ -97,13 +97,13 @@ namespace Terminal.Gui {
 			//Console.Out.Write ("\x1b[2J");
 			//Console.Out.Flush ();
 
-			// Reports current cursor line and column.
+			// Set top and bottom lines of a window.
 			//Console.Out.Write ("\x1b[1;25r");
 			//Console.Out.Flush ();
 
 			//Set cursor key to cursor.
-			Console.Out.Write("\x1b[?1l");
-			Console.Out.Flush();
+			Console.Out.Write ("\x1b[?1l");
+			Console.Out.Flush ();
 		}
 
 		public override void UpdateScreen () => window.redrawwin ();
@@ -695,6 +695,12 @@ namespace Terminal.Gui {
 				return true;
 			});
 
+			mLoop.WinChanged += () => {
+				if (Curses.CheckWinChange ()) {
+					Clip = new Rect (0, 0, Cols, Rows);
+					TerminalResized?.Invoke ();
+				}
+			};
 		}
 
 		Curses.Event oldMouseEvents, reportableMouseEvents;

+ 20 - 7
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -38,6 +38,8 @@ namespace Terminal.Gui {
 	/// can watch file descriptors using the AddWatch methods.
 	/// </remarks>
 	internal class UnixMainLoop : IMainLoopDriver {
+		public const int KEY_RESIZE = unchecked((int)0xffffffffffffffff);
+
 		[StructLayout (LayoutKind.Sequential)]
 		struct Pollfd {
 			public int fd;
@@ -84,10 +86,10 @@ namespace Terminal.Gui {
 		Dictionary<int, Watch> descriptorWatchers = new Dictionary<int, Watch> ();
 
 		[DllImport ("libc")]
-		extern static int poll ([In, Out]Pollfd [] ufds, uint nfds, int timeout);
+		extern static int poll ([In, Out] Pollfd [] ufds, uint nfds, int timeout);
 
 		[DllImport ("libc")]
-		extern static int pipe ([In, Out]int [] pipes);
+		extern static int pipe ([In, Out] int [] pipes);
 
 		[DllImport ("libc")]
 		extern static int read (int fd, IntPtr buf, IntPtr n);
@@ -100,13 +102,17 @@ namespace Terminal.Gui {
 		int [] wakeupPipes = new int [2];
 		static IntPtr ignore = Marshal.AllocHGlobal (1);
 		MainLoop mainLoop;
+		bool winChanged;
+
+		public Action WinChanged;
 
 		void IMainLoopDriver.Wakeup ()
 		{
-			write (wakeupPipes [1], ignore, (IntPtr) 1);
+			write (wakeupPipes [1], ignore, (IntPtr)1);
 		}
 
-		void IMainLoopDriver.Setup (MainLoop mainLoop) {
+		void IMainLoopDriver.Setup (MainLoop mainLoop)
+		{
 			this.mainLoop = mainLoop;
 			pipe (wakeupPipes);
 			AddWatch (wakeupPipes [0], Condition.PollIn, ml => {
@@ -143,7 +149,7 @@ namespace Terminal.Gui {
 		public object AddWatch (int fileDescriptor, Condition condition, Func<MainLoop, bool> callback)
 		{
 			if (callback == null)
-				throw new ArgumentNullException (nameof(callback));
+				throw new ArgumentNullException (nameof (callback));
 
 			var watch = new Watch () { Condition = condition, Callback = callback, File = fileDescriptor };
 			descriptorWatchers [fileDescriptor] = watch;
@@ -175,8 +181,11 @@ namespace Terminal.Gui {
 			UpdatePollMap ();
 
 			var n = poll (pollmap, (uint)pollmap.Length, pollTimeout);
-			
-			return n > 0 || CheckTimers (wait, out pollTimeout);
+
+			if (n == KEY_RESIZE) {
+				winChanged = true;
+			}
+			return n >= KEY_RESIZE || CheckTimers (wait, out pollTimeout);
 		}
 
 		bool CheckTimers (bool wait, out int pollTimeout)
@@ -204,6 +213,10 @@ namespace Terminal.Gui {
 
 		void IMainLoopDriver.MainIteration ()
 		{
+			if (winChanged) {
+				winChanged = false;
+				WinChanged?.Invoke ();
+			}
 			if (pollmap != null) {
 				foreach (var p in pollmap) {
 					Watch watch;

+ 76 - 27
Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs

@@ -48,6 +48,14 @@ namespace Unix.Terminal {
 #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
 
 	public partial class Curses {
+		[StructLayout (LayoutKind.Sequential)]
+		public struct winsize {
+			public ushort ws_row;
+			public ushort ws_col;
+			public ushort ws_xpixel;   /* unused */
+			public ushort ws_ypixel;   /* unused */
+		};
+
 		[StructLayout (LayoutKind.Sequential)]
 		public struct MouseEvent {
 			public short ID;
@@ -66,8 +74,11 @@ namespace Unix.Terminal {
 		static NativeMethods methods;
 
 
-		[DllImport("libc")]
-		public extern static int setlocale(int cate, [MarshalAs(UnmanagedType.LPStr)] string locale);
+		[DllImport ("libc")]
+		public extern static int setlocale (int cate, [MarshalAs (UnmanagedType.LPStr)] string locale);
+
+		[DllImport ("libc")]
+		public extern static int ioctl (int fd, int cmd, out winsize argp);
 
 		static void LoadMethods ()
 		{
@@ -86,18 +97,18 @@ namespace Unix.Terminal {
 			lines_ptr = get_ptr ("LINES");
 			cols_ptr = get_ptr ("COLS");
 		}
-		
+
 		static public Window initscr ()
 		{
-			setlocale(LC_ALL, "");
+			setlocale (LC_ALL, "");
 			FindNCurses ();
-			
+
 			main_window = new Window (methods.initscr ());
 			try {
 				console_sharp_get_dims (out lines, out cols);
-			} catch (DllNotFoundException){
+			} catch (DllNotFoundException) {
 				endwin ();
-				Console.Error.WriteLine ("Unable to find the @MONO_CURSES@ native library\n" + 
+				Console.Error.WriteLine ("Unable to find the @MONO_CURSES@ native library\n" +
 							 "this is different than the managed mono-curses.dll\n\n" +
 							 "Typically you need to install to a LD_LIBRARY_PATH directory\n" +
 							 "or DYLD_LIBRARY_PATH directory or run /sbin/ldconfig");
@@ -106,7 +117,7 @@ namespace Unix.Terminal {
 			return main_window;
 		}
 
-		public static int Lines {	
+		public static int Lines {
 			get {
 				return lines;
 			}
@@ -125,16 +136,22 @@ namespace Unix.Terminal {
 		public static bool CheckWinChange ()
 		{
 			int l, c;
-			
+
 			console_sharp_get_dims (out l, out c);
-			if (l != lines || c != cols){
+
+			if (l == 1 || l != lines || c != cols) {
 				lines = l;
 				cols = c;
+				if (l <= 0 || c <= 0) {
+					Console.Out.Write ($"\x1b[8;50;{c}t");
+					Console.Out.Flush ();
+					return false;
+				}
 				return true;
 			}
 			return false;
 		}
-		
+
 		public static int addstr (string format, params object [] args)
 		{
 			var s = string.Format (format, args);
@@ -151,9 +168,9 @@ namespace Unix.Terminal {
 		//
 		public static int addch (int ch)
 		{
-			if (ch < 127 || ch > 0xffff )
+			if (ch < 127 || ch > 0xffff)
 				return methods.addch (ch);
-			char c = (char) ch;
+			char c = (char)ch;
 			return addwstr (new String (c, 1));
 		}
 
@@ -167,7 +184,7 @@ namespace Unix.Terminal {
 				throw new Exception ("Could not load the key " + key);
 			return ptr;
 		}
-		
+
 		internal static IntPtr read_static_ptr (string key)
 		{
 			var ptr = get_ptr (key);
@@ -175,8 +192,7 @@ namespace Unix.Terminal {
 		}
 
 		internal static IntPtr console_sharp_get_stdscr () => stdscr;
-		
-		
+
 		internal static IntPtr console_sharp_get_curscr ()
 		{
 			return Marshal.ReadIntPtr (curscr_ptr);
@@ -184,15 +200,36 @@ namespace Unix.Terminal {
 
 		internal static void console_sharp_get_dims (out int lines, out int cols)
 		{
-			lines = Marshal.ReadInt32 (lines_ptr);
-			cols = Marshal.ReadInt32 (cols_ptr);
+			//lines = Marshal.ReadInt32 (lines_ptr);
+			//cols = Marshal.ReadInt32 (cols_ptr);
+
+			int cmd;
+			if (UnmanagedLibrary.IsMacOSPlatform) {
+				cmd = TIOCGWINSZ_MAC;
+			} else {
+				cmd = TIOCGWINSZ;
+			}
+
+			if (ioctl (1, cmd, out winsize ws) == 0) {
+				lines = ws.ws_row;
+				cols = ws.ws_col;
+
+				if (lines == Lines && cols == Cols) {
+					return;
+				}
+
+				resizeterm (lines, cols);
+			} else {
+				lines = Lines;
+				cols = Cols;
+			}
 		}
 
 		public static Event mousemask (Event newmask, out Event oldmask)
 		{
 			IntPtr e;
-			var ret = (Event) (methods.mousemask ((IntPtr) newmask, out e));
-			oldmask = (Event) e;
+			var ret = (Event)(methods.mousemask ((IntPtr)newmask, out e));
+			oldmask = (Event)e;
 			return ret;
 		}
 
@@ -210,7 +247,7 @@ namespace Unix.Terminal {
 		public static bool HasColors => methods.has_colors ();
 		public static int InitColorPair (short pair, short foreground, short background) => methods.init_pair (pair, foreground, background);
 		public static int UseDefaultColors () => methods.use_default_colors ();
-		public static int ColorPairs => methods.COLOR_PAIRS();
+		public static int ColorPairs => methods.COLOR_PAIRS ();
 
 		//
 		// The proxy methods to call into each version
@@ -240,11 +277,11 @@ namespace Unix.Terminal {
 		static public int leaveok (IntPtr win, bool bf) => methods.leaveok (win, bf);
 		static public int wsetscrreg (IntPtr win, int top, int bot) => methods.wsetscrreg (win, top, bot);
 		static public int scrollok (IntPtr win, bool bf) => methods.scrollok (win, bf);
-		static public int nl() => methods.nl();
-		static public int nonl() => methods.nonl();
+		static public int nl () => methods.nl ();
+		static public int nonl () => methods.nonl ();
 		static public int setscrreg (int top, int bot) => methods.setscrreg (top, bot);
 		static public int refresh () => methods.refresh ();
-		static public int doupdate() => methods.doupdate();
+		static public int doupdate () => methods.doupdate ();
 		static public int wrefresh (IntPtr win) => methods.wrefresh (win);
 		static public int redrawwin (IntPtr win) => methods.redrawwin (win);
 		//static public int wredrawwin (IntPtr win, int beg_line, int num_lines) => methods.wredrawwin (win, beg_line, num_lines);
@@ -266,10 +303,13 @@ namespace Unix.Terminal {
 		static public int start_color () => methods.start_color ();
 		static public int init_pair (short pair, short f, short b) => methods.init_pair (pair, f, b);
 		static public int use_default_colors () => methods.use_default_colors ();
-		static public int COLOR_PAIRS() => methods.COLOR_PAIRS();
+		static public int COLOR_PAIRS () => methods.COLOR_PAIRS ();
 		static public uint getmouse (out MouseEvent ev) => methods.getmouse (out ev);
 		static public uint ungetmouse (ref MouseEvent ev) => methods.ungetmouse (ref ev);
 		static public int mouseinterval (int interval) => methods.mouseinterval (interval);
+		static public bool is_term_resized (int lines, int columns) => methods.is_term_resized (lines, columns);
+		static public int resize_term (int lines, int columns) => methods.resize_term (lines, columns);
+		static public int resizeterm (int lines, int columns) => methods.resizeterm (lines, columns);
 	}
 
 #pragma warning disable RCS1102 // Make class static.
@@ -313,7 +353,7 @@ namespace Unix.Terminal {
 		public delegate int move (int line, int col);
 		public delegate int curs_set (int visibility);
 		public delegate int addch (int ch);
-		public delegate int addwstr([MarshalAs(UnmanagedType.LPWStr)]string s);
+		public delegate int addwstr ([MarshalAs (UnmanagedType.LPWStr)] string s);
 		public delegate int wmove (IntPtr win, int line, int col);
 		public delegate int waddch (IntPtr win, int ch);
 		public delegate int attron (int attrs);
@@ -332,6 +372,9 @@ namespace Unix.Terminal {
 		public delegate uint ungetmouse (ref Curses.MouseEvent ev);
 		public delegate int mouseinterval (int interval);
 		public delegate IntPtr mousemask (IntPtr newmask, out IntPtr oldMask);
+		public delegate bool is_term_resized (int lines, int columns);
+		public delegate int resize_term (int lines, int columns);
+		public delegate int resizeterm (int lines, int columns);
 	}
 
 	internal class NativeMethods {
@@ -392,6 +435,9 @@ namespace Unix.Terminal {
 		public readonly Delegates.ungetmouse ungetmouse;
 		public readonly Delegates.mouseinterval mouseinterval;
 		public readonly Delegates.mousemask mousemask;
+		public readonly Delegates.is_term_resized is_term_resized;
+		public readonly Delegates.resize_term resize_term;
+		public readonly Delegates.resizeterm resizeterm;
 		public UnmanagedLibrary UnmanagedLibrary;
 
 		public NativeMethods (UnmanagedLibrary lib)
@@ -434,7 +480,7 @@ namespace Unix.Terminal {
 			wnoutrefresh = lib.GetNativeMethodDelegate<Delegates.wnoutrefresh> ("wnoutrefresh");
 			move = lib.GetNativeMethodDelegate<Delegates.move> ("move");
 			curs_set = lib.GetNativeMethodDelegate<Delegates.curs_set> ("curs_set");
-			addch = lib.GetNativeMethodDelegate<Delegates.addch>("addch");
+			addch = lib.GetNativeMethodDelegate<Delegates.addch> ("addch");
 			addwstr = lib.GetNativeMethodDelegate<Delegates.addwstr> ("addwstr");
 			wmove = lib.GetNativeMethodDelegate<Delegates.wmove> ("wmove");
 			waddch = lib.GetNativeMethodDelegate<Delegates.waddch> ("waddch");
@@ -454,6 +500,9 @@ namespace Unix.Terminal {
 			ungetmouse = lib.GetNativeMethodDelegate<Delegates.ungetmouse> ("ungetmouse");
 			mouseinterval = lib.GetNativeMethodDelegate<Delegates.mouseinterval> ("mouseinterval");
 			mousemask = lib.GetNativeMethodDelegate<Delegates.mousemask> ("mousemask");
+			is_term_resized = lib.GetNativeMethodDelegate<Delegates.is_term_resized> ("is_term_resized");
+			resize_term = lib.GetNativeMethodDelegate<Delegates.resize_term> ("resize_term");
+			resizeterm = lib.GetNativeMethodDelegate<Delegates.resizeterm> ("resizeterm");
 		}
 	}
 #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member

+ 3 - 1
Terminal.Gui/ConsoleDrivers/CursesDriver/constants.cs

@@ -53,6 +53,9 @@ namespace Unix.Terminal {
 		public const int COLOR_WHITE = unchecked((int)0x7);
 		public const int KEY_CODE_YES = unchecked((int)0x100);
 		public const int KEY_CODE_SEQ = unchecked((int)0x5b);
+		public const int ERR = unchecked((int)0xffffffff);
+		public const int TIOCGWINSZ  = unchecked((int)0x5413);
+		public const int TIOCGWINSZ_MAC  = unchecked((int)0x40087468);
 
 		[Flags]
 		public enum Event : long {
@@ -93,7 +96,6 @@ namespace Unix.Terminal {
 		public const int DownEnd = unchecked((int)0x0);
 		public const int Home = unchecked((int)0x0);
 #endif
-		public const int ERR = unchecked((int)0xffffffff);
 		public const int KeyBackspace = unchecked((int)0x107);
 		public const int KeyUp = unchecked((int)0x103);
 		public const int KeyDown = unchecked((int)0x102);

+ 0 - 1
Terminal.Gui/Core/Application.cs

@@ -550,7 +550,6 @@ namespace Terminal.Gui {
 			Driver?.End ();
 			Driver = null;
 			Iteration = null;
-			UseSystemConsole = false;
 			RootMouseEvent = null;
 			Resized = null;
 			_initialized = false;

+ 89 - 29
Terminal.Gui/Core/TextFormatter.cs

@@ -68,35 +68,43 @@ namespace Terminal.Gui {
 	/// </summary>
 	public enum TextDirection {
 		/// <summary>
-		/// Normal Horizontal
+		/// Normal horizontal direction.
+		/// <code>HELLO<br/>WORLD</code>
 		/// </summary>
 		LeftRight_TopBottom,
 		/// <summary>
-		/// Normal Vertical
+		/// Normal vertical direction.
+		/// <code>H W<br/>E O<br/>L R<br/>L L<br/>O D</code>
 		/// </summary>
 		TopBottom_LeftRight,
 		/// <summary>
-		/// 
+		/// This is a horizontal direction. <br/> RTL
+		/// <code>OLLEH<br/>DLROW</code>
 		/// </summary>
 		RightLeft_TopBottom,
 		/// <summary>
-		/// 
+		/// This is a vertical direction.
+		/// <code>W H<br/>O E<br/>R L<br/>L L<br/>D O</code>
 		/// </summary>
 		TopBottom_RightLeft,
 		/// <summary>
-		/// 
+		/// This is a horizontal direction.
+		/// <code>WORLD<br/>HELLO</code>
 		/// </summary>
 		LeftRight_BottomTop,
 		/// <summary>
-		/// 
+		/// This is a vertical direction.
+		/// <code>O D<br/>L L<br/>L R<br/>E O<br/>H W</code>
 		/// </summary>
 		BottomTop_LeftRight,
 		/// <summary>
-		/// 
+		/// This is a horizontal direction.
+		/// <code>DLROW<br/>OLLEH</code>
 		/// </summary>
 		RightLeft_BottomTop,
 		/// <summary>
-		/// 
+		/// This is a vertical direction.
+		/// <code>D O<br/>L L<br/>R L<br/>O E<br/>W H</code>
 		/// </summary>
 		BottomTop_RightLeft
 	}
@@ -133,6 +141,14 @@ namespace Terminal.Gui {
 			}
 		}
 
+		/// <summary>
+		/// Used by <see cref="Text"/> to resize the view's <see cref="View.Bounds"/> with the <see cref="Size"/>.
+		/// Setting <see cref="AutoSize"/> to true only work if the <see cref="View.Width"/> and <see cref="View.Height"/> are null or
+		///   <see cref="LayoutStyle.Absolute"/> values and doesn't work with <see cref="LayoutStyle.Computed"/> layout,
+		///   to avoid breaking the <see cref="Pos"/> and <see cref="Dim"/> settings.
+		/// </summary>
+		public bool AutoSize { get; set; }
+
 		// TODO: Add Vertical Text Alignment
 		/// <summary>
 		/// Controls the horizontal text-alignment property. 
@@ -298,8 +314,14 @@ namespace Terminal.Gui {
 
 					if (IsVerticalDirection (textDirection)) {
 						lines = Format (shown_text, Size.Height, textVerticalAlignment == VerticalTextAlignment.Justified, Size.Width > 1);
+						if (!AutoSize && lines.Count > Size.Width) {
+							lines.RemoveRange (Size.Width, lines.Count - Size.Width);
+						}
 					} else {
 						lines = Format (shown_text, Size.Width, textAlignment == TextAlignment.Justified, Size.Height > 1);
+						if (!AutoSize && lines.Count > Size.Height) {
+							lines.RemoveRange (Size.Height, lines.Count - Size.Height);
+						}
 					}
 
 					NeedsFormat = false;
@@ -667,40 +689,77 @@ namespace Terminal.Gui {
 		/// <param name="x">The x location of the rectangle</param>
 		/// <param name="y">The y location of the rectangle</param>
 		/// <param name="text">The text to measure</param>
+		/// <param name="direction">The text direction.</param>
 		/// <returns></returns>
-		public static Rect CalcRect (int x, int y, ustring text)
+		public static Rect CalcRect (int x, int y, ustring text, TextDirection direction = TextDirection.LeftRight_TopBottom)
 		{
 			if (ustring.IsNullOrEmpty (text)) {
 				return new Rect (new Point (x, y), Size.Empty);
 			}
 
-			int mw = 0;
-			int ml = 1;
+			int w, h;
 
-			int cols = 0;
-			foreach (var rune in text) {
-				if (rune == '\n') {
-					ml++;
-					if (cols > mw) {
-						mw = cols;
+			if (IsHorizontalDirection (direction)) {
+				int mw = 0;
+				int ml = 1;
+
+				int cols = 0;
+				foreach (var rune in text) {
+					if (rune == '\n') {
+						ml++;
+						if (cols > mw) {
+							mw = cols;
+						}
+						cols = 0;
+					} else {
+						if (rune != '\r') {
+							cols++;
+							var rw = Rune.ColumnWidth (rune);
+							if (rw > 0) {
+								rw--;
+							}
+							cols += rw;
+						}
 					}
-					cols = 0;
-				} else {
-					if (rune != '\r') {
-						cols++;
-						var rw = Rune.ColumnWidth (rune);
-						if (rw > 0) {
-							rw--;
+				}
+				if (cols > mw) {
+					mw = cols;
+				}
+				w = mw;
+				h = ml;
+			} else {
+				int vw = 0;
+				int vh = 0;
+
+				int rows = 0;
+				foreach (var rune in text) {
+					if (rune == '\n') {
+						vw++;
+						if (rows > vh) {
+							vh = rows;
+						}
+						rows = 0;
+					} else {
+						if (rune != '\r') {
+							rows++;
+							var rw = Rune.ColumnWidth (rune);
+							if (rw < 0) {
+								rw++;
+							}
+							if (rw > vw) {
+								vw = rw;
+							}
 						}
-						cols += rw;
 					}
 				}
-			}
-			if (cols > mw) {
-				mw = cols;
+				if (rows > vh) {
+					vh = rows;
+				}
+				w = vw;
+				h = vh;
 			}
 
-			return new Rect (x, y, mw, ml);
+			return new Rect (x, y, w, h);
 		}
 
 		/// <summary>
@@ -924,6 +983,7 @@ namespace Terminal.Gui {
 				var current = start;
 				for (var idx = start; idx < start + size; idx++) {
 					if (idx < 0) {
+						current++;
 						continue;
 					}
 					var rune = (Rune)' ';

+ 72 - 27
Terminal.Gui/Core/View.cs

@@ -478,6 +478,10 @@ namespace Terminal.Gui {
 
 				x = value;
 				SetNeedsLayout ();
+				if (x is Pos.PosAbsolute) {
+					frame = new Rect (x.Anchor (0), frame.Y, frame.Width, frame.Height);
+				}
+				textFormatter.Size = frame.Size;
 				SetNeedsDisplay (frame);
 			}
 		}
@@ -498,6 +502,10 @@ namespace Terminal.Gui {
 
 				y = value;
 				SetNeedsLayout ();
+				if (y is Pos.PosAbsolute) {
+					frame = new Rect (frame.X, y.Anchor (0), frame.Width, frame.Height);
+				}
+				textFormatter.Size = frame.Size;
 				SetNeedsDisplay (frame);
 			}
 		}
@@ -520,6 +528,10 @@ namespace Terminal.Gui {
 
 				width = value;
 				SetNeedsLayout ();
+				if (width is Dim.DimAbsolute) {
+					frame = new Rect (frame.X, frame.Y, width.Anchor (0), frame.Height);
+				}
+				textFormatter.Size = frame.Size;
 				SetNeedsDisplay (frame);
 			}
 		}
@@ -538,6 +550,10 @@ namespace Terminal.Gui {
 
 				height = value;
 				SetNeedsLayout ();
+				if (height is Dim.DimAbsolute) {
+					frame = new Rect (frame.X, frame.Y, frame.Width, height.Anchor (0));
+				}
+				textFormatter.Size = frame.Size;
 				SetNeedsDisplay (frame);
 			}
 		}
@@ -572,7 +588,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public View (Rect frame)
 		{
-			Initialize (ustring.Empty, frame, LayoutStyle.Absolute);
+			Initialize (ustring.Empty, frame, LayoutStyle.Absolute, TextDirection.LeftRight_TopBottom);
 		}
 
 		/// <summary>
@@ -593,7 +609,7 @@ namespace Terminal.Gui {
 		///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
 		/// </para>
 		/// </remarks>
-		public View () : this (text: string.Empty) { }
+		public View () : this (text: string.Empty, direction: TextDirection.LeftRight_TopBottom) { }
 
 		/// <summary>
 		///   Initializes a new instance of <see cref="View"/> using <see cref="LayoutStyle.Absolute"/> layout.
@@ -647,15 +663,17 @@ namespace Terminal.Gui {
 		/// </para>
 		/// </remarks>
 		/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-		public View (ustring text)
+		/// <param name="direction">The text direction.</param>
+		public View (ustring text, TextDirection direction = TextDirection.LeftRight_TopBottom)
 		{
-			Initialize (text, Rect.Empty);
+			Initialize (text, Rect.Empty, LayoutStyle.Computed, direction);
 		}
 
-		void Initialize (ustring text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed)
+		void Initialize (ustring text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed,
+			TextDirection direction = TextDirection.LeftRight_TopBottom)
 		{
 			textFormatter = new TextFormatter ();
-			Text = text;
+			TextDirection = direction;
 
 			shortcutHelper = new ShortcutHelper ();
 
@@ -666,7 +684,7 @@ namespace Terminal.Gui {
 			// BUGBUG: CalcRect doesn't account for line wrapping
 			Rect r;
 			if (rect.IsEmpty) {
-				r = TextFormatter.CalcRect (0, 0, text);
+				r = TextFormatter.CalcRect (0, 0, text, direction);
 			} else {
 				r = rect;
 			}
@@ -676,6 +694,8 @@ namespace Terminal.Gui {
 			Height = r.Height;
 
 			Frame = r;
+
+			Text = text;
 		}
 
 		/// <summary>
@@ -1969,6 +1989,9 @@ namespace Terminal.Gui {
 			set {
 				textFormatter.Text = value;
 				ResizeView (autoSize);
+				if (textFormatter.Size != Bounds.Size) {
+					textFormatter.Size = Bounds.Size;
+				}
 				SetNeedsLayout ();
 				SetNeedsDisplay ();
 			}
@@ -1984,8 +2007,10 @@ namespace Terminal.Gui {
 			get => autoSize;
 			set {
 				var v = ResizeView (value);
+				textFormatter.AutoSize = v;
 				if (autoSize != v) {
 					autoSize = v;
+					textFormatter.NeedsFormat = true;
 					SetNeedsLayout ();
 					SetNeedsDisplay ();
 				}
@@ -2023,8 +2048,17 @@ namespace Terminal.Gui {
 		public virtual TextDirection TextDirection {
 			get => textFormatter.Direction;
 			set {
-				textFormatter.Direction = value;
-				SetNeedsDisplay ();
+				if (textFormatter.Direction != value) {
+					textFormatter.Direction = value;
+					if (IsInitialized && AutoSize) {
+						ResizeView (true);
+					} else if (IsInitialized) {
+						var b = new Rect (Bounds.X, Bounds.Y, Bounds.Height, Bounds.Width);
+						SetWidthHeight (b);
+					}
+					textFormatter.Size = Bounds.Size;
+					SetNeedsDisplay ();
+				}
 			}
 		}
 
@@ -2045,30 +2079,41 @@ namespace Terminal.Gui {
 
 		bool ResizeView (bool autoSize)
 		{
+			if (!autoSize) {
+				return false;
+			}
+
 			var aSize = autoSize;
-			if (textFormatter.Size != Bounds.Size && (((width == null || width is Dim.DimAbsolute) && (Bounds.Width == 0
-				|| autoSize && Bounds.Width != textFormatter.Size.Width))
+			Rect nBounds = TextFormatter.CalcRect (Bounds.X, Bounds.Y, Text, textFormatter.Direction);
+
+			if ((textFormatter.Size != Bounds.Size || textFormatter.Size != nBounds.Size)
+				&& (((width == null || width is Dim.DimAbsolute) && (Bounds.Width == 0
+				|| autoSize && Bounds.Width != nBounds.Width))
 				|| ((height == null || height is Dim.DimAbsolute) && (Bounds.Height == 0
-				|| autoSize && Bounds.Height != textFormatter.Size.Height)))) {
-				Bounds = new Rect (Bounds.X, Bounds.Y, textFormatter.Size.Width, textFormatter.Size.Height);
-				if (width == null) {
-					width = Bounds.Width;
-				} else if (width is Dim.DimAbsolute) {
-					width = Math.Max (Bounds.Width, height.Anchor (Bounds.Width));
-				} else {
-					aSize = false;
-				}
-				if (height == null) {
-					height = Bounds.Height;
-				} else if (height is Dim.DimAbsolute) {
-					height = Math.Max (Bounds.Height, height.Anchor (Bounds.Height));
-				} else {
-					aSize = false;
-				}
+				|| autoSize && Bounds.Height != nBounds.Height)))) {
+				aSize = SetWidthHeight (nBounds);
 			}
 			return aSize;
 		}
 
+		bool SetWidthHeight (Rect nBounds)
+		{
+			bool aSize;
+			var canSizeW = SetWidth (nBounds.Width, out int rW);
+			var canSizeH = SetHeight (nBounds.Height, out int rH);
+			if (canSizeW && canSizeH) {
+				aSize = true;
+				Bounds = nBounds;
+				width = rW;
+				height = rH;
+				textFormatter.Size = Bounds.Size;
+			} else {
+				aSize = false;
+			}
+
+			return aSize;
+		}
+
 		/// <summary>
 		/// Specifies the event arguments for <see cref="MouseEvent"/>
 		/// </summary>

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

@@ -8,7 +8,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="true" />
+    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.1" PrivateAssets="true" />
     <PackageReference Include="NStack.Core" Version="0.16.0" />
     <PackageReference Include="MinVer" Version="2.5.0">
       <PrivateAssets>all</PrivateAssets>

+ 8 - 2
Terminal.Gui/Views/Label.cs

@@ -13,7 +13,8 @@ using NStack;
 
 namespace Terminal.Gui {
 	/// <summary>
-	/// The Label <see cref="View"/> displays a string at a given position and supports multiple lines separted by newline characters. Multi-line Labels support word wrap.
+	/// The Label <see cref="View"/> displays a string at a given position and supports multiple lines separated by newline characters.
+	/// Multi-line Labels support word wrap.
 	/// </summary>
 	/// <remarks>
 	/// The <see cref="Label"/> view is functionality identical to <see cref="View"/> and is included for API backwards compatibility.
@@ -44,6 +45,12 @@ namespace Terminal.Gui {
 		{
 		}
 
+		/// <inheritdoc/>
+		public Label (ustring text, TextDirection direction)
+			: base (text, direction)
+		{
+		}
+
 		/// <summary>
 		///   Clicked <see cref="Action"/>, raised when the user clicks the primary mouse button within the Bounds of this <see cref="View"/>
 		///   or if the user presses the action key while this view is focused. (TODO: IsDefault)
@@ -84,7 +91,6 @@ namespace Terminal.Gui {
 			if (MouseEvent (mouseEvent))
 				return true;
 
-
 			if (mouseEvent.Flags == MouseFlags.Button1Clicked) {
 				if (!HasFocus && SuperView != null) {
 					SetFocus ();

+ 19 - 0
Terminal.Gui/Views/TextView.cs

@@ -1944,6 +1944,25 @@ namespace Terminal.Gui {
 			int restCount;
 			List<Rune> rest;
 
+			// if the user presses Left (without any control keys) and they are at the start of the text
+			if(kb.Key == Key.CursorLeft && currentColumn == 0 && currentRow == 0) {
+				// do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
+				return false;
+			}
+
+			// if the user presses Right (without any control keys)
+			if (kb.Key == Key.CursorRight) {
+
+				// determine where the last cursor position in the text is
+				var lastRow = model.Count - 1;
+				var lastCol = model.GetLine (lastRow).Count;
+
+				// if they are at the very end of all the text do not respond (this lets the key press fall through to navigation system - which usually changes focus forward)
+				if (currentColumn == lastCol && currentRow == lastRow) {
+					return false;
+				}
+			}
+
 			// Handle some state here - whether the last command was a kill
 			// operation and the column tracking (up/down)
 			switch (kb.Key) {

+ 65 - 0
UICatalog/Scenarios/AutoSizeAndDirectionText.cs

@@ -0,0 +1,65 @@
+using Terminal.Gui;
+
+namespace UICatalog {
+	[ScenarioMetadata (Name: "AutoSize and Direction Text", Description: "Demonstrates the text auto-size and direction manipulation.")]
+	[ScenarioCategory ("Text")]
+	class AutoSizeAndDirectionText : Scenario {
+		public override void Setup ()
+		{
+			var text = "Hello World";
+			var color = Colors.Dialog;
+
+			var labelH = new Label (text, TextDirection.LeftRight_TopBottom) {
+				X = 1,
+				Y = 1,
+				ColorScheme = color
+			};
+			Win.Add (labelH);
+
+			var labelV = new Label (text, TextDirection.TopBottom_LeftRight) {
+				X = 70,
+				Y = 1,
+				ColorScheme = color
+			};
+			Win.Add (labelV);
+
+			var editText = new TextView () {
+				X = Pos.Center (),
+				Y = Pos.Center (),
+				Width = 20,
+				Height = 5,
+				ColorScheme = color,
+				Text = text
+			};
+
+			editText.SetFocus ();
+
+			Win.Add (editText);
+
+			var ckbDirection = new CheckBox ("Toggle Direction") {
+				X = Pos.Center (),
+				Y = Pos.Center () + 3
+			};
+			ckbDirection.Toggled += (_) => {
+				if (labelH.TextDirection == TextDirection.LeftRight_TopBottom) {
+					labelH.TextDirection = TextDirection.TopBottom_LeftRight;
+					labelV.TextDirection = TextDirection.LeftRight_TopBottom;
+				} else {
+					labelH.TextDirection = TextDirection.LeftRight_TopBottom;
+					labelV.TextDirection = TextDirection.TopBottom_LeftRight;
+				}
+			};
+			Win.Add (ckbDirection);
+
+			var ckbAutoSize = new CheckBox ("Auto Size") {
+				X = Pos.Center (),
+				Y = Pos.Center () + 5
+			};
+			ckbAutoSize.Toggled += (_) => labelH.AutoSize = labelV.AutoSize = ckbAutoSize.Checked;
+			Win.Add (ckbAutoSize);
+
+			Win.KeyUp += (_) =>
+				labelH.Text = labelV.Text = text = editText.Text.ToString ();
+		}
+	}
+}

+ 12 - 7
UICatalog/Scenarios/Dialogs.cs

@@ -13,9 +13,9 @@ namespace UICatalog {
 		public override void Setup ()
 		{
 			var frame = new FrameView ("Dialog Options") {
-				X = Pos.Center(),
+				X = Pos.Center (),
 				Y = 1,
-				Width = Dim.Percent(75),
+				Width = Dim.Percent (75),
 				Height = 10
 			};
 			Win.Add (frame);
@@ -72,7 +72,7 @@ namespace UICatalog {
 			var titleEdit = new TextField ("Title") {
 				X = Pos.Right (label) + 1,
 				Y = Pos.Top (label),
-				Width = Dim.Fill(),
+				Width = Dim.Fill (),
 				Height = 1
 			};
 			frame.Add (titleEdit);
@@ -93,8 +93,13 @@ namespace UICatalog {
 			};
 			frame.Add (numButtonsEdit);
 
-			frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit)
-				+ Dim.Height (numButtonsEdit) + 2;
+			void Top_Loaded ()
+			{
+				frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit)
+					+ Dim.Height (numButtonsEdit) + 2;
+				Top.Loaded -= Top_Loaded;
+			}
+			Top.Loaded += Top_Loaded;
 
 			label = new Label ("Button Pressed:") {
 				X = Pos.Center (),
@@ -113,7 +118,7 @@ namespace UICatalog {
 
 			//var btnText = new [] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" };
 			var showDialogButton = new Button ("Show Dialog") {
-				X = Pos.Center(),
+				X = Pos.Center (),
 				Y = Pos.Bottom (frame) + 2,
 				IsDefault = true,
 			};
@@ -129,7 +134,7 @@ namespace UICatalog {
 						var buttonId = i;
 						//var button = new Button (btnText [buttonId % 10],
 						//	is_default: buttonId == 0);
-						var button = new Button (NumberToWords.Convert(buttonId),
+						var button = new Button (NumberToWords.Convert (buttonId),
 							is_default: buttonId == 0);
 						button.Clicked += () => {
 							clicked = buttonId;

+ 1 - 1
UICatalog/Scenarios/Keys.cs

@@ -87,9 +87,9 @@ namespace UICatalog {
 			var labelKeypress = new Label ("") {
 				X = Pos.Left (edit),
 				Y = Pos.Top (keyPressedLabel),
-				Width = 20,
 				TextAlignment = Terminal.Gui.TextAlignment.Centered,
 				ColorScheme = Colors.Error,
+				AutoSize = true
 			};
 			Win.Add (labelKeypress);
 

+ 6 - 1
UICatalog/Scenarios/MessageBoxes.cs

@@ -140,8 +140,13 @@ namespace UICatalog {
 			};
 			frame.Add (styleRadioGroup);
 
-			frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) + Dim.Height (messageEdit)
+			void Top_Loaded ()
+			{
+				frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) + Dim.Height (messageEdit)
 				+ Dim.Height (numButtonsEdit) + Dim.Height(defaultButtonEdit) + Dim.Height (styleRadioGroup) + 2;
+				Top.Loaded -= Top_Loaded;
+			}
+			Top.Loaded += Top_Loaded;
 
 			label = new Label ("Button Pressed:") {
 				X = Pos.Center (),

+ 7 - 5
UICatalog/Scenarios/Scrolling.cs

@@ -129,6 +129,7 @@ namespace UICatalog {
 				X = 0,
 				Y = 0,
 				Width = Dim.Fill (),  // FIXED: I don't think this should be needed; DimFill() should respect container's frame. X does.
+				Height = 2,
 				ColorScheme = Colors.Error
 			};
 			scrollView.Add (horizontalRuler);
@@ -143,12 +144,13 @@ namespace UICatalog {
 			};
 			scrollView.Add (verticalRuler);
 
-			void Top_Loaded()  {
+			void Top_Loaded ()
+			{
 				horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)] +
 				"\n" + "|         ".Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
 				verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height * 2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height * 2)];
 				Top.Loaded -= Top_Loaded;
-			};
+			}
 			Top.Loaded += Top_Loaded;
 
 			var pressMeButton = new Button ("Press me!") {
@@ -204,8 +206,8 @@ namespace UICatalog {
 			scrollView.Add (anchorButton);
 
 			var hCheckBox = new CheckBox ("Horizontal Scrollbar", scrollView.ShowHorizontalScrollIndicator) {
-				X = Pos.X(scrollView),
-				Y = Pos.Bottom(scrollView) + 1,
+				X = Pos.X (scrollView),
+				Y = Pos.Bottom (scrollView) + 1,
 			};
 			Win.Add (hCheckBox);
 
@@ -273,7 +275,7 @@ namespace UICatalog {
 
 			int count = 0;
 			var mousePos = new Label ("Mouse: ");
-			mousePos.X = Pos.Right(scrollView) + 1;
+			mousePos.X = Pos.Right (scrollView) + 1;
 			mousePos.Y = Pos.AnchorEnd (1);
 			mousePos.Width = 50;
 			Application.RootMouseEvent += delegate (MouseEvent me) {

+ 0 - 2
UnitTests/ApplicationTests.cs

@@ -47,7 +47,6 @@ namespace Terminal.Gui.Core {
 			Assert.False (Application.AlwaysSetPosition);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.Iteration);
-			Assert.False (Application.UseSystemConsole);
 			Assert.Null (Application.RootMouseEvent);
 			Assert.Null (Application.Resized);
 		}
@@ -61,7 +60,6 @@ namespace Terminal.Gui.Core {
 			Assert.False (Application.AlwaysSetPosition);
 			Assert.NotNull (Application.MainLoop);
 			Assert.Null (Application.Iteration);
-			Assert.False (Application.UseSystemConsole);
 			Assert.Null (Application.RootMouseEvent);
 			Assert.Null (Application.Resized);
 		}

+ 38 - 1
UnitTests/RectTests.cs

@@ -29,7 +29,6 @@ namespace Terminal.Gui.Types {
 			action = () => new Rect (1, 2, -3, -4);
 			ex = Assert.Throws<ArgumentException> (action);
 			Assert.Equal ("Width must be greater or equal to 0.", ex.Message);
-
 		}
 
 		[Fact]
@@ -110,5 +109,43 @@ namespace Terminal.Gui.Types {
 			rect2 = new Rect (-1, 2, 3, 4);
 			Assert.NotEqual (rect1, rect2);
 		}
+
+		[Fact]
+		public void Positive_X_Y_Positions ()
+		{
+			var rect = new Rect (10, 5, 100, 50);
+			int yCount = 0, xCount = 0, yxCount = 0;
+
+			for (int line = rect.Y; line < rect.Y + rect.Height; line++) {
+				yCount++;
+				xCount = 0;
+				for (int col = rect.X; col < rect.X + rect.Width; col++) {
+					xCount++;
+					yxCount++;
+				}
+			}
+			Assert.Equal (yCount, rect.Height);
+			Assert.Equal (xCount, rect.Width);
+			Assert.Equal (yxCount, rect.Height * rect.Width);
+		}
+
+		[Fact]
+		public void Negative_X_Y_Positions ()
+		{
+			var rect = new Rect (-10, -5, 100, 50);
+			int yCount = 0, xCount = 0, yxCount = 0;
+
+			for (int line = rect.Y; line < rect.Y + rect.Height; line++) {
+				yCount++;
+				xCount = 0;
+				for (int col = rect.X; col < rect.X + rect.Width; col++) {
+					xCount++;
+					yxCount++;
+				}
+			}
+			Assert.Equal (yCount, rect.Height);
+			Assert.Equal (xCount, rect.Width);
+			Assert.Equal (yxCount, rect.Height * rect.Width);
+		}
 	}
 }

+ 37 - 5
UnitTests/ViewTests.cs

@@ -37,6 +37,7 @@ namespace Terminal.Gui.Views {
 			Assert.False (r.WantMousePositionReports);
 			Assert.Null (r.SuperView);
 			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
 
 			// Empty Rect
 			r = new View (Rect.Empty);
@@ -60,6 +61,7 @@ namespace Terminal.Gui.Views {
 			Assert.False (r.WantMousePositionReports);
 			Assert.Null (r.SuperView);
 			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
 
 			// Rect with values
 			r = new View (new Rect (1, 2, 3, 4));
@@ -83,6 +85,32 @@ namespace Terminal.Gui.Views {
 			Assert.False (r.WantMousePositionReports);
 			Assert.Null (r.SuperView);
 			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
+
+			// Initializes a view with a vertical direction
+			r = new View ("Vertical View", TextDirection.TopBottom_LeftRight);
+			Assert.NotNull (r);
+			Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
+			Assert.Equal ("View()({X=0,Y=0,Width=1,Height=13})", r.ToString ());
+			Assert.False (r.CanFocus);
+			Assert.False (r.HasFocus);
+			Assert.Equal (new Rect (0, 0, 1, 13), r.Bounds);
+			Assert.Equal (new Rect (0, 0, 1, 13), r.Frame);
+			Assert.Null (r.Focused);
+			Assert.Null (r.ColorScheme);
+			Assert.NotNull (r.Width);       // All view Dim are initialized now,
+			Assert.NotNull (r.Height);      // avoiding Dim errors.
+			Assert.NotNull (r.X);           // All view Pos are initialized now,
+			Assert.NotNull (r.Y);           // avoiding Pos errors.
+			Assert.False (r.IsCurrentTop);
+			Assert.Empty (r.Id);
+			Assert.Empty (r.Subviews);
+			Assert.False (r.WantContinuousButtonPressed);
+			Assert.False (r.WantMousePositionReports);
+			Assert.Null (r.SuperView);
+			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.TopBottom_LeftRight, r.TextDirection);
+
 		}
 
 		[Fact]
@@ -1020,7 +1048,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
-		public void View_Difference_Between_An_Object_Initializer_And_A_Constructor ()
+		public void View_With_No_Difference_Between_An_Object_Initializer_And_A_Constructor ()
 		{
 			// Object Initializer
 			var view = new View () {
@@ -1033,8 +1061,10 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (2, view.Y);
 			Assert.Equal (3, view.Width);
 			Assert.Equal (4, view.Height);
-			Assert.True (view.Frame.IsEmpty);
-			Assert.True (view.Bounds.IsEmpty);
+			Assert.False (view.Frame.IsEmpty);
+			Assert.Equal (new Rect (1, 2, 3, 4), view.Frame);
+			Assert.False (view.Bounds.IsEmpty);
+			Assert.Equal (new Rect (0, 0, 3, 4), view.Bounds);
 
 			view.LayoutSubviews ();
 
@@ -1073,8 +1103,10 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (2, view.Y);
 			Assert.Equal (3, view.Width);
 			Assert.Equal (4, view.Height);
-			Assert.True (view.Frame.IsEmpty);
-			Assert.True (view.Bounds.IsEmpty);
+			Assert.False (view.Frame.IsEmpty);
+			Assert.Equal (new Rect (1, 2, 3, 4), view.Frame);
+			Assert.False (view.Bounds.IsEmpty);
+			Assert.Equal (new Rect (0, 0, 3, 4), view.Bounds);
 		}
 
 		[Fact]