1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
6
using System.ComponentModel;
7
using System.Diagnostics;
9
using System.Windows.Controls;
10
using System.Windows.Input;
11
using System.Windows.Media;
12
using System.Windows.Threading;
14
using ICSharpCode.WpfDesign.Adorners;
15
using ICSharpCode.WpfDesign.Designer.Controls;
17
namespace ICSharpCode.WpfDesign.Designer
19
sealed class DesignPanel : Decorator, IDesignPanel
23
/// this element is always hit (unless HitTestVisible is set to false)
25
sealed class EatAllHitTestRequests : UIElement
27
protected override GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters)
29
return new GeometryHitTestResult(this, IntersectionDetail.FullyContains);
32
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
34
return new PointHitTestResult(this, hitTestParameters.HitPoint);
38
static void RunHitTest(Visual reference, Point point, HitTestFilterCallback filterCallback, HitTestResultCallback resultCallback)
40
VisualTreeHelper.HitTest(reference, filterCallback, resultCallback,
41
new PointHitTestParameters(point));
44
static HitTestFilterBehavior FilterHitTestInvisibleElements(DependencyObject potentialHitTestTarget)
46
UIElement element = potentialHitTestTarget as UIElement;
47
if (element != null) {
48
if (!(element.IsHitTestVisible && element.Visibility == Visibility.Visible)) {
49
return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
52
return HitTestFilterBehavior.Continue;
56
/// Performs a custom hit testing lookup for the specified mouse event args.
58
public DesignPanelHitTestResult HitTest(Point mousePosition, bool testAdorners, bool testDesignSurface)
60
DesignPanelHitTestResult result = DesignPanelHitTestResult.NoHit;
61
HitTest(mousePosition, testAdorners, testDesignSurface,
62
delegate(DesignPanelHitTestResult r) {
70
/// Performs a hit test on the design surface, raising <paramref name="callback"/> for each match.
71
/// Hit testing continues while the callback returns true.
73
public void HitTest(Point mousePosition, bool testAdorners, bool testDesignSurface, Predicate<DesignPanelHitTestResult> callback)
75
if (mousePosition.X < 0 || mousePosition.Y < 0 || mousePosition.X > this.RenderSize.Width || mousePosition.Y > this.RenderSize.Height) {
78
// First try hit-testing on the adorner layer.
80
bool continueHitTest = true;
84
_adornerLayer, mousePosition, FilterHitTestInvisibleElements,
85
delegate(HitTestResult result) {
86
if (result != null && result.VisualHit != null && result.VisualHit is Visual) {
87
DesignPanelHitTestResult customResult = new DesignPanelHitTestResult((Visual)result.VisualHit);
88
DependencyObject obj = result.VisualHit;
89
while (obj != null && obj != _adornerLayer) {
90
AdornerPanel adorner = obj as AdornerPanel;
91
if (adorner != null) {
92
customResult.AdornerHit = adorner;
94
obj = VisualTreeHelper.GetParent(obj);
96
continueHitTest = callback(customResult);
97
return continueHitTest ? HitTestResultBehavior.Continue : HitTestResultBehavior.Stop;
99
return HitTestResultBehavior.Continue;
104
if (continueHitTest && testDesignSurface) {
106
this.Child, mousePosition, delegate { return HitTestFilterBehavior.Continue; },
107
delegate(HitTestResult result) {
108
if (result != null && result.VisualHit != null && result.VisualHit is Visual) {
109
DesignPanelHitTestResult customResult = new DesignPanelHitTestResult((Visual)result.VisualHit);
111
ViewService viewService = _context.Services.View;
112
DependencyObject obj = result.VisualHit;
113
while (obj != null) {
114
if ((customResult.ModelHit = viewService.GetModel(obj)) != null)
116
obj = VisualTreeHelper.GetParent(obj);
118
if (customResult.ModelHit == null) {
119
customResult.ModelHit = _context.RootItem;
121
continueHitTest = callback(customResult);
122
return continueHitTest ? HitTestResultBehavior.Continue : HitTestResultBehavior.Stop;
124
return HitTestResultBehavior.Continue;
132
#region Fields + Constructor
133
DesignContext _context;
134
readonly EatAllHitTestRequests _eatAllHitTestRequests;
135
readonly AdornerLayer _adornerLayer;
139
this.Focusable = true;
140
this.Margin = new Thickness(16);
141
DesignerProperties.SetIsInDesignMode(this, true);
143
_eatAllHitTestRequests = new EatAllHitTestRequests();
144
_eatAllHitTestRequests.MouseDown += delegate {
145
// ensure the design panel has focus while the user is interacting with it
148
_eatAllHitTestRequests.AllowDrop = true;
149
_adornerLayer = new AdornerLayer(this);
156
/// Gets/Sets the design context.
158
public DesignContext Context {
159
get { return _context; }
160
set { _context = value; }
163
public ICollection<AdornerPanel> Adorners {
165
return _adornerLayer.Adorners;
170
/// Gets/Sets if the design content is visible for hit-testing purposes.
172
public bool IsContentHitTestVisible {
173
get { return !_eatAllHitTestRequests.IsHitTestVisible; }
174
set { _eatAllHitTestRequests.IsHitTestVisible = !value; }
178
/// Gets/Sets if the adorner layer is visible for hit-testing purposes.
180
public bool IsAdornerLayerHitTestVisible {
181
get { return _adornerLayer.IsHitTestVisible; }
182
set { _adornerLayer.IsHitTestVisible = value; }
187
#region Visual Child Management
188
public override UIElement Child {
189
get { return base.Child; }
191
if (base.Child == value)
194
// Child is being set from some value to null
196
// remove _adornerLayer and _eatAllHitTestRequests
197
RemoveVisualChild(_adornerLayer);
198
RemoveVisualChild(_eatAllHitTestRequests);
199
} else if (base.Child == null) {
200
// Child is being set from null to some value
201
AddVisualChild(_adornerLayer);
202
AddVisualChild(_eatAllHitTestRequests);
208
protected override Visual GetVisualChild(int index)
210
if (base.Child != null) {
214
return _eatAllHitTestRequests;
216
return _adornerLayer;
218
return base.GetVisualChild(index);
221
protected override int VisualChildrenCount {
223
if (base.Child != null)
226
return base.VisualChildrenCount;
230
protected override Size MeasureOverride(Size constraint)
232
Size result = base.MeasureOverride(constraint);
233
if (this.Child != null) {
234
_adornerLayer.Measure(constraint);
235
_eatAllHitTestRequests.Measure(constraint);
240
protected override Size ArrangeOverride(Size arrangeSize)
242
Size result = base.ArrangeOverride(arrangeSize);
243
if (this.Child != null) {
244
Rect r = new Rect(new Point(0, 0), arrangeSize);
245
_adornerLayer.Arrange(r);
246
_eatAllHitTestRequests.Arrange(r);
252
protected override void OnQueryCursor(QueryCursorEventArgs e)
254
base.OnQueryCursor(e);
255
if (_context != null) {
256
Cursor cursor = _context.Services.Tool.CurrentTool.Cursor;
257
if (cursor != null) {