Files
SheetMe/src/SheetMe.Designer/Themes/DesignerTheme.xaml
T
MsystechandClaude Opus 5 a30421f9b5 레이어 패널에 [200]SheetMe 그룹 기능 이식 — 폴더 행·계층·타입 필터·다중선택
[200] 의 그룹도 컨테이너가 아니라 GroupId 태그 + 이름 사전이었다. SheetMe 가 이미
같은 구조(ControlElement.GroupId, JsonIgnore)를 갖고 있어 저장 포맷은 그대로 두고
표시·조작 계층만 얹는다 — 왕복 XML 에는 아무 흔적도 남지 않는다.

레이어 목록을 평탄화 결과(LayerRows)로 바꿨다. 그룹 폴더 행과 컨트롤 행이 한
시퀀스로 섞이고, 계층은 들여쓰기 여백으로만 표현한다(TreeView 를 쓰면 가상화와
기존 행 템플릿을 다 버려야 한다 — 인스펙터 섹션이 쓰는 방식과 같게 맞췄다).

새로 되는 것
- 그룹 폴더 행: 접기/펼치기, 멤버 수, 이름 인라인 편집(더블클릭), 그룹 전체 눈·자물쇠
- 그룹 이름 — FormDocument.GroupNames(편집 전용). 비우면 기본 그룹 으로 복귀
- 컨테이너(패널/그룹박스) 자식이 레이어에 보인다. 지금까지는 아예 접근할 수 없었다
- 목록 다중선택(Shift/Ctrl) — 캔버스 선택과 양방향 동기
- 타입 필터: 그 페이지에 실제로 있는 타입만 후보로 띄운다
- 검색 0건·빈 페이지 안내 문구

함께 고친 결함
- 붙여넣기가 원본 그룹에 끼어들었다(Clone 이 GroupId 를 그대로 복사) → 복제본끼리 새 그룹
- 그룹 해제가 선택된 멤버만 풀어 1개짜리 반쪽 그룹이 남았다 → 그룹 전 멤버를 푼다
- 멤버가 1개 이하로 줄어든 그룹이 계속 남았다 → CleanupGroups 자가치유
- 셰브론이 늘 눌린 것처럼 보였다(IsChecked 채움) → MiniChevron 스타일 분리

--edit-smoke 에 레이어 검사 19건 추가(그룹 위생·평탄화·필터·XML 무영향).
회귀: 테스트 124/124, edit-smoke 실패 0, db-smoke 1,271건 diff 0/예외 0,
종이 렌더 P062 바이트 동일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 15:43:37 +09:00

