|
|
|
|
@ -79,7 +79,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -79,7 +79,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
private void SelectThumb(MultiPointResizeThumb mprt) |
|
|
|
|
{ |
|
|
|
|
var points = GetPoints(); |
|
|
|
|
Point p = points[mprt.Index]; |
|
|
|
|
Point p = points[mprt.Index].Point; |
|
|
|
|
_selectedThumbs.Add(mprt.Index, new Bounds { X = p.X, Y = p.Y }); |
|
|
|
|
|
|
|
|
|
mprt.IsPrimarySelection = false; |
|
|
|
|
@ -162,7 +162,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -162,7 +162,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
_isResizing = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ChangeOperation(List<Point> points) |
|
|
|
|
void ChangeOperation(List<PathPoint> points) |
|
|
|
|
{ |
|
|
|
|
//this is for SharpDevelop built in undo functionality
|
|
|
|
|
if (operation != null) |
|
|
|
|
@ -170,8 +170,8 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -170,8 +170,8 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
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); |
|
|
|
|
IEnumerable<double> xs = points.Select(x => x.Point.X); |
|
|
|
|
IEnumerable<double> ys = points.Select(y => y.Point.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(); |
|
|
|
|
@ -229,7 +229,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -229,7 +229,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
Double theta; |
|
|
|
|
//if one point selected snapping angle is calculated in relation to previous point
|
|
|
|
|
if (_selectedThumbs.Count == 1 && mprt.Index > 0) { |
|
|
|
|
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); |
|
|
|
|
theta = (180 / Math.PI) * Math.Atan2(_selectedThumbs[mprt.Index].Y + dy - points[mprt.Index - 1].Point.Y, _selectedThumbs[mprt.Index].X + dx - points[mprt.Index - 1].Point.X); |
|
|
|
|
} else { //if multiple points snapping angle is calculated in relation to mouse dragging angle
|
|
|
|
|
theta = (180 / Math.PI) * Math.Atan2(dy, dx); |
|
|
|
|
} |
|
|
|
|
@ -238,45 +238,45 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -238,45 +238,45 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
// 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].Point;
|
|
|
|
|
//
|
|
|
|
|
// //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)) |
|
|
|
|
/*else*/ if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) |
|
|
|
|
{ |
|
|
|
|
snapAngle = 10; |
|
|
|
|
} |
|
|
|
|
@ -337,49 +337,124 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -337,49 +337,124 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
List<Point> GetPoints() |
|
|
|
|
List<PathPoint> GetPoints() |
|
|
|
|
{ |
|
|
|
|
return GetPoints(this.ExtendedItem.View as Path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static List<Point> GetPoints(Path path) |
|
|
|
|
public static List<PathPoint> GetPoints(Path path) |
|
|
|
|
{ |
|
|
|
|
var retVal = new List<Point>(); |
|
|
|
|
var retVal = new List<PathPoint>(); |
|
|
|
|
AddGeometryPoints(retVal, path.Data); |
|
|
|
|
|
|
|
|
|
var geometry = path.Data as PathGeometry; |
|
|
|
|
if (geometry!=null) { |
|
|
|
|
var figure = geometry.Figures[0] as PathFigure; |
|
|
|
|
if (figure != null) { |
|
|
|
|
retVal.Add(figure.StartPoint); |
|
|
|
|
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).Point1); |
|
|
|
|
retVal.Add(((BezierSegment)s).Point2); |
|
|
|
|
retVal.Add(((BezierSegment)s).Point3); |
|
|
|
|
} |
|
|
|
|
else if (s is QuadraticBezierSegment) { |
|
|
|
|
retVal.Add(((QuadraticBezierSegment)s).Point1); |
|
|
|
|
retVal.Add(((QuadraticBezierSegment)s).Point2); |
|
|
|
|
return retVal; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void AddGeometryPoints(List<PathPoint> list, Geometry geometry) |
|
|
|
|
{ |
|
|
|
|
if (geometry is CombinedGeometry) { |
|
|
|
|
var g = geometry as CombinedGeometry; |
|
|
|
|
AddGeometryPoints(list, g.Geometry1); |
|
|
|
|
AddGeometryPoints(list, g.Geometry2); |
|
|
|
|
} else if (geometry is PathGeometry) { |
|
|
|
|
var g = geometry as PathGeometry; |
|
|
|
|
if (geometry!=null) { |
|
|
|
|
foreach(var figure in g.Figures) { |
|
|
|
|
list.Add(new PathPoint(figure.StartPoint, figure, PointType.StartPoint, (p) => figure.StartPoint = p)); |
|
|
|
|
foreach (var s in figure.Segments) { |
|
|
|
|
if (s is LineSegment) |
|
|
|
|
list.Add(new PathPoint(((LineSegment)s).Point, s, PointType.LineSegment, (p) => ((LineSegment)s).Point = p)); |
|
|
|
|
else if (s is PolyLineSegment) { |
|
|
|
|
//list.AddRange(((PolyLineSegment)s).Points);
|
|
|
|
|
} |
|
|
|
|
else if (s is BezierSegment) { |
|
|
|
|
list.Add(new PathPoint(((BezierSegment)s).Point1, s, PointType.BezierSegment, (p) => ((BezierSegment)s).Point1 = p)); |
|
|
|
|
//list.Add(((BezierSegment)s).Point1);
|
|
|
|
|
//list.Add(((BezierSegment)s).Point2);
|
|
|
|
|
//list.Add(((BezierSegment)s).Point3);
|
|
|
|
|
} |
|
|
|
|
else if (s is QuadraticBezierSegment) { |
|
|
|
|
list.Add(new PathPoint(((QuadraticBezierSegment)s).Point1, s, PointType.QuadricBezierSegment, (p) => ((QuadraticBezierSegment)s).Point1 = p)); |
|
|
|
|
//list.Add(((QuadraticBezierSegment)s).Point1);
|
|
|
|
|
//list.Add(((QuadraticBezierSegment)s).Point2);
|
|
|
|
|
} |
|
|
|
|
else if (s is ArcSegment) |
|
|
|
|
list.Add(new PathPoint(((ArcSegment)s).Point, s, PointType.ArcSegment, (p) => ((ArcSegment)s).Point = p)); |
|
|
|
|
//list.Add(((ArcSegment)s).Point);
|
|
|
|
|
} |
|
|
|
|
else if (s is ArcSegment) |
|
|
|
|
retVal.Add(((ArcSegment)s).Point); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else if (geometry is RectangleGeometry) { |
|
|
|
|
var g = geometry as RectangleGeometry; |
|
|
|
|
list.Add(new PathPoint(g.Rect.TopLeft, geometry, PointType.RectangleGeometryP1, null)); //(p) => g.Rect.Left = p.X));
|
|
|
|
|
list.Add(new PathPoint(g.Rect.TopRight, geometry, PointType.RectangleGeometryP2, null)); //(p) => g.Rect.Width = p.X));
|
|
|
|
|
list.Add(new PathPoint(g.Rect.BottomLeft, geometry, PointType.RectangleGeometryP3, null)); //(p) => g.Rect.Top = p.Y));
|
|
|
|
|
list.Add(new PathPoint(g.Rect.BottomRight, geometry, PointType.RectangleGeometryP4, null)); //(p) => g.Rect.Height = p.Y));
|
|
|
|
|
// list.Add(new Point(g.Rect.Left, g.Rect.Top));
|
|
|
|
|
// list.Add(new Point(g.Rect.Left, g.Rect.Top + g.Rect.Height));
|
|
|
|
|
// list.Add(new Point(g.Rect.Left + g.Rect.Width, g.Rect.Top));
|
|
|
|
|
// list.Add(new Point(g.Rect.Left + g.Rect.Width, g.Rect.Top + g.Rect.Height));
|
|
|
|
|
} else if (geometry is EllipseGeometry) { |
|
|
|
|
var g = geometry as EllipseGeometry; |
|
|
|
|
list.Add(new PathPoint(g.Center, geometry, PointType.EllipseGeometryCenter, (p) => g.Center = p)); |
|
|
|
|
//list.Add(g.Center);
|
|
|
|
|
} else if (geometry is LineGeometry) { |
|
|
|
|
var g = geometry as LineGeometry; |
|
|
|
|
list.Add(new PathPoint(g.StartPoint, geometry, PointType.LineGeometryStart, (p) => g.StartPoint = p)); |
|
|
|
|
list.Add(new PathPoint(g.EndPoint, geometry, PointType.LineGeometryEnd, (p) => g.EndPoint = p)); |
|
|
|
|
//list.Add(g.StartPoint);
|
|
|
|
|
//list.Add(g.EndPoint);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public enum PointType{ |
|
|
|
|
StartPoint, |
|
|
|
|
LineSegment, |
|
|
|
|
BezierSegment, |
|
|
|
|
ArcSegment, |
|
|
|
|
QuadricBezierSegment, |
|
|
|
|
|
|
|
|
|
return retVal; |
|
|
|
|
LineGeometryStart, |
|
|
|
|
LineGeometryEnd, |
|
|
|
|
EllipseGeometryCenter, |
|
|
|
|
RectangleGeometryP1, |
|
|
|
|
RectangleGeometryP2, |
|
|
|
|
RectangleGeometryP3, |
|
|
|
|
RectangleGeometryP4, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<Point> MovePoints(List<Point> pc, double displacementX, double displacementY, double theta, int? snapangle) |
|
|
|
|
|
|
|
|
|
public class PathPoint { |
|
|
|
|
public PathPoint(Point point, Object @object, PointType pointType, Action<Point> setLambda) |
|
|
|
|
{ |
|
|
|
|
this._point = point; |
|
|
|
|
this._setLambda = setLambda; |
|
|
|
|
this.Object = @object; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private Point _point; |
|
|
|
|
Action<Point> _setLambda; |
|
|
|
|
|
|
|
|
|
public Point Point { |
|
|
|
|
get{return _point;} |
|
|
|
|
set{_setLambda(value);} |
|
|
|
|
} |
|
|
|
|
public Point ReferencePoint {get; private set;} |
|
|
|
|
public PointType Start {get; private set;} |
|
|
|
|
public PointType End {get; private set;} |
|
|
|
|
public object Object {get; private set;} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Should not return a List of Points, no a List of Point Object wich say what a Point is.
|
|
|
|
|
//For Example: a Center Point of a Circle, should now it's a Center point!
|
|
|
|
|
//When he is selected, he should show another drag point to change the radius!
|
|
|
|
|
//a Combined Gemoetry should show a Adorner to change the combination mode!
|
|
|
|
|
|
|
|
|
|
List<PathPoint> MovePoints(List<PathPoint> pc, double displacementX, double displacementY, double theta, int? snapangle) |
|
|
|
|
{ |
|
|
|
|
//iterate all selected points
|
|
|
|
|
foreach (int i in _selectedThumbs.Keys) |
|
|
|
|
{ |
|
|
|
|
Point p = pc[i]; |
|
|
|
|
Point p = pc[i].Point; |
|
|
|
|
|
|
|
|
|
//x and y is calculated from the currentl point
|
|
|
|
|
double x = _selectedThumbs[i].X + displacementX; |
|
|
|
|
@ -394,19 +469,19 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
@@ -394,19 +469,19 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
|
|
|
|
|
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; |
|
|
|
|
y = _selectedThumbs.Count == 1 ? pc[i - 1].Point.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; |
|
|
|
|
x = _selectedThumbs.Count == 1 ? pc[i - 1].Point.X : x - displacementX; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
p.X = x; |
|
|
|
|
p.Y = y; |
|
|
|
|
pc[i] = p; |
|
|
|
|
pc[i].Point = p; |
|
|
|
|
} |
|
|
|
|
return pc; |
|
|
|
|
} |
|
|
|
|
|