Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3761, #2886 - Draw and Layout performance issues #3798

Open
wants to merge 190 commits into
base: v2_develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
190 commits
Select commit Hold shift + click to select a range
4d1d740
Initial exploration of how to sixel encode
tznind Sep 9, 2024
f096062
Add ColorQuantizer
tznind Sep 9, 2024
943fa11
Work on SixelEncoder
tznind Sep 9, 2024
c6281dd
Build color palette using median cut instead of naive method
tznind Sep 11, 2024
b482306
Fix build errors
tznind Sep 11, 2024
3081765
Refactoring and comments
tznind Sep 11, 2024
e334bfd
Refactor and split into seperate files WIP
tznind Sep 11, 2024
891adec
Switch to a new WriteSixel algorithm
tznind Sep 13, 2024
484b75a
Output palette in Images scenario
tznind Sep 14, 2024
68d5e99
Fix ConvertToColorArray and namespaces
tznind Sep 14, 2024
d747867
Fix comment
tznind Sep 14, 2024
f103b04
Attribution for the WriteSixel method
tznind Sep 15, 2024
cbef6c5
Add comments
tznind Sep 15, 2024
eaa5c0e
Simplify and speed up palette building
tznind Sep 15, 2024
f8bb2f0
Fix infinite loop building palette
tznind Sep 15, 2024
f40b7b4
Fix test and make comments clearer
tznind Sep 22, 2024
93ce9a8
Add sixel test for grid 3x3 to make 12x12 checkerboard
tznind Sep 22, 2024
ef56998
Tidy up test file and comments in NetDriver
tznind Sep 23, 2024
a7c65bf
Move lab colors to UICatalog
tznind Sep 23, 2024
f07ab92
Switch to simpler and faster palette builder
tznind Sep 23, 2024
2378570
Fix early exit bug in palette builder and change to far more conserva…
tznind Sep 23, 2024
b9bb2ba
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Sep 23, 2024
4571978
Fix fill area - y is not in sixels its in pixels
tznind Sep 25, 2024
3c6804a
Move license to top of page and credit both source repos
tznind Sep 25, 2024
6149c5f
Add 2 tabs to Image scenario - one for sixel one for basic
tznind Sep 26, 2024
050db7a
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Sep 26, 2024
9322b9a
Output at specific position
tznind Sep 26, 2024
519d8c0
Investigate changing sixel to output as part of view render
tznind Sep 28, 2024
94cbc1c
Restore the static approach to rendering for now and fix dispose
tznind Sep 28, 2024
d16f1b6
Fix tabbing into sixel tab view
tznind Sep 28, 2024
18f185d
Fix scenario dispose
tznind Sep 28, 2024
db0fc41
Determine whether sixel is supported by issuing a Device Attributes R…
tznind Sep 29, 2024
08aa992
Switch to existing consts
tznind Sep 30, 2024
b67c662
WIP: trying to get fully transparent alpha to not render
tznind Sep 30, 2024
c240cb1
Fix for when we want alpha pixels
tznind Oct 1, 2024
0122442
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Oct 2, 2024
5e356c2
WindowsDriver prototype sixel support
tznind Oct 3, 2024
f22ef30
Merge branch 'sixel-encoder-tinkering' of https://github.com/tznind/g…
tznind Oct 3, 2024
d60b1fa
Remove double paint!
tznind Oct 3, 2024
23cd888
Do not output sixel if driver does not support it
tznind Oct 3, 2024
14a5fa7
Improve usability of Images scenario
tznind Oct 4, 2024
3566ac2
Make sixel output stop on dispose/close Images scenario
tznind Oct 4, 2024
9058554
Adjust default quantizer
tznind Oct 4, 2024
c4c7754
Add UI components for sixel algorithm
tznind Oct 4, 2024
9d5d853
Actually call relevant builders
tznind Oct 4, 2024
36a8cba
Make updates to the sixel image easier (e.g. changing algorithm)
tznind Oct 4, 2024
a6b1221
Tidy up scenario quantizer options
tznind Oct 5, 2024
97da4cd
Fix unit test expectations
tznind Oct 5, 2024
fd7f994
Fix GetPaletteBuilder
tznind Oct 5, 2024
a3eb19f
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Oct 6, 2024
eee0ded
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Oct 10, 2024
ccb974b
Change to using ansi escape sequences in new standalone class
tznind Oct 5, 2024
78d49fc
Fix algorithm to look for exactly 4 not things like 42 etc.
tznind Oct 5, 2024
ffe8969
Fix new palette order
tznind Oct 5, 2024
fe7e10a
Get sixel resolution using CSI 16 t
tznind Oct 6, 2024
54308ff
Sixel resolution measuring
tznind Oct 6, 2024
64baeca
Update sixel status class name and move to new file
tznind Oct 6, 2024
a8e3a0e
Update xmldoc
tznind Oct 6, 2024
4073ef3
Use round to nearest whole number when calculating sixel resolution f…
tznind Oct 7, 2024
61667fb
Refactor SixelSupportDetector for cleaner reading
tznind Oct 7, 2024
54b737f
If not supporting transparency warn user
tznind Oct 7, 2024
1c3b0d7
Merge pull request #170 from tznind/add-sixel-detector-interface
tznind Oct 10, 2024
9990a55
Fix for accepting
tznind Oct 10, 2024
64d286c
Remove ConsoleDriver.SupportsSixel
tznind Oct 10, 2024
5a6aae6
Fix warnings and tidup code
tznind Oct 10, 2024
bcdb11e
Run TidyCode on all new classes
tznind Oct 10, 2024
57de1ff
Merge branch 'v2_develop' into sixel-encoder-tinkering
tig Oct 11, 2024
06a2f71
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Oct 11, 2024
c46cf78
Merge branch 'v2_develop' into sixel-encoder-tinkering
tznind Oct 13, 2024
04b336a
Try adding sixel to curses driver
tznind Oct 13, 2024
8ddfd71
Merge branch 'v2_develop' into sixel-encoder-tinkering
tig Oct 15, 2024
d104a56
WIP - prototyping...
tig Oct 15, 2024
70bf627
More prototyping
tig Oct 16, 2024
f5ddf6b
More prototyping 2
tig Oct 16, 2024
8c7982f
Tons of Layout refactoring. LayoutSubviews is now internal.
tig Oct 17, 2024
ed80c66
Fixed content scrolling
tig Oct 17, 2024
949f593
Merge branch 'v2_develop' into v2_3761_2886-Draw-and-Layout-Perf
tig Oct 17, 2024
11b3eb0
Fixed more unit tests
tig Oct 17, 2024
9275163
Fixing unit tests
tig Oct 17, 2024
226dd4f
Fixing unit tests 2
tig Oct 17, 2024
b9b853a
Fixing unit tests 3
tig Oct 17, 2024
172409f
Fixed more unit tests ...
tig Oct 18, 2024
5dc832b
Fixing unit tests 4
tig Oct 18, 2024
2d48bc9
Working on shortcut
tig Oct 19, 2024
2e163ee
DimAuto fixes
tig Oct 19, 2024
72ea740
More shortcut stuff
tig Oct 21, 2024
4d4dbbf
Fixing stuff
tig Oct 22, 2024
a632c23
Fixed stoopid screen bug
tig Oct 22, 2024
fe2497e
Back to all unit tests passing
tig Oct 22, 2024
262c671
Added all views tester for draw/layout.
tig Oct 22, 2024
98a2265
fixed all views to deal with Driver is null
tig Oct 22, 2024
6e98d10
Switched back to Application.Begin not calling Refresh
tig Oct 22, 2024
572901b
Switched back to Application.Begin not calling Refresh
tig Oct 22, 2024
5e9178b
Everything but adornment drawing is working
tig Oct 23, 2024
008d497
Fixed TileView & ListView unit test failures
tig Oct 23, 2024
a6f03e4
Merge branch 'v2_develop' into sixel-encoder-tinkering
tig Oct 23, 2024
3156641
Make sixel 'opt in' in images scenario and apply a hack to fix TabVie…
tznind Oct 23, 2024
ce41afd
xml comments
tznind Oct 23, 2024
b31339d
Tons of stuff
tig Oct 23, 2024
ed48864
almost ready
tig Oct 24, 2024
bfb243a
Added benchmarking stuff
tig Oct 24, 2024
7b73517
More benchmarks
tig Oct 24, 2024
bc12c4b
Added timeout to test
tig Oct 24, 2024
76895f1
Fixed bugs
tig Oct 24, 2024
5a11a39
Code cleanup
tig Oct 24, 2024
a93d1ce
better names and API docs
tig Oct 24, 2024
66f5281
code reorg
tig Oct 24, 2024
317d425
debugging iterations
tig Oct 25, 2024
1c429da
debugging iterations
tig Oct 25, 2024
fa37103
reverted diag stuff that broke unit tests
tig Oct 25, 2024
ed05e17
Fixed issue with enter/leave
tig Oct 25, 2024
69cd30c
Prototype Scenario benchmark
tig Oct 25, 2024
0d51b5e
Support nullable scenarios
tig Oct 25, 2024
bbf54f4
Added Benchmarking to UI Catalog
tig Oct 25, 2024
ce900ad
Benchmark cleanup
tig Oct 25, 2024
1cbdb5c
Refactored View editors
tig Oct 25, 2024
98d0454
Refactored View editors 2
tig Oct 25, 2024
10d99a2
Beefed up benchmarking
tig Oct 26, 2024
2b7f3c2
Fixed timeout bug
tig Oct 26, 2024
f49213a
Changed benchmark screen size
tig Oct 26, 2024
f3ec218
Removed extra key
tig Oct 26, 2024
ed6ae17
Fixed animation scenario bug
tig Oct 26, 2024
fc5c3cb
Fixed animation scenario bug2
tig Oct 26, 2024
6a19d85
Fixed animation scenario bug3
tig Oct 26, 2024
1a49896
Fixing unit test failure from bad debug.fail
tig Oct 26, 2024
68bc258
Cleaned up launch settings
tig Oct 26, 2024
d6470fb
IsInitialized->Initialized
tig Oct 26, 2024
94b254a
IDesignable for TableView
tig Oct 26, 2024
6bfa8ba
IDesignable for GraphView
tig Oct 26, 2024
320ff8b
IDesignable for SpinnerView
tig Oct 26, 2024
7315ff7
IDesignable for TreeView
tig Oct 26, 2024
8ea89b8
IDesignable for TreeView
tig Oct 26, 2024
ee29ed8
View Draw API docs and code cleanup
tig Oct 26, 2024
92dac0e
View Draw API docs and code cleanup
tig Oct 26, 2024
6e873e0
View Draw API docs and code cleanup
tig Oct 26, 2024
245cfea
Fix TabView and unit tests.
BDisp Oct 27, 2024
606bdf1
Added View.Set/GetAtribute. Made Driver.Set/GetAttribute internal
tig Oct 27, 2024
6b5d291
Resolving merge conflicts.
BDisp Oct 27, 2024
04881bc
Remove not accessed local variable.
BDisp Oct 27, 2024
dde9b92
Remove unused local variable.
BDisp Oct 27, 2024
bcc1168
Fix typo.
BDisp Oct 27, 2024
116399c
Add #nullable enable.
BDisp Oct 27, 2024
7491983
Tweaked drawing code.
tig Oct 27, 2024
a7040b8
Fixed PosDim bug
tig Oct 27, 2024
c1597b3
Merge branch 'v2_3761_2886-Draw-and-Layout-Perf-tabview' of github.co…
tig Oct 27, 2024
51fcfb5
Draw->DrawIndicator
tig Oct 27, 2024
87486b1
Renamed Refresh. COde Cleanup
tig Oct 27, 2024
53708fa
api doc
tig Oct 28, 2024
e0551f4
NeedsDisplay -> NeedsDraw
tig Oct 28, 2024
d92ef0f
Added a port of System.Drawing.Region with unit tests.
tig Oct 28, 2024
844179b
ConsoleDriver now uses Region for Clip.
tig Oct 28, 2024
7baede5
Remove unused code from UnmanagedLibrary (#3799)
kasperk81 Oct 28, 2024
2f7d80a
Merge pull request #3734 from tznind/sixel-encoder-tinkering
tig Oct 28, 2024
cbb7ddc
Merged latest v2_develop
tig Oct 28, 2024
262bc01
Enabled FileDialog IDesignable
tig Oct 28, 2024
17e3fe8
Non-rectangular clip reigion support basically works
tig Oct 29, 2024
5a41d2c
Fixing unit tests. WIP
tig Oct 30, 2024
0e6a2bc
Fixing unit tests. TableView. WIP
tig Oct 30, 2024
d835b56
Fixed more clipping bugs and unit tests. All tests pass!
tig Oct 30, 2024
fdeb8e9
WIP: Figuring out how to make margin transparent
tig Oct 30, 2024
7e0f606
WIP: Figuring out how to make margin transparent
tig Oct 30, 2024
8835126
All tests pass (esxcept ScrollView and TabView which are disabled for…
tig Nov 1, 2024
b0b5b23
Code cleanup
tig Nov 1, 2024
ef06f4b
Implemented deferred Margin drawing to enable shadow with minimal per…
tig Nov 3, 2024
593160d
Code cleanup and refactor
tig Nov 3, 2024
563d58a
Code cleanup and refactor
tig Nov 3, 2024
e4b5523
drawming.md
tig Nov 3, 2024
304784c
Code cleanup and refactor
tig Nov 4, 2024
2f9cf08
Code cleanup and refactor
tig Nov 4, 2024
7656602
#nullable enable
tig Nov 4, 2024
66485a0
#nullable enable - Attribute.cs
tig Nov 4, 2024
2214d8c
#nullable enable
tig Nov 4, 2024
a5badb8
Added arrangmenteditor to AllViewsTester
tig Nov 4, 2024
c0ee541
Code cleanup and API docs
tig Nov 4, 2024
76b4b72
Code cleanup and API docs
tig Nov 4, 2024
55387d3
Made more Driver APIs internal
tig Nov 4, 2024
947914b
Made more Driver APIs internal
tig Nov 4, 2024
7fb321b
Cleanup
tig Nov 5, 2024
b48bc2b
typo
tig Nov 5, 2024
77ae7ae
Rebuildling TabView - WIP
tig Nov 6, 2024
e6180b6
Revert "Rebuildling TabView - WIP"
tig Nov 6, 2024
49d36f2
Fix SingleBackgroundWorker scenario.
BDisp Nov 6, 2024
10a2d7f
Merge branch 'BDisp-v2_3761_2886-Draw-and-Layout-Perf-fix' into v2_37…
tig Nov 6, 2024
720729d
Merge pull request #42 from BDisp/v2_3761_2886-Draw-and-Layout-Perf-fix
tig Nov 6, 2024
5a7ac91
Merge branch 'v2_3761_2886-Draw-and-Layout-Perf' of tig:tig/Terminal.…
tig Nov 6, 2024
07b295b
Code cleanup
tig Nov 6, 2024
3ad8969
WIP: adding superviewrenderslinecanvas tests
tig Nov 6, 2024
69a2c4d
Messing with border
tig Nov 7, 2024
45ce64a
Added Exclusions to LineCanvas
tig Nov 7, 2024
3d4658d
LineCanvas - Exclude
tig Nov 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CommunityToolkitExample/LoginView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public void Receive (Message<LoginActions> message)
}
}
SetText();
Application.Refresh ();
Application.LayoutAndDraw ();
}

