fix(ui): fix SettingsWindow and dialog titlebar margins, vertical alignment, and button styling
This commit is contained in:
parent
1f794e9e08
commit
7cb75fd3aa
5 changed files with 129 additions and 19 deletions
|
|
@ -23,7 +23,7 @@
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ui:TitleBar Grid.Row="0" Title="진단" Height="32"/>
|
<ui:TitleBar Grid.Row="0" Title="진단" ShowMaximize="False" ShowMinimize="False"/>
|
||||||
<ScrollViewer Grid.Row="1" Margin="24,8,24,16" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Row="1" Margin="24,8,24,16" VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel x:Name="ItemsPanel"/>
|
<StackPanel x:Name="ItemsPanel"/>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
|
||||||
|
|
||||||
<!-- Windows 11 Flagship Acrylic & Neo Glass Backgrounds -->
|
<!-- Windows 11 Flagship Acrylic & Neo Glass Backgrounds -->
|
||||||
|
|
@ -577,16 +578,19 @@
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
|
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
|
||||||
<Setter Property="FontFamily" Value="{StaticResource FsFontSans}"/>
|
<Setter Property="FontFamily" Value="{StaticResource FsFontSans}"/>
|
||||||
|
<Setter Property="FontSize" Value="12"/>
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||||
<Setter Property="ButtonsForeground" Value="#D0D5DD"/>
|
<Setter Property="ButtonsForeground" Value="#D0D5DD"/>
|
||||||
<Setter Property="ButtonsBackground" Value="#1FFFFFFF"/>
|
<Setter Property="ButtonsBackground" Value="Transparent"/>
|
||||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="{x:Type ui:TitleBar}">
|
<ControlTemplate TargetType="{x:Type ui:TitleBar}">
|
||||||
<Grid Background="{TemplateBinding Background}" Name="PART_MainGrid"
|
<Grid Background="{TemplateBinding Background}" Name="PART_MainGrid"
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
VerticalAlignment="Stretch">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
|
|
@ -608,8 +612,12 @@
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Header (Tabs + Telemetry) -->
|
<!-- Header (Tabs + Telemetry) or Title (when Header is string or TextBlock) -->
|
||||||
<ContentPresenter Content="{TemplateBinding Header}" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="0"/>
|
<ContentPresenter Content="{TemplateBinding Header}"
|
||||||
|
Margin="16,0,0,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Grid.Column="0"/>
|
||||||
|
|
||||||
<!-- CenterContent (Wide Native Drag Area) -->
|
<!-- CenterContent (Wide Native Drag Area) -->
|
||||||
<ContentPresenter Content="{TemplateBinding CenterContent}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="Center" Grid.Column="1"/>
|
<ContentPresenter Content="{TemplateBinding CenterContent}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="Center" Grid.Column="1"/>
|
||||||
|
|
@ -626,23 +634,18 @@
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<ui:TitleBarButton ButtonType="Help" Name="PART_HelpButton" AutomationProperties.AutomationId="TitleBarHelpButton" Grid.Column="0" VerticalAlignment="Stretch" Height="Auto" Width="46"/>
|
<ui:TitleBarButton ButtonType="Help" Name="PART_HelpButton" AutomationProperties.AutomationId="TitleBarHelpButton" Grid.Column="0" VerticalAlignment="Stretch" Height="Auto" Width="46" Background="Transparent" Foreground="{TemplateBinding ButtonsForeground}" ButtonsForeground="{TemplateBinding ButtonsForeground}"/>
|
||||||
<ui:TitleBarButton ButtonType="Minimize" Name="PART_MinimizeButton" AutomationProperties.AutomationId="TitleBarMinimizeButton" Grid.Column="1" VerticalAlignment="Stretch" Height="Auto" Width="46"/>
|
<ui:TitleBarButton ButtonType="Minimize" Name="PART_MinimizeButton" AutomationProperties.AutomationId="TitleBarMinimizeButton" Grid.Column="1" VerticalAlignment="Stretch" Height="Auto" Width="46" Background="Transparent" Foreground="{TemplateBinding ButtonsForeground}" ButtonsForeground="{TemplateBinding ButtonsForeground}"/>
|
||||||
<ui:TitleBarButton ButtonType="Maximize" Name="PART_MaximizeButton" IsHitTestVisible="True" AutomationProperties.AutomationId="TitleBarMaximizeButton" Grid.Column="2" VerticalAlignment="Stretch" Height="Auto" Width="46"/>
|
<ui:TitleBarButton ButtonType="Maximize" Name="PART_MaximizeButton" IsHitTestVisible="True" AutomationProperties.AutomationId="TitleBarMaximizeButton" Grid.Column="2" VerticalAlignment="Stretch" Height="Auto" Width="46" Background="Transparent" Foreground="{TemplateBinding ButtonsForeground}" ButtonsForeground="{TemplateBinding ButtonsForeground}"/>
|
||||||
<ui:TitleBarButton ButtonType="Close" MouseOverButtonsForeground="#FFFFFFFF" MouseOverBackground="#E81123" Name="PART_CloseButton" AutomationProperties.AutomationId="TitleBarCloseButton" Grid.Column="4" VerticalAlignment="Stretch" Height="Auto" Width="46"/>
|
<ui:TitleBarButton ButtonType="Close" MouseOverButtonsForeground="#FFFFFFFF" MouseOverBackground="#E81123" Name="PART_CloseButton" AutomationProperties.AutomationId="TitleBarCloseButton" Grid.Column="4" VerticalAlignment="Stretch" Height="Auto" Width="46" Background="Transparent" Foreground="{TemplateBinding ButtonsForeground}" ButtonsForeground="{TemplateBinding ButtonsForeground}"/>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<ControlTemplate.Triggers>
|
<ControlTemplate.Triggers>
|
||||||
<MultiTrigger>
|
|
||||||
<MultiTrigger.Conditions>
|
|
||||||
<Condition Property="Icon" Value="{x:Null}"/>
|
|
||||||
<Condition Property="Title" Value="{x:Null}"/>
|
|
||||||
</MultiTrigger.Conditions>
|
|
||||||
<Setter TargetName="TitleGrid" Property="Visibility" Value="Collapsed"/>
|
|
||||||
</MultiTrigger>
|
|
||||||
<Trigger Property="Icon" Value="{x:Null}">
|
<Trigger Property="Icon" Value="{x:Null}">
|
||||||
<Setter TargetName="PART_Icon" Property="Visibility" Value="Collapsed"/>
|
<Setter TargetName="TitleGrid" Property="Visibility" Value="Collapsed"/>
|
||||||
</Trigger>
|
</Trigger>
|
||||||
<MultiTrigger>
|
<MultiTrigger>
|
||||||
<MultiTrigger.Conditions>
|
<MultiTrigger.Conditions>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
<Grid Background="{StaticResource FsBgBase}">
|
<Grid Background="{StaticResource FsBgBase}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="32"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ui:TitleBar Grid.Row="0" x:Name="WindowTitleBar" Title="빠른 변환"/>
|
<ui:TitleBar Grid.Row="0" x:Name="WindowTitleBar" Title="빠른 변환" ShowMaximize="False" ShowMinimize="False"/>
|
||||||
<Grid Grid.Row="1" Margin="32,12,32,24">
|
<Grid Grid.Row="1" Margin="32,12,32,24">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Everything2Everything.App.Views;
|
using Everything2Everything.App.Views;
|
||||||
using Everything2Everything.Core;
|
using Everything2Everything.Core;
|
||||||
|
|
@ -276,6 +277,112 @@ public class UnifiedTitleBarTests
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SettingsWindow_TitleBar_MustDisplayProperlyAlignedHeaderAndCloseButton()
|
||||||
|
{
|
||||||
|
RunOnSta(() =>
|
||||||
|
{
|
||||||
|
var store = new FakeSettingsStore();
|
||||||
|
var window = new SettingsWindow(store);
|
||||||
|
|
||||||
|
var content = (UIElement)window.Content;
|
||||||
|
content.Measure(new Size(560, 720));
|
||||||
|
content.Arrange(new Rect(0, 0, 560, 720));
|
||||||
|
|
||||||
|
var titleBar = FindLogicalChild<Wpf.Ui.Controls.TitleBar>(window);
|
||||||
|
Assert.NotNull(titleBar);
|
||||||
|
titleBar.ApplyTemplate();
|
||||||
|
|
||||||
|
// 1. TitleBar height must be 42px
|
||||||
|
Assert.Equal(42.0, titleBar.ActualHeight);
|
||||||
|
|
||||||
|
// 2. PART_MainGrid must stretch to 42px
|
||||||
|
var mainGrid = (FrameworkElement)titleBar.Template.FindName("PART_MainGrid", titleBar);
|
||||||
|
Assert.NotNull(mainGrid);
|
||||||
|
Assert.Equal(42.0, mainGrid.ActualHeight);
|
||||||
|
|
||||||
|
// 3. Find the rendered TextBlock with text "설정"
|
||||||
|
var textBlocks = FindVisualChildren<TextBlock>(titleBar).Where(t => t.Text == "설정").ToList();
|
||||||
|
Assert.NotEmpty(textBlocks);
|
||||||
|
var titleTb = textBlocks.First();
|
||||||
|
|
||||||
|
// 4. TextBlock "설정" must not be at X=0 (must have left padding/margin >= 12px)
|
||||||
|
var textPt = titleTb.TransformToAncestor(titleBar).Transform(new Point(0, 0));
|
||||||
|
Assert.True(textPt.X >= 12.0, $"Title text X coordinate ({textPt.X}px) must be >= 12px to prevent touching window edge.");
|
||||||
|
|
||||||
|
var closeBtn = (FrameworkElement)titleBar.Template.FindName("PART_CloseButton", titleBar);
|
||||||
|
Assert.NotNull(closeBtn);
|
||||||
|
Assert.Equal(Visibility.Visible, closeBtn.Visibility);
|
||||||
|
|
||||||
|
// 5. Title text center Y and Close button center Y must match within 2.0px tolerance
|
||||||
|
var textCenterY = textPt.Y + titleTb.ActualHeight / 2.0;
|
||||||
|
var closeCenterY = closeBtn.TransformToAncestor(titleBar).Transform(new Point(0, closeBtn.ActualHeight / 2.0)).Y;
|
||||||
|
Assert.True(Math.Abs(textCenterY - closeCenterY) <= 2.0,
|
||||||
|
$"Title text CenterY ({textCenterY:F1}px) and CloseButton CenterY ({closeCenterY:F1}px) must match within 2px.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DiagnoseWindow_TitleBar_MustHaveStandardHeightAndButtons()
|
||||||
|
{
|
||||||
|
RunOnSta(() =>
|
||||||
|
{
|
||||||
|
var engine = Everything2EverythingBootstrap.CreateDefault();
|
||||||
|
var window = new DiagnoseWindow(engine);
|
||||||
|
|
||||||
|
var content = (UIElement)window.Content;
|
||||||
|
content.Measure(new Size(680, 580));
|
||||||
|
content.Arrange(new Rect(0, 0, 680, 580));
|
||||||
|
|
||||||
|
var titleBar = FindLogicalChild<Wpf.Ui.Controls.TitleBar>(window);
|
||||||
|
Assert.NotNull(titleBar);
|
||||||
|
titleBar.ApplyTemplate();
|
||||||
|
|
||||||
|
// Height must be standard 42px (not hardcoded 32px)
|
||||||
|
Assert.Equal(42.0, titleBar.ActualHeight);
|
||||||
|
Assert.False(titleBar.ShowMaximize);
|
||||||
|
Assert.False(titleBar.ShowMinimize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void QuickOptionsWindow_TitleBar_MustHaveStandardHeightAndButtons()
|
||||||
|
{
|
||||||
|
RunOnSta(() =>
|
||||||
|
{
|
||||||
|
var store = new FakeSettingsStore();
|
||||||
|
var window = new QuickOptionsWindow(".mp4", 1, store);
|
||||||
|
|
||||||
|
var content = (UIElement)window.Content;
|
||||||
|
content.Measure(new Size(380, 500));
|
||||||
|
content.Arrange(new Rect(0, 0, 380, 500));
|
||||||
|
|
||||||
|
var titleBar = FindLogicalChild<Wpf.Ui.Controls.TitleBar>(window);
|
||||||
|
Assert.NotNull(titleBar);
|
||||||
|
titleBar.ApplyTemplate();
|
||||||
|
|
||||||
|
Assert.Equal(42.0, titleBar.ActualHeight);
|
||||||
|
Assert.False(titleBar.ShowMaximize);
|
||||||
|
Assert.False(titleBar.ShowMinimize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) where T : DependencyObject
|
||||||
|
{
|
||||||
|
int count = VisualTreeHelper.GetChildrenCount(parent);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var child = VisualTreeHelper.GetChild(parent, i);
|
||||||
|
if (child is T typed) yield return typed;
|
||||||
|
foreach (var descendant in FindVisualChildren<T>(child))
|
||||||
|
{
|
||||||
|
yield return descendant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static bool IsDescendantOf(DependencyObject? node, DependencyObject targetAncestor)
|
private static bool IsDescendantOf(DependencyObject? node, DependencyObject targetAncestor)
|
||||||
{
|
{
|
||||||
while (node != null)
|
while (node != null)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue