Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2415 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
26 changed files with 904 additions and 420 deletions
@ -1,168 +0,0 @@
@@ -1,168 +0,0 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
using ICSharpCode.WpfDesign.Adorners; |
||||
using ICSharpCode.WpfDesign.Extensions; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Designer.Extensions |
||||
{ |
||||
/// <summary>
|
||||
/// Implements IChildResizeSupport supporting size changes using the
|
||||
/// Width, Height, Margin properties.
|
||||
/// </summary>
|
||||
[ExtensionFor(typeof(FrameworkElement))] |
||||
public sealed class DefaultChildResizeSupport : BehaviorExtension, IChildResizeSupport |
||||
{ |
||||
internal static readonly DefaultChildResizeSupport Instance = new DefaultChildResizeSupport(); |
||||
|
||||
/// <inherits/>
|
||||
protected override void OnInitialized() |
||||
{ |
||||
base.OnInitialized(); |
||||
this.ExtendedItem.AddBehavior(typeof(IChildResizeSupport), this); |
||||
} |
||||
|
||||
/// <inherits/>
|
||||
public bool CanResizeChild(DesignItem childItem) |
||||
{ |
||||
FrameworkElement child = (FrameworkElement)childItem.Component; |
||||
return !double.IsNaN(child.Width) |
||||
|| !double.IsNaN(child.Height) |
||||
|| childItem.Properties[FrameworkElement.MarginProperty].IsSet; |
||||
} |
||||
|
||||
/// <inherits/>
|
||||
public Placement GetPlacement(DesignItem childItem, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical) |
||||
{ |
||||
FrameworkElement child = (FrameworkElement)childItem.Component; |
||||
if (childItem.Properties[FrameworkElement.MarginProperty].IsSet == false) { |
||||
if (child.HorizontalAlignment == HorizontalAlignment.Left) |
||||
horizontal = HorizontalAlignment.Right; |
||||
else if (child.HorizontalAlignment == HorizontalAlignment.Right) |
||||
horizontal = HorizontalAlignment.Left; |
||||
else |
||||
horizontal = HorizontalAlignment.Center; |
||||
if (child.VerticalAlignment == VerticalAlignment.Top) |
||||
horizontal = HorizontalAlignment.Right; |
||||
else if (child.VerticalAlignment == VerticalAlignment.Bottom) |
||||
vertical = VerticalAlignment.Bottom; |
||||
else |
||||
vertical = VerticalAlignment.Center; |
||||
} |
||||
return RootElementResizeSupport.Instance.GetPlacement(childItem, horizontalChange, verticalChange, horizontal, vertical); |
||||
} |
||||
|
||||
/// <inherits/>
|
||||
public void Resize(DesignItem childItem, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical) |
||||
{ |
||||
RelativePlacement p = (RelativePlacement)GetPlacement(childItem, horizontalChange, verticalChange, horizontal, vertical); |
||||
Resize(childItem, p); |
||||
} |
||||
|
||||
internal static void Resize(DesignItem childItem, RelativePlacement p) |
||||
{ |
||||
DesignItemProperty margin = childItem.Properties[FrameworkElement.MarginProperty]; |
||||
if (margin.IsSet) { |
||||
Thickness t = (Thickness)margin.ValueOnInstance; |
||||
t.Left += p.XOffset; |
||||
t.Top += p.YOffset; |
||||
t.Right -= p.XOffset + p.WidthOffset; |
||||
t.Bottom -= p.YOffset + p.HeightOffset; |
||||
margin.SetValue(t); |
||||
} |
||||
|
||||
double horizontalChange = p.WidthOffset; |
||||
double verticalChange = p.HeightOffset; |
||||
|
||||
FrameworkElement child = (FrameworkElement)childItem.Component; |
||||
double width = child.Width; |
||||
double height = child.Height; |
||||
if (margin.IsSet) { |
||||
// when margin is used, only set width/height if it is not Auto
|
||||
if (!double.IsNaN(width)) { |
||||
childItem.Properties[FrameworkElement.WidthProperty].SetValue( Math.Max(0, horizontalChange + width) ); |
||||
} |
||||
if (!double.IsNaN(height)) { |
||||
childItem.Properties[FrameworkElement.HeightProperty].SetValue( Math.Max(0, verticalChange + height) ); |
||||
} |
||||
} else { |
||||
// when margin is not used, we'll have to set width+height
|
||||
// but don't create width if we don't have any horizontal change
|
||||
if (double.IsNaN(width) && horizontalChange != 0) { |
||||
width = child.ActualWidth; |
||||
} |
||||
if (double.IsNaN(height) && verticalChange != 0) { |
||||
height = child.ActualHeight; |
||||
} |
||||
if (!double.IsNaN(width)) { |
||||
childItem.Properties[FrameworkElement.WidthProperty].SetValue( Math.Max(0, horizontalChange + width) ); |
||||
} |
||||
if (!double.IsNaN(height)) { |
||||
childItem.Properties[FrameworkElement.HeightProperty].SetValue( Math.Max(0, verticalChange + height) ); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
sealed class RootElementResizeSupport : IChildResizeSupport |
||||
{ |
||||
public static readonly RootElementResizeSupport Instance = new RootElementResizeSupport(); |
||||
|
||||
public bool CanResizeChild(DesignItem child) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
public Placement GetPlacement(DesignItem child, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical) |
||||
{ |
||||
RelativePlacement rp = new RelativePlacement(HorizontalAlignment.Stretch, VerticalAlignment.Stretch); |
||||
|
||||
if (horizontal == HorizontalAlignment.Right) { |
||||
rp.WidthOffset += horizontalChange; |
||||
} else if (horizontal == HorizontalAlignment.Left) { |
||||
rp.XOffset -= horizontalChange; |
||||
rp.WidthOffset += horizontalChange; |
||||
} else { |
||||
rp.XOffset -= horizontalChange; |
||||
rp.WidthOffset += horizontalChange * 2; |
||||
} |
||||
|
||||
if (vertical == VerticalAlignment.Bottom) { |
||||
rp.HeightOffset += verticalChange; |
||||
} else if (vertical == VerticalAlignment.Top) { |
||||
rp.YOffset -= verticalChange; |
||||
rp.HeightOffset += verticalChange; |
||||
} else { |
||||
rp.YOffset -= verticalChange; |
||||
rp.HeightOffset += verticalChange * 2; |
||||
} |
||||
|
||||
return rp; |
||||
} |
||||
|
||||
public void Resize(DesignItem childItem, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical) |
||||
{ |
||||
FrameworkElement child = (FrameworkElement)childItem.Component; |
||||
double width = child.Width; |
||||
double height = child.Height; |
||||
if (double.IsNaN(width) && horizontalChange != 0) { |
||||
width = child.ActualWidth; |
||||
} |
||||
if (double.IsNaN(height) && verticalChange != 0) { |
||||
height = child.ActualHeight; |
||||
} |
||||
if (!double.IsNaN(width)) { |
||||
childItem.Properties[FrameworkElement.WidthProperty].SetValue( Math.Max(0, horizontalChange + width) ); |
||||
} |
||||
if (!double.IsNaN(height)) { |
||||
childItem.Properties[FrameworkElement.HeightProperty].SetValue( Math.Max(0, verticalChange + height) ); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Windows; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Designer.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Base class for mouse gestures that should start dragging only after a minimum drag distance.
|
||||
/// </summary>
|
||||
abstract class ClickOrDragMouseGesture : MouseGestureBase |
||||
{ |
||||
protected Point startPoint; |
||||
protected bool hasDragStarted; |
||||
protected IInputElement positionRelativeTo; |
||||
|
||||
const double MinimumDragDistance = 3; |
||||
|
||||
protected sealed override void OnStarted(MouseButtonEventArgs e) |
||||
{ |
||||
Debug.Assert(positionRelativeTo != null); |
||||
hasDragStarted = false; |
||||
startPoint = e.GetPosition(positionRelativeTo); |
||||
} |
||||
|
||||
protected override void OnMouseMove(object sender, MouseEventArgs e) |
||||
{ |
||||
if (!hasDragStarted) { |
||||
Vector v = e.GetPosition(positionRelativeTo) - startPoint; |
||||
if (v.LengthSquared >= MinimumDragDistance * MinimumDragDistance) { |
||||
hasDragStarted = true; |
||||
OnDragStarted(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected override void OnStopped() |
||||
{ |
||||
hasDragStarted = false; |
||||
} |
||||
|
||||
protected virtual void OnDragStarted() {} |
||||
} |
||||
} |
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Windows; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Designer.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Mouse gesture for moving elements inside a container or between containers.
|
||||
/// Belongs to the PointerTool.
|
||||
/// </summary>
|
||||
sealed class DragMoveMouseGesture : ClickOrDragMouseGesture |
||||
{ |
||||
DesignItem clickedOn; |
||||
PlacementOperation operation; |
||||
|
||||
internal DragMoveMouseGesture(DesignItem clickedOn) |
||||
{ |
||||
Debug.Assert(clickedOn != null); |
||||
|
||||
this.clickedOn = clickedOn; |
||||
|
||||
if (clickedOn.Parent != null) |
||||
this.positionRelativeTo = clickedOn.Parent.View; |
||||
else |
||||
this.positionRelativeTo = clickedOn.View; |
||||
} |
||||
|
||||
double startLeft, startRight, startTop, startBottom; |
||||
|
||||
protected override void OnDragStarted() |
||||
{ |
||||
IPlacementBehavior b = PlacementOperation.GetPlacementBehavior(clickedOn); |
||||
if (b != null && b.CanPlace(clickedOn, PlacementType.Move, PlacementAlignments.TopLeft)) { |
||||
operation = PlacementOperation.Start(clickedOn, PlacementType.Move); |
||||
startLeft = operation.Left; |
||||
startRight = operation.Right; |
||||
startTop = operation.Top; |
||||
startBottom = operation.Bottom; |
||||
} |
||||
} |
||||
|
||||
protected override void OnMouseMove(object sender, MouseEventArgs e) |
||||
{ |
||||
base.OnMouseMove(sender, e); // call OnDragStarted if min. drag distace is reached
|
||||
if (operation != null) { |
||||
Vector v = e.GetPosition(positionRelativeTo) - startPoint; |
||||
operation.Left = startLeft + v.X; |
||||
operation.Right = startRight + v.X; |
||||
operation.Top = startTop + v.Y; |
||||
operation.Bottom = startBottom + v.Y; |
||||
operation.UpdatePlacement(); |
||||
} |
||||
} |
||||
|
||||
protected override void OnMouseUp(object sender, MouseButtonEventArgs e) |
||||
{ |
||||
if (operation != null) { |
||||
operation.Commit(); |
||||
operation = null; |
||||
} |
||||
Stop(); |
||||
} |
||||
|
||||
protected override void OnStopped() |
||||
{ |
||||
if (operation != null) { |
||||
operation.Abort(); |
||||
operation = null; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.Windows; |
||||
using System.Windows.Media; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Adorners |
||||
{ |
||||
/// <summary>
|
||||
/// Defines how a design-time adorner is placed.
|
||||
/// </summary>
|
||||
public abstract class AdornerPlacement |
||||
{ |
||||
/// <summary>
|
||||
/// A placement instance that places the adorner above the content, using the same bounds as the content.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] |
||||
public static readonly AdornerPlacement FillContent = new FillContentPlacement(); |
||||
|
||||
/// <summary>
|
||||
/// Arranges the adorner element on the specified adorner panel.
|
||||
/// </summary>
|
||||
public abstract void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize); |
||||
|
||||
sealed class FillContentPlacement : AdornerPlacement |
||||
{ |
||||
public override void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize) |
||||
{ |
||||
adorner.Arrange(new Rect(adornedElementSize)); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.Windows; |
||||
using System.Windows.Media; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Adorners |
||||
{ |
||||
/// <summary>
|
||||
/// Describes the space in which an adorner is placed.
|
||||
/// </summary>
|
||||
public enum AdornerPlacementSpace |
||||
{ |
||||
/// <summary>
|
||||
/// The adorner is affected by the render transform of the adorned element.
|
||||
/// </summary>
|
||||
Render, |
||||
/// <summary>
|
||||
/// The adorner is affected by the layout transform of the adorned element.
|
||||
/// </summary>
|
||||
Layout, |
||||
/// <summary>
|
||||
/// The adorner is not affected by transforms of designed controls.
|
||||
/// </summary>
|
||||
Designer |
||||
} |
||||
} |
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
|
||||
namespace ICSharpCode.WpfDesign |
||||
{ |
||||
/// <summary>
|
||||
/// A combination of HorizontalAlignment/VerticalAlignment.
|
||||
/// </summary>
|
||||
public struct PlacementAlignment : IEquatable<PlacementAlignment> |
||||
{ |
||||
readonly HorizontalAlignment horizontal; |
||||
readonly VerticalAlignment vertical; |
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal component.
|
||||
/// </summary>
|
||||
public HorizontalAlignment Horizontal { |
||||
get { return horizontal; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the vertical component.
|
||||
/// </summary>
|
||||
public VerticalAlignment Vertical { |
||||
get { return vertical; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the PlacementAlignment structure.
|
||||
/// </summary>
|
||||
public PlacementAlignment(HorizontalAlignment horizontal, VerticalAlignment vertical) |
||||
{ |
||||
if (horizontal == HorizontalAlignment.Stretch) |
||||
throw new ArgumentException("Strech is not a valid value", "horizontal"); |
||||
if (vertical == VerticalAlignment.Stretch) |
||||
throw new ArgumentException("Strech is not a valid value", "vertical"); |
||||
this.horizontal = horizontal; |
||||
this.vertical = vertical; |
||||
} |
||||
|
||||
#region Equals and GetHashCode implementation
|
||||
/// <summary>Compares this to <paramref name="other"/>.</summary>
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
if (obj is PlacementAlignment) |
||||
return Equals((PlacementAlignment)obj); // use Equals method below
|
||||
else |
||||
return false; |
||||
} |
||||
|
||||
/// <summary>Compares this to <paramref name="other"/>.</summary>
|
||||
public bool Equals(PlacementAlignment other) |
||||
{ |
||||
return this.horizontal == other.horizontal && this.vertical == other.vertical; |
||||
} |
||||
|
||||
/// <inherit/>
|
||||
public override int GetHashCode() |
||||
{ |
||||
unchecked { |
||||
return horizontal.GetHashCode() * 27 + vertical.GetHashCode(); |
||||
} |
||||
} |
||||
|
||||
/// <summary>Compares <paramref name="lhs"/> to <paramref name="rhs"/>.</summary>
|
||||
public static bool operator ==(PlacementAlignment lhs, PlacementAlignment rhs) |
||||
{ |
||||
return lhs.Equals(rhs); |
||||
} |
||||
|
||||
/// <summary>Compares <paramref name="lhs"/> to <paramref name="rhs"/>.</summary>
|
||||
public static bool operator !=(PlacementAlignment lhs, PlacementAlignment rhs) |
||||
{ |
||||
return !(lhs.Equals(rhs)); |
||||
} |
||||
#endregion
|
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Contains known PlacementAlignment values like an enumeration.
|
||||
/// </summary>
|
||||
public static class PlacementAlignments |
||||
{ |
||||
/// <summary>Top left</summary>
|
||||
public static readonly PlacementAlignment TopLeft = new PlacementAlignment(HorizontalAlignment.Left, VerticalAlignment.Top); |
||||
/// <summary>Top center</summary>
|
||||
public static readonly PlacementAlignment Top = new PlacementAlignment(HorizontalAlignment.Center, VerticalAlignment.Top); |
||||
/// <summary>Top right</summary>
|
||||
public static readonly PlacementAlignment TopRight = new PlacementAlignment(HorizontalAlignment.Right, VerticalAlignment.Top); |
||||
/// <summary>Center left</summary>
|
||||
public static readonly PlacementAlignment Left = new PlacementAlignment(HorizontalAlignment.Left, VerticalAlignment.Center); |
||||
/// <summary>Center center</summary>
|
||||
public static readonly PlacementAlignment Center = new PlacementAlignment(HorizontalAlignment.Center, VerticalAlignment.Center); |
||||
/// <summary>Center right</summary>
|
||||
public static readonly PlacementAlignment Right = new PlacementAlignment(HorizontalAlignment.Right, VerticalAlignment.Center); |
||||
/// <summary>Bottom left</summary>
|
||||
public static readonly PlacementAlignment BottomLeft = new PlacementAlignment(HorizontalAlignment.Left, VerticalAlignment.Bottom); |
||||
/// <summary>Bottom center</summary>
|
||||
public static readonly PlacementAlignment Bottom = new PlacementAlignment(HorizontalAlignment.Center, VerticalAlignment.Bottom); |
||||
/// <summary>Bottom right</summary>
|
||||
public static readonly PlacementAlignment BottomRight = new PlacementAlignment(HorizontalAlignment.Right, VerticalAlignment.Bottom); |
||||
} |
||||
} |
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
using System.Windows.Input; |
||||
|
||||
using ICSharpCode.WpfDesign.Adorners; |
||||
|
||||
namespace ICSharpCode.WpfDesign |
||||
{ |
||||
/// <summary>
|
||||
/// Behavior interface implemented by container elements to support resizing
|
||||
/// child elements.
|
||||
/// </summary>
|
||||
public interface IPlacementBehavior |
||||
{ |
||||
/// <summary>
|
||||
/// Gets if the child element can be resized.
|
||||
/// </summary>
|
||||
bool CanPlace(DesignItem child, PlacementType type, PlacementAlignment position); |
||||
|
||||
/// <summary>
|
||||
/// Starts placement mode of the child element specified in the placement operation.
|
||||
/// </summary>
|
||||
void StartPlacement(PlacementOperation operation, out bool supportsRemoveFromContainer); |
||||
|
||||
/// <summary>
|
||||
/// Updates the placement of the element specified in the placement operation.
|
||||
/// </summary>
|
||||
void UpdatePlacement(PlacementOperation operation); |
||||
|
||||
/// <summary>
|
||||
/// Finishes placement of a child element. This method is called both for aborted
|
||||
/// and committed placement operations.
|
||||
/// </summary>
|
||||
void FinishPlacement(PlacementOperation operation); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Behavior interface for root elements (elements where item.Parent is null).
|
||||
/// Is used instead of <see cref="IPlacementBehavior"/> to support resizing the root element.
|
||||
/// </summary>
|
||||
public interface IRootPlacementBehavior : IPlacementBehavior |
||||
{ |
||||
} |
||||
} |
@ -0,0 +1,179 @@
@@ -0,0 +1,179 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
using System.Windows.Input; |
||||
|
||||
using ICSharpCode.WpfDesign.Adorners; |
||||
|
||||
namespace ICSharpCode.WpfDesign |
||||
{ |
||||
/// <summary>
|
||||
/// Stores data about a placement operation.
|
||||
/// </summary>
|
||||
public sealed class PlacementOperation |
||||
{ |
||||
readonly ChangeGroup changeGroup; |
||||
readonly DesignItem placedItem; |
||||
readonly PlacementType type; |
||||
readonly DesignItem oldContainer; |
||||
readonly IPlacementBehavior oldContainerBehavior; |
||||
DesignItem currentContainer; |
||||
IPlacementBehavior currentContainerBehavior; |
||||
bool supportsRemoveFromContainer; |
||||
bool isAborted, isCommitted; |
||||
|
||||
//DesignItem newContainer;
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// The item being placed.
|
||||
/// </summary>
|
||||
public DesignItem PlacedItem { |
||||
get { return placedItem; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The type of the placement being done.
|
||||
/// </summary>
|
||||
public PlacementType Type { |
||||
get { return type; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets if removing the placed item from the container is supported.
|
||||
/// </summary>
|
||||
public bool SupportsRemoveFromContainer { |
||||
get { return supportsRemoveFromContainer; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets if the placement operation was aborted.
|
||||
/// </summary>
|
||||
public bool IsAborted { |
||||
get { return isAborted; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets if the placement operation was committed.
|
||||
/// </summary>
|
||||
public bool IsCommitted { |
||||
get { return isCommitted; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The position of the left/right/top/bottom side in the coordinate system of the parent container.
|
||||
/// These values must be set by IPlacementBehavior.StartPlacement and are updated by the drag operation.
|
||||
/// </summary>
|
||||
public double Left, Right, Top, Bottom; |
||||
|
||||
#endregion
|
||||
|
||||
public void UpdatePlacement() |
||||
{ |
||||
currentContainerBehavior.UpdatePlacement(this); |
||||
} |
||||
|
||||
#region Start
|
||||
/// <summary>
|
||||
/// Starts a new placement operation that changes the placement of <paramref name="placedItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="placedItem">The item to be placed.</param>
|
||||
/// <param name="type">The type of the placement.</param>
|
||||
/// <returns>A PlacementOperation object.</returns>
|
||||
/// <remarks>
|
||||
/// You MUST call either <see cref="Abort"/> or <see cref="Commit"/> on the returned PlacementOperation
|
||||
/// once you are done with it, otherwise a ChangeGroup will be left open and Undo/Redo will fail to work!
|
||||
/// </remarks>
|
||||
public static PlacementOperation Start(DesignItem placedItem, PlacementType type) |
||||
{ |
||||
if (placedItem == null) |
||||
throw new ArgumentNullException("placedItem"); |
||||
if (type == null) |
||||
throw new ArgumentNullException("type"); |
||||
PlacementOperation op = new PlacementOperation(placedItem, type); |
||||
try { |
||||
if (op.currentContainerBehavior == null) |
||||
throw new InvalidOperationException("Starting the operation is not supported"); |
||||
op.Left = op.Top = op.Bottom = op.Right = double.NaN; |
||||
op.currentContainerBehavior.StartPlacement(op, out op.supportsRemoveFromContainer); |
||||
if (double.IsNaN(op.Left) || double.IsNaN(op.Top) || double.IsNaN(op.Bottom) || double.IsNaN(op.Right)) |
||||
throw new InvalidOperationException("IPlacementBehavior.StartPlacement must set Left,Top,Right+Bottom to non-NAN values"); |
||||
} catch { |
||||
op.changeGroup.Abort(); |
||||
throw; |
||||
} |
||||
return op; |
||||
} |
||||
private PlacementOperation(DesignItem placedItem, PlacementType type) |
||||
{ |
||||
this.placedItem = placedItem; |
||||
this.type = type; |
||||
|
||||
this.oldContainer = placedItem.Parent; |
||||
this.oldContainerBehavior = GetPlacementBehavior(placedItem); |
||||
|
||||
this.currentContainer = oldContainer; |
||||
this.currentContainerBehavior = oldContainerBehavior; |
||||
this.changeGroup = placedItem.OpenGroup(type.ToString()); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the placement behavior associated with the specified item.
|
||||
/// </summary>
|
||||
public static IPlacementBehavior GetPlacementBehavior(DesignItem item) |
||||
{ |
||||
if (item == null) |
||||
throw new ArgumentNullException("item"); |
||||
if (item.Parent != null) { |
||||
return item.Parent.GetBehavior<IPlacementBehavior>(); |
||||
} else { |
||||
return item.GetBehavior<IRootPlacementBehavior>(); |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region ChangeGroup handling
|
||||
/// <summary>
|
||||
/// Gets/Sets the description of the underlying change group.
|
||||
/// </summary>
|
||||
public string Description { |
||||
get { return changeGroup.Title; } |
||||
set { changeGroup.Title = value; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Aborts the operation.
|
||||
/// This aborts the underlying change group, reverting all changes done while the operation was running.
|
||||
/// </summary>
|
||||
public void Abort() |
||||
{ |
||||
if (!isAborted) { |
||||
if (isCommitted) |
||||
throw new InvalidOperationException("PlacementOperation is committed."); |
||||
isAborted = true; |
||||
currentContainerBehavior.FinishPlacement(this); |
||||
changeGroup.Abort(); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Commits the operation.
|
||||
/// This commits the underlying change group.
|
||||
/// </summary>
|
||||
public void Commit() |
||||
{ |
||||
if (isAborted || isCommitted) |
||||
throw new InvalidOperationException("PlacementOperation is already aborted/committed."); |
||||
isCommitted = true; |
||||
currentContainerBehavior.FinishPlacement(this); |
||||
changeGroup.Commit(); |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.WpfDesign |
||||
{ |
||||
/// <summary>
|
||||
/// Describes how a placement is done.
|
||||
/// </summary>
|
||||
public sealed class PlacementType |
||||
{ |
||||
/// <summary>
|
||||
/// Placement is done by resizing an element.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] |
||||
public static readonly PlacementType Resize = Register("Resize"); |
||||
|
||||
/// <summary>
|
||||
/// Placement is done by moving an element.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] |
||||
public static readonly PlacementType Move = Register("Move"); |
||||
|
||||
readonly string name; |
||||
|
||||
private PlacementType(string name) |
||||
{ |
||||
this.name = name; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new unique PlacementKind.
|
||||
/// </summary>
|
||||
public static PlacementType Register(string name) |
||||
{ |
||||
return new PlacementType(name); |
||||
} |
||||
|
||||
/// <inherit/>
|
||||
public override string ToString() |
||||
{ |
||||
return name; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue