Files
SheetMe/src/SheetMe.Designer/Views/MainView.xaml
T
MsystechandClaude Opus 5 4150ebe1d7 메인 화면을 게이트에 넣고, 최소 크기를 단일 출처로, 창 크기를 기억한다
재설계 1단계 계속.

<b>메인 셸이 게이트에 아예 없었다.</b> 사용자가 하루 종일 보는 화면만 자동 검증 밖이었다.
넣고 나서 글자 31개만 검사되는 것을 보고 빈 껍데기를 찍고 있다는 것을 알았다 —
컨트롤을 놓고 하나를 골라 인스펙터·레이어를 채우니 81~95개가 된다.
세 크기·탭으로 찍는다: 기본 1440x920, 현장 최대화 1920x1032, 도구 상자 탭.
Loaded 커맨드(서식 목록 DB 조회)는 진단 모드에서 돌지 않게 막았다 —
게이트 결과가 접속 상태에 따라 달라지면 안 된다.

<b>게이트가 게이트의 오류를 잡았다.</b> 메인 화면을 넣자 세로잘림 30건이 떴는데 전부 오탐이었다.
DesiredSize 는 Margin 을 포함하고 RenderSize 는 포함하지 않아서, 세로 Margin 이 있는
TextBlock 이 예외 없이 걸린 것이다(도구 상자 그룹 머리가 "필요 27 > 실제 14" 였고 그 13 이 Margin).
Margin 을 빼고 비교하도록 고쳤다. 이 검사기에서 측정이 나를 정정한 세 번째다.

<b>--maxrect 가 최소 크기를 베껴 두고 있었다.</b> ProbeMinWidth=940 / ProbeMinHeight=640 /
ProbeBorder=6 은 MainView.xaml 의 복사본이라, 최소 크기를 바꾸면 이 검사가
<b>옛 값을 계속 검사하며 계속 통과한다</b>. 실제 MainView 를 만들어 XAML 이 정한 값을 읽는다.

<b>창 크기·위치·상태·두 패널 폭을 기억한다.</b> UserPrefs 가 Dictionary&lt;string,bool&gt; 이라
숫자를 못 담던 것이 원인이었다. JsonElement 로 바꿔 이미 깔린 prefs.json 이 살아남게 했다 —
string 이나 double 로 바꾸면 역직렬화가 터져 기존 취향이 통째로 초기화된다.

복원값은 반드시 클램프한다. 이 앱은 WindowStyle=None 이라 제목 표시줄을 직접 그리므로,
저장된 위치가 지금 화면에 없으면(회사에서 두 번째 모니터, 집에서 노트북) 메뉴·저장·닫기가
전부 손에 닿지 않고 마우스로 되돌릴 방법이 없다.
기본 크기로는 이 문제가 안 나지만, 저장을 시작하는 순간 복원되는 것은 사용자가 만든 값이다.
닫기를 물렀을 때는 저장하지 않는다 — 조작하지 않은 값이 남는다.

게이트: 테스트 277/277, --dialog-shots 대조군 4/4 · 글자 2,465개 검사 · 넘침 0건,
--maxrect 0실패(MainView 실측 940x640 테두리 6), --cleartype 11/11,
--edit-smoke 0실패, --modal-check 0실패, 빌드 경고 0,
--db-smoke 1271건 diff 0, --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 동일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 16:50:24 +09:00

751 lines
59 KiB
XML

