Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a18f360
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 8, 2026
c72bba7
Cleans up examples.
tig Apr 11, 2026
918f98b
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 11, 2026
6238893
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 11, 2026
e78909b
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 12, 2026
d0b085d
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 12, 2026
db6347d
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 12, 2026
bfaef7c
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 12, 2026
aa0e09b
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 12, 2026
851ec1e
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 13, 2026
5446a3c
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 13, 2026
7a8cfb6
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 13, 2026
5501ed9
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 13, 2026
3f6a47b
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 14, 2026
fde0105
Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop
tig Apr 15, 2026
b27370a
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 17, 2026
2cbf468
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 17, 2026
d018f2d
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 17, 2026
9580b0d
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 19, 2026
fd9fbef
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 19, 2026
a2e0d6f
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 19, 2026
36e64f2
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 19, 2026
7c68730
updated docs
tig Apr 19, 2026
c700d81
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
c511c14
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
fa3cefa
Initial plan
Copilot Apr 20, 2026
276463e
Fixes #4885. Button: avoid create-then-destroy shadow allocation via …
Copilot Apr 20, 2026
ca29a76
Merge branch 'develop' into copilot/fix-button-shadow-creation-issue
tig Apr 20, 2026
6c77b70
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
fc86b5f
Update Terminal.Gui/Views/ScrollBar/ScrollButton.cs
tig Apr 20, 2026
0861fb7
Update Terminal.Gui/ViewBase/Adornment/ArrangerButton.cs
tig Apr 20, 2026
549d923
Update Tests/UnitTestsParallelizable/Views/ButtonTests.cs
tig Apr 20, 2026
6a4f0b3
Update Terminal.Gui/Views/Button.cs
tig Apr 20, 2026
5e5f020
Merge branch 'develop' into copilot/fix-button-shadow-creation-issue
tig Apr 20, 2026
4dd7d76
Merge branch 'develop' into copilot/fix-button-shadow-creation-issue
tig Apr 20, 2026
2b24272
Merge branch 'copilot/fix-button-shadow-creation-issue' of github.com…
tig Apr 20, 2026
59289b4
Redesign shadow initialization to use CWP event (OnInitializingShadow…
Copilot Apr 20, 2026
58e4148
Darken shadow effect in ShadowView for non-opaque style
tig Apr 20, 2026
6a96e46
Merge branch 'copilot/fix-button-shadow-creation-issue' of github.com…
tig Apr 20, 2026
1f88d04
Merge branch 'develop' into copilot/fix-button-shadow-creation-issue
tig Apr 20, 2026
c743916
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
e7d807d
Merge branch 'develop' into copilot/fix-button-shadow-creation-issue
tig Apr 20, 2026
397f0c8
Merge branch 'copilot/fix-button-shadow-creation-issue' of github.com…
tig Apr 20, 2026
df899e7
Refactor docs and style in Button and ArrangerButton
tig Apr 20, 2026
8222464
Update ShadowTests expected ANSI output for background
tig Apr 20, 2026
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
5 changes: 4 additions & 1 deletion Terminal.Gui/ViewBase/Adornment/ArrangerButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public ArrangerButton ()
Height = 1;
NoDecorations = true;
NoPadding = true;
base.ShadowStyle = null;
base.Visible = false;

AddCommand (Command.Up, DefaultAcceptHandler);
Expand All @@ -85,6 +84,10 @@ public ArrangerButton ()
_orientationHelper = new OrientationHelper (this);
}

/// <inheritdoc/>
/// <remarks>Returns <see langword="null"/> so that no shadow infrastructure is ever allocated for arranger buttons.</remarks>
Comment thread
tig marked this conversation as resolved.
Outdated
protected override ShadowStyles? GetDefaultShadowStyle () => null;

private ArrangeButtons _buttonType = (ArrangeButtons)(-1);

/// <summary>
Expand Down
17 changes: 16 additions & 1 deletion Terminal.Gui/Views/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,25 @@ public Button ()

TitleChanged += Button_TitleChanged;

base.ShadowStyle = DefaultShadow;
// Apply the initial shadow via a virtual method so that subclasses (e.g. ScrollButton)
// can override GetDefaultShadowStyle() to return null, completely avoiding the
// create-then-destroy allocation cycle that would otherwise occur.
base.ShadowStyle = GetDefaultShadowStyle ();
Comment thread
tig marked this conversation as resolved.
Outdated
MouseHighlightStates = DefaultMouseHighlightStates;
}

