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
4 changes: 4 additions & 0 deletions samples/AvalonDraw/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<MenuItem Header="Text Path" Click="TextPathToolMenuItem_Click" InputGesture="K"/>
<MenuItem Header="Text Area" Click="TextAreaToolMenuItem_Click" InputGesture="H"/>
<MenuItem Header="Symbol" Click="SymbolToolMenuItem_Click" InputGesture="U"/>
<MenuItem Header="Freehand" Click="FreehandToolMenuItem_Click" InputGesture="F"/>
<Separator/>
<MenuItem Header="Path Line" Click="PathLineToolMenuItem_Click" InputGesture="B"/>
<MenuItem Header="Path Cubic" Click="PathCubicToolMenuItem_Click" InputGesture="J"/>
Expand Down Expand Up @@ -132,11 +133,14 @@
<RadioButton Content="TextPath" GroupName="tools" Margin="4,0" Click="TextPathToolButton_Click" />
<RadioButton Content="TextArea" GroupName="tools" Margin="4,0" Click="TextAreaToolButton_Click" />
<RadioButton Content="Symbol" GroupName="tools" Margin="4,0" Click="SymbolToolButton_Click" />
<RadioButton Content="Free" GroupName="tools" Margin="4,0" Click="FreehandToolButton_Click" />
<RadioButton Content="PLine" GroupName="tools" Margin="4,0" Click="PathLineToolButton_Click" />
<RadioButton Content="PCubic" GroupName="tools" Margin="4,0" Click="PathCubicToolButton_Click" />
<RadioButton Content="PQuad" GroupName="tools" Margin="4,0" Click="PathQuadraticToolButton_Click" />
<RadioButton Content="PArc" GroupName="tools" Margin="4,0" Click="PathArcToolButton_Click" />
<RadioButton Content="PMove" GroupName="tools" Margin="4,0" Click="PathMoveToolButton_Click" />
<TextBlock Text="Width:" VerticalAlignment="Center" Margin="8,0,0,0"/>
<TextBox x:Name="StrokeWidthBox" Width="50" KeyUp="StrokeWidthBox_OnKeyUp" />
</StackPanel>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
Expand Down
59 changes: 52 additions & 7 deletions samples/AvalonDraw/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ private enum DropPosition { None, Inside, Before, After }
private readonly List<SvgVisualElement> _multiSelected = new();
private readonly List<DrawableBase> _multiDrawables = new();
private SK.SKRect _multiBounds = SK.SKRect.Empty;
private readonly List<Shim.SKPoint> _freehandPoints = new();
private TextBox? _strokeWidthBox;

public MainWindow()
{
Expand Down Expand Up @@ -347,6 +349,9 @@ public MainWindow()
_layerTree = this.FindControl<TreeView>("LayerTree");
_swatchList = this.FindControl<ListBox>("SwatchList");
_brushList = this.FindControl<ListBox>("BrushList");
_strokeWidthBox = this.FindControl<TextBox>("StrokeWidthBox");
if (_strokeWidthBox is { })
_strokeWidthBox.Text = _toolService.CurrentStrokeWidth.ToString(System.Globalization.CultureInfo.InvariantCulture);
_wireframeEnabled = false;
_filtersDisabled = false;
_snapToGrid = false;
Expand Down Expand Up @@ -873,13 +878,28 @@ private void SvgView_OnPointerMoved(object? sender, PointerEventArgs e)
if (_creating && SvgView.TryGetPicturePoint(point, out var cp) && _newElement is { })
{
var cur = new Shim.SKPoint(cp.X, cp.Y);
_toolService.UpdateElement(_newElement, _toolService.CurrentTool,
_newStart, cur, _snapToGrid, _selectionService.Snap);
SvgView.SkSvg!.FromSvgDocument(_document);
UpdateSelectedDrawable();
if (_pathService.IsEditing)
_pathService.EditDrawable = _selectedDrawable;
SvgView.InvalidateVisual();
if (_toolService.CurrentTool == Tool.Freehand)
{
var last = _freehandPoints[^1];
if (Math.Abs(last.X - cur.X) > DragThreshold || Math.Abs(last.Y - cur.Y) > DragThreshold)
{
_freehandPoints.Add(cur);
_toolService.AddFreehandPoint(_newElement, cur, _snapToGrid, _selectionService.Snap);
SvgView.SkSvg!.FromSvgDocument(_document);
UpdateSelectedDrawable();
SvgView.InvalidateVisual();
}
}
else
{
_toolService.UpdateElement(_newElement, _toolService.CurrentTool,
_newStart, cur, _snapToGrid, _selectionService.Snap);
SvgView.SkSvg!.FromSvgDocument(_document);
UpdateSelectedDrawable();
if (_pathService.IsEditing)
_pathService.EditDrawable = _selectedDrawable;
SvgView.InvalidateVisual();
}
return;
}

Expand Down Expand Up @@ -1217,12 +1237,20 @@ private void SvgView_OnPointerReleased(object? sender, PointerReleasedEventArgs
_creating = false;
if (_newElement is { })
{
if (_toolService.CurrentTool == Tool.Freehand && _newElement is SvgPath fp && _freehandPoints.Count > 1)
{
fp.PathData = PathService.MakeSmooth(_freehandPoints);
if (_selectedBrush is { })
fp.CustomAttributes["stroke-profile"] = _selectedBrush.Profile.ToString();
SvgView.SkSvg!.FromSvgDocument(_document);
}
LoadProperties(_newElement);
_selectedElement = _newElement;
_selectedSvgElement = _newElement;
UpdateSelectedDrawable();
}
_newElement = null;
_freehandPoints.Clear();
}
}
else if (_isResizing)
Expand Down Expand Up @@ -2408,6 +2436,13 @@ private void PathMoveToolButton_Click(object? sender, RoutedEventArgs e)
_pathService.CurrentSegmentTool = PathService.SegmentTool.Move;
}

