Browse Source

Allow selecting multiple child elements inside a Panel by "drawing" a selection rectangle.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2414 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
e65517ff29
  1. 75
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/GrayOutDesignerExceptActiveArea.cs
  2. 5
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/CanvasChildResizeSupport.cs
  3. 14
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/DefaultChildResizeSupport.cs
  4. 162
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelSelectionHandler.cs
  5. 20
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/ResizeThumbExtension.cs
  6. 43
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
  7. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
  8. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
  9. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs
  10. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItemProperty.cs
  11. 18
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/MouseInteraction.cs
  12. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs
  13. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

75
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/GrayOutDesignerExceptActiveArea.cs

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
// <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.Media;
namespace ICSharpCode.WpfDesign.Designer.Controls
{
/// <summary>
/// Gray out everything except a specific area.
/// </summary>
sealed class GrayOutDesignerExceptActiveArea : FrameworkElement
{
//Geometry infiniteRectangle = new RectangleGeometry(new Rect(0, 0, double.PositiveInfinity, double.PositiveInfinity));
Geometry infiniteRectangle = new RectangleGeometry(new Rect(0, 0, 10000, 10000));
Geometry activeAreaGeometry;
Geometry combinedGeometry;
Brush grayOutBrush;
public GrayOutDesignerExceptActiveArea()
{
Color c = SystemColors.GrayTextColor;
c.R = (byte)Math.Max(0, c.R - 20);
c.G = (byte)Math.Max(0, c.G - 20);
c.B = (byte)Math.Max(0, c.B - 20);
c.A = 30;
this.GrayOutBrush = new SolidColorBrush(c);
}
public Brush GrayOutBrush {
get { return grayOutBrush; }
set { grayOutBrush = value; }
}
public Geometry ActiveAreaGeometry {
get { return activeAreaGeometry; }
set {
activeAreaGeometry = value;
combinedGeometry = new CombinedGeometry(GeometryCombineMode.Exclude, infiniteRectangle, activeAreaGeometry);
}
}
public void SetActiveArea(UIElement activeContainer)
{
this.ActiveAreaGeometry = new RectangleGeometry(new Rect(activeContainer.RenderSize), 0, 0, (Transform)activeContainer.TransformToVisual(this));
}
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawGeometry(grayOutBrush, null, combinedGeometry);
}
internal static void Start(ref GrayOutDesignerExceptActiveArea grayOut, IDesignPanel designPanel, UIElement activeContainer)
{
if (designPanel != null) {
grayOut = new GrayOutDesignerExceptActiveArea();
designPanel.MarkerCanvas.Children.Add(grayOut);
grayOut.SetActiveArea(activeContainer);
}
}
internal static void Stop(ref GrayOutDesignerExceptActiveArea grayOut, IDesignPanel designPanel)
{
if (grayOut != null) {
designPanel.MarkerCanvas.Children.Remove(grayOut);
grayOut = null;
}
}
}
}

5
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/CanvasChildResizeSupport.cs

