From ee29ed87ede37c50fd8684c445c9bf6e0211a341 Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 26 Oct 2024 16:24:41 -0700 Subject: [PATCH] View Draw API docs and code cleanup --- Terminal.Gui/View/View.Drawing.cs | 74 ++++++++++++++++++++++--------- docfx/docs/drawing.md | 22 ++++++--- 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/Terminal.Gui/View/View.Drawing.cs b/Terminal.Gui/View/View.Drawing.cs index d7404cb87..fbd75542e 100644 --- a/Terminal.Gui/View/View.Drawing.cs +++ b/Terminal.Gui/View/View.Drawing.cs @@ -1,4 +1,5 @@ #nullable enable +using System.ComponentModel; using System.Diagnostics; namespace Terminal.Gui; @@ -26,12 +27,7 @@ public partial class View // Drawing APIs } DoDrawAdornments (); - - // Set the color scheme for the view after adornments have been drawn - if (ColorScheme is { }) - { - Driver?.SetAttribute (GetNormalColor ()); - } + DoSetAttribute (); // By default, we clip to the viewport preventing drawing outside the viewport // We also clip to the content, but if a developer wants to draw outside the viewport, they can do @@ -130,6 +126,52 @@ public partial class View // Drawing APIs #endregion DrawAdornments + #region SetAttribute + + private void DoSetAttribute () + { + if (OnSettingAttribute ()) + { + return; + } + + var args = new CancelEventArgs (); + SettingAttribute?.Invoke (this, args); + + if (args.Cancel) + { + return; + } + + SetNormalAttribute (); + } + + + /// + /// Called when the normal attribute for the View is to be set. This is called before the View is drawn. + /// + /// to stop default behavior. + protected virtual bool OnSettingAttribute () { return false; } + + /// Raised when the normal attribute for the View is to be set. This is raised before the View is drawn. + /// + /// Set to to stop default behavior. + /// + public event EventHandler? SettingAttribute; + + /// + /// Sets the attribute for the View. This is called before the View is drawn. + /// + public void SetNormalAttribute () + { + if (ColorScheme is { }) + { + Driver?.SetAttribute (GetNormalColor ()); + } + } + + + #endregion #region ClearViewport private void DoClearViewport (Rectangle viewport) @@ -465,20 +507,11 @@ public partial class View // Drawing APIs #region DrawComplete - private void DoDrawComplete (Rectangle viewport) + private void DoDrawComplete () { - Debug.Assert (viewport == Viewport); + OnDrawComplete (); - if (OnDrawComplete (Viewport)) - { - return; - } - - var dev = new DrawEventArgs (Viewport, Rectangle.Empty); - DrawComplete?.Invoke (this, dev); - - if (dev.Cancel) - { } + DrawComplete?.Invoke (this, EventArgs.Empty); // Default implementation does nothing. } @@ -486,13 +519,12 @@ public partial class View // Drawing APIs /// /// Called when the View is completed drawing. /// - /// - protected virtual bool OnDrawComplete (Rectangle viewport) { return false; } + protected virtual void OnDrawComplete () { } /// Raised when the View is completed drawing. /// /// - public event EventHandler? DrawComplete; + public event EventHandler? DrawComplete; #endregion DrawComplete diff --git a/docfx/docs/drawing.md b/docfx/docs/drawing.md index 577be2b51..02095e3a8 100644 --- a/docfx/docs/drawing.md +++ b/docfx/docs/drawing.md @@ -6,13 +6,13 @@ Color is supported on all platforms, including Windows, Mac, and Linux. The defa ## View Drawing API -A @Terminal.Gui.View will typically draw text when the @Terminal.Gui.Border.OnDrawContent(System.Drawing.Rectangle) is called (or the `DrawContent` event is received). +Terminal.Gui apps draw using the @Terminal.Gui.View.Move and @Terminal.Gui.View.AddRune APIs. @Terminal.Gui.View.Move selects the column and row of the @Terminal.Gui.Cell and @Terminal.Gui.AddRune places the specified glyph in that cell using the @Terminal.Gui.Attribute that was most recently set via @Terminal.Gui.SetAttribute. The @Terminal.Gui.ConsoleDriver caches all changed Cells and efficiently outputs them to the terminal each iteration of the Application. In other words, Terminal.Gui uses deferred rendering. Outputting unformatted text involves: -a) Moving the draw cursor using the `Move` API. -b) Setting the attributes using `SetAttribute`. -c) Outputting glyphs by calling `AddRune` or `AddStr`. +a) Moving the draw cursor using @Terminal.Gui.ViewMove. +b) Setting the attributes using @Terminal.Gui.ViewSetAttribute` +c) Outputting glyphs by calling @Terminal.Gui.View.AddRune or @Terminal.Gui.View.AddStr Outputting formatted text involves: @@ -25,9 +25,21 @@ Line drawing is accomplished using the @Terminal.Gui.LineCanvas API: a) Add the lines via @Terminal.Gui.LineCanvas.Add. b) Either render the line canvas via @Terminal.Gui.LineCanvas.GetMap() or let the @Terminal.Gui.View do so automatically (which enables automatic line joining across Views). +The @Terminal.Gui.Application MainLoop will iterate over all Views in an application looking for views have their @Terminal.Gui.View.NeedsDisplay property set. The @Terminal.Gui.View.Draw method will be called which, in turn. + +1) Draws the Adornments (e.g. @Terminal.Gui.View.Border). +2) Sets the Normal color scheme. +3) Clears the @Terminal.Gui.View.Viewport. +4) Draws @Terminal.Gui.View.Text. +5) Draws any non-text or Subview content. +6) Draws @Terminal.Gui.View.Subviews. +7) Draws @Terminal.Gui.View.LineCanvas (which may have been added to by any of the steps above). + +Each of these steps can be overridden by developers using the standard [Terminal.Gui cancellable event pattern](events.md). For example, the base @Terminal.Gui.View always clears the viewport. To override this, a subclass can override @Terminal.Gui.View.OnClearingViewport to simply return `true`. Or, a user of `View` can subscribe to the @Terminal.Gui.View.ClearingViewport event and set the `Cancel` argument to `true`. + ## Coordinate System for Drawing -The @Terminal.Gui.View draw APIs, including the `OnDrawContent` method, the `DrawContent` event, and the @Terminal.Gui.View.Move method, all take coordinates specified in *Viewport-Relative* coordinates. That is, `0, 0` is the top-left cell visible to the user. +The @Terminal.Gui.View draw APIs all take coordinates specified in *Viewport-Relative* coordinates. That is, `0, 0` is the top-left cell visible to the user. See [Layout](layout.md) for more details of the Terminal.Gui coordinate system.