Browse Source

Status bar snap (#384)

* KeyDown/Up support

* updated demo

* defined styles

* Smarter StatusBar bottom tracking.

* Prepping for https://github.com/migueldeicaza/gui.cs/issues/376

* Fixed StatusBar 'snap to bottom'
Charlie Kindel 5 years ago
parent
commit
5df8500862
4 changed files with 115 additions and 903 deletions
  1. 4 1
      Example/demo.cs
  2. 0 840
      Terminal.Gui/Drivers/WindowsDriver.cs.orig
  3. 52 3
      Terminal.Gui/Views/StatusBar.cs
  4. 59 59
      Terminal.sln

+ 4 - 1
Example/demo.cs

@@ -551,7 +551,9 @@ static class Demo {
 			new StatusItem(Key.F2, "~F2~ Load", null),
 			new StatusItem(Key.F3, "~F3~ Save", null),
 			new StatusItem(Key.ControlX, "~^X~ Quit", () => { if (Quit ()) top.Running = false; }),
-		});
+		}) {
+			Parent = null,
+		};
 
 		win.Add (drag, dragText);
 #if true
@@ -570,6 +572,7 @@ static class Demo {
 		};
 #endif
 
+
 		top.Add (win);
 		//top.Add (menu);
 		top.Add (menu, statusBar);

+ 0 - 840
Terminal.Gui/Drivers/WindowsDriver.cs.orig

