페이지 속성 편집 — 레이어의 페이지 행을 고르면 속성 패널이 페이지를 연다
레거시에서 페이지는 MDesignerHost 라는 하나의 Object 이고 자기 속성을 갖는다. SheetMe 도 그 루트 노드를 FormPage.Root 로 통째로 보존해 왔고(그래서 운영 1,271건 왕복 diff 가 0이다), 값도 일부는 이미 쓰고 있었다 — BackColor 는 용지 배경으로 렌더하고 Font 는 자식이 상속한다. 없던 것은 편집 화면뿐이었다. 그 결과 용지 크기조차 바꿀 수 없는 상태였다. ApplyPaperSize 는 구현돼 있었지만 호출처가 편집 스모크뿐이고 메뉴·XAML 어디에도 배선이 없었다 — 새 서식은 720×856 고정으로만 시작했다. 레이어 아웃라인의 페이지 헤더 행을 누르면 선택을 비우고 속성 패널이 페이지 모드로 바뀐다. 컨트롤을 하나라도 고르면 자동으로 빠져나온다. 용지 너비·높이(한 줄), 배경색 기본 글꼴 글꼴·크기 — 여기를 바꾸면 Font 를 명시하지 않은 컨트롤이 전부 따라온다 전체 속성 나머지 원본 속성(레거시 PropertyGrid 등가) 저장 규약을 지켰다. writer 는 저장할 때 Size 를 Bounds 에서, Name 을 Id 에서 다시 만들어 덮으므로 그 두 키는 raw 편집 대상에서 뺐다 — 열어 두면 고쳐도 저장하면 되돌아간다. 크기는 raw Size 가 아니라 Bounds 를 고치고, 편집 결과가 저장 XML 의 Size 와 같은지 스모크로 못 박았다. 용지 크기가 바뀌면 페이지 스택 오프셋과 월드 크기를 다시 계산한다(여러 장이면 한 장의 높이 변화가 아래 페이지를 전부 밀어낸다). 기본 글꼴이 바뀌면 그 페이지 컨트롤의 상속 컨텍스트를 다시 흘린다. 편집 스모크에 페이지 속성 검사 11건 추가. 회귀: 테스트 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
f5cce00019
commit
38093691ad
@@ -77,6 +77,7 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
// 레이어 목록 상태 — 접힌 그룹과 타입 필터는 문서가 아니라 편집 세션에 속한다(Undo 대상 아님)
|
||||
private readonly HashSet<string> collapsedGroups = new(StringComparer.Ordinal);
|
||||
private readonly HashSet<PageViewModel> collapsedPages = new();
|
||||
private PageViewModel? inspectedPage;
|
||||
private readonly HashSet<string> layerTypeFilter = new(StringComparer.Ordinal);
|
||||
private readonly List<System.Collections.Specialized.INotifyCollectionChanged> watchedControls = new();
|
||||
#endregion
|
||||
@@ -275,6 +276,9 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
Interaction = new InteractionController(this);
|
||||
Inspector = new InspectorViewModel(this);
|
||||
Selection.Changed += RefreshOverlay;
|
||||
// 순서 주의 — 인스펙터가 Rebuild 하기 전에 페이지 모드를 걷어야 한다
|
||||
// (Inspector 는 생성자 안에서 SetChanged 를 구독하므로 여기가 먼저다)
|
||||
Selection.SetChanged += ClearInspectedPageOnSelection;
|
||||
Selection.SetChanged += LayerSelectionChanged;
|
||||
|
||||
UndoCommand = new Command((sender, e) => Undo.Undo());
|
||||
@@ -502,6 +506,33 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
OnPropertyChanged(nameof(WorldHeight));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 용지 크기가 바뀐 뒤 — 페이지 스택 오프셋과 월드 크기를 다시 계산한다.
|
||||
/// 페이지가 여러 장이면 한 장의 높이 변화가 아래 페이지 전부를 밀어낸다.
|
||||
/// </summary>
|
||||
public void NotifyPaperResized()
|
||||
{
|
||||
RecalcPageOffsets();
|
||||
OnPropertyChanged(nameof(WorldWidth));
|
||||
OnPropertyChanged(nameof(WorldHeight));
|
||||
RefreshOverlay();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 페이지 기본 글꼴이 바뀐 뒤 — 그 페이지 컨트롤의 상속 컨텍스트를 다시 흘린다.
|
||||
/// Font 를 명시하지 않은 컨트롤은 루트 글꼴을 물려받으므로 값 하나가 화면 전체를 바꾼다.
|
||||
/// </summary>
|
||||
public void RefreshPageInheritance(PageViewModel page)
|
||||
{
|
||||
var rootFontText = page.Model.Root.Props.GetText("Font");
|
||||
var rootFont = rootFontText is not null ? LegacyFormat.ParseFont(rootFontText) : new LegacyFont();
|
||||
foreach (var control in page.Controls)
|
||||
{
|
||||
control.ResolveVisualContext(rootFont, control.ParentForeground);
|
||||
}
|
||||
RefreshOverlay();
|
||||
}
|
||||
|
||||
/// <summary>문서 교체 후 재구성 — Undo 복원 경로</summary>
|
||||
public void ReplaceDocument(FormDocument newDocument)
|
||||
{
|
||||
@@ -1773,13 +1804,20 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>페이지 헤더 행 클릭 — 활성 페이지로 삼고 캔버스를 그 페이지로 옮긴다</summary>
|
||||
/// <summary>
|
||||
/// 페이지 헤더 행 클릭 — 활성 페이지로 삼고, 캔버스를 그 페이지로 옮기고, 속성 패널을 페이지로 돌린다.
|
||||
///
|
||||
/// 페이지도 레거시에서는 하나의 <c>Object</c>(MDesignerHost)라 자기 속성을 갖는다.
|
||||
/// 컨트롤을 하나도 고르지 않은 상태에서만 페이지 속성을 보여주므로 선택은 비운다.
|
||||
/// </summary>
|
||||
public void ActivatePage(PageViewModel page)
|
||||
{
|
||||
if (!ReferenceEquals(SelectedPage, page))
|
||||
{
|
||||
SelectedPage = page;
|
||||
}
|
||||
Selection.Clear();
|
||||
InspectedPage = page;
|
||||
foreach (var header in LayerRows.OfType<LayerPageViewModel>())
|
||||
{
|
||||
header.NotifyStateChanged();
|
||||
@@ -1787,6 +1825,32 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
ScrollToPageRequested?.Invoke(page);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 속성 패널이 들여다보는 페이지 — 컨트롤 선택이 없을 때만 유효하다.
|
||||
/// 컨트롤을 고르는 순간 <see cref="SelectionService.SetChanged"/> 경로에서 비워진다.
|
||||
/// </summary>
|
||||
public PageViewModel? InspectedPage
|
||||
{
|
||||
get => inspectedPage;
|
||||
private set
|
||||
{
|
||||
if (!ReferenceEquals(inspectedPage, value))
|
||||
{
|
||||
inspectedPage = value;
|
||||
Inspector.Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>선택이 생기면 페이지 속성 모드를 벗어난다</summary>
|
||||
private void ClearInspectedPageOnSelection()
|
||||
{
|
||||
if (inspectedPage is not null && Selection.Items.Count > 0)
|
||||
{
|
||||
inspectedPage = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>캔버스를 특정 페이지로 스크롤하라는 요청 — 뷰가 구독한다</summary>
|
||||
public event Action<PageViewModel>? ScrollToPageRequested;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user