From 415cd11e20dac6b8c9d380a0127a9b4def8ba463 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 23 Nov 2020 23:19:39 +0000 Subject: [PATCH 01/15] Fixes #1020. NetDriver does not deal well with unicode characters yet. --- Example/demo.cs | 4 +- .../CursesDriver/CursesDriver.cs | 2 + .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 1 + Terminal.Gui/ConsoleDrivers/NetDriver.cs | 195 +++++++---- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 331 +++++++++++------- Terminal.Gui/Core/Application.cs | 32 +- Terminal.Gui/Core/ConsoleDriver.cs | 19 + UICatalog/Scenarios/CharacterMap.cs | 40 ++- 8 files changed, 404 insertions(+), 220 deletions(-) diff --git a/Example/demo.cs b/Example/demo.cs index 1bcc64446..c10bb84ce 100644 --- a/Example/demo.cs +++ b/Example/demo.cs @@ -562,9 +562,11 @@ static class Demo { if (Debugger.IsAttached) CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US"); - //Application.UseSystemConsole = true; + Application.UseSystemConsole = true; Application.Init(); + Application.HeightSize = HeightSize.BufferHeight; + //ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler; var top = Application.Top; diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 3551b0699..e430f4da1 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -20,6 +20,7 @@ namespace Terminal.Gui { public override int Cols => Curses.Cols; public override int Rows => Curses.Lines; public override int Top => 0; + public override HeightSize HeightSize { get; set; } // Current row, and current col, tracked by Move/AddRune only int ccol, crow; @@ -70,6 +71,7 @@ namespace Terminal.Gui { public override void Refresh () { Curses.refresh (); if (Curses.CheckWinChange ()) { + Clip = new Rect (0, 0, Cols, Rows); TerminalResized?.Invoke (); } } diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 7566d6928..424e1def0 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -20,6 +20,7 @@ namespace Terminal.Gui { public override int Cols => cols; public override int Rows => rows; public override int Top => 0; + public override HeightSize HeightSize { get; set; } // The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag int [,,] contents; diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index ab36cf957..59a9b1375 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -18,17 +18,12 @@ namespace Terminal.Gui { public override int Cols => cols; public override int Rows => rows; public override int Top => top; + public override HeightSize HeightSize { get; set; } // The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag int [,,] contents; bool [] dirtyLine; - public NetDriver () - { - ResizeScreen (); - UpdateOffscreen (); - } - void UpdateOffscreen () { int cols = Cols; @@ -48,53 +43,39 @@ namespace Terminal.Gui { static bool sync = false; - bool needMove; // Current row, and current col, tracked by Move/AddCh only int ccol, crow; public override void Move (int col, int row) { ccol = col; crow = row; - - if (Clip.Contains (col, row)) { - if (cols == Console.WindowWidth && rows == Console.WindowHeight) { - Console.SetCursorPosition (col, row); - needMove = false; - } - } else { - if (cols == Console.WindowWidth && rows == Console.WindowHeight) { - if (Console.WindowHeight > 0) { - Console.SetCursorPosition (Clip.X, Clip.Y); - } - needMove = true; - } - } } public override void AddRune (Rune rune) { rune = MakePrintable (rune); if (Clip.Contains (ccol, crow)) { - if (needMove) { - if (cols == Console.WindowWidth && rows == Console.WindowHeight) { - Console.SetCursorPosition (ccol, crow); - } - needMove = false; - } contents [crow, ccol, 0] = (int)(uint)rune; contents [crow, ccol, 1] = currentAttribute; contents [crow, ccol, 2] = 1; dirtyLine [crow] = true; - } else - needMove = true; + } ccol++; + var runeWidth = Rune.ColumnWidth (rune); + if (runeWidth > 1) { + for (int i = 1; i < runeWidth; i++) { + contents [crow, ccol, 2] = 0; + ccol++; + } + } //if (ccol == Cols) { // ccol = 0; // if (crow + 1 < Rows) // crow++; //} - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -122,10 +103,16 @@ namespace Terminal.Gui { return new Attribute () { value = ((((int)f) & 0xffff) << 16) | (((int)b) & 0xffff) }; } + bool isWinPlatform; + public override void Init (Action terminalResized) { TerminalResized = terminalResized; Console.TreatControlCAsInput = true; + var p = Environment.OSVersion.Platform; + if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) { + isWinPlatform = true; + } Colors.TopLevel = new ColorScheme (); Colors.Base = new ColorScheme (); @@ -164,14 +151,64 @@ namespace Terminal.Gui { Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red); Colors.Error.HotFocus = Colors.Error.HotNormal; Clear (); + ResizeScreen (); + UpdateOffscreen (); } void ResizeScreen () { - cols = Console.WindowWidth; - rows = Console.WindowHeight; + const int Min_WindowWidth = 14; + + switch (HeightSize) { + case HeightSize.WindowHeight: + if (Console.WindowHeight > 0) { + // Can raise an exception while is still resizing. + try { + // Not supported on Unix. + if (isWinPlatform) { + Console.CursorTop = 0; + Console.CursorLeft = 0; + Console.WindowTop = 0; + Console.WindowLeft = 0; + Console.SetBufferSize (Math.Max (Min_WindowWidth, Console.WindowWidth), + Console.WindowHeight); + } else { + //Console.Out.Write ($"\x1b[8;{Console.WindowHeight};{Console.WindowWidth}t"); + //Console.Out.Flush (); + Console.Out.Write ($"\x1b[0;0" + + $";{Console.WindowHeight};" + + $"{Math.Max (Min_WindowWidth, Console.WindowWidth)}w"); + } + } catch (System.IO.IOException) { + return; + } catch (ArgumentOutOfRangeException) { + return; + } + } + cols = Console.WindowWidth; + rows = Console.WindowHeight; + top = 0; + break; + case HeightSize.BufferHeight: + if (isWinPlatform && Console.WindowHeight > 0) { + if (isWinPlatform) { + // Can raise an exception while is still resizing. + try { + Console.WindowTop = Math.Max (Math.Min (top, Console.BufferHeight - Console.WindowHeight), 0); + } catch (Exception) { + return; + } + } + } else { + Console.Out.Write ($"\x1b[{top};{Console.WindowLeft}" + + $";{Console.BufferHeight}" + + $";{Math.Max (Min_WindowWidth, Console.BufferWidth)}w"); + } + cols = Console.BufferWidth; + rows = Console.BufferHeight; + break; + } Clip = new Rect (0, 0, Cols, Rows); - top = Console.WindowTop; } public override Attribute MakeAttribute (Color fore, Color back) @@ -196,29 +233,40 @@ namespace Terminal.Gui { public override void UpdateScreen () { - if (Rows == 0) { + if (winChanging || Console.WindowHeight == 0 + || (HeightSize == HeightSize.WindowHeight && Rows != Console.WindowHeight) + || (HeightSize == HeightSize.BufferHeight && Rows != Console.BufferHeight)) { return; } - int rows = Rows; + int top = Top; + int rows = Math.Min (Console.WindowHeight + top, Rows); int cols = Cols; for (int row = top; row < rows; row++) { - if (!dirtyLine [row]) + if (!dirtyLine [row]) { continue; + } dirtyLine [row] = false; + int [,,] damage = new int [0, 0, 0]; for (int col = 0; col < cols; col++) { - if (contents [row, col, 2] != 1) + if (contents [row, col, 2] != 1) { continue; + } if (Console.WindowHeight > 0) { - Console.SetCursorPosition (col, row); + // Could happens that the windows is still resizing and the col is bigger than Console.WindowWidth. + try { + Console.SetCursorPosition (col, row); + } catch (Exception) { + return; + } } for (; col < cols && contents [row, col, 2] == 1; col++) { var color = contents [row, col, 1]; - if (color != redrawColor) + if (color != redrawColor) { SetColor (color); - + } Console.Write ((char)contents [row, col, 0]); contents [row, col, 2] = 0; } @@ -230,12 +278,6 @@ namespace Terminal.Gui { public override void Refresh () { - if (Console.WindowWidth != Cols || Console.WindowHeight != Rows || Console.WindowTop != Top) { - ResizeScreen (); - UpdateOffscreen (); - TerminalResized.Invoke (); - } - UpdateScreen (); } @@ -243,10 +285,12 @@ namespace Terminal.Gui { { // Prevents the exception of size changing during resizing. try { - if (ccol > 0 && ccol < Console.WindowWidth && crow > 0 && crow < Console.WindowHeight) { + if (ccol >= 0 && ccol <= cols && crow >= 0 && crow <= rows) { Console.SetCursorPosition (ccol, crow); } - } catch (ArgumentOutOfRangeException) { } + } catch (System.IO.IOException) { + } catch (ArgumentOutOfRangeException) { + } } public override void StartReportingMouseMoves () @@ -377,10 +421,11 @@ namespace Terminal.Gui { keyModifiers.Alt = true; } + bool winChanging; public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { // Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called - (mainLoop.Driver as NetMainLoop).KeyPressed = delegate (ConsoleKeyInfo consoleKey) { + (mainLoop.Driver as NetMainLoop).KeyPressed = (consoleKey) => { var map = MapKey (consoleKey); if (map == (Key)0xffffffff) { return; @@ -389,16 +434,23 @@ namespace Terminal.Gui { keyUpHandler (new KeyEvent (map, keyModifiers)); keyModifiers = null; }; + + (mainLoop.Driver as NetMainLoop).WinChanged = (e) => { + winChanging = true; + top = e; + ResizeScreen (); + UpdateOffscreen (); + winChanging = false; + TerminalResized.Invoke (); + }; } public override void SetColors (ConsoleColor foreground, ConsoleColor background) { - throw new NotImplementedException (); } public override void SetColors (short foregroundColorId, short backgroundColorId) { - throw new NotImplementedException (); } public override void CookMouse () @@ -424,14 +476,15 @@ namespace Terminal.Gui { /// /// This implementation is used for NetDriver. /// - public class NetMainLoop : IMainLoopDriver { + internal class NetMainLoop : IMainLoopDriver { ManualResetEventSlim keyReady = new ManualResetEventSlim (false); ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false); ManualResetEventSlim winChange = new ManualResetEventSlim (false); - ConsoleKeyInfo? keyResult = null; + Queue keyResult = new Queue (); MainLoop mainLoop; ConsoleDriver consoleDriver; bool winChanged; + int newTop; CancellationTokenSource tokenSource = new CancellationTokenSource (); /// @@ -439,6 +492,8 @@ namespace Terminal.Gui { /// public Action KeyPressed; + public Action WinChanged; + /// /// Initializes the class with the console driver. /// @@ -449,7 +504,7 @@ namespace Terminal.Gui { public NetMainLoop (ConsoleDriver consoleDriver = null) { if (consoleDriver == null) { - throw new ArgumentNullException ("console driver instance must be provided."); + throw new ArgumentNullException ("Console driver instance must be provided."); } this.consoleDriver = consoleDriver; } @@ -459,7 +514,9 @@ namespace Terminal.Gui { while (true) { waitForProbe.Wait (); waitForProbe.Reset (); - keyResult = Console.ReadKey (true); + if (keyResult.Count == 0) { + keyResult.Enqueue (Console.ReadKey (true)); + } keyReady.Set (); } } @@ -478,9 +535,19 @@ namespace Terminal.Gui { void WaitWinChange () { while (true) { - if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows - || Console.WindowTop != consoleDriver.Top) { // Top only working on Windows. - return; + switch (consoleDriver.HeightSize) { + case HeightSize.WindowHeight: + if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows) { + return; + } + break; + case HeightSize.BufferHeight: + if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows + || Console.WindowTop != consoleDriver.Top) { + newTop = Console.WindowTop; + return; + } + break; } } } @@ -499,8 +566,6 @@ namespace Terminal.Gui { bool IMainLoopDriver.EventsPending (bool wait) { - long now = DateTime.UtcNow.Ticks; - waitForProbe.Set (); winChange.Set (); @@ -519,7 +584,7 @@ namespace Terminal.Gui { } if (!tokenSource.IsCancellationRequested) { - return keyResult.HasValue || CheckTimers (wait, out _) || winChanged; + return keyResult.Count > 0 || CheckTimers (wait, out _) || winChanged; } tokenSource.Dispose (); @@ -552,14 +617,12 @@ namespace Terminal.Gui { void IMainLoopDriver.MainIteration () { - if (keyResult.HasValue) { - var kr = keyResult; - keyResult = null; - KeyPressed?.Invoke (kr.Value); + if (keyResult.Count > 0) { + KeyPressed?.Invoke (keyResult.Dequeue ().Value); } if (winChanged) { winChanged = false; - consoleDriver.Refresh (); + WinChanged.Invoke (newTop); } } } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 714a6a76f..f02e1ed8e 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -207,7 +207,7 @@ namespace Terminal.Gui { public override string ToString () => $"({X},{Y})"; }; - internal struct WindowBufferSizeRecord { + public struct WindowBufferSizeRecord { public Coordinate size; public WindowBufferSizeRecord (short x, short y) @@ -355,6 +355,20 @@ namespace Terminal.Gui { } } + [StructLayout (LayoutKind.Sequential)] + public struct ConsoleKeyInfoEx { + public ConsoleKeyInfo consoleKeyInfo; + public bool CapsLock; + public bool NumLock; + + public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock) + { + this.consoleKeyInfo = consoleKeyInfo; + CapsLock = capslock; + NumLock = numlock; + } + } + [DllImport ("kernel32.dll", SetLastError = true)] static extern IntPtr GetStdHandle (int nStdHandle); @@ -431,14 +445,15 @@ namespace Terminal.Gui { return numberEventsRead == 0 ? null - : new [] {Marshal.PtrToStructure (pRecord)}; + : new [] { Marshal.PtrToStructure (pRecord) }; } catch (Exception) { return null; } finally { Marshal.FreeHGlobal (pRecord); } } -#if false // Not needed on the constructor. Perhaps could be used on resizing. To study. + +#if false // Not needed on the constructor. Perhaps could be used on resizing. To study. [DllImport ("kernel32.dll", ExactSpelling = true)] private static extern IntPtr GetConsoleWindow (); @@ -498,19 +513,17 @@ namespace Terminal.Gui { #endif } - internal class WindowsDriver : ConsoleDriver, IMainLoopDriver { + internal class WindowsDriver : ConsoleDriver { static bool sync = false; - ManualResetEventSlim eventReady = new ManualResetEventSlim (false); - ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false); - MainLoop mainLoop; WindowsConsole.CharInfo [] OutputBuffer; - int cols, rows; + int cols, rows, top; WindowsConsole winConsole; WindowsConsole.SmallRect damageRegion; public override int Cols => cols; public override int Rows => rows; - public override int Top => 0; + public override int Top => top; + public override HeightSize HeightSize { get; set; } public WindowsDriver () { @@ -527,8 +540,11 @@ namespace Terminal.Gui { ResizeScreen (); UpdateOffScreen (); + } - Task.Run ((Action)WindowsInputHandler); + public WindowsConsole WinConsole { + get => winConsole; + private set => winConsole = value; } private void SetupColorsAndBorders () @@ -566,98 +582,6 @@ namespace Terminal.Gui { Colors.Error.HotFocus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkRed); } - [StructLayout (LayoutKind.Sequential)] - public struct ConsoleKeyInfoEx { - public ConsoleKeyInfo consoleKeyInfo; - public bool CapsLock; - public bool NumLock; - - public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock) - { - this.consoleKeyInfo = consoleKeyInfo; - CapsLock = capslock; - NumLock = numlock; - } - } - - // The records that we keep fetching - WindowsConsole.InputRecord [] result, records = new WindowsConsole.InputRecord [1]; - - void WindowsInputHandler () - { - while (true) { - waitForProbe.Wait (); - waitForProbe.Reset (); - - result = winConsole.ReadConsoleInput (); - - eventReady.Set (); - } - } - - void IMainLoopDriver.Setup (MainLoop mainLoop) - { - this.mainLoop = mainLoop; - } - - void IMainLoopDriver.Wakeup () - { - //tokenSource.Cancel (); - eventReady.Reset (); - eventReady.Set (); - } - - bool IMainLoopDriver.EventsPending (bool wait) - { - if (CheckTimers (wait, out var waitTimeout)) { - return true; - } - - result = null; - waitForProbe.Set (); - - try { - if (!tokenSource.IsCancellationRequested) { - eventReady.Wait (waitTimeout, tokenSource.Token); - } - } catch (OperationCanceledException) { - return true; - } finally { - eventReady.Reset (); - } - - if (!tokenSource.IsCancellationRequested) { - return result != null || CheckTimers (wait, out waitTimeout); - } - - tokenSource.Dispose (); - tokenSource = new CancellationTokenSource (); - return true; - } - - bool CheckTimers (bool wait, out int waitTimeout) - { - long now = DateTime.UtcNow.Ticks; - - 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; - - int ic; - lock (mainLoop.idleHandlers) { - ic = mainLoop.idleHandlers.Count; - } - - return ic > 0; - } - Action keyHandler; Action keyDownHandler; Action keyUpHandler; @@ -669,14 +593,12 @@ namespace Terminal.Gui { this.keyDownHandler = keyDownHandler; this.keyUpHandler = keyUpHandler; this.mouseHandler = mouseHandler; + + (mainLoop.Driver as WindowsMainLoop).ProcessInput = (e) => ProcessInput (e); } - void IMainLoopDriver.MainIteration () + void ProcessInput (WindowsConsole.InputRecord inputEvent) { - if (result == null) - return; - - var inputEvent = result [0]; switch (inputEvent.EventType) { case WindowsConsole.EventType.Key: var map = MapKey (ToConsoleKeyInfoEx (inputEvent.KeyEvent)); @@ -775,11 +697,7 @@ namespace Terminal.Gui { case WindowsConsole.EventType.Focus: break; - - default: - break; } - result = null; } WindowsConsole.ButtonState? LastMouseButtonPressed = null; @@ -871,23 +789,23 @@ namespace Terminal.Gui { Y = mouseEvent.MousePosition.Y }; //if (p == point) { - switch (LastMouseButtonPressed) { - case WindowsConsole.ButtonState.Button1Pressed: - mouseFlag = MouseFlags.Button1Clicked; - break; + switch (LastMouseButtonPressed) { + case WindowsConsole.ButtonState.Button1Pressed: + mouseFlag = MouseFlags.Button1Clicked; + break; - case WindowsConsole.ButtonState.Button2Pressed: - mouseFlag = MouseFlags.Button2Clicked; - break; + case WindowsConsole.ButtonState.Button2Pressed: + mouseFlag = MouseFlags.Button2Clicked; + break; - case WindowsConsole.ButtonState.RightmostButtonPressed: - mouseFlag = MouseFlags.Button3Clicked; - break; - } - point = new Point () { - X = mouseEvent.MousePosition.X, - Y = mouseEvent.MousePosition.Y - }; + case WindowsConsole.ButtonState.RightmostButtonPressed: + mouseFlag = MouseFlags.Button3Clicked; + break; + } + point = new Point () { + X = mouseEvent.MousePosition.X, + Y = mouseEvent.MousePosition.Y + }; //} else { // mouseFlag = 0; //} @@ -1009,7 +927,7 @@ namespace Terminal.Gui { KeyModifiers keyModifiers; - public ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEventRecord keyEvent) + public WindowsConsole.ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEventRecord keyEvent) { var state = keyEvent.dwControlKeyState; @@ -1036,10 +954,10 @@ namespace Terminal.Gui { keyModifiers.Scrolllock = scrolllock; var ConsoleKeyInfo = new ConsoleKeyInfo (keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control); - return new ConsoleKeyInfoEx (ConsoleKeyInfo, capslock, numlock); + return new WindowsConsole.ConsoleKeyInfoEx (ConsoleKeyInfo, capslock, numlock); } - public Key MapKey (ConsoleKeyInfoEx keyInfoEx) + public Key MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx) { var keyInfo = keyInfoEx.consoleKeyInfo; switch (keyInfo.Key) { @@ -1245,7 +1163,6 @@ namespace Terminal.Gui { } int currentAttribute; - CancellationTokenSource tokenSource = new CancellationTokenSource (); public override void SetAttribute (Attribute c) { @@ -1325,7 +1242,7 @@ namespace Terminal.Gui { winConsole.Cleanup (); } -#region Unused + #region Unused public override void SetColors (ConsoleColor foreground, ConsoleColor background) { } @@ -1353,8 +1270,156 @@ namespace Terminal.Gui { public override void CookMouse () { } -#endregion - + #endregion } + /// + /// Mainloop intended to be used with the , and can + /// only be used on Windows. + /// + /// + /// This implementation is used for WindowsDriver. + /// + internal class WindowsMainLoop : IMainLoopDriver { + ManualResetEventSlim eventReady = new ManualResetEventSlim (false); + ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false); + ManualResetEventSlim winChange = new ManualResetEventSlim (false); + MainLoop mainLoop; + ConsoleDriver consoleDriver; + WindowsConsole winConsole; + bool winChanged; + CancellationTokenSource tokenSource = new CancellationTokenSource (); + + // The records that we keep fetching + WindowsConsole.InputRecord [] result = new WindowsConsole.InputRecord [1]; + + /// + /// Invoked when a Key is pressed or released. + /// + public Action ProcessInput; + + public WindowsMainLoop (ConsoleDriver consoleDriver = null) + { + this.consoleDriver = consoleDriver; + winConsole = ((WindowsDriver)consoleDriver).WinConsole; + } + + void IMainLoopDriver.Setup (MainLoop mainLoop) + { + this.mainLoop = mainLoop; + Task.Run ((Action)WindowsInputHandler); + Task.Run (CheckWinChange); + } + + void WindowsInputHandler () + { + while (true) { + waitForProbe.Wait (); + waitForProbe.Reset (); + + result = winConsole.ReadConsoleInput (); + + eventReady.Set (); + } + } + + void CheckWinChange () + { + while (true) { + winChange.Wait (); + winChange.Reset (); + WaitWinChange (); + winChanged = true; + eventReady.Set (); + } + } + + void WaitWinChange () + { + while (true) { + switch (consoleDriver.HeightSize) { + case HeightSize.WindowHeight: + if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows + || Console.WindowTop != consoleDriver.Top) { // Top only working on Windows. + return; + } + break; + case HeightSize.BufferHeight: + if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows) { + return; + } + break; + } + } + } + + void IMainLoopDriver.Wakeup () + { + //tokenSource.Cancel (); + eventReady.Reset (); + eventReady.Set (); + } + + bool IMainLoopDriver.EventsPending (bool wait) + { + if (CheckTimers (wait, out var waitTimeout)) { + return true; + } + + //result = null; + waitForProbe.Set (); + winChange.Set (); + + try { + if (!tokenSource.IsCancellationRequested) { + eventReady.Wait (waitTimeout, tokenSource.Token); + } + } catch (OperationCanceledException) { + return true; + } finally { + eventReady.Reset (); + } + + if (!tokenSource.IsCancellationRequested) { + return result != null || CheckTimers (wait, out waitTimeout); + } + + tokenSource.Dispose (); + tokenSource = new CancellationTokenSource (); + return true; + } + + bool CheckTimers (bool wait, out int waitTimeout) + { + long now = DateTime.UtcNow.Ticks; + + 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; + + int ic; + lock (mainLoop.idleHandlers) { + ic = mainLoop.idleHandlers.Count; + } + + return ic > 0; + } + + void IMainLoopDriver.MainIteration () + { + if (result == null) + return; + + var inputEvent = result [0]; + result = null; + ProcessInput.Invoke (inputEvent); + } + } } diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 51c4dc941..d30bf1b94 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -59,7 +59,7 @@ namespace Terminal.Gui { /// The current in use. /// public static ConsoleDriver Driver; - + /// /// The object used for the application on startup () /// @@ -73,11 +73,32 @@ namespace Terminal.Gui { public static Toplevel Current { get; private set; } /// - /// TThe current object being redrawn. + /// The current object being redrawn. /// /// /// The current. public static View CurrentView { get; set; } + /// + /// The current used in the terminal. + /// + public static HeightSize HeightSize { + get { + if (Driver == null) { + throw new ArgumentNullException ("The driver must be initialized first."); + } + return Driver.HeightSize; + } + set { + if (Driver == null) { + throw new ArgumentNullException ("The driver must be initialized first."); + } + if (Driver.HeightSize != value) { + Driver.HeightSize = value; + Driver.Refresh (); + } + } + } + /// /// The driver for the application /// @@ -167,7 +188,7 @@ namespace Terminal.Gui { static void Init (Func topLevelFactory, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null) { if (_initialized && driver == null) return; - + // Used only for start debugging on Unix. //#if DEBUG // while (!System.Diagnostics.Debugger.IsAttached) { @@ -193,9 +214,8 @@ namespace Terminal.Gui { Driver = new NetDriver (); mainLoopDriver = new NetMainLoop (Driver); } else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) { - var windowsDriver = new WindowsDriver (); - mainLoopDriver = windowsDriver; - Driver = windowsDriver; + Driver = new WindowsDriver (); + mainLoopDriver = new WindowsMainLoop (Driver); } else { mainLoopDriver = new UnixMainLoop (); Driver = new CursesDriver (); diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index c0084e9ce..093db0d60 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -458,6 +458,20 @@ namespace Terminal.Gui { public static Dictionary ColorSchemes { get; } } + /// + /// The visible height should be used on the window. + /// + public enum HeightSize { + /// + /// Only window height will be visible not allowing scroll. + /// + WindowHeight, + /// + /// All buffer height will be visible allowing scroll. + /// + BufferHeight + } + ///// ///// Special characters that can be drawn with ///// @@ -546,6 +560,11 @@ namespace Terminal.Gui { /// public abstract int Top { get; } + /// + /// The current used in the terminal. + /// + public abstract HeightSize HeightSize { get; set; } + /// /// Initializes the driver /// diff --git a/UICatalog/Scenarios/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap.cs index 849978f26..ca60f4874 100644 --- a/UICatalog/Scenarios/CharacterMap.cs +++ b/UICatalog/Scenarios/CharacterMap.cs @@ -1,4 +1,7 @@ -using NStack; +#define DRAW_CONTENT +//#define BASE_DRAW_CONTENT + +using NStack; using System.Collections.Generic; using System.Linq; using System.Text; @@ -58,15 +61,19 @@ namespace UICatalog { CreateRadio("End", CharMap.MaxCodePointVal - 16, CharMap.MaxCodePointVal), }; - var jumpList = new RadioGroup (radioItems.Select (t => t.radioLabel).ToArray ()); - jumpList.X = Pos.X (label); - jumpList.Y = Pos.Bottom (label); - jumpList.Width = Dim.Fill (); + var jumpList = new RadioGroup (radioItems.Select (t => t.radioLabel).ToArray ()) { + X = Pos.X (label), + Y = Pos.Bottom (label), + Width = Dim.Fill (), + SelectedItem = 8 + }; jumpList.SelectedItemChanged += (args) => { - _charMap.Start = radioItems[args.SelectedItem].start; + _charMap.Start = radioItems [args.SelectedItem].start; }; Win.Add (jumpList); + + jumpList.Refresh (); } public override void Run () @@ -91,11 +98,14 @@ namespace UICatalog { } int _start = 0x2500; + public const int H_SPACE = 2; + public const int V_SPACE = 2; + public static int MaxCodePointVal => 0xE0FFF; // Row Header + space + (space + char + space) public static int RowHeaderWidth => $"U+{MaxCodePointVal:x5}".Length; - public static int RowWidth => RowHeaderWidth + (" c".Length * 16); + public static int RowWidth => RowHeaderWidth + (H_SPACE * 16); public CharMap () { @@ -109,10 +119,12 @@ namespace UICatalog { ShowHorizontalScrollIndicator = false; } }; +#if DRAW_CONTENT DrawContent += CharMap_DrawContent; +#endif } -#if true + private void CharMap_DrawContent (Rect viewport) { //Rune ReplaceNonPrintables (Rune c) @@ -125,10 +137,10 @@ namespace UICatalog { //} for (int header = 0; header < 16; header++) { - Move (viewport.X + RowHeaderWidth + (header * 2), 0); + Move (viewport.X + RowHeaderWidth + (header * H_SPACE), 0); Driver.AddStr ($" {header:x} "); } - for (int row = 0, y = 0; row < viewport.Height / 2 - 1; row++, y += 2) { + for (int row = 0, y = 0; row < viewport.Height / 2 - 1; row++, y+= V_SPACE) { int val = (-viewport.Y + row) * 16; if (val < MaxCodePointVal) { var rowLabel = $"U+{val / 16:x4}x"; @@ -137,17 +149,17 @@ namespace UICatalog { var prevColWasWide = false; for (int col = 0; col < 16; col++) { var rune = new Rune ((uint)((uint)(-viewport.Y + row) * 16 + col)); - Move (viewport.X + RowHeaderWidth + (col * 2) + (prevColWasWide ? 0 : 1), 0 + y + 1); + Move (viewport.X + RowHeaderWidth + (col * H_SPACE) + (prevColWasWide ? 0 : 1), y + 1); Driver.AddRune (rune); - //prevColWasWide = Rune.ColumnWidth(rune) > 1; + //prevColWasWide = Rune.ColumnWidth (rune) > 1; } } } } -#else +#if BASE_DRAW_CONTENT public override void OnDrawContent (Rect viewport) { - CharMap_DrawContent(this, viewport); + CharMap_DrawContent (viewport); base.OnDrawContent (viewport); } #endif From d8fbd3efb27d257b4b1bac6d9936091abb6831c4 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 24 Nov 2020 01:42:11 +0000 Subject: [PATCH 02/15] True font types has its own non printable characters and we should use them. --- Terminal.Gui/Core/ConsoleDriver.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 093db0d60..68cfb1dc2 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -589,12 +589,10 @@ namespace Terminal.Gui { /// public static Rune MakePrintable (Rune c) { - if (c <= 0x1F) { - // ASCII (C0) control characters. - return new Rune (c + 0x2400); - } else if (c >= 0x80 && c <= 0x9F) { + if (c <= 0x1F || (c >= 0x80 && c <= 0x9F)) { + // ASCII (C0) control characters. // C1 control characters (https://www.aivosto.com/articles/control-characters.html#c1) - return new Rune (0x25a1); // U+25A1, WHITE SQUARE, □: + return new Rune (c + 0x2400); } else { return c; } From 934c0b962930f84767cb36a3c66ad3a687ed5136 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 24 Nov 2020 01:59:47 +0000 Subject: [PATCH 03/15] isWinPlatform was written twice. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 59a9b1375..0793741a0 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -191,13 +191,11 @@ namespace Terminal.Gui { break; case HeightSize.BufferHeight: if (isWinPlatform && Console.WindowHeight > 0) { - if (isWinPlatform) { - // Can raise an exception while is still resizing. - try { - Console.WindowTop = Math.Max (Math.Min (top, Console.BufferHeight - Console.WindowHeight), 0); - } catch (Exception) { - return; - } + // Can raise an exception while is still resizing. + try { + Console.WindowTop = Math.Max (Math.Min (top, Console.BufferHeight - Console.WindowHeight), 0); + } catch (Exception) { + return; } } else { Console.Out.Write ($"\x1b[{top};{Console.WindowLeft}" + From b6cb860b7328d05a08d267b27eb9c74cb94c5662 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 24 Nov 2020 16:10:07 +0000 Subject: [PATCH 04/15] Disabling supported operation system warnings. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 0793741a0..8e88b2b86 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -166,12 +166,14 @@ namespace Terminal.Gui { try { // Not supported on Unix. if (isWinPlatform) { +#pragma warning disable CA1416 Console.CursorTop = 0; Console.CursorLeft = 0; Console.WindowTop = 0; Console.WindowLeft = 0; Console.SetBufferSize (Math.Max (Min_WindowWidth, Console.WindowWidth), Console.WindowHeight); +#pragma warning restore CA1416 } else { //Console.Out.Write ($"\x1b[8;{Console.WindowHeight};{Console.WindowWidth}t"); //Console.Out.Flush (); @@ -193,7 +195,9 @@ namespace Terminal.Gui { if (isWinPlatform && Console.WindowHeight > 0) { // Can raise an exception while is still resizing. try { +#pragma warning disable CA1416 Console.WindowTop = Math.Max (Math.Min (top, Console.BufferHeight - Console.WindowHeight), 0); +#pragma warning restore CA1416 } catch (Exception) { return; } From a7c2847256e637799c1f4328ca031b28751506db Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 24 Nov 2020 21:55:29 +0000 Subject: [PATCH 05/15] Fixes Console.WindowHeight detection when HeightSize.BufferHeight is set. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 5 ++++- UICatalog/Scenarios/CharacterMap.cs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 8e88b2b86..31895a074 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -534,6 +534,7 @@ namespace Terminal.Gui { } } + int lastWindowHeight; void WaitWinChange () { while (true) { @@ -545,8 +546,10 @@ namespace Terminal.Gui { break; case HeightSize.BufferHeight: if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows - || Console.WindowTop != consoleDriver.Top) { + || Console.WindowTop != consoleDriver.Top + || Console.WindowHeight != lastWindowHeight) { newTop = Console.WindowTop; + lastWindowHeight = Console.WindowHeight; return; } break; diff --git a/UICatalog/Scenarios/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap.cs index ca60f4874..923a61f60 100644 --- a/UICatalog/Scenarios/CharacterMap.cs +++ b/UICatalog/Scenarios/CharacterMap.cs @@ -74,6 +74,7 @@ namespace UICatalog { Win.Add (jumpList); jumpList.Refresh (); + jumpList.SetFocus (); } public override void Run () From 148a8133656e99b83e2c40c8ac01526021587549 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 25 Nov 2020 19:31:55 +0000 Subject: [PATCH 06/15] NetDriver now process the hot keys and shortcut keys. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 171 ++++++++++++------- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 109 ++++++------ Terminal.Gui/Core/Toplevel.cs | 29 ---- Terminal.Gui/Core/View.cs | 27 ++- 4 files changed, 184 insertions(+), 152 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 31895a074..2efb3d12d 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -24,23 +24,6 @@ namespace Terminal.Gui { int [,,] contents; bool [] dirtyLine; - void UpdateOffscreen () - { - int cols = Cols; - int rows = Rows; - - contents = new int [rows, cols, 3]; - dirtyLine = new bool [rows]; - for (int row = 0; row < rows; row++) { - for (int c = 0; c < cols; c++) { - contents [row, c, 0] = ' '; - contents [row, c, 1] = (ushort)Colors.TopLevel.Normal; - contents [row, c, 2] = 0; - dirtyLine [row] = true; - } - } - } - static bool sync = false; // Current row, and current col, tracked by Move/AddCh only @@ -65,7 +48,11 @@ namespace Terminal.Gui { if (runeWidth > 1) { for (int i = 1; i < runeWidth; i++) { contents [crow, ccol, 2] = 0; - ccol++; + if (ccol + 1 < cols) { + ccol++; + } else { + break; + } } } //if (ccol == Cols) { @@ -108,12 +95,20 @@ namespace Terminal.Gui { public override void Init (Action terminalResized) { TerminalResized = terminalResized; + Console.TreatControlCAsInput = true; var p = Environment.OSVersion.Platform; if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) { isWinPlatform = true; } + cols = Console.WindowWidth; + rows = Console.WindowHeight; + + Clear (); + ResizeScreen (); + UpdateOffscreen (); + Colors.TopLevel = new ColorScheme (); Colors.Base = new ColorScheme (); Colors.Dialog = new ColorScheme (); @@ -150,15 +145,10 @@ namespace Terminal.Gui { Colors.Error.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red); Colors.Error.HotFocus = Colors.Error.HotNormal; - Clear (); - ResizeScreen (); - UpdateOffscreen (); } void ResizeScreen () { - const int Min_WindowWidth = 14; - switch (HeightSize) { case HeightSize.WindowHeight: if (Console.WindowHeight > 0) { @@ -171,15 +161,12 @@ namespace Terminal.Gui { Console.CursorLeft = 0; Console.WindowTop = 0; Console.WindowLeft = 0; - Console.SetBufferSize (Math.Max (Min_WindowWidth, Console.WindowWidth), - Console.WindowHeight); + Console.SetBufferSize (Cols, Rows); #pragma warning restore CA1416 } else { //Console.Out.Write ($"\x1b[8;{Console.WindowHeight};{Console.WindowWidth}t"); - //Console.Out.Flush (); Console.Out.Write ($"\x1b[0;0" + - $";{Console.WindowHeight};" + - $"{Math.Max (Min_WindowWidth, Console.WindowWidth)}w"); + $";{Rows};{Cols}w"); } } catch (System.IO.IOException) { return; @@ -187,30 +174,47 @@ namespace Terminal.Gui { return; } } - cols = Console.WindowWidth; - rows = Console.WindowHeight; - top = 0; break; case HeightSize.BufferHeight: if (isWinPlatform && Console.WindowHeight > 0) { // Can raise an exception while is still resizing. try { #pragma warning disable CA1416 - Console.WindowTop = Math.Max (Math.Min (top, Console.BufferHeight - Console.WindowHeight), 0); + Console.WindowTop = Math.Max (Math.Min (top, Rows - Console.WindowHeight), 0); #pragma warning restore CA1416 } catch (Exception) { return; } } else { Console.Out.Write ($"\x1b[{top};{Console.WindowLeft}" + - $";{Console.BufferHeight}" + - $";{Math.Max (Min_WindowWidth, Console.BufferWidth)}w"); + $";{Rows};{Cols}w"); } - cols = Console.BufferWidth; - rows = Console.BufferHeight; break; } Clip = new Rect (0, 0, Cols, Rows); + + contents = new int [Rows, Cols, 3]; + dirtyLine = new bool [Rows]; + + winChanging = false; + } + + void UpdateOffscreen () + { + if (!winChanging) { + return; + } + // Can raise an exception while is still resizing. + try { + for (int row = 0; row < rows; row++) { + for (int c = 0; c < cols; c++) { + contents [row, c, 0] = ' '; + contents [row, c, 1] = (ushort)Colors.TopLevel.Normal; + contents [row, c, 2] = 0; + dirtyLine [row] = true; + } + } + } catch (IndexOutOfRangeException) { } } public override Attribute MakeAttribute (Color fore, Color back) @@ -315,36 +319,39 @@ namespace Terminal.Gui { Key MapKey (ConsoleKeyInfo keyInfo) { - MapKeyModifiers (keyInfo); + MapKeyModifiers (keyInfo, (Key)keyInfo.Key); switch (keyInfo.Key) { case ConsoleKey.Escape: - return Key.Esc; + return MapKeyModifiers (keyInfo, Key.Esc); case ConsoleKey.Tab: return keyInfo.Modifiers == ConsoleModifiers.Shift ? Key.BackTab : Key.Tab; case ConsoleKey.Home: - return Key.Home; + return MapKeyModifiers (keyInfo, Key.Home); case ConsoleKey.End: - return Key.End; + return MapKeyModifiers (keyInfo, Key.End); case ConsoleKey.LeftArrow: - return Key.CursorLeft; + return MapKeyModifiers (keyInfo, Key.CursorLeft); case ConsoleKey.RightArrow: - return Key.CursorRight; + return MapKeyModifiers (keyInfo, Key.CursorRight); case ConsoleKey.UpArrow: - return Key.CursorUp; + return MapKeyModifiers (keyInfo, Key.CursorUp); case ConsoleKey.DownArrow: - return Key.CursorDown; + return MapKeyModifiers (keyInfo, Key.CursorDown); case ConsoleKey.PageUp: - return Key.PageUp; + return MapKeyModifiers (keyInfo, Key.PageUp); case ConsoleKey.PageDown: - return Key.PageDown; + return MapKeyModifiers (keyInfo, Key.PageDown); case ConsoleKey.Enter: - return Key.Enter; + return MapKeyModifiers (keyInfo, Key.Enter); case ConsoleKey.Spacebar: - return Key.Space; + return MapKeyModifiers (keyInfo, Key.Space); case ConsoleKey.Backspace: - return Key.Backspace; + return MapKeyModifiers (keyInfo, Key.Backspace); case ConsoleKey.Delete: - return Key.Delete; + return MapKeyModifiers (keyInfo, Key.DeleteChar); + case ConsoleKey.Insert: + return MapKeyModifiers (keyInfo, Key.InsertChar); + case ConsoleKey.Oem1: case ConsoleKey.Oem2: @@ -373,7 +380,7 @@ namespace Terminal.Gui { } if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) { if (keyInfo.KeyChar == 0 || (keyInfo.KeyChar != 0 && keyInfo.KeyChar >= 1 && keyInfo.KeyChar <= 26)) { - return (Key)((uint)Key.A + delta); + return MapKeyModifiers (keyInfo, (Key)((uint)Key.A + delta)); } } return (Key)((uint)keyInfo.KeyChar); @@ -388,7 +395,7 @@ namespace Terminal.Gui { } if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) { if (keyInfo.KeyChar == 0 || keyInfo.KeyChar == 30) { - return (Key)((uint)Key.D0 + delta); + return MapKeyModifiers (keyInfo, (Key)((uint)Key.D0 + delta)); } } return (Key)((uint)keyInfo.KeyChar); @@ -396,7 +403,7 @@ namespace Terminal.Gui { if (key >= ConsoleKey.F1 && key <= ConsoleKey.F12) { var delta = key - ConsoleKey.F1; if ((keyInfo.Modifiers & (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) { - return (Key)((uint)Key.F1 + delta); + return MapKeyModifiers (keyInfo, (Key)((uint)Key.F1 + delta)); } return (Key)((uint)Key.F1 + delta); @@ -410,17 +417,26 @@ namespace Terminal.Gui { KeyModifiers keyModifiers; - void MapKeyModifiers (ConsoleKeyInfo keyInfo) + Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key) { - if (keyModifiers == null) + if (keyModifiers == null) { keyModifiers = new KeyModifiers (); - - if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0) + } + Key keyMod = new Key (); + if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0) { + keyMod = Key.ShiftMask; keyModifiers.Shift = true; - if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0) + } + if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0) { + keyMod |= Key.CtrlMask; keyModifiers.Ctrl = true; - if ((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0) + } + if ((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0) { + keyMod |= Key.AltMask; keyModifiers.Alt = true; + } + + return keyMod != Key.Null ? keyMod | key : key; } bool winChanging; @@ -432,18 +448,43 @@ namespace Terminal.Gui { if (map == (Key)0xffffffff) { return; } - keyHandler (new KeyEvent (map, keyModifiers)); - keyUpHandler (new KeyEvent (map, keyModifiers)); - keyModifiers = null; + + if (map == (Key.Space | Key.CtrlMask) || map == (Key.Space | Key.AltMask)) { + map = Key.AltMask; + keyModifiers.Alt = true; + keyModifiers.Ctrl = false; + keyDownHandler (new KeyEvent (map, keyModifiers)); + keyUpHandler (new KeyEvent (map, keyModifiers)); + } else { + keyDownHandler (new KeyEvent (map, keyModifiers)); + keyHandler (new KeyEvent (map, keyModifiers)); + keyUpHandler (new KeyEvent (map, keyModifiers)); + } + keyModifiers = new KeyModifiers (); }; (mainLoop.Driver as NetMainLoop).WinChanged = (e) => { winChanging = true; - top = e; + const int Min_WindowWidth = 14; + Size size = new Size (); + switch (HeightSize) { + case HeightSize.WindowHeight: + size = new Size (Math.Max (Min_WindowWidth, Console.WindowWidth), + Console.WindowHeight); + top = 0; + break; + case HeightSize.BufferHeight: + size = new Size (Console.BufferWidth, Console.BufferHeight); + top = e; + break; + } + cols = size.Width; + rows = size.Height; ResizeScreen (); UpdateOffscreen (); - winChanging = false; - TerminalResized.Invoke (); + if (!winChanging) { + TerminalResized.Invoke (); + } }; } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index f02e1ed8e..76f3288b3 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -455,10 +455,10 @@ namespace Terminal.Gui { #if false // Not needed on the constructor. Perhaps could be used on resizing. To study. [DllImport ("kernel32.dll", ExactSpelling = true)] - private static extern IntPtr GetConsoleWindow (); + static extern IntPtr GetConsoleWindow (); [DllImport ("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - private static extern bool ShowWindow (IntPtr hWnd, int nCmdShow); + static extern bool ShowWindow (IntPtr hWnd, int nCmdShow); public const int HIDE = 0; public const int MAXIMIZE = 3; @@ -525,68 +525,21 @@ namespace Terminal.Gui { public override int Top => top; public override HeightSize HeightSize { get; set; } - public WindowsDriver () - { - winConsole = new WindowsConsole (); - - SetupColorsAndBorders (); - - cols = Console.WindowWidth; - rows = Console.WindowHeight; -#if false - winConsole.ShowWindow (WindowsConsole.RESTORE); -#endif - WindowsConsole.SmallRect.MakeEmpty (ref damageRegion); - - ResizeScreen (); - UpdateOffScreen (); - } - public WindowsConsole WinConsole { get => winConsole; private set => winConsole = value; } - private void SetupColorsAndBorders () - { - Colors.TopLevel = new ColorScheme (); - Colors.Base = new ColorScheme (); - Colors.Dialog = new ColorScheme (); - Colors.Menu = new ColorScheme (); - Colors.Error = new ColorScheme (); - - Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black); - Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan); - Colors.TopLevel.HotNormal = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.Black); - Colors.TopLevel.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkCyan); - - Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkBlue); - Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); - Colors.Base.HotNormal = MakeColor (ConsoleColor.DarkCyan, ConsoleColor.DarkBlue); - Colors.Base.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray); - - Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkGray); - Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black); - Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.DarkGray); - Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black); - Colors.Menu.Disabled = MakeColor (ConsoleColor.Gray, ConsoleColor.DarkGray); - - Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); - Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkGray); - Colors.Dialog.HotNormal = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.Gray); - Colors.Dialog.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkGray); - - Colors.Error.Normal = MakeColor (ConsoleColor.DarkRed, ConsoleColor.White); - Colors.Error.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkRed); - Colors.Error.HotNormal = MakeColor (ConsoleColor.Black, ConsoleColor.White); - Colors.Error.HotFocus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkRed); - } - Action keyHandler; Action keyDownHandler; Action keyUpHandler; Action mouseHandler; + public WindowsDriver () + { + winConsole = new WindowsConsole (); + } + public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { this.keyHandler = keyHandler; @@ -1081,7 +1034,7 @@ namespace Terminal.Gui { return (Key)(0xffffffff); } - private Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key) + Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key) { Key keyMod = new Key (); if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0) @@ -1097,7 +1050,48 @@ namespace Terminal.Gui { public override void Init (Action terminalResized) { TerminalResized = terminalResized; - SetupColorsAndBorders (); + + cols = Console.WindowWidth; + rows = Console.WindowHeight; +#if false + winConsole.ShowWindow (WindowsConsole.RESTORE); +#endif + WindowsConsole.SmallRect.MakeEmpty (ref damageRegion); + + ResizeScreen (); + UpdateOffScreen (); + + Colors.TopLevel = new ColorScheme (); + Colors.Base = new ColorScheme (); + Colors.Dialog = new ColorScheme (); + Colors.Menu = new ColorScheme (); + Colors.Error = new ColorScheme (); + + Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black); + Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan); + Colors.TopLevel.HotNormal = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.Black); + Colors.TopLevel.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkCyan); + + Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkBlue); + Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); + Colors.Base.HotNormal = MakeColor (ConsoleColor.DarkCyan, ConsoleColor.DarkBlue); + Colors.Base.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray); + + Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkGray); + Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black); + Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.DarkGray); + Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black); + Colors.Menu.Disabled = MakeColor (ConsoleColor.Gray, ConsoleColor.DarkGray); + + Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); + Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkGray); + Colors.Dialog.HotNormal = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.Gray); + Colors.Dialog.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkGray); + + Colors.Error.Normal = MakeColor (ConsoleColor.DarkRed, ConsoleColor.White); + Colors.Error.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkRed); + Colors.Error.HotNormal = MakeColor (ConsoleColor.Black, ConsoleColor.White); + Colors.Error.HotFocus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkRed); } void ResizeScreen () @@ -1300,6 +1294,9 @@ namespace Terminal.Gui { public WindowsMainLoop (ConsoleDriver consoleDriver = null) { + if (consoleDriver == null) { + throw new ArgumentNullException ("Console driver instance must be provided."); + } this.consoleDriver = consoleDriver; winConsole = ((WindowsDriver)consoleDriver).WinConsole; } diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index 2e555a547..55ab69a67 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -421,35 +421,6 @@ namespace Terminal.Gui { } } - /// - public override void Redraw (Rect bounds) - { - Application.CurrentView = this; - - if (IsCurrentTop || this == Application.Top) { - if (!NeedDisplay.IsEmpty || LayoutNeeded) { - Driver.SetAttribute (Colors.TopLevel.Normal); - - // This is the Application.Top. Clear just the region we're being asked to redraw - // (the bounds passed to us). - Clear (bounds); - Driver.SetAttribute (Colors.Base.Normal); - PositionToplevels (); - - foreach (var view in Subviews) { - if (view.Frame.IntersectsWith (bounds)) { - view.SetNeedsLayout (); - view.SetNeedsDisplay (view.Bounds); - } - } - - ClearLayoutNeeded (); - ClearNeedsDisplay (); - } - } - - base.Redraw (base.Bounds); - } /// /// Invoked by as part of the after diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index e5f1177a3..d45703725 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -1310,14 +1310,17 @@ namespace Terminal.Gui { /// public virtual void Redraw (Rect bounds) { + Application.CurrentView = this; + if (!CanBeVisible (this)) { return; } var clipRect = new Rect (Point.Empty, frame.Size); - if (ColorScheme != null) + if (ColorScheme != null) { Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal); + } if (!ustring.IsNullOrEmpty (Text)) { Clear (); @@ -1328,12 +1331,31 @@ namespace Terminal.Gui { textFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : ColorScheme.Normal, HasFocus ? ColorScheme.HotFocus : ColorScheme.HotNormal); } + if (IsCurrentTop || this == Application.Top) { + if (!NeedDisplay.IsEmpty || LayoutNeeded) { + Driver.SetAttribute (Colors.TopLevel.Normal); + + // This is the Application.Top. Clear just the region we're being asked to redraw + // (the bounds passed to us). + Clear (bounds); + Driver.SetAttribute (Colors.Base.Normal); + ((Toplevel)this).PositionToplevels (); + + foreach (var view in Subviews) { + if (view.Frame.IntersectsWith (bounds)) { + view.SetNeedsLayout (); + view.SetNeedsDisplay (view.Bounds); + } + } + } + } + // Invoke DrawContentEvent OnDrawContent (bounds); if (subviews != null) { foreach (var view in subviews) { - if (!view.NeedDisplay.IsEmpty || view.ChildNeedsDisplay) { + if (!view.NeedDisplay.IsEmpty || view.ChildNeedsDisplay || view.LayoutNeeded) { if (view.Frame.IntersectsWith (clipRect) && (view.Frame.IntersectsWith (bounds) || bounds.X < 0 || bounds.Y < 0)) { if (view.LayoutNeeded) view.LayoutSubviews (); @@ -1350,6 +1372,7 @@ namespace Terminal.Gui { } } } + ClearLayoutNeeded (); ClearNeedsDisplay (); } From 9b0ea4e992ebd0d3ea84836a3216163617b8770e Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 25 Nov 2020 22:21:23 +0000 Subject: [PATCH 07/15] Changed from Enum HeightSize to bool HeightAsBuffer. --- .../CursesDriver/CursesDriver.cs | 2 +- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 2 +- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 27 +++++++------------ Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 8 +++--- Terminal.Gui/Core/Application.cs | 10 +++---- Terminal.Gui/Core/ConsoleDriver.cs | 19 +++---------- 6 files changed, 23 insertions(+), 45 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index e430f4da1..759476388 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -20,7 +20,7 @@ namespace Terminal.Gui { public override int Cols => Curses.Cols; public override int Rows => Curses.Lines; public override int Top => 0; - public override HeightSize HeightSize { get; set; } + public override bool HeightAsBuffer { get; set; } // Current row, and current col, tracked by Move/AddRune only int ccol, crow; diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 424e1def0..c5a611fe7 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -20,7 +20,7 @@ namespace Terminal.Gui { public override int Cols => cols; public override int Rows => rows; public override int Top => 0; - public override HeightSize HeightSize { get; set; } + public override bool HeightAsBuffer { get; set; } // The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag int [,,] contents; diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 2efb3d12d..cf3d88f58 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -18,7 +18,7 @@ namespace Terminal.Gui { public override int Cols => cols; public override int Rows => rows; public override int Top => top; - public override HeightSize HeightSize { get; set; } + public override bool HeightAsBuffer { get; set; } // The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag int [,,] contents; @@ -149,8 +149,7 @@ namespace Terminal.Gui { void ResizeScreen () { - switch (HeightSize) { - case HeightSize.WindowHeight: + if (!HeightAsBuffer) { if (Console.WindowHeight > 0) { // Can raise an exception while is still resizing. try { @@ -174,8 +173,7 @@ namespace Terminal.Gui { return; } } - break; - case HeightSize.BufferHeight: + } else { if (isWinPlatform && Console.WindowHeight > 0) { // Can raise an exception while is still resizing. try { @@ -189,8 +187,8 @@ namespace Terminal.Gui { Console.Out.Write ($"\x1b[{top};{Console.WindowLeft}" + $";{Rows};{Cols}w"); } - break; } + Clip = new Rect (0, 0, Cols, Rows); contents = new int [Rows, Cols, 3]; @@ -240,8 +238,8 @@ namespace Terminal.Gui { public override void UpdateScreen () { if (winChanging || Console.WindowHeight == 0 - || (HeightSize == HeightSize.WindowHeight && Rows != Console.WindowHeight) - || (HeightSize == HeightSize.BufferHeight && Rows != Console.BufferHeight)) { + || (!HeightAsBuffer && Rows != Console.WindowHeight) + || (HeightAsBuffer && Rows != Console.BufferHeight)) { return; } @@ -467,16 +465,13 @@ namespace Terminal.Gui { winChanging = true; const int Min_WindowWidth = 14; Size size = new Size (); - switch (HeightSize) { - case HeightSize.WindowHeight: + if (!HeightAsBuffer) { size = new Size (Math.Max (Min_WindowWidth, Console.WindowWidth), Console.WindowHeight); top = 0; - break; - case HeightSize.BufferHeight: + } else { size = new Size (Console.BufferWidth, Console.BufferHeight); top = e; - break; } cols = size.Width; rows = size.Height; @@ -579,13 +574,11 @@ namespace Terminal.Gui { void WaitWinChange () { while (true) { - switch (consoleDriver.HeightSize) { - case HeightSize.WindowHeight: + if (!consoleDriver.HeightAsBuffer) { if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows) { return; } - break; - case HeightSize.BufferHeight: + } else { if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows || Console.WindowTop != consoleDriver.Top || Console.WindowHeight != lastWindowHeight) { diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 76f3288b3..be4455520 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -523,7 +523,7 @@ namespace Terminal.Gui { public override int Cols => cols; public override int Rows => rows; public override int Top => top; - public override HeightSize HeightSize { get; set; } + public override bool HeightAsBuffer { get; set; } public WindowsConsole WinConsole { get => winConsole; @@ -1334,14 +1334,12 @@ namespace Terminal.Gui { void WaitWinChange () { while (true) { - switch (consoleDriver.HeightSize) { - case HeightSize.WindowHeight: + if (!consoleDriver.HeightAsBuffer) { if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows || Console.WindowTop != consoleDriver.Top) { // Top only working on Windows. return; } - break; - case HeightSize.BufferHeight: + } else { if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows) { return; } diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index d30bf1b94..0e7e474ae 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -79,21 +79,21 @@ namespace Terminal.Gui { public static View CurrentView { get; set; } /// - /// The current used in the terminal. + /// The current used in the terminal. /// - public static HeightSize HeightSize { + public static bool HeightAsBuffer { get { if (Driver == null) { throw new ArgumentNullException ("The driver must be initialized first."); } - return Driver.HeightSize; + return Driver.HeightAsBuffer; } set { if (Driver == null) { throw new ArgumentNullException ("The driver must be initialized first."); } - if (Driver.HeightSize != value) { - Driver.HeightSize = value; + if (Driver.HeightAsBuffer != value) { + Driver.HeightAsBuffer = value; Driver.Refresh (); } } diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 68cfb1dc2..1f618e5d7 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -458,20 +458,6 @@ namespace Terminal.Gui { public static Dictionary ColorSchemes { get; } } - /// - /// The visible height should be used on the window. - /// - public enum HeightSize { - /// - /// Only window height will be visible not allowing scroll. - /// - WindowHeight, - /// - /// All buffer height will be visible allowing scroll. - /// - BufferHeight - } - ///// ///// Special characters that can be drawn with ///// @@ -561,9 +547,10 @@ namespace Terminal.Gui { public abstract int Top { get; } /// - /// The current used in the terminal. + /// If false height is measured by the window height and thus no scrolling. + /// If true then height is measured by the buffer height, enabling scrolling. /// - public abstract HeightSize HeightSize { get; set; } + public abstract bool HeightAsBuffer { get; set; } /// /// Initializes the driver From 7de9db69c6ca9ed0c931c73ebb5dc05123d1ace2 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 25 Nov 2020 22:33:42 +0000 Subject: [PATCH 08/15] Fixing demo. --- Example/demo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/demo.cs b/Example/demo.cs index c10bb84ce..f31ecd101 100644 --- a/Example/demo.cs +++ b/Example/demo.cs @@ -565,7 +565,7 @@ static class Demo { Application.UseSystemConsole = true; Application.Init(); - Application.HeightSize = HeightSize.BufferHeight; + Application.HeightAsBuffer = true; //ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler; var top = Application.Top; From 12383e4c313afb4b01af289df5c30c9a7af82c4d Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 25 Nov 2020 23:09:09 +0000 Subject: [PATCH 09/15] Avoid exception if LastFocused is null. --- Terminal.Gui/Views/Menu.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 7a749dafd..e2a67beaa 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -1415,7 +1415,7 @@ namespace Terminal.Gui { CloseMenu (); if (openedByAltKey) { openedByAltKey = false; - LastFocused.SetFocus (); + LastFocused?.SetFocus (); } break; From 441fcbecbe9fe701a13d19dae236014afe6778cb Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 26 Nov 2020 00:04:55 +0000 Subject: [PATCH 10/15] Removed break. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index cf3d88f58..832d65123 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -586,7 +586,6 @@ namespace Terminal.Gui { lastWindowHeight = Console.WindowHeight; return; } - break; } } } From 88c33bb9248819e2289043402e6aec106bbf16e5 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 26 Nov 2020 10:46:49 +0000 Subject: [PATCH 11/15] Reverting the breaking Toplevel Redraw. --- Terminal.Gui/Core/Toplevel.cs | 33 +++++++++++++++++++++++++++++++-- Terminal.Gui/Core/View.cs | 25 +++---------------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index 55ab69a67..da4eb22b7 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -401,10 +401,10 @@ namespace Terminal.Gui { { EnsureVisibleBounds (top, top.Frame.X, top.Frame.Y, out int nx, out int ny); if ((nx != top.Frame.X || ny != top.Frame.Y) && top.LayoutStyle == LayoutStyle.Computed) { - if (top.X is Pos.PosAbsolute && top.Bounds.X != nx) { + if ((top.X == null || top.X is Pos.PosAbsolute) && top.Bounds.X != nx) { top.X = nx; } - if (top.Y is Pos.PosAbsolute && top.Bounds.Y != ny) { + if ((top.Y == null || top.Y is Pos.PosAbsolute) && top.Bounds.Y != ny) { top.Y = ny; } } @@ -421,6 +421,35 @@ namespace Terminal.Gui { } } + /// + public override void Redraw (Rect bounds) + { + Application.CurrentView = this; + + if (IsCurrentTop || this == Application.Top) { + if (!NeedDisplay.IsEmpty || LayoutNeeded) { + Driver.SetAttribute (Colors.TopLevel.Normal); + + // This is the Application.Top. Clear just the region we're being asked to redraw + // (the bounds passed to us). + Clear (bounds); + Driver.SetAttribute (Colors.Base.Normal); + PositionToplevels (); + + foreach (var view in Subviews) { + if (view.Frame.IntersectsWith (bounds)) { + view.SetNeedsLayout (); + view.SetNeedsDisplay (view.Bounds); + } + } + + ClearLayoutNeeded (); + ClearNeedsDisplay (); + } + } + + base.Redraw (base.Bounds); + } /// /// Invoked by as part of the after diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index d45703725..ac0a519d0 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -1310,12 +1310,12 @@ namespace Terminal.Gui { /// public virtual void Redraw (Rect bounds) { - Application.CurrentView = this; - if (!CanBeVisible (this)) { return; } + Application.CurrentView = this; + var clipRect = new Rect (Point.Empty, frame.Size); if (ColorScheme != null) { @@ -1331,25 +1331,6 @@ namespace Terminal.Gui { textFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : ColorScheme.Normal, HasFocus ? ColorScheme.HotFocus : ColorScheme.HotNormal); } - if (IsCurrentTop || this == Application.Top) { - if (!NeedDisplay.IsEmpty || LayoutNeeded) { - Driver.SetAttribute (Colors.TopLevel.Normal); - - // This is the Application.Top. Clear just the region we're being asked to redraw - // (the bounds passed to us). - Clear (bounds); - Driver.SetAttribute (Colors.Base.Normal); - ((Toplevel)this).PositionToplevels (); - - foreach (var view in Subviews) { - if (view.Frame.IntersectsWith (bounds)) { - view.SetNeedsLayout (); - view.SetNeedsDisplay (view.Bounds); - } - } - } - } - // Invoke DrawContentEvent OnDrawContent (bounds); @@ -1362,7 +1343,7 @@ namespace Terminal.Gui { Application.CurrentView = view; // Draw the subview - // Use the view's bounds (view-relative; Location will always be (0,0) because + // Use the view's bounds (view-relative; Location will always be (0,0) if (view.Visible) { view.Redraw (view.Bounds); } From 55c682dde109d74bda98927612360c4cc9af0a64 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 26 Nov 2020 18:07:28 +0000 Subject: [PATCH 12/15] Ensures that the Toplevel redraw if the LayoutNeeded is true in the RunLoop too. --- Terminal.Gui/Core/Application.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 0e7e474ae..e476e5e56 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -608,11 +608,11 @@ namespace Terminal.Gui { } else if (!wait) { return; } - if (state.Toplevel != Top && (!Top.NeedDisplay.IsEmpty || Top.ChildNeedsDisplay)) { + if (state.Toplevel != Top && (!Top.NeedDisplay.IsEmpty || Top.ChildNeedsDisplay || Top.LayoutNeeded)) { Top.Redraw (Top.Bounds); state.Toplevel.SetNeedsDisplay (state.Toplevel.Bounds); } - if (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.ChildNeedsDisplay) { + if (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.ChildNeedsDisplay || state.Toplevel.LayoutNeeded) { state.Toplevel.Redraw (state.Toplevel.Bounds); if (DebugDrawBounds) { DrawBounds (state.Toplevel); From 3e29baa5c54588cee80b0a7ee80ca77459e3271d Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 26 Nov 2020 18:51:56 +0000 Subject: [PATCH 13/15] Cleanup. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 832d65123..4b98ea064 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -252,7 +252,6 @@ namespace Terminal.Gui { continue; } dirtyLine [row] = false; - int [,,] damage = new int [0, 0, 0]; for (int col = 0; col < cols; col++) { if (contents [row, col, 2] != 1) { continue; From c0540b5de6b37a15ec15714bdbcbf737dad3a223 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 28 Nov 2020 19:46:05 +0000 Subject: [PATCH 14/15] Adjusting the code. --- .../CursesDriver/CursesDriver.cs | 6 +- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 60 +++++++----- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 92 ++++++++++++++----- 3 files changed, 107 insertions(+), 51 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 759476388..0cf0c4497 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -647,16 +647,16 @@ namespace Terminal.Gui { } Action mouseHandler; - MainLoop mainLoop; public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { // Note: Curses doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called Curses.timeout (0); this.mouseHandler = mouseHandler; - this.mainLoop = mainLoop; - (mainLoop.Driver as UnixMainLoop).AddWatch (0, UnixMainLoop.Condition.PollIn, x => { + var mLoop = mainLoop.Driver as UnixMainLoop; + + mLoop.AddWatch (0, UnixMainLoop.Condition.PollIn, x => { ProcessInput (keyHandler, keyDownHandler, keyUpHandler, mouseHandler); return true; }); diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 4b98ea064..53997351f 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -36,25 +36,33 @@ namespace Terminal.Gui { public override void AddRune (Rune rune) { + if (contents.Length != Rows * Cols * 3) { + return; + } rune = MakePrintable (rune); - if (Clip.Contains (ccol, crow)) { + var runeWidth = Rune.ColumnWidth (rune); + if (Clip.Contains (ccol, crow) && ccol + Math.Max (runeWidth, 1) <= Cols) { contents [crow, ccol, 0] = (int)(uint)rune; contents [crow, ccol, 1] = currentAttribute; contents [crow, ccol, 2] = 1; dirtyLine [crow] = true; - } - ccol++; - var runeWidth = Rune.ColumnWidth (rune); - if (runeWidth > 1) { - for (int i = 1; i < runeWidth; i++) { - contents [crow, ccol, 2] = 0; - if (ccol + 1 < cols) { + + ccol++; + if (runeWidth > 1) { + for (int i = 1; i < runeWidth; i++) { + if (ccol < cols) { + contents [crow, ccol, 2] = 0; + } else { + break; + } ccol++; - } else { - break; } } + } else if (ccol < cols && crow < rows) { + contents [crow, ccol, 2] = 1; + dirtyLine [crow] = true; } + //if (ccol == Cols) { // ccol = 0; // if (crow + 1 < Rows) @@ -107,7 +115,7 @@ namespace Terminal.Gui { Clear (); ResizeScreen (); - UpdateOffscreen (); + UpdateOffScreen (); Colors.TopLevel = new ColorScheme (); Colors.Base = new ColorScheme (); @@ -193,15 +201,10 @@ namespace Terminal.Gui { contents = new int [Rows, Cols, 3]; dirtyLine = new bool [Rows]; - - winChanging = false; } - void UpdateOffscreen () + void UpdateOffScreen () { - if (!winChanging) { - return; - } // Can raise an exception while is still resizing. try { for (int row = 0; row < rows; row++) { @@ -213,6 +216,8 @@ namespace Terminal.Gui { } } } catch (IndexOutOfRangeException) { } + + winChanging = false; } public override Attribute MakeAttribute (Color fore, Color back) @@ -237,7 +242,7 @@ namespace Terminal.Gui { public override void UpdateScreen () { - if (winChanging || Console.WindowHeight == 0 + if (winChanging || Console.WindowHeight == 0 || contents.Length != Rows * Cols * 3 || (!HeightAsBuffer && Rows != Console.WindowHeight) || (HeightAsBuffer && Rows != Console.BufferHeight)) { return; @@ -256,7 +261,6 @@ namespace Terminal.Gui { if (contents [row, col, 2] != 1) { continue; } - if (Console.WindowHeight > 0) { // Could happens that the windows is still resizing and the col is bigger than Console.WindowWidth. try { @@ -266,6 +270,10 @@ namespace Terminal.Gui { } } for (; col < cols && contents [row, col, 2] == 1; col++) { + // Needed for the .Net Framework. + if (row == rows - 1 && col == cols - 1) { + break; + } var color = contents [row, col, 1]; if (color != redrawColor) { SetColor (color); @@ -439,8 +447,10 @@ namespace Terminal.Gui { bool winChanging; public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { + var mLoop = mainLoop.Driver as NetMainLoop; + // Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called - (mainLoop.Driver as NetMainLoop).KeyPressed = (consoleKey) => { + mLoop.KeyPressed = (consoleKey) => { var map = MapKey (consoleKey); if (map == (Key)0xffffffff) { return; @@ -460,7 +470,7 @@ namespace Terminal.Gui { keyModifiers = new KeyModifiers (); }; - (mainLoop.Driver as NetMainLoop).WinChanged = (e) => { + mLoop.WinChanged = (e) => { winChanging = true; const int Min_WindowWidth = 14; Size size = new Size (); @@ -475,7 +485,7 @@ namespace Terminal.Gui { cols = size.Width; rows = size.Height; ResizeScreen (); - UpdateOffscreen (); + UpdateOffScreen (); if (!winChanging) { TerminalResized.Invoke (); } @@ -529,6 +539,9 @@ namespace Terminal.Gui { /// public Action KeyPressed; + /// + /// Invoked when the window is changed. + /// public Action WinChanged; /// @@ -581,6 +594,7 @@ namespace Terminal.Gui { if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows || Console.WindowTop != consoleDriver.Top || Console.WindowHeight != lastWindowHeight) { + // Top only working on Windows. newTop = Console.WindowTop; lastWindowHeight = Console.WindowHeight; return; @@ -659,7 +673,7 @@ namespace Terminal.Gui { } if (winChanged) { winChanged = false; - WinChanged.Invoke (newTop); + WinChanged?.Invoke (newTop); } } } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index be4455520..c1341e351 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -86,6 +86,13 @@ namespace Terminal.Gui { return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = window.Left, Y = window.Top }, ref window); } + public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window) + { + OriginalStdOutChars = new CharInfo [size.Height * size.Width]; + + ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window); + } + public bool SetCursorPosition (Coord position) { return SetConsoleCursorPosition (ScreenBuffer, position); @@ -540,6 +547,8 @@ namespace Terminal.Gui { winConsole = new WindowsConsole (); } + bool winChanging; + public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { this.keyHandler = keyHandler; @@ -547,7 +556,33 @@ namespace Terminal.Gui { this.keyUpHandler = keyUpHandler; this.mouseHandler = mouseHandler; - (mainLoop.Driver as WindowsMainLoop).ProcessInput = (e) => ProcessInput (e); + var mLoop = mainLoop.Driver as WindowsMainLoop; + + mLoop.ProcessInput = (e) => ProcessInput (e); + + mLoop.WinChanged = (e) => { + ChangeWin (e); + }; + } + + private void ChangeWin (Size e) + { + winChanging = true; + if (!HeightAsBuffer) { + top = 0; + cols = e.Width; + rows = e.Height; + ResizeScreen (); + UpdateOffScreen (); + var bufferCoords = new WindowsConsole.Coord () { + X = (short)Clip.Width, + Y = (short)Clip.Height + }; + winConsole.ReadFromConsoleOutput (e, bufferCoords, ref damageRegion); + if (!winChanging) { + TerminalResized.Invoke (); + } + } } void ProcessInput (WindowsConsole.InputRecord inputEvent) @@ -1108,12 +1143,15 @@ namespace Terminal.Gui { void UpdateOffScreen () { - for (int row = 0; row < rows; row++) + for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { int position = row * cols + col; OutputBuffer [position].Attributes = (ushort)Colors.TopLevel.Normal; OutputBuffer [position].Char.UnicodeChar = ' '; } + } + + winChanging = false; } int ccol, crow; @@ -1209,12 +1247,12 @@ namespace Terminal.Gui { Y = (short)Clip.Height }; - var window = new WindowsConsole.SmallRect () { - Top = 0, - Left = 0, - Right = (short)Clip.Right, - Bottom = (short)Clip.Bottom - }; + //var window = new WindowsConsole.SmallRect () { + // Top = 0, + // Left = 0, + // Right = (short)Clip.Right, + // Bottom = (short)Clip.Bottom + //}; UpdateCursor (); winConsole.WriteToConsole (OutputBuffer, bufferCoords, damageRegion); @@ -1282,6 +1320,7 @@ namespace Terminal.Gui { ConsoleDriver consoleDriver; WindowsConsole winConsole; bool winChanged; + Size windowSize; CancellationTokenSource tokenSource = new CancellationTokenSource (); // The records that we keep fetching @@ -1292,6 +1331,11 @@ namespace Terminal.Gui { /// public Action ProcessInput; + /// + /// Invoked when the window is changed. + /// + public Action WinChanged; + public WindowsMainLoop (ConsoleDriver consoleDriver = null) { if (consoleDriver == null) { @@ -1304,7 +1348,7 @@ namespace Terminal.Gui { void IMainLoopDriver.Setup (MainLoop mainLoop) { this.mainLoop = mainLoop; - Task.Run ((Action)WindowsInputHandler); + Task.Run (WindowsInputHandler); Task.Run (CheckWinChange); } @@ -1335,15 +1379,11 @@ namespace Terminal.Gui { { while (true) { if (!consoleDriver.HeightAsBuffer) { - if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows - || Console.WindowTop != consoleDriver.Top) { // Top only working on Windows. - return; + windowSize = new Size (Console.WindowWidth, Console.WindowHeight); + if (windowSize.Height < consoleDriver.Rows) { + // I still haven't been able to find a way to capture the shrinking in height. + //return; } - } else { - if (Console.BufferWidth != consoleDriver.Cols || Console.BufferHeight != consoleDriver.Rows) { - return; - } - break; } } } @@ -1351,7 +1391,6 @@ namespace Terminal.Gui { void IMainLoopDriver.Wakeup () { //tokenSource.Cancel (); - eventReady.Reset (); eventReady.Set (); } @@ -1376,7 +1415,7 @@ namespace Terminal.Gui { } if (!tokenSource.IsCancellationRequested) { - return result != null || CheckTimers (wait, out waitTimeout); + return result != null || CheckTimers (wait, out waitTimeout) || winChanged; } tokenSource.Dispose (); @@ -1409,12 +1448,15 @@ namespace Terminal.Gui { void IMainLoopDriver.MainIteration () { - if (result == null) - return; - - var inputEvent = result [0]; - result = null; - ProcessInput.Invoke (inputEvent); + if (result != null) { + var inputEvent = result [0]; + result = null; + ProcessInput?.Invoke (inputEvent); + } + if (winChanged) { + winChanged = false; + WinChanged?.Invoke (windowSize); + } } } } From 94f58acecf70a7b1bfa6be1906b7f7cb91d1f1ef Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 30 Nov 2020 01:16:50 +0000 Subject: [PATCH 15/15] Trying fix #335 --- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 181 ++++++++++++------- 1 file changed, 115 insertions(+), 66 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index c1341e351..abc70c0a1 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -86,10 +86,29 @@ namespace Terminal.Gui { return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = window.Left, Y = window.Top }, ref window); } - public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window) + public void ReadFromConsoleOutput (Size size, Coord coords) { - OriginalStdOutChars = new CharInfo [size.Height * size.Width]; + 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 [size.Height * size.Width]; + SmallRect window = new SmallRect (); ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window); } @@ -460,62 +479,79 @@ namespace Terminal.Gui { } } -#if false // Not needed on the constructor. Perhaps could be used on resizing. To study. + // Not needed on the constructor. Perhaps could be used on resizing. To study. [DllImport ("kernel32.dll", ExactSpelling = true)] static extern IntPtr GetConsoleWindow (); - [DllImport ("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - static extern bool ShowWindow (IntPtr hWnd, int nCmdShow); + [DllImport ("user32.dll")] + [return: MarshalAs (UnmanagedType.Bool)] + static extern bool GetWindowPlacement (IntPtr hWnd, ref WindowPlacement lpwndpl); + [DllImport ("user32.dll", SetLastError = true)] + [return: MarshalAs (UnmanagedType.Bool)] + static extern bool SetWindowPlacement (IntPtr hWnd, [In] ref WindowPlacement lpwndpl); + + internal struct WindowPlacement { + public int length; + public int flags; + public int showCmd; + public System.Drawing.Point ptMinPosition; + public System.Drawing.Point ptMaxPosition; + public System.Drawing.Rectangle rcNormalPosition; + public System.Drawing.Rectangle rcDevice; + } + + // flags + public const int WPF_SET_MIN_POSITION = 1; + public const int WPF_RESTORE_TO_MAXIMIZED = 2; + public const int WPF_ASYNC_WINDOWPLACEMENT = 4; + + // showCmd public const int HIDE = 0; - public const int MAXIMIZE = 3; + public const int NORMAL = 1; + public const int SHOW_MINIMIZED = 2; + public const int SHOW_MAXIMIZED = 3; + public const int SHOW_NOACTIVATE = 4; + public const int SHOW = 5; public const int MINIMIZE = 6; + public const int SHOW_MIN_NOACTIVE = 7; + public const int SHOW_NA = 8; public const int RESTORE = 9; + public const int SHOW_DEFAULT = 10; + public const int FORCE_MINIMIZE = 11; - internal void ShowWindow (int state) + internal WindowPlacement GetWindow () { IntPtr thisConsole = GetConsoleWindow (); - ShowWindow (thisConsole, state); - } -#endif -#if false // See: https://github.com/migueldeicaza/gui.cs/issues/357 - [StructLayout (LayoutKind.Sequential)] - public struct SMALL_RECT { - public short Left; - public short Top; - public short Right; - public short Bottom; + WindowPlacement placement = new WindowPlacement { + length = Marshal.SizeOf (typeof (WindowPlacement)) + }; + GetWindowPlacement (thisConsole, ref placement); - public SMALL_RECT (short Left, short Top, short Right, short Bottom) - { - this.Left = Left; - this.Top = Top; - this.Right = Right; - this.Bottom = Bottom; - } + return placement; } - [StructLayout (LayoutKind.Sequential)] - public struct CONSOLE_SCREEN_BUFFER_INFO { - public int dwSize; - public int dwCursorPosition; - public short wAttributes; - public SMALL_RECT srWindow; - public int dwMaximumWindowSize; - } - - [DllImport ("kernel32.dll", SetLastError = true)] - static extern bool GetConsoleScreenBufferInfo (IntPtr hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo); - - // Theoretically GetConsoleScreenBuffer height should give the console Windoww size - // It does not work, however, and always returns the size the window was initially created at - internal Size GetWindowSize () + internal void SetWindow (int showCmd) { - var consoleScreenBufferInfo = new CONSOLE_SCREEN_BUFFER_INFO (); - //consoleScreenBufferInfo.dwSize = Marshal.SizeOf (typeof (CONSOLE_SCREEN_BUFFER_INFO)); - GetConsoleScreenBufferInfo (OutputHandle, out consoleScreenBufferInfo); - return new Size (consoleScreenBufferInfo.srWindow.Right - consoleScreenBufferInfo.srWindow.Left, - consoleScreenBufferInfo.srWindow.Bottom - consoleScreenBufferInfo.srWindow.Top); + IntPtr thisConsole = GetConsoleWindow (); + WindowPlacement placement = new WindowPlacement { + length = Marshal.SizeOf (typeof (WindowPlacement)), + showCmd = showCmd + }; + SetWindowPlacement (thisConsole, ref placement); + } + +#if false + [DllImport ("kernel32.dll", SetLastError = true)] + static extern bool GetConsoleScreenBufferInfo (IntPtr hConsoleOutput, out ConsoleScreenBufferInfo ConsoleScreenBufferInfo); + + // Theoretically GetConsoleScreenBuffer height should give the console Window size, but the Top is always 0. + // It does not work, however, and always returns the size the window was initially created at + internal Size GetWindowSize (IntPtr handle) + { + GetConsoleScreenBufferInfo (handle, out ConsoleScreenBufferInfo consoleScreenBufferInfo); + return new Size (consoleScreenBufferInfo.srWindow.Right - consoleScreenBufferInfo.srWindow.Left + 1, + consoleScreenBufferInfo.srWindow.Bottom - consoleScreenBufferInfo.srWindow.Top + 1); } #endif } @@ -560,27 +596,27 @@ namespace Terminal.Gui { mLoop.ProcessInput = (e) => ProcessInput (e); - mLoop.WinChanged = (e) => { - ChangeWin (e); - }; + mLoop.WinChanged = (e) => ChangeWin (e); } - private void ChangeWin (Size e) + void ChangeWin (Size size) { - winChanging = true; if (!HeightAsBuffer) { + winChanging = true; top = 0; - cols = e.Width; - rows = e.Height; + cols = size.Width; + rows = size.Height; + var bufferCoords = new WindowsConsole.Coord () { + X = (short)cols, + Y = (short)rows + }; + winConsole.ReadFromConsoleOutput (size, bufferCoords); ResizeScreen (); UpdateOffScreen (); - var bufferCoords = new WindowsConsole.Coord () { - X = (short)Clip.Width, - Y = (short)Clip.Height - }; - winConsole.ReadFromConsoleOutput (e, bufferCoords, ref damageRegion); if (!winChanging) { TerminalResized.Invoke (); + } else { + System.Diagnostics.Debugger.Break (); } } } @@ -676,11 +712,13 @@ namespace Terminal.Gui { break; case WindowsConsole.EventType.WindowBufferSize: - cols = inputEvent.WindowBufferSizeEvent.size.X; - rows = inputEvent.WindowBufferSizeEvent.size.Y; - ResizeScreen (); - UpdateOffScreen (); - TerminalResized?.Invoke (); + if (HeightAsBuffer) { + cols = inputEvent.WindowBufferSizeEvent.size.X; + rows = inputEvent.WindowBufferSizeEvent.size.Y; + ResizeScreen (); + UpdateOffScreen (); + TerminalResized?.Invoke (); + } break; case WindowsConsole.EventType.Focus: @@ -1256,7 +1294,7 @@ namespace Terminal.Gui { UpdateCursor (); winConsole.WriteToConsole (OutputBuffer, bufferCoords, damageRegion); - // System.Diagnostics.Debugger.Log(0, "debug", $"Region={damageRegion.Right - damageRegion.Left},{damageRegion.Bottom - damageRegion.Top}\n"); + //System.Diagnostics.Debugger.Log(0, "debug", $"Region={damageRegion.Right - damageRegion.Left},{damageRegion.Bottom - damageRegion.Top}\n"); WindowsConsole.SmallRect.MakeEmpty (ref damageRegion); } @@ -1320,6 +1358,7 @@ namespace Terminal.Gui { ConsoleDriver consoleDriver; WindowsConsole winConsole; bool winChanged; + WindowsConsole.WindowPlacement windowPlacement; Size windowSize; CancellationTokenSource tokenSource = new CancellationTokenSource (); @@ -1379,10 +1418,20 @@ namespace Terminal.Gui { { while (true) { if (!consoleDriver.HeightAsBuffer) { - windowSize = new Size (Console.WindowWidth, Console.WindowHeight); - if (windowSize.Height < consoleDriver.Rows) { - // I still haven't been able to find a way to capture the shrinking in height. - //return; + windowPlacement = winConsole.GetWindow (); + if (windowPlacement.rcNormalPosition.Size.Height > -1) { + windowSize = new Size (Math.Max (((windowPlacement.rcNormalPosition.Size.Width - + windowPlacement.rcNormalPosition.X) / 8) - 2, 0), + Math.Max (((windowPlacement.rcNormalPosition.Size.Height - + windowPlacement.rcNormalPosition.Y) / 16) - 7, 0)); + if (windowPlacement.showCmd != WindowsConsole.SHOW_MAXIMIZED + && (windowSize.Width != consoleDriver.Cols || windowSize.Height != consoleDriver.Rows)) { + return; + } else if (windowPlacement.showCmd == WindowsConsole.SHOW_MAXIMIZED + && (Console.LargestWindowWidth != consoleDriver.Cols || Console.LargestWindowHeight != consoleDriver.Rows)) { + windowSize = new Size (Console.LargestWindowWidth, Console.LargestWindowHeight); + return; + } } } }