From 442497418595b0c219b26ed9a44ba13b1d802400 Mon Sep 17 00:00:00 2001 From: Tigger Kindel Date: Fri, 3 Mar 2023 10:22:50 -0700 Subject: [PATCH] merged --- .../Configuration/ConfigurationManager.cs | 22 +- .../CursesDriver/CursesDriver.cs | 5 - .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 5 - Terminal.Gui/ConsoleDrivers/NetDriver.cs | 6 - Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 5 - Terminal.Gui/Core/Application.cs | 17 +- Terminal.Gui/Core/Border.cs | 172 +++++-- Terminal.Gui/Core/ConsoleDriver.cs | 6 - Terminal.Gui/Core/PosDim.cs | 20 +- Terminal.Gui/Core/Toplevel.cs | 8 + Terminal.Gui/Core/View.cs | 88 ++-- Terminal.Gui/Terminal.Gui.csproj | 2 + Terminal.Gui/Views/FrameView.cs | 47 +- Terminal.Gui/Windows/Dialog.cs | 1 + UICatalog/Properties/launchSettings.json | 10 - UICatalog/Scenarios/ASCIICustomButton.cs | 313 +++++++++++++ UICatalog/Scenarios/Borders.cs | 13 +- UICatalog/Scenarios/BordersComparisons.cs | 6 +- UICatalog/Scenarios/BordersOnContainers.cs | 386 +++++++++++++++ UICatalog/Scenarios/BordersOnFrameView.cs | 388 +-------------- UICatalog/Scenarios/BordersOnToplevel.cs | 388 +-------------- UICatalog/Scenarios/BordersOnWindow.cs | 387 +-------------- UICatalog/UICatalog.cs | 16 +- UnitTests/Core/BorderTests.cs | 80 +++- UnitTests/Core/LayoutTests.cs | 442 +++++++++++++----- UnitTests/Core/ViewTests.cs | 99 ++++ UnitTests/TopLevels/ToplevelTests.cs | 52 ++- UnitTests/Types/DimTests.cs | 136 +++--- UnitTests/Types/PosTests.cs | 94 ++-- UnitTests/Views/ScrollBarViewTests.cs | 40 +- UnitTests/Views/ScrollViewTests.cs | 228 ++++++++- UnitTests/Views/StatusBarTests.cs | 2 +- UnitTests/Views/TextViewTests.cs | 12 +- 33 files changed, 1883 insertions(+), 1613 deletions(-) create mode 100644 UICatalog/Scenarios/ASCIICustomButton.cs create mode 100644 UICatalog/Scenarios/BordersOnContainers.cs diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index 1cfaa00d0..26c82db9c 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -44,7 +44,7 @@ namespace Terminal.Gui.Configuration { /// 3. Application configuration found in the applications's resources (Resources/config.json). /// /// - /// 4. Global configuration found in the the user's home directory (~/.tui/config.json). + /// 4. Global configuration found in the user's home directory (~/.tui/config.json). /// /// /// 5. Global configuration found in the directory the app was launched from (./.tui/config.json). @@ -63,7 +63,7 @@ namespace Terminal.Gui.Configuration { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, WriteIndented = true, Converters = { - // No need to set converterss - the ConfigRootConverter uses property attributes apply the correct + // No need to set converters - the ConfigRootConverter uses property attributes apply the correct // Converter. }, }; @@ -196,7 +196,7 @@ namespace Terminal.Gui.Configuration { /// /// /// Is until is called. Gets set to a new instance by - /// deserializtion (see ). + /// deserialization (see ). /// private static SettingsScope? _settings; @@ -230,7 +230,7 @@ namespace Terminal.Gui.Configuration { /// /// Initializes the internal state of ConfiguraitonManager. Nominally called once as part of application - /// startup to initilaize global state. Also called from some Unit Tests to ensure correctness (e.g. Reset()). + /// startup to initialize global state. Also called from some Unit Tests to ensure correctness (e.g. Reset()). /// internal static void Initialize () { @@ -260,7 +260,7 @@ namespace Terminal.Gui.Configuration { select p) { if (p.GetCustomAttribute (typeof (SerializableConfigurationProperty)) is SerializableConfigurationProperty scp) { if (p.GetGetMethod (true)!.IsStatic) { - // If the class name is ommited, JsonPropertyName is allowed. + // If the class name is omitted, JsonPropertyName is allowed. _allConfigProperties!.Add (scp.OmitClassName ? ConfigProperty.GetJsonPropertyName (p) : $"{p.DeclaringType?.Name}.{p.Name}", new ConfigProperty { PropertyInfo = p, PropertyValue = null @@ -357,7 +357,7 @@ namespace Terminal.Gui.Configuration { } /// - /// Event fired when the configuration has been upddated from a configuration source. + /// Event fired when the configuration has been updated from a configuration source. /// application. /// public static event Action? Updated; @@ -378,7 +378,7 @@ namespace Terminal.Gui.Configuration { } ClearJsonErrors (); - + Settings = new SettingsScope (); ThemeManager.Reset (); AppSettings = new AppScope (); @@ -402,7 +402,7 @@ namespace Terminal.Gui.Configuration { /// to generate the JSON doc that is embedded into Terminal.Gui (during development). /// /// - /// WARNING: The Terminal.Gui.Resources.config.json resource has setting defintions (Themes) + /// WARNING: The Terminal.Gui.Resources.config.json resource has setting definitions (Themes) /// that are NOT generated by this function. If you use this function to regenerate Terminal.Gui.Resources.config.json, /// make sure you copy the Theme definitions from the existing Terminal.Gui.Resources.config.json file. /// @@ -455,7 +455,7 @@ namespace Terminal.Gui.Configuration { public static string AppName { get; set; } = Assembly.GetEntryAssembly ()?.FullName?.Split (',') [0]?.Trim ()!; /// - /// Describes the location of the configuration files. The constancts can be + /// Describes the location of the configuration files. The constants can be /// combined (bitwise) to specify multiple locations. /// [Flags] @@ -488,7 +488,7 @@ namespace Terminal.Gui.Configuration { public static ConfigLocations Locations { get; set; } = ConfigLocations.All; /// - /// Loads all settings found in the various configuraiton storage locations to + /// Loads all settings found in the various configuration storage locations to /// the . Optionally, /// resets all settings attributed with to the defaults. /// @@ -507,7 +507,7 @@ namespace Terminal.Gui.Configuration { if (Locations == ConfigLocations.All) { var embeddedStylesResourceName = Assembly.GetEntryAssembly ()? .GetManifestResourceNames ().FirstOrDefault (x => x.EndsWith (_configFilename)); - if (string.IsNullOrEmpty(embeddedStylesResourceName)) { + if (string.IsNullOrEmpty (embeddedStylesResourceName)) { embeddedStylesResourceName = _configFilename; } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 7e5f4dcfd..7a7b09402 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -21,11 +21,6 @@ namespace Terminal.Gui { public override int Left => 0; public override int Top => 0; public override bool EnableConsoleScrolling { get; set; } - [Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)] - public override bool HeightAsBuffer { - get => EnableConsoleScrolling; - set => EnableConsoleScrolling = value; - } public override IClipboard Clipboard { get => clipboard; } CursorVisibility? initialCursorVisibility = null; diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 824a63829..30951dd73 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -46,11 +46,6 @@ namespace Terminal.Gui { public override int Left => 0; public override int Top => 0; public override bool EnableConsoleScrolling { get; set; } - [Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)] - public override bool HeightAsBuffer { - get => EnableConsoleScrolling; - set => EnableConsoleScrolling = value; - } private IClipboard clipboard = null; public override IClipboard Clipboard => clipboard; diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index da969d136..08e827683 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -621,12 +621,6 @@ namespace Terminal.Gui { public override int Left => left; public override int Top => top; public override bool EnableConsoleScrolling { get; set; } - [Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)] - public override bool HeightAsBuffer { - get => EnableConsoleScrolling; - set => EnableConsoleScrolling = value; - } - public NetWinVTConsole NetWinConsole { get; } public bool IsWinPlatform { get; } public override IClipboard Clipboard { get; } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index a2f87af0e..5de19fa85 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -716,11 +716,6 @@ namespace Terminal.Gui { public override int Left => left; public override int Top => top; public override bool EnableConsoleScrolling { get; set; } - [Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)] - public override bool HeightAsBuffer { - get => EnableConsoleScrolling; - set => EnableConsoleScrolling = value; - } public override IClipboard Clipboard => clipboard; public override int [,,] Contents => contents; diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 7f77bce97..a646cbddb 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -133,7 +133,7 @@ namespace Terminal.Gui { /// /// This API was previously named 'HeightAsBuffer` but was renamed to make its purpose more clear. /// - [SerializableConfigurationProperty (Scope = typeof(SettingsScope))] + [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] public static bool EnableConsoleScrolling { get { if (Driver == null) { @@ -150,21 +150,12 @@ namespace Terminal.Gui { } } - /// - /// This API is deprecated; use instead. - /// - [Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)] - public static bool HeightAsBuffer { - get => EnableConsoleScrolling; - set => EnableConsoleScrolling = value; - } - static Key alternateForwardKey = Key.PageDown | Key.CtrlMask; /// /// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key. /// - [SerializableConfigurationProperty (Scope = typeof(SettingsScope)), JsonConverter(typeof(KeyJsonConverter))] + [SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))] public static Key AlternateForwardKey { get => alternateForwardKey; set { @@ -188,7 +179,7 @@ namespace Terminal.Gui { /// /// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key. /// - [SerializableConfigurationProperty (Scope = typeof(SettingsScope)), JsonConverter (typeof (KeyJsonConverter))] + [SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))] public static Key AlternateBackwardKey { get => alternateBackwardKey; set { @@ -212,7 +203,7 @@ namespace Terminal.Gui { /// /// Gets or sets the key to quit the application. /// - [SerializableConfigurationProperty (Scope = typeof(SettingsScope)), JsonConverter (typeof (KeyJsonConverter))] + [SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))] public static Key QuitKey { get => quitKey; set { diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs index a7c5dac11..95a0f19f9 100644 --- a/Terminal.Gui/Core/Border.cs +++ b/Terminal.Gui/Core/Border.cs @@ -331,7 +331,8 @@ namespace Terminal.Gui { private Point effect3DOffset = new Point (1, 1); private Attribute? effect3DBrush; private ustring title = ustring.Empty; - + private View child; + /// /// Specifies the for a view. /// @@ -447,8 +448,47 @@ namespace Terminal.Gui { /// /// Gets or sets the single child element of a . /// - [JsonIgnore] - public View Child { get; set; } + public View Child { + get => child; + set { + child = value; + if (child != null && Parent != null) { + Parent.Initialized += Parent_Initialized; + Parent.Removed += Parent_Removed; + } + } + } + + private void Parent_Removed (View obj) + { + BorderBrush = default; + Background = default; + child.Removed -= Parent_Removed; + } + + private void Parent_Initialized (object s, EventArgs e) + { + SetMarginFrameTitleBrush (); + child.Initialized -= Parent_Initialized; + } + + private void SetMarginFrameTitleBrush () + { + if (child != null) { + var view = Parent?.Border != null ? Parent : child; + if (view.ColorScheme != null) { + if (borderBrush == default) { + BorderBrush = view.GetNormalColor ().Foreground; + } + if (background == default) { + Background = view.GetNormalColor ().Background; + } + return; + } + } + BorderBrush = default; + Background = default; + } /// /// Gets the parent parent if any. @@ -651,9 +691,13 @@ namespace Terminal.Gui { // Draw the upper BorderThickness for (int r = frame.Y - drawMarginFrame - sumThickness.Top; - r > 0 && r < frame.Y - drawMarginFrame - padding.Top; r++) { + r < frame.Y - drawMarginFrame - padding.Top; r++) { + + if (r < 0) { + continue; + } for (int c = frame.X - drawMarginFrame - sumThickness.Left; - c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -661,9 +705,13 @@ namespace Terminal.Gui { // Draw the left BorderThickness for (int r = frame.Y - drawMarginFrame - padding.Top; - r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { + + if (r < 0) { + continue; + } for (int c = frame.X - drawMarginFrame - sumThickness.Left; - c > 0 && c < frame.X - drawMarginFrame - padding.Left; c++) { + c < frame.X - drawMarginFrame - padding.Left; c++) { AddRuneAt (driver, c, r, ' '); } @@ -671,9 +719,13 @@ namespace Terminal.Gui { // Draw the right BorderThickness for (int r = frame.Y - drawMarginFrame - padding.Top; - r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { + + if (r < 0) { + continue; + } for (int c = frame.Right + drawMarginFrame + padding.Right; - c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -681,9 +733,9 @@ namespace Terminal.Gui { // Draw the lower BorderThickness for (int r = frame.Bottom + drawMarginFrame + padding.Bottom; - r > 0 && r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - sumThickness.Left; - c > 0 && c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { + c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -693,9 +745,13 @@ namespace Terminal.Gui { // Draw the upper Padding for (int r = frame.Y - drawMarginFrame - padding.Top; - r > 0 && r < frame.Y - drawMarginFrame; r++) { + r < frame.Y - drawMarginFrame; r++) { + + if (r < 0) { + continue; + } for (int c = frame.X - drawMarginFrame - padding.Left; - c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { + c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -703,9 +759,9 @@ namespace Terminal.Gui { // Draw the left Padding for (int r = frame.Y - drawMarginFrame; - r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) { + r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - padding.Left; - c > 0 && c < frame.X - drawMarginFrame; c++) { + c < frame.X - drawMarginFrame; c++) { AddRuneAt (driver, c, r, ' '); } @@ -713,9 +769,9 @@ namespace Terminal.Gui { // Draw the right Padding for (int r = frame.Y - drawMarginFrame; - r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) { + r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) { for (int c = frame.Right + drawMarginFrame; - c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { + c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -723,9 +779,9 @@ namespace Terminal.Gui { // Draw the lower Padding for (int r = frame.Bottom + drawMarginFrame; - r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) { for (int c = frame.X - drawMarginFrame - padding.Left; - c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { + c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -825,9 +881,12 @@ namespace Terminal.Gui { // Draw the upper BorderThickness for (int r = frame.Y; - r > 0 && r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) { + r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) { + if (r < 0) { + continue; + } for (int c = frame.X; - c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) { + c < Math.Min (frame.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -835,9 +894,13 @@ namespace Terminal.Gui { // Draw the left BorderThickness for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom); - r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { + + if (r < 0) { + continue; + } for (int c = frame.X; - c > 0 && c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) { + c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) { AddRuneAt (driver, c, r, ' '); } @@ -845,9 +908,13 @@ namespace Terminal.Gui { // Draw the right BorderThickness for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom); - r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { + + if (r < 0) { + continue; + } for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X); - c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) { + c < Math.Min (frame.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -855,9 +922,9 @@ namespace Terminal.Gui { // Draw the lower BorderThickness for (int r = Math.Max (frame.Bottom - borderThickness.Bottom, frame.Y); - r > 0 && r < Math.Min (frame.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom, driver.Rows); r++) { for (int c = frame.X; - c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) { + c < Math.Min (frame.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -867,9 +934,13 @@ namespace Terminal.Gui { // Draw the upper Padding for (int r = frame.Y + borderThickness.Top; - r > 0 && r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) { + r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) { + + if (r < 0) { + continue; + } for (int c = frame.X + borderThickness.Left; - c > 0 && c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) { + c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -877,9 +948,13 @@ namespace Terminal.Gui { // Draw the left Padding for (int r = frame.Y + sumThickness.Top; - r > 0 && r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) { + + if (r < 0) { + continue; + } for (int c = frame.X + borderThickness.Left; - c > 0 && c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) { + c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) { AddRuneAt (driver, c, r, ' '); } @@ -887,9 +962,13 @@ namespace Terminal.Gui { // Draw the right Padding for (int r = frame.Y + sumThickness.Top; - r > 0 && r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) { + + if (r < 0) { + continue; + } for (int c = Math.Max (frame.Right - sumThickness.Right, frame.X + sumThickness.Left); - c > 0 && c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) { + c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) { AddRuneAt (driver, c, r, ' '); } @@ -897,9 +976,9 @@ namespace Terminal.Gui { // Draw the lower Padding for (int r = Math.Max (frame.Bottom - sumThickness.Bottom, frame.Y + borderThickness.Top); - r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { + r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) { for (int c = frame.X + borderThickness.Left; - c > 0 && c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) { + c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) { AddRuneAt (driver, c, r, ' '); } @@ -926,9 +1005,9 @@ namespace Terminal.Gui { // Draw the upper Effect3D for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0); - r > 0 && r < frame.Y; r++) { + r < frame.Y; r++) { for (int c = Math.Max (frame.X + effect3DOffset.X, 0); - c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { + c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } @@ -936,9 +1015,9 @@ namespace Terminal.Gui { // Draw the left Effect3D for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0); - r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { + r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = Math.Max (frame.X + effect3DOffset.X, 0); - c > 0 && c < frame.X; c++) { + c < frame.X; c++) { AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } @@ -946,9 +1025,9 @@ namespace Terminal.Gui { // Draw the right Effect3D for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0); - r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { + r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = frame.Right; - c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { + c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } @@ -956,9 +1035,9 @@ namespace Terminal.Gui { // Draw the lower Effect3D for (int r = frame.Bottom; - r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { + r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) { for (int c = Math.Max (frame.X + effect3DOffset.X, 0); - c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { + c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) { AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]); } @@ -987,9 +1066,10 @@ namespace Terminal.Gui { { var driver = Application.Driver; if (DrawMarginFrame) { - driver.SetAttribute (Child.GetNormalColor ()); - if (Child.HasFocus) - driver.SetAttribute (Child.ColorScheme.HotNormal); + driver.SetAttribute (new Attribute (BorderBrush, Background)); + if (view.HasFocus) { + driver.SetAttribute (new Attribute (Child.ColorScheme.HotNormal.Foreground, Background)); + } var padding = view.Border.GetSumThickness (); Rect scrRect; if (view == Child) { diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 8b2b535c1..48fcb26eb 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -713,12 +713,6 @@ namespace Terminal.Gui { /// public abstract bool EnableConsoleScrolling { get; set; } - /// - /// This API is deprecated; use instead. - /// - [Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)] - public abstract bool HeightAsBuffer { get; set; } - /// /// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag /// diff --git a/Terminal.Gui/Core/PosDim.cs b/Terminal.Gui/Core/PosDim.cs index 696607696..0c9278359 100644 --- a/Terminal.Gui/Core/PosDim.cs +++ b/Terminal.Gui/Core/PosDim.cs @@ -85,7 +85,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Factor({factor})"; + return $"PosFactor({factor})"; } public override int GetHashCode () => factor.GetHashCode (); @@ -135,7 +135,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"AnchorEnd({n})"; + return $"PosAnchorEnd({n})"; } } @@ -174,7 +174,7 @@ namespace Terminal.Gui { public override string ToString () { - return "Center"; + return "PosCenter"; } } @@ -209,7 +209,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Absolute({n})"; + return $"PosAbsolute({n})"; } internal override int Anchor (int width) @@ -264,7 +264,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Combine({left}{(add ? '+' : '-')}{right})"; + return $"PosCombine({left}{(add ? '+' : '-')}{right})"; } } @@ -345,7 +345,7 @@ namespace Terminal.Gui { case 3: tside = "bottom"; break; default: tside = "unknown"; break; } - return $"View({tside},{Target.ToString()})"; + return $"PosView({tside},{Target.ToString ()})"; } public override int GetHashCode () => Target.GetHashCode (); @@ -482,7 +482,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Factor({factor},{remaining})"; + return $"DimFactor({factor},{remaining})"; } public override int GetHashCode () => factor.GetHashCode (); @@ -522,7 +522,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Absolute({n})"; + return $"DimAbsolute({n})"; } internal override int Anchor (int width) @@ -541,7 +541,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Fill({margin})"; + return $"DimFill({margin})"; } internal override int Anchor (int width) @@ -613,7 +613,7 @@ namespace Terminal.Gui { public override string ToString () { - return $"Combine({left}{(add ? '+' : '-')}{right})"; + return $"DimCombine({left}{(add ? '+' : '-')}{right})"; } } diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index 02691b84f..63e11e626 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -167,6 +167,7 @@ namespace Terminal.Gui { /// virtual public void OnLoaded () { + IsLoaded = true; foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) { tl.OnLoaded (); } @@ -367,6 +368,13 @@ namespace Terminal.Gui { } } + /// + /// if was already loaded by the + /// , otherwise. This is used to avoid the + /// having wrong values while this was not yet loaded. + /// + public bool IsLoaded { get; private set; } + /// public override bool OnKeyDown (KeyEvent keyEvent) { diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 2b85cfbc5..045a8a53a 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -829,6 +829,11 @@ namespace Terminal.Gui { Rect GetMaxNeedDisplay (Rect oldFrame, Rect newFrame) { + var topSuperView = GetTopSuperView (); + if (topSuperView == null || topSuperView is not Toplevel || ((Toplevel)topSuperView)?.IsLoaded == false) { + return newFrame; + } + var rect = new Rect () { X = Math.Min (oldFrame.X, newFrame.X), Y = Math.Min (oldFrame.Y, newFrame.Y), @@ -1110,15 +1115,8 @@ namespace Terminal.Gui { /// public void Clear () { - Rect containerBounds = GetContainerBounds (); - Rect viewBounds = Bounds; - if (!containerBounds.IsEmpty) { - viewBounds.Width = Math.Min (viewBounds.Width, containerBounds.Width); - viewBounds.Height = Math.Min (viewBounds.Height, containerBounds.Height); - } - - var h = viewBounds.Height; - var w = viewBounds.Width; + var h = Frame.Height; + var w = Frame.Width; for (var line = 0; line < h; line++) { Move (0, line); for (var col = 0; col < w; col++) @@ -1524,8 +1522,6 @@ namespace Terminal.Gui { var boundsAdjustedForBorder = Bounds; if (!IgnoreBorderPropertyOnRedraw && Border != null) { Border.DrawContent (this); - boundsAdjustedForBorder = new Rect (bounds.X + 1, bounds.Y + 1, Math.Max (0, bounds.Width - 2), Math.Max(0, bounds.Height - 2)); - boundsAdjustedForBorder = Bounds;// new Rect (bounds.X + 1, bounds.Y + 1, Math.Max (bounds.Width, bounds.Width - 2), Math.Max (bounds.Height, bounds.Height - 2)); } else if (ustring.IsNullOrEmpty (TextFormatter.Text) && (GetType ().IsNestedPublic && !IsOverridden (this, "Redraw") || GetType ().Name == "View") && (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded)) { @@ -1536,14 +1532,14 @@ namespace Terminal.Gui { if (!ustring.IsNullOrEmpty (TextFormatter.Text)) { Rect containerBounds = GetContainerBounds (); - Clear (ViewToScreen (GetNeedDisplay (containerBounds))); + Clear (GetNeedDisplay (containerBounds)); SetChildNeedsDisplay (); // Draw any Text if (TextFormatter != null) { TextFormatter.NeedsFormat = true; } - TextFormatter?.Draw (ViewToScreen (boundsAdjustedForBorder), HasFocus ? ColorScheme.Focus : GetNormalColor (), - HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled, + TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (), + HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (), containerBounds); } @@ -1553,7 +1549,7 @@ namespace Terminal.Gui { if (subviews != null) { foreach (var view in subviews) { if (!view.NeedDisplay.IsEmpty || view.ChildNeedsDisplay || view.LayoutNeeded) { - if (view.Frame.IntersectsWith (clipRect) && (view.Frame.IntersectsWith (boundsAdjustedForBorder) || boundsAdjustedForBorder.X < 0 || bounds.Y < 0)) { + if (view.Frame.IntersectsWith (clipRect) && (view.Frame.IntersectsWith (bounds) || bounds.X < 0 || bounds.Y < 0)) { if (view.LayoutNeeded) { view.LayoutSubviews (); } @@ -1582,7 +1578,7 @@ namespace Terminal.Gui { Rect GetNeedDisplay (Rect containerBounds) { - Rect rect = NeedDisplay; + Rect rect = ViewToScreen (NeedDisplay); if (!containerBounds.IsEmpty) { rect.Width = Math.Min (NeedDisplay.Width, containerBounds.Width); rect.Height = Math.Min (NeedDisplay.Height, containerBounds.Height); @@ -2223,8 +2219,7 @@ namespace Terminal.Gui { newLocation = pos.Anchor (superviewDimension - newDimension); break; - case Pos.PosCombine: - var combine = pos as Pos.PosCombine; + case Pos.PosCombine combine: int left, right; (left, newDimension) = GetNewLocationAndDimension (superviewLocation, superviewDimension, combine.left, dim, autosizeDimension); (right, newDimension) = GetNewLocationAndDimension (superviewLocation, superviewDimension, combine.right, dim, autosizeDimension); @@ -2251,7 +2246,7 @@ namespace Terminal.Gui { // Recursively calculates the new dimension (width or height) of the given Dim given: // the current location (x or y) - // the current dimennsion (width or height) + // the current dimension (width or height) int CalculateNewDimension (Dim d, int location, int dimension, int autosize) { int newDimension; @@ -2269,12 +2264,12 @@ namespace Terminal.Gui { } newDimension = AutoSize && autosize > newDimension ? autosize : newDimension; break; - + case Dim.DimFactor factor when !factor.IsFromRemaining (): newDimension = d.Anchor (dimension); newDimension = AutoSize && autosize > newDimension ? autosize : newDimension; break; - + case Dim.DimFill: default: newDimension = Math.Max (d.Anchor (dimension - location), 0); @@ -2286,11 +2281,11 @@ namespace Terminal.Gui { } - // horiztonal - (newX, newW) = GetNewLocationAndDimension (superviewFrame.X, superviewFrame.Width, x, Width, autosize.Width); + // horizontal + (newX, newW) = GetNewLocationAndDimension (superviewFrame.X, superviewFrame.Width, x, width, autosize.Width); // vertical - (newY, newH) = GetNewLocationAndDimension (superviewFrame.Y, superviewFrame.Height, y, Height, autosize.Height); + (newY, newH) = GetNewLocationAndDimension (superviewFrame.Y, superviewFrame.Height, y, height, autosize.Height); var r = new Rect (newX, newY, newW, newH); if (Frame != r) { @@ -2438,7 +2433,7 @@ namespace Terminal.Gui { if (edges.Any ()) { (var from, var to) = edges.First (); - if (from != Application.Top) { + if (from != superView?.GetTopSuperView (to, from)) { if (!ReferenceEquals (from, to)) { throw new InvalidOperationException ($"TopologicalSort (for Pos/Dim) cannot find {from} linked with {to}. Did you forget to add it to {superView}?"); } else { @@ -2449,8 +2444,8 @@ namespace Terminal.Gui { // return L (a topologically sorted order) return result; } // TopologicalSort - - + + /// /// Invoked when a view starts executing or when the dimensions of the view have changed, for example in /// response to the container view or terminal resizing. @@ -2475,20 +2470,16 @@ namespace Terminal.Gui { CollectAll (this, ref nodes, ref edges); var ordered = View.TopologicalSort (SuperView, nodes, edges); foreach (var v in ordered) { - if (v.LayoutStyle == LayoutStyle.Computed) { - v.SetRelativeLayout (Frame); - } - - v.LayoutSubviews (); - v.LayoutNeeded = false; + LayoutSubview (v, Frame); } - // If our SuperView is Application.Top and the layoutstyle is Computed it's a special-cass. - // Use SetRelativeaLayout with the Frame of the Application.Top - if (SuperView != null && SuperView == Application.Top && LayoutNeeded - && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) { - Debug.Assert (Application.Top.Frame.Location == Point.Empty); - SetRelativeLayout (Application.Top.Frame); + // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case. + // Use LayoutSubview with the Frame of the 'from' + if (SuperView != null && GetTopSuperView () != null && LayoutNeeded + && ordered.Count == 0 && edges.Count > 0 && LayoutStyle == LayoutStyle.Computed) { + + (var from, var to) = edges.First (); + LayoutSubview (to, from.Frame); } LayoutNeeded = false; @@ -2496,6 +2487,16 @@ namespace Terminal.Gui { OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds }); } + private void LayoutSubview (View v, Rect hostFrame) + { + if (v.LayoutStyle == LayoutStyle.Computed) { + v.SetRelativeLayout (hostFrame); + } + + v.LayoutSubviews (); + v.LayoutNeeded = false; + } + ustring text; /// @@ -3165,11 +3166,14 @@ namespace Terminal.Gui { /// Get the top superview of a given . /// /// The superview view. - public View GetTopSuperView () + public View GetTopSuperView (View view = null, View superview = null) { - View top = Application.Top; - for (var v = this?.SuperView; v != null; v = v.SuperView) { + View top = superview ?? Application.Top; + for (var v = view?.SuperView ?? (this?.SuperView); v != null; v = v.SuperView) { top = v; + if (top == superview) { + break; + } } return top; diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index 8a39d1591..d69d6d92a 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -30,6 +30,7 @@ + @@ -60,6 +61,7 @@ Strings.Designer.cs + net472;netstandard2.0;net6.0 9 diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs index 8528a6abc..1264d4159 100644 --- a/Terminal.Gui/Views/FrameView.cs +++ b/Terminal.Gui/Views/FrameView.cs @@ -162,7 +162,8 @@ namespace Terminal.Gui { this.Title = title; if (border == null) { Border = new Border () { - BorderStyle = DefaultBorderStyle + BorderStyle = DefaultBorderStyle, + Title = title }; } else { Border = border; @@ -284,13 +285,7 @@ namespace Terminal.Gui { if (!IgnoreBorderPropertyOnRedraw) { Driver.SetAttribute (GetNormalColor ()); - //Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: false); Border.DrawContent (this, false); - if (HasFocus) - Driver.SetAttribute (ColorScheme.HotNormal); - if (Border.DrawMarginFrame) - Driver.DrawWindowTitle (scrRect, Title, padding.Left, padding.Top, padding.Right, padding.Bottom); - Driver.SetAttribute (GetNormalColor ()); } else { var lc = new LineCanvas (); @@ -312,28 +307,28 @@ namespace Terminal.Gui { //} - Driver.SetAttribute (ColorScheme.Normal); - foreach (var p in lc.GenerateImage (bounds)) { - this.AddRune (p.Key.X, p.Key.Y, p.Value); - } + //Driver.SetAttribute (ColorScheme.Normal); + //foreach (var p in lc.GenerateImage (bounds)) { + // this.AddRune (p.Key.X, p.Key.Y, p.Value); + //} - // Redraw the lines so that focus/drag symbol renders - foreach (var subview in contentView.Subviews) { - // line.DrawSplitterSymbol (); - } + //// Redraw the lines so that focus/drag symbol renders + //foreach (var subview in contentView.Subviews) { + // // line.DrawSplitterSymbol (); + //} - // Draw Titles over Border - foreach (var subview in contentView.Subviews) { - // TODO: Use reflection to see if subview has a Title property - if (subview is FrameView viewWithTite) { - var rect = viewWithTite.Frame; - rect.X = rect.X + 1; - rect.Y = rect.Y + 2; - // TODO: Do focus color correctly - Driver.DrawWindowTitle (rect, viewWithTite.Title, padding.Left, padding.Top, padding.Right, padding.Bottom); - } - } + //// Draw Titles over Border + //foreach (var subview in contentView.Subviews) { + // // TODO: Use reflection to see if subview has a Title property + // if (subview is FrameView viewWithTite) { + // var rect = viewWithTite.Frame; + // rect.X = rect.X + 1; + // rect.Y = rect.Y + 2; + // // TODO: Do focus color correctly + // Driver.DrawWindowTitle (rect, viewWithTite.Title, padding.Left, padding.Top, padding.Right, padding.Bottom); + // } + //} } } diff --git a/Terminal.Gui/Windows/Dialog.cs b/Terminal.Gui/Windows/Dialog.cs index fa88257a0..f1ff80a69 100644 --- a/Terminal.Gui/Windows/Dialog.cs +++ b/Terminal.Gui/Windows/Dialog.cs @@ -79,6 +79,7 @@ namespace Terminal.Gui { Modal = true; ButtonAlignment = DefaultButtonAlignment; Border = DefaultBorder; + Border.Title = title; if (buttons != null) { foreach (var b in buttons) { diff --git a/UICatalog/Properties/launchSettings.json b/UICatalog/Properties/launchSettings.json index e2cc967c3..4fe02b923 100644 --- a/UICatalog/Properties/launchSettings.json +++ b/UICatalog/Properties/launchSettings.json @@ -50,16 +50,6 @@ "Windows & FrameViews": { "commandName": "Project", "commandLineArgs": "\"Windows & FrameViews\"" - }, - "WSL : UICatalog": { - "commandName": "Executable", - "executablePath": "wsl", - "commandLineArgs": "dotnet UICatalog.dll", - "distributionName": "" - }, - "Tile View Experiments": { - "commandName": "Project", - "commandLineArgs": "\"Tile View Experiments\"" } } } \ No newline at end of file diff --git a/UICatalog/Scenarios/ASCIICustomButton.cs b/UICatalog/Scenarios/ASCIICustomButton.cs new file mode 100644 index 000000000..a58b2200c --- /dev/null +++ b/UICatalog/Scenarios/ASCIICustomButton.cs @@ -0,0 +1,313 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Terminal.Gui; + +namespace UICatalog.Scenarios { + [ScenarioMetadata (Name: "ASCIICustomButtonTest", Description: "ASCIICustomButton sample")] + [ScenarioCategory ("Controls")] + public class ASCIICustomButtonTest : Scenario { + private static bool smallerWindow; + private ScrollViewTestWindow scrollViewTestWindow; + private MenuItem miSmallerWindow; + + public override void Init (ColorScheme colorScheme) + { + Application.Init (); + scrollViewTestWindow = new ScrollViewTestWindow (); + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem("Window Size", new MenuItem [] { + miSmallerWindow = new MenuItem ("Smaller Window", "", ChangeWindowSize) { + CheckType = MenuItemCheckStyle.Checked + }, + null, + new MenuItem("Quit", "",() => Application.RequestStop(),null,null, Key.Q | Key.CtrlMask) + }) + }); + Application.Top.Add (menu, scrollViewTestWindow); + Application.Run (); + } + + private void ChangeWindowSize () + { + smallerWindow = (bool)(miSmallerWindow.Checked = !miSmallerWindow.Checked); + scrollViewTestWindow.Dispose (); + Application.Top.Remove (scrollViewTestWindow); + scrollViewTestWindow = new ScrollViewTestWindow (); + Application.Top.Add (scrollViewTestWindow); + } + + public override void Run () + { + } + + public class ASCIICustomButton : Button { + public string Description => $"Description of: {id}"; + + public event Action PointerEnter; + + private Label fill; + private FrameView border; + private string id; + + public ASCIICustomButton (string text, Pos x, Pos y, int width, int height) : base (text) + { + CustomInitialize ("", text, x, y, width, height); + } + + public ASCIICustomButton (string id, string text, Pos x, Pos y, int width, int height) : base (text) + { + CustomInitialize (id, text, x, y, width, height); + } + + private void CustomInitialize (string id, string text, Pos x, Pos y, int width, int height) + { + this.id = id; + X = x; + Y = y; + + Frame = new Rect { + Width = width, + Height = height + }; + + border = new FrameView () { + Width = width, + Height = height + }; + + AutoSize = false; + + var fillText = new System.Text.StringBuilder (); + for (int i = 0; i < Bounds.Height; i++) { + if (i > 0) { + fillText.AppendLine (""); + } + for (int j = 0; j < Bounds.Width; j++) { + fillText.Append ("█"); + } + } + + fill = new Label (fillText.ToString ()) { + Visible = false, + CanFocus = false + }; + + var title = new Label (text) { + X = Pos.Center (), + Y = Pos.Center (), + }; + + border.MouseClick += This_MouseClick; + border.Subviews [0].MouseClick += This_MouseClick; + fill.MouseClick += This_MouseClick; + title.MouseClick += This_MouseClick; + + Add (border, fill, title); + } + + private void This_MouseClick (MouseEventArgs obj) + { + OnMouseEvent (obj.MouseEvent); + } + + public override bool OnMouseEvent (MouseEvent mouseEvent) + { + Debug.WriteLine ($"{mouseEvent.Flags}"); + if (mouseEvent.Flags == MouseFlags.Button1Clicked) { + if (!HasFocus && SuperView != null) { + if (!SuperView.HasFocus) { + SuperView.SetFocus (); + } + SetFocus (); + SetNeedsDisplay (); + } + + OnClicked (); + return true; + } + return base.OnMouseEvent (mouseEvent); + } + + public override bool OnEnter (View view) + { + border.Visible = false; + fill.Visible = true; + PointerEnter.Invoke (this); + view = this; + return base.OnEnter (view); + } + + public override bool OnLeave (View view) + { + border.Visible = true; + fill.Visible = false; + if (view == null) + view = this; + return base.OnLeave (view); + } + } + + public class ScrollViewTestWindow : Window { + private List