색상 행에 인라인 팔레트 — 스와치를 누르면 그 자리에서 고르고, '자세히…' 로 피커
색을 바꾸려면 매번 대화상자를 열어야 했다. 실측해 보니 그럴 이유가 없다 — --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:
co-authored by
Claude Opus 5
parent
ac36f93a03
commit
e84337705f
@@ -512,6 +512,8 @@ public sealed class QueryRowViewModel : PropertyRowViewModel
|
||||
/// <summary>색 행 — 레거시 invariant 문자열("R, G, B"/명명색) + 미리보기 스와치</summary>
|
||||
public sealed class ColorRowViewModel : PropertyRowViewModel
|
||||
{
|
||||
private bool isPaletteOpen;
|
||||
|
||||
/// <summary>미리보기 브러시</summary>
|
||||
public Brush Preview
|
||||
{
|
||||
@@ -531,9 +533,47 @@ public sealed class ColorRowViewModel : PropertyRowViewModel
|
||||
/// <summary>색상 피커 열기 — 확정 시 레거시 invariant 형식("R, G, B")으로 반영</summary>
|
||||
public M.Framework.WPF.ICustomCommand? PickCommand { get; set; }
|
||||
|
||||
/// <summary>인라인 팔레트 열림 — 스와치를 누르면 토글된다</summary>
|
||||
public bool IsPaletteOpen
|
||||
{
|
||||
get => isPaletteOpen;
|
||||
set => SetProperty(ref isPaletteOpen, value);
|
||||
}
|
||||
|
||||
/// <summary>자주 쓰는 배경색 견본</summary>
|
||||
public IReadOnlyList<ColorSwatchViewModel> BackgroundSwatches { get; } =
|
||||
Core.Catalog.LegacyColorCatalog.Backgrounds.Select(e => new ColorSwatchViewModel(e.Value, e.Usage)).ToList();
|
||||
|
||||
/// <summary>자주 쓰는 글자색·강조 견본</summary>
|
||||
public IReadOnlyList<ColorSwatchViewModel> ForegroundSwatches { get; } =
|
||||
Core.Catalog.LegacyColorCatalog.Foregrounds.Select(e => new ColorSwatchViewModel(e.Value, e.Usage)).ToList();
|
||||
|
||||
/// <summary>견본 선택 — 레거시 원문 값을 그대로 넣고 팔레트를 닫는다</summary>
|
||||
public M.Framework.WPF.ICustomCommand? ApplySwatchCommand { get; set; }
|
||||
|
||||
/// <summary>비우기 — 속성값을 지운다(상속/기본값으로 되돌림)</summary>
|
||||
public M.Framework.WPF.ICustomCommand? ClearCommand { get; set; }
|
||||
|
||||
public ColorRowViewModel(string label) : base(label)
|
||||
{
|
||||
PickCommand = new M.Framework.WPF.Command((sender, e) => OnPick());
|
||||
PickCommand = new M.Framework.WPF.Command((sender, e) =>
|
||||
{
|
||||
IsPaletteOpen = false;
|
||||
OnPick();
|
||||
});
|
||||
ApplySwatchCommand = new M.Framework.WPF.Command((object? parameter) =>
|
||||
{
|
||||
if (parameter is ColorSwatchViewModel swatch)
|
||||
{
|
||||
ValueText = swatch.Value;
|
||||
}
|
||||
IsPaletteOpen = false;
|
||||
});
|
||||
ClearCommand = new M.Framework.WPF.Command((sender, e) =>
|
||||
{
|
||||
ValueText = string.Empty;
|
||||
IsPaletteOpen = false;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnValueApplied() => OnPropertyChanged(nameof(Preview));
|
||||
@@ -556,6 +596,44 @@ public sealed class ColorRowViewModel : PropertyRowViewModel
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 색 견본 하나 — 인라인 팔레트 항목.
|
||||
/// <see cref="Value"/> 는 화면 표시용 hex 가 아니라 <b>레거시 원문 그대로</b>(명명색 또는 "R, G, B")다.
|
||||
/// 명명색을 RGB 로 풀어 저장하면 원문과 달라져 왕복 diff 가 생기고, 시스템색이 갖는 의미(Window/Control)도 잃는다.
|
||||
/// </summary>
|
||||
public sealed class ColorSwatchViewModel
|
||||
{
|
||||
/// <summary>저장될 레거시 값</summary>
|
||||
public string Value { get; }
|
||||
|
||||
/// <summary>견본 채움</summary>
|
||||
public Brush Preview { get; }
|
||||
|
||||
/// <summary>견본 윤곽 — 배경이 아니라 견본 자신의 명도로 정한다</summary>
|
||||
public Brush Edge { get; }
|
||||
|
||||
/// <summary>툴팁 — 값 + 실사용 건수</summary>
|
||||
public string ToolTip { get; }
|
||||
|
||||
public ColorSwatchViewModel(string value, string usage)
|
||||
{
|
||||
Value = value;
|
||||
var (a, r, g, b) = Core.Serialization.LegacyFormat.ParseColor(value);
|
||||
var fill = new SolidColorBrush(Color.FromArgb(a, r, g, b));
|
||||
fill.Freeze();
|
||||
Preview = fill;
|
||||
|
||||
var luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255.0;
|
||||
var edge = new SolidColorBrush(luminance > 0.6
|
||||
? Color.FromRgb(0x8A, 0x8A, 0x8A)
|
||||
: Color.FromRgb(0xD0, 0xD0, 0xD0));
|
||||
edge.Freeze();
|
||||
Edge = edge;
|
||||
|
||||
ToolTip = usage.Length > 0 ? $"{value} ({usage})" : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>읽기 전용 행 — 중첩/바이너리/참조 등 raw 편집 불가 값 표시</summary>
|
||||
public sealed class ReadOnlyRowViewModel : PropertyRowViewModel
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user