미리보기가 거짓말을 멈춘다, 그리고 9번째 컨트롤이 1번째를 덮지 않는다

3단계 시작 — 실사용 버그 두 건.

<b>① 미리보기·인쇄가 인쇄 필터를 무시하고 있었다.</b>
레거시 런타임은 인쇄에서 이렇게 걸러낸다 —
  If Me.Visible = False OrElse mbPrintOutPut = False Then Return False
그 문장이 ControlRegistry.cs:17 에 인용까지 되어 있는데, 렌더 경로가 두 키를 아무도 읽지 않았다.
대신 걸러낸 것은 ControlElement.Hidden 뿐이고 그건 [JsonIgnore] 디자이너 전용 플래그다
(주석에도 "레거시 Visible 과 별개"라고 적혀 있다).
그래서 인스펙터에서 '인쇄 출력'을 꺼도 미리보기에 그대로 나왔다 —
서식을 저장하기 전에 결과를 확인할 유일한 수단이 거짓말을 하고 있었다.

<b>키 이름이 타입마다 다르다.</b> 라벨만 소문자 visible 이다
(Label.vb 가 Shadows Property visible 로 Control.Visible 을 가리고 직렬화기가 그림자를 쓴다).
운영에서 소문자 58,864건(99.7%) 대 대문자 196건이다.
그래서 관용으로 둘 다 읽지 않는다 — 타입이 선언한 키를 카탈로그에서 찾아 그것만 읽는다.
둘 다 읽으면 대문자 Visible=False 인 라벨이 우리 인쇄에서만 빠지고, 그건 호환이 아니라 새 차이다.
모르는 값과 없는 키는 인쇄한다 — 내용을 조용히 빼는 것이 조용히 넣는 것보다 나쁘다.

캔버스는 그대로 다 보여 준다. 편집 중인 것을 못 보면 고칠 수 없다.
--db-render 는 이 경로를 쓰지 않아 종이 렌더 md5 는 불변이다(확인했다).

<b>② 팔레트 즉시 배치가 9번째부터 겹쳤다.</b>
(page.Controls.Count % 8) * 16 이라 두 가지가 틀렸다 —
9번째가 1번째와 정확히 같은 자리에 떨어지고, 하나 지우고 다시 놓으면 지운 자리로 갔다.
단조 증가 카운터로 바꿨다. 계단은 종이를 벗어나기 전에 옆으로 비킨다.

<b>순수 함수 테스트만으로는 배선을 증명하지 못한다.</b>
PrintFilter 단위 테스트 8건은 판정이 옳다는 것만 말한다. 렌더 경로가 그 판정을 부르는지는
다른 문제이고, 이 앱에서 "코드는 맞아 보이는데 화면은 다른" 일이 이번 세션에만 세 번 있었다.
그래서 --edit-smoke 에서 BuildPageVisual 의 자식 수를 실제로 세는 검사 3건을 더했다.

게이트: 테스트 285/285(신규 8), --edit-smoke 0실패(신규 5),
--dialog-shots 넘침 0(대조군 4/4), --scale-budget 5/5, --maxrect 0실패,
--cleartype 11/11, --modal-check 0실패, 빌드 경고 0,
--db-smoke 1271건 diff 0, --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 동일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-14 17:01:46 +09:00
co-authored by Claude Opus 5
parent d55ca39e6a
commit 1b49f07dd9
5 changed files with 251 additions and 4 deletions
@@ -65,6 +65,12 @@ public sealed class DesignerViewModel : ViewModelBase
private const double PageGap = 28;
private const double WorldPad = 24;
private static readonly List<ControlElement> clipboard = new();
/// <summary>한 계단에 몇 번 내려간 뒤 옆으로 비키는가 — 종이를 벗어나기 전에 접는다</summary>
private const int PlacementLaneSteps = 12;
/// <summary>팔레트 즉시 배치 계단 — 지우고 다시 놓아도 같은 자리로 돌아가지 않게 단조 증가한다</summary>
private int placementStep;
private double zoom = 1.0;
private FormDocument document;
private PageViewModel? selectedPage;
@@ -1153,8 +1159,18 @@ public sealed class DesignerViewModel : ViewModelBase
{
return;
}
var offset = (page.Controls.Count % 8) * 16;
AddControlAt(type, new Point(page.WidthDip / 2 + offset, page.OffsetY + page.HeightDip / 3 + offset));
// 겹침 방지 오프셋은 <b>단조 증가하는 자체 카운터</b>로 센다.
//
// 전에는 (page.Controls.Count % 8) * 16 이었다. 두 가지가 잘못이다 —
// ① % 8 이라 <b>9번째가 1번째와 정확히 같은 자리</b>에 떨어진다.
// ② Controls.Count 를 쓰므로 하나 지우고 다시 놓으면 지운 것과 같은 자리로 간다.
// 계단은 종이를 벗어나기 전에 접는다 — 접히더라도 방금 놓은 것 위로는 가지 않는다.
var step = placementStep++;
var lane = step / PlacementLaneSteps;
var offset = (step % PlacementLaneSteps) * 16;
AddControlAt(type, new Point(
page.WidthDip / 2 + offset + (lane * 12),
page.OffsetY + page.HeightDip / 3 + offset));
}
/// <summary>팔레트 드롭 — 월드 좌표에 신규 컨트롤 생성(모델 index 0 = 최상위)</summary>