색상 행에 인라인 팔레트 — 스와치를 누르면 그 자리에서 고르고, '자세히…' 로 피커

색을 바꾸려면 매번 대화상자를 열어야 했다. 실측해 보니 그럴 이유가 없다 —
--db-colors 진단을 신설해 운영 디자인 1,271건의 BackColor·ForeColor 60,319건을 집계한 결과
상위 두 값이 전체의 84%다: White 29,010건(48%), "224, 224, 224" 21,497건(36%).
뒤는 꼬리가 길고 얇다(Transparent 792 · Silver 557 · Window 440 · Gainsboro 415 …).
ForeColor 는 Black 4,920건(85%) · ControlText 345건이 사실상 전부.

스와치를 토글로 바꾸고 팝업에 실사용 상위 값을 배경 12종 / 글자·강조 12종으로 깔았다.
표준 색상표를 늘어놓지 않은 것은 의도다 — 목적은 자주 쓰는 값을 한 번에 고르게 하는 것이지
색을 발명하게 하는 것이 아니다. 임의 색은 팝업 아래 '자세히…' 로 기존 피커
(채도·명도 사각형 + 색상 슬라이더 + HEX·RGB + 프리셋·최근색)를 연다.

핵심은 견본이 레거시 원문 값을 그대로 넣는다는 점이다. 명명색을 RGB 로 풀면
원문과 달라져 왕복 diff 가 생기고, 시스템색이 갖는 의미(Window/Control/ControlText)도 잃는다.
'Window' 를 고르면 "Window" 가 저장된다. 툴팁에는 실사용 건수를 함께 띄운다.

'비우기'는 기본값을 저장하는 것이 아니라 키를 지운다 — 레거시 PropertyGrid 의 재설정과
같고, 원래 BackColor 가 없던 페이지(12.7%)를 원상태로 되돌릴 수 있어야 한다.

함께 고친 것: 페이지 속성 모드에서 '컨트롤을 선택하면 속성이 표시됩니다' 안내가 행과 같이
뜨던 것(HasSelection 이 컨트롤 선택만 보고 있었다). 탭 스트립은 페이지 모드에서 숨긴다.

편집 스모크 4건 추가(원문 값 적용 / 명명색 보존 / 적용 후 닫힘 / 비우기는 키 제거).
회귀: 테스트 124/124, 편집 스모크 실패 0, DB 왕복 1,271건 diff 0/예외 0,
종이 렌더 P062 바이트 동일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-13 10:56:47 +09:00
co-authored by Claude Opus 5
parent ac36f93a03
commit e84337705f
7 changed files with 337 additions and 21 deletions
+81 -16
View File
@@ -424,26 +424,91 @@
</StackPanel>
</DataTemplate>
<!-- 팔레트 견본 하나 — 윤곽은 테마색이 아니라 견본 자신의 명도로 정한다
(테마 테두리를 쓰면 라이트에서 흰 견본이, 다크에서 검정 견본이 빈칸으로 보인다) -->
<DataTemplate x:Key="ColorSwatchTemplate" DataType="{x:Type ins:ColorSwatchViewModel}">
<Button Width="22" Height="22" Margin="0,0,4,4" Padding="0" Cursor="Hand"
ToolTip="{Binding ToolTip}"
Command="{Binding DataContext.ApplySwatchCommand,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="sw" Background="{Binding Preview}" BorderBrush="{Binding Edge}"
BorderThickness="1" CornerRadius="4" SnapsToDevicePixels="True"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="sw" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
<Setter TargetName="sw" Property="BorderThickness" Value="2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
<DataTemplate DataType="{x:Type ins:ColorRowViewModel}">
<DockPanel Margin="0,2">
<TextBlock Text="{Binding Label}" Style="{StaticResource RowLabel}"
ToolTip="{Binding LabelToolTip}"/>
<!-- 스와치 = 피커 버튼(클릭 → 색상 선택 대화상자), 직접 입력도 병행 -->
<Button DockPanel.Dock="Right" Width="30" Height="26" Margin="4,0,0,0" Padding="0"
Command="{Binding PickCommand}" Cursor="Hand"
ToolTip="클릭하여 색상 선택">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" Background="{Binding Preview}" BorderBrush="{DynamicResource B.Line2}"
BorderThickness="1" CornerRadius="4" SnapsToDevicePixels="True"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
<!--
스와치 = 인라인 팔레트 토글. 실측상 배경색의 84%가 White 와 "224, 224, 224"
단 두 값이라, 그 자리에서 바로 고르는 편이 대화상자를 여는 것보다 빠르다.
임의 색은 팔레트 아래 '자세히…' 로 기존 피커(SV/Hue/HEX/RGB)를 연다.
-->
<Grid DockPanel.Dock="Right" Margin="4,0,0,0">
<ToggleButton x:Name="SwatchToggle" Width="30" Height="26" Padding="0" Cursor="Hand"
IsChecked="{Binding IsPaletteOpen, Mode=TwoWay}"
ToolTip="클릭하여 색 고르기">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="bd" Background="{Binding Preview}" BorderBrush="{DynamicResource B.Line2}"
BorderThickness="1" CornerRadius="4" SnapsToDevicePixels="True"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Popup IsOpen="{Binding IsPaletteOpen, Mode=TwoWay}" StaysOpen="False" AllowsTransparency="True"
PlacementTarget="{Binding ElementName=SwatchToggle}" Placement="Bottom"
HorizontalOffset="-176" VerticalOffset="4">
<Border Background="{DynamicResource B.Surface}" BorderBrush="{DynamicResource B.Line2}"
BorderThickness="1" CornerRadius="8" Padding="10" Effect="{DynamicResource B.FloatShadow}">
<StackPanel Width="212">
<TextBlock Text="배경" FontSize="11" Foreground="{DynamicResource B.Muted}" Margin="0,0,0,5"/>
<ItemsControl ItemsSource="{Binding BackgroundSwatches}"
ItemTemplate="{StaticResource ColorSwatchTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<TextBlock Text="글자·강조" FontSize="11" Foreground="{DynamicResource B.Muted}" Margin="0,8,0,5"/>
<ItemsControl ItemsSource="{Binding ForegroundSwatches}"
ItemTemplate="{StaticResource ColorSwatchTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Border Height="1" Background="{DynamicResource B.Line}" Margin="0,9,0,8"/>
<DockPanel>
<Button DockPanel.Dock="Right" Content="자세히…" Height="28" Padding="10,0"
Command="{Binding PickCommand}"
ToolTip="색상 피커 — 채도·명도·색상환, HEX·RGB 직접 입력"/>
<Button HorizontalAlignment="Left" Content="비우기" Height="28" Padding="10,0"
Style="{StaticResource Subtle}" Command="{Binding ClearCommand}"
ToolTip="속성값을 지웁니다(기본값·상속으로 되돌림)"/>
</DockPanel>
</StackPanel>
</Border>
</Popup>
</Grid>
<Grid>
<TextBox Style="{StaticResource RowInput}" bh:InspectorFieldBehavior.CommitOnEnter="True" Text="{Binding ValueText, UpdateSourceTrigger=LostFocus}"
ToolTip="R, G, B 또는 색 이름 (예: 224, 224, 224 / White) — 오른쪽 스와치 클릭 시 피커"/>