Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 26 additions & 19 deletions Examples/UICatalog/Scenarios/ShadowStyleDemo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,31 @@ public override void Main ()
using IApplication app = Application.Create ();
app.Init ();

using Window window = new ()
{
Id = "app",
Title = GetQuitKeyAndName ()
};
using Window window = new ();
window.Id = "app";
window.Title = GetQuitKeyAndName ();
window.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Accent);

AdornmentsEditor editor = new ()
{
Id = "editor",
BorderStyle = LineStyle.Single,
AutoSelectViewToEdit = true,
ShowViewIdentifier = true
};
editor.Initialized += (_, _) => editor.MarginEditor!.ExpanderButton!.Collapsed = false;

window.Add (editor);
// This is for giggles, to show that the editor can be moved around.
Arrangement = ViewArrangement.Movable,
Id = "editor"
};
editor.Border.Thickness = new Thickness (1, 2, 1, 1);

Window shadowWindow = new ()
{
Id = "shadowWindow",
X = Pos.Right (editor),
X = Pos.Center (),
Y = 0,
Width = Dim.Percent (30),
Height = Dim.Percent (30),
Title = "Shadow Window",
SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Accent),
Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped,
BorderStyle = LineStyle.Double,
ShadowStyle = ShadowStyles.Transparent
Expand All @@ -51,11 +52,11 @@ public override void Main ()
{
Id = "buttonInWin",
X = Pos.Center (),
Y = Pos.Center (), Text = "Button in Window",
Y = Pos.Center (),
Text = "Button in Window",
ShadowStyle = ShadowStyles.Opaque
};
shadowWindow.Add (buttonInWin);
window.Add (shadowWindow);

Window shadowWindow2 = new ()
{
Expand All @@ -65,17 +66,18 @@ public override void Main ()
Width = Dim.Percent (30),
Height = Dim.Percent (30),
Title = "Shadow Window #2",
SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Error),
Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped,
BorderStyle = LineStyle.Double,
ShadowStyle = ShadowStyles.Transparent
};
window.Add (shadowWindow2);

Button button = new ()
{
Id = "button",
X = Pos.Right (editor) + 10,
Y = Pos.Center (), Text = "Button",
Y = Pos.Center (),
Text = "Button",
ShadowStyle = ShadowStyles.Opaque
};
button.Accepting += ButtonOnAccepting;
Expand All @@ -84,7 +86,7 @@ public override void Main ()
{
Title = "ColorPicker to illustrate highlight (currently broken)",
BorderStyle = LineStyle.Dotted,
Id = "colorPicker16",
Id = "colorPicker",
X = Pos.Center (),
Y = Pos.AnchorEnd (),
Width = Dim.Percent (80)
Expand All @@ -93,13 +95,18 @@ public override void Main ()
colorPicker.ValueChanged += (_, args) =>
{
Attribute normal = window.GetScheme ().Normal;
window.SetScheme (window.GetScheme () with { Normal = new (normal.Foreground, args.NewValue ?? Color.Black) });

window.SetScheme (window.GetScheme () with
{
Normal = new Attribute (normal.Foreground, args.NewValue ?? Color.Black)
});
};
window.Add (button, colorPicker);
window.Add (button, colorPicker, editor, shadowWindow, shadowWindow2);

editor.ShowViewIdentifier = true;
editor.AutoSelectViewToEdit = true;
Comment thread
tig marked this conversation as resolved.
editor.AutoSelectSuperView = window;
editor.AutoSelectAdornments = false;
editor.AutoSelectAdornments = true;

app.Run (window);
}
Expand Down
8 changes: 6 additions & 2 deletions Terminal.Gui/ViewBase/Adornment/Margin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected override void OnThicknessChanged ()
/// </summary>
public ShadowStyles? ShadowStyle
{
get => field ?? Parent?.SuperView?.ShadowStyle ?? null;
get => field;
set
{
if (field == value)
Expand All @@ -68,7 +68,11 @@ public ShadowStyles? ShadowStyle
if (field is null)
{
// null means no shadow and no thickness
(View as MarginView)?.SetShadow (null);
if (View is MarginView mv)
{
mv.SetShadow (null);
mv.ShadowSize = Size.Empty;
}

return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void Changing_ShadowStyle_Correctly_Set_ShadowWidth_ShadowHeight_Thicknes
Assert.Equal (new Thickness (0, 0, 2, 2), view.Margin.Thickness);

view.ShadowStyle = null;
Assert.Equal (new Size (2, 2), (view.Margin.View as MarginView)?.ShadowSize);
Assert.Equal (Size.Empty, (view.Margin.View as MarginView)?.ShadowSize);
Assert.Equal (new Thickness (0, 0, 0, 0), view.Margin.Thickness);

view.ShadowStyle = ShadowStyles.Opaque;
Expand Down Expand Up @@ -577,4 +577,62 @@ public void TransparentShadow_OverWide_Draws_Transparent_At_Driver_Output ()
output,
app.Driver);
}

/// <summary>
/// Proves Issue #5088: ShadowStyle getter returns an inherited value from
/// SuperView even though no shadow was ever set on the view itself. Reading the
/// value and writing it back should be a no-op, but instead it creates a
/// MarginView and adds shadow thickness.
/// </summary>
[Fact]
public void ShadowStyle_Getter_Does_Not_Inherit_From_SuperView ()
{
// Explicitly give the SuperView a transparent shadow for this inheritance test.
Window superView = new () { Width = 20, Height = 10, ShadowStyle = ShadowStyles.Transparent };

View child = new () { Width = 5, Height = 3 };
superView.Add (child);

// The subview was never assigned a ShadowStyle - it must be null.
Assert.Null (child.Margin.ShadowStyle);
Assert.Null (child.ShadowStyle);

// Round-trip: reading and writing back should be a safe no-op.
ShadowStyles? readBack = child.ShadowStyle;
child.ShadowStyle = readBack;

// After the round-trip the subview must still have no shadow and no Margin thickness.
Assert.Null (child.ShadowStyle);
Assert.Equal (Thickness.Empty, child.Margin.Thickness);

// MarginView should NOT have been created by a no-op assignment.
Assert.Null (child.Margin.View);

child.Dispose ();
superView.Dispose ();
}

/// <summary>
/// Proves that setting ShadowStyle to null resets ShadowSize on the MarginView
/// to <see cref="Size.Empty"/>, so that state is consistent when no shadow is active.
/// </summary>
[Fact]
public void Setting_ShadowStyle_Null_Resets_ShadowSize ()
{
View view = new ();

// Set a shadow - this creates a MarginView with ShadowSize {1,1}.
view.ShadowStyle = ShadowStyles.Transparent;
var marginView = view.Margin.View as MarginView;
Assert.NotNull (marginView);
Assert.Equal (new Size (1, 1), marginView.ShadowSize);

// Now clear the shadow.
view.ShadowStyle = null;

// ShadowSize should be reset to Empty - no residual state.
Assert.Equal (Size.Empty, marginView.ShadowSize);

view.Dispose ();
}
}
Loading