<Window x:Class="SheetMe.Designer.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
xmlns:vm="clr-namespace:SheetMe.Designer.ViewModels"
xmlns:v="clr-namespace:SheetMe.Designer.Views"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:bh="clr-namespace:SheetMe.Designer.Behaviors"
xmlns:ctl="clr-namespace:SheetMe.Designer.Controls"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance vm:MainViewModel}"
Title="{Binding Title}"
Icon="pack://application:,,,/SheetMe.Designer;component/Assets/sheetme.ico"
Width="1440" Height="920" MinWidth="940" MinHeight="640"
WindowStyle="None" WindowStartupLocation="CenterScreen"
Background="{DynamicResource B.AppBg}" FontFamily="Malgun Gothic" FontSize="13"
Loaded="OnWindowLoaded" StateChanged="OnWindowStateChanged" Closing="OnWindowClosing"
Style="{StaticResource ThemedWindow}">
<!--
파일/앱 계열만 창 단위로 바인딩한다. 편집 계열(Ctrl+Z/C/V/X/D/A/G)은 CanvasKeyboardBehavior 가
처리하며, 여기 올리면 인스펙터·검색 상자 등 TextBox 의 표준 편집 키와 충돌한다.
-->
<Window.InputBindings>
<KeyBinding Key="N" Modifiers="Control" Command="{Binding NewFileCommand}"/>
<KeyBinding Key="O" Modifiers="Control" Command="{Binding OpenFileCommand}"/>
<KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveFileCommand}"/>
<KeyBinding Key="S" Modifiers="Control+Shift" Command="{Binding SaveAsFileCommand}"/>
<KeyBinding Key="P" Modifiers="Control" Command="{Binding PrintCommand}"/>
<KeyBinding Key="W" Modifiers="Control" Command="{Binding CloseDocumentCommand}"/>
</Window.InputBindings>
<!-- GlassFrameThickness 0,0,0,1: DWM 창 그림자 활성화([200]SheetMe 크롬과 동일) -->
<shell:WindowChrome.WindowChrome>
<shell:WindowChrome CaptionHeight="40" ResizeBorderThickness="6" GlassFrameThickness="0,0,0,1"
CornerRadius="0" UseAeroCaptionButtons="False"/>
</shell:WindowChrome.WindowChrome>
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<ctl:TypeToIconConverter x:Key="TypeToIcon"/>
<ctl:TypeToCategoryConverter x:Key="TypeToCategory"/>
<ctl:IconNameToVisualConverter x:Key="IconName"/>
<ctl:IconSpecConverter x:Key="IconSpec"/>
<ctl:InverseBoolConverter x:Key="InverseBool"/>
<BooleanToVisibilityConverter x:Key="BoolToVisibility"/>
<vm:SheetClassToGroupConverter x:Key="SheetClassToGroup"/>
<!--
서식 목록 — 분류(E_ShtMst.ShtClsCod) 그룹 뷰.
SortDescriptions 를 두지 않는 것이 의도다: 그룹 순서는 SQL 의 ORDER BY(분류코드 A~X, 미분류 뒤)가
정하고 CollectionView 는 등장 순서대로 그룹을 만든다. 여기서 다시 정렬하면 그 의도가 덮인다.
-->
<CollectionViewSource x:Key="SheetsGrouped" Source="{Binding SheetList}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="ClassCode" Converter="{StaticResource SheetClassToGroup}"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<!-- 팔레트(도구 상자/플라이아웃 공용) — 카테고리 그룹 뷰 -->
<CollectionViewSource x:Key="PaletteGrouped" Source="{Binding PaletteItems}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Type" Converter="{StaticResource TypeToCategory}"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<!-- 도구 상자 타일 카드([200] 컴포넌트 카드 룩) — 선택 하이라이트 없음 -->
<Style x:Key="PaletteTile" TargetType="ListBoxItem">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="bd" Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line}"
BorderThickness="1" CornerRadius="5" Margin="3" SnapsToDevicePixels="True">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}"/>
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Line2}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 팔레트 카테고리 그룹 헤더 -->
<Style x:Key="PaletteGroupHeader" TargetType="TextBlock">
<Setter Property="FontSize" Value="10.5"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
<Setter Property="Margin" Value="5,9,0,4"/>
</Style>
<!-- 플라이아웃/줌 팝업 행 버튼 — 왼정렬 hover 행 -->
<Style x:Key="FlyoutRow" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{DynamicResource B.Ink}"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="12,7"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" Background="{TemplateBinding Background}" CornerRadius="6"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
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>
</Window.Resources>
<DockPanel>
<!-- ===== 커스텀 타이틀바: 로고 + 메뉴 | 중앙 제목 | 창 제어 ===== -->
<Border DockPanel.Dock="Top" Background="{DynamicResource B.Titlebar}" Height="40"
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,0,1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- 좌: 로고 메뉴 루트 + 편집 아이콘 스트립 ([200] 타이틀바 구성) -->
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="8,0,0,0"
shell:WindowChrome.IsHitTestVisibleInChrome="True">
<!-- 5개 텍스트 메뉴를 로고 하나 아래로 접어 넣는다 — 타이틀바가 아이콘 스트립 자리를 확보한다 -->
<Menu VerticalAlignment="Center">
<MenuItem>
<MenuItem.Header>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Image Source="pack://application:,,,/SheetMe.Designer;component/Assets/sheetme-logo.png"
Width="20" Height="20" VerticalAlignment="Center" RenderOptions.BitmapScalingMode="HighQuality"/>
<ContentControl Margin="3,1,0,0" VerticalAlignment="Center" IsTabStop="False"
Content="{Binding Source=chevron-down, Converter={StaticResource IconName}, ConverterParameter=11}"/>
</StackPanel>
</MenuItem.Header>
<MenuItem Header="파일(_F)">
<MenuItem Header="새 서식(_N)" Command="{Binding NewFileCommand}" InputGestureText="Ctrl+N"/>
<MenuItem Header="열기(_O)..." Command="{Binding OpenFileCommand}" InputGestureText="Ctrl+O"/>
<Separator/>
<MenuItem Header="저장(_S)" Command="{Binding SaveFileCommand}" InputGestureText="Ctrl+S"/>
<MenuItem Header="다른 이름으로 저장(_A)..." Command="{Binding SaveAsFileCommand}" InputGestureText="Ctrl+Shift+S"/>
<Separator/>
<MenuItem Header="DB에서 열기(_D)..." Command="{Binding OpenFromDbCommand}"/>
<MenuItem Header="DB에 저장(_B)..." Command="{Binding SaveToDbCommand}"/>
<Separator/>
<MenuItem Header="JSON 가져오기(_I)..." Command="{Binding ImportJsonCommand}"/>
<MenuItem Header="JSON 내보내기(_E)..." Command="{Binding ExportJsonCommand}"/>
<Separator/>
<MenuItem Header="미리보기(_V)..." Command="{Binding PreviewCommand}"/>
<MenuItem Header="인쇄(_P)..." Command="{Binding PrintCommand}" InputGestureText="Ctrl+P"/>
<Separator/>
<MenuItem Header="종료(_X)" Command="{Binding ExitCommand}"/>
</MenuItem>
<MenuItem Header="편집(_E)">
<MenuItem Header="실행 취소(_U)" Command="{Binding CurrentDesigner.UndoCommand}" InputGestureText="Ctrl+Z"/>
<MenuItem Header="다시 실행(_R)" Command="{Binding CurrentDesigner.RedoCommand}" InputGestureText="Ctrl+Y"/>
<Separator/>
<MenuItem Header="잘라내기(_T)" Command="{Binding CurrentDesigner.CutCommand}" InputGestureText="Ctrl+X"/>
<MenuItem Header="복사(_C)" Command="{Binding CurrentDesigner.CopyCommand}" InputGestureText="Ctrl+C"/>
<MenuItem Header="붙여넣기(_P)" Command="{Binding CurrentDesigner.PasteCommand}" InputGestureText="Ctrl+V"/>
<MenuItem Header="복제(_D)" Command="{Binding CurrentDesigner.DuplicateCommand}" InputGestureText="Ctrl+D"/>
<MenuItem Header="삭제(_L)" Command="{Binding CurrentDesigner.DeleteCommand}" InputGestureText="Del"/>
<Separator/>
<MenuItem Header="전체 선택(_A)" Command="{Binding CurrentDesigner.SelectAllCommand}" InputGestureText="Ctrl+A"/>
</MenuItem>
<MenuItem Header="배치(_A)">
<MenuItem Header="맨 앞으로(_F)" Command="{Binding CurrentDesigner.BringToFrontCommand}"/>
<MenuItem Header="맨 뒤로(_B)" Command="{Binding CurrentDesigner.SendToBackCommand}"/>
<Separator/>
<MenuItem Header="그룹(_G)" Command="{Binding CurrentDesigner.GroupCommand}" InputGestureText="Ctrl+G"/>
<MenuItem Header="그룹 해제(_U)" Command="{Binding CurrentDesigner.UngroupCommand}" InputGestureText="Ctrl+Shift+G"/>
<Separator/>
<!-- 기준: 선택 1개면 페이지(컨테이너 안이면 그 컨테이너), 2개 이상이면 선택 영역 -->
<MenuItem Header="왼쪽 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Left"
ToolTip="선택 1개면 페이지(또는 부모 컨테이너) 기준, 2개 이상이면 선택 영역 기준"/>
<MenuItem Header="오른쪽 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Right"
ToolTip="선택 1개면 페이지(또는 부모 컨테이너) 기준, 2개 이상이면 선택 영역 기준"/>
<MenuItem Header="위 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Top"
ToolTip="여러 페이지에 걸친 선택에서는 동작하지 않습니다"/>
<MenuItem Header="아래 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Bottom"
ToolTip="여러 페이지에 걸친 선택에서는 동작하지 않습니다"/>
<MenuItem Header="가로 가운데" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="CenterH"
ToolTip="선택 1개면 페이지(또는 부모 컨테이너) 기준, 2개 이상이면 선택 영역 기준"/>
<MenuItem Header="세로 가운데" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="CenterV"
ToolTip="여러 페이지에 걸친 선택에서는 동작하지 않습니다"/>
<Separator/>
<MenuItem Header="같은 크기로">
<MenuItem Header="너비/높이 모두(_B)" Command="{Binding CurrentDesigner.SizeToControlCommand}" CommandParameter="Both"/>
<MenuItem Header="너비(_W)" Command="{Binding CurrentDesigner.SizeToControlCommand}" CommandParameter="Width"/>
<MenuItem Header="높이(_H)" Command="{Binding CurrentDesigner.SizeToControlCommand}" CommandParameter="Height"/>
</MenuItem>
<MenuItem Header="가로 간격">
<MenuItem Header="균등(_E)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="HorizEqual"/>
<MenuItem Header="넓게(_I)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="HorizIncrease"/>
<MenuItem Header="좁게(_D)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="HorizDecrease"/>
<MenuItem Header="붙이기(_C)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="HorizConcat"/>
</MenuItem>
<MenuItem Header="세로 간격">
<MenuItem Header="균등(_E)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="VertEqual"/>
<MenuItem Header="넓게(_I)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="VertIncrease"/>
<MenuItem Header="좁게(_D)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="VertDecrease"/>
<MenuItem Header="붙이기(_C)" Command="{Binding CurrentDesigner.SpacingCommand}" CommandParameter="VertConcat"/>
</MenuItem>
<Separator/>
<MenuItem Header="페이지 가로 가운데 — 묶음째(_H)"
ToolTip="상대 배치를 유지한 채 선택 전체를 페이지 가운데로 옮깁니다" Command="{Binding CurrentDesigner.CenterInPageCommand}" CommandParameter="H"/>
<MenuItem Header="페이지 세로 가운데 — 묶음째(_V)"
ToolTip="상대 배치를 유지한 채 선택 전체를 페이지 가운데로 옮깁니다" Command="{Binding CurrentDesigner.CenterInPageCommand}" CommandParameter="V"/>
<Separator/>
<MenuItem Header="{Binding CurrentDesigner.TabOrderMenuHeader, FallbackValue=탭순서 편집 시작}"
Command="{Binding CurrentDesigner.TabOrderCommand}"
IsChecked="{Binding CurrentDesigner.IsTabOrderMode, Mode=OneWay}"
ToolTip="입력 컨트롤을 원하는 입력 순서대로 클릭한 뒤 완료 — Esc 취소"/>
</MenuItem>
<MenuItem Header="보기(_V)">
<MenuItem Header="확대(_I)" Command="{Binding ZoomInCommand}" InputGestureText="Ctrl+휠↑"/>
<MenuItem Header="축소(_O)" Command="{Binding ZoomOutCommand}" InputGestureText="Ctrl+휠↓"/>
<MenuItem Header="100%(_R)" Command="{Binding ZoomResetCommand}"/>
<Separator/>
<MenuItem x:Name="ThemeMenuItem" Header="다크 테마(_D)" IsCheckable="True" Click="OnThemeToggleClick"/>
</MenuItem>
<MenuItem Header="도구(_T)">
<MenuItem Header="서식 수정이력(_H)..." Command="{Binding SheetHistoryCommand}"/>
<Separator/>
<MenuItem Header="상용구 관리(_W)..." Command="{Binding RecordWordCommand}"/>
<MenuItem Header="폰트 일괄 변경(_F)..." Command="{Binding FontManagerCommand}"/>
</MenuItem>
</MenuItem>
</Menu>
<Border Width="1" Height="18" Background="{DynamicResource B.Line2}" Margin="6,0" VerticalAlignment="Center"/>
<!-- 편집 아이콘 스트립 — 메뉴 하위에만 있던 명령을 한 번에 닿게 -->
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0" ToolTip="실행 취소 (Ctrl+Z)"
Command="{Binding CurrentDesigner.UndoCommand}"
Content="{Binding Source=undo-2, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0" ToolTip="다시 실행 (Ctrl+Y)"
Command="{Binding CurrentDesigner.RedoCommand}"
Content="{Binding Source=redo-2, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Border Width="1" Height="18" Background="{DynamicResource B.Line2}" Margin="6,0" VerticalAlignment="Center"/>
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0" ToolTip="복사 (Ctrl+C)"
Command="{Binding CurrentDesigner.CopyCommand}"
Content="{Binding Source=copy, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0" ToolTip="삭제 (Delete)"
Command="{Binding CurrentDesigner.DeleteCommand}"
Content="{Binding Source=trash-2, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0" ToolTip="그룹 (Ctrl+G)"
Command="{Binding CurrentDesigner.GroupCommand}"
Content="{Binding Source=group, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0" ToolTip="그룹 해제 (Ctrl+Shift+G)"
Command="{Binding CurrentDesigner.UngroupCommand}"
Content="{Binding Source=ungroup, Converter={StaticResource IconName}, ConverterParameter=16}"/>
</StackPanel>
<!-- 중앙: 비움 — 서식명은 문서 탭이 이미 보여준다(Window.Title 은 작업표시줄용으로 유지) -->
<Border Grid.Column="1"/>
<!-- 우: 액션 아이콘 -->
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,8,0"
shell:WindowChrome.IsHitTestVisibleInChrome="True">
<Button Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0" ToolTip="다크/라이트 전환"
Click="OnThemeToggleClick"
Content="{Binding Source=sun, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Button Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0" ToolTip="DB에 저장"
Command="{Binding SaveToDbCommand}"
Content="{Binding Source=save, Converter={StaticResource IconName}, ConverterParameter=16}"/>
<Button Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0" ToolTip="미리보기"
Command="{Binding PreviewCommand}"
Content="{Binding Source=play, Converter={StaticResource IconName}, ConverterParameter=16|B.Accent}"/>
</StackPanel>
<!-- 우: 창 제어 -->
<StackPanel Grid.Column="3" Orientation="Horizontal" shell:WindowChrome.IsHitTestVisibleInChrome="True">
<Button Style="{StaticResource CaptionBtn}" Click="OnMinimizeClick" ToolTip="최소화">
<TextBlock Text="&#xE921;" FontFamily="Segoe MDL2 Assets" FontSize="10"/>
</Button>
<Button Style="{StaticResource CaptionBtn}" Click="OnMaxRestoreClick" ToolTip="최대화/복원">
<TextBlock x:Name="MaxGlyph" Text="&#xE922;" FontFamily="Segoe MDL2 Assets" FontSize="10"/>
</Button>
<Button Style="{StaticResource CloseBtn}" Click="OnCloseWinClick" ToolTip="닫기">
<TextBlock Text="&#xE8BB;" FontFamily="Segoe MDL2 Assets" FontSize="10"/>
</Button>
</StackPanel>
</Grid>
</Border>
<!-- ===== 하단 상태바 (줌은 플로팅 바로 이동) ===== -->
<Border DockPanel.Dock="Bottom" Background="{DynamicResource B.Titlebar}"
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,1,0,0" Padding="14,5">
<TextBlock Text="{Binding StatusText}" Foreground="{DynamicResource B.Muted}" FontSize="11.5"
TextTrimming="CharacterEllipsis"/>
</Border>
<!-- ===== 본문 3열: 좌 탭 패널 | 문서 탭+캔버스+플로팅 바 | 속성 ([200] 레이아웃) ===== -->
<Grid>
<Grid.ColumnDefinitions>
<!-- [200] 기본 폭 — 좌 248(레이어 행에 타입 아이콘 + 토글 2개가 들어가 232 로는 이름이 잘린다),
우 300(인스펙터 X|Y 쌍이 한 줄에 들어가는 최소치) -->
<ColumnDefinition x:Name="LeftColumn" Width="248" MinWidth="180" MaxWidth="480"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<!-- 최소 250 — 글꼴 스타일 행이 라벨 92 + 토글 4칸 128 = 220px 를 요구한다
(행 가용폭 = 폭 − 스크롤바 9 − 여백 20). 220 이면 마지막 토글이 잘린다. -->
<ColumnDefinition x:Name="RightColumn" Width="300" MinWidth="250" MaxWidth="560"/>
</Grid.ColumnDefinitions>
<!-- 좌: 알약 탭 — 서식 목록 / 레이어 / 도구 상자 -->
<Border Grid.Column="0" Background="{DynamicResource B.Panel}">
<TabControl x:Name="LeftTabs" SelectedIndex="{Binding SelectedLeftTabIndex, Mode=TwoWay}">
<!-- 서식 목록 -->
<TabItem>
<TabItem.Header><TextBlock Text="서식 목록" Style="{StaticResource TabHeaderText}"/></TabItem.Header>
<DockPanel>
<DockPanel DockPanel.Dock="Top" Margin="8,8,8,4">
<Button DockPanel.Dock="Right" Style="{StaticResource Subtle}" Width="30" Padding="0"
Margin="6,0,0,0" ToolTip="검색 (Enter)"
Command="{Binding SearchSheetsCommand}"
Content="{Binding Source=search, Converter={StaticResource IconName}, ConverterParameter=15}"/>
<!-- 분류 24종을 하나씩 여닫는 건 번거롭다 — 전체 여닫기 -->
<ToggleButton DockPanel.Dock="Right" Style="{StaticResource MiniToggle}" Width="26" Height="28"
Margin="4,0,0,0" ToolTip="분류 전체 펼치기 / 접기"
IsChecked="{Binding AreSheetGroupsExpanded, Mode=TwoWay}"
Content="{Binding SheetGroupToggleIcon, Converter={StaticResource IconName}, ConverterParameter=15}"/>
<!-- 자리표시자는 TextBox 위에 겹친 TextBlock — Text 가 비었을 때만 보인다 -->
<Grid>
<TextBox x:Name="SheetSearchBox"
Text="{Binding SheetSearchKeyword, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding SearchSheetsCommand}"/>
</TextBox.InputBindings>
</TextBox>
<TextBlock Text="서식명 또는 코드 검색" FontSize="12" Foreground="{DynamicResource B.Muted}"
Margin="9,0,0,0" VerticalAlignment="Center" IsHitTestVisible="False">
<TextBlock.Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=SheetSearchBox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</DockPanel>
<!-- 목록 상태 한 줄 — 로딩/결과 없음/조회 실패/건수를 같은 자리에서 보여준다 -->
<TextBlock DockPanel.Dock="Bottom" Text="{Binding SheetListStatusText}" FontSize="11"
Foreground="{DynamicResource B.Muted}" Margin="9,4,9,8" TextWrapping="Wrap"/>
<Grid>
<!--
IsVirtualizingWhenGrouping 은 반드시 켜야 한다 — 그룹핑을 걸면 WPF 는 기본적으로
가상화를 끄고 1,600여 항목을 한꺼번에 실체화한다(탭 전환이 눈에 띄게 멈춘다).
-->
<ListBox x:Name="SheetListBox" ItemsSource="{Binding Source={StaticResource SheetsGrouped}}"
Margin="4,0,4,4"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
MouseDoubleClick="OnSheetListDoubleClick"
ToolTip="분류 머리글을 눌러 펼치고, 서식을 더블클릭해 엽니다">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<StackPanel>
<!-- 그룹 키가 SheetGroupViewModel 인스턴스라 Name.IsExpanded 를 TwoWay 로 잡을 수 있다 -->
<ToggleButton IsChecked="{Binding Name.IsExpanded, Mode=TwoWay}" Cursor="Hand"
Focusable="False">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="bd" Background="Transparent" CornerRadius="5"
Padding="4,5" Margin="1,4,1,1">
<DockPanel>
<ContentControl DockPanel.Dock="Left" Margin="0,0,5,0" VerticalAlignment="Center"
IsTabStop="False" Focusable="False"
Content="{Binding Name.ChevronIcon, Converter={StaticResource IconName}, ConverterParameter=12}"/>
<!-- 검색 중이면 이 숫자는 '검색 통과분'이지 그 분류의 전체 건수가 아니다 -->
<TextBlock DockPanel.Dock="Right" Text="{Binding ItemCount}" FontSize="11"
Foreground="{DynamicResource B.Muted}" VerticalAlignment="Center"
Margin="6,0,3,0"
ToolTip="현재 목록에 표시된 건수(검색 중이면 검색 통과분)"/>
<TextBlock Text="{Binding Name.Label}" FontWeight="Bold" FontSize="11.5"
Foreground="{DynamicResource B.Muted}" VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"/>
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ItemsPresenter>
<ItemsPresenter.Style>
<Style TargetType="ItemsPresenter">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Name.IsExpanded}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsPresenter.Style>
</ItemsPresenter>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- 좌측 여백은 분류 머리글 아래 항목임을 드러내는 들여쓰기 -->
<StackPanel Orientation="Horizontal" Margin="14,1,1,1">
<TextBlock Text="{Binding ShtCod}" FontSize="11" Foreground="{DynamicResource B.Muted}"
Width="52" VerticalAlignment="Center"/>
<!-- 서식생성기 사용이 꺼진 서식(ShtUsrDesYon='N') — 열기 시 거부된다 -->
<TextBlock Text="&#xE72E;" FontFamily="Segoe MDL2 Assets" FontSize="10"
VerticalAlignment="Center" Margin="0,0,4,0"
Foreground="{DynamicResource B.Muted}"
ToolTip="기록지 정보에서 서식생성기 사용이 꺼져 있습니다">
<TextBlock.Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DesignAllowed}" Value="False">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding Name}" FontSize="12" TextTrimming="CharacterEllipsis">
<TextBlock.Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Style.Triggers>
<DataTrigger Binding="{Binding HasDesign}" Value="False">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
<Setter Property="Opacity" Value="0.6"/>
</DataTrigger>
<DataTrigger Binding="{Binding DesignAllowed}" Value="False">
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
<Setter Property="Opacity" Value="0.6"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DockPanel>
</TabItem>
<!--
레이어 — [200]SheetMe 아웃라인.
페이지를 별도 섹션으로 두지 않고 트리의 최상위 노드로 삼는다. 부수 효과가 하나 있는데
의도한 것이다: 페이지 행은 항상 무강조라 연속 선택 블록이 페이지 경계에서 저절로 끊긴다.
-->
<TabItem>
<TabItem.Header><TextBlock Text="레이어" Style="{StaticResource TabHeaderText}"/></TabItem.Header>
<DockPanel>
<v:LayerPanelView/>
</DockPanel>
</TabItem>
<!-- 도구 상자 ([200] 타일 카드 룩 — 드래그/더블클릭 배치) -->
<TabItem>
<TabItem.Header><TextBlock Text="도구 상자" Style="{StaticResource TabHeaderText}"/></TabItem.Header>
<ListBox ItemsSource="{Binding Source={StaticResource PaletteGrouped}}"
ItemContainerStyle="{StaticResource PaletteTile}"
Margin="6,4,6,6"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ToolTip="더블클릭 또는 드래그로 캔버스에 배치">
<b:Interaction.Behaviors>
<bh:PaletteDragBehavior/>
</b:Interaction.Behaviors>
<!-- 그룹 세로 나열(GroupStyle.Panel 기본) + 그룹 내 타일 2열(ItemsPanel — 그룹 내부 항목이 상속) -->
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Style="{StaticResource PaletteGroupHeader}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center" Margin="2,9,2,8" Background="Transparent">
<ContentControl Content="{Binding Type, Converter={StaticResource TypeToIcon}}"
HorizontalAlignment="Center" Margin="0,0,0,5" IsTabStop="False" Focusable="False"/>
<TextBlock Text="{Binding DisplayName}" FontSize="11" TextAlignment="Center"
HorizontalAlignment="Center" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</TabItem>
</TabControl>
</Border>
<GridSplitter Grid.Column="1" Style="{StaticResource ColSplitter}" ToolTip="좌측 패널 너비 조절"/>
<!-- 중앙: 문서 탭(크롬식) + 캔버스 + 플로팅 팔레트 바 -->
<Grid Grid.Column="2" Background="{DynamicResource B.CanvasBg}">
<TabControl Style="{StaticResource DocTabs}"
ItemsSource="{Binding OpenDesigners}"
SelectedItem="{Binding CurrentDesigner}"
ItemContainerStyle="{StaticResource DocTabItem}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- 활성 탭만 아이콘을 강조색으로 — 탭이 여러 개일 때 어디가 활성인지가 배경색 차이만으로는 약하다 -->
<ContentControl Margin="0,0,6,0" VerticalAlignment="Center" IsTabStop="False" Focusable="False">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Content"
Value="{Binding Source=file-text, Converter={StaticResource IconName}, ConverterParameter=12}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">
<Setter Property="Content"
Value="{Binding Source=file-text, Converter={StaticResource IconName}, ConverterParameter=12|B.Accent}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<TextBlock Text="{Binding DisplayName}" MaxWidth="170" Style="{StaticResource TabHeaderText}"
TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
<Button Content="✕" FontSize="11" Margin="7,0,0,0"
Style="{StaticResource Subtle}" Padding="3,0" Cursor="Hand" ToolTip="문서 닫기"
Command="{Binding DataContext.CloseDocumentCommand,
RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<v:DesignerCanvasView/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<!-- 플로팅 팔레트 바 (Figma 식 — 컨트롤 추가 플라이아웃 | 줌) -->
<Border Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line}" BorderThickness="1"
CornerRadius="12" Padding="7,5" HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="0,0,0,20">
<!-- 그림자는 토큰으로 — 라이트에서 흰 배경에 검은 그림자가 그대로 얹히던 것을 테마별로 분리.
반드시 DynamicResource — 요소 구문 <StaticResource/> 로 넣으면 로드 시점 값으로 굳어
테마를 바꿔도 다크용 진한 그림자가 그대로 남는다. -->
<Border.Effect>
<DynamicResource ResourceKey="B.FloatShadow"/>
</Border.Effect>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<ToggleButton Style="{StaticResource BarToolToggle}" Width="38" Height="34" Padding="0" Focusable="False"
ToolTip="선택 도구 — 클릭으로 선택, 드래그로 이동"
IsChecked="{Binding IsHandTool, Converter={StaticResource InverseBool}, Mode=OneWay}"
Click="OnSelectToolClick"
Content="{Binding Source=mouse-pointer-click, Converter={StaticResource IconName}, ConverterParameter=18|B.Ink}"/>
<ToggleButton Style="{StaticResource BarToolToggle}" Width="38" Height="34" Padding="0" Focusable="False"
ToolTip="손 도구 — 드래그로 화면 이동 (Space 누르는 동안 임시)"
IsChecked="{Binding IsHandTool, Mode=OneWay}"
Click="OnHandToolClick"
Content="{Binding Source=hand, Converter={StaticResource IconName}, ConverterParameter=18|B.Ink}"/>
<Border Width="1" Height="22" Background="{DynamicResource B.Line}" Margin="5,0" VerticalAlignment="Center"/>
<Button x:Name="AddControlBtn" Style="{StaticResource Subtle}" Width="38" Height="34" Padding="0"
ToolTip="컨트롤 추가 — 활성 페이지 중앙에 배치" Click="OnAddControlFlyoutClick"
Content="{Binding Source=layout-grid, Converter={StaticResource IconName}, ConverterParameter=18}"/>
<Border Width="1" Height="22" Background="{DynamicResource B.Line}" Margin="5,0" VerticalAlignment="Center"/>
<!-- ±버튼은 두지 않는다([200] 와 동일) — Ctrl+휠이 주 조작이고, 배율 버튼이 플라이아웃을 겸한다 -->
<Button x:Name="ZoomBtn" Style="{StaticResource Subtle}" Height="34" Padding="8,0,6,0" ToolTip="줌"
Click="OnZoomFlyoutClick">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{Binding CurrentDesigner.ZoomPercentText, FallbackValue=100%}"
FontSize="12" MinWidth="38" TextAlignment="Center" VerticalAlignment="Center"/>
<ContentControl Content="{Binding Source=chevron-down, Converter={StaticResource IconName}, ConverterParameter=11}"
Margin="3,1,0,0" VerticalAlignment="Center" IsTabStop="False" Focusable="False"/>
</StackPanel>
</Button>
</StackPanel>
</Border>
<!-- 컨트롤 추가 플라이아웃 (카테고리별 타일) -->
<Popup x:Name="AddControlPopup" PlacementTarget="{Binding ElementName=AddControlBtn}" Placement="Top"
StaysOpen="False" AllowsTransparency="True" PopupAnimation="Fade" VerticalOffset="-8">
<Border Margin="18" Background="{DynamicResource B.Panel}" BorderBrush="{DynamicResource B.Line}"
BorderThickness="1" CornerRadius="10" MinWidth="300">
<!-- 플라이아웃 그림자도 토큰으로 — 라이트에서 흰 배경에 진한 검정이 그대로 얹힌다 -->
<Border.Effect>
<DynamicResource ResourceKey="B.FloatShadow"/>
</Border.Effect>
<!-- 힌트는 ScrollViewer <b>안쪽</b>이어야 한다 — ScrollViewer 도 중간 서피스를 열어
바깥에 걸면 무효다(진단 cleartype 의 I/J 표본이 그 차이다). -->
<ScrollViewer MaxHeight="440" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding Source={StaticResource PaletteGrouped}}" Margin="10,9,10,10"
Background="{DynamicResource B.Panel}" RenderOptions.ClearTypeHint="Enabled">
<!-- 그룹 세로 나열 + 그룹 내 타일 4열([200] 플라이아웃 치수) -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontSize="10.5" FontWeight="Bold"
Foreground="{DynamicResource B.Muted}" Margin="2,9,0,6"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="66" Margin="3" Padding="4,9,4,8" Click="OnFlyoutTileClick"
Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line}"
ToolTip="{Binding DisplayName}">
<StackPanel HorizontalAlignment="Center">
<ContentControl Content="{Binding Type, Converter={StaticResource TypeToIcon}}"
HorizontalAlignment="Center" Margin="0,0,0,5" IsTabStop="False" Focusable="False"/>
<TextBlock Text="{Binding DisplayName}" FontSize="11" TextAlignment="Center"
HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
</Popup>
<!-- 줌 플라이아웃 -->
<Popup x:Name="ZoomPopup" PlacementTarget="{Binding ElementName=ZoomBtn}" Placement="Top"
StaysOpen="False" AllowsTransparency="True" PopupAnimation="Fade" VerticalOffset="-8">
<Border Margin="18" Background="{DynamicResource B.Panel}" BorderBrush="{DynamicResource B.Line}"
BorderThickness="1" CornerRadius="10" MinWidth="190">
<!-- 플라이아웃 그림자도 토큰으로 — 라이트에서 흰 배경에 진한 검정이 그대로 얹힌다 -->
<Border.Effect>
<DynamicResource ResourceKey="B.FloatShadow"/>
</Border.Effect>
<StackPanel Margin="5" Background="{DynamicResource B.Panel}"
RenderOptions.ClearTypeHint="Enabled">
<Button Style="{StaticResource FlyoutRow}" Command="{Binding ZoomInCommand}" Click="OnZoomRowClick">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Text="Ctrl+휠↑" Foreground="{DynamicResource B.Muted}"
FontSize="11.5" Margin="24,0,0,0" VerticalAlignment="Center"/>
<TextBlock Text="확대" FontSize="12.5" VerticalAlignment="Center"/>
</DockPanel>
</Button>
<Button Style="{StaticResource FlyoutRow}" Command="{Binding ZoomOutCommand}" Click="OnZoomRowClick">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Text="Ctrl+휠↓" Foreground="{DynamicResource B.Muted}"
FontSize="11.5" Margin="24,0,0,0" VerticalAlignment="Center"/>
<TextBlock Text="축소" FontSize="12.5" VerticalAlignment="Center"/>
</DockPanel>
</Button>
<Border Height="1" Background="{DynamicResource B.Line}" Margin="8,5"/>
<Button Style="{StaticResource FlyoutRow}" Command="{Binding ZoomResetCommand}" Click="OnZoomRowClick">
<TextBlock Text="100%" FontSize="12.5" VerticalAlignment="Center"/>
</Button>
<Button Style="{StaticResource FlyoutRow}" Command="{Binding ZoomFitCommand}" Click="OnZoomRowClick">
<TextBlock Text="화면 맞춤" FontSize="12.5" VerticalAlignment="Center"/>
</Button>
</StackPanel>
</Border>
</Popup>
<!-- 빈 상태 — 열린 문서가 없으면 회색 허공 대신 다음 행동을 제시한다.
플로팅 바보다 뒤에 두어 위에 덮인다(문서 없이 줌·컨트롤 추가는 의미가 없다). -->
<Border Background="{DynamicResource B.CanvasBg}">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding HasOpenDocuments}" Value="False">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" MaxWidth="360">
<ContentControl HorizontalAlignment="Center" IsTabStop="False" Focusable="False" Opacity="0.5"
Content="{Binding Source=file-text, Converter={StaticResource IconName}, ConverterParameter=44}"/>
<TextBlock Text="열린 서식이 없습니다" FontSize="15" FontWeight="Bold" TextAlignment="Center"
HorizontalAlignment="Center" Margin="0,16,0,6"/>
<TextBlock Foreground="{DynamicResource B.Muted}" FontSize="12.5" TextAlignment="Center"
TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0,0,0,20"
Text="새 서식을 만들거나, 왼쪽 서식 목록에서 기존 서식을 두 번 눌러 엽니다."/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="새 서식" Command="{Binding NewFileCommand}" Padding="16,7" Margin="0,0,8,0"/>
<Button Content="DB에서 열기" Command="{Binding OpenFromDbCommand}" Padding="16,7"
IsEnabled="{Binding CanUseDb}"/>
<Button Content="파일 열기" Command="{Binding OpenFileCommand}" Padding="16,7" Margin="8,0,0,0"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
<GridSplitter Grid.Column="3" Style="{StaticResource ColSplitter}" ToolTip="속성 패널 너비 조절"/>
<!-- 우: 속성 인스펙터 -->
<Border Grid.Column="4" Background="{DynamicResource B.Panel}">
<DockPanel>
<Border DockPanel.Dock="Top" Background="{DynamicResource B.PanelHeader}" Padding="11,8"
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,0,1">
<TextBlock Text="속성" FontWeight="Bold" Foreground="{DynamicResource B.Muted}"/>
</Border>
<v:InspectorView DataContext="{Binding CurrentDesigner.Inspector}"/>
</DockPanel>
</Border>
</Grid>
</DockPanel>
</Window>