mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-26 20:02:14 +08:00
344 lines
12 KiB
C#
344 lines
12 KiB
C#
using AtomUI.Controls;
|
|
using AtomUI.Desktop.Controls.Primitives.Themes;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Presenters;
|
|
using Avalonia.Controls.Templates;
|
|
using Avalonia.Threading;
|
|
using Avalonia.VisualTree;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.Input;
|
|
|
|
public class AddOnContentTemplateTests
|
|
{
|
|
static AddOnContentTemplateTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void TemplateOnly_AddOnDecoratedBox_Slots_Create_Visible_Children()
|
|
{
|
|
var decoratedBox = new AddOnDecoratedBox
|
|
{
|
|
Width = 320,
|
|
Content = new Border { Width = 120, Height = 32 },
|
|
LeftAddOnTemplate = CreateTemplate("left"),
|
|
RightAddOnTemplate = CreateTemplate("right"),
|
|
ContentLeftAddOnTemplate = CreateTemplate("content-left"),
|
|
ContentRightAddOnTemplate = CreateTemplate("content-right")
|
|
};
|
|
|
|
ShowInWindow(decoratedBox, () =>
|
|
{
|
|
AssertPresenterChild(decoratedBox, AddOnDecoratedBoxThemeConstants.LeftAddOnPresenterPart, "left");
|
|
AssertPresenterChild(decoratedBox, AddOnDecoratedBoxThemeConstants.RightAddOnPresenterPart, "right");
|
|
AssertPresenterChild(decoratedBox, AddOnDecoratedBoxThemeConstants.ContentLeftAddOnPart, "content-left");
|
|
AssertPresenterChild(decoratedBox, AddOnDecoratedBoxThemeConstants.ContentRightAddOnPart, "content-right");
|
|
|
|
FindNamedControl(decoratedBox, AddOnDecoratedBoxThemeConstants.LeftAddOnPart).IsVisible.ShouldBeTrue();
|
|
FindNamedControl(decoratedBox, AddOnDecoratedBoxThemeConstants.RightAddOnPart).IsVisible.ShouldBeTrue();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void LineEdit_TemplateOnly_InnerRightContent_Creates_ToolTip_Host()
|
|
{
|
|
var lineEdit = new LineEdit
|
|
{
|
|
Width = 240,
|
|
InnerRightContentTemplate = CreateTemplate("line-edit-right", "line edit tip")
|
|
};
|
|
|
|
ShowInWindow(lineEdit, () =>
|
|
{
|
|
var child = AssertPresenterChild(lineEdit, "InnerRightContentPresenter", "line-edit-right");
|
|
ToolTip.GetTip(child).ShouldBe("line edit tip");
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void TextArea_InnerRightContent_And_Template_Are_Visible()
|
|
{
|
|
var directContent = new Border { Tag = "direct-right" };
|
|
var textArea = new TextArea
|
|
{
|
|
Width = 240,
|
|
Height = 100,
|
|
InnerRightContent = directContent,
|
|
InnerRightContentTemplate = CreateTemplate("template-right")
|
|
};
|
|
|
|
ShowInWindow(textArea, () =>
|
|
{
|
|
var presenter = FindPresenter(textArea, "PART_InnerRightContentPresenter");
|
|
presenter.IsVisible.ShouldBeTrue();
|
|
presenter.Content.ShouldBeSameAs(directContent);
|
|
presenter.ContentTemplate.ShouldBeSameAs(textArea.InnerRightContentTemplate);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void ButtonSpinner_TemplateOnly_InnerContent_Creates_Both_Children()
|
|
{
|
|
var spinner = new ButtonSpinner
|
|
{
|
|
Width = 240,
|
|
Content = "value",
|
|
InnerLeftContentTemplate = CreateTemplate("spinner-left"),
|
|
InnerRightContentTemplate = CreateTemplate("spinner-right")
|
|
};
|
|
|
|
ShowInWindow(spinner, () =>
|
|
{
|
|
AssertPresenterChild(spinner, AddOnDecoratedBoxThemeConstants.ContentLeftAddOnPart, "spinner-left");
|
|
AssertPresenterChild(spinner, AddOnDecoratedBoxThemeConstants.ContentRightAddOnPart, "spinner-right");
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void DatePicker_TemplateOnly_LeftAddOn_Uses_LeftAddOnTemplate()
|
|
{
|
|
var datePicker = new DatePicker
|
|
{
|
|
Width = 240,
|
|
LeftAddOnTemplate = CreateTemplate("date-picker-left")
|
|
};
|
|
|
|
ShowInWindow(datePicker, () =>
|
|
{
|
|
AssertPresenterChild(datePicker, AddOnDecoratedBoxThemeConstants.LeftAddOnPresenterPart,
|
|
"date-picker-left");
|
|
FindNamedControl(datePicker, AddOnDecoratedBoxThemeConstants.LeftAddOnPart).IsVisible.ShouldBeTrue();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void SearchEdit_TemplateOnly_InnerContent_Creates_Both_Children()
|
|
{
|
|
var searchEdit = new SearchEdit
|
|
{
|
|
Width = 240,
|
|
InnerLeftContentTemplate = CreateTemplate("search-left"),
|
|
InnerRightContentTemplate = CreateTemplate("search-right")
|
|
};
|
|
|
|
ShowInWindow(searchEdit, () =>
|
|
{
|
|
AssertMarkerVisible(searchEdit, "search-left");
|
|
AssertMarkerVisible(searchEdit, "search-right");
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void TemplateOnly_Content_Works_Across_AddOnDecoratedBox_Consumers()
|
|
{
|
|
var controls = new Control[]
|
|
{
|
|
new AtomUI.Desktop.Controls.ComboBox
|
|
{
|
|
ContentRightAddOnTemplate = CreateTemplate("combo-box-right")
|
|
},
|
|
new Select
|
|
{
|
|
ContentRightAddOnTemplate = CreateTemplate("select-right")
|
|
},
|
|
new TreeSelect
|
|
{
|
|
ContentRightAddOnTemplate = CreateTemplate("tree-select-right")
|
|
},
|
|
new AtomUI.Desktop.Controls.Cascader
|
|
{
|
|
ContentRightAddOnTemplate = CreateTemplate("cascader-right")
|
|
},
|
|
new DatePicker
|
|
{
|
|
ContentRightAddOnTemplate = CreateTemplate("date-picker-right")
|
|
},
|
|
new AtomUI.Desktop.Controls.NumericUpDown
|
|
{
|
|
InnerRightContentTemplate = CreateTemplate("numeric-up-down-right")
|
|
}
|
|
};
|
|
|
|
foreach (var control in controls)
|
|
{
|
|
control.Width = 240;
|
|
ShowInWindow(control, () => AssertMarkerVisible(control, GetExpectedMarker(control)));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void TemplateOnly_Content_Works_Through_AutoComplete_And_Mentions_Wrappers()
|
|
{
|
|
var controls = new Control[]
|
|
{
|
|
new AtomUI.Desktop.Controls.AutoComplete
|
|
{
|
|
ContentLeftAddOnTemplate = CreateTemplate("auto-complete-left"),
|
|
ContentRightAddOnTemplate = CreateTemplate("auto-complete-right")
|
|
},
|
|
new AutoCompleteSearchEdit
|
|
{
|
|
ContentLeftAddOnTemplate = CreateTemplate("auto-search-left"),
|
|
ContentRightAddOnTemplate = CreateTemplate("auto-search-right")
|
|
},
|
|
new AutoCompleteTextArea
|
|
{
|
|
ContentLeftAddOnTemplate = CreateTemplate("auto-text-area-left"),
|
|
ContentRightAddOnTemplate = CreateTemplate("auto-text-area-right")
|
|
},
|
|
new Mentions
|
|
{
|
|
ContentLeftAddOnTemplate = CreateTemplate("mentions-left"),
|
|
ContentRightAddOnTemplate = CreateTemplate("mentions-right")
|
|
}
|
|
};
|
|
|
|
var expectedMarkers = new[]
|
|
{
|
|
new[] { "auto-complete-left", "auto-complete-right" },
|
|
new[] { "auto-search-left", "auto-search-right" },
|
|
new[] { "auto-text-area-left", "auto-text-area-right" },
|
|
new[] { "mentions-left", "mentions-right" }
|
|
};
|
|
|
|
for (var index = 0; index < controls.Length; index++)
|
|
{
|
|
var control = controls[index];
|
|
control.Width = 240;
|
|
ShowInWindow(control, () =>
|
|
{
|
|
foreach (var marker in expectedMarkers[index])
|
|
{
|
|
AssertMarkerVisible(control, marker);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Runtime_Template_Changes_Update_Child_Visibility_And_CornerRadius()
|
|
{
|
|
var decoratedBox = new AddOnDecoratedBox
|
|
{
|
|
Width = 240,
|
|
CornerRadius = new Avalonia.CornerRadius(8),
|
|
StyleVariant = InputControlStyleVariant.Outlined,
|
|
Content = new Border { Width = 120, Height = 32 },
|
|
LeftAddOnTemplate = CreateTemplate("runtime-first")
|
|
};
|
|
|
|
ShowInWindow(decoratedBox, () =>
|
|
{
|
|
AssertPresenterChild(decoratedBox, AddOnDecoratedBoxThemeConstants.LeftAddOnPresenterPart,
|
|
"runtime-first");
|
|
decoratedBox.InnerBoxCornerRadius.TopLeft.ShouldBe(0);
|
|
decoratedBox.InnerBoxCornerRadius.BottomLeft.ShouldBe(0);
|
|
|
|
decoratedBox.LeftAddOnTemplate = CreateTemplate("runtime-second");
|
|
Dispatcher.UIThread.RunJobs();
|
|
AssertPresenterChild(decoratedBox, AddOnDecoratedBoxThemeConstants.LeftAddOnPresenterPart,
|
|
"runtime-second");
|
|
|
|
decoratedBox.LeftAddOnTemplate = null;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
var presenter = FindPresenter(decoratedBox,
|
|
AddOnDecoratedBoxThemeConstants.LeftAddOnPresenterPart);
|
|
presenter.Child.ShouldBeNull();
|
|
presenter.IsVisible.ShouldBeFalse();
|
|
FindNamedControl(decoratedBox, AddOnDecoratedBoxThemeConstants.LeftAddOnPart)
|
|
.IsVisible.ShouldBeFalse();
|
|
decoratedBox.InnerBoxCornerRadius.TopLeft.ShouldBe(8);
|
|
decoratedBox.InnerBoxCornerRadius.BottomLeft.ShouldBe(8);
|
|
});
|
|
}
|
|
|
|
private static IDataTemplate CreateTemplate(string marker, string? toolTip = null)
|
|
{
|
|
return new FuncDataTemplate(_ => true, (_, _) =>
|
|
{
|
|
var child = new Border
|
|
{
|
|
Width = 16,
|
|
Height = 16,
|
|
Tag = marker
|
|
};
|
|
if (toolTip is not null)
|
|
{
|
|
ToolTip.SetTip(child, toolTip);
|
|
}
|
|
return child;
|
|
});
|
|
}
|
|
|
|
private static Control AssertPresenterChild(Control owner, string presenterName, string marker)
|
|
{
|
|
var presenter = FindPresenter(owner, presenterName);
|
|
presenter.IsVisible.ShouldBeTrue();
|
|
presenter.Child.ShouldNotBeNull();
|
|
presenter.Child!.Tag.ShouldBe(marker);
|
|
return presenter.Child;
|
|
}
|
|
|
|
private static void AssertMarkerVisible(Control owner, string marker)
|
|
{
|
|
owner.GetVisualDescendants()
|
|
.OfType<Control>()
|
|
.Single(control => Equals(control.Tag, marker))
|
|
.IsVisible.ShouldBeTrue();
|
|
}
|
|
|
|
private static string GetExpectedMarker(Control control)
|
|
{
|
|
return control switch
|
|
{
|
|
AtomUI.Desktop.Controls.ComboBox => "combo-box-right",
|
|
Select => "select-right",
|
|
TreeSelect => "tree-select-right",
|
|
AtomUI.Desktop.Controls.Cascader => "cascader-right",
|
|
DatePicker => "date-picker-right",
|
|
AtomUI.Desktop.Controls.NumericUpDown => "numeric-up-down-right",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(control))
|
|
};
|
|
}
|
|
|
|
private static ContentPresenter FindPresenter(Control owner, string name)
|
|
{
|
|
return owner.GetVisualDescendants()
|
|
.OfType<ContentPresenter>()
|
|
.Single(item => item.Name == name);
|
|
}
|
|
|
|
private static Control FindNamedControl(Control owner, string name)
|
|
{
|
|
return owner.GetVisualDescendants()
|
|
.OfType<Control>()
|
|
.Single(item => item.Name == name);
|
|
}
|
|
|
|
private static void ShowInWindow(Control content, Action assertion)
|
|
{
|
|
var window = new AvaloniaWindow
|
|
{
|
|
Width = 420,
|
|
Height = 180,
|
|
Content = content
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
assertion();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
}
|