@@ -1,840 +0,0 @@
-//
-// WindowsDriver.cs: Windows specific driver 
-//
-// Authors:
-//   Miguel de Icaza ([email protected])
-//   Nick Van Dyck ([email protected])
-//
-// Copyright (c) 2018
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-// 
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
-using System;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Mono.Terminal;
-using NStack;
-
-namespace Terminal.Gui {
-
-	internal class WindowsConsole {
-		public const int STD_OUTPUT_HANDLE = -11;
-		public const int STD_INPUT_HANDLE = -10;
-		public const int STD_ERROR_HANDLE = -12;
-
-		internal IntPtr InputHandle, OutputHandle;
-		IntPtr ScreenBuffer;
-		uint originalConsoleMode;
-
-		public WindowsConsole ()
-		{
-			InputHandle = GetStdHandle (STD_INPUT_HANDLE);
-			OutputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
-			originalConsoleMode = ConsoleMode;
-			var newConsoleMode = originalConsoleMode;
-			newConsoleMode |= (uint)(ConsoleModes.EnableMouseInput | ConsoleModes.EnableExtendedFlags);
-			newConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode;
-			ConsoleMode = newConsoleMode;
-		}
-
-		public CharInfo[] OriginalStdOutChars;
-
-		public bool WriteToConsole (CharInfo[] charInfoBuffer, Coord coords, SmallRect window)
-		{
-			if (ScreenBuffer == IntPtr.Zero)
-			{
-				ScreenBuffer = CreateConsoleScreenBuffer (
-					DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
-					ShareMode.FileShareRead | ShareMode.FileShareWrite,
-					IntPtr.Zero,
-					1,
-					IntPtr.Zero
-				);
-				if (ScreenBuffer == INVALID_HANDLE_VALUE){
-					var err = Marshal.GetLastWin32Error ();
-
-					if (err != 0)
-					throw new System.ComponentModel.Win32Exception(err);
-				}
-
-				if (!SetConsoleActiveScreenBuffer (ScreenBuffer)){
-					var err = Marshal.GetLastWin32Error();
-					throw new System.ComponentModel.Win32Exception(err);
-				}
-
-				OriginalStdOutChars = new CharInfo[Console.WindowHeight * Console.WindowWidth];
-
-				ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window);
-			}
-
-			return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = 0, Y = 0 }, ref window);
-		}
-
-		public bool SetCursorPosition(Coord position)
-		{
-			return SetConsoleCursorPosition (ScreenBuffer, position);
-		}
-
-		public void Cleanup ()
-		{
-			ContinueListeningForConsoleEvents = false;
-			if (!SetConsoleActiveScreenBuffer (OutputHandle)){
-				var err = Marshal.GetLastWin32Error ();
-				Console.WriteLine("Error: {0}", err);
-			}
-		}
-
-		private bool ContinueListeningForConsoleEvents = true;
-
-		public uint ConsoleMode {
-			get {
-				uint v;
-				GetConsoleMode (InputHandle, out v);
-				return v;
-			}
-
-			set {
-				SetConsoleMode (InputHandle, value);
-			}
-		}
-
-		[Flags]
-		public enum ConsoleModes : uint
-		{
-			EnableMouseInput = 16,
-			EnableQuickEditMode = 64,
-			EnableExtendedFlags = 128,
-		}
-
-		[StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
-		public struct KeyEventRecord {
-			[FieldOffset (0), MarshalAs (UnmanagedType.Bool)]
-			public bool bKeyDown;
-			[FieldOffset (4), MarshalAs (UnmanagedType.U2)]
-			public ushort wRepeatCount;
-			[FieldOffset (6), MarshalAs (UnmanagedType.U2)]
-			public ushort wVirtualKeyCode;
-			[FieldOffset (8), MarshalAs (UnmanagedType.U2)]
-			public ushort wVirtualScanCode;
-			[FieldOffset (10)]
-			public char UnicodeChar;
-			[FieldOffset (12), MarshalAs (UnmanagedType.U4)]
-			public ControlKeyState dwControlKeyState;
-		}
-
-		[Flags]
-		public enum ButtonState {
-			Button1Pressed = 1,
-			Button2Pressed = 4,
-			Button3Pressed = 8,
-			Button4Pressed = 16,
-			RightmostButtonPressed = 2,
-
-		}
-
-		[Flags]
-		public enum ControlKeyState {
-			RightAltPressed = 1,
-			LeftAltPressed = 2,
-			RightControlPressed = 4,
-			LeftControlPressed = 8,
-			ShiftPressed = 16,
-			NumlockOn = 32,
-			ScrolllockOn = 64,
-			CapslockOn = 128,
-			EnhancedKey = 256
-		}
-
-		[Flags]
-		public enum EventFlags {
-			MouseMoved = 1,
-			DoubleClick = 2,
-			MouseWheeled = 4,
-			MouseHorizontalWheeled = 8
-		}
-
-		[StructLayout (LayoutKind.Explicit)]
-		public struct MouseEventRecord {
-			[FieldOffset (0)]
-			public Coordinate MousePosition;
-			[FieldOffset (4)]
-			public ButtonState ButtonState;
-			[FieldOffset (8)]
-			public ControlKeyState ControlKeyState;
-			[FieldOffset (12)]
-			public EventFlags EventFlags;
-
-			public override string ToString ()
-			{
-				return $"[Mouse({MousePosition},{ButtonState},{ControlKeyState},{EventFlags}";
-			}
-		}
-
-		[StructLayout (LayoutKind.Sequential)]
-		public struct Coordinate {
-			public short X;
-			public short Y;
-
-			public Coordinate (short X, short Y)
-			{
-				this.X = X;
-				this.Y = Y;
-			}
-
-			public override string ToString () => $"({X},{Y})";
-		};
-
-		internal struct WindowBufferSizeRecord {
-			public Coordinate size;
-
-			public WindowBufferSizeRecord (short x, short y)
-			{
-				this.size = new Coordinate (x, y);
-			}
-
-			public override string ToString () => $"[WindowBufferSize{size}";
-		}
-
-		[StructLayout (LayoutKind.Sequential)]
-		public struct MenuEventRecord {
-			public uint dwCommandId;
-		}
-
-		[StructLayout (LayoutKind.Sequential)]
-		public struct FocusEventRecord {
-			public uint bSetFocus;
-		}
-
-		public enum EventType {
-			Focus = 0x10,
-			Key = 0x1,
-			Menu = 0x8,
-			Mouse = 2,
-			WindowBufferSize = 4
-		}
-
-		[StructLayout (LayoutKind.Explicit)]
-		public struct InputRecord {
-			[FieldOffset (0)]
-			public EventType EventType;
-			[FieldOffset (4)]
-			public KeyEventRecord KeyEvent;
-			[FieldOffset (4)]
-			public MouseEventRecord MouseEvent;
-			[FieldOffset (4)]
-			public WindowBufferSizeRecord WindowBufferSizeEvent;
-			[FieldOffset (4)]
-			public MenuEventRecord MenuEvent;
-			[FieldOffset (4)]
-			public FocusEventRecord FocusEvent;
-
-			public override string ToString ()
-			{
-				switch (EventType) {
-				case EventType.Focus:
-					return FocusEvent.ToString ();
-				case EventType.Key:
-					return KeyEvent.ToString ();
-				case EventType.Menu:
-					return MenuEvent.ToString ();
-				case EventType.Mouse:
-					return MouseEvent.ToString ();
-				case EventType.WindowBufferSize:
-					return WindowBufferSizeEvent.ToString ();
-				default:
-					return "Unknown event type: " + EventType;
-				}
-			}
-		};
-
-		[Flags]
-		enum ShareMode : uint
-		{
-			FileShareRead = 1,
-			FileShareWrite = 2,
-		}
-
-		[Flags]
-		enum DesiredAccess : uint
-		{
-			GenericRead = 2147483648,
-			GenericWrite = 1073741824,
-		}
-
-		[StructLayout(LayoutKind.Sequential)]
-		public struct ConsoleScreenBufferInfo
-		{
-			public Coord dwSize;
-			public Coord dwCursorPosition;
-			public ushort wAttributes;
-			public SmallRect srWindow;
-			public Coord dwMaximumWindowSize;
-		}
-
-		[StructLayout(LayoutKind.Sequential)]
-		public struct Coord
-		{
-			public short X;
-			public short Y;
-
-			public Coord(short X, short Y)
-			{
-				this.X = X;
-				this.Y = Y;
-			}
-		};
-
-		[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
-		public struct CharUnion
-		{
-			[FieldOffset(0)] public char UnicodeChar;
-			[FieldOffset(0)] public byte AsciiChar;
-		}
-
-		[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
-		public struct CharInfo
-		{
-			[FieldOffset(0)] public CharUnion Char;
-			[FieldOffset(2)] public ushort Attributes;
-		}
-
-		[StructLayout(LayoutKind.Sequential)]
-		public struct SmallRect
-		{
-			public short Left;
-			public short Top;
-			public short Right;
-			public short Bottom;
-		}
-
-		[DllImport ("kernel32.dll", SetLastError = true)]
-		static extern IntPtr GetStdHandle (int nStdHandle);
-
-		[DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)]
-		public static extern bool ReadConsoleInput (
-			IntPtr hConsoleInput,
-			[Out] InputRecord [] lpBuffer,
-			uint nLength,
-			out uint lpNumberOfEventsRead);
-
-		[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
-		static extern bool ReadConsoleOutput(
-			IntPtr hConsoleOutput,
-			[Out] CharInfo[] lpBuffer,
-			Coord dwBufferSize,
-			Coord dwBufferCoord,
-			ref SmallRect lpReadRegion
-		);
-		
-		[DllImport("kernel32.dll", EntryPoint="WriteConsoleOutput", SetLastError=true, CharSet=CharSet.Unicode)]
-		static extern bool WriteConsoleOutput(
-			IntPtr hConsoleOutput,
-			CharInfo[] lpBuffer,
-			Coord dwBufferSize,
-			Coord dwBufferCoord,
-			ref SmallRect lpWriteRegion
-		);
-
-		[DllImport ("kernel32.dll")]
-		static extern bool SetConsoleCursorPosition(IntPtr hConsoleOutput, Coord dwCursorPosition);
-
-		[DllImport ("kernel32.dll")]
-		static extern bool GetConsoleMode (IntPtr hConsoleHandle, out uint lpMode);
-
-
-		[DllImport ("kernel32.dll")]
-		static extern bool SetConsoleMode (IntPtr hConsoleHandle, uint dwMode);
-
-		[DllImport("kernel32.dll", SetLastError = true)]
-		static extern IntPtr CreateConsoleScreenBuffer(
-			DesiredAccess dwDesiredAccess,
-			ShareMode dwShareMode,
-			IntPtr secutiryAttributes,
-			UInt32 flags,
-			IntPtr screenBufferData
-		);
-
-		internal static IntPtr INVALID_HANDLE_VALUE = new IntPtr (-1);
-
-
-		[DllImport("kernel32.dll", SetLastError = true)]
-		static extern bool SetConsoleActiveScreenBuffer(IntPtr Handle);
-
-		[DllImport ("kernel32.dll", SetLastError = true)]
-		static extern bool GetNumberOfConsoleInputEvents (IntPtr handle, out uint lpcNumberOfEvents);
-		public uint InputEventCount {
-			get {
-				uint v;
-				GetNumberOfConsoleInputEvents (InputHandle, out v);
-				return v;
-			}
-		}
-	}
-
-	internal class WindowsDriver : ConsoleDriver, Mono.Terminal.IMainLoopDriver {
-		static bool sync;
-		AutoResetEvent eventReady = new AutoResetEvent (false);
-		AutoResetEvent waitForProbe = new AutoResetEvent (false);
-		MainLoop mainLoop;
-		Action TerminalResized;
-		WindowsConsole.CharInfo[] OutputBuffer;
-		int cols, rows;
-		WindowsConsole winConsole;
-
-		public override int Cols => cols;
-		public override int Rows => rows;
-
-		public WindowsDriver ()
-		{
-			winConsole = new WindowsConsole();
-
-			cols = Console.WindowWidth;
-			rows = Console.WindowHeight - 1;
-
-			ResizeScreen ();
-			UpdateOffScreen ();
-
-			Task.Run ((Action)WindowsInputHandler);
-		}
-
-		// The records that we keep fetching
-		WindowsConsole.InputRecord [] result, records = new WindowsConsole.InputRecord [1];
-
-		void WindowsInputHandler () 
-		{
-			while (true) {
-				waitForProbe.WaitOne ();
-
-				uint numberEventsRead = 0;
-
-				WindowsConsole.ReadConsoleInput (winConsole.InputHandle, records, 1, out numberEventsRead);
-				if (numberEventsRead == 0)
-					result = null;
-				else
-					result = records;
-				
-				eventReady.Set ();
-			}
-		}
-
-		void IMainLoopDriver.Setup (MainLoop mainLoop)
-		{
-			this.mainLoop = mainLoop;
-		}
-
-		void IMainLoopDriver.Wakeup ()
-		{
-		}
-
-		bool IMainLoopDriver.EventsPending (bool wait)
-		{
-			long now = DateTime.UtcNow.Ticks;
-
-			int waitTimeout;
-			if (mainLoop.timeouts.Count > 0) {
-				waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
-				if (waitTimeout < 0)
-					return true;
-			} else
-				waitTimeout = -1;
-
-			if (!wait)
-				waitTimeout = 0;
-
-			result = null;
-			waitForProbe.Set ();
-			eventReady.WaitOne (waitTimeout);
-			return result != null;
-		}
-
-		Action<KeyEvent> keyHandler;
-		Action<MouseEvent> mouseHandler;
-
-		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
-		{
-			this.keyHandler = keyHandler;
-			this.mouseHandler = mouseHandler;
-		}
-		
-
-		void IMainLoopDriver.MainIteration ()
-		{
-			if (result == null)
-				return;
-
-			var inputEvent = result [0];
-			switch (inputEvent.EventType) {
-			case WindowsConsole.EventType.Key:
-				if (inputEvent.KeyEvent.bKeyDown == false)
-					return;
-				var map = MapKey (ToConsoleKeyInfo (inputEvent.KeyEvent));
-				if (map == (Key)0xffffffff)
-					return;
-				keyHandler (new KeyEvent (map));
-				break;
-
-			case WindowsConsole.EventType.Mouse:
-				mouseHandler (ToDriverMouse (inputEvent.MouseEvent));
-				break;
-
-			case WindowsConsole.EventType.WindowBufferSize:
-				cols = inputEvent.WindowBufferSizeEvent.size.X;
-				rows = inputEvent.WindowBufferSizeEvent.size.Y - 1;
-				ResizeScreen ();
-				UpdateOffScreen ();
-				TerminalResized ();
-				break;
-			}
-			result = null;
-		}
-
-		private WindowsConsole.ButtonState? LastMouseButtonPressed = null;
-
-		private MouseEvent ToDriverMouse(WindowsConsole.MouseEventRecord mouseEvent)
-		{
-			MouseFlags mouseFlag = MouseFlags.AllEvents;
-
-			// The ButtonState member of the MouseEvent structure has bit corresponding to each mouse button.
-			// This will tell when a mouse button is pressed. When the button is released this event will
-			// be fired with it's bit set to 0. So when the button is up ButtonState will be 0.
-			// To map to the correct driver events we save the last pressed mouse button so we can
-			// map to the correct clicked event.
-			if (LastMouseButtonPressed != null && mouseEvent.ButtonState != 0)
-			{
-				LastMouseButtonPressed = null;
-			}
-
-			if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null){
-				switch (mouseEvent.ButtonState){
-				case WindowsConsole.ButtonState.Button1Pressed:
-					mouseFlag = MouseFlags.Button1Pressed;
-					break;
-
-				case WindowsConsole.ButtonState.Button2Pressed:
-					mouseFlag = MouseFlags.Button2Pressed;
-					break;
-
-				case WindowsConsole.ButtonState.Button3Pressed:
-					mouseFlag = MouseFlags.Button3Pressed;
-					break;
-				}
-				LastMouseButtonPressed = mouseEvent.ButtonState;
-			} else if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed != null){
-				switch (LastMouseButtonPressed){
-				case WindowsConsole.ButtonState.Button1Pressed:
-					mouseFlag = MouseFlags.Button1Clicked;
-					break;
-
-				case WindowsConsole.ButtonState.Button2Pressed:
-					mouseFlag = MouseFlags.Button2Clicked;
-					break;
-
-				case WindowsConsole.ButtonState.Button3Pressed:
-					mouseFlag = MouseFlags.Button3Clicked;
-					break;
-				}
-				LastMouseButtonPressed = null;
-			} else if(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved){
-				mouseFlag = MouseFlags.ReportMousePosition;
-			}
-
-			return new MouseEvent () {
-				X = mouseEvent.MousePosition.X,
-				Y = mouseEvent.MousePosition.Y,
-				Flags = mouseFlag
-			};
-		}
-
-		private ConsoleKeyInfo ToConsoleKeyInfo (WindowsConsole.KeyEventRecord keyEvent)
-		{
-			var state = keyEvent.dwControlKeyState;
-
-			bool shift = (state & WindowsConsole.ControlKeyState.ShiftPressed) != 0;
-			bool alt = (state & (WindowsConsole.ControlKeyState.LeftAltPressed | WindowsConsole.ControlKeyState.RightAltPressed)) != 0;
-			bool control = (state & (WindowsConsole.ControlKeyState.LeftControlPressed | WindowsConsole.ControlKeyState.RightControlPressed)) != 0;
-
-			return new ConsoleKeyInfo(keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
-		}
-
-		public Key MapKey (ConsoleKeyInfo keyInfo)
-		{
-			switch (keyInfo.Key) {
-			case ConsoleKey.Escape:
-				return Key.Esc;
-			case ConsoleKey.Tab:
-				return Key.Tab;
-			case ConsoleKey.Home:
-				return Key.Home;
-			case ConsoleKey.End:
-				return Key.End;
-			case ConsoleKey.LeftArrow:
-				return Key.CursorLeft;
-			case ConsoleKey.RightArrow:
-				return Key.CursorRight;
-			case ConsoleKey.UpArrow:
-				return Key.CursorUp;
-			case ConsoleKey.DownArrow:
-				return Key.CursorDown;
-			case ConsoleKey.PageUp:
-				return Key.PageUp;
-			case ConsoleKey.PageDown:
-				return Key.PageDown;
-			case ConsoleKey.Enter:
-				return Key.Enter;
-			case ConsoleKey.Spacebar:
-				return Key.Space;
-			case ConsoleKey.Backspace:
-				return Key.Backspace;
-			case ConsoleKey.Delete:
-				return Key.DeleteChar;
-
-			case ConsoleKey.Oem1:
-			case ConsoleKey.Oem2:
-			case ConsoleKey.Oem3:
-			case ConsoleKey.Oem4:
-			case ConsoleKey.Oem5:
-			case ConsoleKey.Oem6:
-			case ConsoleKey.Oem7:
-			case ConsoleKey.Oem8:
-			case ConsoleKey.Oem102:
-			case ConsoleKey.OemPeriod:
-			case ConsoleKey.OemComma:
-			case ConsoleKey.OemPlus:
-			case ConsoleKey.OemMinus:
-				return (Key)((uint)keyInfo.KeyChar);
-			}
-
-			var key = keyInfo.Key;
-			if (key >= ConsoleKey.A && key <= ConsoleKey.Z) {
-				var delta = key - ConsoleKey.A;
-				if (keyInfo.Modifiers == ConsoleModifiers.Control)
-					return (Key)((uint)Key.ControlA + delta);
-				if (keyInfo.Modifiers == ConsoleModifiers.Alt)
-					return (Key)(((uint)Key.AltMask) | ((uint)'A' + delta));
-				if (keyInfo.Modifiers == ConsoleModifiers.Shift)
-					return (Key)((uint)'A' + delta);
-				else
-					return (Key)((uint)'a' + delta);
-			}
-			if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) {
-				var delta = key - ConsoleKey.D0;
-				if (keyInfo.Modifiers == ConsoleModifiers.Alt)
-					return (Key)(((uint)Key.AltMask) | ((uint)'0' + delta));
-				if (keyInfo.Modifiers == ConsoleModifiers.Shift)
-					return (Key)((uint)keyInfo.KeyChar);
-				return (Key)((uint)'0' + delta);
-			}
-			if (key >= ConsoleKey.F1 && key <= ConsoleKey.F10) {
-				var delta = key - ConsoleKey.F1;
-
-				return (Key)((int)Key.F1 + delta);
-			}
-			return (Key)(0xffffffff);
-		}
-
-		public override void Init (Action terminalResized)
-		{
-			TerminalResized = terminalResized;
-
-			Colors.Base = new ColorScheme ();
-			Colors.Dialog = new ColorScheme ();
-			Colors.Menu = new ColorScheme ();
-			Colors.Error = new ColorScheme ();
-
-			HLine = '\u2500';
-			VLine = '\u2502';
-			Stipple = '\u2592';
-			Diamond = '\u25c6';
-			ULCorner = '\u250C';
-			LLCorner = '\u2514';
-			URCorner = '\u2510';
-			LRCorner = '\u2518';
-			LeftTee = '\u251c';
-			RightTee = '\u2524';
-			TopTee = '\u22a4';
-			BottomTee = '\u22a5';
-
-			Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Blue);
-			Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
-			Colors.Base.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Blue);
-			Colors.Base.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
-
-			Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black);
-			Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
-			Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
-			Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan);
-
-			Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
-			Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
-			Colors.Dialog.HotNormal = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray);
-			Colors.Dialog.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Cyan);
-
-			Colors.Error.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Red);
-			Colors.Error.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
-			Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red);
-			Colors.Error.HotFocus = Colors.Error.HotNormal;
-			Console.Clear ();
-		}
-
-		void ResizeScreen ()
-		{
-			OutputBuffer = new WindowsConsole.CharInfo[Rows * Cols];
-			Clip = new Rect (0, 0, Cols, Rows);
-		}
-
-		void UpdateOffScreen ()
-		{
-			for (int row = 0; row < rows; row++)
-				for (int col = 0; col < cols; col++){
-					int position = row * cols + col;
-					OutputBuffer[position].Attributes = (ushort)MakeColor(ConsoleColor.White, ConsoleColor.Blue);
-					OutputBuffer[position].Char.UnicodeChar = ' ';
-				}
-		}
-
-		int ccol, crow;
-		public override void Move (int col, int row)
-		{
-			ccol = col;
-			crow = row;
-		}
-
-		public override void AddRune (Rune rune)
-		{
-			var position = crow * Cols + ccol;
-
-			if (Clip.Contains (ccol, crow)){
-				OutputBuffer[position].Attributes = (ushort)currentAttribute;
-				OutputBuffer[position].Char.UnicodeChar = (char)rune;
-			}
-
-			ccol++;
-			if (ccol == Cols) {
-				ccol = 0;
-				if (crow + 1 < Rows)
-					crow++;
-			}
-			if (sync)
-				UpdateScreen ();
-		}
-
-		public override void AddStr (ustring str)
-		{
-			foreach (var rune in str)
-				AddRune (rune);
-		}
-
-		int currentAttribute;
-		public override void SetAttribute (Attribute c)
-		{
-			currentAttribute = c.value;
-		}
-
-		private Attribute MakeColor (ConsoleColor f, ConsoleColor b)
-		{
-			// Encode the colors into the int value.
-			return new Attribute (){
-				value = ((int)f | (int)b << 4)
-			};
-		}
-
-		public override void Refresh()
-		{
-			var bufferCoords = new WindowsConsole.Coord (){
-				X = (short)Clip.Width,
-				Y = (short)Clip.Height
-			};
-
-			var window = new WindowsConsole.SmallRect (){
-				Top = 0,
-				Left = 0,
-				Right = (short)Clip.Right,
-				Bottom = (short)Clip.Bottom
-			};
-
-			UpdateCursor();
-			winConsole.WriteToConsole (OutputBuffer, bufferCoords, window);
-		}
-
-		public override void UpdateScreen ()
-		{
-			var bufferCoords = new WindowsConsole.Coord (){
-				X = (short)Clip.Width,
-				Y = (short)Clip.Height
-			};
-
-			var window = new WindowsConsole.SmallRect (){
-				Top = 0,
-				Left = 0,
-				Right = (short)Clip.Right,
-				Bottom = (short)Clip.Bottom
-			};
-
-			UpdateCursor();
-			winConsole.WriteToConsole (OutputBuffer, bufferCoords, window);
-		}
-
-		public override void UpdateCursor()
-		{
-			var position = new WindowsConsole.Coord(){
-				X = (short)ccol,
-				Y = (short)crow
-			};
-			winConsole.SetCursorPosition(position);
-		}
-		public override void End ()
-		{
-			winConsole.Cleanup();
-		}
-
-		#region Unused
-		public override void SetColors (ConsoleColor foreground, ConsoleColor background)
-		{
-		}
-
-		public override void SetColors (short foregroundColorId, short backgroundColorId)
-		{
-		}
-
-		public override void Suspend ()
-		{
-		}
-
-		public override void StartReportingMouseMoves ()
-		{
-		}
-
-		public override void StopReportingMouseMoves ()
-		{
-		}
-
-		public override void UncookMouse ()
-		{
-		}
-
-		public override void CookMouse ()
-		{
-		}
-		#endregion
-
-	}
-
-	
-}

