초기 커밋: SheetMe 서식생성기 (P0~P5 완료 상태)
레거시 서식생성기(VB.NET WinForms) 대체용 C#/.NET 10 WPF 디자이너. 기준선: 실DB 활성 디자인 1,271건 왕복 의미론 diff 0 / 예외 0, 단위 테스트 49/49. 이 커밋에 함께 포함된 자격증명 분리: - appsettings.json 을 __HOST__/__PASSWORD__ 플레이스홀더로 전환 - 실접속 정보는 appsettings.Development.json 으로 분리(.gitignore 제외, csproj Debug 조건부 복사라 Release 산출물에 실리지 않음) - ConfigLoader 를 환경변수 > Development > appsettings 순 레이어링으로 변경, 미치환 플레이스홀더는 '미설정'으로 간주 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,540 @@
|
||||
<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">
|
||||
|
||||
<!-- 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:InverseBoolConverter x:Key="InverseBool"/>
|
||||
|
||||
<!-- 팔레트(도구 상자/플라이아웃 공용) — 카테고리 그룹 뷰 -->
|
||||
<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"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 좌: 로고 + 메뉴 -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,0,0"
|
||||
shell:WindowChrome.IsHitTestVisibleInChrome="True">
|
||||
<Image Source="pack://application:,,,/SheetMe.Designer;component/Assets/sheetme-logo.png"
|
||||
Width="20" Height="20" VerticalAlignment="Center" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
<Menu VerticalAlignment="Center" Margin="8,0,0,0">
|
||||
<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}"/>
|
||||
<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>
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 중앙: 창 제목 -->
|
||||
<TextBlock Grid.Column="1" Text="{Binding Title}" Foreground="{DynamicResource B.Muted}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="12"/>
|
||||
|
||||
<!-- 우: 창 제어 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" shell:WindowChrome.IsHitTestVisibleInChrome="True">
|
||||
<Button Style="{StaticResource CaptionBtn}" Click="OnMinimizeClick" ToolTip="최소화">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="10"/>
|
||||
</Button>
|
||||
<Button Style="{StaticResource CaptionBtn}" Click="OnMaxRestoreClick" ToolTip="최대화/복원">
|
||||
<TextBlock x:Name="MaxGlyph" Text="" FontFamily="Segoe MDL2 Assets" FontSize="10"/>
|
||||
</Button>
|
||||
<Button Style="{StaticResource CloseBtn}" Click="OnCloseWinClick" ToolTip="닫기">
|
||||
<TextBlock Text="" 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="12,6">
|
||||
<TextBlock Text="{Binding StatusText}" Foreground="{DynamicResource B.Muted}" FontSize="12"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
</Border>
|
||||
|
||||
<!-- ===== 본문 3열: 좌 탭 패널 | 문서 탭+캔버스+플로팅 바 | 속성 ([200] 레이아웃) ===== -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="232" MinWidth="180" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="280" MinWidth="220" 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" Content="검색" Margin="6,0,0,0"
|
||||
Command="{Binding SearchSheetsCommand}"/>
|
||||
<TextBox Text="{Binding SheetSearchKeyword, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="서식명/코드 검색 (Enter)">
|
||||
<TextBox.InputBindings>
|
||||
<KeyBinding Key="Enter" Command="{Binding SearchSheetsCommand}"/>
|
||||
</TextBox.InputBindings>
|
||||
</TextBox>
|
||||
</DockPanel>
|
||||
<Grid>
|
||||
<ListBox x:Name="SheetListBox" ItemsSource="{Binding SheetList}"
|
||||
Margin="4,0,4,4"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
MouseDoubleClick="OnSheetListDoubleClick"
|
||||
ToolTip="더블클릭으로 열기 — 여러 서식을 탭으로 동시에 편집할 수 있습니다">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" Margin="1">
|
||||
<TextBlock Text="{Binding ShtCod}" FontSize="11" Foreground="{DynamicResource B.Muted}"
|
||||
Width="52" VerticalAlignment="Center"/>
|
||||
<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>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<TextBlock Text="불러오는 중..." HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource B.Muted}"
|
||||
Visibility="{Binding IsSheetListLoading, Converter={StaticResource BoolToVisibility}}"/>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<!-- 레이어 (+ 페이지) -->
|
||||
<TabItem>
|
||||
<TabItem.Header><TextBlock Text="레이어" Style="{StaticResource TabHeaderText}"/></TabItem.Header>
|
||||
<DockPanel>
|
||||
<!-- 페이지 섹션 -->
|
||||
<DockPanel DockPanel.Dock="Top" Margin="0,4,0,0">
|
||||
<TextBlock DockPanel.Dock="Top" Text="페이지" FontWeight="Bold" FontSize="11"
|
||||
Margin="10,4,10,4" Foreground="{DynamicResource B.Muted}"/>
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="10,2,10,6">
|
||||
<Button Content="추가" Command="{Binding CurrentDesigner.AddPageCommand}"/>
|
||||
<Button Content="삭제" Margin="6,0,0,0" Command="{Binding CurrentDesigner.RemovePageCommand}"/>
|
||||
</StackPanel>
|
||||
<ListBox ItemsSource="{Binding CurrentDesigner.Pages}"
|
||||
SelectedItem="{Binding CurrentDesigner.SelectedPage}"
|
||||
MaxHeight="110" Margin="4,0">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" Margin="2,1">
|
||||
<TextBlock Text="{Binding Index, StringFormat=페이지 {0}}" FontSize="12"/>
|
||||
<TextBlock Text="{Binding SizeText, StringFormat= ({0})}" FontSize="11" Foreground="{DynamicResource B.Muted}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
<Border DockPanel.Dock="Top" Height="1" Background="{DynamicResource B.Line}" Margin="8,2"/>
|
||||
<!-- 레이어 목록 (활성 페이지, 그리기 순서) -->
|
||||
<ListBox ItemsSource="{Binding CurrentDesigner.SelectedPage.Controls}"
|
||||
SelectedItem="{Binding CurrentDesigner.SelectedLayerItem}"
|
||||
Margin="4,2,4,6"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel Margin="0,1">
|
||||
<CheckBox DockPanel.Dock="Right" IsChecked="{Binding IsLockedFlag}"
|
||||
ToolTip="잠금" Margin="4,0,0,0"/>
|
||||
<CheckBox DockPanel.Dock="Right" IsChecked="{Binding IsHiddenFlag}"
|
||||
ToolTip="숨김" Margin="4,0,0,0"/>
|
||||
<TextBlock Text="{Binding Id}" FontSize="12" TextTrimming="CharacterEllipsis"/>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</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 Content="{Binding Source=file-text, Converter={StaticResource IconName}, ConverterParameter=12}"
|
||||
Margin="0,0,6,0" VerticalAlignment="Center" IsTabStop="False" Focusable="False"/>
|
||||
<TextBlock Text="{Binding DisplayName}" MaxWidth="170" Style="{StaticResource TabHeaderText}"
|
||||
TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||||
<Button Content="✕" FontSize="9" 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">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="20" ShadowDepth="3" Opacity="0.35" Color="Black"/>
|
||||
</Border.Effect>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<ToggleButton 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}"/>
|
||||
<ToggleButton 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}"/>
|
||||
<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"/>
|
||||
<Button Style="{StaticResource Subtle}" Width="30" Height="34" Padding="0" ToolTip="축소 (Ctrl+휠↓)"
|
||||
Command="{Binding ZoomOutCommand}"
|
||||
Content="{Binding Source=zoom-out, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||
<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>
|
||||
<Button Style="{StaticResource Subtle}" Width="30" Height="34" Padding="0" ToolTip="확대 (Ctrl+휠↑)"
|
||||
Command="{Binding ZoomInCommand}"
|
||||
Content="{Binding Source=zoom-in, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||
</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>
|
||||
<DropShadowEffect BlurRadius="16" ShadowDepth="3" Opacity="0.4" Color="Black"/>
|
||||
</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>
|
||||
<DropShadowEffect BlurRadius="16" ShadowDepth="3" Opacity="0.4" Color="Black"/>
|
||||
</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>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
</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>
|
||||
Reference in New Issue
Block a user