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 @@ |
|||||||
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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