캔버스·인스펙터 잔손질 넷 — 마퀴·치수 칩·죽은 버튼·잘린 설명
## 패널 안에 그린 마퀴가 아무것도 안 잡았다 마퀴가 최상위만 훑고 컨테이너 안으로 안 들어갔다. 패널 안 체크박스 5개를 한 번에 고르려고 안쪽을 끌면 패널만 잡히거나 아무것도 안 잡혀서, Ctrl+클릭 반복이나 레이어 목록으로 우회했다. 컨테이너 자식은 전체 컨트롤의 <b>18.3%</b>(실측 18,749개/컨테이너 4,099개)라 드문 경우가 아니다. 규칙은 <b>'담김'</b>이다 — 마퀴가 컨테이너 사각형 안에 들어가 있으면 그 안의 것을 고른다 (내 상자가 패널보다 작으니 그 안을 고르려는 뜻이다). 걸치기만 하면 예전처럼 패널이 잡힌다. 모드도 수정키도 없이 <b>그린 모양만으로</b> 갈리므로 예측할 수 있다. 한 군데를 더 고쳐야 했다. 클릭 선택이 쓰는 GroupMatesOf 는 자식을 부모 컨테이너로 되돌리는데 (패널 안의 것을 집으면 패널이 움직여야 하므로 옳다) 마퀴가 그것을 그대로 쓰고 있었다 — 안쪽을 정확히 골라 놓고도 결과가 다시 패널 하나가 되어 위 규칙이 아무 일도 못 한다. 마퀴 전용 경로를 따로 뒀다. 걸치기 동작이 그대로인 것도 검사로 고정했다. ## 끄는 동안 숫자가 캔버스에 없었다 라벨 폭을 종이 칸에 맞추는 동안 숫자는 300px 떨어진 인스펙터에만 떴다 — 끌고, 손 떼고, 오른쪽 보고, 다시 끈다. 간격 수치 칩은 <b>균등 스냅이 성립할 때만</b> 나타나므로 "지금 이게 몇 px 인가"는 드래그 중에 알 방법이 아예 없었다. 이동이면 좌표, 크기 조절이면 크기를 보여 준다 — 지금 <b>바꾸고 있는 값</b>이 그것이다. 오버레이 층이라 종이에는 없고, 줌이 걸린 층이라 역배율로 글자 크기를 화면 고정으로 만든다. ## 눌러도 아무 일이 없는 ⋮ 버튼 Command·Click·ContextMenu 가 <b>전부 없었다</b>. 그런데 툴팁은 '이 컨트롤에 대한 명령'이라 "단일 선택일 때만 되는 뭔가가 있다"고 오해시켰다. 없는 버튼보다 죽은 버튼이 나쁘다 — 컨트롤 단위 명령은 캔버스 우클릭 메뉴에 이미 다 있다. ## 주석이 논증한 값과 실제 값이 달랐다 라벨 폭 주석이 "92px + 줄바꿈이면 두 줄로 접혀 전부 읽힌다"고 근거까지 적어 놓고 값은 72 였다. 그래서 '액션 대상 컨…' 처럼 잘렸다. 92 로 맞췄다. 같은 자리에서 설명 행(ReadOnlyRow)이 값처럼 잘리고 있었다 — "타입이 달라 값의 뜻이 다른 속성 2개 — 타입별로 따로 고르세요" 에서 <b>지시에 해당하는 뒷부분</b>이 사라져 무엇을 하라는 건지 알 수 없었다. 접어서 다 보여 준다. ## 판정 - 단위 시험 388 · edit-smoke 396건 전건 통과 (마퀴 2건 · 치수 칩 4건 추가) - --dialog-shots 69장 전건 통과 (인스펙터 8종을 눈으로 대조 — 라벨·설명 잘림 없음) - --modal-check · --maxrect · --scale-budget 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f6b456753c
commit
8c76a978a9
@@ -1112,6 +1112,73 @@ public static class EditSmoke
|
||||
$"ValueText='{choiceRow.ValueText}' IsMixed={choiceRow.IsMixed}");
|
||||
}
|
||||
|
||||
// 15-a0000000) 끄는 동안 치수·좌표가 캔버스에 보인다.
|
||||
//
|
||||
// 전에는 숫자가 300px 떨어진 인스펙터에만 떴다 — 끌고, 손 떼고, 오른쪽을 보고, 다시 끈다.
|
||||
// 간격 수치 칩은 균등 스냅이 성립할 때만 나타나므로 "지금 몇 px 인가"는 알 방법이 없었다.
|
||||
{
|
||||
var badge = new DesignerViewModel(new FormDesignDataBusiness().CreateNew());
|
||||
badge.AddControlAt("Label", new Point(80, 80));
|
||||
var one = badge.Pages[0].Controls[0];
|
||||
badge.Selection.SetSingle(one);
|
||||
Check("치수 칩: 평소에는 안 보인다", !badge.Overlay.ShowDragBadge);
|
||||
|
||||
var world = badge.WorldBoundsOf(one);
|
||||
var grab = new Point(world.X + world.Width / 2, world.Y + world.Height / 2);
|
||||
var noSnap = new PointerContext(false, false, true, 1);
|
||||
badge.Interaction.PointerDown(grab, noSnap);
|
||||
badge.Interaction.PointerMove(new Point(grab.X + 30, grab.Y + 10), noSnap);
|
||||
Check("치수 칩: 끄는 동안 좌표가 보인다",
|
||||
badge.Overlay.ShowDragBadge && badge.Overlay.DragBadgeText.StartsWith("X ", StringComparison.Ordinal),
|
||||
badge.Overlay.DragBadgeText);
|
||||
|
||||
badge.Interaction.PointerUp(new Point(grab.X + 30, grab.Y + 10), noSnap);
|
||||
Check("치수 칩: 놓으면 사라진다", !badge.Overlay.ShowDragBadge);
|
||||
|
||||
// 크기 조절일 때는 <b>크기</b>를 보여 준다 — 지금 바꾸고 있는 값이 그것이다
|
||||
badge.Selection.SetSingle(one);
|
||||
var bounds = badge.WorldBoundsOf(one);
|
||||
var handles = ViewModels.SelectionOverlayViewModel.HandlePositions(bounds);
|
||||
badge.Interaction.PointerDown(handles[4], noSnap); // 우하단
|
||||
badge.Interaction.PointerMove(new Point(handles[4].X + 25, handles[4].Y + 12), noSnap);
|
||||
Check("치수 칩: 크기 조절 중에는 크기가 보인다",
|
||||
badge.Overlay.ShowDragBadge && badge.Overlay.DragBadgeText.Contains('×'),
|
||||
badge.Overlay.DragBadgeText);
|
||||
badge.Interaction.PointerUp(new Point(handles[4].X + 25, handles[4].Y + 12), noSnap);
|
||||
}
|
||||
|
||||
// 15-a000000) 패널 안에 그린 마퀴는 그 안의 것을 고른다.
|
||||
//
|
||||
// 전에는 마퀴가 최상위만 훑어서, 패널 안 체크박스 5개를 한 번에 고르려고
|
||||
// 패널 안쪽을 끌면 패널만 잡히거나 아무것도 안 잡혔다 —
|
||||
// 결국 Ctrl+클릭 반복이나 레이어 목록으로 우회했다.
|
||||
// 컨테이너 자식은 전체 컨트롤의 18.3%(실측)라 드문 경우가 아니다.
|
||||
{
|
||||
var mq = new DesignerViewModel(new FormDesignDataBusiness().CreateNew());
|
||||
mq.AddControlAt("CheckBox", new Point(100, 100));
|
||||
mq.AddControlAt("CheckBox", new Point(100, 140));
|
||||
mq.Selection.Set(mq.Pages[0].Controls.ToList(), mq.Pages[0].Controls[0]);
|
||||
mq.GroupSelection();
|
||||
var box = mq.Pages[0].Controls.OfType<ViewModels.Controls.ContainerViewModel>().First();
|
||||
var boxWorld = mq.WorldBoundsOf(box);
|
||||
|
||||
// ① 패널 <b>안쪽</b>을 끈다 — 자식이 잡혀야 한다
|
||||
var inside = new Rect(boxWorld.X + 2, boxWorld.Y + 2,
|
||||
Math.Max(1, boxWorld.Width - 4), Math.Max(1, boxWorld.Height - 4));
|
||||
var innerHits = mq.MarqueeHits(inside);
|
||||
Check("마퀴: 패널 안에 그리면 안의 것이 잡힌다",
|
||||
innerHits.Count == box.Children.Count
|
||||
&& innerHits.All(h => ReferenceEquals(h.Parent, box)),
|
||||
$"{innerHits.Count}개 (패널 자식 {box.Children.Count}개)");
|
||||
|
||||
// ② 패널을 <b>걸치도록</b> 끈다 — 예전처럼 패널 자체가 잡혀야 한다
|
||||
var across = new Rect(boxWorld.X - 20, boxWorld.Y - 20, boxWorld.Width + 40, 30);
|
||||
var outerHits = mq.MarqueeHits(across);
|
||||
Check("마퀴: 패널에 걸치면 패널이 잡힌다(기존 동작 유지)",
|
||||
outerHits.Count == 1 && ReferenceEquals(outerHits[0], box),
|
||||
$"{outerHits.Count}개 — {string.Join(",", outerHits.Select(h => h.Type))}");
|
||||
}
|
||||
|
||||
// 15-a00000) 태그 행이 사실대로 말하는가.
|
||||
{
|
||||
// 카탈로그에 없는 이름은 표식이 붙어야 한다 — 그러나 <b>막지는 않는다</b>.
|
||||
|
||||
@@ -233,20 +233,21 @@ public sealed class InteractionController
|
||||
designer.ReassignPagesAfterMove(origBounds.Keys.ToList());
|
||||
designer.Overlay.ClearGuides();
|
||||
designer.Snap.EndDrag();
|
||||
designer.Overlay.ClearDragBadge();
|
||||
break;
|
||||
|
||||
case Mode.Resize:
|
||||
designer.Overlay.ClearGuides();
|
||||
designer.Snap.EndDrag();
|
||||
designer.Overlay.ClearDragBadge();
|
||||
break;
|
||||
|
||||
case Mode.Marquee:
|
||||
var rect = RectFrom(downPoint, world);
|
||||
designer.Overlay.UpdateMarquee(null);
|
||||
var hits = designer.ControlsIntersecting(rect)
|
||||
.SelectMany(designer.GroupMatesOf)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
// 마퀴 전용 규칙 — 그룹은 넓히되 컨테이너 자식은 부모로 되돌리지 않는다.
|
||||
// GroupMatesOf 를 그대로 쓰면 패널 안쪽을 정확히 골라 놓고도 결과가 패널 하나가 된다.
|
||||
var hits = designer.MarqueeHits(rect);
|
||||
if (ctx.Ctrl || ctx.Shift)
|
||||
{
|
||||
var merged = designer.Selection.Items.Union(hits).ToList();
|
||||
@@ -285,6 +286,7 @@ public sealed class InteractionController
|
||||
{
|
||||
designer.Overlay.ClearGuides();
|
||||
designer.Snap.EndDrag();
|
||||
designer.Overlay.ClearDragBadge();
|
||||
mode = Mode.None;
|
||||
origBounds.Clear();
|
||||
downControl = null;
|
||||
@@ -443,6 +445,11 @@ public sealed class InteractionController
|
||||
}
|
||||
|
||||
designer.Selection.NotifyBoundsChanged();
|
||||
// 끄는 동안 지금 값을 보여 준다 — 숫자가 인스펙터에만 있으면 끌다 말고 오른쪽을 봐야 한다
|
||||
if (designer.SelectionWorldBounds() is { } movedBounds)
|
||||
{
|
||||
designer.Overlay.SetDragBadge(movedBounds, resizing: false);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoResize(Point world, PointerContext ctx)
|
||||
@@ -509,6 +516,10 @@ public sealed class InteractionController
|
||||
}
|
||||
|
||||
designer.Selection.NotifyBoundsChanged();
|
||||
if (designer.SelectionWorldBounds() is { } sizedBounds)
|
||||
{
|
||||
designer.Overlay.SetDragBadge(sizedBounds, resizing: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>드래그 첫 실변경 시 1회 스냅샷 — 드래그 전체 = Undo 1스텝</summary>
|
||||
|
||||
@@ -864,21 +864,70 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
var result = new List<ControlViewModel>();
|
||||
foreach (var page in Pages)
|
||||
{
|
||||
foreach (var vm in page.Controls)
|
||||
{
|
||||
if (vm.Model.Hidden || vm.Model.Locked)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (worldRect.IntersectsWith(WorldBoundsOf(vm)))
|
||||
{
|
||||
result.Add(vm);
|
||||
}
|
||||
}
|
||||
CollectIntersecting(page.Controls, worldRect, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 마퀴에 걸리는 것을 모은다 — <b>컨테이너 안에 그린 마퀴는 그 안의 것을 고른다</b>.
|
||||
///
|
||||
/// 전에는 최상위만 훑어서, 패널 안 체크박스 5개를 한 번에 고르려고 패널 안쪽을 끌면
|
||||
/// 패널만 잡히거나 아무것도 안 잡혔다 — 결국 Ctrl+클릭 반복이나 레이어 목록으로 우회했다.
|
||||
/// 컨테이너 자식은 전체 컨트롤의 18.3%(실측 18,749/컨테이너 4,099개)라 드문 경우가 아니다.
|
||||
///
|
||||
/// <b>규칙은 '담김'이다.</b> 마퀴가 컨테이너 사각형 <b>안에</b> 들어가 있으면
|
||||
/// 사용자는 그 안의 것을 고르려는 것이다(내 상자가 패널보다 작으니까).
|
||||
/// 걸치기만 하면 예전처럼 컨테이너 자체가 잡힌다 — 패널을 통째로 고르는 조작이 그대로 남는다.
|
||||
/// 모드도 수정키도 없이 그린 모양만으로 갈리므로 예측할 수 있다.
|
||||
/// </summary>
|
||||
private void CollectIntersecting(IEnumerable<ControlViewModel> controls, Rect worldRect,
|
||||
List<ControlViewModel> result)
|
||||
{
|
||||
foreach (var vm in controls)
|
||||
{
|
||||
if (vm.Model.Hidden || vm.Model.Locked)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var bounds = WorldBoundsOf(vm);
|
||||
if (!worldRect.IntersectsWith(bounds))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (vm is ContainerViewModel container && bounds.Contains(worldRect))
|
||||
{
|
||||
CollectIntersecting(container.Children, worldRect, result);
|
||||
continue;
|
||||
}
|
||||
result.Add(vm);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 마퀴가 최종적으로 고를 것 — 그룹은 통째로 넓히되 <b>컨테이너 자식은 그대로 둔다</b>.
|
||||
///
|
||||
/// 클릭 선택은 <see cref="GroupMatesOf"/> 를 쓰는데 그것은 자식을 부모 컨테이너로 되돌린다
|
||||
/// (패널 안의 것을 집으면 패널이 움직여야 하므로 옳다). 마퀴에 그것을 그대로 쓰면
|
||||
/// 안쪽을 정확히 골라 놓고도 결과가 다시 패널 하나가 되어, 위 규칙이 아무 일도 하지 않는다.
|
||||
/// </summary>
|
||||
public List<ControlViewModel> MarqueeHits(Rect worldRect)
|
||||
{
|
||||
var hits = ControlsIntersecting(worldRect);
|
||||
var result = new List<ControlViewModel>();
|
||||
foreach (var vm in hits)
|
||||
{
|
||||
// 그룹(GroupId)은 페이지 최상위 개념이다 — 컨테이너 자식에는 붙지 않는다
|
||||
if (vm.Parent is null && vm.Model.GroupId is not null)
|
||||
{
|
||||
result.AddRange(GroupMatesOf(vm));
|
||||
continue;
|
||||
}
|
||||
result.Add(vm);
|
||||
}
|
||||
return result.Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <summary>오버레이(선택 박스/핸들) 재계산</summary>
|
||||
public void RefreshOverlay()
|
||||
{
|
||||
|
||||
@@ -116,6 +116,10 @@ public sealed class SelectionOverlayViewModel : ViewModelBase
|
||||
private double selW;
|
||||
private double selH;
|
||||
private bool showHandles;
|
||||
private string dragBadgeText = string.Empty;
|
||||
private bool showDragBadge;
|
||||
private double dragBadgeX;
|
||||
private double dragBadgeY;
|
||||
private bool hasMarquee;
|
||||
private double marX;
|
||||
private double marY;
|
||||
@@ -189,6 +193,43 @@ public sealed class SelectionOverlayViewModel : ViewModelBase
|
||||
/// <summary>탭순서 배지 목록(탭순서 편집 모드 전용)</summary>
|
||||
public ObservableCollection<TabBadgeInfo> TabBadges { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 끄는 동안 보여 주는 치수·좌표 — <b>드래그 중에만</b> 있다.
|
||||
///
|
||||
/// 전에는 숫자가 300px 떨어진 인스펙터에만 떴다. 라벨 폭을 종이 칸에 맞추려면
|
||||
/// 끌고, 손 떼고, 오른쪽을 보고, 다시 끄는 왕복이 붙었다.
|
||||
/// 간격 수치 칩은 <b>균등 스냅이 성립하는 순간에만</b> 나타나므로
|
||||
/// "지금 이게 몇 px 인가"는 드래그 중에 알 방법이 없었다.
|
||||
/// </summary>
|
||||
public string DragBadgeText { get => dragBadgeText; private set => SetProperty(ref dragBadgeText, value); }
|
||||
|
||||
/// <summary>치수 칩을 보일지</summary>
|
||||
public bool ShowDragBadge { get => showDragBadge; private set => SetProperty(ref showDragBadge, value); }
|
||||
|
||||
/// <summary>치수 칩 X(월드) — 선택 상자 좌하단 바깥</summary>
|
||||
public double DragBadgeX { get => dragBadgeX; private set => SetProperty(ref dragBadgeX, value); }
|
||||
|
||||
/// <summary>치수 칩 Y(월드)</summary>
|
||||
public double DragBadgeY { get => dragBadgeY; private set => SetProperty(ref dragBadgeY, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 끄는 동안의 치수·좌표를 갱신한다 — 이동이면 좌표, 크기 조절이면 크기를 보여 준다.
|
||||
/// 사용자가 지금 <b>바꾸고 있는 값</b>을 보여 주는 것이 요점이다.
|
||||
/// </summary>
|
||||
public void SetDragBadge(Rect bounds, bool resizing)
|
||||
{
|
||||
DragBadgeText = resizing
|
||||
? $"{Math.Round(bounds.Width)} × {Math.Round(bounds.Height)}"
|
||||
: $"X {Math.Round(bounds.X)} · Y {Math.Round(bounds.Y)}";
|
||||
// 선택 상자 <b>아래</b>에 둔다 — 위에 두면 위쪽으로 끌 때 커서가 칩을 밀고 다닌다
|
||||
DragBadgeX = bounds.X;
|
||||
DragBadgeY = bounds.Bottom + (6 * InverseZoom);
|
||||
ShowDragBadge = true;
|
||||
}
|
||||
|
||||
/// <summary>드래그가 끝났다 — 칩을 치운다</summary>
|
||||
public void ClearDragBadge() => ShowDragBadge = false;
|
||||
|
||||
/// <summary>
|
||||
/// 잠긴 컨트롤의 테두리 — <b>편집 크롬</b>이라 종이에는 그려지지 않는다.
|
||||
///
|
||||
|
||||
@@ -175,7 +175,8 @@
|
||||
(자르기보다 낫다 — 잘린 라벨은 툴팁을 띄워봐야 아는 정보가 된다).
|
||||
-->
|
||||
<Style x:Key="RowLabel" TargetType="TextBlock">
|
||||
<Setter Property="Width" Value="72"/>
|
||||
<!-- 위 주석이 92 를 논증해 놓고 값은 72 였다 — 그래서 '액션 대상 컨…' 처럼 잘렸다 -->
|
||||
<Setter Property="Width" Value="92"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
@@ -694,8 +695,15 @@
|
||||
<DataTemplate DataType="{x:Type ins:ReadOnlyRowViewModel}">
|
||||
<DockPanel Margin="0,2">
|
||||
<TextBlock Text="{Binding Label}" Style="{StaticResource RowLabel}"/>
|
||||
<!--
|
||||
이 자리는 값이 아니라 <b>설명</b>이다 — 자르면 결론이 사라진다.
|
||||
"타입이 달라 값의 뜻이 다른 속성 2개 — 타입별로 따로 고르세요" 에서
|
||||
지시에 해당하는 뒷부분이 잘려 나가 무엇을 하라는 건지 알 수 없었다.
|
||||
접어서 다 보여 주고, 그래도 좁으면 툴팁이 받는다.
|
||||
-->
|
||||
<TextBlock Text="{Binding ValueText}" FontSize="11" Foreground="{DynamicResource B.Muted}"
|
||||
VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
|
||||
VerticalAlignment="Center" TextWrapping="Wrap"
|
||||
ToolTip="{Binding ValueText}"/>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -906,11 +914,11 @@
|
||||
<ContentControl DockPanel.Dock="Left" Margin="0,0,7,0" VerticalAlignment="Center"
|
||||
IsTabStop="False" Focusable="False"
|
||||
Content="{Binding HeaderIcon, Converter={StaticResource IconName}, ConverterParameter=16|B.Muted}"/>
|
||||
<Button DockPanel.Dock="Right" Width="24" Height="24" Padding="0"
|
||||
Style="{StaticResource Subtle}" ToolTip="이 컨트롤에 대한 명령"
|
||||
AutomationProperties.Name="더보기"
|
||||
Visibility="{Binding IsSingleSelection, Converter={StaticResource BoolToVisibility}}"
|
||||
Content="{Binding Source=ellipsis-vertical, Converter={StaticResource IconName}, ConverterParameter=14|B.Muted}"/>
|
||||
<!--
|
||||
⋮ 버튼을 지웠다. Command·Click·ContextMenu 가 <b>전부 없어</b> 눌러도 아무 일이 없었는데,
|
||||
툴팁은 '이 컨트롤에 대한 명령' 이라 '단일 선택일 때만 되는 뭔가가 있다'고 오해시켰다.
|
||||
없는 버튼보다 죽은 버튼이 나쁘다. 컨트롤 단위 명령은 캔버스 우클릭 메뉴에 다 있다.
|
||||
-->
|
||||
<TextBlock Text="{Binding HeaderName}" FontWeight="Bold" FontSize="12.5"
|
||||
Foreground="{DynamicResource B.Ink}" VerticalAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis" ToolTip="{Binding Summary}"/>
|
||||
|
||||
@@ -66,6 +66,22 @@
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!--
|
||||
끄는 동안의 치수·좌표 — 편집 크롬이라 종이에는 없다.
|
||||
줌이 걸린 층이라 역배율로 되돌려 글자 크기를 화면 고정으로 만든다
|
||||
(간격 수치 칩이 이미 같은 방식을 쓴다).
|
||||
-->
|
||||
<Border Canvas.Left="{Binding DragBadgeX}" Canvas.Top="{Binding DragBadgeY}"
|
||||
Background="{DynamicResource B.AccentFill}" CornerRadius="3" Padding="5,1"
|
||||
RenderTransformOrigin="0,0"
|
||||
Visibility="{Binding ShowDragBadge, Converter={StaticResource BoolToVisibility}}">
|
||||
<Border.RenderTransform>
|
||||
<ScaleTransform ScaleX="{Binding InverseZoom}" ScaleY="{Binding InverseZoom}"/>
|
||||
</Border.RenderTransform>
|
||||
<TextBlock Text="{Binding DragBadgeText}" FontSize="11"
|
||||
Foreground="{DynamicResource B.OnAccent}"/>
|
||||
</Border>
|
||||
|
||||
<!-- 마퀴(러버밴드) -->
|
||||
<Rectangle Canvas.Left="{Binding MarX}" Canvas.Top="{Binding MarY}"
|
||||
Width="{Binding MarW}" Height="{Binding MarH}"
|
||||
|
||||
Reference in New Issue
Block a user