제목줄 환자 아이콘이 혼자 까맸다

지적을 받고서야 실제로 봤다. 앞 커밋에서 "제목줄의 환자 아이콘 버튼은 손대지 않았다 —
옆 아이콘들과 같은 스타일·크기다" 라고 썼는데, <b>마크업만 읽고 화면을 안 봤다.</b>
스타일과 크기는 같았지만 색이 달랐다.

## 무슨 일이었나

이웃 아이콘(복사·삭제·테마·저장)은 XAML 컨버터를 타고, 그 기본 브러시 키가 <b>B.Muted</b> 다.
환자 아이콘만 코드에서 만드는데 안 고른 상태에 <c>null</c> 을 넘겼고,
LucideIcons.Paint 는 키도 색도 없으면 <c>Brushes.Black</c> 으로 칠했다 —
어두운 제목줄에서 <b>안 보이는 아이콘</b>이라는 뜻이다.

컴파일러가 CS8604 로 그 자리(MainView.xaml.cs:139)를 이 세션 내내 경고하고 있었다.
빌드 로그에서 매번 지나쳤다.

## 두 군데를 고친다

① 호출부 — 안 고른 상태의 키를 "B.Muted" 로. 이웃과 같은 토큰이라 테마 전환도 따라간다.
② 기본값 자체 — 색도 키도 없으면 이제 B.Muted 리소스 참조로 떨어진다.
   검정은 다크 테마에서 아이콘을 숨기는 기본값이라 함정으로 남겨 둘 이유가 없다.
   null 을 넘기던 호출부는 ①이 유일했으므로 다른 곳의 색은 바뀌지 않는다.

## 확인 방법도 고쳤다

이번에는 제목줄을 잘라 3배로 키워 다크·라이트 양쪽을 눈으로 대조했다.
전에는 대화상자 사진만 보고 제목줄은 마크업으로 판단했다 — 그래서 놓쳤다.
회귀 방지로 edit-smoke 에 "아이콘 기본색이 하드코딩 검정이 아니다" 를 넣는다.

## 판정

