6 changed files with 622 additions and 2 deletions
@ -0,0 +1,161 @@ |
|||||||
|
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Linq; |
||||||
|
using System.Windows; |
||||||
|
using System.Windows.Controls; |
||||||
|
using System.Windows.Input; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Windows.Shapes; |
||||||
|
using ICSharpCode.WpfDesign.Extensions; |
||||||
|
using ICSharpCode.WpfDesign.Designer.Services; |
||||||
|
|
||||||
|
namespace ICSharpCode.WpfDesign.Designer.Extensions |
||||||
|
{ |
||||||
|
[ExtensionFor(typeof(Canvas))] |
||||||
|
[ExtensionFor(typeof(Grid))] |
||||||
|
public class DrawPathExtension : BehaviorExtension, IDrawItemExtension |
||||||
|
{ |
||||||
|
private ChangeGroup changeGroup; |
||||||
|
|
||||||
|
DesignItem CreateItem(DesignContext context, Type componentType) |
||||||
|
{ |
||||||
|
object newInstance = context.Services.ExtensionManager.CreateInstanceWithCustomInstanceFactory(componentType, null); |
||||||
|
DesignItem item = context.Services.Component.RegisterComponentForDesigner(newInstance); |
||||||
|
changeGroup = item.OpenGroup("Draw Path"); |
||||||
|
context.Services.ExtensionManager.ApplyDefaultInitializers(item); |
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
#region IDrawItemBehavior implementation
|
||||||
|
|
||||||
|
public bool CanItemBeDrawn(Type createItemType) |
||||||
|
{ |
||||||
|
return createItemType == typeof(Path); |
||||||
|
} |
||||||
|
|
||||||
|
public void StartDrawItem(DesignItem clickedOn, Type createItemType, IDesignPanel panel, System.Windows.Input.MouseEventArgs e) |
||||||
|
{ |
||||||
|
var createdItem = CreateItem(panel.Context, createItemType); |
||||||
|
|
||||||
|
var startPoint = e.GetPosition(clickedOn.View); |
||||||
|
var operation = PlacementOperation.TryStartInsertNewComponents(clickedOn, |
||||||
|
new DesignItem[] { createdItem }, |
||||||
|
new Rect[] { new Rect(startPoint.X, startPoint.Y, double.NaN, double.NaN) }, |
||||||
|
PlacementType.AddItem); |
||||||
|
if (operation != null) { |
||||||
|
createdItem.Services.Selection.SetSelectedComponents(new DesignItem[] { createdItem }); |
||||||
|
operation.Commit(); |
||||||
|
} |
||||||
|
|
||||||
|
createdItem.Properties[Shape.StrokeProperty].SetValue(Brushes.Black); |
||||||
|
createdItem.Properties[Shape.StrokeThicknessProperty].SetValue(2d); |
||||||
|
createdItem.Properties[Shape.StretchProperty].SetValue(Stretch.None); |
||||||
|
|
||||||
|
var figure = new PathFigure(); |
||||||
|
var geometry = new PathGeometry(); |
||||||
|
var geometryDesignItem = createdItem.Services.Component.RegisterComponentForDesigner(geometry); |
||||||
|
var figureDesignItem = createdItem.Services.Component.RegisterComponentForDesigner(figure); |
||||||
|
createdItem.Properties[Path.DataProperty].SetValue(geometry); |
||||||
|
geometryDesignItem.Properties[PathGeometry.FiguresProperty].CollectionElements.Add(figureDesignItem); |
||||||
|
figureDesignItem.Properties[PathFigure.StartPointProperty].SetValue(new Point(0,0)); |
||||||
|
|
||||||
|
new DrawPathMouseGesture(figure, createdItem, clickedOn.View, changeGroup).Start(panel, (MouseButtonEventArgs) e); |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
sealed class DrawPathMouseGesture : ClickOrDragMouseGesture |
||||||
|
{ |
||||||
|
private ChangeGroup changeGroup; |
||||||
|
private DesignItem newLine; |
||||||
|
private Point startPoint; |
||||||
|
private PathFigure figure; |
||||||
|
|
||||||
|
public DrawPathMouseGesture(PathFigure figure, DesignItem newLine, IInputElement relativeTo, ChangeGroup changeGroup) |
||||||
|
{ |
||||||
|
this.newLine = newLine; |
||||||
|
this.positionRelativeTo = relativeTo; |
||||||
|
this.changeGroup = changeGroup; |
||||||
|
this.figure = figure; |
||||||
|
figure.Segments.Add(new LineSegment()); |
||||||
|
|
||||||
|
startPoint = Mouse.GetPosition(null); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) |
||||||
|
{ |
||||||
|
e.Handled = true; |
||||||
|
base.OnPreviewMouseLeftButtonDown(sender, e); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseMove(object sender, MouseEventArgs e) |
||||||
|
{ |
||||||
|
var delta = e.GetPosition(null) - startPoint; |
||||||
|
var point = new Point(delta.X, delta.Y); |
||||||
|
|
||||||
|
var segment = figure.Segments.Last(); |
||||||
|
if (segment is LineSegment) |
||||||
|
{ |
||||||
|
((LineSegment)segment).Point = point; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseUp(object sender, MouseButtonEventArgs e) |
||||||
|
{ |
||||||
|
var delta = e.GetPosition(null) - startPoint; |
||||||
|
var point = new Point(delta.X, delta.Y); |
||||||
|
|
||||||
|
figure.Segments.Add(new LineSegment(point, false)); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseDoubleClick(object sender, MouseButtonEventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseDoubleClick(sender, e); |
||||||
|
|
||||||
|
var geometry = newLine.Properties[Path.DataProperty].Value; |
||||||
|
geometry.Properties[PathGeometry.FiguresProperty].CollectionElements.Clear(); |
||||||
|
geometry.Properties[PathGeometry.FiguresProperty].SetValue(figure.ToString()); |
||||||
|
|
||||||
|
if (changeGroup != null) { |
||||||
|
changeGroup.Commit(); |
||||||
|
changeGroup = null; |
||||||
|
} |
||||||
|
|
||||||
|
Stop(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnStopped() |
||||||
|
{ |
||||||
|
if (changeGroup != null) { |
||||||
|
changeGroup.Abort(); |
||||||
|
changeGroup = null; |
||||||
|
} |
||||||
|
if (services.Tool.CurrentTool is CreateComponentTool) { |
||||||
|
services.Tool.CurrentTool = services.Tool.PointerTool; |
||||||
|
} |
||||||
|
|
||||||
|
((DesignPanel) newLine.Services.DesignPanel).AdornerLayer.UpdateAdornersForElement(this.newLine.View, true); |
||||||
|
|
||||||
|
base.OnStopped(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,453 @@ |
|||||||
|
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using ICSharpCode.WpfDesign.Extensions; |
||||||
|
using ICSharpCode.WpfDesign; |
||||||
|
using ICSharpCode.WpfDesign.Adorners; |
||||||
|
using ICSharpCode.WpfDesign.Designer; |
||||||
|
using ICSharpCode.WpfDesign.Designer.Controls; |
||||||
|
using System.Windows.Input; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Windows.Shapes; |
||||||
|
using System.Windows; |
||||||
|
using System.Windows.Controls; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Linq; |
||||||
|
using ICSharpCode.WpfDesign.Designer.UIExtensions; |
||||||
|
|
||||||
|
namespace ICSharpCode.WpfDesign.Designer.Extensions |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Description of PolyLineHandlerExtension.
|
||||||
|
/// </summary>
|
||||||
|
[ExtensionFor(typeof(Path))] |
||||||
|
internal class PathHandlerExtension : LineExtensionBase, IKeyDown, IKeyUp |
||||||
|
{ |
||||||
|
private readonly Dictionary<int, Bounds> _selectedThumbs = new Dictionary<int, Bounds>(); |
||||||
|
private bool _isDragging; |
||||||
|
ZoomControl _zoom; |
||||||
|
|
||||||
|
#region thumb methods
|
||||||
|
protected ResizeThumb CreateThumb(PlacementAlignment alignment, Cursor cursor, int index) |
||||||
|
{ |
||||||
|
ResizeThumb resizeThumb = new MultiPointResizeThumb { Index = index, Alignment = alignment, Cursor = cursor, IsPrimarySelection = true }; |
||||||
|
AdornerPlacement ap = Place(ref resizeThumb, alignment, index); |
||||||
|
(resizeThumb as MultiPointResizeThumb).AdornerPlacement = ap; |
||||||
|
|
||||||
|
AdornerPanel.SetPlacement(resizeThumb, ap); |
||||||
|
adornerPanel.Children.Add(resizeThumb); |
||||||
|
|
||||||
|
DragListener drag = new DragListener(resizeThumb); |
||||||
|
|
||||||
|
WeakEventManager<ResizeThumb, MouseButtonEventArgs>.AddHandler(resizeThumb, "PreviewMouseLeftButtonDown", ResizeThumbOnMouseLeftButtonUp); |
||||||
|
|
||||||
|
drag.Started += drag_Started; |
||||||
|
drag.Changed += drag_Changed; |
||||||
|
drag.Completed += drag_Completed; |
||||||
|
return resizeThumb; |
||||||
|
} |
||||||
|
|
||||||
|
private void ResetThumbs() |
||||||
|
{ |
||||||
|
foreach (FrameworkElement rt in adornerPanel.Children) |
||||||
|
{ |
||||||
|
if (rt is ResizeThumb) |
||||||
|
(rt as ResizeThumb).IsPrimarySelection = true; |
||||||
|
} |
||||||
|
_selectedThumbs.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
private void SelectThumb(MultiPointResizeThumb mprt) |
||||||
|
{ |
||||||
|
var points = GetPoints(); |
||||||
|
Point p = points[mprt.Index]; |
||||||
|
_selectedThumbs.Add(mprt.Index, new Bounds { X = p.X, Y = p.Y }); |
||||||
|
|
||||||
|
mprt.IsPrimarySelection = false; |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region eventhandlers
|
||||||
|
|
||||||
|
private void ResizeThumbOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs) |
||||||
|
{ |
||||||
|
//get current thumb
|
||||||
|
MultiPointResizeThumb mprt = sender as MultiPointResizeThumb; |
||||||
|
if (mprt != null) |
||||||
|
{ |
||||||
|
//shift+ctrl will remove selected point
|
||||||
|
if ((Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) && |
||||||
|
(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))) |
||||||
|
{ |
||||||
|
//unselect all points
|
||||||
|
ResetThumbs(); |
||||||
|
var points = GetPoints(); |
||||||
|
|
||||||
|
//iterate thumbs to lower index of remaining thumbs
|
||||||
|
foreach (MultiPointResizeThumb m in adornerPanel.Children) |
||||||
|
{ |
||||||
|
if (m.Index > mprt.Index) |
||||||
|
m.Index--; |
||||||
|
} |
||||||
|
|
||||||
|
//remove point and thumb
|
||||||
|
points.RemoveAt(mprt.Index); |
||||||
|
adornerPanel.Children.Remove(mprt); |
||||||
|
|
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//if not keyboard ctrl is pressed and selected point is not previously selected, clear selection
|
||||||
|
if (!_selectedThumbs.ContainsKey(mprt.Index) & !Keyboard.IsKeyDown(Key.LeftCtrl) & |
||||||
|
!Keyboard.IsKeyDown(Key.RightCtrl)) |
||||||
|
{ |
||||||
|
ResetThumbs(); |
||||||
|
} |
||||||
|
//add selected thumb, if ctrl pressed this could be all points in poly
|
||||||
|
if (!_selectedThumbs.ContainsKey(mprt.Index)) |
||||||
|
SelectThumb(mprt); |
||||||
|
_isDragging = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO : Remove all hide/show extensions from here.
|
||||||
|
protected void drag_Started(DragListener drag) |
||||||
|
{ |
||||||
|
//get current thumb
|
||||||
|
MultiPointResizeThumb mprt = (drag.Target as MultiPointResizeThumb); |
||||||
|
if (mprt != null) |
||||||
|
{ |
||||||
|
SetOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void SetOperation() |
||||||
|
{ |
||||||
|
var designPanel = ExtendedItem.Services.DesignPanel as DesignPanel; |
||||||
|
_zoom = designPanel.TryFindParent<ZoomControl>(); |
||||||
|
|
||||||
|
if (resizeBehavior != null) |
||||||
|
operation = PlacementOperation.Start(extendedItemArray, PlacementType.Resize); |
||||||
|
else |
||||||
|
{ |
||||||
|
changeGroup = ExtendedItem.Context.OpenGroup("Resize", extendedItemArray); |
||||||
|
} |
||||||
|
_isResizing = true; |
||||||
|
} |
||||||
|
|
||||||
|
void ChangeOperation(List<Point> points) |
||||||
|
{ |
||||||
|
//this is for SharpDevelop built in undo functionality
|
||||||
|
if (operation != null) |
||||||
|
{ |
||||||
|
var info = operation.PlacedItems[0]; |
||||||
|
var result = info.OriginalBounds; |
||||||
|
|
||||||
|
IEnumerable<double> xs = points.Select(x => x.X); |
||||||
|
IEnumerable<double> ys = points.Select(y => y.Y); |
||||||
|
result.X = (double)(info.Item.Properties.GetAttachedProperty(Canvas.LeftProperty).ValueOnInstance); |
||||||
|
result.Y = (double)(info.Item.Properties.GetAttachedProperty(Canvas.TopProperty).ValueOnInstance); |
||||||
|
result.Width = xs.Max() - xs.Min(); |
||||||
|
result.Height = ys.Max() - ys.Min(); |
||||||
|
|
||||||
|
info.Bounds = result.Round(); |
||||||
|
operation.CurrentContainerBehavior.BeforeSetPosition(operation); |
||||||
|
operation.CurrentContainerBehavior.SetPosition(info); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void CommitOperation() |
||||||
|
{ |
||||||
|
if (operation != null) |
||||||
|
{ |
||||||
|
PointCollection points; |
||||||
|
Polygon pg = ExtendedItem.View as Polygon; |
||||||
|
Polyline pl = ExtendedItem.View as Polyline; |
||||||
|
if (pl == null) |
||||||
|
{ |
||||||
|
points = pg.Points; |
||||||
|
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
points = pl.Points; |
||||||
|
} |
||||||
|
|
||||||
|
foreach (int i in _selectedThumbs.Keys) |
||||||
|
{ |
||||||
|
_selectedThumbs[i].X = points[i].X; |
||||||
|
_selectedThumbs[i].Y = points[i].Y; |
||||||
|
} |
||||||
|
ExtendedItem.Properties.GetProperty(pl != null ? Polyline.PointsProperty : Polygon.PointsProperty).SetValue(points); |
||||||
|
operation.Commit(); |
||||||
|
|
||||||
|
operation = null; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (changeGroup != null) |
||||||
|
changeGroup.Commit(); |
||||||
|
changeGroup = null; |
||||||
|
} |
||||||
|
_isResizing = false; |
||||||
|
|
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void drag_Changed(DragListener drag) |
||||||
|
{ |
||||||
|
var points = GetPoints(); |
||||||
|
|
||||||
|
MultiPointResizeThumb mprt = drag.Target as MultiPointResizeThumb; |
||||||
|
if (mprt != null) |
||||||
|
{ |
||||||
|
double dx = 0; |
||||||
|
double dy = 0; |
||||||
|
//if has zoomed
|
||||||
|
if (_zoom != null) |
||||||
|
{ |
||||||
|
dx = drag.Delta.X * (1 / _zoom.CurrentZoom); |
||||||
|
dy = drag.Delta.Y * (1 / _zoom.CurrentZoom); |
||||||
|
} |
||||||
|
|
||||||
|
Double theta; |
||||||
|
//if one point selected snapping angle is calculated in relation to previous point
|
||||||
|
if (_selectedThumbs.Count == 1) |
||||||
|
{ |
||||||
|
theta = (180 / Math.PI) * Math.Atan2(_selectedThumbs[mprt.Index].Y + dy - points[mprt.Index - 1].Y, _selectedThumbs[mprt.Index].X + dx - points[mprt.Index - 1].X); |
||||||
|
} |
||||||
|
else//if multiple points snapping angle is calculated in relation to mouse dragging angle
|
||||||
|
{ |
||||||
|
theta = (180 / Math.PI) * Math.Atan2(dy, dx); |
||||||
|
} |
||||||
|
|
||||||
|
//snappingAngle is used for snapping function to horizontal or vertical plane in line drawing, and is activated by pressing ctrl or shift button
|
||||||
|
int? snapAngle = null; |
||||||
|
|
||||||
|
//shift+alt gives a new point
|
||||||
|
if ((Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))) |
||||||
|
{ |
||||||
|
//if dragging occurs on a point and that point is the only selected, a new node will be added.
|
||||||
|
//_isCtrlDragging is needed since this method is called for every x pixel that the mouse moves
|
||||||
|
//so it could be many thousands of times during a single dragging
|
||||||
|
if (!_isDragging && _selectedThumbs.Count == 1 && (Math.Abs(dx) > 0 || Math.Abs(dy) > 0)) |
||||||
|
{ |
||||||
|
|
||||||
|
//duplicate point that is selected
|
||||||
|
Point p = points[mprt.Index]; |
||||||
|
|
||||||
|
//insert duplicate
|
||||||
|
points.Insert(mprt.Index, p); |
||||||
|
|
||||||
|
//create adorner marker
|
||||||
|
CreateThumb(PlacementAlignment.BottomRight, Cursors.Cross, mprt.Index); |
||||||
|
|
||||||
|
//set index of all points that had a higher index than selected to +1
|
||||||
|
foreach (FrameworkElement rt in adornerPanel.Children) |
||||||
|
{ |
||||||
|
if (rt is MultiPointResizeThumb) |
||||||
|
{ |
||||||
|
MultiPointResizeThumb t = rt as MultiPointResizeThumb; |
||||||
|
if (t.Index > mprt.Index) |
||||||
|
t.Index++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//set index of new point to old point index + 1
|
||||||
|
mprt.Index = mprt.Index + 1; |
||||||
|
ResetThumbs(); |
||||||
|
SelectThumb(mprt); |
||||||
|
|
||||||
|
} |
||||||
|
snapAngle = 10; |
||||||
|
} |
||||||
|
|
||||||
|
//snapping occurs when mouse is within 10 degrees from horizontal or vertical plane if shift is pressed
|
||||||
|
else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) |
||||||
|
{ |
||||||
|
snapAngle = 10; |
||||||
|
} |
||||||
|
//snapping occurs within 45 degree intervals that is line will always be horizontal or vertical if alt is pressed
|
||||||
|
else if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)) |
||||||
|
{ |
||||||
|
snapAngle = 45; |
||||||
|
} |
||||||
|
_isDragging = true; |
||||||
|
points = MovePoints(points, dx, dy, theta, snapAngle); |
||||||
|
|
||||||
|
} |
||||||
|
ChangeOperation(points); |
||||||
|
(drag.Target as ResizeThumb).InvalidateArrange(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void drag_Completed(DragListener drag) |
||||||
|
{ |
||||||
|
MultiPointResizeThumb mprt = drag.Target as MultiPointResizeThumb; |
||||||
|
if (mprt != null) |
||||||
|
{ |
||||||
|
if (operation != null && drag.IsCanceled) |
||||||
|
{ |
||||||
|
operation.Abort(); |
||||||
|
} |
||||||
|
else if (drag.IsCanceled) |
||||||
|
{ |
||||||
|
changeGroup.Abort(); |
||||||
|
} |
||||||
|
CommitOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnInitialized() |
||||||
|
{ |
||||||
|
base.OnInitialized(); |
||||||
|
|
||||||
|
var points = GetPoints(); |
||||||
|
|
||||||
|
resizeThumbs = new List<ResizeThumb>(); |
||||||
|
for (int i = 1; i < points.Count; i++) |
||||||
|
{ |
||||||
|
CreateThumb(PlacementAlignment.BottomRight, Cursors.Cross, i); |
||||||
|
} |
||||||
|
|
||||||
|
Invalidate(); |
||||||
|
|
||||||
|
ResetThumbs(); |
||||||
|
_isDragging = false; |
||||||
|
|
||||||
|
extendedItemArray[0] = ExtendedItem; |
||||||
|
ExtendedItem.PropertyChanged += OnPropertyChanged; |
||||||
|
resizeBehavior = PlacementOperation.GetPlacementBehavior(extendedItemArray); |
||||||
|
UpdateAdornerVisibility(); |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
List<Point> GetPoints() |
||||||
|
{ |
||||||
|
var retVal = new List<Point>(); |
||||||
|
|
||||||
|
var path = this.ExtendedItem.View as Path; |
||||||
|
var geometry = path.Data as PathGeometry; |
||||||
|
if (geometry!=null) { |
||||||
|
var figure = geometry.Figures[0] as PathFigure; |
||||||
|
if (figure != null) { |
||||||
|
foreach (var s in figure.Segments) { |
||||||
|
if (s is LineSegment) |
||||||
|
retVal.Add(((LineSegment)s).Point); |
||||||
|
else if (s is PolyLineSegment) |
||||||
|
retVal.AddRange(((PolyLineSegment)s).Points); |
||||||
|
// else if (s is BezierSegment)
|
||||||
|
// retVal.Add(((BezierSegment)s).Point3);
|
||||||
|
// else if (s is QuadraticBezierSegment)
|
||||||
|
// retVal.Add(((QuadraticBezierSegment)s).Point2);
|
||||||
|
// else if (s is ArcSegment)
|
||||||
|
// retVal.Add(((ArcSegment)s).Point);
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return retVal; |
||||||
|
} |
||||||
|
|
||||||
|
List<Point> MovePoints(List<Point> pc, double displacementX, double displacementY, double theta, int? snapangle) |
||||||
|
{ |
||||||
|
//iterate all selected points
|
||||||
|
foreach (int i in _selectedThumbs.Keys) |
||||||
|
{ |
||||||
|
Point p = pc[i]; |
||||||
|
|
||||||
|
//x and y is calculated from the currentl point
|
||||||
|
double x = _selectedThumbs[i].X + displacementX; |
||||||
|
double y = _selectedThumbs[i].Y + displacementY; |
||||||
|
|
||||||
|
//if snap is applied
|
||||||
|
if (snapangle != null) |
||||||
|
{ |
||||||
|
if (_selectedThumbs.Count > 0) |
||||||
|
{ |
||||||
|
//horizontal snap
|
||||||
|
if (Math.Abs(theta) < snapangle || 180 - Math.Abs(theta) < snapangle) |
||||||
|
{ |
||||||
|
//if one point selected use point before as snap point, else snap to movement
|
||||||
|
y = _selectedThumbs.Count == 1 ? pc[i - 1].Y : y - displacementY; |
||||||
|
} |
||||||
|
else if (Math.Abs(90 - Math.Abs(theta)) < snapangle)//vertical snap
|
||||||
|
{ |
||||||
|
//if one point selected use point before as snap point, else snap to movement
|
||||||
|
x = _selectedThumbs.Count == 1 ? pc[i - 1].X : x - displacementX; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
p.X = x; |
||||||
|
p.Y = y; |
||||||
|
pc[i] = p; |
||||||
|
} |
||||||
|
return pc; |
||||||
|
} |
||||||
|
|
||||||
|
#region IKeyDown
|
||||||
|
|
||||||
|
public bool InvokeDefaultAction |
||||||
|
{ |
||||||
|
get { return _selectedThumbs.Count == 0 || _selectedThumbs.Count == GetPoints().Count - 1; } |
||||||
|
} |
||||||
|
|
||||||
|
int _movingDistance; |
||||||
|
public void KeyDownAction(object sender, KeyEventArgs e) |
||||||
|
{ |
||||||
|
Debug.WriteLine("KeyDown"); |
||||||
|
if (IsArrowKey(e.Key)) |
||||||
|
if (operation == null) |
||||||
|
{ |
||||||
|
SetOperation(); |
||||||
|
_movingDistance = 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var dx1 = (e.Key == Key.Left) ? Keyboard.IsKeyDown(Key.LeftShift) ? _movingDistance - 10 : _movingDistance - 1 : 0; |
||||||
|
var dy1 = (e.Key == Key.Up) ? Keyboard.IsKeyDown(Key.LeftShift) ? _movingDistance - 10 : _movingDistance - 1 : 0; |
||||||
|
var dx2 = (e.Key == Key.Right) ? Keyboard.IsKeyDown(Key.LeftShift) ? _movingDistance + 10 : _movingDistance + 1 : 0; |
||||||
|
var dy2 = (e.Key == Key.Down) ? Keyboard.IsKeyDown(Key.LeftShift) ? _movingDistance + 10 : _movingDistance + 1 : 0; |
||||||
|
|
||||||
|
ChangeOperation(MovePoints(GetPoints(), dx1 + dx2, dy1 + dy2, 0, null)); |
||||||
|
_movingDistance = (dx1 + dx2 + dy1 + dy2); |
||||||
|
} |
||||||
|
|
||||||
|
public void KeyUpAction(object sender, KeyEventArgs e) |
||||||
|
{ |
||||||
|
Debug.WriteLine("Keyup"); |
||||||
|
if (IsArrowKey(e.Key)) |
||||||
|
CommitOperation(); |
||||||
|
} |
||||||
|
|
||||||
|
bool IsArrowKey(Key key) |
||||||
|
{ |
||||||
|
return (key == Key.Left || key == Key.Right || key == Key.Up || key == Key.Down); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue