정렬 기준을 고를 수 있게 + 간격 균등 + 아이콘 되돌리기
"전체 선택 후 오브젝트끼리 정렬 / 페이지에서 정렬" — 둘 다 필요한데 하나만 됐다. 직전 커밋의 규칙은 자동이었다: 여럿이면 무조건 선택 영역, 하나면 무조건 부모/페이지. 여럿을 골라 놓고 종이에 맞추고 싶을 때 방법이 없었다. 기준을 명시적으로 고르게 했다. 인스펙터 정렬 행 아래에 알약 둘 — 왼쪽은 선택에 따라 문구가 바뀐다(여럿이면 '선택 영역', 컨테이너 안의 하나면 '부모'), 오른쪽은 '페이지'. 최상위 컨트롤 하나만 골랐을 때는 이 줄을 아예 접는다 — 그 경우 '선택 영역'도 곧 페이지라 알약 둘이 똑같은 말을 하게 된다(실제로 그렇게 렌더돼서 접기로 했다). 컨테이너 안의 것을 페이지 기준으로 맞추면 부모 밖으로 나간다. 막지는 않는다 — 사용자가 고른 것이고 되돌릴 수 있다 — 대신 '페이지' 알약 툴팁이 그 사실을 말한다. 간격 균등 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:
co-authored by
Claude Opus 5
parent
26f696ab00
commit
7f8808eb44
@@ -84,9 +84,9 @@ public static class LucideIcons
|
||||
["moon"] = """<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />""",
|
||||
["move-horizontal"] = """<polyline points="18 8 22 12 18 16" /> <polyline points="6 8 2 12 6 16" /> <line x1="2" x2="22" y1="12" y2="12" />""",
|
||||
["move-vertical"] = """<polyline points="8 18 12 22 16 18" /> <polyline points="8 6 12 2 16 6" /> <line x1="12" x2="12" y1="2" y2="22" />""",
|
||||
["align-obj-top"] = """<rect x="4.5" y="4.5" width="15" height="4.5" /> <line x1="3" x2="21" y1="4.5" y2="4.5" />""",
|
||||
["align-obj-middle"] = """<rect x="4.5" y="7.5" width="15" height="9" /> <line x1="3" x2="21" y1="12" y2="12" />""",
|
||||
["align-obj-bottom"] = """<rect x="4.5" y="15" width="15" height="4.5" /> <line x1="3" x2="21" y1="19.5" y2="19.5" />""",
|
||||
["align-obj-top"] = """<line x1="3" x2="21" y1="4" y2="4" /> <rect x="6" y="7" width="4" height="9" rx="1" /> <rect x="14" y="7" width="4" height="13" rx="1" />""",
|
||||
["align-obj-middle"] = """<line x1="3" x2="21" y1="12" y2="12" /> <rect x="6" y="4" width="4" height="6" rx="1" /> <rect x="14" y="14" width="4" height="6" rx="1" />""",
|
||||
["align-obj-bottom"] = """<line x1="3" x2="21" y1="20" y2="20" /> <rect x="6" y="8" width="4" height="9" rx="1" /> <rect x="14" y="4" width="4" height="13" rx="1" />""",
|
||||
["distribute-h"] = """<rect x="3" y="7" width="3.5" height="10" rx="1" /> <rect x="10.25" y="7" width="3.5" height="10" rx="1" /> <rect x="17.5" y="7" width="3.5" height="10" rx="1" />""",
|
||||
["distribute-v"] = """<rect x="7" y="3" width="10" height="3.5" rx="1" /> <rect x="7" y="10.25" width="10" height="3.5" rx="1" /> <rect x="7" y="17.5" width="10" height="3.5" rx="1" />""",
|
||||
["square"] = """<rect width="18" height="18" x="3" y="3" rx="2" />""",
|
||||
@@ -94,9 +94,9 @@ public static class LucideIcons
|
||||
["unlock"] = """<rect width="18" height="11" x="3" y="11" rx="2" ry="2" /> <path d="M7 11V7a5 5 0 0 1 9.9-1" />""",
|
||||
["group"] = """<path d="M3 7V5a2 2 0 0 1 2-2h2" /> <path d="M17 3h2a2 2 0 0 1 2 2v2" /> <path d="M21 17v2a2 2 0 0 1-2 2h-2" /> <path d="M7 21H5a2 2 0 0 1-2-2v-2" /> <rect width="7" height="5" x="7" y="7" rx="1" /> <rect width="7" height="5" x="10" y="12" rx="1" />""",
|
||||
["ungroup"] = """<rect width="8" height="6" x="5" y="4" rx="1" /> <rect width="8" height="6" x="11" y="14" rx="1" />""",
|
||||
["align-obj-left"] = """<rect x="4.5" y="4.5" width="4.5" height="15" /> <line x1="4.5" x2="4.5" y1="3" y2="21" />""",
|
||||
["align-obj-center-h"] = """<rect x="7.5" y="4.5" width="9" height="15" /> <line x1="12" x2="12" y1="3" y2="21" />""",
|
||||
["align-obj-right"] = """<rect x="15" y="4.5" width="4.5" height="15" /> <line x1="19.5" x2="19.5" y1="3" y2="21" />""",
|
||||
["align-obj-left"] = """<line x1="4" x2="4" y1="3" y2="21" /> <rect x="7" y="6" width="9" height="4" rx="1" /> <rect x="7" y="14" width="13" height="4" rx="1" />""",
|
||||
["align-obj-center-h"] = """<line x1="12" x2="12" y1="3" y2="21" /> <rect x="6" y="6" width="12" height="4" rx="1" /> <rect x="3" y="14" width="18" height="4" rx="1" />""",
|
||||
["align-obj-right"] = """<line x1="20" x2="20" y1="3" y2="21" /> <rect x="11" y="6" width="9" height="4" rx="1" /> <rect x="7" y="14" width="13" height="4" rx="1" />""",
|
||||
["droplet"] = """<path d="M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z" />""",
|
||||
["rotate-cw"] = """<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" /> <path d="M21 3v5h-5" />""",
|
||||
["frame"] = """<line x1="22" x2="2" y1="6" y2="6" /> <line x1="22" x2="2" y1="18" y2="18" /> <line x1="6" x2="6" y1="2" y2="22" /> <line x1="18" x2="18" y1="2" y2="22" />""",
|
||||
|
||||
@@ -1138,6 +1138,25 @@ public static class EditSmoke
|
||||
Check("정렬: 실행취소 1회로 되돌아온다", restored is not null && restored.X == beforeUndoX,
|
||||
$"실제 {restored?.X}");
|
||||
|
||||
// 기준 전환 — 여럿을 골라 놓고 '서로 맞추기'와 '종이에 맞추기'가 갈린다
|
||||
var a = Put(300, 500, 60, 20);
|
||||
var b = Put(340, 540, 60, 20);
|
||||
alignDoc.Selection.Set(new List<ControlViewModel> { a, b }, a);
|
||||
|
||||
alignDoc.AlignToPage = false;
|
||||
alignDoc.Align("Left");
|
||||
Check("정렬: 여럿을 서로 맞추면 선택 영역 왼쪽", a.X == 300 && b.X == 300,
|
||||
$"실제 {a.X} / {b.X}");
|
||||
|
||||
alignDoc.AlignToPage = true;
|
||||
alignDoc.Align("Left");
|
||||
Check("정렬: 기준을 페이지로 바꾸면 종이 왼쪽", a.X == 0 && b.X == 0, $"실제 {a.X} / {b.X}");
|
||||
|
||||
alignDoc.Align("Right");
|
||||
Check("정렬: 페이지 기준 오른쪽", a.X == page0.WidthDip - a.Width && b.X == page0.WidthDip - b.Width,
|
||||
$"실제 {a.X} / {b.X}");
|
||||
alignDoc.AlignToPage = false;
|
||||
|
||||
// 컨테이너 자식은 페이지가 아니라 부모가 기준 — 페이지 기준이면 X 가 음수가 된다
|
||||
var nestDoc = new DesignerViewModel(business.CreateNew());
|
||||
nestDoc.AddControlAt("Panel", new Point(120, 90));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -65,11 +65,61 @@ public sealed class InspectorViewModel : ViewModelBase
|
||||
? AlignScopeText
|
||||
: "여러 페이지에 걸친 선택은 세로 정렬을 할 수 없습니다";
|
||||
|
||||
/// <summary>'선택 영역' 세그먼트 문구 — 하나만 골랐으면 그건 부모(또는 페이지)다</summary>
|
||||
public string AlignSelectionScopeLabel => designer.AlignSelectionScopeLabel();
|
||||
|
||||
/// <summary>
|
||||
/// 기준 선택 줄을 보일 것인가 — 고를 것이 둘일 때만.
|
||||
/// 최상위 컨트롤 하나를 골랐으면 '선택 영역'도 곧 페이지라 알약 둘이 똑같은 말을 하게 된다.
|
||||
/// </summary>
|
||||
public bool ShowAlignScope => designer.Selection.Items.Count >= 2
|
||||
|| (designer.Selection.Items.Count == 1 && designer.Selection.Items[0].Parent is not null);
|
||||
|
||||
/// <summary>컨테이너 안의 것을 페이지에 맞추면 부모 밖으로 나간다 — 막지는 않되 말은 해 준다</summary>
|
||||
public string PageScopeTip => designer.Selection.Items.Count == 1
|
||||
&& designer.Selection.Items[0].Parent is not null
|
||||
? "종이 기준으로 맞춥니다 — 부모 밖으로 나가면 실행 시 잘릴 수 있습니다"
|
||||
: "종이 기준으로 맞춥니다";
|
||||
|
||||
/// <summary>기준 = 선택 영역(또는 부모)</summary>
|
||||
public bool AlignToSelection
|
||||
{
|
||||
get => !designer.AlignToPage;
|
||||
set
|
||||
{
|
||||
if (value && designer.AlignToPage)
|
||||
{
|
||||
designer.AlignToPage = false;
|
||||
NotifyAlignScope();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>기준 = 페이지</summary>
|
||||
public bool AlignToPage
|
||||
{
|
||||
get => designer.AlignToPage;
|
||||
set
|
||||
{
|
||||
if (value && !designer.AlignToPage)
|
||||
{
|
||||
designer.AlignToPage = true;
|
||||
NotifyAlignScope();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>간격 균등 버튼을 보일 것인가 — 사이가 있어야 나눌 것이 있다(3개 이상)</summary>
|
||||
public bool CanDistribute => designer.CanDistribute();
|
||||
|
||||
/// <summary>
|
||||
/// 정렬 실행 — 뷰의 DataContext 가 인스펙터라 디자이너 커맨드에 직접 닿을 수 없어 위임한다.
|
||||
/// </summary>
|
||||
public M.Framework.WPF.ICustomCommand AlignCommand { get; }
|
||||
|
||||
/// <summary>간격 균등 실행 — 위와 같은 이유로 위임</summary>
|
||||
public M.Framework.WPF.ICustomCommand DistributeCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 선택된 탭. 컨트롤을 바꿔도 유지된다 — 데이터 탭에서 여러 컨트롤의 태그를 잇달아 손보는
|
||||
/// 작업이 흔한데, 선택할 때마다 디자인 탭으로 되돌아가면 매번 다시 눌러야 한다.
|
||||
@@ -173,12 +223,28 @@ public sealed class InspectorViewModel : ViewModelBase
|
||||
this.designer = designer;
|
||||
AlignCommand = new M.Framework.WPF.Command(
|
||||
(object parameter) => designer.Align(parameter as string ?? string.Empty));
|
||||
DistributeCommand = new M.Framework.WPF.Command(
|
||||
(object parameter) => designer.AdjustSpacing(parameter as string ?? string.Empty));
|
||||
designer.Selection.SetChanged += Rebuild;
|
||||
designer.Selection.Changed += RefreshBoundsRows; // 드래그/리사이즈 중 X/Y/W/H 실시간 갱신
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>정렬 기준에 딸린 표시들 — 선택이 바뀌거나 기준 토글을 누를 때 함께 움직인다</summary>
|
||||
private void NotifyAlignScope()
|
||||
{
|
||||
OnPropertyChanged(nameof(CanAlignVertical));
|
||||
OnPropertyChanged(nameof(CanDistribute));
|
||||
OnPropertyChanged(nameof(AlignScopeText));
|
||||
OnPropertyChanged(nameof(VerticalScopeText));
|
||||
OnPropertyChanged(nameof(AlignSelectionScopeLabel));
|
||||
OnPropertyChanged(nameof(ShowAlignScope));
|
||||
OnPropertyChanged(nameof(PageScopeTip));
|
||||
OnPropertyChanged(nameof(AlignToSelection));
|
||||
OnPropertyChanged(nameof(AlignToPage));
|
||||
}
|
||||
|
||||
/// <summary>경계(X/Y/W/H) 행 값만 갱신 — 이동/리사이즈 프레임(재구성 없이 가볍게)</summary>
|
||||
private void RefreshBoundsRows()
|
||||
{
|
||||
@@ -203,9 +269,7 @@ public sealed class InspectorViewModel : ViewModelBase
|
||||
OnPropertyChanged(nameof(Summary));
|
||||
OnPropertyChanged(nameof(HasSelection));
|
||||
OnPropertyChanged(nameof(ShowAlignBar));
|
||||
OnPropertyChanged(nameof(CanAlignVertical));
|
||||
OnPropertyChanged(nameof(AlignScopeText));
|
||||
OnPropertyChanged(nameof(VerticalScopeText));
|
||||
NotifyAlignScope();
|
||||
|
||||
var items = designer.Selection.Items;
|
||||
if (items.Count == 0)
|
||||
|
||||
@@ -132,6 +132,42 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- 정렬 기준 알약 — 둘 중 하나만 켜지는 선택지라 RadioButton 이다(토글 두 개면 둘 다 꺼질 수 있다) -->
|
||||
<Style x:Key="ScopePill" TargetType="RadioButton">
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FontSize" Value="11.5"/>
|
||||
<Setter Property="Margin" Value="0,0,4,0"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<Border x:Name="bd" Background="{DynamicResource B.Input}" CornerRadius="6"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource B.InputBorder}"
|
||||
Padding="9,3" SnapsToDevicePixels="True">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<ContentPresenter.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
|
||||
</Style>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Hover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="{DynamicResource B.Accent}"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="{DynamicResource B.Accent}"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- 세그먼트 한 칸 — 붙어 있는 아이콘 토글(굵게/기울임/밑줄/취소선) -->
|
||||
<!-- 폭 30 + 간격 2 = 4칸 128px. 라벨 92 와 합쳐 220px 라 패널 최소폭(250 → 행 가용 221)에 들어간다 -->
|
||||
<Style x:Key="SegmentToggle" TargetType="ToggleButton">
|
||||
@@ -655,7 +691,7 @@
|
||||
행 VM(Rows)이 아니라 여기 두는 이유 둘: AlignRowViewModel 은 이미 '텍스트 정렬'로
|
||||
이름과 템플릿을 선점했고, 정렬은 스크롤과 무관하게 늘 보이는 편이 조작에 맞다.
|
||||
-->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="12,2,10,8"
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="12,2,10,6"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
Visibility="{Binding ShowAlignBar, Converter={StaticResource BoolToVisibility}}">
|
||||
<Button Style="{StaticResource AlignBtn}" Command="{Binding AlignCommand}" CommandParameter="Left"
|
||||
@@ -671,10 +707,8 @@
|
||||
ToolTip="{Binding AlignScopeText, StringFormat=오른쪽 맞춤 — {0}}"
|
||||
Content="{Binding Source=align-obj-right, Converter={StaticResource IconName}, ConverterParameter=18|B.Muted}"/>
|
||||
|
||||
<!-- 가로 축과 세로 축을 눈으로 가르는 틈 — 참조 .align .gap{width:8px} -->
|
||||
<Border Width="8" Margin="0,0,2,0"/>
|
||||
|
||||
<Button Style="{StaticResource AlignBtn}" Command="{Binding AlignCommand}" CommandParameter="Top"
|
||||
<!-- 가로 축과 세로 축 사이 틈 8px — 참조 .align .gap -->
|
||||
<Button Style="{StaticResource AlignBtn}" Margin="8,0,2,0" Command="{Binding AlignCommand}" CommandParameter="Top"
|
||||
IsEnabled="{Binding CanAlignVertical}" AutomationProperties.Name="위 맞춤"
|
||||
ToolTip="{Binding VerticalScopeText, StringFormat=위 맞춤 — {0}}"
|
||||
Content="{Binding Source=align-obj-top, Converter={StaticResource IconName}, ConverterParameter=18|B.Muted}"/>
|
||||
@@ -686,6 +720,39 @@
|
||||
IsEnabled="{Binding CanAlignVertical}" AutomationProperties.Name="아래 맞춤"
|
||||
ToolTip="{Binding VerticalScopeText, StringFormat=아래 맞춤 — {0}}"
|
||||
Content="{Binding Source=align-obj-bottom, Converter={StaticResource IconName}, ConverterParameter=18|B.Muted}"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!--
|
||||
간격 균등 — 사이가 있어야 나눌 것이 있다(3개 이상). 없으면 회색으로 남기지 않고 접는다.
|
||||
정렬 6개와 같은 줄에 두면 8칸 276px 가 되어 패널 최소 폭(250)에서 잘린다 — 줄을 나눈다.
|
||||
-->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="12,0,10,6"
|
||||
Visibility="{Binding CanDistribute, Converter={StaticResource BoolToVisibility}}">
|
||||
<TextBlock Text="간격" VerticalAlignment="Center" FontSize="11.5" Margin="0,0,8,0"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
<Button Style="{StaticResource AlignBtn}" Command="{Binding DistributeCommand}" CommandParameter="HorizEqual"
|
||||
AutomationProperties.Name="가로 간격 균등" ToolTip="가로 간격을 고르게"
|
||||
Content="{Binding Source=distribute-h, Converter={StaticResource IconName}, ConverterParameter=18|B.Muted}"/>
|
||||
<Button Style="{StaticResource AlignBtn}" Command="{Binding DistributeCommand}" CommandParameter="VertEqual"
|
||||
AutomationProperties.Name="세로 간격 균등" ToolTip="세로 간격을 고르게"
|
||||
Content="{Binding Source=distribute-v, Converter={StaticResource IconName}, ConverterParameter=18|B.Muted}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!--
|
||||
정렬 기준 — 여럿을 골라 놓고도 '서로 맞추기'와 '종이에 맞추기'는 다른 작업이다.
|
||||
왼쪽 문구는 선택에 따라 바뀐다: 여럿이면 '선택 영역', 하나면 '부모'(또는 '페이지').
|
||||
-->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="12,0,10,10"
|
||||
Visibility="{Binding ShowAlignScope, Converter={StaticResource BoolToVisibility}}">
|
||||
<TextBlock Text="기준" VerticalAlignment="Center" FontSize="11.5" Margin="0,0,8,0"
|
||||
Foreground="{DynamicResource B.Muted}"/>
|
||||
<RadioButton Style="{StaticResource ScopePill}" GroupName="AlignScope"
|
||||
IsChecked="{Binding AlignToSelection, Mode=TwoWay}"
|
||||
Content="{Binding AlignSelectionScopeLabel}"/>
|
||||
<RadioButton Style="{StaticResource ScopePill}" GroupName="AlignScope"
|
||||
IsChecked="{Binding AlignToPage, Mode=TwoWay}" Content="페이지"
|
||||
ToolTip="{Binding PageScopeTip}"/>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
|
||||
Reference in New Issue
Block a user