Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions samples/AvalonDraw/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
<MenuItem Header="Path Quadratic" Click="PathQuadraticToolMenuItem_Click" InputGesture="Q"/>
<MenuItem Header="Path Arc" Click="PathArcToolMenuItem_Click" InputGesture="A"/>
<MenuItem Header="Path Move" Click="PathMoveToolMenuItem_Click" InputGesture="M"/>
<Separator/>
<MenuItem Header="Skew Mode" Click="SkewModeMenuItem_Click" InputGesture="Ctrl+Shift+K"/>
</MenuItem>
<MenuItem Header="Arrange">
<MenuItem Header="Align Left" Click="AlignLeftMenuItem_Click"/>
Expand Down
35 changes: 34 additions & 1 deletion samples/AvalonDraw/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ private enum DropPosition { None, Inside, Before, After }
private SK.SKPoint _rotateStart;
private SK.SKPoint _rotateCenter;
private float _startAngle;
private bool _isSkewing;
private float _startSkewX;
private float _startSkewY;
private bool _skewMode;

private bool _isPanning;
private Point _panStart;
Expand Down Expand Up @@ -682,7 +686,10 @@ private async void SvgView_OnPointerPressed(object? sender, PointerPressedEventA
return;
}
SaveUndoState();
_isResizing = true;
if (_skewMode)
_isSkewing = true;
else
_isResizing = true;
_resizeElement = _selectedElement;
_resizeHandle = handle;
_resizeStart = new Shim.SKPoint(pp.X, pp.Y);
Expand All @@ -697,6 +704,7 @@ private async void SvgView_OnPointerPressed(object? sender, PointerPressedEventA
_resizeStartLocal = _resizeInverse.MapPoint(_resizeStart);
(_startTransX, _startTransY) = _selectionService.GetTranslation(_resizeElement);
(_startScaleX, _startScaleY) = _selectionService.GetScale(_resizeElement);
(_startSkewX, _startSkewY) = _selectionService.GetSkew(_resizeElement);
e.Pointer.Capture(SvgView);
return;
}
Expand Down Expand Up @@ -999,6 +1007,16 @@ private void SvgView_OnPointerMoved(object? sender, PointerEventArgs e)
UpdateSelectedDrawable();
SvgView.InvalidateVisual();
}
else if (_isSkewing && _resizeElement is { })
{
var local = _resizeInverse.MapPoint(new Shim.SKPoint(skp.X, skp.Y));
var dx = local.X - _resizeStartLocal.X;
var dy = local.Y - _resizeStartLocal.Y;
_selectionService.SkewElement(_resizeElement, _resizeHandle, dx, dy, _startRect, _startSkewX, _startSkewY);
SvgView.SkSvg!.FromSvgDocument(_document);
UpdateSelectedDrawable();
SvgView.InvalidateVisual();
}
else if (_isRotating && _rotateElement is { })
{
var a1 = Math.Atan2(_rotateStart.Y - _rotateCenter.Y, _rotateStart.X - _rotateCenter.X);
Expand Down Expand Up @@ -1183,6 +1201,15 @@ private void SvgView_OnPointerReleased(object? sender, PointerReleasedEventArgs
LoadProperties(_resizeElement);
}
}
else if (_isSkewing)
{
_isSkewing = false;
if (_resizeElement is { })
{
SaveUndoState();
LoadProperties(_resizeElement);
}
}
else if (_pathService.ActivePoint >= 0)
{
_pathService.ActivePoint = -1;
Expand Down Expand Up @@ -2136,6 +2163,11 @@ private void FiltersMenuItem_Click(object? sender, RoutedEventArgs e)
SvgView.InvalidateVisual();
}

private void SkewModeMenuItem_Click(object? sender, RoutedEventArgs e)
{
_skewMode = !_skewMode;
}

