|
|
@ -6,6 +6,8 @@ |
|
|
|
// </file>
|
|
|
|
// </file>
|
|
|
|
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System; |
|
|
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
|
|
using System.Collections.ObjectModel; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Windows; |
|
|
|
using System.Windows; |
|
|
|
using System.Windows.Input; |
|
|
|
using System.Windows.Input; |
|
|
@ -20,7 +22,7 @@ namespace ICSharpCode.WpfDesign |
|
|
|
public sealed class PlacementOperation |
|
|
|
public sealed class PlacementOperation |
|
|
|
{ |
|
|
|
{ |
|
|
|
readonly ChangeGroup changeGroup; |
|
|
|
readonly ChangeGroup changeGroup; |
|
|
|
readonly DesignItem placedItem; |
|
|
|
readonly ReadOnlyCollection<PlacementInformation> placedItems; |
|
|
|
readonly PlacementType type; |
|
|
|
readonly PlacementType type; |
|
|
|
readonly DesignItem oldContainer; |
|
|
|
readonly DesignItem oldContainer; |
|
|
|
readonly IPlacementBehavior oldContainerBehavior; |
|
|
|
readonly IPlacementBehavior oldContainerBehavior; |
|
|
@ -30,10 +32,10 @@ namespace ICSharpCode.WpfDesign |
|
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// The item being placed.
|
|
|
|
/// The items being placed.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public DesignItem PlacedItem { |
|
|
|
public ReadOnlyCollection<PlacementInformation> PlacedItems { |
|
|
|
get { return placedItem; } |
|
|
|
get { return placedItems; } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
@ -57,12 +59,6 @@ namespace ICSharpCode.WpfDesign |
|
|
|
get { return 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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the current container for the placement operation.
|
|
|
|
/// Gets the current container for the placement operation.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
@ -79,6 +75,7 @@ namespace ICSharpCode.WpfDesign |
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Container changing
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Make the placed item switch the container.
|
|
|
|
/// Make the placed item switch the container.
|
|
|
|
/// This method assumes that you already have checked if changing the container is possible.
|
|
|
|
/// This method assumes that you already have checked if changing the container is possible.
|
|
|
@ -93,6 +90,12 @@ namespace ICSharpCode.WpfDesign |
|
|
|
try { |
|
|
|
try { |
|
|
|
currentContainerBehavior.LeaveContainer(this); |
|
|
|
currentContainerBehavior.LeaveContainer(this); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
System.Windows.Media.GeneralTransform transform = currentContainer.View.TransformToVisual(newContainer.View); |
|
|
|
|
|
|
|
foreach (PlacementInformation info in placedItems) { |
|
|
|
|
|
|
|
info.OriginalBounds = transform.TransformBounds(info.OriginalBounds); |
|
|
|
|
|
|
|
info.Bounds = transform.TransformBounds(info.Bounds); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
currentContainer = newContainer; |
|
|
|
currentContainer = newContainer; |
|
|
|
currentContainerBehavior = newContainer.GetBehavior<IPlacementBehavior>(); |
|
|
|
currentContainerBehavior = newContainer.GetBehavior<IPlacementBehavior>(); |
|
|
|
|
|
|
|
|
|
|
@ -104,63 +107,82 @@ namespace ICSharpCode.WpfDesign |
|
|
|
throw; |
|
|
|
throw; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Start
|
|
|
|
#region Start
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Starts a new placement operation that changes the placement of <paramref name="placedItem"/>.
|
|
|
|
/// Starts a new placement operation that changes the placement of <paramref name="placedItem"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="placedItem">The item to be placed.</param>
|
|
|
|
/// <param name="placedItems">The items to be placed.</param>
|
|
|
|
/// <param name="type">The type of the placement.</param>
|
|
|
|
/// <param name="type">The type of the placement.</param>
|
|
|
|
/// <returns>A PlacementOperation object.</returns>
|
|
|
|
/// <returns>A PlacementOperation object.</returns>
|
|
|
|
/// <remarks>
|
|
|
|
/// <remarks>
|
|
|
|
/// You MUST call either <see cref="Abort"/> or <see cref="Commit"/> on the returned PlacementOperation
|
|
|
|
/// 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!
|
|
|
|
/// once you are done with it, otherwise a ChangeGroup will be left open and Undo/Redo will fail to work!
|
|
|
|
/// </remarks>
|
|
|
|
/// </remarks>
|
|
|
|
public static PlacementOperation Start(DesignItem placedItem, PlacementType type) |
|
|
|
public static PlacementOperation Start(ICollection<DesignItem> placedItems, PlacementType type) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (placedItem == null) |
|
|
|
if (placedItems == null) |
|
|
|
throw new ArgumentNullException("placedItem"); |
|
|
|
throw new ArgumentNullException("placedItems"); |
|
|
|
if (type == null) |
|
|
|
if (type == null) |
|
|
|
throw new ArgumentNullException("type"); |
|
|
|
throw new ArgumentNullException("type"); |
|
|
|
PlacementOperation op = new PlacementOperation(placedItem, type); |
|
|
|
DesignItem[] items = Func.ToArray(placedItems); |
|
|
|
|
|
|
|
if (items.Length == 0) |
|
|
|
|
|
|
|
throw new ArgumentException("placedItems.Length must be > 0"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PlacementOperation op = new PlacementOperation(items, type); |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (op.currentContainerBehavior == null) |
|
|
|
if (op.currentContainerBehavior == null) |
|
|
|
throw new InvalidOperationException("Starting the operation is not supported"); |
|
|
|
throw new InvalidOperationException("Starting the operation is not supported"); |
|
|
|
op.Left = op.Top = op.Bottom = op.Right = double.NaN; |
|
|
|
|
|
|
|
op.currentContainerBehavior.StartPlacement(op); |
|
|
|
op.currentContainerBehavior.BeginPlacement(op); |
|
|
|
if (double.IsNaN(op.Left) || double.IsNaN(op.Top) || double.IsNaN(op.Bottom) || double.IsNaN(op.Right)) |
|
|
|
foreach (PlacementInformation info in op.placedItems) { |
|
|
|
throw new InvalidOperationException("IPlacementBehavior.StartPlacement must set Left,Top,Right+Bottom to non-NAN values"); |
|
|
|
info.OriginalBounds = op.currentContainerBehavior.GetPosition(op, info.Item); |
|
|
|
|
|
|
|
info.Bounds = info.OriginalBounds; |
|
|
|
|
|
|
|
} |
|
|
|
} catch { |
|
|
|
} catch { |
|
|
|
op.changeGroup.Abort(); |
|
|
|
op.changeGroup.Abort(); |
|
|
|
throw; |
|
|
|
throw; |
|
|
|
} |
|
|
|
} |
|
|
|
return op; |
|
|
|
return op; |
|
|
|
} |
|
|
|
} |
|
|
|
private PlacementOperation(DesignItem placedItem, PlacementType type) |
|
|
|
private PlacementOperation(DesignItem[] items, PlacementType type) |
|
|
|
{ |
|
|
|
{ |
|
|
|
this.placedItem = placedItem; |
|
|
|
PlacementInformation[] information = new PlacementInformation[items.Length]; |
|
|
|
|
|
|
|
for (int i = 0; i < information.Length; i++) { |
|
|
|
|
|
|
|
information[i] = new PlacementInformation(items[i], this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.placedItems = new ReadOnlyCollection<PlacementInformation>(information); |
|
|
|
this.type = type; |
|
|
|
this.type = type; |
|
|
|
|
|
|
|
|
|
|
|
this.oldContainer = placedItem.Parent; |
|
|
|
this.oldContainer = items[0].Parent; |
|
|
|
this.oldContainerBehavior = GetPlacementBehavior(placedItem); |
|
|
|
this.oldContainerBehavior = GetPlacementBehavior(items); |
|
|
|
|
|
|
|
|
|
|
|
this.currentContainer = oldContainer; |
|
|
|
this.currentContainer = oldContainer; |
|
|
|
this.currentContainerBehavior = oldContainerBehavior; |
|
|
|
this.currentContainerBehavior = oldContainerBehavior; |
|
|
|
this.changeGroup = placedItem.OpenGroup(type.ToString()); |
|
|
|
this.changeGroup = items[0].Context.OpenGroup(type.ToString(), items); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the placement behavior associated with the specified item.
|
|
|
|
/// Gets the placement behavior associated with the specified items.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public static IPlacementBehavior GetPlacementBehavior(DesignItem item) |
|
|
|
public static IPlacementBehavior GetPlacementBehavior(ICollection<DesignItem> items) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (item == null) |
|
|
|
if (items == null) |
|
|
|
throw new ArgumentNullException("item"); |
|
|
|
throw new ArgumentNullException("items"); |
|
|
|
if (item.Parent != null) { |
|
|
|
if (items.Count == 0) |
|
|
|
return item.Parent.GetBehavior<IPlacementBehavior>(); |
|
|
|
return null; |
|
|
|
} else { |
|
|
|
DesignItem parent = Func.First(items).Parent; |
|
|
|
return item.GetBehavior<IRootPlacementBehavior>(); |
|
|
|
foreach (DesignItem item in Func.Skip(items, 1)) { |
|
|
|
} |
|
|
|
if (item.Parent != parent) |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (parent != null) |
|
|
|
|
|
|
|
return parent.GetBehavior<IPlacementBehavior>(); |
|
|
|
|
|
|
|
else if (items.Count == 1) |
|
|
|
|
|
|
|
return Func.First(items).GetBehavior<IRootPlacementBehavior>(); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
@ -183,7 +205,7 @@ namespace ICSharpCode.WpfDesign |
|
|
|
if (isCommitted) |
|
|
|
if (isCommitted) |
|
|
|
throw new InvalidOperationException("PlacementOperation is committed."); |
|
|
|
throw new InvalidOperationException("PlacementOperation is committed."); |
|
|
|
isAborted = true; |
|
|
|
isAborted = true; |
|
|
|
currentContainerBehavior.FinishPlacement(this); |
|
|
|
currentContainerBehavior.EndPlacement(this); |
|
|
|
changeGroup.Abort(); |
|
|
|
changeGroup.Abort(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -197,7 +219,7 @@ namespace ICSharpCode.WpfDesign |
|
|
|
if (isAborted || isCommitted) |
|
|
|
if (isAborted || isCommitted) |
|
|
|
throw new InvalidOperationException("PlacementOperation is already aborted/committed."); |
|
|
|
throw new InvalidOperationException("PlacementOperation is already aborted/committed."); |
|
|
|
isCommitted = true; |
|
|
|
isCommitted = true; |
|
|
|
currentContainerBehavior.FinishPlacement(this); |
|
|
|
currentContainerBehavior.EndPlacement(this); |
|
|
|
changeGroup.Commit(); |
|
|
|
changeGroup.Commit(); |
|
|
|
} |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|