@ -6,17 +6,18 @@ @@ -6,17 +6,18 @@
// </file>
using System;
using ICSharpCode.WpfDesign.Extensions;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.WpfDesign.Adorners;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
/// <summary>
/// Provides <see cref="IChildResizeSupport"/> behavior for <see cref="Canvas"/>.
/// </summary>
[ExtensionFor(typeof(Canvas))]
[ExtensionFor(typeof(Canvas), OverrideExtension = typeof(DefaultChildResizeSupport))]
public sealed class CanvasChildResizeSupport : BehaviorExtension, IChildResizeSupport
{
/// <inherits/>

14
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/DefaultChildResizeSupport.cs

@ -6,9 +6,9 @@ @@ -6,9 +6,9 @@
// </file>
using System;
using ICSharpCode.WpfDesign.Extensions;
using ICSharpCode.WpfDesign.Adorners;
using System.Windows;
using ICSharpCode.WpfDesign.Adorners;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
@ -16,21 +16,17 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -16,21 +16,17 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
/// Implements IChildResizeSupport supporting size changes using the
/// Width, Height, Margin properties.
/// </summary>
//[ExtensionFor(typeof(FrameworkElement))]
sealed class DefaultChildResizeSupport : IChildResizeSupport
[ExtensionFor(typeof(FrameworkElement))]
public sealed class DefaultChildResizeSupport : BehaviorExtension, IChildResizeSupport
{
// the default behavior is not an extension because it does not depend
// on a parent container instance
public static readonly DefaultChildResizeSupport Instance = new DefaultChildResizeSupport();
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)

162
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelSelectionHandler.cs

@ -0,0 +1,162 @@ @@ -0,0 +1,162 @@
// <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.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.WpfDesign.Adorners;
using ICSharpCode.WpfDesign.Designer.Controls;
using ICSharpCode.WpfDesign.Designer.Services;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
/// <summary>
/// Handles selection multiple controls inside a Panel.
/// </summary>
[ExtensionFor(typeof(Panel))]
public class PanelSelectionHandler : BehaviorExtension, IHandlePointerToolMouseDown
{
/// <inherit/>
protected override void OnInitialized()
{
base.OnInitialized();
this.ExtendedItem.AddBehavior(typeof(IHandlePointerToolMouseDown), this);
}
/// <inherit/>
public void HandleSelectionMouseDown(IDesignPanel designPanel, MouseButtonEventArgs e, DesignPanelHitTestResult result)
{
new RangeSelectionGesture(result.ModelHit).Start(designPanel, e);
}
}
sealed class RangeSelectionGesture : MouseGestureBase
{
DesignItem container;
AdornerPanel adornerPanel;
DragFrame selectionFrame;
Point startPoint;
GrayOutDesignerExceptActiveArea grayOut;
public RangeSelectionGesture(DesignItem container)
{
this.container = container;
}
protected override void OnStarted(MouseButtonEventArgs e)
{
startPoint = e.GetPosition(container.View);
adornerPanel = new AdornerPanel();
adornerPanel.SetAdornedElement(container.View, container);
selectionFrame = new DragFrame();
SetPlacement(e.GetPosition(container.View));
adornerPanel.Children.Add(selectionFrame);
designPanel.Adorners.Add(adornerPanel);
GrayOutDesignerExceptActiveArea.Start(ref grayOut, designPanel, container.View);
}
protected override void OnMouseMove(object sender, MouseEventArgs e)
{
SetPlacement(e.GetPosition(container.View));
}
protected override void OnMouseUp(object sender, MouseButtonEventArgs e)
{
Point endPoint = e.GetPosition(container.View);
Rect frameRect = new Rect(
Math.Min(startPoint.X, endPoint.X),
Math.Min(startPoint.Y, endPoint.Y),
Math.Abs(startPoint.X - endPoint.X),
Math.Abs(startPoint.Y - endPoint.Y)
);
ICollection<DesignItem> items = GetChildDesignItemsInContainer(container, new RectangleGeometry(frameRect));
if (items.Count == 0) {
items.Add(container);
}
services.Selection.SetSelectedComponents(items, SelectionTypes.Auto);
Stop();
}
static ICollection<DesignItem> GetChildDesignItemsInContainer(
DesignItem container, Geometry geometry)
{
HashSet<DesignItem> resultItems = new HashSet<DesignItem>();
ViewService viewService = container.Services.View;
HitTestFilterCallback filterCallback = delegate(DependencyObject potentialHitTestTarget) {
FrameworkElement element = potentialHitTestTarget as FrameworkElement;
if (element != null) {
// ensure we are able to select elements with width/height=0
if (element.ActualWidth == 0 || element.ActualHeight == 0) {
DependencyObject tmp = element;
DesignItem model = null;
while (tmp != null) {
model = viewService.GetModel(tmp);
if (model != null) break;
tmp = VisualTreeHelper.GetParent(tmp);
}
if (model != container) {
resultItems.Add(model);
return HitTestFilterBehavior.ContinueSkipChildren;
}
}
}
return HitTestFilterBehavior.Continue;
};
HitTestResultCallback resultCallback = delegate(HitTestResult result) {
if (((GeometryHitTestResult) result).IntersectionDetail == IntersectionDetail.FullyInside) {
// find the model for the visual contained in the selection area
DependencyObject tmp = result.VisualHit;
DesignItem model = null;
while (tmp != null) {
model = viewService.GetModel(tmp);
if (model != null) break;
tmp = VisualTreeHelper.GetParent(tmp);
}
if (model != container) {
resultItems.Add(model);
}
}
return HitTestResultBehavior.Continue;
};
VisualTreeHelper.HitTest(container.View, filterCallback, resultCallback, new GeometryHitTestParameters(geometry));
return resultItems;
}
void SetPlacement(Point endPoint)
{
RelativePlacement p = new RelativePlacement();
p.XOffset = Math.Min(startPoint.X, endPoint.X);
p.YOffset = Math.Min(startPoint.Y, endPoint.Y);
p.WidthOffset = Math.Max(startPoint.X, endPoint.X) - p.XOffset;
p.HeightOffset = Math.Max(startPoint.Y, endPoint.Y) - p.YOffset;
AdornerPanel.SetPlacement(selectionFrame, p);
}
protected override void OnStopped()
{
if (adornerPanel != null) {
designPanel.Adorners.Remove(adornerPanel);
adornerPanel = null;
}
GrayOutDesignerExceptActiveArea.Stop(ref grayOut, designPanel);
selectionFrame = null;
}
}
}

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

