1
0
Fork 0

fix(ui): fix SettingsWindow and dialog titlebar margins, vertical alignment, and button styling

This commit is contained in:
Yun Chan 2026-09-05 06:36:26 +09:00
parent 1f794e9e08
commit 7cb75fd3aa
5 changed files with 129 additions and 19 deletions

View file

@ -23,7 +23,7 @@
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</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">
<StackPanel x:Name="ItemsPanel"/>
</ScrollViewer>

View file

@ -1,6 +1,7 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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">
<!-- Windows 11 Flagship Acrylic & Neo Glass Backgrounds -->
@ -577,16 +578,19 @@
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
<Setter Property="FontFamily" Value="{StaticResource FsFontSans}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="ButtonsForeground" Value="#D0D5DD"/>
<Setter Property="ButtonsBackground" Value="#1FFFFFFF"/>
<Setter Property="ButtonsBackground" Value="Transparent"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ui:TitleBar}">
<Grid Background="{TemplateBinding Background}" Name="PART_MainGrid"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
@ -608,8 +612,12 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Header (Tabs + Telemetry) -->
<ContentPresenter Content="{TemplateBinding Header}" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="0"/>
<!-- Header (Tabs + Telemetry) or Title (when Header is string or TextBlock) -->
<ContentPresenter Content="{TemplateBinding Header}"
Margin="16,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Column="0"/>
<!-- CenterContent (Wide Native Drag Area) -->
<ContentPresenter Content="{TemplateBinding CenterContent}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="Center" Grid.Column="1"/>
@ -626,23 +634,18 @@
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ui:TitleBarButton ButtonType="Help" Name="PART_HelpButton" AutomationProperties.AutomationId="TitleBarHelpButton" Grid.Column="0" 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"/>
<ui:TitleBarButton ButtonType="Maximize" Name="PART_MaximizeButton" IsHitTestVisible="True" AutomationProperties.AutomationId="TitleBarMaximizeButton" Grid.Column="2" 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"/>
<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" 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" 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" Background="Transparent" Foreground="{TemplateBinding ButtonsForeground}" ButtonsForeground="{TemplateBinding ButtonsForeground}"/>
</Grid>
</Grid>
</Grid>
<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}">
<Setter TargetName="PART_Icon" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="TitleGrid" Property="Visibility" Value="Collapsed"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>

View file

@ -20,7 +20,7 @@
<Grid Background="{StaticResource FsBgBase}">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

View file

@ -22,7 +22,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</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.RowDefinitions>
<RowDefinition Height="Auto"/>

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xml.Linq;
using Everything2Everything.App.Views;
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)
{
while (node != null)