Files
SheetMe/src/SheetMe.Designer/Views/MainView.xaml
T
MsystechandClaude Opus 5 76584e5004 레이어 패널을 [200]SheetMe 아웃라인으로 교체 — 페이지 노드·선택 밴드·드래그 재정렬
[200] 의 패널은 코드로 Border 를 쌓는 비가상화 렌더고 SheetMe 는 가상화 ListBox 다.
골격은 SheetMe 것을 지키고 겉모습과 조작 표면만 옮겼다 — 통째로 베끼면 1,067 컨트롤
서식에서 검색어 한 글자마다 수천 비주얼을 다시 만들게 되고, [200] 에 대응물이 없는
컨테이너 자식 재귀 표시가 사라진다.

구조
- 페이지를 별도 섹션이 아니라 아웃라인의 최상위 노드로. 접기·복제·삭제·컨트롤 수·현재 강조
- 맨 아래 '+ 페이지 추가' 행
- 목록 순서를 뒤집었다 — 이제 맨 위가 z-order 최상위(캔버스에서 위에 겹쳐 보이는 것이 목록 위)
- 들여쓰기 12 / 32 / +16
- 레이어 패널을 LayerPanelView 로 분리(MainView.xaml 이 1,000줄을 넘겼고, 진단 렌더러가
  이 패널만 따로 찍어 라이트·다크·선택 상태를 검사할 수 있어야 한다)

선택 표시
- IsSelected 가 아니라 Highlight 3상태(None/Blue/Navy)가 배경을 그린다. 그룹 전원 선택 시
  폴더는 파랑, 멤버는 서브트리 배경이 되고 맞닿는 모서리를 각지게 해 하나의 블록으로 이어진다
- 밴드 위에서는 아이콘·보조 텍스트 색도 함께 뒤집는다. 안 그러면 눈·자물쇠가 1.6:1 로 묻혀
  선택한 행에서만 잠금 상태가 안 보이는 상태가 된다
- 신설 토큰 3종(B.LayerSel / B.LayerSubtree / B.OnSelMuted) — [200] 원본값은 각각
  흰 글자 3.00:1, 다크 밴드 1.03:1, 라이트 밴드 1.14:1 로 이 저장소가 이미 기각한 값이다

기능
- 드래그로 z-order 재정렬(삽입선 어도너). 임의 index 이동 연산 MoveWithinParent 신설
- 페이지 복제 — 컨트롤 이름을 전부 새로 발급하고 그룹도 복제본끼리 다시 묶는다
  ([200] 은 GroupId 를 그대로 둬서 복제 그룹이 원본과 gid 를 공유한다)
- 페이지 헤더 클릭 → 캔버스가 그 페이지로 이동(ScrollToPage)
- 데이터 배선 배지 — 값이 조회·데이터소스에서 오는 컨트롤 표시
- 검색칩에 테두리(라이트에서 B.Input=B.Panel 이라 경계 대비가 1.00:1 이었다)

이식하지 않은 것: 컨트롤 행 인라인 개명. [200] 이 고치는 값은 표시 전용 별칭이지만
SheetMe 의 컨트롤 이름은 외부 참조 키라 목록에서 무심코 고치면 배선이 끊긴다.
더블클릭은 요청대로 캔버스 이동을 유지하고, 그룹 행에서만 이름 편집으로 간다.

동반 수정: 눈·자물쇠 토글에 되돌리기 지점 추가(400ms 코얼레스), 그룹 이름 비우기 경로가
스냅숏 없이 지워지던 것, 숨김 흐리기를 행 전체가 아니라 이름 줄에만.

편집 스모크의 레이어 검사 19 → 42건. 회귀: 테스트 124/124, 편집 스모크 실패 0,
DB 왕복 1,271건 diff 0/예외 0, 종이 렌더 P062 바이트 동일.

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

738 lines
58 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/>
<MenuItem Header="왼쪽 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Left"/>
<MenuItem Header="오른쪽 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Right"/>
<MenuItem Header="위 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Top"/>
<MenuItem Header="아래 맞춤" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="Bottom"/>
<MenuItem Header="가로 가운데" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="CenterH"/>
<MenuItem Header="세로 가운데" Command="{Binding CurrentDesigner.AlignCommand}" CommandParameter="CenterV"/>
<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)" Command="{Binding CurrentDesigner.CenterInPageCommand}" CommandParameter="H"/>
<MenuItem Header="페이지 세로 가운데(_V)" 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 Width="248" MinWidth="180" MaxWidth="480"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<!-- 최소 250 — 글꼴 스타일 행이 라벨 92 + 토글 4칸 128 = 220px 를 요구한다
(행 가용폭 = 폭 − 스크롤바 9 − 여백 20). 220 이면 마지막 토글이 잘린다. -->
<ColumnDefinition 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 MaxHeight="440" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding Source={StaticResource PaletteGrouped}}" Margin="10,9,10,10">
<!-- 그룹 세로 나열 + 그룹 내 타일 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">
<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>