/// <summary>
/// Returns the shadow style that should be applied during construction. Subclasses that
/// never show a shadow (e.g. <see cref="ScrollButton"/>, <see cref="ArrangerButton"/>) should
/// override this to return <see langword="null"/> to avoid the create-then-destroy allocation
/// pattern.
Comment thread
tig marked this conversation as resolved.
Outdated
/// </summary>
/// <returns>
/// <see cref="DefaultShadow"/> by default. Return <see langword="null"/> to construct without
/// any shadow infrastructure.
/// </returns>
protected virtual ShadowStyles? GetDefaultShadowStyle () => DefaultShadow;

/// <inheritdoc/>
protected override void OnMouseHoldRepeatChanged (ValueChangedEventArgs<MouseFlags?> args) => SetMouseBindings (args.NewValue);

Expand Down
5 changes: 4 additions & 1 deletion Terminal.Gui/Views/ScrollBar/ScrollButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,17 @@ public ScrollButton ()
CanFocus = false;
NoDecorations = true;
NoPadding = true;
base.ShadowStyle = null;
MouseHoldRepeat = MouseFlags.LeftButtonReleased;

// ReSharper disable once UseObjectOrCollectionInitializer
_orientationHelper = new OrientationHelper (this);
SetGlyph ();
}

/// <inheritdoc/>
/// <remarks>Returns <see langword="null"/> so that no shadow infrastructure is ever allocated for scroll buttons.</remarks>
Comment thread
tig marked this conversation as resolved.
Outdated
protected override ShadowStyles? GetDefaultShadowStyle () => null;

/// <summary>
/// Gets or sets the direction this <see cref="ScrollButton"/> scrolls.
/// </summary>
Expand Down
69 changes: 69 additions & 0 deletions Tests/UnitTestsParallelizable/Views/ButtonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,4 +1005,73 @@ public void Mouse_Click_Does_Not_Raise_Activating ()

button.Dispose ();
}

// Copilot
/// <summary>
/// Verifies that a newly-constructed Button has shadow infrastructure allocated by default,
/// because <see cref="Button.GetDefaultShadowStyle"/> returns <see cref="Button.DefaultShadow"/>
/// and is called in the constructor.
/// </summary>
[Fact]
public void ShadowStyle_Applied_In_Constructor_By_Default ()
{
Button button = new ();

// Default shadow is applied in the constructor via GetDefaultShadowStyle().
Assert.Equal (Button.DefaultShadow, button.ShadowStyle);
Assert.NotNull (button.Margin.View); // MarginView was created.

button.Dispose ();
}

// Copilot
/// <summary>
/// Verifies that setting <see cref="View.ShadowStyle"/> to <see langword="null"/> after construction
/// removes the shadow infrastructure.
/// </summary>
[Fact]
public void ShadowStyle_Null_After_Construction_Removes_Shadow ()
{
Button button = new ();
button.ShadowStyle = null;

Assert.Null (button.ShadowStyle);
Comment thread
tig marked this conversation as resolved.
Outdated

button.Dispose ();
}

// Copilot
/// <summary>
/// Verifies that <see cref="ScrollButton"/> does not create shadow infrastructure during construction
/// because <see cref="ScrollButton.GetDefaultShadowStyle"/> returns <see langword="null"/>,
/// eliminating the create-then-destroy allocation pattern described in the issue.
/// </summary>
[Fact]
public void ScrollButton_GetDefaultShadowStyle_Returns_Null_No_MarginView ()
{
ScrollButton btn = new ();

// GetDefaultShadowStyle() returns null → Button constructor sets ShadowStyle = null
// → no shadow infrastructure is ever created.
Assert.Null (btn.ShadowStyle);
Assert.Null (btn.Margin.View);

btn.Dispose ();
}

// Copilot
/// <summary>
/// Verifies that explicitly setting <see cref="View.ShadowStyle"/> to a non-default value
/// after construction correctly replaces the initial default.
/// </summary>
[Fact]
public void ShadowStyle_ExplicitValue_After_Construction_IsApplied ()
{
Button button = new ();
button.ShadowStyle = ShadowStyles.Transparent;

Assert.Equal (ShadowStyles.Transparent, button.ShadowStyle);

button.Dispose ();
}
}
Loading