Browse Source

Code fixes in Line/Polyline Extensions

pull/630/head
jkuehner 11 years ago
parent
commit
6ca3555dc7
  1. 350
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/LineExtensionBase.cs
  2. 457
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/LineHandlerExtension.cs
  3. 859
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PolyLineHandlerExtension.cs
  4. 11
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/ResizeThumbExtension.cs

350
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/LineExtensionBase.cs

@ -1,11 +1,21 @@ @@ -1,11 +1,21 @@
/*
* Created by SharpDevelop.
* User: trubra
* Date: 2014-12-22
* Time: 11:00
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// 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.Designer.Controls;
using ICSharpCode.WpfDesign.Designer.Extensions;
@ -25,166 +35,166 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -25,166 +35,166 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
/// Description of LineExtensionBase.
/// </summary>
class Bounds
{
public double X, Y, Left, Top;
}
/// <summary>
/// base class for the Line, Polyline and Polygon extension classes
/// </summary>
public class LineExtensionBase : SelectionAdornerProvider
{
internal AdornerPanel adornerPanel;
internal IEnumerable resizeThumbs;
/// <summary>An array containing this.ExtendedItem as only element</summary>
internal readonly DesignItem[] extendedItemArray = new DesignItem[1];
internal IPlacementBehavior resizeBehavior;
internal PlacementOperation operation;
internal ChangeGroup changeGroup;
private Canvas _surface;
internal bool _isResizing;
private TextBlock _text;
//private DesignPanel designPanel;
/// <summary>
/// Gets whether this extension is resizing any element.
/// </summary>
public bool IsResizing
{
get { return _isResizing; }
}
/// <summary>
/// on creation add adornerlayer
/// </summary>
public LineExtensionBase()
{
_surface = new Canvas();
adornerPanel = new AdornerPanel();
adornerPanel.Order = AdornerOrder.Foreground;
adornerPanel.Children.Add(_surface);
Adorners.Add(adornerPanel);
}
#region eventhandlers
protected void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
UpdateAdornerVisibility();
}
protected override void OnRemove()
{
this.ExtendedItem.PropertyChanged -= OnPropertyChanged;
this.Services.Selection.PrimarySelectionChanged -= OnPrimarySelectionChanged;
DependencyPropertyDescriptor.FromProperty(FrameworkElement.HeightProperty, typeof (Shape))
.RemoveValueChanged(ExtendedItem.View, (s, ev) => ResetWidthHeightProperties());
base.OnRemove();
}
protected void OnPrimarySelectionChanged(object sender, EventArgs e)
{
bool isPrimarySelection = this.Services.Selection.PrimarySelection == this.ExtendedItem;
if (isPrimarySelection)
DependencyPropertyDescriptor.FromProperty(FrameworkElement.HeightProperty, typeof (Shape))
.AddValueChanged(ExtendedItem.View, (s, ev) => ResetWidthHeightProperties());
//foreach (ResizeThumb g in adornerPanel.Children)
//{
// g.IsPrimarySelection = isPrimarySelection;
//}
}
#endregion
protected void UpdateAdornerVisibility()
{
FrameworkElement fe = this.ExtendedItem.View as FrameworkElement;
foreach (ResizeThumb r in resizeThumbs)
{
bool isVisible = resizeBehavior != null &&
resizeBehavior.CanPlace(extendedItemArray, PlacementType.Resize, r.Alignment);
r.Visibility = isVisible ? Visibility.Visible : Visibility.Hidden;
}
}
/// <summary>
/// Places resize thumbs at their respective positions
/// and streches out thumbs which are at the center of outline to extend resizability across the whole outline
/// </summary>
/// <param name="resizeThumb"></param>
/// <param name="alignment"></param>
/// <param name="index">if using a polygon or multipoint adorner this is the index of the point in the Points array</param>
/// <returns></returns>
protected PointTrackerPlacementSupport Place(ref ResizeThumb resizeThumb, PlacementAlignment alignment, int index = -1)
{
PointTrackerPlacementSupport placement = new PointTrackerPlacementSupport(ExtendedItem.View as Shape, alignment, index);
return placement;
}
/// <summary>
/// forces redraw of shape
/// </summary>
protected void Invalidate()
{
Shape s = ExtendedItem.View as Shape;
if (s != null)
{
s.InvalidateVisual();
s.BringIntoView();
}
}
protected void SetSurfaceInfo(int x, int y, string s)
{
if (_text == null)
{
_text = new TextBlock();
_surface.Children.Add(_text);
}
AdornerPanel ap = _surface.Parent as AdornerPanel;
_surface.Width = ap.Width;
_surface.Height = ap.Height;
_text.Text = s;
Canvas.SetLeft(_text, x);
Canvas.SetTop(_text, y);
}
protected void HideSizeAndShowHandles()
{
SizeDisplayExtension sizeDisplay = null;
MarginHandleExtension marginDisplay = null;
foreach (var extension in ExtendedItem.Extensions)
{
if (extension is SizeDisplayExtension)
sizeDisplay = extension as SizeDisplayExtension;
if (extension is MarginHandleExtension)
marginDisplay = extension as MarginHandleExtension;
}
if (sizeDisplay != null)
{
sizeDisplay.HeightDisplay.Visibility = Visibility.Hidden;
sizeDisplay.WidthDisplay.Visibility = Visibility.Hidden;
}
if (marginDisplay != null)
{
marginDisplay.ShowHandles();
}
}
protected void ResetWidthHeightProperties()
{
ExtendedItem.Properties.GetProperty(FrameworkElement.HeightProperty).Reset();
ExtendedItem.Properties.GetProperty(FrameworkElement.WidthProperty).Reset();
}
}
{
public double X, Y, Left, Top;
}
/// <summary>
/// base class for the Line, Polyline and Polygon extension classes
/// </summary>
public class LineExtensionBase : SelectionAdornerProvider
{
internal AdornerPanel adornerPanel;
internal IEnumerable resizeThumbs;
/// <summary>An array containing this.ExtendedItem as only element</summary>
internal readonly DesignItem[] extendedItemArray = new DesignItem[1];
internal IPlacementBehavior resizeBehavior;
internal PlacementOperation operation;
internal ChangeGroup changeGroup;
private Canvas _surface;
internal bool _isResizing;
private TextBlock _text;
//private DesignPanel designPanel;
/// <summary>
/// Gets whether this extension is resizing any element.
/// </summary>
public bool IsResizing
{
get { return _isResizing; }
}
/// <summary>
/// on creation add adornerlayer
/// </summary>
public LineExtensionBase()
{
_surface = new Canvas();
adornerPanel = new AdornerPanel();
adornerPanel.Order = AdornerOrder.Foreground;
adornerPanel.Children.Add(_surface);
Adorners.Add(adornerPanel);
}
#region eventhandlers
protected void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
UpdateAdornerVisibility();
}
protected override void OnRemove()
{
this.ExtendedItem.PropertyChanged -= OnPropertyChanged;
this.Services.Selection.PrimarySelectionChanged -= OnPrimarySelectionChanged;
DependencyPropertyDescriptor.FromProperty(FrameworkElement.HeightProperty, typeof (Shape))
.RemoveValueChanged(ExtendedItem.View, (s, ev) => ResetWidthHeightProperties());
base.OnRemove();
}
protected void OnPrimarySelectionChanged(object sender, EventArgs e)
{
bool isPrimarySelection = this.Services.Selection.PrimarySelection == this.ExtendedItem;
if (isPrimarySelection)
DependencyPropertyDescriptor.FromProperty(FrameworkElement.HeightProperty, typeof (Shape))
.AddValueChanged(ExtendedItem.View, (s, ev) => ResetWidthHeightProperties());
//foreach (ResizeThumb g in adornerPanel.Children)
//{
// g.IsPrimarySelection = isPrimarySelection;
//}
}
#endregion
protected void UpdateAdornerVisibility()
{
FrameworkElement fe = this.ExtendedItem.View as FrameworkElement;
foreach (ResizeThumb r in resizeThumbs)
{
bool isVisible = resizeBehavior != null &&
resizeBehavior.CanPlace(extendedItemArray, PlacementType.Resize, r.Alignment);
r.Visibility = isVisible ? Visibility.Visible : Visibility.Hidden;
}
}
/// <summary>
/// Places resize thumbs at their respective positions
/// and streches out thumbs which are at the center of outline to extend resizability across the whole outline
/// </summary>
/// <param name="resizeThumb"></param>
/// <param name="alignment"></param>
/// <param name="index">if using a polygon or multipoint adorner this is the index of the point in the Points array</param>
/// <returns></returns>
protected PointTrackerPlacementSupport Place(ref ResizeThumb resizeThumb, PlacementAlignment alignment, int index = -1)
{
PointTrackerPlacementSupport placement = new PointTrackerPlacementSupport(ExtendedItem.View as Shape, alignment, index);
return placement;
}
/// <summary>
/// forces redraw of shape
/// </summary>
protected void Invalidate()
{
Shape s = ExtendedItem.View as Shape;
if (s != null)
{
s.InvalidateVisual();
s.BringIntoView();
}
}
protected void SetSurfaceInfo(int x, int y, string s)
{
if (_text == null)
{
_text = new TextBlock();
_surface.Children.Add(_text);
}
AdornerPanel ap = _surface.Parent as AdornerPanel;
_surface.Width = ap.Width;
_surface.Height = ap.Height;
_text.Text = s;
Canvas.SetLeft(_text, x);
Canvas.SetTop(_text, y);
}
protected void HideSizeAndShowHandles()
{
SizeDisplayExtension sizeDisplay = null;
MarginHandleExtension marginDisplay = null;
foreach (var extension in ExtendedItem.Extensions)
{
if (extension is SizeDisplayExtension)
sizeDisplay = extension as SizeDisplayExtension;
if (extension is MarginHandleExtension)
marginDisplay = extension as MarginHandleExtension;
}
if (sizeDisplay != null)
{
sizeDisplay.HeightDisplay.Visibility = Visibility.Hidden;
sizeDisplay.WidthDisplay.Visibility = Visibility.Hidden;
}
if (marginDisplay != null)
{
marginDisplay.ShowHandles();
}
}
protected void ResetWidthHeightProperties()
{
ExtendedItem.Properties.GetProperty(FrameworkElement.HeightProperty).Reset();
ExtendedItem.Properties.GetProperty(FrameworkElement.WidthProperty).Reset();
}
}
}

457
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/LineHandlerExtension.cs

@ -1,11 +1,21 @@ @@ -1,11 +1,21 @@
/*
* Created by SharpDevelop.
* User: trubra
* Date: 2014-12-22
* Time: 10:34
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// 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;
@ -21,228 +31,221 @@ using System; @@ -21,228 +31,221 @@ 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 LineHandlerExtension.
/// </summary>
[ExtensionFor(typeof(Line), OverrideExtensions = new Type[] { typeof(ResizeThumbExtension), typeof(SelectedElementRectangleExtension), typeof(CanvasPositionExtension), typeof(QuickOperationMenuExtension), typeof(RotateThumbExtension), typeof(RenderTransformOriginExtension), typeof(InPlaceEditorExtension) })]
internal class LineHandlerExtension : LineExtensionBase
{
//
private double CurrentX2;
private double CurrentY2;
private double CurrentLeft;
private double CurrentTop;
//Size oldSize;
ZoomControl zoom;
protected ResizeThumb CreateThumb(PlacementAlignment alignment, Cursor cursor)
{
ResizeThumb resizeThumb = new ResizeThumb { Alignment = alignment, Cursor = cursor, IsPrimarySelection = true};
AdornerPanel.SetPlacement(resizeThumb, Place(ref resizeThumb, alignment));
adornerPanel.Children.Add(resizeThumb);
DragListener drag = new DragListener(resizeThumb);
drag.Started += drag_Started;
drag.Changed += drag_Changed;
drag.Completed += drag_Completed;
return resizeThumb;
}
protected Bounds CalculateDrawing(double x, double y, double left, double top, double xleft, double xtop)
{
Double theta = (180 / Math.PI) * Math.Atan2(y, x);
double verticaloffset = Math.Abs(90 - Math.Abs(theta));
if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
{
if (Math.Abs(theta) < 45 || Math.Abs(theta) > 135)
{
y = 0;
top = xtop;
}
else if (verticaloffset < 45)
{
x = 0;
left = xleft;
}
}
else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
if (verticaloffset < 10)
{
x = 0;
left = xleft;
}
else if (Math.Abs(theta) < 10 || Math.Abs(theta) > 170)
{
y = 0;
top = xtop;
}
}
SetSurfaceInfo(0, 0, Math.Round((180 / Math.PI) * Math.Atan2(y, x), 0).ToString());
return new Bounds { X = Math.Round(x, 1), Y = Math.Round(y, 1), Left = Math.Round(left, 1), Top = Math.Round(top, 1) };
}
#region eventhandlers
// TODO : Remove all hide/show extensions from here.
protected virtual void drag_Started(DragListener drag)
{
Line al = ExtendedItem.View as Line;
CurrentX2 = al.X2;
CurrentY2 = al.Y2;
CurrentLeft = (double)al.GetValue(Canvas.LeftProperty);
CurrentTop = (double)al.GetValue(Canvas.TopProperty);
var designPanel = ExtendedItem.Services.DesignPanel as DesignPanel;
if (designPanel != null)
{
var p = VisualTreeHelper.GetParent(designPanel);
while (p != null && !(p is ZoomControl))
{
p = VisualTreeHelper.GetParent(p);
}
zoom = p as ZoomControl;
}
if (resizeBehavior != null)
operation = PlacementOperation.Start(extendedItemArray, PlacementType.Resize);
else
{
changeGroup = this.ExtendedItem.Context.OpenGroup("Resize", extendedItemArray);
}
_isResizing = true;
(drag.Target as ResizeThumb).IsPrimarySelection = false;
}
protected virtual void drag_Changed(DragListener drag)
{
Line al = ExtendedItem.View as Line;
var alignment = (drag.Target as ResizeThumb).Alignment;
var info = operation.PlacedItems[0];
double dx = 0;
double dy = 0;
if (zoom != null)
{
dx = drag.Delta.X * (1 / zoom.CurrentZoom);
dy = drag.Delta.Y * (1 / zoom.CurrentZoom);
}
double top, left, x, y, xtop, xleft;
if (alignment == PlacementAlignment.TopLeft)
{
//normal values
x = CurrentX2 - dx;
y = CurrentY2 - dy;
top = CurrentTop + dy;
left = CurrentLeft + dx;
//values to use when keys are pressed
xtop = CurrentTop + CurrentY2;
xleft = CurrentLeft + CurrentX2;
}
else
{
x = CurrentX2 + dx;
y = CurrentY2 + dy;
top = xtop = CurrentTop;
left = xleft = CurrentLeft;
}
Bounds position = CalculateDrawing(x, y, left, top, xleft, xtop);
ExtendedItem.Properties.GetProperty(Line.X1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.Y1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.X2Property).SetValue(position.X);
ExtendedItem.Properties.GetProperty(Line.Y2Property).SetValue(position.Y);
if (operation != null)
{
var result = info.OriginalBounds;
result.X = position.Left;
result.Y = position.Top;
result.Width = Math.Abs(position.X);
result.Height = Math.Abs(position.Y);
info.Bounds = result.Round();
operation.CurrentContainerBehavior.BeforeSetPosition(operation);
operation.CurrentContainerBehavior.SetPosition(info);
}
(drag.Target as ResizeThumb).InvalidateArrange();
ResetWidthHeightProperties();
}
protected virtual void drag_Completed(DragListener drag)
{
if (operation != null)
{
if (drag.IsCanceled) operation.Abort();
else
{
ResetWidthHeightProperties();
operation.Commit();
}
operation = null;
}
else
{
if (drag.IsCanceled) changeGroup.Abort();
else changeGroup.Commit();
changeGroup = null;
}
_isResizing = false;
(drag.Target as ResizeThumb).IsPrimarySelection = true;
HideSizeAndShowHandles();
}
/// <summary>
/// is invoked whenever a line is selected on the canvas, remember that the adorners are created for each line object and never destroyed
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
if (ExtendedItem.Properties.GetProperty(Line.StrokeProperty).ValueOnInstance == null)
{
ExtendedItem.Properties[Shape.StrokeProperty].SetValue(Colors.Black);
ExtendedItem.Properties[Shape.StrokeThicknessProperty].SetValue(2d);
ExtendedItem.Properties[Shape.StretchProperty].SetValue(Stretch.None);
ExtendedItem.Properties.GetProperty(Line.X1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.Y1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.X2Property).SetValue(20);
ExtendedItem.Properties.GetProperty(Line.Y2Property).SetValue(20);
(ExtendedItem.View as Line).BringIntoView();
}
resizeThumbs = new ResizeThumb[]
{
CreateThumb(PlacementAlignment.TopLeft, Cursors.SizeNWSE),
CreateThumb(PlacementAlignment.BottomRight, Cursors.SizeNWSE)
};
extendedItemArray[0] = this.ExtendedItem;
Invalidate();
//ResetWidthHeightProperties();
this.ExtendedItem.PropertyChanged += OnPropertyChanged;
this.Services.Selection.PrimarySelectionChanged += OnPrimarySelectionChanged;
resizeBehavior = PlacementOperation.GetPlacementBehavior(extendedItemArray);
UpdateAdornerVisibility();
OnPrimarySelectionChanged(null, null);
}
#endregion
}
[ExtensionFor(typeof(Line), OverrideExtensions = new Type[] { typeof(ResizeThumbExtension), typeof(SelectedElementRectangleExtension), typeof(CanvasPositionExtension), typeof(QuickOperationMenuExtension), typeof(RotateThumbExtension), typeof(RenderTransformOriginExtension), typeof(InPlaceEditorExtension), typeof(SkewThumbExtension) })]
internal class LineHandlerExtension : LineExtensionBase
{
//
private double CurrentX2;
private double CurrentY2;
private double CurrentLeft;
private double CurrentTop;
//Size oldSize;
ZoomControl zoom;
protected ResizeThumb CreateThumb(PlacementAlignment alignment, Cursor cursor)
{
ResizeThumb resizeThumb = new ResizeThumb { Alignment = alignment, Cursor = cursor, IsPrimarySelection = true};
AdornerPanel.SetPlacement(resizeThumb, Place(ref resizeThumb, alignment));
adornerPanel.Children.Add(resizeThumb);
DragListener drag = new DragListener(resizeThumb);
drag.Started += drag_Started;
drag.Changed += drag_Changed;
drag.Completed += drag_Completed;
return resizeThumb;
}
protected Bounds CalculateDrawing(double x, double y, double left, double top, double xleft, double xtop)
{
Double theta = (180 / Math.PI) * Math.Atan2(y, x);
double verticaloffset = Math.Abs(90 - Math.Abs(theta));
if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
{
if (Math.Abs(theta) < 45 || Math.Abs(theta) > 135)
{
y = 0;
top = xtop;
}
else if (verticaloffset < 45)
{
x = 0;
left = xleft;
}
}
else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
if (verticaloffset < 10)
{
x = 0;
left = xleft;
}
else if (Math.Abs(theta) < 10 || Math.Abs(theta) > 170)
{
y = 0;
top = xtop;
}
}
SetSurfaceInfo(0, 0, Math.Round((180 / Math.PI) * Math.Atan2(y, x), 0).ToString());
return new Bounds { X = Math.Round(x, 1), Y = Math.Round(y, 1), Left = Math.Round(left, 1), Top = Math.Round(top, 1) };
}
#region eventhandlers
// TODO : Remove all hide/show extensions from here.
protected virtual void drag_Started(DragListener drag)
{
Line al = ExtendedItem.View as Line;
CurrentX2 = al.X2;
CurrentY2 = al.Y2;
CurrentLeft = (double)al.GetValue(Canvas.LeftProperty);
CurrentTop = (double)al.GetValue(Canvas.TopProperty);
var designPanel = ExtendedItem.Services.DesignPanel as DesignPanel;
zoom = designPanel.TryFindParent<ZoomControl>();
if (resizeBehavior != null)
operation = PlacementOperation.Start(extendedItemArray, PlacementType.Resize);
else
{
changeGroup = this.ExtendedItem.Context.OpenGroup("Resize", extendedItemArray);
}
_isResizing = true;
(drag.Target as ResizeThumb).IsPrimarySelection = false;
}
protected virtual void drag_Changed(DragListener drag)
{
Line al = ExtendedItem.View as Line;
var alignment = (drag.Target as ResizeThumb).Alignment;
var info = operation.PlacedItems[0];
double dx = 0;
double dy = 0;
if (zoom != null)
{
dx = drag.Delta.X * (1 / zoom.CurrentZoom);
dy = drag.Delta.Y * (1 / zoom.CurrentZoom);
}
double top, left, x, y, xtop, xleft;
if (alignment == PlacementAlignment.TopLeft)
{
//normal values
x = CurrentX2 - dx;
y = CurrentY2 - dy;
top = CurrentTop + dy;
left = CurrentLeft + dx;
//values to use when keys are pressed
xtop = CurrentTop + CurrentY2;
xleft = CurrentLeft + CurrentX2;
}
else
{
x = CurrentX2 + dx;
y = CurrentY2 + dy;
top = xtop = CurrentTop;
left = xleft = CurrentLeft;
}
Bounds position = CalculateDrawing(x, y, left, top, xleft, xtop);
ExtendedItem.Properties.GetProperty(Line.X1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.Y1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.X2Property).SetValue(position.X);
ExtendedItem.Properties.GetProperty(Line.Y2Property).SetValue(position.Y);
if (operation != null)
{
var result = info.OriginalBounds;
result.X = position.Left;
result.Y = position.Top;
result.Width = Math.Abs(position.X);
result.Height = Math.Abs(position.Y);
info.Bounds = result.Round();
operation.CurrentContainerBehavior.BeforeSetPosition(operation);
operation.CurrentContainerBehavior.SetPosition(info);
}
(drag.Target as ResizeThumb).InvalidateArrange();
ResetWidthHeightProperties();
}
protected virtual void drag_Completed(DragListener drag)
{
if (operation != null)
{
if (drag.IsCanceled) operation.Abort();
else
{
ResetWidthHeightProperties();
operation.Commit();
}
operation = null;
}
else
{
if (drag.IsCanceled) changeGroup.Abort();
else changeGroup.Commit();
changeGroup = null;
}
_isResizing = false;
(drag.Target as ResizeThumb).IsPrimarySelection = true;
HideSizeAndShowHandles();
}
/// <summary>
/// is invoked whenever a line is selected on the canvas, remember that the adorners are created for each line object and never destroyed
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
if (ExtendedItem.Properties.GetProperty(Line.StrokeProperty).ValueOnInstance == null)
{
ExtendedItem.Properties[Shape.StrokeProperty].SetValue(Colors.Black);
ExtendedItem.Properties[Shape.StrokeThicknessProperty].SetValue(2d);
ExtendedItem.Properties[Shape.StretchProperty].SetValue(Stretch.None);
ExtendedItem.Properties.GetProperty(Line.X1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.Y1Property).SetValue(0);
ExtendedItem.Properties.GetProperty(Line.X2Property).SetValue(20);
ExtendedItem.Properties.GetProperty(Line.Y2Property).SetValue(20);
(ExtendedItem.View as Line).BringIntoView();
}
resizeThumbs = new ResizeThumb[]
{
CreateThumb(PlacementAlignment.TopLeft, Cursors.SizeNWSE),
CreateThumb(PlacementAlignment.BottomRight, Cursors.SizeNWSE)
};
extendedItemArray[0] = this.ExtendedItem;
Invalidate();
//ResetWidthHeightProperties();
this.ExtendedItem.PropertyChanged += OnPropertyChanged;
this.Services.Selection.PrimarySelectionChanged += OnPrimarySelectionChanged;
resizeBehavior = PlacementOperation.GetPlacementBehavior(extendedItemArray);
UpdateAdornerVisibility();
OnPrimarySelectionChanged(null, null);
}
#endregion
}
}

859
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PolyLineHandlerExtension.cs

@ -1,11 +1,21 @@ @@ -1,11 +1,21 @@
/*
* Created by SharpDevelop.
* User: trubra
* Date: 2014-12-22
* Time: 10:34
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// 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;
@ -21,430 +31,423 @@ using System; @@ -21,430 +31,423 @@ 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(Polyline), OverrideExtensions = new Type[] { typeof(ResizeThumbExtension), typeof(SelectedElementRectangleExtension), typeof(CanvasPositionExtension), typeof(QuickOperationMenuExtension), typeof(RotateThumbExtension), typeof(RenderTransformOriginExtension), typeof(InPlaceEditorExtension), typeof(SizeDisplayExtension) })]
internal class PolyLineHandlerExtension : 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)
{
PointCollection points = GetPointCollection();
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();
PointCollection points = GetPointCollection();
//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;
if (designPanel != null)
{
var p = VisualTreeHelper.GetParent(designPanel);
while (p != null && !(p is ZoomControl))
{
p = VisualTreeHelper.GetParent(p);
}
_zoom = p as ZoomControl;
}
if (resizeBehavior != null)
operation = PlacementOperation.Start(extendedItemArray, PlacementType.Resize);
else
{
changeGroup = ExtendedItem.Context.OpenGroup("Resize", extendedItemArray);
}
_isResizing = true;
}
void ChangeOperation(PointCollection 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);
}
ResetWidthHeightProperties();
}
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);
ResetWidthHeightProperties();
operation.Commit();
operation = null;
}
else
{
changeGroup.Commit();
changeGroup = null;
}
_isResizing = false;
ResetWidthHeightProperties();
Invalidate();
}
protected void drag_Changed(DragListener drag)
{
PointCollection points = GetPointCollection();
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.SizeNWSE, 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();
PointCollection points = GetPointCollection();
if (ExtendedItem.Properties[Shape.StrokeProperty].ValueOnInstance == null)
{
ExtendedItem.Properties[Shape.StrokeProperty].SetValue(Colors.Black);
ExtendedItem.Properties[Shape.StrokeThicknessProperty].SetValue(2d);
ExtendedItem.Properties[Shape.StretchProperty].SetValue(Stretch.None);
points.AddRange(new List<Point> { new Point(0, 0), new Point(20, 20) });
ExtendedItem.Properties.GetProperty(ExtendedItem.View as Polyline != null ? Polyline.PointsProperty : Polygon.PointsProperty).SetValue(points);
}
resizeThumbs = new List<ResizeThumb>();
for (int i = 1; i < points.Count; i++)
{
CreateThumb(PlacementAlignment.BottomRight, Cursors.SizeNWSE, i);
}
Invalidate();
ResetWidthHeightProperties();
ResetThumbs();
_isDragging = false;
extendedItemArray[0] = ExtendedItem;
ExtendedItem.PropertyChanged += OnPropertyChanged;
Services.Selection.PrimarySelectionChanged += OnPrimarySelectionChanged;
resizeBehavior = PlacementOperation.GetPlacementBehavior(extendedItemArray);
UpdateAdornerVisibility();
OnPrimarySelectionChanged(null, null);
}
#endregion
PointCollection GetPointCollection()
{
Polygon pg = ExtendedItem.View as Polygon;
Polyline pl = ExtendedItem.View as Polyline;
return pl == null ? pg.Points : pl.Points;
}
PointCollection MovePoints(PointCollection 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 == GetPointCollection().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(GetPointCollection(), 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
}
[ExtensionFor(typeof(Polyline), OverrideExtensions = new Type[] { typeof(ResizeThumbExtension), typeof(SelectedElementRectangleExtension), typeof(CanvasPositionExtension), typeof(QuickOperationMenuExtension), typeof(RotateThumbExtension), typeof(RenderTransformOriginExtension), typeof(InPlaceEditorExtension), typeof(SizeDisplayExtension), typeof(SkewThumbExtension) })]
internal class PolyLineHandlerExtension : 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)
{
PointCollection points = GetPointCollection();
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();
PointCollection points = GetPointCollection();
//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(PointCollection 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);
}
ResetWidthHeightProperties();
}
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);
ResetWidthHeightProperties();
operation.Commit();
operation = null;
}
else
{
changeGroup.Commit();
changeGroup = null;
}
_isResizing = false;
ResetWidthHeightProperties();
Invalidate();
}
protected void drag_Changed(DragListener drag)
{
PointCollection points = GetPointCollection();
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.SizeNWSE, 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();
PointCollection points = GetPointCollection();
if (ExtendedItem.Properties[Shape.StrokeProperty].ValueOnInstance == null)
{
ExtendedItem.Properties[Shape.StrokeProperty].SetValue(Colors.Black);
ExtendedItem.Properties[Shape.StrokeThicknessProperty].SetValue(2d);
ExtendedItem.Properties[Shape.StretchProperty].SetValue(Stretch.None);
points.AddRange(new List<Point> { new Point(0, 0), new Point(20, 20) });
ExtendedItem.Properties.GetProperty(ExtendedItem.View as Polyline != null ? Polyline.PointsProperty : Polygon.PointsProperty).SetValue(points);
}
resizeThumbs = new List<ResizeThumb>();
for (int i = 1; i < points.Count; i++)
{
CreateThumb(PlacementAlignment.BottomRight, Cursors.SizeNWSE, i);
}
Invalidate();
ResetWidthHeightProperties();
ResetThumbs();
_isDragging = false;
extendedItemArray[0] = ExtendedItem;
ExtendedItem.PropertyChanged += OnPropertyChanged;
Services.Selection.PrimarySelectionChanged += OnPrimarySelectionChanged;
resizeBehavior = PlacementOperation.GetPlacementBehavior(extendedItemArray);
UpdateAdornerVisibility();
OnPrimarySelectionChanged(null, null);
}
#endregion
PointCollection GetPointCollection()
{
Polygon pg = ExtendedItem.View as Polygon;
Polyline pl = ExtendedItem.View as Polyline;
return pl == null ? pg.Points : pl.Points;
}
PointCollection MovePoints(PointCollection 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 == GetPointCollection().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(GetPointCollection(), 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
}
}

11
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/ResizeThumbExtension.cs

@ -26,6 +26,7 @@ using ICSharpCode.WpfDesign.Adorners; @@ -26,6 +26,7 @@ using ICSharpCode.WpfDesign.Adorners;
using ICSharpCode.WpfDesign.Designer.Controls;
using ICSharpCode.WpfDesign.Extensions;
using System.Collections.Generic;
using ICSharpCode.WpfDesign.Designer.UIExtensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
@ -124,15 +125,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -124,15 +125,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
void drag_Started(DragListener drag)
{
var designPanel = ExtendedItem.Services.DesignPanel as DesignPanel;
if (designPanel != null)
{
var p = VisualTreeHelper.GetParent(designPanel);
while (p != null && !(p is ZoomControl))
{
p = VisualTreeHelper.GetParent(p);
}
zoom = p as ZoomControl;
}
zoom = designPanel.TryFindParent<ZoomControl>();
/* Abort editing Text if it was editing, because it interferes with the undo stack. */
foreach(var extension in this.ExtendedItem.Extensions){

Loading…
Cancel
Save