쿼리 편집기 — 한글에서 색과 글자가 어긋나던 문제, 다크 제목 표시줄, 목업 맞춤
■ 한글을 치면 색칠이 글자와 어긋났다 (가장 중요) 색칠 레이어가 글자 위치를 <b>직접 재서</b> 잡고 있었다. 앞부분을 FormattedText 로 측정해 그 폭만큼 오른쪽으로 옮겨 그리는 방식이다. ASCII 에서는 맞았지만 한글에서 무너졌다 — 편집 글꼴(Consolas)에 한글 글리프가 없어 폰트 대체가 일어나는데, TextBox 의 내부 조판과 이쪽 측정이 같은 글꼴·같은 셰이핑을 고르리라는 보장이 없다. 조금만 달라도 뒤로 갈수록 벌어져 색과 글자가 따로 논다. 이제 <b>TextBox 에게 좌표를 묻는다</b>(GetRectFromCharacterIndex). 여백·스크롤·줄 높이·폰트 대체가 전부 TextBox 기준으로 이미 반영돼 오고, 조각마다 위치를 새로 물으므로 오차가 누적되지 않는다. 줄 높이를 손으로 계산하던 코드도 함께 사라졌다. 편집 글꼴 순서도 한글이 있는 것(D2Coding → 굴림체 → Consolas)으로 바꿔 대체 자체를 줄였다. --query-popup 진단에 정렬 검사 2건을 넣었다: 한글이 섞인 줄에서 글자 좌표가 뒤로 밀리지 않는가, 마지막 글자 다음 좌표가 캐럿 자리와 이어지는가. 현재 9/9. ■ 다크 모드인데 제목 표시줄만 밝게 남던 문제 ThemedWindow 스타일은 창 <b>안쪽</b>만 칠한다. 제목 표시줄은 OS 가 그리고 기본값은 Windows 의 테마를 따르므로, 앱을 다크로 바꿔도 Windows 가 라이트면 흰 띠가 남는다. DWM 속성(DWMWA_USE_IMMERSIVE_DARK_MODE)으로 창별로 지정한다. 커스텀 크롬을 직접 그리는 것보다 훨씬 싸고, 최소화·최대화·닫기의 동작과 접근성이 OS 것 그대로 남는다. 창마다 손으로 넣으면 새 대화상자에서 반드시 빠지므로 App 에서 Window 클래스 핸들러로 한 번만 걸었다 — 지금 있는 창과 앞으로 만들 창 모두 자동으로 적용된다. 테마를 바꾸는 순간 이미 떠 있는 창들도 함께 맞춘다(ThemeManager.ApplyChromeToOpenWindows). ■ 목업과 위치 맞춤 앞 배지(아이콘) · 검색칸의 돋보기와 안내 문구 · 안내 상자의 ⓘ 를 넣었다. 갈래 칩 순서는 개수순에서 <b>고정 순서</b>(환자·서식·작업자·컨트롤)로 바꿨다 — 컨트롤 수는 서식마다 달라서 개수순으로 두면 서식을 바꿀 때마다 칩이 자리를 바꿔 손이 기억하지 못한다. 회귀: 테스트 230/230, 편집 스모크 실패 0, 팝업·정렬 점검 9/9, 검증 실행 점검 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
68fc01c6ba
commit
3e26af8739
@@ -701,6 +701,35 @@ public static class DbSmoke
|
||||
// ⑦ 바깥 클릭으로 닫히는 설정인지
|
||||
Check("바깥 클릭으로 닫히는 설정(StaysOpen=False)", !popup.StaysOpen);
|
||||
|
||||
// ⑧ 색칠 레이어와 실제 글자 위치가 맞는지 — 한글이 섞이면 폰트 대체 때문에 어긋났었다.
|
||||
// 레이어는 TextBox 에게 좌표를 물으므로, 같은 인덱스의 사각형이 곧 그리는 자리다.
|
||||
// 여기서는 '캐럿이 글자 끝에 있을 때 그 x 가 앞 글자들 폭의 합과 단조 증가하는가'를 본다.
|
||||
Type("SELECT ㄴㅁㅇㄹ FROM ㅎㄱ");
|
||||
var xs = new List<double>();
|
||||
for (var i = 0; i <= box.Text.Length; i++)
|
||||
{
|
||||
var r = box.GetRectFromCharacterIndex(i);
|
||||
xs.Add(r.IsEmpty ? double.NaN : r.X);
|
||||
}
|
||||
var monotonic = true;
|
||||
for (var i = 1; i < xs.Count; i++)
|
||||
{
|
||||
if (!double.IsNaN(xs[i]) && !double.IsNaN(xs[i - 1]) && xs[i] < xs[i - 1] - 0.01)
|
||||
{
|
||||
monotonic = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Check("한글 섞인 줄에서 글자 좌표가 뒤로 밀리지 않는다", monotonic,
|
||||
$"첫 x {xs[0]:F1} → 끝 x {xs[^1]:F1}");
|
||||
|
||||
// 마지막 글자의 오른쪽 끝이 캐럿 자리와 같아야 한다(레이어가 이 값으로 그린다)
|
||||
var lastCharRect = box.GetRectFromCharacterIndex(box.Text.Length - 1);
|
||||
var caretRect = box.GetRectFromCharacterIndex(box.Text.Length);
|
||||
Check("마지막 글자 다음 좌표가 캐럿 자리와 이어진다",
|
||||
!lastCharRect.IsEmpty && !caretRect.IsEmpty && caretRect.X >= lastCharRect.X,
|
||||
$"글자 {lastCharRect.X:F1} / 캐럿 {caretRect.X:F1}");
|
||||
|
||||
window.Close();
|
||||
DrainDispatcher();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user