mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-18 22:46:38 +08:00
254 lines
8.0 KiB
C#
254 lines
8.0 KiB
C#
using AtomUI.Controls.Primitives;
|
|
using AtomUI.Icons.AntDesign;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Presenters;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Threading;
|
|
using Avalonia.VisualTree;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.TreeSelectControl;
|
|
|
|
public class TreeSelectBehaviorTests
|
|
{
|
|
static TreeSelectBehaviorTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void Template_Binds_Right_AddOn_Count_And_Handle_State_From_Axaml()
|
|
{
|
|
var jack = new TreeItemNode
|
|
{
|
|
Header = "Jack",
|
|
Value = "jack"
|
|
};
|
|
var lucy = new TreeItemNode
|
|
{
|
|
Header = "Lucy",
|
|
Value = "lucy"
|
|
};
|
|
var rightAddOn = new TextBlock { Text = "extra" };
|
|
var suffixIcon = new DownOutlined();
|
|
var loadingIcon = new LoadingOutlined();
|
|
var treeSelect = new Desktop.Controls.TreeSelect
|
|
{
|
|
Width = 240,
|
|
IsMultiple = true,
|
|
IsFilterEnabled = true,
|
|
IsAllowClear = true,
|
|
IsMotionEnabled = false,
|
|
MaxCount = 3,
|
|
IsShowMaxCountIndicator = true,
|
|
SelectedItems = [jack, lucy],
|
|
ContentRightAddOn = rightAddOn,
|
|
SuffixIcon = suffixIcon,
|
|
SuffixLoadingIcon = loadingIcon
|
|
};
|
|
|
|
ShowInWindow(treeSelect, () =>
|
|
{
|
|
var indicator = GetVisualDescendant<SelectMaxCountIndicator>(treeSelect, "PART_SelectMaxCountIndicator");
|
|
indicator.MaxCount.ShouldBe(3);
|
|
indicator.SelectedCount.ShouldBe(2);
|
|
indicator.IsVisible.ShouldBeTrue();
|
|
|
|
var contentPresenter = GetVisualDescendant<ContentPresenter>(treeSelect, "PART_ContentRightAddOnPresenter");
|
|
contentPresenter.Content.ShouldBeSameAs(rightAddOn);
|
|
contentPresenter.IsVisible.ShouldBeTrue();
|
|
|
|
var handle = GetVisualDescendant<SelectHandle>(treeSelect, "PART_SelectHandle");
|
|
handle.OpenIndicator.ShouldBeSameAs(suffixIcon);
|
|
handle.LoadingIcon.ShouldBeSameAs(loadingIcon);
|
|
handle.IsFilterEnabled.ShouldBeTrue();
|
|
handle.IsMotionEnabled.ShouldBeFalse();
|
|
handle.IsAllowClear.ShouldBeTrue();
|
|
handle.IsSelectionEmpty.ShouldBeFalse();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Template_Relays_AddOnDecoratedBox_Input_State_To_Handle()
|
|
{
|
|
var treeSelect = new Desktop.Controls.TreeSelect
|
|
{
|
|
Width = 240
|
|
};
|
|
|
|
ShowInWindow(treeSelect, () =>
|
|
{
|
|
var addOnBox = GetVisualDescendant<AddOnDecoratedBox>(
|
|
treeSelect,
|
|
AddOnDecoratedBox.AddOnDecoratedBoxPart);
|
|
var handle = GetVisualDescendant<SelectHandle>(treeSelect, "PART_SelectHandle");
|
|
|
|
addOnBox.IsInnerBoxHover = true;
|
|
addOnBox.IsInnerBoxPressed = true;
|
|
|
|
handle.IsInputHover.ShouldBeTrue();
|
|
handle.IsInputPressed.ShouldBeTrue();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Custom_Size_Single_Selected_Text_Is_Vertically_Centered()
|
|
{
|
|
var selectedNode = new TreeItemNode
|
|
{
|
|
Header = "My leaf",
|
|
Value = "my-leaf"
|
|
};
|
|
var treeSelect = new Desktop.Controls.TreeSelect
|
|
{
|
|
Width = 240,
|
|
Height = 38,
|
|
FontSize = 15,
|
|
SizeType = CustomizableSizeType.Custom,
|
|
IsAllowClear = true,
|
|
SelectedItem = selectedNode,
|
|
ItemsSource = [selectedNode],
|
|
PlaceholderText = "Please select"
|
|
};
|
|
|
|
ShowInWindow(treeSelect, () =>
|
|
{
|
|
var addOnBox = GetVisualDescendant<AddOnDecoratedBox>(
|
|
treeSelect,
|
|
AddOnDecoratedBox.AddOnDecoratedBoxPart);
|
|
var textPresenter = GetVisualDescendant<TextPresenter>(treeSelect, "PART_TextPresenter");
|
|
|
|
var textTop = textPresenter.TranslatePoint(default, addOnBox);
|
|
textTop.ShouldNotBeNull();
|
|
|
|
var textCenterY = textTop.Value.Y + textPresenter.Bounds.Height / 2;
|
|
var boxCenterY = addOnBox.Bounds.Height / 2;
|
|
|
|
Math.Abs(textCenterY - boxCenterY).ShouldBeLessThanOrEqualTo(1.0);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Single_Filter_Input_Uses_Outer_Content_Padding_Only()
|
|
{
|
|
var selectedNode = new TreeItemNode
|
|
{
|
|
Header = "My leaf",
|
|
Value = "my-leaf"
|
|
};
|
|
var treeSelect = new Desktop.Controls.TreeSelect
|
|
{
|
|
Width = 240,
|
|
IsFilterEnabled = true,
|
|
ItemsSource = [selectedNode]
|
|
};
|
|
|
|
ShowInWindow(treeSelect, () =>
|
|
{
|
|
var searchTextBox = GetVisualDescendant<SelectFilterTextBox>(treeSelect, "PART_SingleFilterInput");
|
|
|
|
AssertEmbeddedSelectFilterTextBox(searchTextBox);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Multiple_Search_Input_Uses_Outer_Content_Padding_Only()
|
|
{
|
|
var selectedNode = new TreeItemNode
|
|
{
|
|
Header = "My leaf",
|
|
Value = "my-leaf"
|
|
};
|
|
var treeSelect = new Desktop.Controls.TreeSelect
|
|
{
|
|
Width = 240,
|
|
IsMultiple = true,
|
|
IsFilterEnabled = true,
|
|
SelectedItems = [selectedNode],
|
|
ItemsSource = [selectedNode]
|
|
};
|
|
|
|
ShowInWindow(treeSelect, () =>
|
|
{
|
|
var searchTextBox = GetTagsSearchTextBox(treeSelect);
|
|
|
|
AssertEmbeddedSelectFilterTextBox(searchTextBox);
|
|
});
|
|
}
|
|
|
|
private static T GetVisualDescendant<T>(Control control, string name)
|
|
where T : Control
|
|
{
|
|
var descendant = control.GetVisualDescendants()
|
|
.OfType<T>()
|
|
.SingleOrDefault(x => x.Name == name);
|
|
descendant.ShouldNotBeNull();
|
|
return descendant;
|
|
}
|
|
|
|
private static SelectFilterTextBox GetTagsSearchTextBox(Control control)
|
|
{
|
|
var textBox = control.GetVisualDescendants()
|
|
.OfType<SelectFilterTextBox>()
|
|
.SingleOrDefault(item => item.Name != "PART_SingleFilterInput");
|
|
textBox.ShouldNotBeNull();
|
|
return textBox;
|
|
}
|
|
|
|
private static void AssertEmbeddedSelectFilterTextBox(SelectFilterTextBox searchTextBox)
|
|
{
|
|
searchTextBox.ShouldBeAssignableTo<EmbeddedTextBox>();
|
|
searchTextBox.SizeType.ShouldBe(CustomizableSizeType.Custom);
|
|
searchTextBox.Padding.ShouldBe(new Thickness(0));
|
|
searchTextBox.BorderThickness.ShouldBe(new Thickness(0));
|
|
searchTextBox.IsCustomFontSize.ShouldBeTrue();
|
|
}
|
|
|
|
private static void ShowInWindow(Control content, Action assertion)
|
|
{
|
|
var overlayPanel = new ScopeAwareOverlayLayerPanel
|
|
{
|
|
Width = 420,
|
|
Height = 320
|
|
};
|
|
overlayPanel.Children.Add(content);
|
|
|
|
var visualLayerManager = new VisualLayerManager
|
|
{
|
|
Child = overlayPanel
|
|
};
|
|
EnablePopupOverlayLayer(visualLayerManager);
|
|
|
|
var window = new AvaloniaWindow
|
|
{
|
|
Width = 420,
|
|
Height = 320,
|
|
Content = visualLayerManager
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
assertion();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
private static void EnablePopupOverlayLayer(VisualLayerManager visualLayerManager)
|
|
{
|
|
var property = typeof(VisualLayerManager).GetProperty(
|
|
"EnablePopupOverlayLayer",
|
|
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
|
|
|
property.ShouldNotBeNull();
|
|
property.SetValue(visualLayerManager, true);
|
|
}
|
|
}
|