@ -6,14 +6,13 @@ @@ -6,14 +6,13 @@
// </file>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using ICSharpCode.WpfDesign.Adorners;
using ICSharpCode.WpfDesign.Extensions;
using ICSharpCode.WpfDesign.Designer.Controls;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
@ -25,6 +24,8 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -25,6 +24,8 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
{
AdornerPanel adornerPanel;
DragFrame dragFrame;
IChildResizeSupport resizeBehavior;
GrayOutDesignerExceptActiveArea grayOut;
/// <summary></summary>
public ResizeThumbExtension()
@ -49,13 +50,15 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -49,13 +50,15 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
resizeThumb.DragCompleted += OnDragCompleted(horizontalAlignment, verticalAlignment);
}
IChildResizeSupport resizeBehavior;
void OnDragStarted(object sender, DragStartedEventArgs e)
{
if (dragFrame == null)
dragFrame = new DragFrame();
if (this.ExtendedItem.Parent != null) {
GrayOutDesignerExceptActiveArea.Start(ref grayOut, this.Services.GetService<IDesignPanel>(), this.ExtendedItem.Parent.View);
}
AdornerPanel.SetPlacement(dragFrame, Placement.FillContent);
adornerPanel.Children.Add(dragFrame);
adornerPanel.Cursor = Cursors.SizeNWSE;
@ -83,8 +86,9 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -83,8 +86,9 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
return delegate (object sender, DragCompletedEventArgs e) {
adornerPanel.Children.Remove(dragFrame);
adornerPanel.ClearValue(AdornerPanel.CursorProperty);
GrayOutDesignerExceptActiveArea.Stop(ref grayOut, this.Services.GetService<IDesignPanel>());
if (resizeBehavior != null) {
if (e.Canceled == false && resizeBehavior != null) {
using (ChangeGroup group = this.ExtendedItem.OpenGroup("Resize")) {
resizeBehavior.Resize(this.ExtendedItem,
FixChange(e.HorizontalChange, horizontalAlignment),
@ -127,7 +131,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -127,7 +131,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
if (parentItem == null) // resizing the root element
resizeBehavior = RootElementResizeSupport.Instance;
else
resizeBehavior = parentItem.GetBehavior<IChildResizeSupport>() ?? DefaultChildResizeSupport.Instance;
resizeBehavior = parentItem.GetBehavior<IChildResizeSupport>();
UpdateAdornerVisibility();
OnPrimarySelectionChanged(null, null);

43
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs

@ -64,11 +64,23 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -64,11 +64,23 @@ namespace ICSharpCode.WpfDesign.Designer.Services
{
if (e.ChangedButton == MouseButton.Left && MouseGestureBase.IsOnlyButtonPressed(e, MouseButton.Left)) {
e.Handled = true;
new SelectionGesture().Start((IDesignPanel)sender, e);
IDesignPanel designPanel = (IDesignPanel)sender;
DesignPanelHitTestResult result = designPanel.HitTest(e, false, true);
if (result.ModelHit != null) {
IHandlePointerToolMouseDown b = result.ModelHit.GetBehavior<IHandlePointerToolMouseDown>();
if (b != null) {
b.HandleSelectionMouseDown(designPanel, e, result);
} else {
designPanel.Context.Services.Selection.SetSelectedComponents(new DesignItem[] { result.ModelHit }, SelectionTypes.Auto);
}
}
}
}
}
/// <summary>
/// Base class for classes handling mouse gestures on the design surface.
/// </summary>
abstract class MouseGestureBase
{
/// <summary>
@ -89,12 +101,19 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -89,12 +101,19 @@ namespace ICSharpCode.WpfDesign.Designer.Services
public void Start(IDesignPanel designPanel, MouseButtonEventArgs e)
{
if (designPanel == null)
throw new ArgumentNullException("designPanel");
if (e == null)
throw new ArgumentNullException("e");
if (isStarted)
throw new InvalidOperationException("Gesture already was started");
isStarted = true;
this.designPanel = designPanel;
this.services = designPanel.Context.Services;
isStarted = true;
designPanel.IsAdornerLayerHitTestVisible = false;
RegisterEvents();
if (designPanel.CaptureMouse()) {
RegisterEvents();
OnStarted(e);
} else {
Stop();
@ -148,22 +167,4 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -148,22 +167,4 @@ namespace ICSharpCode.WpfDesign.Designer.Services
protected virtual void OnStarted(MouseButtonEventArgs e) {}
protected virtual void OnStopped() {}
}
sealed class SelectionGesture : MouseGestureBase
{
protected override void OnStarted(MouseButtonEventArgs e)
{
base.OnStarted(e);
DesignPanelHitTestResult result = designPanel.HitTest(e, false, true);
if (result.ModelHit != null) {
services.Selection.SetSelectedComponents(new DesignItem[] { result.ModelHit }, SelectionTypes.Auto);
}
}
protected override void OnStopped()
{
//designPanel.cur
base.OnStopped();
}
}
}

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj

@ -60,6 +60,7 @@ @@ -60,6 +60,7 @@
<Compile Include="Controls\ContainerDragHandle.cs" />
<Compile Include="Controls\DragFrame.cs" />
<Compile Include="Controls\ErrorBalloon.cs" />
<Compile Include="Controls\GrayOutDesignerExceptActiveArea.cs" />
<Compile Include="Controls\PropertyEditor\DependencyPropertyDotButton.cs" />
<Compile Include="Controls\PropertyEditor\PropertyEditor.cs" />
<Compile Include="Controls\PropertyEditor\PropertyEditorCategoryView.cs" />
@ -73,6 +74,7 @@ @@ -73,6 +74,7 @@
<Compile Include="Extensions\CanvasChildResizeSupport.cs" />
<Compile Include="Extensions\DefaultChildResizeSupport.cs" />
<Compile Include="Extensions\PanelInstanceFactory.cs" />
<Compile Include="Extensions\PanelSelectionHandler.cs" />
<Compile Include="Extensions\SelectedElementRectangleExtension.cs" />
<Compile Include="Extensions\TabItemClickableExtension.cs" />
<Compile Include="Extensions\TopLeftContainerDragHandle.cs" />

1
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.Xml;
using ICSharpCode.WpfDesign.XamlDom;
using ICSharpCode.WpfDesign.Designer.Services;
using ICSharpCode.WpfDesign.Designer.Extensions;
using ICSharpCode.WpfDesign.Extensions;
using ICSharpCode.WpfDesign.PropertyEditor;

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.WpfDesign @@ -152,7 +152,7 @@ namespace ICSharpCode.WpfDesign
#endregion
#region Manage behavior
Dictionary<Type, object> _behaviorObjects = new Dictionary<Type, object>();
readonly Dictionary<Type, object> _behaviorObjects = new Dictionary<Type, object>();
/// <summary>
/// Adds a bevahior extension object to this design item.
@ -163,6 +163,8 @@ namespace ICSharpCode.WpfDesign @@ -163,6 +163,8 @@ namespace ICSharpCode.WpfDesign
throw new ArgumentNullException("bevahiorInterface");
if (behaviorImplementation == null)
throw new ArgumentNullException("behaviorImplementation");
if (!bevahiorInterface.IsInstanceOfType(behaviorImplementation))
throw new ArgumentException("behaviorImplementation must implement bevahiorInterface", "behaviorImplementation");
_behaviorObjects.Add(bevahiorInterface, behaviorImplementation);
}

1
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItemProperty.cs

@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
// </file>
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;

18
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Behavior.cs → src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/MouseInteraction.cs

@ -6,11 +6,27 @@ @@ -6,11 +6,27 @@
// </file>
using System;
using ICSharpCode.WpfDesign.Adorners;
using System.Windows;
using System.Windows.Input;
using ICSharpCode.WpfDesign.Adorners;
namespace ICSharpCode.WpfDesign
{
// Interfaces for mouse interaction on the design surface.
/// <summary>
/// Behavior interface implemented by elements to handle the mouse down event
/// on them.
/// </summary>
public interface IHandlePointerToolMouseDown
{
/// <summary>
/// Called to handle the mouse down event.
/// </summary>
void HandleSelectionMouseDown(IDesignPanel designPanel, MouseButtonEventArgs e, DesignPanelHitTestResult result);
}
/// <summary>
/// Behavior interface implemented by container elements to support resizing
/// child elements.

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs

@ -9,7 +9,6 @@ using System; @@ -9,7 +9,6 @@ using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using ICSharpCode.WpfDesign.Adorners;
@ -83,7 +82,8 @@ namespace ICSharpCode.WpfDesign @@ -83,7 +82,8 @@ namespace ICSharpCode.WpfDesign
/// <summary>
/// A canvas that is on top of the design surface and all adorners.
/// Used for temporary drawings that are not attached to any element, e.g. the selection frame.
/// Used for temporary drawings that are not attached to any element, e.g. graying out everything
/// except the target container in drag'n'drop operations.
/// </summary>
Canvas MarkerCanvas { get; }

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

@ -61,7 +61,7 @@ @@ -61,7 +61,7 @@
<Compile Include="Adorners\AdornerProvider.cs" />
<Compile Include="Adorners\AdornerProviderClasses.cs" />
<Compile Include="Adorners\Placement.cs" />
<Compile Include="Behavior.cs" />
<Compile Include="MouseInteraction.cs" />
<Compile Include="ChangeGroup.cs" />
<Compile Include="DesignContext.cs" />
<Compile Include="DesignItemProperty.cs" />

Loading…
Cancel
Save