From 5df8500862dbc65f35843a084b9888d33cdbcf73 Mon Sep 17 00:00:00 2001 From: Charlie Kindel Date: Mon, 20 Apr 2020 14:08:34 -0600 Subject: [PATCH] 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' --- Example/demo.cs | 5 +- Terminal.Gui/Drivers/WindowsDriver.cs.orig | 840 --------------------- Terminal.Gui/Views/StatusBar.cs | 55 +- Terminal.sln | 118 +-- 4 files changed, 115 insertions(+), 903 deletions(-) delete mode 100644 Terminal.Gui/Drivers/WindowsDriver.cs.orig diff --git a/Example/demo.cs b/Example/demo.cs index 0ec5cc9ae..f138bc329 100644 --- a/Example/demo.cs +++ b/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); diff --git a/Terminal.Gui/Drivers/WindowsDriver.cs.orig b/Terminal.Gui/Drivers/WindowsDriver.cs.orig deleted file mode 100644 index 1b9084f52..000000000 --- a/Terminal.Gui/Drivers/WindowsDriver.cs.orig +++ /dev/null @@ -1,840 +0,0 @@ -// -// WindowsDriver.cs: Windows specific driver -// -// Authors: -// Miguel de Icaza (miguel@gnome.org) -// Nick Van Dyck (vandyck.nick@outlook.com) -// -// 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 keyHandler; - Action mouseHandler; - - public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action 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 - - } - - -} diff --git a/Terminal.Gui/Views/StatusBar.cs b/Terminal.Gui/Views/StatusBar.cs index 85c6de3fa..fe1573a91 100644 --- a/Terminal.Gui/Views/StatusBar.cs +++ b/Terminal.Gui/Views/StatusBar.cs @@ -55,11 +55,43 @@ namespace Terminal.Gui { /// So for each context must be a new instance of a statusbar. /// 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 + /// + /// The style supported by StatusBar + /// + public enum StatusBarStyle { + Default = 0, + /// + /// 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. + /// + SnapToBottom = Default, + + /// + /// The StatusBar will act identically to MenuBar, snapping to the first line of the + /// console window. + /// + SnapToTop = 1, + } + + public StatusBarStyle Style { get; set; } = StatusBarStyle.Default; +#endif + public View Parent { get; set; } + public StatusItem [] Items { get; set; } /// /// Initializes a new instance of the 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. /// /// A list of statusbar items. 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 }; } diff --git a/Terminal.sln b/Terminal.sln index c5070ec8a..5bace6618 100644 --- a/Terminal.sln +++ b/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