From d55ae77331c49998fbda8ec435cc667d87cd4a33 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 5 Oct 2021 17:22:13 +0100 Subject: [PATCH] Fixes #1446. Added more features to the Border and Toplevel focus. (#1447) * Fixes #1446. Added more features to the Border and Toplevel focus. * Prevents throwing exception on negative effect3DOffset values * Ensures that a view can be focused. * Only sets focus if it isn't disposing. * Fixes ViewToScreen and DrawChildBorder Effect3D. * Unit test for negative coordinates with the ViewToScreen method. * Added Tab navigation feature to the Editor scenario. * ComboBox cursonDownKey nullref fix (#1472) * added null guard to fix null ref when pressing keyDown inside combobox Improved an error message when view cannot be found * Added a unit test to ensure combobox can process all key events Found and fixed a new nullref * Found a new bug when source is already present and combobox is added to a top view * searchSet is auto initialized to new List() now to make the code a little bit safer * Fixes WindowsDriver HeightAsBuffer set to false. (#1466) * Bump ReportGenerator from 4.8.12 to 4.8.13 (#1473) Bumps [ReportGenerator](https://github.com/danielpalme/ReportGenerator) from 4.8.12 to 4.8.13. - [Release notes](https://github.com/danielpalme/ReportGenerator/releases) - [Commits](https://github.com/danielpalme/ReportGenerator/compare/v4.8.12...v4.8.13) --- updated-dependencies: - dependency-name: ReportGenerator dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fixes #1445. Fixing more the Curses and WSL clipboard. (#1448) * Fixes #1445. Fixing more the Curses and WSL clipboard. * Fixing unit tests. * Changing namespace. * Fixes WSL2 clipboard unit test. * Upgrades devcontainer with the MainLoop fix. * Fixes pasting with no selection and with lines break. * Prevents the event button click being fired after a button pressed with mouse move. * Fixes the char [ not being processed. * Added Application.QuitKey property to allow change the quitting application key. (#1450) * Added Application.QuitKey property to allow change the quitting application key. * Fixes QuitKey unit test by reseting his value. * Locks timeouts until is added. * Fixes #1467. AlternateForward/BackwardKey bypasses dialog modality (#1468) * Changed namespace. * Fixing merge conflicts. * Fixes mouse click issue. * Removing windows resizing because buffer resizing is enough. * Fixes #1477. Mouse click and console bottom on Windows Terminal. Co-authored-by: Igor Bagdamyan <37334640+En3Tho@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../CursesDriver/CursesDriver.cs | 30 +++- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 2 +- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 1 + Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 45 ++++-- Terminal.Gui/Core/Application.cs | 25 ++- Terminal.Gui/Core/Border.cs | 145 ++++++++++-------- Terminal.Gui/Core/ConsoleDriver.cs | 3 + Terminal.Gui/Core/Toplevel.cs | 19 ++- Terminal.Gui/Core/View.cs | 19 ++- Terminal.Gui/Core/Window.cs | 5 +- Terminal.Gui/Views/Label.cs | 3 + UICatalog/Scenarios/Editor.cs | 53 +++++-- UnitTests/ApplicationTests.cs | 91 +++++++++++ UnitTests/BorderTests.cs | 4 +- UnitTests/ComboBoxTests.cs | 2 +- UnitTests/ToplevelTests.cs | 5 + UnitTests/ViewTests.cs | 10 +- 17 files changed, 341 insertions(+), 121 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 57e20051b..a8e2c4222 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -28,6 +28,9 @@ namespace Terminal.Gui { CursorVisibility? initialCursorVisibility = null; CursorVisibility? currentCursorVisibility = null; IClipboard clipboard; + int [,,] contents; + + internal override int [,,] Contents => contents; // Current row, and current col, tracked by Move/AddRune only int ccol, crow; @@ -54,7 +57,11 @@ namespace Terminal.Gui { Curses.move (crow, ccol); needMove = false; } - Curses.addch ((int)(uint)MakePrintable (rune)); + rune = MakePrintable (rune); + Curses.addch ((int)(uint)rune); + contents [crow, ccol, 0] = (int)(uint)rune; + contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 2] = 1; } else needMove = true; if (sync) @@ -80,6 +87,7 @@ namespace Terminal.Gui { Curses.refresh (); if (Curses.CheckWinChange ()) { Clip = new Rect (0, 0, Cols, Rows); + UpdateOffScreen (); TerminalResized?.Invoke (); } } @@ -765,6 +773,7 @@ namespace Terminal.Gui { mLoop.WinChanged += () => { if (Curses.CheckWinChange ()) { Clip = new Rect (0, 0, Cols, Rows); + UpdateOffScreen (); TerminalResized?.Invoke (); } }; @@ -854,6 +863,7 @@ namespace Terminal.Gui { Colors.Menu = new ColorScheme (); Colors.Error = new ColorScheme (); Clip = new Rect (0, 0, Cols, Rows); + UpdateOffScreen (); if (Curses.HasColors) { Curses.StartColor (); Curses.UseDefaultColors (); @@ -867,7 +877,7 @@ namespace Terminal.Gui { Colors.Base.Normal = MakeColor (Color.White, Color.Blue); Colors.Base.Focus = MakeColor (Color.Black, Color.Gray); Colors.Base.HotNormal = MakeColor (Color.Cyan, Color.Blue); - Colors.Base.HotFocus = MakeColor (Color.Blue, Color.Gray); + Colors.Base.HotFocus = MakeColor (Color.BrightBlue, Color.Gray); Colors.Base.Disabled = MakeColor (Color.DarkGray, Color.Blue); // Focused, @@ -921,6 +931,21 @@ namespace Terminal.Gui { } } + void UpdateOffScreen () + { + contents = new int [Rows, Cols, 3]; + for (int row = 0; row < Rows; row++) { + for (int col = 0; col < Cols; col++) { + //Curses.move (row, col); + //Curses.attrset (Colors.TopLevel.Normal); + //Curses.addch ((int)(uint)' '); + contents [row, col, 0] = ' '; + contents [row, col, 1] = Colors.TopLevel.Normal; + contents [row, col, 2] = 0; + } + } + } + public static bool Is_WSL_Platform () { var result = BashRunner.Run ("uname -a", runCurses: false); @@ -1139,7 +1164,6 @@ namespace Terminal.Gui { foreground = MapCursesColor ((value - (back << 12)) >> 8); } return hasColor; - } } diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 6bede9a16..784e84edb 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -35,7 +35,7 @@ namespace Terminal.Gui { /// /// Assists with testing, the format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag /// - public int [,,] Contents => contents; + internal override int [,,] Contents => contents; void UpdateOffscreen () { diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 67cc397a4..3a7c326c3 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1155,6 +1155,7 @@ namespace Terminal.Gui { public bool IsWinPlatform { get; } public bool AlwaysSetPosition { get; set; } public override IClipboard Clipboard { get; } + internal override int [,,] Contents => contents; int largestWindowHeight; diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 60f26dac9..597653267 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -209,7 +209,9 @@ namespace Terminal.Gui { var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX (); csbi.cbSize = (uint)Marshal.SizeOf (csbi); if (!GetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)) { - throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); + //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); + position = Point.Empty; + return Size.Empty; } var sz = new Size (csbi.srWindow.Right - csbi.srWindow.Left + 1, csbi.srWindow.Bottom - csbi.srWindow.Top + 1); @@ -239,18 +241,22 @@ namespace Terminal.Gui { if (!GetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)) { throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); } - csbi.dwSize = new Coord (cols, Math.Max (rows, (short)1)); - csbi.srWindow = new SmallRect (0, 0, cols, rows); - csbi.dwMaximumWindowSize = new Coord (cols, rows); + var maxWinSize = GetLargestConsoleWindowSize (ScreenBuffer); + var newCols = Math.Min (cols, maxWinSize.X); + var newRows = Math.Min (rows, maxWinSize.Y); + csbi.dwSize = new Coord (newCols, Math.Max (newRows, (short)1)); + csbi.srWindow = new SmallRect (0, 0, newCols, newRows); + csbi.dwMaximumWindowSize = new Coord (newCols, newRows); if (!SetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)) { throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); } - var winRect = new SmallRect (0, 0, (short)(cols - 1), (short)Math.Max (rows - 1, 0)); + var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0)); if (!SetConsoleWindowInfo (ScreenBuffer, true, ref winRect)) { - throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); + //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); + return new Size (cols, rows); } SetConsoleOutputWindow (csbi); - return new Size (winRect.Right + 1, rows - 1 < 0 ? 0 : winRect.Bottom + 1); + return new Size (winRect.Right + 1, newRows - 1 < 0 ? 0 : winRect.Bottom + 1); } void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi) @@ -706,6 +712,10 @@ namespace Terminal.Gui { IntPtr hConsoleOutput, bool bAbsolute, [In] ref SmallRect lpConsoleWindow); + + [DllImport ("kernel32.dll", SetLastError = true)] + static extern Coord GetLargestConsoleWindowSize ( + IntPtr hConsoleOutput); } internal class WindowsDriver : ConsoleDriver { @@ -714,6 +724,7 @@ namespace Terminal.Gui { int cols, rows, left, top; WindowsConsole.SmallRect damageRegion; IClipboard clipboard; + int [,,] contents; public override int Cols => cols; public override int Rows => rows; @@ -721,6 +732,7 @@ namespace Terminal.Gui { public override int Top => top; public override bool HeightAsBuffer { get; set; } public override IClipboard Clipboard => clipboard; + internal override int [,,] Contents => contents; public WindowsConsole WinConsole { get; private set; } @@ -735,8 +747,6 @@ namespace Terminal.Gui { clipboard = new WindowsClipboard (); } - bool winChanging; - public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { this.keyHandler = keyHandler; @@ -755,7 +765,6 @@ namespace Terminal.Gui { private void ChangeWin (Size e) { - winChanging = true; if (!HeightAsBuffer) { var w = e.Width; if (w == cols - 3 && e.Height < rows) { @@ -769,9 +778,7 @@ namespace Terminal.Gui { rows = newSize.Height; ResizeScreen (); UpdateOffScreen (); - if (!winChanging) { - TerminalResized.Invoke (); - } + TerminalResized.Invoke (); } } @@ -1044,6 +1051,9 @@ namespace Terminal.Gui { } isButtonPressed = false; isButtonReleased = true; + if (point.X == mouseEvent.MousePosition.X && point.Y == mouseEvent.MousePosition.Y) { + processButtonClick = true; + } } else if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved && !isOneFingerDoubleClicked && isButtonReleased && p == point) { @@ -1436,15 +1446,17 @@ namespace Terminal.Gui { void UpdateOffScreen () { + contents = new int [rows, cols, 3]; 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 = ' '; + contents [row, col, 0] = OutputBuffer [position].Char.UnicodeChar; + contents [row, col, 1] = OutputBuffer [position].Attributes; + contents [row, col, 2] = 0; } } - - winChanging = false; } int ccol, crow; @@ -1462,6 +1474,9 @@ namespace Terminal.Gui { if (Clip.Contains (ccol, crow)) { OutputBuffer [position].Attributes = (ushort)currentAttribute; OutputBuffer [position].Char.UnicodeChar = (char)rune; + contents [crow, ccol, 0] = (int)(uint)rune; + contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 2] = 1; WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index fb9f7d483..e09d6f8c5 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -480,12 +480,11 @@ namespace Terminal.Gui { static View FindTopFromView (View view) { - View top = view?.SuperView != null ? view.SuperView : view; + View top = view?.SuperView != null && view?.SuperView != Top + ? view.SuperView : view; - while (top?.SuperView != null) { - if (top?.SuperView != null) { - top = top.SuperView; - } + while (top?.SuperView != null && top?.SuperView != Top) { + top = top.SuperView; } return top; } @@ -594,6 +593,8 @@ namespace Terminal.Gui { // Should we bubbled up the event, if it is not handled? view.OnMouseEvent (nme); + + EnsuresTopOnFront (); } } @@ -1235,5 +1236,19 @@ namespace Terminal.Gui { { MainLoop.Driver.Wakeup (); } + + /// + /// Ensures that the superview of the most focused view is on front. + /// + public static void EnsuresTopOnFront () + { + if (MdiTop != null) { + return; + } + var top = FindTopFromView (Top?.MostFocused); + if (top != null && Top.Subviews.Count > 1 && Top.Subviews [Top.Subviews.Count - 1] != top) { + Top.BringSubviewToFront (top); + } + } } } diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs index a3848c54b..cf8f6e32a 100644 --- a/Terminal.Gui/Core/Border.cs +++ b/Terminal.Gui/Core/Border.cs @@ -357,11 +357,12 @@ namespace Terminal.Gui { /// public int ActualWidth { get { + var driver = Application.Driver; if (Parent?.Border == null) { - return Child?.Frame.Width + (2 * marginFrame) + Padding.Right - + BorderThickness.Right + Padding.Left + BorderThickness.Left ?? 0; + return Math.Min (Child?.Frame.Width + (2 * marginFrame) + Padding.Right + + BorderThickness.Right + Padding.Left + BorderThickness.Left ?? 0, driver.Cols); } - return Parent.Frame.Width; + return Math.Min (Parent.Frame.Width, driver.Cols); } } /// @@ -369,11 +370,12 @@ namespace Terminal.Gui { /// public int ActualHeight { get { + var driver = Application.Driver; if (Parent?.Border == null) { - return Child?.Frame.Height + (2 * marginFrame) + Padding.Bottom - + BorderThickness.Bottom + Padding.Top + BorderThickness.Top ?? 0; + return Math.Min (Child?.Frame.Height + (2 * marginFrame) + Padding.Bottom + + BorderThickness.Bottom + Padding.Top + BorderThickness.Top ?? 0, driver.Rows); } - return Parent.Frame.Height; + return Math.Min (Parent.Frame.Height, driver.Rows); } } @@ -405,7 +407,7 @@ namespace Terminal.Gui { /// /// Gets or sets the color for the /// - public Color Effect3DBrush { get; set; } = Color.DarkGray; + public Attribute? Effect3DBrush { get; set; } /// /// Calculate the sum of the and the @@ -428,9 +430,9 @@ namespace Terminal.Gui { public void DrawContent () { if (Parent?.Border != null) { - DrawParentBorder (Parent.ViewToScreen (new Rect (0, 0, Parent.Frame.Width, Parent.Frame.Height))); + DrawParentBorder (Parent.ViewToScreen (Parent.Bounds)); } else { - DrawChildBorder (Child.ViewToScreen (new Rect (0, 0, Child.Frame.Width, Child.Frame.Height))); + DrawChildBorder (Child.ViewToScreen (Child.Bounds)); } } @@ -445,9 +447,9 @@ namespace Terminal.Gui { var driver = Application.Driver; Rect scrRect; if (Parent?.Border != null) { - scrRect = Parent.ViewToScreen (new Rect (0, 0, Parent.Frame.Width, Parent.Frame.Height)); + scrRect = Parent.ViewToScreen (Parent.Bounds); } else { - scrRect = Child.ViewToScreen (new Rect (0, 0, Child.Frame.Width, Child.Frame.Height)); + scrRect = Child.ViewToScreen (Child.Bounds); } Rect borderRect; if (Parent?.Border != null) { @@ -464,14 +466,21 @@ namespace Terminal.Gui { // Draw 3D effects if (Effect3D) { - driver.SetAttribute (new Attribute (Effect3DBrush)); + driver.SetAttribute (GetEffect3DBrush ()); + var effectBorder = new Rect () { X = borderRect.X + Effect3DOffset.X, Y = borderRect.Y + Effect3DOffset.Y, Width = ActualWidth, Height = ActualHeight }; - Child.Clear (effectBorder); + //Child.Clear (effectBorder); + for (int r = effectBorder.Y; r < Math.Min (effectBorder.Bottom, driver.Rows); r++) { + for (int c = effectBorder.X; c < Math.Min (effectBorder.Right, driver.Cols); c++) { + + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); + } + } } // Draw border thickness @@ -530,7 +539,7 @@ namespace Terminal.Gui { for (int r = frame.Y - drawMarginFrame - sumThickness.Top; r < frame.Y - drawMarginFrame - padding.Top; r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left; - c < frame.Right + drawMarginFrame + sumThickness.Right; c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -538,7 +547,7 @@ namespace Terminal.Gui { // Draw the left BorderThickness for (int r = frame.Y - drawMarginFrame - padding.Top; - r < frame.Bottom + drawMarginFrame + padding.Bottom; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left; c < frame.X - drawMarginFrame - padding.Left; c++) { @@ -548,9 +557,9 @@ namespace Terminal.Gui { // Draw the right BorderThickness for (int r = frame.Y - drawMarginFrame - padding.Top; - r < frame.Bottom + drawMarginFrame + padding.Bottom; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { for (int c = frame.Right + drawMarginFrame + padding.Right; - c < frame.Right + drawMarginFrame + sumThickness.Right; c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -558,9 +567,9 @@ namespace Terminal.Gui { // Draw the lower BorderThickness for (int r = frame.Bottom + drawMarginFrame + padding.Bottom; - r < frame.Bottom + drawMarginFrame + sumThickness.Bottom; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left; - c < frame.Right + drawMarginFrame + sumThickness.Right; c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -572,7 +581,7 @@ namespace Terminal.Gui { for (int r = frame.Y - drawMarginFrame - padding.Top; r < frame.Y - drawMarginFrame; r++) { for (int c = frame.X - drawMarginFrame - padding.Left; - c < frame.Right + drawMarginFrame + padding.Right; c++) { + c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -580,7 +589,7 @@ namespace Terminal.Gui { // Draw the left Padding for (int r = frame.Y - drawMarginFrame; - r < frame.Bottom + drawMarginFrame; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - padding.Left; c < frame.X - drawMarginFrame; c++) { @@ -590,9 +599,9 @@ namespace Terminal.Gui { // Draw the right Padding for (int r = frame.Y - drawMarginFrame; - r < frame.Bottom + drawMarginFrame; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) { for (int c = frame.Right + drawMarginFrame; - c < frame.Right + drawMarginFrame + padding.Right; c++) { + c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -600,9 +609,9 @@ namespace Terminal.Gui { // Draw the lower Padding for (int r = frame.Bottom + drawMarginFrame; - r < frame.Bottom + drawMarginFrame + padding.Bottom; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - padding.Left; - c < frame.Right + drawMarginFrame + padding.Right; c++) { + c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -622,45 +631,45 @@ namespace Terminal.Gui { } if (Effect3D) { - driver.SetAttribute (new Attribute (Effect3DBrush)); + driver.SetAttribute (GetEffect3DBrush ()); // Draw the upper Effect3D for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y; r < frame.Y - drawMarginFrame - sumThickness.Top; r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X; - c < frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X; c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } // Draw the left Effect3D for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y; - r < frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X; c < frame.X - drawMarginFrame - sumThickness.Left; c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } // Draw the right Effect3D for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y; - r < frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = frame.Right + drawMarginFrame + sumThickness.Right; - c < frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X; c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } // Draw the lower Effect3D for (int r = frame.Bottom + drawMarginFrame + sumThickness.Bottom; - r < frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y; r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X; - c < frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X; c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } } @@ -668,7 +677,6 @@ namespace Terminal.Gui { private void DrawParentBorder (Rect frame) { - var drawMarginFrame = DrawMarginFrame ? 1 : 0; var sumThickness = GetSumThickness (); var borderThickness = BorderThickness; var effect3DOffset = Effect3DOffset; @@ -682,7 +690,7 @@ namespace Terminal.Gui { for (int r = frame.Y; r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) { for (int c = frame.X; - c < frame.Right; c++) { + c < Math.Min (frame.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -690,7 +698,7 @@ namespace Terminal.Gui { // Draw the left BorderThickness for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom); - r < frame.Bottom - borderThickness.Bottom; r++) { + r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { for (int c = frame.X; c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) { @@ -700,9 +708,9 @@ namespace Terminal.Gui { // Draw the right BorderThickness for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom); - r < frame.Bottom - borderThickness.Bottom; r++) { + r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X); - c < frame.Right; c++) { + c < Math.Min (frame.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -710,9 +718,9 @@ namespace Terminal.Gui { // Draw the lower BorderThickness for (int r = Math.Max (frame.Bottom - borderThickness.Bottom, frame.Y); - r < frame.Bottom; r++) { + r < Math.Min (frame.Bottom, driver.Rows); r++) { for (int c = frame.X; - c < frame.Right; c++) { + c < Math.Min (frame.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -724,7 +732,7 @@ namespace Terminal.Gui { for (int r = frame.Y + borderThickness.Top; r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) { for (int c = frame.X + borderThickness.Left; - c < frame.Right - borderThickness.Right; c++) { + c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -732,7 +740,7 @@ namespace Terminal.Gui { // Draw the left Padding for (int r = frame.Y + sumThickness.Top; - r < frame.Bottom - sumThickness.Bottom; r++) { + r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) { for (int c = frame.X + borderThickness.Left; c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) { @@ -742,7 +750,7 @@ namespace Terminal.Gui { // Draw the right Padding for (int r = frame.Y + sumThickness.Top; - r < frame.Bottom - sumThickness.Bottom; r++) { + r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) { for (int c = Math.Max (frame.Right - sumThickness.Right, frame.X + sumThickness.Left); c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) { @@ -752,9 +760,9 @@ namespace Terminal.Gui { // Draw the lower Padding for (int r = Math.Max (frame.Bottom - sumThickness.Bottom, frame.Y + borderThickness.Top); - r < frame.Bottom - borderThickness.Bottom; r++) { + r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { for (int c = frame.X + borderThickness.Left; - c < frame.Right - borderThickness.Right; c++) { + c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -774,50 +782,57 @@ namespace Terminal.Gui { } if (Effect3D) { - driver.SetAttribute (new Attribute (Effect3DBrush)); + driver.SetAttribute (GetEffect3DBrush ()); // Draw the upper Effect3D - for (int r = frame.Y + effect3DOffset.Y; + for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0); r < frame.Y; r++) { - for (int c = frame.X + effect3DOffset.X; - c < frame.Right + effect3DOffset.X; c++) { + for (int c = Math.Max (frame.X + effect3DOffset.X, 0); + c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } // Draw the left Effect3D - for (int r = frame.Y + effect3DOffset.Y; - r < frame.Bottom + effect3DOffset.Y; r++) { - for (int c = frame.X + effect3DOffset.X; + for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0); + r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { + for (int c = Math.Max (frame.X + effect3DOffset.X, 0); c < frame.X; c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } // Draw the right Effect3D - for (int r = frame.Y + effect3DOffset.Y; - r < frame.Bottom + effect3DOffset.Y; r++) { + for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0); + r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = frame.Right; - c < frame.Right + effect3DOffset.X; c++) { + c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } // Draw the lower Effect3D for (int r = frame.Bottom; - r < frame.Bottom + effect3DOffset.Y; r++) { - for (int c = frame.X + effect3DOffset.X; - c < frame.Right + effect3DOffset.X; c++) { + r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { + for (int c = Math.Max (frame.X + effect3DOffset.X, 0); + c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { - AddRuneAt (driver, c, r, ' '); + AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } } } } + private Attribute GetEffect3DBrush () + { + return Effect3DBrush == null + ? new Attribute (Color.Gray, Color.DarkGray) + : (Attribute)Effect3DBrush; + } + private void AddRuneAt (ConsoleDriver driver, int col, int row, Rune ch) { driver.Move (col, row); diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 8d424ef79..dd2d1dd58 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -665,6 +665,9 @@ namespace Terminal.Gui { /// public abstract bool HeightAsBuffer { get; set; } + // The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag + internal abstract int [,,] Contents { get; } + /// /// Initializes the driver /// diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index 8056d23cd..e191169fe 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -213,7 +213,7 @@ namespace Terminal.Gui { /// /// true if can focus; otherwise, false. public override bool CanFocus { - get => true; + get => SuperView == null ? true : base.CanFocus; } /// @@ -348,6 +348,7 @@ namespace Terminal.Gui { top.FocusNext (); } top.SetNeedsDisplay (); + Application.EnsuresTopOnFront (); } else { MoveNext (); } @@ -361,6 +362,7 @@ namespace Terminal.Gui { top.FocusPrev (); } top.SetNeedsDisplay (); + Application.EnsuresTopOnFront (); } else { MovePrevious (); } @@ -656,16 +658,25 @@ namespace Terminal.Gui { // Driver.UncookMouse does not seem to have an effect if there is // a pending mouse event activated. + if (!CanFocus) { + return true; + } + int nx, ny; - if (!dragPosition.HasValue && mouseEvent.Flags == (MouseFlags.Button1Pressed)) { + if (!dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed + || mouseEvent.Flags == MouseFlags.Button2Pressed + || mouseEvent.Flags == MouseFlags.Button3Pressed)) { + + SetFocus (); + Application.EnsuresTopOnFront (); + // Only start grabbing if the user clicks on the title bar. - if (mouseEvent.Y == 0) { + if (mouseEvent.Y == 0 && mouseEvent.Flags == MouseFlags.Button1Pressed) { start = new Point (mouseEvent.X, mouseEvent.Y); dragPosition = new Point (); nx = mouseEvent.X - mouseEvent.OfX; ny = mouseEvent.Y - mouseEvent.OfY; dragPosition = new Point (nx, ny); - SuperView?.BringSubviewToFront (this); Application.GrabMouse (this); } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 642a92729..7d0e7b6d2 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -344,11 +344,6 @@ namespace Terminal.Gui { TabIndex = SuperView != null ? SuperView.tabIndexes.IndexOf (this) : -1; } TabStop = value; - if (!value && HasFocus) { - SetHasFocus (false, this); - } - OnCanFocusChanged (); - SetNeedsDisplay (); } if (subviews != null && IsInitialized) { foreach (var view in subviews) { @@ -369,6 +364,16 @@ namespace Terminal.Gui { } } } + if (!value && HasFocus) { + SetHasFocus (false, this); + EnsureFocus (); + if (Focused == null) { + Application.Top.FocusNext (); + Application.EnsuresTopOnFront (); + } + } + OnCanFocusChanged (); + SetNeedsDisplay (); } } @@ -1013,8 +1018,8 @@ namespace Terminal.Gui { internal void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true) { // Computes the real row, col relative to the screen. - rrow = Math.Max (row + frame.Y, 0); - rcol = Math.Max (col + frame.X, 0); + rrow = row + frame.Y; + rcol = col + frame.X; var ccontainer = container; while (ccontainer != null) { rrow += ccontainer.frame.Y; diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs index 5395ef016..6f84081da 100644 --- a/Terminal.Gui/Core/Window.cs +++ b/Terminal.Gui/Core/Window.cs @@ -159,6 +159,7 @@ namespace Terminal.Gui { void Initialize (ustring title, Rect frame, int padding = 0, Border border = null) { + CanFocus = true; ColorScheme = Colors.Base; Title = title; if (border == null) { @@ -235,13 +236,15 @@ namespace Terminal.Gui { } SetNeedsDisplay (); - var touched = view.Frame; contentView.Remove (view); if (contentView.InternalSubviews.Count < 1) { CanFocus = false; } RemoveMenuStatusBar (view); + if (view != contentView && Focused == null) { + FocusFirst (); + } } /// diff --git a/Terminal.Gui/Views/Label.cs b/Terminal.Gui/Views/Label.cs index 56aaeca7d..df70fdcce 100644 --- a/Terminal.Gui/Views/Label.cs +++ b/Terminal.Gui/Views/Label.cs @@ -101,6 +101,9 @@ namespace Terminal.Gui { if (mouseEvent.Flags == MouseFlags.Button1Clicked) { if (!HasFocus && SuperView != null) { + if (!SuperView.HasFocus) { + SuperView.SetFocus (); + } SetFocus (); SetNeedsDisplay (); } diff --git a/UICatalog/Scenarios/Editor.cs b/UICatalog/Scenarios/Editor.cs index 7e809d0a9..566a17079 100644 --- a/UICatalog/Scenarios/Editor.cs +++ b/UICatalog/Scenarios/Editor.cs @@ -23,6 +23,7 @@ namespace UICatalog { private bool _matchCase; private bool _matchWholeWord; private Window winDialog; + private TabView _tabView; public override void Init (Toplevel top, ColorScheme colorScheme) { @@ -97,7 +98,7 @@ namespace UICatalog { }), new MenuBarItem ("Forma_t", new MenuItem [] { CreateWrapChecked (), - CreateAutocomplete(), + CreateAutocomplete(), CreateAllowsTabChecked () }), new MenuBarItem ("_Responder", new MenuItem [] { @@ -163,12 +164,27 @@ namespace UICatalog { }; Win.KeyPress += (e) => { + var keys = ShortcutHelper.GetModifiersKey (e.KeyEvent); if (winDialog != null && (e.KeyEvent.Key == Key.Esc || e.KeyEvent.Key == (Key.Q | Key.CtrlMask))) { DisposeWinDialog (); } else if (e.KeyEvent.Key == (Key.Q | Key.CtrlMask)) { Quit (); e.Handled = true; + } else if (keys == (Key.Tab | Key.CtrlMask)) { + if (_tabView.SelectedTab == _tabView.Tabs.ElementAt (_tabView.Tabs.Count - 1)) { + _tabView.SelectedTab = _tabView.Tabs.ElementAt (0); + } else { + _tabView.SwitchTabBy (1); + } + e.Handled = true; + } else if (keys == (Key.Tab | Key.CtrlMask | Key.ShiftMask)) { + if (_tabView.SelectedTab == _tabView.Tabs.ElementAt (0)) { + _tabView.SelectedTab = _tabView.Tabs.ElementAt (_tabView.Tabs.Count - 1); + } else { + _tabView.SwitchTabBy (-1); + } + e.Handled = true; } }; } @@ -364,7 +380,7 @@ namespace UICatalog { private bool SaveAs () { - var aTypes = new List () { ".txt", ".bin", ".xml", ".*" }; + var aTypes = new List () { ".txt", ".bin", ".xml", ".*" }; var sd = new SaveDialog ("Save file", "Choose the path where to save the file.", aTypes); sd.FilePath = System.IO.Path.Combine (sd.FilePath.ToString (), Win.Title.ToString ()); Application.Run (sd); @@ -476,22 +492,21 @@ namespace UICatalog { return item; } - private MenuItem CreateAutocomplete() + private MenuItem CreateAutocomplete () { var auto = new MenuItem (); auto.Title = "Autocomplete"; auto.CheckType |= MenuItemCheckStyle.Checked; auto.Checked = false; auto.Action += () => { - if(auto.Checked = !auto.Checked) { + if (auto.Checked = !auto.Checked) { // setup autocomplete with all words currently in the editor - _textView.Autocomplete.AllSuggestions = - - Regex.Matches(_textView.Text.ToString(),"\\w+") - .Select(s=>s.Value) + _textView.Autocomplete.AllSuggestions = + + Regex.Matches (_textView.Text.ToString (), "\\w+") + .Select (s => s.Value) .Distinct ().ToList (); - } - else { + } else { _textView.Autocomplete.AllSuggestions.Clear (); } @@ -567,24 +582,30 @@ namespace UICatalog { private void CreateFindReplace (bool isFind = true) { + if (winDialog != null) { + winDialog.SetFocus (); + return; + } + winDialog = new Window (isFind ? "Find" : "Replace") { X = Win.Bounds.Width / 2 - 30, Y = Win.Bounds.Height / 2 - 10, - ColorScheme = Colors.Menu + ColorScheme = Colors.TopLevel }; + winDialog.Border.Effect3D = true; - var tabView = new TabView () { + _tabView = new TabView () { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () }; - tabView.AddTab (new TabView.Tab ("Find", FindTab ()), isFind); + _tabView.AddTab (new TabView.Tab ("Find", FindTab ()), isFind); var replace = ReplaceTab (); - tabView.AddTab (new TabView.Tab ("Replace", replace), !isFind); - tabView.SelectedTabChanged += (s, e) => tabView.SelectedTab.View.FocusFirst (); - winDialog.Add (tabView); + _tabView.AddTab (new TabView.Tab ("Replace", replace), !isFind); + _tabView.SelectedTabChanged += (s, e) => _tabView.SelectedTab.View.FocusFirst (); + winDialog.Add (_tabView); Win.Add (winDialog); diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs index c24f95673..e5b28a67c 100644 --- a/UnitTests/ApplicationTests.cs +++ b/UnitTests/ApplicationTests.cs @@ -1173,5 +1173,96 @@ namespace Terminal.Gui.Core { // Reset the QuitKey to avoid throws errors on another tests Application.QuitKey = Key.Q | Key.CtrlMask; } + + [Fact] + [AutoInitShutdown] + public void EnsuresTopOnFront_CanFocus_True_By_Keyboard_And_Mouse () + { + var top = Application.Top; + var win = new Window ("win") { X = 0, Y = 0, Width = 20, Height = 10 }; + var tf = new TextField () { Width = 10 }; + win.Add (tf); + var win2 = new Window ("win2") { X = 22, Y = 0, Width = 20, Height = 10 }; + var tf2 = new TextField () { Width = 10 }; + win2.Add (tf2); + top.Add (win, win2); + + Application.Begin (top); + + Assert.True (win.CanFocus); + Assert.True (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.False (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + + top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ())); + Assert.True (win.CanFocus); + Assert.False (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.True (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + + top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ())); + Assert.True (win.CanFocus); + Assert.True (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.False (win2.HasFocus); + Assert.Equal ("win", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + + win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed }); + Assert.True (win.CanFocus); + Assert.False (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.True (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released }); + Assert.Null (Toplevel.dragPosition); + } + + [Fact] + [AutoInitShutdown] + public void EnsuresTopOnFront_CanFocus_False_By_Keyboard_And_Mouse () + { + var top = Application.Top; + var win = new Window ("win") { X = 0, Y = 0, Width = 20, Height = 10 }; + var tf = new TextField () { Width = 10 }; + win.Add (tf); + var win2 = new Window ("win2") { X = 22, Y = 0, Width = 20, Height = 10 }; + var tf2 = new TextField () { Width = 10 }; + win2.Add (tf2); + top.Add (win, win2); + + Application.Begin (top); + + win.CanFocus = false; + Assert.False (win.CanFocus); + Assert.False (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.True (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + + top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ())); + Assert.True (win2.CanFocus); + Assert.False (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.True (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + + top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ())); + Assert.False (win.CanFocus); + Assert.False (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.True (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + + win.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed }); + Assert.False (win.CanFocus); + Assert.False (win.HasFocus); + Assert.True (win2.CanFocus); + Assert.True (win2.HasFocus); + Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title); + win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released }); + Assert.Null (Toplevel.dragPosition); + } } } diff --git a/UnitTests/BorderTests.cs b/UnitTests/BorderTests.cs index d65623136..4e2d88e15 100644 --- a/UnitTests/BorderTests.cs +++ b/UnitTests/BorderTests.cs @@ -9,6 +9,7 @@ using Rune = System.Rune; namespace Terminal.Gui.Core { public class BorderTests { [Fact] + [AutoInitShutdown] public void Constructor_Defaults () { var b = new Border (); @@ -24,7 +25,7 @@ namespace Terminal.Gui.Core { Assert.Null (b.ChildContainer); Assert.False (b.Effect3D); Assert.Equal (new Point (1, 1), b.Effect3DOffset); - Assert.Equal (Color.DarkGray, b.Effect3DBrush); + Assert.Null (b.Effect3DBrush); } [Fact] @@ -44,6 +45,7 @@ namespace Terminal.Gui.Core { } [Fact] + [AutoInitShutdown] public void ActualWidth_ActualHeight () { var v = new View (new Rect (5, 10, 60, 20), "", new Border ()); diff --git a/UnitTests/ComboBoxTests.cs b/UnitTests/ComboBoxTests.cs index 2b1088d33..3d6fc0095 100644 --- a/UnitTests/ComboBoxTests.cs +++ b/UnitTests/ComboBoxTests.cs @@ -3,7 +3,7 @@ using System.Linq; using Terminal.Gui; using Xunit; -namespace UnitTests { +namespace Terminal.Gui.Views { public class ComboBoxTests { [Fact] [AutoInitShutdown] diff --git a/UnitTests/ToplevelTests.cs b/UnitTests/ToplevelTests.cs index d8eaf0ba8..3bb59ba3b 100644 --- a/UnitTests/ToplevelTests.cs +++ b/UnitTests/ToplevelTests.cs @@ -310,6 +310,11 @@ namespace Terminal.Gui.Core { Assert.Null (Toplevel.dragPosition); win.MouseEvent (new MouseEvent () { X = 6, Y = 0, Flags = MouseFlags.Button1Pressed }); Assert.Equal (new Point (6, 0), Toplevel.dragPosition); + win.MouseEvent (new MouseEvent () { X = 6, Y = 0, Flags = MouseFlags.Button1Released }); + Assert.Null (Toplevel.dragPosition); + win.CanFocus = false; + win.MouseEvent (new MouseEvent () { X = 6, Y = 0, Flags = MouseFlags.Button1Pressed }); + Assert.Null (Toplevel.dragPosition); } } } diff --git a/UnitTests/ViewTests.cs b/UnitTests/ViewTests.cs index fb34db691..52baddb70 100644 --- a/UnitTests/ViewTests.cs +++ b/UnitTests/ViewTests.cs @@ -878,7 +878,7 @@ namespace Terminal.Gui.Views { Assert.True (v2.CanFocus); w.CanFocus = false; - Assert.True (w.CanFocus); + Assert.False (w.CanFocus); Assert.False (f.CanFocus); Assert.False (v1.CanFocus); Assert.False (v2.CanFocus); @@ -913,7 +913,7 @@ namespace Terminal.Gui.Views { Assert.True (v2.CanFocus); w.CanFocus = false; - Assert.True (w.CanFocus); + Assert.False (w.CanFocus); Assert.False (f.CanFocus); Assert.False (v1.CanFocus); Assert.False (v2.CanFocus); @@ -1411,6 +1411,12 @@ namespace Terminal.Gui.Views { view.LayoutComplete += (_) => { layoutStarted = false; }; view.OnLayoutComplete (null); Assert.False (layoutStarted); + view.X = Pos.Center () - 41; + view.Y = Pos.Center () - 13; + view.SetRelativeLayout (top.Bounds); + view.ViewToScreen (0, 0, out rcol, out rrow); + Assert.Equal (-1, rcol); + Assert.Equal (-1, rrow); } [Fact]