private void FreehandToolButton_Click(object? sender, RoutedEventArgs e)
{
if (_pathService.IsEditing)
_pathService.Stop();
_toolService.SetTool(Tool.Freehand);
}

private async void SymbolToolButton_Click(object? sender, RoutedEventArgs e)
{
if (_pathService.IsEditing)
Expand Down Expand Up @@ -2446,6 +2481,7 @@ private async void SymbolToolButton_Click(object? sender, RoutedEventArgs e)
private void PathArcToolMenuItem_Click(object? sender, RoutedEventArgs e) => PathArcToolButton_Click(sender, e);
private void PathMoveToolMenuItem_Click(object? sender, RoutedEventArgs e) => PathMoveToolButton_Click(sender, e);
private void SymbolToolMenuItem_Click(object? sender, RoutedEventArgs e) => SymbolToolButton_Click(sender, e);
private void FreehandToolMenuItem_Click(object? sender, RoutedEventArgs e) => FreehandToolButton_Click(sender, e);

private async void SettingsMenuItem_Click(object? sender, RoutedEventArgs e)
{
Expand Down Expand Up @@ -2696,6 +2732,15 @@ private void PropertyFilterBox_OnKeyUp(object? sender, KeyEventArgs e)
}
}

private void StrokeWidthBox_OnKeyUp(object? sender, KeyEventArgs e)
{
if (sender is TextBox tb &&
float.TryParse(tb.Text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var w))
{
_toolService.CurrentStrokeWidth = w;
}
}

private void DocumentTree_OnPointerPressed(object? sender, PointerPressedEventArgs e)
{
var pos = e.GetPosition(DocumentTree);
Expand Down
24 changes: 24 additions & 0 deletions samples/AvalonDraw/Services/PathService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,30 @@ public static SK.SKPoint[] ConvertPoints(SvgPointCollection pc)
return pts;
}

public static SvgPathSegmentList MakeSmooth(IList<Shim.SKPoint> points)
{
var list = new SvgPathSegmentList();
if (points.Count == 0)
return list;
list.Add(new SvgMoveToSegment(false, new System.Drawing.PointF(points[0].X, points[0].Y)));
if (points.Count == 1)
return list;
for (int i = 0; i < points.Count - 1; i++)
{
var p0 = i == 0 ? points[i] : points[i - 1];
var p1 = points[i];
var p2 = points[i + 1];
var p3 = i + 2 < points.Count ? points[i + 2] : p2;
var c1 = new Shim.SKPoint(p1.X + (p2.X - p0.X) / 6f, p1.Y + (p2.Y - p0.Y) / 6f);
var c2 = new Shim.SKPoint(p2.X - (p3.X - p1.X) / 6f, p2.Y - (p3.Y - p1.Y) / 6f);
list.Add(new SvgCubicCurveSegment(false,
new System.Drawing.PointF(c1.X, c1.Y),
new System.Drawing.PointF(c2.X, c2.Y),
new System.Drawing.PointF(p2.X, p2.Y)));
}
return list;
}

public static void AddPathSegments(SK.SKPath path, SvgPathSegmentList segments)
{
var cur = new SK.SKPoint();
Expand Down
29 changes: 28 additions & 1 deletion samples/AvalonDraw/Services/ToolService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public enum Tool
PathArc,
PathMove,
Symbol,
Image
Image,
Freehand
}

public Tool CurrentTool { get; private set; } = Tool.Select;
Expand Down Expand Up @@ -142,6 +143,7 @@ public void SetTool(Tool tool)
Height = new SvgUnit(SvgUnitType.User, 0),
Href = ImageHref
},
Tool.Freehand => CreateFreehand(start),
_ => null!
};
}
Expand Down Expand Up @@ -176,6 +178,19 @@ private SvgPath CreatePath(ShimSkiaSharp.SKPoint start, Tool tool)
return path;
}

private SvgPath CreateFreehand(ShimSkiaSharp.SKPoint start)
{
return new SvgPath
{
Stroke = new SvgColourServer(System.Drawing.Color.Black),
StrokeWidth = new SvgUnit(CurrentStrokeWidth),
PathData = new SvgPathSegmentList
{
new SvgMoveToSegment(false, new System.Drawing.PointF(start.X, start.Y))
}
};
}

public void UpdateElement(SvgVisualElement element, Tool tool, ShimSkiaSharp.SKPoint start, ShimSkiaSharp.SKPoint current, bool snapToGrid, Func<float, float> snap)
{
switch (tool)
Expand Down Expand Up @@ -367,4 +382,16 @@ public void FinalizePolygon(SvgVisualElement element, Tool tool, ShimSkiaSharp.S
pts[pts.Count - 1] = new SvgUnit(pts[1].Type, y);
}
}

public void AddFreehandPoint(SvgVisualElement element, ShimSkiaSharp.SKPoint point, bool snapToGrid, Func<float, float> snap)
{
if (element is not SvgPath path)
return;
var x = snapToGrid ? snap(point.X) : point.X;
var y = snapToGrid ? snap(point.Y) : point.Y;
if (path.PathData.Count == 0)
path.PathData.Add(new SvgMoveToSegment(false, new System.Drawing.PointF(x, y)));
else
path.PathData.Add(new SvgLineSegment(false, new System.Drawing.PointF(x, y)));
}
}
Loading