- 단위 시험 388 · edit-smoke 377건 전건 통과 (아이콘 색 1건 추가)
- CS8604 경고 소멸
- --dialog-shots 69장 · --modal-check · --maxrect · --scale-budget 전건 통과
- --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-20 17:56:36 +09:00
co-authored by Claude Fable 5
parent 33461a6c67
commit 13edf3ecd9
3 changed files with 53 additions and 2 deletions
+15 -1
View File
@@ -168,6 +168,15 @@ public static class LucideIcons
return new Viewbox { Width = size, Height = size, Child = canvas, Stretch = Stretch.Uniform, SnapsToDevicePixels = true };
}
/// <summary>
/// 아이콘 색 칠하기 — 키가 있으면 리소스 참조(테마 추종), 없으면 넘겨받은 브러시.
///
/// <b>둘 다 없으면 검정이 아니라 B.Muted 다.</b> 전에는 <c>Brushes.Black</c> 으로 떨어졌는데,
/// 그건 다크 테마에서 <b>아이콘을 보이지 않게 만드는</b> 기본값이다.
/// 실제로 제목줄의 환자 아이콘이 그 경로로 혼자만 까맣게 묻혀 있었고,
/// 컴파일러가 CS8604 로 그 자리를 계속 가리키고 있었는데도 오래 남아 있었다.
/// 기본값을 테마 토큰으로 두면 어느 호출부도 같은 함정에 빠질 수 없다.
/// </summary>
private static void Paint(Path path, DependencyProperty property, Brush? color, string? brushKey)
{
if (brushKey is not null)
@@ -175,7 +184,12 @@ public static class LucideIcons
path.SetResourceReference(property, brushKey);
return;
}
path.SetValue(property, color ?? Brushes.Black);
if (color is not null)
{
path.SetValue(property, color);
return;
}
path.SetResourceReference(property, "B.Muted");
}
private static (GeometryGroup Stroke, GeometryGroup Fill) Parse(string markup)
@@ -36,6 +36,23 @@ public static class EditSmoke
/// 종이에 실제로 그려진 글자를 모은다 — 값이 <b>찍혔는지</b>는 시각 트리에서 확인해야 한다.
/// VM 속성만 보면 템플릿이 그 값을 쓰는지 알 수 없다(배선과 결과는 다른 문제다).
/// </summary>
/// <summary>시각 트리에서 Path 를 전부 모은다 — 아이콘 색 검사에 쓴다</summary>
private static IEnumerable<System.Windows.Shapes.Path> FindPaths(System.Windows.DependencyObject node)
{
if (node is System.Windows.Shapes.Path path)
{
yield return path;
}
// 아이콘은 Viewbox → Canvas → Path 라 논리 자식을 훑어야 한다(시각 트리는 아직 안 만들어졌다)
foreach (var child in System.Windows.LogicalTreeHelper.GetChildren(node).OfType<System.Windows.DependencyObject>())
{
foreach (var found in FindPaths(child))
{
yield return found;
}
}
}
private static string CollectText(System.Windows.DependencyObject node)
{
var text = node is System.Windows.Controls.TextBlock block ? block.Text + "\n" : string.Empty;
@@ -1095,6 +1112,22 @@ public static class EditSmoke
$"ValueText='{choiceRow.ValueText}' IsMixed={choiceRow.IsMixed}");
}
// 15-a00) 아이콘 기본색이 검정으로 떨어지지 않는다.
//
// 색도 리소스 키도 안 준 아이콘이 <c>Brushes.Black</c> 으로 칠해지고 있었다.
// 다크 테마에서 그건 <b>안 보이는 아이콘</b>이라는 뜻이다 — 제목줄의 환자 아이콘이
// 정확히 그 상태로, 옆 아이콘들이 B.Muted 로 밝게 그려지는 사이에서 혼자 까맸다.
// 컴파일러가 CS8604 로 그 자리를 가리키고 있었는데도 오래 남아 있었다.
{
var iconVisual = Controls.LucideIcons.Icon("user", 16, (System.Windows.Media.Brush?)null);
var painted = FindPaths(iconVisual).ToList();
Check("아이콘: 기본색이 하드코딩 검정이 아니다",
painted.Count > 0 && painted.All(p =>
!ReferenceEquals(p.Stroke, System.Windows.Media.Brushes.Black)
&& !ReferenceEquals(p.Fill, System.Windows.Media.Brushes.Black)),
$"경로 {painted.Count}개");
}
// 15-a0) 선택 확장 — 정렬·간격 명령이 전제하는 '올바른 선택'을 만드는 수단.
//
// 마퀴는 <b>교차</b> 판정이라 행 띠를 스치는 것이 전부 딸려 온다(실측 787건:
+5 -1
View File
@@ -136,7 +136,11 @@ public partial class MainView : Window
return;
}
var on = PatientSession.HasPatient;
PatientIconButton.Content = Controls.LucideIcons.Icon("user", 16, on ? "B.Accent" : null);
// 안 고른 상태의 색은 <b>B.Muted</b> 다 — 옆 아이콘들(복사·삭제·테마·저장)이 XAML 컨버터의
// 기본값으로 쓰는 바로 그 키다. 전에는 null 을 넘겼고, 그러면 아이콘이 테마 토큰이 아니라
// 하드코딩 검정으로 칠해져 어두운 제목줄에서 <b>혼자만 까맣게</b> 묻혔다.
// (컴파일러가 CS8604 로 계속 경고하고 있었는데 그 경고가 가리키던 것이 이것이다.)
PatientIconButton.Content = Controls.LucideIcons.Icon("user", 16, on ? "B.Accent" : "B.Muted");
PatientIconButton.ToolTip = on
? $"환자: {PatientSession.Label}\n누르면 바꾸기·해제"
: "환자 선택 — 태그와 MDataTable 에 실제 값이 들어갑니다(앱 전체 적용)";