정렬 기준을 고를 수 있게 + 간격 균등 + 아이콘 되돌리기

"전체 선택 후 오브젝트끼리 정렬 / 페이지에서 정렬" — 둘 다 필요한데 하나만 됐다.
직전 커밋의 규칙은 자동이었다: 여럿이면 무조건 선택 영역, 하나면 무조건 부모/페이지.
여럿을 골라 놓고 종이에 맞추고 싶을 때 방법이 없었다.

기준을 명시적으로 고르게 했다. 인스펙터 정렬 행 아래에 알약 둘 — 왼쪽은 선택에 따라
문구가 바뀐다(여럿이면 '선택 영역', 컨테이너 안의 하나면 '부모'), 오른쪽은 '페이지'.
최상위 컨트롤 하나만 골랐을 때는 이 줄을 아예 접는다 — 그 경우 '선택 영역'도 곧 페이지라
알약 둘이 똑같은 말을 하게 된다(실제로 그렇게 렌더돼서 접기로 했다).

컨테이너 안의 것을 페이지 기준으로 맞추면 부모 밖으로 나간다. 막지는 않는다 —
사용자가 고른 것이고 되돌릴 수 있다 — 대신 '페이지' 알약 툴팁이 그 사실을 말한다.

간격 균등 2개(가로·세로)를 붙였다. 3개 이상 골랐을 때만 나타난다 — 사이가 있어야 나눌 것이 있다.
정렬 6개와 같은 줄에 두면 8칸 276px 가 되어 패널 최소 폭 250 에서 잘리고, WrapPanel 로 흘리면
7+1 로 깨진다(둘 다 렌더로 확인했다). 그래서 '간격' 이라는 제 줄을 준다.

아이콘은 [200] 와이어프레임의 '사각형 하나 + 기준선'에서 원래 Lucide 도형
'길이 다른 막대 둘 + 기준선'으로 되돌렸다 — 후보 4종을 그려 고른 결과다.
막대가 둘이면 '무엇을 무엇에 맞추는가'가 도형만으로 읽히고, 저장소의 다른 아이콘과도 결이 맞는다.
LucideIcons 의 align-obj-* 6개는 직전 커밋 이전 상태로 정확히 복귀했다.

기준 알약은 RadioButton 이다. ToggleButton 둘로 만들면 둘 다 꺼진 상태가 표현 가능해지는데
그건 뜻이 없는 상태다.

게이트: 테스트 267/267, --edit-smoke 237건 0실패(기준 전환 검사 3건 신규),
--query-popup 17/17, --maxrect 10/10, --snap-shots 7종 0실패,
--db-smoke 3000 diff 0·예외 0, --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 동일,
--dialog-shots 57파일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-14 10:31:24 +09:00
co-authored by Claude Opus 5
parent 26f696ab00
commit 7f8808eb44
5 changed files with 205 additions and 15 deletions
@@ -74,6 +74,9 @@ public sealed class DesignerViewModel : ViewModelBase
private bool isTabOrderMode;
private readonly List<ControlViewModel> tabOrderSequence = new();
private readonly Dictionary<string, SpreadGridInfo>? spreadDesigns;
/// <summary>정렬을 페이지에 맞출 것인가 — 인스펙터 토글이 세운다</summary>
private bool alignToPage;
// 레이어 목록 상태 — 접힌 그룹과 타입 필터는 문서가 아니라 편집 세션에 속한다(Undo 대상 아님)
private readonly HashSet<string> collapsedGroups = new(StringComparer.Ordinal);
private readonly HashSet<PageViewModel> collapsedPages = new();
@@ -1531,9 +1534,28 @@ public sealed class DesignerViewModel : ViewModelBase
Selection.NotifyBoundsChanged();
}
/// <summary>정렬 기준 사각형(월드) — 여럿이면 선택 영역, 하나면 그것을 담고 있는 것</summary>
/// <summary>
/// 정렬 기준 — 무엇에 맞출 것인가.
///
/// 여럿을 골라 놓고도 "서로 맞추기"와 "종이에 맞추기"는 다른 작업이다.
/// 예전에는 전자만 가능했다.
/// </summary>
public bool AlignToPage
{
get => alignToPage;
set => SetProperty(ref alignToPage, value);
}
/// <summary>정렬 기준 사각형(월드)</summary>
private SheetMe.Core.Layout.SnapRect? ReferenceFor(IReadOnlyList<ControlViewModel> targets)
{
if (alignToPage)
{
return PageOf(targets[0]) is { } target
? new SheetMe.Core.Layout.SnapRect(0, target.OffsetY, target.WidthDip, target.HeightDip)
: null;
}
if (targets.Count >= 2)
{
if (SelectionWorldBounds() is not { } bbox)
@@ -1579,6 +1601,10 @@ public sealed class DesignerViewModel : ViewModelBase
{
return string.Empty;
}
if (alignToPage)
{
return "페이지 기준";
}
if (items.Count >= 2)
{
return items.Select(PageOf).Distinct().Count() > 1
@@ -1591,6 +1617,20 @@ public sealed class DesignerViewModel : ViewModelBase
: "페이지 기준";
}
/// <summary>'선택 영역' 쪽 세그먼트에 뭐라고 쓸 것인가 — 하나만 골랐으면 그건 부모(또는 페이지)다</summary>
public string AlignSelectionScopeLabel()
{
var items = Selection.Items;
if (items.Count >= 2)
{
return "선택 영역";
}
return items.Count == 1 && items[0].Parent is not null ? "부모" : "페이지";
}
/// <summary>간격 균등이 뜻을 갖는가 — 사이가 있어야 나눌 것이 있다</summary>
public bool CanDistribute() => Selection.Items.Count >= 3;
/// <summary>세로 정렬이 가능한가 — 여러 페이지에 걸친 선택에서는 뜻이 없다</summary>
public bool CanAlignVertical()
=> Selection.Items.Count > 0 && Selection.Items.Select(PageOf).Distinct().Count() <= 1;