+ 52 - 3
Terminal.Gui/Views/StatusBar.cs

@@ -55,11 +55,43 @@ namespace Terminal.Gui {
 	/// So for each context must be a new instance of a statusbar.
 	/// </summary>
 	public class StatusBar : View {
+// After attempting to implement this, I noticed that there are hard dependencies
+// on StatusBar and MenuBars within core. They will need to be refactored for having the
+// StatusBar work at the top
+#if SNAP_TO_TOP
+		/// <summary>
+		/// The style supported by StatusBar
+		/// </summary>
+		public enum StatusBarStyle {
+			Default = 0,
+			/// <summary>
+			/// The StatusBar will snap at the the bottom line of the Parent view.
+			/// If the console window is made larger while the app is runing, the StatusBar
+			/// will continue to snap to the bottom line of the Parent, staying visible.
+			/// On consoles that support resizing of console apps (e.g. Windows Terminal and ConEmu),
+			/// if the console window is subsequently made shorter, the status bar will remain visible
+			/// as the Parent view resizes. If Parent is null, the StatusBar will snap to the bottom line
+			/// of the console window.
+			/// This is the default.
+			/// </summary>
+			SnapToBottom = Default,
+
+			/// <summary>
+			/// The StatusBar will act identically to MenuBar, snapping to the first line of the
+			/// console window.
+			/// </summary>
+			SnapToTop = 1,
+		}
+
+		public StatusBarStyle Style { get; set; } = StatusBarStyle.Default;
+#endif
+		public View Parent { get; set; }
+
 		public StatusItem [] Items { get; set; }
 
 		/// <summary>
 		/// Initializes a new instance of the <see cref="T:Terminal.Gui.StatusBar"/> class with the specified set of statusbar items.
-		/// It will be drawn in the lowest column of the terminal.
+		/// It will be drawn in the lowest line of the terminal.
 		/// </summary>
 		/// <param name="items">A list of statusbar items.</param>
 		public StatusBar (StatusItem [] items) : base ()
@@ -71,8 +103,25 @@ namespace Terminal.Gui {
 			ColorScheme = Colors.Menu;
 
 			Application.OnLoad += () => {
-				this.X = Pos.Left (Application.Top);
-				this.Y = Pos.Bottom (Application.Top);
+				X = 0;
+				Height = 1;
+#if SNAP_TO_TOP
+				switch (Style) {
+				case StatusBarStyle.SnapToTop:
+					X = 0;
+					Y = 0;
+					break;
+				case StatusBarStyle.SnapToBottom:
+#endif
+					if (Parent == null) {
+						Y = Application.Driver.Rows - 1; // TODO: using internals of Application
+					} else {
+						Y = Pos.Bottom (Parent);
+					}
+#if SNAP_TO_TOP
+					break;
+				}
+#endif
 			};
 		}
 

+ 59 - 59
Terminal.sln

@@ -1,59 +1,59 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x86 = Debug|x86
-		Release|x86 = Release|x86
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|x86
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|x86
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|x86
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|x86
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.Build.0 = Debug|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
-		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.ActiveCfg = Debug|x86
-		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.Build.0 = Debug|x86
-		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.ActiveCfg = Release|x86
-		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.Build.0 = Release|x86
-	EndGlobalSection
-	GlobalSection(MonoDevelopProperties) = preSolution
-		Policies = $0
-		$0.TextStylePolicy = $1
-		$1.FileWidth = 80
-		$1.scope = text/x-csharp
-		$1.TabWidth = 8
-		$1.IndentWidth = 8
-		$0.CSharpFormattingPolicy = $2
-		$2.scope = text/x-csharp
-		$2.IndentSwitchSection = False
-		$2.NewLinesForBracesInTypes = False
-		$2.NewLinesForBracesInProperties = False
-		$2.NewLinesForBracesInAccessors = False
-		$2.NewLinesForBracesInAnonymousMethods = False
-		$2.NewLinesForBracesInControlBlocks = False
-		$2.NewLinesForBracesInAnonymousTypes = False
-		$2.NewLinesForBracesInObjectCollectionArrayInitializers = False
-		$2.NewLinesForBracesInLambdaExpressionBody = False
-		$2.NewLineForElse = False
-		$2.NewLineForCatch = False
-		$2.NewLineForFinally = False
-		$2.NewLineForMembersInObjectInit = False
-		$2.NewLineForMembersInAnonymousTypes = False
-		$2.NewLineForClausesInQuery = False
-		$2.SpacingAfterMethodDeclarationName = True
-		$2.SpaceAfterMethodCallName = True
-		$2.SpaceBeforeOpenSquareBracket = True
-		$0.DotNetNamingPolicy = $3
-		$0.StandardHeader = $4
-	EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x86 = Debug|x86
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|x86
+		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|x86
+		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|x86
+		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|x86
+		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.Build.0 = Debug|Any CPU
+		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
+		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
+		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.ActiveCfg = Debug|x86
+		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.Build.0 = Debug|x86
+		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.ActiveCfg = Release|x86
+		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		Policies = $0
+		$0.TextStylePolicy = $1
+		$1.FileWidth = 80
+		$1.scope = text/x-csharp
+		$1.TabWidth = 8
+		$1.IndentWidth = 8
+		$0.CSharpFormattingPolicy = $2
+		$2.scope = text/x-csharp
+		$2.IndentSwitchSection = False
+		$2.NewLinesForBracesInTypes = False
+		$2.NewLinesForBracesInProperties = False
+		$2.NewLinesForBracesInAccessors = False
+		$2.NewLinesForBracesInAnonymousMethods = False
+		$2.NewLinesForBracesInControlBlocks = False
+		$2.NewLinesForBracesInAnonymousTypes = False
+		$2.NewLinesForBracesInObjectCollectionArrayInitializers = False
+		$2.NewLinesForBracesInLambdaExpressionBody = False
+		$2.NewLineForElse = False
+		$2.NewLineForCatch = False
+		$2.NewLineForFinally = False
+		$2.NewLineForMembersInObjectInit = False
+		$2.NewLineForMembersInAnonymousTypes = False
+		$2.NewLineForClausesInQuery = False
+		$2.SpacingAfterMethodDeclarationName = True
+		$2.SpaceAfterMethodCallName = True
+		$2.SpaceBeforeOpenSquareBracket = True
+		$0.DotNetNamingPolicy = $3
+		$0.StandardHeader = $4
+	EndGlobalSection
+EndGlobal