private void SetText ()
Expand Down
6 changes: 6 additions & 0 deletions Terminal.Gui/Application/Application.Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ public static partial class Application // Driver abstractions
/// </remarks>
[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
public static string ForceDriver { get; set; } = string.Empty;

/// <summary>
/// Collection of sixel images to write out to screen when updating.
/// Only add to this collection if you are sure terminal supports sixel format.
/// </summary>
public static List<SixelToRender> Sixel = new List<SixelToRender> ();
}
21 changes: 15 additions & 6 deletions Terminal.Gui/Application/Application.Initialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public static partial class Application // Initialization (Init/Shutdown)
[RequiresDynamicCode ("AOT")]
public static void Init (ConsoleDriver? driver = null, string? driverName = null) { InternalInit (driver, driverName); }

internal static bool IsInitialized { get; set; }
internal static int MainThreadId { get; set; } = -1;

// INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop.
Expand All @@ -59,12 +58,12 @@ internal static void InternalInit (
bool calledViaRunT = false
)
{
if (IsInitialized && driver is null)
if (Initialized && driver is null)
{
return;
}

if (IsInitialized)
if (Initialized)
{
throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown.");
}
Expand Down Expand Up @@ -173,7 +172,7 @@ internal static void InternalInit (

SupportedCultures = GetSupportedCultures ();
MainThreadId = Thread.CurrentThread.ManagedThreadId;
bool init = IsInitialized = true;
bool init = Initialized = true;
InitializedChanged?.Invoke (null, new (init));
}

Expand Down Expand Up @@ -215,17 +214,27 @@ public static void Shutdown ()
{
// TODO: Throw an exception if Init hasn't been called.

bool wasInitialized = IsInitialized;
bool wasInitialized = Initialized;
ResetState ();
PrintJsonErrors ();

if (wasInitialized)
{
bool init = IsInitialized;
bool init = Initialized;
InitializedChanged?.Invoke (null, new (in init));
}
}

/// <summary>
/// Gets whether the application has been initialized with <see cref="Init"/> and not yet shutdown with <see cref="Shutdown"/>.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="InitializedChanged"/> event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
/// </para>
/// </remarks>
public static bool Initialized { get; internal set; }

/// <summary>
/// This event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Terminal.Gui/Application/Application.Keyboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public static bool RaiseKeyDownEvent (Key key)
/// <returns><see langword="true"/> if the key was handled.</returns>
public static bool RaiseKeyUpEvent (Key key)
{
if (!IsInitialized)
if (!Initialized)
{
return true;
}
Expand Down Expand Up @@ -200,7 +200,7 @@ internal static void AddApplicationKeyBindings ()
Command.Refresh,
static () =>
{
Refresh ();
LayoutAndDraw ();

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/Application/Application.Mouse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ internal static void RaiseMouseEvent (MouseEventArgs mouseEvent)
{
if (deepestViewUnderMouse is Adornment adornmentView)
{
deepestViewUnderMouse = adornmentView.Parent!.SuperView;
deepestViewUnderMouse = adornmentView.Parent?.SuperView;
}
else
{
Expand Down
107 changes: 62 additions & 45 deletions Terminal.Gui/Application/Application.Run.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Terminal.Gui;

Expand Down Expand Up @@ -80,27 +81,20 @@ public static RunState Begin (Toplevel toplevel)
{
ArgumentNullException.ThrowIfNull (toplevel);

//#if DEBUG_IDISPOSABLE
// Debug.Assert (!toplevel.WasDisposed);
//#if DEBUG_IDISPOSABLE
// Debug.Assert (!toplevel.WasDisposed);

// if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel)
// {
// Debug.Assert (_cachedRunStateToplevel.WasDisposed);
// }
//#endif
// if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel)
// {
// Debug.Assert (_cachedRunStateToplevel.WasDisposed);
// }
//#endif

// Ensure the mouse is ungrabbed.
MouseGrabView = null;

var rs = new RunState (toplevel);

// View implements ISupportInitializeNotification which is derived from ISupportInitialize
if (!toplevel.IsInitialized)
{
toplevel.BeginInit ();
toplevel.EndInit ();
}

#if DEBUG_IDISPOSABLE
if (Top is { } && toplevel != Top && !TopLevels.Contains (Top))
{
Expand Down Expand Up @@ -176,16 +170,26 @@ public static RunState Begin (Toplevel toplevel)
Top.HasFocus = false;
}

// Force leave events for any entered views in the old Top
if (GetLastMousePosition () is { })
{
RaiseMouseEnterLeaveEvents (GetLastMousePosition ()!.Value, new List<View?> ());
}

Top?.OnDeactivate (toplevel);
Toplevel previousCurrent = Top!;
Toplevel previousTop = Top!;

Top = toplevel;
Top.OnActivate (previousCurrent);
Top.OnActivate (previousTop);
}
}

toplevel.SetRelativeLayout (Driver!.Screen.Size);
toplevel.LayoutSubviews ();
// View implements ISupportInitializeNotification which is derived from ISupportInitialize
if (!toplevel.IsInitialized)
{
toplevel.BeginInit ();
toplevel.EndInit (); // Calls Layout
}

// Try to set initial focus to any TabStop
if (!toplevel.HasFocus)
Expand All @@ -195,15 +199,16 @@ public static RunState Begin (Toplevel toplevel)

toplevel.OnLoaded ();

Refresh ();

if (PositionCursor ())
{
Driver.UpdateCursor ();
Driver?.UpdateCursor ();
}

NotifyNewRunState?.Invoke (toplevel, new (rs));

// Force an Idle event so that an Iteration (and Refresh) happen.
Application.Invoke (() => { });

return rs;
}

Expand All @@ -225,11 +230,12 @@ internal static bool PositionCursor ()
// If the view is not visible or enabled, don't position the cursor
if (mostFocused is null || !mostFocused.Visible || !mostFocused.Enabled)
{
Driver!.GetCursorVisibility (out CursorVisibility current);
CursorVisibility current = CursorVisibility.Invisible;
Driver?.GetCursorVisibility (out current);

if (current != CursorVisibility.Invisible)
{
Driver.SetCursorVisibility (CursorVisibility.Invisible);
Driver?.SetCursorVisibility (CursorVisibility.Invisible);
}

return false;
Expand Down Expand Up @@ -326,7 +332,7 @@ internal static bool PositionCursor ()
public static T Run<T> (Func<Exception, bool>? errorHandler = null, ConsoleDriver? driver = null)
where T : Toplevel, new()
{
if (!IsInitialized)
if (!Initialized)
{
// Init() has NOT been called.
InternalInit (driver, null, true);
Expand Down Expand Up @@ -381,7 +387,7 @@ public static void Run (Toplevel view, Func<Exception, bool>? errorHandler = nul
{
ArgumentNullException.ThrowIfNull (view);

if (IsInitialized)
if (Initialized)
{
if (Driver is null)
{
Expand Down Expand Up @@ -452,7 +458,10 @@ public static void Run (Toplevel view, Func<Exception, bool>? errorHandler = nul
/// reset, repeating the invocation. If it returns false, the timeout will stop and be removed. The returned value is a
/// token that can be used to stop the timeout by calling <see cref="RemoveTimeout(object)"/>.
/// </remarks>
public static object AddTimeout (TimeSpan time, Func<bool> callback) { return MainLoop!.AddTimeout (time, callback); }
public static object? AddTimeout (TimeSpan time, Func<bool> callback)
{
return MainLoop?.AddTimeout (time, callback) ?? null;
}

/// <summary>Removes a previously scheduled timeout</summary>
/// <remarks>The token parameter is the value returned by <see cref="AddTimeout"/>.</remarks>
Expand Down Expand Up @@ -486,20 +495,25 @@ public static void Invoke (Action action)
/// <summary>Wakes up the running application that might be waiting on input.</summary>
public static void Wakeup () { MainLoop?.Wakeup (); }

/// <summary>Triggers a refresh of the entire display.</summary>
public static void Refresh ()
/// <summary>
/// Causes any Toplevels that need layout to be laid out. Then draws any Toplevels that need display. Only Views that need to be laid out (see <see cref="View.NeedsLayout"/>) will be laid out.
/// Only Views that need to be drawn (see <see cref="View.NeedsDraw"/>) will be drawn.
/// </summary>
/// <param name="forceDraw">If <see langword="true"/> the entire View hierarchy will be redrawn. The default is <see langword="false"/> and should only be overriden for testing.</param>
public static void LayoutAndDraw (bool forceDraw = false)
{
foreach (Toplevel tl in TopLevels.Reverse ())
{
if (tl.LayoutNeeded)
{
tl.LayoutSubviews ();
}
bool neededLayout = View.Layout (TopLevels.Reverse (), Screen.Size);

tl.Draw ();
if (forceDraw)
{
Driver?.ClearContents ();
}

Driver!.Refresh ();
View.SetClipToScreen ();
View.Draw (TopLevels, neededLayout || forceDraw);
View.SetClipToScreen ();

Driver?.Refresh ();
}

/// <summary>This event is raised on each iteration of the main loop.</summary>
Expand Down Expand Up @@ -534,24 +548,25 @@ public static void RunLoop (RunState state)
return;
}

RunIteration (ref state, ref firstIteration);
firstIteration = RunIteration (ref state, firstIteration);
}

MainLoop!.Running = false;

// Run one last iteration to consume any outstanding input events from Driver
// This is important for remaining OnKeyUp events.
RunIteration (ref state, ref firstIteration);
RunIteration (ref state, firstIteration);
}

/// <summary>Run one application iteration.</summary>
/// <param name="state">The state returned by <see cref="Begin(Toplevel)"/>.</param>
/// <param name="firstIteration">
/// Set to <see langword="true"/> if this is the first run loop iteration. Upon return, it
/// will be set to <see langword="false"/> if at least one iteration happened.
/// Set to <see langword="true"/> if this is the first run loop iteration.
/// </param>
public static void RunIteration (ref RunState state, ref bool firstIteration)
/// <returns><see langword="false"/> if at least one iteration happened.</returns>
public static bool RunIteration (ref RunState state, bool firstIteration = false)
{
// If the driver has events pending do an iteration of the driver MainLoop
if (MainLoop!.Running && MainLoop.EventsPending ())
{
// Notify Toplevel it's ready
Expand All @@ -561,23 +576,25 @@ public static void RunIteration (ref RunState state, ref bool firstIteration)
}

MainLoop.RunIteration ();

Iteration?.Invoke (null, new ());
}

firstIteration = false;

if (Top is null)
{
return;
return firstIteration;
}

Refresh ();
LayoutAndDraw ();

if (PositionCursor ())
{
Driver!.UpdateCursor ();
}

return firstIteration;
}

/// <summary>Stops the provided <see cref="Toplevel"/>, causing or the <paramref name="top"/> if provided.</summary>
Expand Down Expand Up @@ -652,7 +669,7 @@ public static void End (RunState runState)
if (TopLevels.Count > 0)
{
Top = TopLevels.Peek ();
Top.SetNeedsDisplay ();
Top.SetNeedsDraw ();
}

if (runState.Toplevel is { HasFocus: true })
Expand All @@ -670,6 +687,6 @@ public static void End (RunState runState)
runState.Toplevel = null;
runState.Dispose ();

Refresh ();
LayoutAndDraw ();
}
}
Loading
Loading