쿼리 편집기 레이아웃 — 카드 두 장, 갈래 칩, 그리고 《컨트롤명》 치환
목업대로 다시 짰다. 색·모서리·간격은 SheetMe 토큰을 그대로 쓴다. ■ 레이아웃 머리말(제목 + 대상 칩) / SQL 편집기 카드 / 치환 변수 카드 / 아래 버튼 줄. 편집기 카드에는 툴바(포맷·주석·자동완성 · 전체 지우기)와 상태 줄(연결 상태 · 글자·줄 수 · 줄,열)을 뒀다. 변수 카드에는 검색 + 갈래 칩 + 접이식 그룹 + 행마다 + 버튼을 뒀다. + 버튼을 넣은 이유는 더블클릭이 유일한 삽입 수단이었기 때문이다 — 화면에 드러나지 않는 조작이다. ■ 《컨트롤명》 치환 — 아예 없던 기능 레거시 화면에는 Controls 목록이 따로 있었다. 우리에겐 그 문법 자체가 없었다. clsMDataTable.ConvertQuery 는 <<…>> 를 모두 치환한 뒤 《 로 다시 쪼개 poAllControlOnSheet(이름).GETVALUE 를 박는다(:78-94). 즉 같은 서식의 다른 컨트롤 값을 쿼리 조건에 넣을 수 있다. 이제 이 서식의 컨트롤이 '컨트롤' 갈래로 목록에 뜨고, 토크나이저도 《》 를 변수로 잡아 색이 붙고 검증에 걸린다. 다만 디자인 시점에는 컨트롤 목록이 없어 런타임이 무조건 "0" 으로 치환한다(:86) — 검증 실행이 통과해도 운영에서는 다른 값이 들어간다는 뜻이라 코드에 적어 뒀다. ■ 형식(String/Int32/DataRow) 표시 레거시가 '목록/형식' 두 열로 보여 주던 정보다. DataRow 인지 아닌지가 곧 '컬럼명을 더 채워야 하는가'를 뜻해서 고를 때 필요하다. ■ 갈래 칩 그룹이 일곱이라 칩으로 다 늘어놓으면 그것대로 목록이 된다. '값이 어디서 오는가'로 네 갈래(환자·서식·컨트롤·작업자)로 묶고, 같은 칩을 다시 누르면 해제된다. ■ 포맷(Ctrl+Shift+F 상당 — 툴바 버튼) 예약어·함수를 대문자로 바꾸고 주요 절 앞에서 줄을 나누며 괄호 깊이만큼 들여쓴다. 문자열·주석·치환 변수는 손대지 않는다 — 특히 치환 변수는 대소문자가 맞아야 런타임이 찾으므로 대문자로 바꾸면 그 칸이 조용히 빈다. 이 포매터가 저지를 수 있는 가장 나쁜 일이라 테스트로 막았다. 두 번 눌러도 결과가 같다(안정성도 테스트로 고정). 단위 테스트 14건 추가(포매터 11 · 컨트롤 치환 3). 회귀: 테스트 230/230, 편집 스모크 실패 0, 팝업 점검 7/7, 검증 실행 점검 10/10, DB 왕복 1,271건 diff 0/예외 0, 종이 렌더 P062 바이트 동일. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7ce7506286
commit
68fc01c6ba
@@ -2,157 +2,322 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ctl="clr-namespace:SheetMe.Designer.Controls"
|
||||
Title="쿼리 편집" Width="1060" Height="640" MinWidth="780" MinHeight="440"
|
||||
Title="쿼리 편집" Width="1180" Height="760" MinWidth="880" MinHeight="520"
|
||||
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Style="{StaticResource ThemedWindow}">
|
||||
<DockPanel Margin="12">
|
||||
<TextBlock x:Name="HintText" DockPanel.Dock="Top" Foreground="{DynamicResource B.Muted}" TextWrapping="Wrap" Margin="0,0,0,8"
|
||||
Text="작성 시점에 <<변수>> 가 실제 값으로 치환됩니다. 변수는 클래스 전체 이름을 포함해야 하므로 우측 목록에서 삽입하세요 — 임의로 줄여 쓰면 치환되지 않고 SQL 에 그대로 남아 오류가 납니다."/>
|
||||
<Window.Resources>
|
||||
<!-- 처음 펼쳐 둘 그룹 판단 — 가장 많이 쓰는 '환자'와 이 서식의 컨트롤만 펴 둔다 -->
|
||||
<ctl:QueryGroupExpandedConverter x:Key="GroupExpanded"/>
|
||||
|
||||
<DockPanel DockPanel.Dock="Bottom" Margin="0,10,0,0">
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<TextBlock x:Name="LengthText" VerticalAlignment="Center" Margin="0,0,12,0"
|
||||
Foreground="{DynamicResource B.Muted}" FontSize="11.5"/>
|
||||
<Button x:Name="TrialButton" Content="검증 실행" Padding="14,5" Click="OnTrial"
|
||||
ToolTip="DB 에서 실제로 돌려 봅니다 (F5). 조회만 실행되며 표본 몇 행만 가져옵니다."/>
|
||||
<Button Content="확인" Padding="20,5" Margin="8,0,0,0" Click="OnConfirm" IsDefault="True"/>
|
||||
<Button Content="취소" Padding="20,5" Margin="8,0,0,0" IsCancel="True"/>
|
||||
<!-- 카드: 두 영역을 눈으로 갈라 준다 -->
|
||||
<Style x:Key="Card" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="10"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource B.InputBorder}"/>
|
||||
<Setter Property="Background" Value="{DynamicResource B.Surface}"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CardTitle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="13.5"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Ink}"/>
|
||||
</Style>
|
||||
|
||||
<!-- 편집기 툴바 버튼 -->
|
||||
<Style x:Key="ToolBtn" TargetType="Button" BasedOn="{StaticResource Subtle}">
|
||||
<Setter Property="Padding" Value="8,3"/>
|
||||
<Setter Property="FontSize" Value="11.5"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Ink}"/>
|
||||
</Style>
|
||||
|
||||
<!-- 갈래 칩 -->
|
||||
<Style x:Key="BucketChip" TargetType="ToggleButton">
|
||||
<Setter Property="FontSize" Value="11.5"/>
|
||||
<Setter Property="Padding" Value="10,3"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Ink}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Border x:Name="chip" CornerRadius="12" Padding="{TemplateBinding Padding}"
|
||||
Background="{DynamicResource B.Input}"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" BorderThickness="1">
|
||||
<ContentPresenter VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="chip" Property="Background" Value="{DynamicResource B.Accent}"/>
|
||||
<Setter TargetName="chip" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.OnAccent}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="chip" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<DockPanel Margin="16,14,16,14">
|
||||
<!-- ── 머리말 ── -->
|
||||
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,12">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="쿼리 편집" FontSize="17" FontWeight="Bold"
|
||||
Foreground="{DynamicResource B.Ink}" VerticalAlignment="Center"/>
|
||||
<Border x:Name="TargetChip" CornerRadius="6" Padding="8,2" Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Background="{DynamicResource B.Input}" BorderBrush="{DynamicResource B.InputBorder}"
|
||||
BorderThickness="1">
|
||||
<TextBlock x:Name="TargetChipText" FontSize="11.5" FontFamily="Consolas, D2Coding, 굴림체"
|
||||
Foreground="{DynamicResource B.AccentText}"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<TextBlock x:Name="HintText" Margin="0,6,0,0" FontSize="11.5" TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource B.Muted}"
|
||||
Text="작성 시점에 <<변수>> 가 실제 값으로 치환됩니다. 변수는 클래스 전체 이름을 포함해야 하므로 우측 목록에서 삽입하세요."/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── 아래 버튼 줄 ── -->
|
||||
<DockPanel DockPanel.Dock="Bottom" Margin="0,12,0,0">
|
||||
<TextBlock x:Name="ProblemText" VerticalAlignment="Center" Margin="0,0,12,0"
|
||||
Foreground="{DynamicResource B.Danger}" FontSize="11.5"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button x:Name="TrialButton" Padding="14,6" Click="OnTrial"
|
||||
ToolTip="DB 에서 실제로 돌려 봅니다 (F5). 조회만 실행되며 표본 몇 행만 가져옵니다.">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="▶" FontSize="10" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||||
<TextBlock Text="검증 실행" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Content="확인" Padding="24,6" Margin="8,0,0,0"
|
||||
Style="{StaticResource Primary}" Click="OnConfirm" IsDefault="True"/>
|
||||
<Button Content="취소" Padding="20,6" Margin="8,0,0,0" IsCancel="True"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
<!-- 검증 결과 — 실행했을 때만 뜬다 -->
|
||||
<Border x:Name="TrialPane" DockPanel.Dock="Bottom" Visibility="Collapsed" Margin="0,10,0,0"
|
||||
MaxHeight="200" CornerRadius="6" BorderThickness="1"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" Background="{DynamicResource B.Surface}">
|
||||
<DockPanel Margin="10,8">
|
||||
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,6">
|
||||
<Button DockPanel.Dock="Right" Content="닫기" Padding="8,1" Style="{StaticResource Subtle}"
|
||||
Click="OnCloseTrial"/>
|
||||
<TextBlock x:Name="TrialSummary" FontSize="11.5" TextWrapping="Wrap"/>
|
||||
</DockPanel>
|
||||
<DataGrid x:Name="TrialGrid" AutoGenerateColumns="True" IsReadOnly="True"
|
||||
HeadersVisibility="Column" FontSize="11.5" MaxHeight="150"
|
||||
GridLinesVisibility="Horizontal" Background="Transparent"
|
||||
AutomationProperties.Name="검증 결과 표본"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition x:Name="SplitterColumn" Width="8"/>
|
||||
<ColumnDefinition x:Name="VariableColumn" Width="360"/>
|
||||
<ColumnDefinition x:Name="SplitterColumn" Width="12"/>
|
||||
<ColumnDefinition x:Name="VariableColumn" Width="430"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- SQL 편집 영역.
|
||||
색칠은 뒤에 깔린 SqlHighlightLayer 가 하고, 편집은 위에 얹힌 투명 TextBox 가 그대로 한다
|
||||
(캐럿·선택·실행취소·IME 를 직접 만들지 않기 위해서다).
|
||||
두 요소의 글꼴·크기·여백이 어긋나면 글자와 색이 어긋난다 — 반드시 같이 고칠 것. -->
|
||||
<Border Grid.Column="0" BorderThickness="1" CornerRadius="6" ClipToBounds="True"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" Background="{DynamicResource B.Input}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- ══ SQL 편집기 카드 ══ -->
|
||||
<Border Grid.Column="0" Style="{StaticResource Card}">
|
||||
<DockPanel Margin="14,12,14,12">
|
||||
<TextBlock DockPanel.Dock="Top" Text="SQL 편집기" Style="{StaticResource CardTitle}"
|
||||
Margin="0,0,0,10"/>
|
||||
|
||||
<!-- 줄 번호 -->
|
||||
<Border Grid.Column="0" Background="{DynamicResource B.Surface}" Padding="6,6,6,6">
|
||||
<TextBlock x:Name="LineNumbers" FontFamily="Consolas, D2Coding, 굴림체" FontSize="13"
|
||||
Foreground="{DynamicResource B.Muted}" TextAlignment="Right" MinWidth="26"/>
|
||||
<!-- 툴바 -->
|
||||
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource ToolBtn}" Click="OnClearAll"
|
||||
Foreground="{DynamicResource B.Danger}" Content="전체 지우기"
|
||||
ToolTip="편집 내용을 모두 지웁니다"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Style="{StaticResource ToolBtn}" Content="포맷" Click="OnFormat"
|
||||
ToolTip="예약어를 대문자로 바꾸고 절마다 줄을 나눕니다 (Ctrl+Shift+F). 문자열·치환 변수는 건드리지 않습니다."/>
|
||||
<Button Style="{StaticResource ToolBtn}" Content="주석" Click="OnToggleComment"
|
||||
ToolTip="선택한 줄에 -- 를 붙이거나 뗍니다 (Ctrl+/)"/>
|
||||
<Button Style="{StaticResource ToolBtn}" Content="자동완성" Click="OnInvokeCompletion"
|
||||
ToolTip="커서 위치에서 후보를 띄웁니다 (Ctrl+Space)"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
<!-- 상태 줄 -->
|
||||
<Border DockPanel.Dock="Bottom" Margin="0,8,0,0" Padding="10,5" CornerRadius="6"
|
||||
Background="{DynamicResource B.Input}">
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Right" x:Name="CaretText" FontSize="11"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Ellipse x:Name="ConnDot" Width="7" Height="7" VerticalAlignment="Center"
|
||||
Margin="0,0,6,0" Fill="{DynamicResource B.Muted}"/>
|
||||
<TextBlock x:Name="ConnText" FontSize="11" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
<TextBlock Text="│" FontSize="11" Margin="10,0" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource B.InputBorder}"/>
|
||||
<TextBlock x:Name="LengthText" FontSize="11" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<ctl:SqlHighlightLayer x:Name="Highlight" IsHitTestVisible="False"/>
|
||||
<!-- 자동완성 목록 — 커서 아래에 띄운다. StaysOpen 이라 목록을 눌러도 편집 포커스를 잃지 않는다 -->
|
||||
<!-- StaysOpen=False 여야 바깥을 클릭했을 때 닫힌다.
|
||||
True 로 두면 목록 항목을 고르기 전까지 화면에 계속 남는다. -->
|
||||
<Popup x:Name="CompletionPopup" Placement="Relative" AllowsTransparency="True"
|
||||
StaysOpen="False" PopupAnimation="None" Focusable="False">
|
||||
<Border Background="{DynamicResource B.Surface}" BorderThickness="1"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" CornerRadius="6" Padding="2">
|
||||
<ListBox x:Name="CompletionList" MaxHeight="240" MinWidth="260" FontSize="12"
|
||||
BorderThickness="0" Background="Transparent"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
MouseDoubleClick="OnCompletionPicked">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel MinWidth="240">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding KindLabel}" FontSize="10"
|
||||
Foreground="{DynamicResource B.Muted}" Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Text}" FontFamily="Consolas, D2Coding, 굴림체"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<!-- 검증 결과 -->
|
||||
<Border x:Name="TrialPane" DockPanel.Dock="Bottom" Visibility="Collapsed" Margin="0,8,0,0"
|
||||
MaxHeight="190" CornerRadius="8" BorderThickness="1"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" Background="{DynamicResource B.Input}">
|
||||
<DockPanel Margin="10,8">
|
||||
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,6">
|
||||
<Button DockPanel.Dock="Right" Content="닫기" Padding="8,1"
|
||||
Style="{StaticResource ToolBtn}" Click="OnCloseTrial"/>
|
||||
<TextBlock x:Name="TrialSummary" FontSize="11.5" TextWrapping="Wrap"/>
|
||||
</DockPanel>
|
||||
<DataGrid x:Name="TrialGrid" AutoGenerateColumns="True" IsReadOnly="True"
|
||||
HeadersVisibility="Column" FontSize="11.5" MaxHeight="140"
|
||||
GridLinesVisibility="Horizontal" Background="Transparent"
|
||||
AutomationProperties.Name="검증 결과 표본"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 편집 영역: 색칠 레이어 + 투명 TextBox -->
|
||||
<Border BorderThickness="1" CornerRadius="8" ClipToBounds="True"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" Background="{DynamicResource B.Input}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.Column="0" Background="{DynamicResource B.Surface}" Padding="8,6">
|
||||
<TextBlock x:Name="LineNumbers" FontFamily="Consolas, D2Coding, 굴림체" FontSize="13"
|
||||
Foreground="{DynamicResource B.Muted}" TextAlignment="Right" MinWidth="24"/>
|
||||
</Border>
|
||||
</Popup>
|
||||
<TextBox x:Name="SqlBox"
|
||||
FontFamily="Consolas, D2Coding, 굴림체" FontSize="13"
|
||||
AcceptsReturn="True" AcceptsTab="False"
|
||||
TextWrapping="NoWrap" Padding="6"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Foreground="Transparent"
|
||||
CaretBrush="{DynamicResource B.Ink}"
|
||||
SelectionBrush="{DynamicResource B.Accent}" SelectionOpacity="0.35"
|
||||
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
|
||||
TextChanged="OnSqlChanged" PreviewKeyDown="OnSqlKeyDown"
|
||||
SelectionChanged="OnSqlSelectionChanged" LostFocus="OnSqlLostFocus"
|
||||
AutomationProperties.Name="SQL 편집"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1">
|
||||
<ctl:SqlHighlightLayer x:Name="Highlight" IsHitTestVisible="False"/>
|
||||
<!-- StaysOpen=False 여야 바깥을 클릭했을 때 닫힌다 -->
|
||||
<Popup x:Name="CompletionPopup" Placement="Relative" AllowsTransparency="True"
|
||||
StaysOpen="False" PopupAnimation="None" Focusable="False">
|
||||
<Border Background="{DynamicResource B.Surface}" BorderThickness="1"
|
||||
BorderBrush="{DynamicResource B.InputBorder}" CornerRadius="8" Padding="3">
|
||||
<ListBox x:Name="CompletionList" MaxHeight="260" MinWidth="280" FontSize="12"
|
||||
BorderThickness="0" Background="Transparent"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
MouseDoubleClick="OnCompletionPicked">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel MinWidth="260">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding KindLabel}" FontSize="10"
|
||||
Foreground="{DynamicResource B.Muted}" Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Text}" FontFamily="Consolas, D2Coding, 굴림체"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</Popup>
|
||||
<TextBox x:Name="SqlBox"
|
||||
FontFamily="Consolas, D2Coding, 굴림체" FontSize="13"
|
||||
AcceptsReturn="True" AcceptsTab="False"
|
||||
TextWrapping="NoWrap" Padding="8,6"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Foreground="Transparent"
|
||||
CaretBrush="{DynamicResource B.Ink}"
|
||||
SelectionBrush="{DynamicResource B.Accent}" SelectionOpacity="0.35"
|
||||
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
|
||||
TextChanged="OnSqlChanged" PreviewKeyDown="OnSqlKeyDown"
|
||||
SelectionChanged="OnSqlSelectionChanged" LostFocus="OnSqlLostFocus"
|
||||
AutomationProperties.Name="SQL 편집"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<GridSplitter Grid.Column="1" Style="{StaticResource ColSplitter}"/>
|
||||
|
||||
<!-- 치환 변수 (SQL 용도에서만) -->
|
||||
<DockPanel x:Name="VariablePane" Grid.Column="2">
|
||||
<TextBlock DockPanel.Dock="Top" Text="치환 변수" FontWeight="Bold"
|
||||
Foreground="{DynamicResource B.Muted}" Margin="4,0,0,6"/>
|
||||
<TextBox x:Name="VariableSearch" DockPanel.Dock="Top" Margin="0,0,0,6" Padding="6,3"
|
||||
VerticalContentAlignment="Center" TextChanged="OnVariableSearchChanged"
|
||||
AutomationProperties.Name="치환 변수 검색"
|
||||
ToolTip="이름·설명·초성으로 찾습니다 (예: ㅊㅌㅂㅎ → 차트번호)"/>
|
||||
<TextBlock DockPanel.Dock="Bottom" x:Name="VariableHint" FontSize="10.5" TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource B.Muted}" Margin="4,6,0,0"
|
||||
Text="더블클릭 또는 Enter 로 커서 위치에 삽입합니다."/>
|
||||
<ListBox x:Name="VariableList" FontSize="11" MouseDoubleClick="OnInsertVariable"
|
||||
KeyDown="OnVariableListKeyDown"
|
||||
FontFamily="Consolas, D2Coding, 굴림체"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
AutomationProperties.Name="치환 변수 목록">
|
||||
<!-- 토큰 전체(60자 넘음)를 줄마다 깔면 앞 40자가 전부 같아 정작 다른 부분이 잘린다.
|
||||
설명 + 속성명만 띄우고 전체는 툴팁으로 둔다. -->
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel Margin="0,2" ToolTip="{Binding Token}">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding ShortForm}"
|
||||
Foreground="{DynamicResource B.Muted}" FontSize="10.5"
|
||||
VerticalAlignment="Center" Margin="8,0,0,0"/>
|
||||
<TextBlock Text="{Binding Description}" FontFamily="Segoe UI, 맑은 고딕" FontSize="12"
|
||||
TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
<ListBox.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" FontWeight="Bold" Margin="2,8,0,3"
|
||||
FontFamily="Segoe UI, 맑은 고딕" FontSize="12"
|
||||
Foreground="{DynamicResource B.AccentText}"/>
|
||||
</DataTemplate>
|
||||
</GroupStyle.HeaderTemplate>
|
||||
</GroupStyle>
|
||||
</ListBox.GroupStyle>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
<!-- ══ 치환 변수 카드 ══ -->
|
||||
<Border x:Name="VariablePane" Grid.Column="2" Style="{StaticResource Card}">
|
||||
<DockPanel Margin="14,12,14,12">
|
||||
<TextBlock DockPanel.Dock="Top" Text="치환 변수" Style="{StaticResource CardTitle}"
|
||||
Margin="0,0,0,10"/>
|
||||
|
||||
<TextBox x:Name="VariableSearch" DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8,4"
|
||||
VerticalContentAlignment="Center" TextChanged="OnVariableSearchChanged"
|
||||
AutomationProperties.Name="치환 변수 검색"
|
||||
ToolTip="변수명·설명·초성으로 찾습니다 (예: ㅊㅌㅂㅎ → 차트번호)"/>
|
||||
|
||||
<!-- 갈래 칩 -->
|
||||
<ItemsControl x:Name="BucketChips" DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ToggleButton Style="{StaticResource BucketChip}"
|
||||
IsChecked="{Binding IsActive, Mode=OneWay}"
|
||||
Tag="{Binding Name}" Click="OnBucketClick">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
<TextBlock Text="{Binding Count}" Margin="6,0,0,0" Opacity="0.75"/>
|
||||
</StackPanel>
|
||||
</ToggleButton>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- 안내 -->
|
||||
<Border DockPanel.Dock="Bottom" Margin="0,8,0,0" Padding="10,7" CornerRadius="8"
|
||||
Background="{DynamicResource B.Input}">
|
||||
<TextBlock x:Name="VariableHint" FontSize="10.5" TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
</Border>
|
||||
|
||||
<ListBox x:Name="VariableList" FontSize="11.5" MouseDoubleClick="OnInsertVariable"
|
||||
KeyDown="OnVariableListKeyDown"
|
||||
BorderThickness="0" Background="Transparent"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
AutomationProperties.Name="치환 변수 목록">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel Margin="0,3" ToolTip="{Binding Token}">
|
||||
<!-- ⊕ 로 바로 삽입 — 더블클릭을 모르는 사람도 넣을 수 있어야 한다 -->
|
||||
<Button DockPanel.Dock="Right" Width="22" Height="22" Padding="0"
|
||||
Margin="8,0,0,0" Style="{StaticResource ToolBtn}"
|
||||
Content="+" FontSize="13"
|
||||
Foreground="{DynamicResource B.AccentText}"
|
||||
Command="{Binding DataContext.InsertCommand,
|
||||
RelativeSource={RelativeSource AncestorType=ListBox}}"
|
||||
CommandParameter="{Binding}"
|
||||
ToolTip="커서 위치에 삽입"/>
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding ShortForm}"
|
||||
Foreground="{DynamicResource B.Muted}" FontSize="10.5"
|
||||
FontFamily="Consolas, D2Coding, 굴림체"
|
||||
VerticalAlignment="Center" Margin="8,0,0,0"/>
|
||||
<TextBlock Text="{Binding Description}" FontFamily="Segoe UI, 맑은 고딕" FontSize="12"
|
||||
TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
<ListBox.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.ContainerStyle>
|
||||
<Style TargetType="GroupItem">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GroupItem">
|
||||
<Expander IsExpanded="{Binding Name,
|
||||
Converter={StaticResource GroupExpanded}, Mode=OneTime}"
|
||||
Margin="0,4,0,0">
|
||||
<Expander.Header>
|
||||
<DockPanel MinWidth="330">
|
||||
<Border DockPanel.Dock="Right" CornerRadius="9" Padding="6,1"
|
||||
VerticalAlignment="Center" Margin="6,0,0,0"
|
||||
Background="{DynamicResource B.Input}">
|
||||
<TextBlock Text="{Binding ItemCount}" FontSize="10"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"
|
||||
FontFamily="Segoe UI, 맑은 고딕" FontSize="12"/>
|
||||
</DockPanel>
|
||||
</Expander.Header>
|
||||
<ItemsPresenter Margin="8,2,0,6"/>
|
||||
</Expander>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</GroupStyle.ContainerStyle>
|
||||
</GroupStyle>
|
||||
</ListBox.GroupStyle>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
|
||||
Reference in New Issue
Block a user