1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using System.Windows.Controls;
|
---|
6 | using System.Windows;
|
---|
7 | using System.Windows.Media;
|
---|
8 | using System.Diagnostics;
|
---|
9 | using Microsoft.Research.DynamicDataDisplay.Common;
|
---|
10 | using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
|
---|
11 | using System.ComponentModel;
|
---|
12 |
|
---|
13 | namespace Microsoft.Research.DynamicDataDisplay.Charts
|
---|
14 | {
|
---|
15 | /// <summary>
|
---|
16 | /// Represents a panel on which elements are arranged in coordinates in viewport space.
|
---|
17 | /// </summary>
|
---|
18 | public partial class ViewportPanel : IndividualArrangePanel
|
---|
19 | {
|
---|
20 | static ViewportPanel()
|
---|
21 | {
|
---|
22 | Type thisType = typeof(ViewportPanel);
|
---|
23 | Plotter.PlotterProperty.OverrideMetadata(thisType, new FrameworkPropertyMetadata { PropertyChangedCallback = OnPlotterChanged });
|
---|
24 | }
|
---|
25 |
|
---|
26 | private static void OnPlotterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
---|
27 | {
|
---|
28 | ViewportPanel panel = (ViewportPanel)d;
|
---|
29 | panel.OnPlotterChanged((Plotter)e.NewValue, (Plotter)e.OldValue);
|
---|
30 | }
|
---|
31 |
|
---|
32 | private void OnPlotterChanged(Plotter currPlotter, Plotter prevPlotter)
|
---|
33 | {
|
---|
34 | if (currPlotter != null)
|
---|
35 | {
|
---|
36 | Plotter2D plotter2d = (Plotter2D)currPlotter;
|
---|
37 | viewport = plotter2d.Viewport;
|
---|
38 | }
|
---|
39 | else
|
---|
40 | {
|
---|
41 | this.viewport = null;
|
---|
42 | }
|
---|
43 | }
|
---|
44 |
|
---|
45 | /// <summary>
|
---|
46 | /// Initializes a new instance of the <see cref="ViewportRectPanel"/> class.
|
---|
47 | /// </summary>
|
---|
48 | public ViewportPanel()
|
---|
49 | {
|
---|
50 | }
|
---|
51 |
|
---|
52 | #region Panel methods override
|
---|
53 |
|
---|
54 | protected override void OnChildDesiredSizeChanged(UIElement child)
|
---|
55 | {
|
---|
56 | base.OnChildDesiredSizeChanged(child);
|
---|
57 |
|
---|
58 | InvalidateMeasure();
|
---|
59 | }
|
---|
60 |
|
---|
61 | protected internal override void OnChildAdded(FrameworkElement child)
|
---|
62 | {
|
---|
63 | InvalidatePosition(child);
|
---|
64 | }
|
---|
65 |
|
---|
66 | protected virtual void InvalidatePosition(FrameworkElement child)
|
---|
67 | {
|
---|
68 | if (viewport == null) return;
|
---|
69 |
|
---|
70 | var transform = GetTransform(availableSize);
|
---|
71 |
|
---|
72 | Size elementSize = GetElementSize(child, AvailableSize, transform);
|
---|
73 | child.Measure(elementSize);
|
---|
74 |
|
---|
75 | Rect bounds = GetElementScreenBounds(transform, child);
|
---|
76 | if (!bounds.IsNaN())
|
---|
77 | {
|
---|
78 | child.Arrange(bounds);
|
---|
79 | }
|
---|
80 | }
|
---|
81 |
|
---|
82 | private Size availableSize;
|
---|
83 | protected Size AvailableSize
|
---|
84 | {
|
---|
85 | get { return availableSize; }
|
---|
86 | set { availableSize = value; }
|
---|
87 | }
|
---|
88 |
|
---|
89 | protected override Size MeasureOverride(Size availableSize)
|
---|
90 | {
|
---|
91 | this.availableSize = availableSize;
|
---|
92 |
|
---|
93 | var transform = GetTransform(availableSize);
|
---|
94 |
|
---|
95 | foreach (FrameworkElement child in InternalChildren)
|
---|
96 | {
|
---|
97 | if (child != null)
|
---|
98 | {
|
---|
99 | Size elementSize = GetElementSize(child, availableSize, transform);
|
---|
100 | child.Measure(elementSize);
|
---|
101 | }
|
---|
102 | }
|
---|
103 |
|
---|
104 | if (availableSize.Width.IsInfinite())
|
---|
105 | availableSize.Width = 0;
|
---|
106 | if (availableSize.Height.IsInfinite())
|
---|
107 | availableSize.Height = 0;
|
---|
108 | return availableSize;
|
---|
109 | }
|
---|
110 |
|
---|
111 | protected virtual Size GetElementSize(FrameworkElement child, Size availableSize, CoordinateTransform transform)
|
---|
112 | {
|
---|
113 | Size result = availableSize;
|
---|
114 |
|
---|
115 | DataRect ownViewportBounds = GetViewportBounds(child);
|
---|
116 | if (!ownViewportBounds.IsEmpty)
|
---|
117 | {
|
---|
118 | result = ownViewportBounds.ViewportToScreen(transform).Size;
|
---|
119 | }
|
---|
120 | else
|
---|
121 | {
|
---|
122 | double viewportWidth = GetViewportWidth(child);
|
---|
123 | double viewportHeight = GetViewportHeight(child);
|
---|
124 |
|
---|
125 | bool hasViewportWidth = viewportWidth.IsNotNaN();
|
---|
126 | bool hasViewportHeight = viewportHeight.IsNotNaN();
|
---|
127 |
|
---|
128 | double minScreenWidth = GetMinScreenWidth(child);
|
---|
129 | bool hasMinScreenWidth = minScreenWidth.IsNotNaN();
|
---|
130 |
|
---|
131 | double selfWidth = child.Width.IsNotNaN() ? child.Width : availableSize.Width;
|
---|
132 | double width = hasViewportWidth ? viewportWidth : selfWidth;
|
---|
133 |
|
---|
134 | double selfHeight = child.Height.IsNotNaN() ? child.Height : availableSize.Height;
|
---|
135 | double height = hasViewportHeight ? viewportHeight : selfHeight;
|
---|
136 |
|
---|
137 | if (width < 0) width = 0;
|
---|
138 | if (height < 0) height = 0;
|
---|
139 |
|
---|
140 | DataRect bounds = new DataRect(new Size(width, height));
|
---|
141 | Rect screenBounds = bounds.ViewportToScreen(transform);
|
---|
142 |
|
---|
143 | result = new Size(hasViewportWidth ? screenBounds.Width : selfWidth,
|
---|
144 | hasViewportHeight ? screenBounds.Height : selfHeight);
|
---|
145 |
|
---|
146 | if (hasMinScreenWidth && result.Width < minScreenWidth)
|
---|
147 | {
|
---|
148 | result.Width = minScreenWidth;
|
---|
149 | }
|
---|
150 | }
|
---|
151 |
|
---|
152 | if (result.Width.IsNaN()) result.Width = 0;
|
---|
153 | if (result.Height.IsNaN()) result.Height = 0;
|
---|
154 |
|
---|
155 | return result;
|
---|
156 | }
|
---|
157 |
|
---|
158 | protected Rect GetElementScreenBounds(CoordinateTransform transform, UIElement child)
|
---|
159 | {
|
---|
160 | Rect screenBounds = GetElementScreenBoundsCore(transform, child);
|
---|
161 |
|
---|
162 | DataRect viewportBounds = screenBounds.ScreenToViewport(transform);
|
---|
163 | DataRect prevViewportBounds = GetActualViewportBounds(child);
|
---|
164 |
|
---|
165 | SetPrevActualViewportBounds(child, prevViewportBounds);
|
---|
166 | SetActualViewportBounds(child, viewportBounds);
|
---|
167 |
|
---|
168 | return screenBounds;
|
---|
169 | }
|
---|
170 |
|
---|
171 | protected virtual Rect GetElementScreenBoundsCore(CoordinateTransform transform, UIElement child)
|
---|
172 | {
|
---|
173 | Rect bounds = new Rect(0, 0, 1, 1);
|
---|
174 |
|
---|
175 | DataRect ownViewportBounds = GetViewportBounds(child);
|
---|
176 | if (!ownViewportBounds.IsEmpty)
|
---|
177 | {
|
---|
178 | bounds = ownViewportBounds.ViewportToScreen(transform);
|
---|
179 | }
|
---|
180 | else
|
---|
181 | {
|
---|
182 | double viewportX = GetX(child);
|
---|
183 | double viewportY = GetY(child);
|
---|
184 |
|
---|
185 | if (viewportX.IsNaN() || viewportY.IsNaN())
|
---|
186 | {
|
---|
187 | //Debug.WriteLine("ViewportRectPanel: Position is not set!");
|
---|
188 |
|
---|
189 | return bounds;
|
---|
190 | }
|
---|
191 |
|
---|
192 | double viewportWidth = GetViewportWidth(child);
|
---|
193 | if (viewportWidth < 0) viewportWidth = 0;
|
---|
194 | double viewportHeight = GetViewportHeight(child);
|
---|
195 | if (viewportHeight < 0) viewportHeight = 0;
|
---|
196 |
|
---|
197 | bool hasViewportWidth = viewportWidth.IsNotNaN();
|
---|
198 | bool hasViewportHeight = viewportHeight.IsNotNaN();
|
---|
199 |
|
---|
200 | DataRect r = new DataRect(new Size(hasViewportWidth ? viewportWidth : child.DesiredSize.Width,
|
---|
201 | hasViewportHeight ? viewportHeight : child.DesiredSize.Height));
|
---|
202 | r = r.ViewportToScreen(transform);
|
---|
203 |
|
---|
204 | double screenWidth = hasViewportWidth ? r.Width : child.DesiredSize.Width;
|
---|
205 | double screenHeight = hasViewportHeight ? r.Height : child.DesiredSize.Height;
|
---|
206 |
|
---|
207 | double minScreenWidth = GetMinScreenWidth(child);
|
---|
208 | bool hasMinScreemWidth = minScreenWidth.IsNotNaN();
|
---|
209 |
|
---|
210 | if (hasViewportWidth && screenWidth < minScreenWidth)
|
---|
211 | screenWidth = minScreenWidth;
|
---|
212 |
|
---|
213 | Point location = new Point(viewportX, viewportY).ViewportToScreen(transform);
|
---|
214 |
|
---|
215 | double screenX = location.X;
|
---|
216 | double screenY = location.Y;
|
---|
217 |
|
---|
218 | HorizontalAlignment horizAlignment = GetViewportHorizontalAlignment(child);
|
---|
219 | switch (horizAlignment)
|
---|
220 | {
|
---|
221 | case HorizontalAlignment.Stretch:
|
---|
222 | case HorizontalAlignment.Center:
|
---|
223 | screenX -= screenWidth / 2;
|
---|
224 | break;
|
---|
225 | case HorizontalAlignment.Left:
|
---|
226 | break;
|
---|
227 | case HorizontalAlignment.Right:
|
---|
228 | screenX -= screenWidth;
|
---|
229 | break;
|
---|
230 | }
|
---|
231 |
|
---|
232 | VerticalAlignment vertAlignment = GetViewportVerticalAlignment(child);
|
---|
233 | switch (vertAlignment)
|
---|
234 | {
|
---|
235 | case VerticalAlignment.Bottom:
|
---|
236 | screenY -= screenHeight;
|
---|
237 | break;
|
---|
238 | case VerticalAlignment.Center:
|
---|
239 | case VerticalAlignment.Stretch:
|
---|
240 | screenY -= screenHeight / 2;
|
---|
241 | break;
|
---|
242 | case VerticalAlignment.Top:
|
---|
243 | break;
|
---|
244 | default:
|
---|
245 | break;
|
---|
246 | }
|
---|
247 |
|
---|
248 | bounds = new Rect(screenX, screenY, screenWidth, screenHeight);
|
---|
249 | }
|
---|
250 |
|
---|
251 | // applying screen offset
|
---|
252 | double screenOffsetX = GetScreenOffsetX(child);
|
---|
253 | if (screenOffsetX.IsNaN()) screenOffsetX = 0;
|
---|
254 | double screenOffsetY = GetScreenOffsetY(child);
|
---|
255 | if (screenOffsetY.IsNaN()) screenOffsetY = 0;
|
---|
256 |
|
---|
257 | Vector screenOffset = new Vector(screenOffsetX, screenOffsetY);
|
---|
258 | bounds.Offset(screenOffset);
|
---|
259 |
|
---|
260 | return bounds;
|
---|
261 | }
|
---|
262 |
|
---|
263 | protected override Size ArrangeOverride(Size finalSize)
|
---|
264 | {
|
---|
265 | var transform = GetTransform(finalSize);
|
---|
266 |
|
---|
267 | foreach (UIElement child in InternalChildren)
|
---|
268 | {
|
---|
269 | if (child != null)
|
---|
270 | {
|
---|
271 | Rect bounds = GetElementScreenBounds(transform, child);
|
---|
272 | if (!bounds.IsNaN())
|
---|
273 | {
|
---|
274 | child.Arrange(bounds);
|
---|
275 | }
|
---|
276 | }
|
---|
277 | }
|
---|
278 |
|
---|
279 | return finalSize;
|
---|
280 | }
|
---|
281 |
|
---|
282 | private CoordinateTransform GetTransform(Size size)
|
---|
283 | {
|
---|
284 | return viewport.Transform.WithRects(ViewportPanel.GetViewportBounds(this), new Rect(size));
|
---|
285 | }
|
---|
286 |
|
---|
287 | #endregion
|
---|
288 |
|
---|
289 | private Viewport2D viewport;
|
---|
290 | }
|
---|
291 | }
|
---|