6 changed files with 622 additions and 2 deletions
@ -0,0 +1,161 @@
@@ -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 @@
@@ -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