From fdeb8e90d198051c2d6ba0041d64ba2a280eb996 Mon Sep 17 00:00:00 2001 From: Tig Date: Wed, 30 Oct 2024 15:47:38 -0600 Subject: [PATCH] WIP: Figuring out how to make margin transparent --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 4 +- Terminal.Gui/Text/TextFormatter.cs | 7 ++- Terminal.Gui/View/Adornment/Border.cs | 44 ++++++++++++++---- Terminal.Gui/View/Adornment/Margin.cs | 28 +++++++++++ Terminal.Gui/View/View.Adornments.cs | 3 ++ Terminal.Gui/View/View.Content.cs | 1 - Terminal.Gui/View/View.Drawing.cs | 37 +++++++-------- Terminal.Gui/Views/Shortcut.cs | 2 + Terminal.Gui/Views/SpinnerView/SpinnerView.cs | 12 ++++- UICatalog/Scenarios/AdvancedClipping.cs | 46 ++++++++++--------- UICatalog/Scenarios/ShadowStyles.cs | 2 +- 11 files changed, 129 insertions(+), 57 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index a5e2315d4..23607e664 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -437,8 +437,8 @@ public abstract class ConsoleDriver /// public virtual bool IsRuneSupported (Rune rune) { return Rune.IsValid (rune.Value); } - /// Tests whether the specified coordinate are valid for drawing. - /// + /// Tests whether the specified coordinate are valid for drawing the specified Rune. + /// Used to determine if one or two columns are required. /// The column. /// The row. /// diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs index 5748ae0fb..325f03f90 100644 --- a/Terminal.Gui/Text/TextFormatter.cs +++ b/Terminal.Gui/Text/TextFormatter.cs @@ -68,7 +68,12 @@ public class TextFormatter return; } - driver ??= Application.Driver; + if (driver is null) + { + driver = Application.Driver; + } + + Debug.Assert (driver is { }); driver?.SetAttribute (normalColor); diff --git a/Terminal.Gui/View/Adornment/Border.cs b/Terminal.Gui/View/Adornment/Border.cs index 5db617015..bbaa848fe 100644 --- a/Terminal.Gui/View/Adornment/Border.cs +++ b/Terminal.Gui/View/Adornment/Border.cs @@ -64,6 +64,39 @@ public class Border : Adornment HighlightStyle |= HighlightStyle.Pressed; Highlight += Border_Highlight; + + ThicknessChanged += OnThicknessChanged; + } + + private void OnThicknessChanged (object? sender, EventArgs e) + { + if (IsInitialized) + { + ShowHideDrawIndicator(); + } + } + + private void ShowHideDrawIndicator () + { + if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.DrawIndicator) && Thickness != Thickness.Empty) + { + if (DrawIndicator is null) + { + DrawIndicator = new SpinnerView () + { + X = 1, + Style = new SpinnerStyle.Dots2 (), + SpinDelay = 0, + }; + Add (DrawIndicator); + } + } + else if (DrawIndicator is { }) + { + Remove (DrawIndicator); + DrawIndicator!.Dispose (); + DrawIndicator = null; + } } #if SUBVIEW_BASED_BORDER @@ -80,6 +113,7 @@ public class Border : Adornment { base.BeginInit (); + ShowHideDrawIndicator (); #if SUBVIEW_BASED_BORDER if (Parent is { }) { @@ -105,16 +139,6 @@ public class Border : Adornment LayoutStarted += OnLayoutStarted; } #endif - if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.DrawIndicator)) - { - DrawIndicator = new SpinnerView () - { - X = 1, - Style = new SpinnerStyle.Dots2 (), - SpinDelay = 0, - }; - Add (DrawIndicator); - } } #if SUBVIEW_BASED_BORDER diff --git a/Terminal.Gui/View/Adornment/Margin.cs b/Terminal.Gui/View/Adornment/Margin.cs index c325462f0..17edaed04 100644 --- a/Terminal.Gui/View/Adornment/Margin.cs +++ b/Terminal.Gui/View/Adornment/Margin.cs @@ -1,9 +1,17 @@ #nullable enable +using Microsoft.VisualBasic; +using static Terminal.Gui.SpinnerStyle; +using static Unix.Terminal.Curses; +using System.Text; + namespace Terminal.Gui; /// The Margin for a . Accessed via /// +/// +/// The margin is typically transparent. This can be overriden by explicitly setting . +/// /// See the class. /// public class Margin : Adornment @@ -70,6 +78,7 @@ public class Margin : Adornment /// protected override bool OnClearingViewport () { + return ColorScheme is null; if (Thickness == Thickness.Empty) { return true; @@ -89,6 +98,25 @@ public class Margin : Adornment return true; } + /// + protected override bool OnDrawingContent () + { + Rectangle screen = FrameToScreen(); + for (int r = 0; r < screen.Height; r++) + { + for (int c = 0; c < screen.Width; c++) + { + Driver?.Move (c, r); + + if (Driver?.Contents is { } && c < Driver.Contents.GetLength (1) && r < Driver.Contents.GetLength (0)) + { + Driver.AddRune (Driver.Contents [r, c].Rune); + } + } + } + return true; + } + ///// ////protected override bool OnDrawSubviews (Rectangle viewport) { return true; } diff --git a/Terminal.Gui/View/View.Adornments.cs b/Terminal.Gui/View/View.Adornments.cs index 4a1d8d9e3..0775cdcd3 100644 --- a/Terminal.Gui/View/View.Adornments.cs +++ b/Terminal.Gui/View/View.Adornments.cs @@ -46,6 +46,9 @@ public partial class View // Adornments /// /// /// + /// The margin is typically transparent. This can be overriden by explicitly setting . + /// + /// /// Enabling will change the Thickness of the Margin to include the shadow. /// /// diff --git a/Terminal.Gui/View/View.Content.cs b/Terminal.Gui/View/View.Content.cs index c09bf4950..8021cbb1c 100644 --- a/Terminal.Gui/View/View.Content.cs +++ b/Terminal.Gui/View/View.Content.cs @@ -170,7 +170,6 @@ public partial class View public Point ContentToScreen (in Point location) { // Subtract the ViewportOffsetFromFrame to get the Viewport-relative location. - Point viewportOffset = GetViewportOffsetFromFrame (); Point contentRelativeToViewport = location; contentRelativeToViewport.Offset (-Viewport.X, -Viewport.Y); diff --git a/Terminal.Gui/View/View.Drawing.cs b/Terminal.Gui/View/View.Drawing.cs index 160036351..e54e8c07f 100644 --- a/Terminal.Gui/View/View.Drawing.cs +++ b/Terminal.Gui/View/View.Drawing.cs @@ -25,23 +25,8 @@ public partial class View // Drawing APIs Region? saved = null; if (CanBeVisible (this) && (NeedsDraw || SubViewNeedsDraw)) { - if (Border is { Diagnostics: ViewDiagnosticFlags.DrawIndicator }) - { - if (Border.DrawIndicator is { }) - { - Border.DrawIndicator.AdvanceAnimation (false); - Border.DrawIndicator.DrawText (); - - } - } - - // Frame/View-relative relative, thus the bounds location should be 0,0 - //Debug.Assert(clipRegion.GetBounds().X == 0 && clipRegion.GetBounds ().Y == 0); - saved = SetClipToFrame (); DoDrawAdornments (); - DoSetAttribute (); - Application.SetClip (saved); // By default, we clip to the viewport preventing drawing outside the viewport @@ -51,19 +36,34 @@ public partial class View // Drawing APIs saved = SetClipToViewport (); + DoSetAttribute (); + DoDrawSubviews (); + + DoSetAttribute (); DoClearViewport (); + + DoSetAttribute (); DoDrawText (); + + DoSetAttribute (); DoDrawContent (); - DoDrawSubviews (); // Restore the clip before rendering the line canvas and adornment subviews // because they may draw outside the viewport. Application.SetClip (saved); saved = SetClipToFrame (); + DoRenderLineCanvas (); DoDrawAdornmentSubViews (); + + if (Border is { Diagnostics: ViewDiagnosticFlags.DrawIndicator, DrawIndicator: { } }) + { + Border.DrawIndicator.AdvanceAnimation (false); + Border.DrawIndicator.Render (); + } + ClearNeedsDraw (); } @@ -71,7 +71,8 @@ public partial class View // Drawing APIs DoDrawComplete (); Application.SetClip (saved); - if (this is not Adornment && Driver?.Clip is {}) + + if (this is not Adornment && Driver?.Clip is { }) { Application.ExcludeFromClip (FrameToScreen ()); } @@ -454,7 +455,7 @@ public partial class View // Drawing APIs IEnumerable subviewsNeedingDraw = _subviews.Where (view => (view.Visible)); #endif - foreach (View view in subviewsNeedingDraw.Reverse()) + foreach (View view in subviewsNeedingDraw.Reverse ()) { #if HACK_DRAW_OVERLAPPED if (view.Arrangement.HasFlag (ViewArrangement.Overlapped)) diff --git a/Terminal.Gui/Views/Shortcut.cs b/Terminal.Gui/Views/Shortcut.cs index eadb3d73d..0eaefccf1 100644 --- a/Terminal.Gui/Views/Shortcut.cs +++ b/Terminal.Gui/Views/Shortcut.cs @@ -762,6 +762,8 @@ public class Shortcut : View, IOrientation, IDesignable }; KeyView.ColorScheme = cs; } + + CommandView.Margin.ColorScheme = base.ColorScheme; } /// diff --git a/Terminal.Gui/Views/SpinnerView/SpinnerView.cs b/Terminal.Gui/Views/SpinnerView/SpinnerView.cs index e80db3e00..216167221 100644 --- a/Terminal.Gui/Views/SpinnerView/SpinnerView.cs +++ b/Terminal.Gui/Views/SpinnerView/SpinnerView.cs @@ -186,14 +186,22 @@ public class SpinnerView : View, IDesignable protected override bool OnClearingViewport () { return true; } /// - protected override bool OnDrawingText () + protected override bool OnDrawingContent () + { + Render (); + return true; + } + + /// + /// Renders the current frame of the spinner. + /// + public void Render () { if (Sequence is { Length: > 0 } && _currentIdx < Sequence.Length) { Move (Viewport.X, Viewport.Y); View.Driver?.AddStr (Sequence [_currentIdx]); } - return true; } /// diff --git a/UICatalog/Scenarios/AdvancedClipping.cs b/UICatalog/Scenarios/AdvancedClipping.cs index 734eedfaf..75a03437b 100644 --- a/UICatalog/Scenarios/AdvancedClipping.cs +++ b/UICatalog/Scenarios/AdvancedClipping.cs @@ -17,9 +17,16 @@ public class AdvancedClipping : Scenario Window app = new () { Title = GetQuitKeyAndName (), - BorderStyle = LineStyle.None + //BorderStyle = LineStyle.None }; + app.DrawingText += (s, e) => + { + Application.Driver?.FillRect (app.ViewportToScreen (app.Viewport), CM.Glyphs.Dot); + //app.SetSubViewNeedsDraw(); + e.Cancel = true; + }; + //var arrangementEditor = new ArrangementEditor() //{ // X = Pos.AnchorEnd (), @@ -30,26 +37,27 @@ public class AdvancedClipping : Scenario View tiledView1 = CreateTiledView (1, 0, 0); - ProgressBar tiledProgressBar = new () { X = 0, - Y = 1, + Y = Pos.AnchorEnd(), Width = Dim.Fill (), Id = "tiledProgressBar", + BidirectionalMarquee = true, + ProgressBarStyle = ProgressBarStyle.MarqueeBlocks // BorderStyle = LineStyle.Rounded }; tiledView1.Add (tiledProgressBar); - View tiledView2 = CreateTiledView (2, 2, 2); + View tiledView2 = CreateTiledView (2, 4, 2); app.Add (tiledView1); app.Add (tiledView2); - //View tiledView3 = CreateTiledView (3, 6, 6); - //app.Add (tiledView3); + View tiledView3 = CreateTiledView (3, 8, 4); + app.Add (tiledView3); - //using View overlappedView1 = CreateOverlappedView (1, 30, 2); + // View overlappedView1 = CreateOverlappedView (1, 30, 2); //ProgressBar progressBar = new () //{ @@ -69,23 +77,15 @@ public class AdvancedClipping : Scenario //app.Add (overlappedView2); //app.Add (overlappedView3); - Timer progressTimer = new Timer (250) + Timer progressTimer = new Timer (150) { AutoReset = true }; progressTimer.Elapsed += (s, e) => { - - if (tiledProgressBar.Fraction == 1.0) - { - tiledProgressBar.Fraction = 0; - } - + tiledProgressBar.Pulse(); Application.Wakeup (); - - tiledProgressBar.Fraction += 0.1f; - // tiledProgressBar.SetNeedsDraw (); }; progressTimer.Start (); @@ -123,8 +123,8 @@ public class AdvancedClipping : Scenario { X = x, Y = y, - Height = Dim.Auto (minimumContentDim: 4), - Width = Dim.Auto (minimumContentDim: 14), + Height = Dim.Auto (minimumContentDim: 8), + Width = Dim.Auto (minimumContentDim: 15), Title = $"Tiled{id} _{GetNextHotKey ()}", Id = $"Tiled{id}", Text = $"Tiled{id}", @@ -133,14 +133,16 @@ public class AdvancedClipping : Scenario TabStop = TabBehavior.TabStop, Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable }; - tiled.Padding.Thickness = new (1); - tiled.Padding.Diagnostics = ViewDiagnosticFlags.Thickness; + //tiled.Padding.Thickness = new (1); + //tiled.Padding.Diagnostics = ViewDiagnosticFlags.Thickness; + + tiled.Margin.Thickness = new (1); FrameView fv = new () { Title = "FrameView", Width = 15, - Height = 1, + Height = 3, }; tiled.Add (fv); diff --git a/UICatalog/Scenarios/ShadowStyles.cs b/UICatalog/Scenarios/ShadowStyles.cs index 75ee30b3c..59e9f6852 100644 --- a/UICatalog/Scenarios/ShadowStyles.cs +++ b/UICatalog/Scenarios/ShadowStyles.cs @@ -45,7 +45,7 @@ public class ShadowStyles : Scenario app.DrawingText += (s, e) => { - Application.Driver?.FillRect (app.ViewportToScreen (app.Viewport), '*'); + Application.Driver?.FillRect (app.ViewportToScreen (app.Viewport), CM.Glyphs.Dot); e.Cancel = true; };