1120 lines
68 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
xmlns:ctl="clr-namespace:SheetMe.Designer.Controls">
<!-- ============================================================
디자이너 공유 테마 (암시 스타일 + 컨트롤 템플릿)
· 색상은 {DynamicResource B.*} 로 참조 → 토큰 dict(Tokens.Dark/Light.xaml) 교체로 라이트/다크 전환
· MainWindow.Resources 에 [이 파일 + 토큰 dict] 머지(토큰 dict 만 스왑)
· 스타일 키(Subtle/CaptionBtn/B.ComboItem/ScrollThumb…)는 StaticResource 유지
============================================================ -->
<!-- ===== 창 공통(다이얼로그 배경/폰트 — 로컬 지정이 있으면 로컬 우선) =====
FontSize/Foreground 가 없으면 대화상자들이 WPF 기본 12px + 시스템 검정으로 렌더돼
메인 셸(13px)과 결이 어긋난다. 토큰 참조는 DynamicResource 로 둬야 테마 전환에 따라간다. -->
<!--
⚠ 창에는 **반드시 Style="{StaticResource ThemedWindow}" 를 직접 걸어야 한다.**
WPF 는 암시 스타일을 요소의 '정확한 런타임 타입'으로만 찾는다. 모든 대화상자가
Window 를 **상속한** 클래스(SheetOpenDialogView : Window 등)라 아래 암시 스타일은
이들에게 단 한 번도 적용된 적이 없었다 — 진단(dialog-shots)이 창 8종 전부
배경=#FFFFFFFF / Style=null 로 보고했다. 결과적으로 다크 테마에서 흰 창 위에
B.Ink(#EDEDED) 글자가 얹혀 대화상자 내용이 통째로 보이지 않았다.
(TextBlock·TextBox 등은 정확한 타입이라 암시 스타일이 정상 적용돼, 창 배경만
WPF 기본 흰색으로 남는 형태로 드러났다.)
-->
<Style x:Key="ThemedWindow" TargetType="Window">
<Setter Property="Background" Value="{DynamicResource B.AppBg}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
</Style>
<!-- 순수 Window 인스턴스용(파생 클래스에는 위 키 스타일을 직접 걸어야 한다) -->
<Style TargetType="Window" BasedOn="{StaticResource ThemedWindow}" />
<!-- ===== 타이포 ===== -->
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="TextOptions.TextFormattingMode" Value="Ideal" />
</Style>
<!-- ===== 버튼 (기본: 은은한 다크 채움) ===== -->
<Style TargetType="Button">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Background" Value="{DynamicResource B.Input}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.Line}" />
<Setter Property="Padding" Value="10,5" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" CornerRadius="5" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=ButtonBase}}" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.BtnHover}" />
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Line2}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.BtnPressed}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="bd" Property="Opacity" Value="0.45" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 강조 버튼 -->
<Style x:Key="Primary" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<!-- 흰 글자를 얹는 채움이라 브랜드색(#0099FF, 흰 글자 대비 3.0:1)이 아니라 짙은 강조 토큰을 쓴다 -->
<Setter Property="Background" Value="{DynamicResource B.AccentFill}" />
<Setter Property="Foreground" Value="{DynamicResource B.OnAccent}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.AccentFill}" />
</Style>
<!-- 텍스트형(테두리 없는) 버튼 — 툴바 아이콘/네비 -->
<Style x:Key="Subtle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource B.Muted}" />
</Style>
<!-- ===== 텍스트박스 ===== -->
<!-- Framer 식 입력칩: 채움만(평소 테두리 없음)·라운드8·높이30·세로 가운데 -->
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="BorderBrush" Value="{DynamicResource B.InputBorder}" />
<Setter Property="Background" Value="{DynamicResource B.Input}" />
<Setter Property="Padding" Value="4,0" />
<Setter Property="MinHeight" Value="30" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="CaretBrush" Value="{DynamicResource B.Accent}" />
<Setter Property="SelectionBrush" Value="{DynamicResource B.Accent}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" CornerRadius="8" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Margin="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Line2}" />
</Trigger>
<!-- 포커스는 호버와 같은 색이면 안 된다 — 어디에 입력되는지가 유일한 단서인데
B.Line2 는 입력칩 배경과 1.3~1.4:1 이라 포커스 위치를 알 수 없었다 -->
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Accent}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!--
여러 줄 입력은 위에서부터 흘러야 한다. 종전에는 템플릿 트리거가 ScrollViewer 의
VerticalContentAlignment 만 Stretch 로 바꿨는데, 텍스트를 배치하는 것은 TextBox 자신의
VerticalContentAlignment 이라 아무 효과가 없었다 — 쿼리 편집기에서 SQL 이 큰 상자
한가운데 떠 있었다(dialog-shots 진단으로 확인).
-->
<Trigger Property="AcceptsReturn" Value="True">
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="Padding" Value="6,5" />
</Trigger>
</Style.Triggers>
</Style>
<!-- Framer 식 슬라이더(불투명도 등): 얇은 트랙 + 흰 원형 썸 -->
<Style TargetType="Slider">
<Setter Property="MinHeight" Value="20" />
<Setter Property="IsMoveToPointEnabled" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid VerticalAlignment="Center">
<Border Height="4" CornerRadius="2" Background="{DynamicResource B.Chip}" VerticalAlignment="Center" />
<Track x:Name="PART_Track">
<Track.DecreaseRepeatButton>
<RepeatButton Command="Slider.DecreaseLarge" Focusable="False">
<RepeatButton.Template>
<ControlTemplate TargetType="RepeatButton">
<Border Height="4" CornerRadius="2" Background="{DynamicResource B.Accent}" VerticalAlignment="Center" />
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="Slider.IncreaseLarge" Focusable="False">
<RepeatButton.Template>
<ControlTemplate TargetType="RepeatButton"><Border Background="Transparent" /></ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb>
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Ellipse Width="13" Height="13" Fill="White" Stroke="{DynamicResource B.SliderRing}" StrokeThickness="1" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 리스트 ===== -->
<Style TargetType="ListBox">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
</Style>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Padding" Value="6,5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="bd" Background="Transparent" CornerRadius="5" Padding="{TemplateBinding Padding}" Margin="2,1">
<!-- string Content 가 앱 라이트 TextBlock 스타일(어두운색)로 떨어지지 않게 밝은색 지역 지정(ComboBoxItem 과 동일 패턴) -->
<ContentPresenter TextElement.Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter.Resources>
<Style TargetType="TextBlock"><Setter Property="Foreground" Value="{DynamicResource B.Ink}" /></Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Sel}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- =====================================================================
ListView / GridView — 반드시 필요하다.
ListView·ListViewItem·GridViewColumnHeader 는 각자 DefaultStyleKey 를 자기 타입으로
재정의하므로 위의 ListBox·ListBoxItem 암시 스타일을 <b>물려받지 못한다</b>. 스타일이 없으면
WPF 기본(Aero2)의 흰 시스템 크롬으로 떨어지는데, 그 안의 글자는 앱 전역 암시 TextBlock
스타일(B.Ink)을 받는다 → 다크에서 흰 바탕에 흰 글자(1.0~1.2:1)로 목록이 통째로 사라진다.
실제 피해 화면: DB에서 서식 열기, 서식 수정이력.
===================================================================== -->
<Style TargetType="ListView" BasedOn="{StaticResource {x:Type ListBox}}" />
<!--
행 템플릿은 반드시 GridViewRowPresenter 를 써야 한다.
ListBoxItem 스타일을 그대로 물려주면(BasedOn) 그 안의 ContentPresenter 템플릿이 GridView 의
열 구성을 대체해, 행이 열 대신 바인딩 객체의 ToString() 한 줄로 렌더된다
(SheetSummary { ShtCod = C020, Name = … } 이 그대로 노출된다).
저장소의 ListView 는 둘 다 GridView 를 쓴다(DB에서 서식 열기 · 서식 수정이력).
-->
<Style TargetType="ListViewItem">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Padding" Value="2,4" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border x:Name="bd" Background="Transparent" Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}"
VerticalAlignment="Center">
<GridViewRowPresenter.Resources>
<Style TargetType="TextBlock"><Setter Property="Foreground" Value="{DynamicResource B.Ink}" /></Style>
</GridViewRowPresenter.Resources>
</GridViewRowPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Sel}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="GridViewColumnHeader">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Padding" Value="8,5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewColumnHeader">
<Border x:Name="bd" Background="{DynamicResource B.PanelHeader}"
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,1,1">
<ContentPresenter Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="Center">
<ContentPresenter.Resources>
<Style TargetType="TextBlock"><Setter Property="Foreground" Value="{DynamicResource B.Muted}" /></Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- =====================================================================
ToolBar / ToolBarTray — 같은 이유. 스타일이 없으면 다크 창 위에 WPF 기본 밝은 회색 띠가
그대로 박히고, 그 안의 글자는 B.Ink 라 배율 표시 등이 사라진다(미리보기 창).
===================================================================== -->
<Style TargetType="ToolBarTray">
<Setter Property="Background" Value="{DynamicResource B.PanelHeader}" />
</Style>
<Style TargetType="ToolBar">
<Setter Property="Background" Value="{DynamicResource B.PanelHeader}" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolBar">
<Border Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,0,1" Padding="6,4">
<ToolBarPanel IsItemsHost="True" Orientation="Horizontal" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- =====================================================================
ToolTip — 저장소 48곳에서 쓰는데 스타일이 없었다.
스타일이 없으면 Aero2 기본 밝은 팝업으로 떨어지고, 내부 문자열이 만든 TextBlock 은
앱 전역 암시 스타일(B.Ink)을 받아 **다크에서 1.15:1 로 글자가 사라진다**.
(ListView·Window 와 정확히 같은 부류의 결함이다.)
===================================================================== -->
<Style TargetType="ToolTip">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Background" Value="{DynamicResource B.Surface}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.Line2}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12" />
<Setter Property="MaxWidth" Value="420" />
<Setter Property="HasDropShadow" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" CornerRadius="6" Padding="9,6" SnapsToDevicePixels="True">
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--
ToolBar 는 직계 자식에 SetResourceReference 로 자기 키 스타일을 꽂아 암시 Button 스타일을
이긴다 — 이 키들을 채워주지 않으면 툴바 안 버튼만 Aero2 로 남는다(미리보기 창).
-->
<Style x:Key="{x:Static ToolBar.ButtonStyleKey}" TargetType="Button" BasedOn="{StaticResource Subtle}" />
<Style x:Key="{x:Static ToolBar.ToggleButtonStyleKey}" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}" />
<Style x:Key="{x:Static ToolBar.SeparatorStyleKey}" TargetType="Separator" BasedOn="{StaticResource {x:Type Separator}}" />
<Style x:Key="{x:Static ToolBar.TextBoxStyleKey}" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}" />
<!--
키보드 포커스 표시. Aero2 기본은 검정 점선이라 다크 버튼 채움(#262626) 위에서 1.39:1 이고,
커스텀 Button 템플릿에 IsKeyboardFocused 트리거도 없어 Tab 위치를 알 단서가 전혀 없었다.
-->
<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="-2" StrokeThickness="1.4" RadiusX="6" RadiusY="6"
Stroke="{DynamicResource B.Accent}" StrokeDashArray="2 2" SnapsToDevicePixels="True" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 콤보박스 ===== -->
<Style x:Key="B.ComboItem" TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Padding" Value="8,5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="bd" Background="Transparent" CornerRadius="4" Padding="{TemplateBinding Padding}" Margin="2,1">
<!-- 생성되는 글자 TextBlock 이 앱 라이트 TextBlock 스타일(어두운색)로 떨어지지 않게, 여기서 밝은색 스타일을 지역 지정 -->
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="TextBlock"><Setter Property="Foreground" Value="{DynamicResource B.Ink}" /></Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Sel}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 전역 암시 콤보 항목(드롭다운 밖 용도 대비) — 키 스타일 상속 -->
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource B.ComboItem}" />
<Style TargetType="ComboBox">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Background" Value="{DynamicResource B.Input}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.Line}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Height" Value="30" />
<!-- 드롭다운 항목 스타일을 컨테이너에 직접 지정(생성기가 적용 → 앱 라이트 ComboBoxItem 누수보다 우선) -->
<Setter Property="ItemContainerStyle" Value="{StaticResource B.ComboItem}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Focusable="False" ClickMode="Press"
IsChecked="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="bd" Background="{DynamicResource B.Input}" BorderBrush="{DynamicResource B.InputBorder}"
BorderThickness="1" CornerRadius="8" SnapsToDevicePixels="True">
<Path x:Name="arr" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,9,0"
Data="M0,0 L4,4 L8,0" Stroke="{DynamicResource B.Muted}" StrokeThickness="1.4"
StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Line2}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ContentPresenter x:Name="cp" Margin="9,0,26,0" VerticalAlignment="Center" HorizontalAlignment="Left"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
TextElement.Foreground="{DynamicResource B.Ink}"
IsHitTestVisible="False">
<!-- 닫힌 표시 텍스트(SelectionBoxItem)가 앱 라이트 TextBlock 스타일(어두운색)로 떨어지지 않게 스코프 지정 -->
<ContentPresenter.Resources>
<Style TargetType="TextBlock"><Setter Property="Foreground" Value="{DynamicResource B.Ink}" /></Style>
</ContentPresenter.Resources>
</ContentPresenter>
<!-- 편집 가능 콤보(글꼴·형식 등)의 입력/표시 텍스트 -->
<TextBox x:Name="PART_EditableTextBox" Margin="8,0,26,0" VerticalAlignment="Center"
Foreground="{DynamicResource B.Ink}" CaretBrush="{DynamicResource B.Accent}"
Background="Transparent" Visibility="Collapsed" IsReadOnly="{TemplateBinding IsReadOnly}">
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<ScrollViewer x:Name="PART_ContentHost" Focusable="False"
HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" />
</ControlTemplate>
</TextBox.Template>
</TextBox>
<!-- HorizontalOffset(-10)+좌우 Margin(10): 그림자 여백 확보하면서 드롭다운을 콤보 좌측에 정렬 -->
<Popup IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" AllowsTransparency="True"
Focusable="False" PopupAnimation="Fade" HorizontalOffset="-10">
<Border Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line}" BorderThickness="1"
CornerRadius="5" Margin="10,3,10,12" Padding="2"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}">
<Border.Effect>
<DynamicResource ResourceKey="B.FloatShadow"/>
</Border.Effect>
<!-- 드롭다운(별도 팝업)이 앱 라이트 ComboBoxItem 으로 새지 않게, 팝업 안에 다크 항목 스타일을 지역 지정 -->
<Border.Resources>
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource B.ComboItem}" />
</Border.Resources>
<ScrollViewer MaxHeight="260"><ItemsPresenter /></ScrollViewer>
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEditable" Value="True">
<Setter TargetName="cp" Property="Visibility" Value="Collapsed" />
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
<!-- ===== 탭 (좌측 패널) ===== -->
<Style TargetType="TabControl">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabControl">
<DockPanel>
<!-- 세그먼트(알약) 탭 바 — FlutterFlow 식: 둥근 컨테이너 안에 알약 탭 -->
<Border DockPanel.Dock="Top" Background="{DynamicResource B.Panel}" BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,0,1" Padding="8">
<Border Background="{DynamicResource B.Chip}" CornerRadius="9" Padding="3">
<UniformGrid Rows="1" IsItemsHost="True" />
</Border>
</Border>
<ContentPresenter ContentSource="SelectedContent" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TabItem">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border x:Name="bd" Background="Transparent" CornerRadius="6" Margin="2,0" Padding="6,6">
<ContentPresenter ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center"
TextElement.Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.TabHover}" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.TabSel}" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 문서 탭 (중앙 상단 — 크롬식: 라운드 상단, 활성=Surface+테두리) ===== -->
<Style x:Key="DocTabs" TargetType="TabControl">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabControl">
<DockPanel>
<Border DockPanel.Dock="Top" Background="{DynamicResource B.Titlebar}"
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,0,1" Padding="8,5,8,0">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
<StackPanel Orientation="Horizontal" IsItemsHost="True" />
<!-- 새 서식 탭(+) — 탭 흐름 바로 옆([200] 문서탭 관행) -->
<Button Content="" Command="{Binding NewFileCommand}" Style="{StaticResource Subtle}"
Width="26" Height="24" Padding="0" Margin="2,0,0,3" FontSize="13"
VerticalAlignment="Center" ToolTip="새 서식 탭"/>
</StackPanel>
</ScrollViewer>
</Border>
<ContentPresenter ContentSource="SelectedContent" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DocTabItem" TargetType="TabItem">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<!-- 비활성 탭은 사면 테두리, 활성 탭만 하단을 끊어 본문과 이어지게 한다(크롬식 룩) -->
<Border x:Name="bd" CornerRadius="6,6,0,0" Padding="11,5,6,6" Margin="0,0,3,0"
Background="Transparent" BorderBrush="Transparent" BorderThickness="1"
SnapsToDevicePixels="True">
<ContentPresenter ContentSource="Header" VerticalAlignment="Center"
TextElement.Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.TabHover}" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Surface}" />
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Line}" />
<Setter TargetName="bd" Property="BorderThickness" Value="1,1,1,0" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontWeight" Value="SemiBold" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 좌측 탭 헤더 텍스트 — 미선택=Muted, 선택=Ink+Bold(알약 위 밝은 글씨). 템플릿 색 상속 불안정 우회 -->
<Style x:Key="TabHeaderText" TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}" />
<Setter Property="FontSize" Value="12" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
<!-- ===== 토글 버튼 ===== -->
<Style TargetType="ToggleButton">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="6,4" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" CornerRadius="5" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=ButtonBase}}" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Sel}" />
<Setter Property="Foreground" Value="{DynamicResource B.Accent}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="bd" Property="Opacity" Value="0.45" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 플로팅 바 도구 토글(선택/손) — [200] 은 켜짐을 B.Accent2 로 은은하게 채운다.
암시 ToggleButton 스타일(위)은 인스펙터·레이어 토글도 함께 쓰므로 손대지 않고 키 스타일로 분리한다. -->
<Style x:Key="BarToolToggle" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Style.Triggers>
<!-- '켜짐'을 채움색 하나로만 알리면 안 된다 — 바 배경 대비 1.14~1.19:1 이라 어느 도구가
활성인지 읽히지 않았다. 강조 테두리를 함께 얹어 채움이 옅어도 상태가 드러나게 한다. -->
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="{DynamicResource B.Accent2}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.Accent}" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
</Trigger>
</Style.Triggers>
</Style>
<!-- 레이어 행의 눈·자물쇠 같은 소형 토글 — 꺼짐은 흐리게, 켜짐만 강조색 -->
<Style x:Key="MiniToggle" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="22" />
<Setter Property="Padding" Value="0" />
<!-- 0.55 는 이미 옅은 B.Muted 를 또 반으로 깎아 라이트 2.22:1 이 된다(아이콘 기준 3:1 미달) -->
<Setter Property="Opacity" Value="0.75" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Opacity" Value="1" />
<Setter Property="Foreground" Value="{DynamicResource B.Accent}" />
</Trigger>
</Style.Triggers>
</Style>
<!--
접기/펼치기 셰브론 — 켜짐(=펼침)이 기본 상태라 IsChecked 채움이 들어가면 항상 눌린 것처럼 보인다.
방향이 이미 상태를 말해 주므로 채움은 빼고 호버 반응만 남긴다.
-->
<Style x:Key="MiniChevron" TargetType="ToggleButton" BasedOn="{StaticResource MiniToggle}">
<Setter Property="Opacity" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="bd" Background="Transparent" CornerRadius="5" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 체크박스 ===== -->
<Style TargetType="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<StackPanel Orientation="Horizontal" Background="Transparent">
<Border x:Name="box" Width="17" Height="17" CornerRadius="4" BorderThickness="1.3"
BorderBrush="{DynamicResource B.Line2}" Background="{DynamicResource B.Input}" VerticalAlignment="Center" SnapsToDevicePixels="True">
<Path x:Name="chk" Data="M 3.5 8 L 7 11 L 13 4.5" Stroke="{DynamicResource B.OnAccent}" StrokeThickness="2"
StrokeStartLineCap="Round" StrokeEndLineCap="Round" Visibility="Collapsed" />
</Border>
<ContentPresenter Margin="7,0,0,0" VerticalAlignment="Center"
TextElement.Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="box" Property="Background" Value="{DynamicResource B.Accent}" />
<Setter TargetName="box" Property="BorderBrush" Value="{DynamicResource B.Accent}" />
<Setter TargetName="chk" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="box" Property="BorderBrush" Value="{DynamicResource B.Accent}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 익스팬더 (인스펙터 섹션) ===== -->
<Style TargetType="Expander">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<DockPanel Background="Transparent">
<ToggleButton DockPanel.Dock="Top" Focusable="False" Cursor="Hand"
Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}"
IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="hb" Background="Transparent" CornerRadius="5" Padding="2,6">
<StackPanel Orientation="Horizontal">
<Path x:Name="arrow" Data="M 0 0 L 4 4 L 8 0" Stroke="{DynamicResource B.Muted}" StrokeThickness="1.6"
Margin="2,1,8,0" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform><RotateTransform Angle="-90" /></Path.RenderTransform>
</Path>
<ContentPresenter VerticalAlignment="Center" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="arrow" Property="RenderTransform">
<Setter.Value><RotateTransform Angle="0" /></Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="hb" Property="Background" Value="{DynamicResource B.Hover}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ContentPresenter x:Name="content" DockPanel.Dock="Bottom" Visibility="Collapsed" Margin="8,2,2,10" />
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="content" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 카드 / 패널헤더 / 칩 ===== -->
<Style x:Key="Card" TargetType="Border">
<Setter Property="Background" Value="{DynamicResource B.Surface}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.Line}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="12" />
</Style>
<Style x:Key="PanelHeader" TargetType="Border">
<Setter Property="Background" Value="{DynamicResource B.Surface}" />
<Setter Property="BorderBrush" Value="{DynamicResource B.Line}" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="Padding" Value="10,7" />
</Style>
<Style x:Key="Chip" TargetType="Border">
<Setter Property="Background" Value="{DynamicResource B.Chip}" />
<Setter Property="CornerRadius" Value="20" />
<Setter Property="Padding" Value="9,2" />
</Style>
<!-- ===== 메뉴 (타이틀바) ===== -->
<Style TargetType="Menu">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
</Style>
<Style TargetType="Separator">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Separator">
<Border Height="1" Background="{DynamicResource B.Line}" Margin="8,4" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="MenuItem">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Padding" Value="10,6" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Grid TextElement.Foreground="{DynamicResource B.Ink}">
<Border x:Name="bd" Background="Transparent" CornerRadius="4" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" x:Name="icon" ContentSource="Icon" Margin="0,0,8,0" VerticalAlignment="Center" />
<ContentPresenter Grid.Column="1" ContentSource="Header" VerticalAlignment="Center" RecognizesAccessKey="True" />
<TextBlock Grid.Column="2" x:Name="gesture" Text="{TemplateBinding InputGestureText}" Foreground="{DynamicResource B.Muted}"
Margin="20,0,0,0" VerticalAlignment="Center" />
<Path Grid.Column="2" x:Name="sub" Visibility="Collapsed" Data="M0,0 L4,4 L0,8"
Stroke="{DynamicResource B.Muted}" StrokeThickness="1.4" Margin="14,0,0,0" VerticalAlignment="Center" />
</Grid>
</Border>
<Popup x:Name="pop" Placement="Bottom" IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True"
Focusable="False" PopupAnimation="Fade">
<Border Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line}" BorderThickness="1"
CornerRadius="6" Padding="4" Margin="0,3,0,0">
<StackPanel IsItemsHost="True" />
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Role" Value="SubmenuHeader">
<Setter TargetName="pop" Property="Placement" Value="Right" />
<Setter TargetName="sub" Property="Visibility" Value="Visible" />
</Trigger>
<!-- 최상위 메뉴(파일/편집…)는 아이콘·단축키 칸을 접어 폭을 좁힘 -->
<Trigger Property="Role" Value="TopLevelHeader">
<Setter TargetName="icon" Property="Visibility" Value="Collapsed" />
<Setter TargetName="gesture" Property="Visibility" Value="Collapsed" />
</Trigger>
<!-- 키보드로 메뉴를 훑을 때 현재 위치를 알려주는 유일한 표시라 호버용 옅은 채움으로는
부족하다(양 테마 1.1:1). 선택 채움과 같은 강도로 올린다. -->
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Sel}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.4" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 우클릭 컨텍스트 메뉴 (다크 컨테이너) — 캔버스 우클릭 메뉴가 기본 라이트 팝업으로 안 깨지게 ===== -->
<Style TargetType="ContextMenu">
<Setter Property="Foreground" Value="{DynamicResource B.Ink}" />
<Setter Property="FontFamily" Value="Malgun Gothic" />
<Setter Property="FontSize" Value="12.5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line}" BorderThickness="1"
CornerRadius="6" Padding="4" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 창 캡션 버튼 (최소화/최대화/닫기) ===== -->
<Style x:Key="CaptionBtn" TargetType="Button">
<Setter Property="Width" Value="46" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource B.CaptionFg}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
<Setter Property="FontSize" Value="10" />
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
TextElement.FontFamily="{Binding FontFamily, RelativeSource={RelativeSource TemplatedParent}}"
TextElement.FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}"
TextElement.Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}">
<!-- Content 가 <TextBlock> 요소면 그 자신의 암시 스타일(B.Ink)이 위의
TextElement.Foreground 상속을 이긴다 — B.CaptionFg/Hover/CloseHover 4종이
통째로 죽은 코드가 된다. 지역 암시 스타일로 되돌려 잡는다. -->
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource B.CaptionHover}" />
<Setter Property="Foreground" Value="{DynamicResource B.CaptionFgHover}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="CloseBtn" TargetType="Button" BasedOn="{StaticResource CaptionBtn}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource B.CloseHover}" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
<!-- ===== 컬럼 스플리터 (사이드바 너비 드래그 조절) ===== -->
<Style x:Key="ColSplitter" TargetType="GridSplitter">
<Setter Property="Width" Value="5" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="ResizeBehavior" Value="PreviousAndNext" />
<Setter Property="ResizeDirection" Value="Columns" />
<Setter Property="Background" Value="{DynamicResource B.Line}" />
<Setter Property="Cursor" Value="SizeWE" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridSplitter">
<Border x:Name="bd" Background="{TemplateBinding Background}" SnapsToDevicePixels="True" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Accent}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 행 스플리터 (팔레트 ↔ 레이어 높이 조절) ===== -->
<Style x:Key="RowSplitter" TargetType="GridSplitter">
<Setter Property="Height" Value="6" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="ResizeBehavior" Value="PreviousAndNext" />
<Setter Property="ResizeDirection" Value="Rows" />
<Setter Property="Background" Value="{DynamicResource B.Line}" />
<Setter Property="Cursor" Value="SizeNS" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridSplitter">
<Border x:Name="bd" Background="{TemplateBinding Background}" SnapsToDevicePixels="True" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Accent}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ===== 스크롤바 ([200] 통일 규격 이식) =====
9px 폭 + 상하 14px 화살표 + 둥근 막대. 전 ScrollViewer/ListBox/캔버스/팝업에 암시 적용된다.
막대 색은 토큰이 아니라 리터럴 중립 그레이다 — 다크·라이트 양쪽에서 같은 회색으로 보여야
스크롤바가 배경에 따라 튀지 않는다([200] 과 동일한 의도적 선택).
막대 최소 길이는 MinThumbTrack 이 보장한다. 기본 WPF Track 은 Thumb.MinHeight 를 무시해
항목이 많은 목록에서 막대가 실처럼 가늘어진다. -->
<SolidColorBrush x:Key="ScrollBtnHover" Color="#22808080" />
<Style x:Key="ScrollThumb" TargetType="Thumb">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MinHeight" Value="24" />
<Setter Property="MinWidth" Value="24" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border x:Name="t" CornerRadius="5" Background="{DynamicResource B.ScrollThumb}" Margin="2" SnapsToDevicePixels="True" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True"><Setter TargetName="t" Property="Background" Value="{DynamicResource B.ScrollThumbHover}" /></Trigger>
<Trigger Property="IsDragging" Value="True"><Setter TargetName="t" Property="Background" Value="{DynamicResource B.ScrollThumbDrag}" /></Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollLineBtn" TargetType="RepeatButton">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Focusable" Value="False" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border x:Name="b" Background="Transparent" CornerRadius="3" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True"><Setter TargetName="b" Property="Background" Value="{StaticResource ScrollBtnHover}" /></Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollPageBtn" TargetType="RepeatButton">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Focusable" Value="False" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton"><Border Background="Transparent" /></ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="VScrollBar" TargetType="ScrollBar">
<Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid.RowDefinitions>
<RowDefinition Height="14" />
<RowDefinition Height="*" />
<RowDefinition Height="14" />
</Grid.RowDefinitions>
<RepeatButton Grid.Row="0" Style="{StaticResource ScrollLineBtn}" Command="ScrollBar.LineUpCommand">
<Path Stretch="None" Data="M1,5 L4.5,1.5 L8,5" Stroke="{DynamicResource B.ScrollThumb}"
StrokeThickness="1.4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" />
</RepeatButton>
<ctl:MinThumbTrack x:Name="PART_Track" MinThumbLength="44" Grid.Row="1" Orientation="Vertical"
Minimum="{TemplateBinding Minimum}" Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Value}" ViewportSize="{TemplateBinding ViewportSize}">
<ctl:MinThumbTrack.DecreaseRepeatButton><RepeatButton Style="{StaticResource ScrollPageBtn}" Command="ScrollBar.PageUpCommand" /></ctl:MinThumbTrack.DecreaseRepeatButton>
<ctl:MinThumbTrack.Thumb><Thumb Style="{StaticResource ScrollThumb}" /></ctl:MinThumbTrack.Thumb>
<ctl:MinThumbTrack.IncreaseRepeatButton><RepeatButton Style="{StaticResource ScrollPageBtn}" Command="ScrollBar.PageDownCommand" /></ctl:MinThumbTrack.IncreaseRepeatButton>
</ctl:MinThumbTrack>
<RepeatButton Grid.Row="2" Style="{StaticResource ScrollLineBtn}" Command="ScrollBar.LineDownCommand">
<Path Stretch="None" Data="M1,1.5 L4.5,5 L8,1.5" Stroke="{DynamicResource B.ScrollThumb}"
StrokeThickness="1.4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" />
</RepeatButton>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="HScrollBar" TargetType="ScrollBar">
<Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="14" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="14" />
</Grid.ColumnDefinitions>
<RepeatButton Grid.Column="0" Style="{StaticResource ScrollLineBtn}" Command="ScrollBar.LineLeftCommand">
<Path Stretch="None" Data="M5,1 L1.5,4.5 L5,8" Stroke="{DynamicResource B.ScrollThumb}"
StrokeThickness="1.4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" />
</RepeatButton>
<ctl:MinThumbTrack x:Name="PART_Track" MinThumbLength="44" Grid.Column="1" Orientation="Horizontal"
Minimum="{TemplateBinding Minimum}" Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Value}" ViewportSize="{TemplateBinding ViewportSize}">
<ctl:MinThumbTrack.DecreaseRepeatButton><RepeatButton Style="{StaticResource ScrollPageBtn}" Command="ScrollBar.PageLeftCommand" /></ctl:MinThumbTrack.DecreaseRepeatButton>
<ctl:MinThumbTrack.Thumb><Thumb Style="{StaticResource ScrollThumb}" /></ctl:MinThumbTrack.Thumb>
<ctl:MinThumbTrack.IncreaseRepeatButton><RepeatButton Style="{StaticResource ScrollPageBtn}" Command="ScrollBar.PageRightCommand" /></ctl:MinThumbTrack.IncreaseRepeatButton>
</ctl:MinThumbTrack>
<RepeatButton Grid.Column="2" Style="{StaticResource ScrollLineBtn}" Command="ScrollBar.LineRightCommand">
<Path Stretch="None" Data="M1,1 L4.5,4.5 L1,8" Stroke="{DynamicResource B.ScrollThumb}"
StrokeThickness="1.4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" />
</RepeatButton>
</Grid>
</ControlTemplate>
<Style TargetType="ScrollBar">
<Setter Property="Background" Value="Transparent" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Width" Value="9" />
<Setter Property="MinWidth" Value="9" />
<Setter Property="Template" Value="{StaticResource VScrollBar}" />
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Width" Value="Auto" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="Height" Value="9" />
<Setter Property="MinHeight" Value="9" />
<Setter Property="Template" Value="{StaticResource HScrollBar}" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>