private void ResetViewButton_Click(object? sender, RoutedEventArgs e)
{
SvgView.Zoom = 1.0;
Expand Down Expand Up @@ -2999,6 +3031,7 @@ private void ToolServiceOnToolChanged(Tool oldTool, Tool newTool)
if (_polyEditing && newTool != Tool.PolygonSelect && newTool != Tool.PolylineSelect)
StopPolyEditing();
_isResizing = false;
_isSkewing = false;
_isRotating = false;
SvgView.InvalidateVisual();
}
Expand Down
188 changes: 160 additions & 28 deletions samples/AvalonDraw/Services/SelectionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using SK = SkiaSharp;
using Svg;
using Svg.Model.Drawables;
using Svg.Transforms;
using Svg.Skia;
using Svg.Transforms;
using Shim = ShimSkiaSharp;
using SK = SkiaSharp;

namespace AvalonDraw.Services;

Expand Down Expand Up @@ -172,6 +172,32 @@ public void SetScale(SvgVisualElement element, float x, float y)
}
}

public (float X, float Y) GetSkew(SvgVisualElement? element)
{
if (element?.Transforms is { } t)
{
var sk = t.OfType<SvgSkew>().FirstOrDefault();
if (sk is { })
return (sk.AngleX, sk.AngleY);
}
return (0f, 0f);
}

public void SetSkew(SvgVisualElement element, float x, float y)
{
element.Transforms ??= new SvgTransformCollection();
var sk = element.Transforms.OfType<SvgSkew>().FirstOrDefault();
if (sk != null)
{
sk.AngleX = x;
sk.AngleY = y;
}
else
{
element.Transforms.Add(new SvgSkew(x, y));
}
}

public float Snap(float value)
{
if (!SnapToGrid || GridSize <= 0)
Expand Down Expand Up @@ -204,14 +230,40 @@ void ResizeBox(dynamic el, int h, float ddx, float ddy)
float hgt = el.Height.Value;
switch (h)
{
case 0: x = startRect.Left + ddx; y = startRect.Top + ddy; w = startRect.Right - x; hgt = startRect.Bottom - y; break;
case 1: y = startRect.Top + ddy; hgt = startRect.Bottom - y; break;
case 2: y = startRect.Top + ddy; w = startRect.Width + ddx; hgt = startRect.Bottom - y; break;
case 3: w = startRect.Width + ddx; break;
case 4: w = startRect.Width + ddx; hgt = startRect.Height + ddy; break;
case 5: hgt = startRect.Height + ddy; break;
case 6: x = startRect.Left + ddx; w = startRect.Right - x; hgt = startRect.Height + ddy; break;
case 7: x = startRect.Left + ddx; w = startRect.Right - x; break;
case 0:
x = startRect.Left + ddx;
y = startRect.Top + ddy;
w = startRect.Right - x;
hgt = startRect.Bottom - y;
break;
case 1:
y = startRect.Top + ddy;
hgt = startRect.Bottom - y;
break;
case 2:
y = startRect.Top + ddy;
w = startRect.Width + ddx;
hgt = startRect.Bottom - y;
break;
case 3:
w = startRect.Width + ddx;
break;
case 4:
w = startRect.Width + ddx;
hgt = startRect.Height + ddy;
break;
case 5:
hgt = startRect.Height + ddy;
break;
case 6:
x = startRect.Left + ddx;
w = startRect.Right - x;
hgt = startRect.Height + ddy;
break;
case 7:
x = startRect.Left + ddx;
w = startRect.Right - x;
break;
}
if (SnapToGrid)
{
Expand All @@ -234,14 +286,40 @@ void ResizeCircle(SvgCircle c, int h, float ddx, float ddy)
float hgt = startRect.Height;
switch (h)
{
case 0: x += ddx; y += ddy; w = startRect.Right - x; hgt = startRect.Bottom - y; break;
case 1: y += ddy; hgt = startRect.Bottom - y; break;
case 2: y += ddy; w += ddx; hgt = startRect.Bottom - y; break;
case 3: w += ddx; break;
case 4: w += ddx; hgt += ddy; break;
case 5: hgt += ddy; break;
case 6: x += ddx; w = startRect.Right - x; hgt += ddy; break;
case 7: x += ddx; w = startRect.Right - x; break;
case 0:
x += ddx;
y += ddy;
w = startRect.Right - x;
hgt = startRect.Bottom - y;
break;
case 1:
y += ddy;
hgt = startRect.Bottom - y;
break;
case 2:
y += ddy;
w += ddx;
hgt = startRect.Bottom - y;
break;
case 3:
w += ddx;
break;
case 4:
w += ddx;
hgt += ddy;
break;
case 5:
hgt += ddy;
break;
case 6:
x += ddx;
w = startRect.Right - x;
hgt += ddy;
break;
case 7:
x += ddx;
w = startRect.Right - x;
break;
}
var cx = x + w / 2f;
var cy = y + hgt / 2f;
Expand All @@ -265,20 +343,52 @@ void ResizePath(SvgPath p, int h, float ddx, float ddy)
float hgt = startRect.Height;
switch (h)
{
case 0: x += ddx; y += ddy; w = startRect.Right - x; hgt = startRect.Bottom - y; break;
case 1: y += ddy; hgt = startRect.Bottom - y; break;
case 2: y += ddy; w += ddx; hgt = startRect.Bottom - y; break;
case 3: w += ddx; break;
case 4: w += ddx; hgt += ddy; break;
case 5: hgt += ddy; break;
case 6: x += ddx; w = startRect.Right - x; hgt += ddy; break;
case 7: x += ddx; w = startRect.Right - x; break;
case 0:
x += ddx;
y += ddy;
w = startRect.Right - x;
hgt = startRect.Bottom - y;
break;
case 1:
y += ddy;
hgt = startRect.Bottom - y;
break;
case 2:
y += ddy;
w += ddx;
hgt = startRect.Bottom - y;
break;
case 3:
w += ddx;
break;
case 4:
w += ddx;
hgt += ddy;
break;
case 5:
hgt += ddy;
break;
case 6:
x += ddx;
w = startRect.Right - x;
hgt += ddy;
break;
case 7:
x += ddx;
w = startRect.Right - x;
break;
}
if (SnapToGrid)
{
x = Snap(x); y = Snap(y); w = Snap(w); hgt = Snap(hgt);
x = Snap(x);
y = Snap(y);
w = Snap(w);
hgt = Snap(hgt);
}
if (w == 0) w = 0.01f; if (hgt == 0) hgt = 0.01f;
if (w == 0)
w = 0.01f;
if (hgt == 0)
hgt = 0.01f;
var sx = w / startRect.Width;
var sy = hgt / startRect.Height;
var tx = x - startRect.Left;
Expand All @@ -288,6 +398,28 @@ void ResizePath(SvgPath p, int h, float ddx, float ddy)
}
}

public void SkewElement(SvgVisualElement element, int handle, float dx, float dy, SK.SKRect startRect, float startSkewX, float startSkewY)
{
var ax = startSkewX;
var ay = startSkewY;
switch (handle)
{
case 1:
case 5:
ax += (float)(Math.Atan(dx / startRect.Height) * 180.0 / Math.PI);
break;
case 3:
case 7:
ay += (float)(Math.Atan(dy / startRect.Width) * 180.0 / Math.PI);
break;
default:
ax += (float)(Math.Atan(dx / startRect.Height) * 180.0 / Math.PI);
ay += (float)(Math.Atan(dy / startRect.Width) * 180.0 / Math.PI);
break;
}
SetSkew(element, ax, ay);
}

public bool GetDragProperties(SvgVisualElement element, out List<(PropertyInfo Prop, SvgUnit Unit, char Axis)> props)
{
var list = new List<(PropertyInfo Prop, SvgUnit Unit, char Axis)>();
Expand Down
Loading