Mercurial > silverbladetech
comparison SilverlightGlimpse/SilverFlow.Controls/Controllers/SnapinController.cs @ 63:536498832a79
Latest version before changing bindings to Listbox
author | Steven Hollidge <stevenhollidge@hotmail.com> |
---|---|
date | Sun, 22 Apr 2012 13:33:42 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
62:810116cd6b8e | 63:536498832a79 |
---|---|
1 using System.Collections.Generic; | |
2 using System.Windows; | |
3 using SilverFlow.Controls.Extensions; | |
4 using SilverFlow.Geometry; | |
5 | |
6 namespace SilverFlow.Controls.Controllers | |
7 { | |
8 /// <summary> | |
9 /// Provides helpers methods for calculating window position | |
10 /// during movement and resizing. | |
11 /// </summary> | |
12 public class SnapinController : ISnapinController | |
13 { | |
14 /// <summary> | |
15 /// Distance on which snapping works. | |
16 /// </summary> | |
17 private const double SnapinDistanceDefaultValue = 5; | |
18 | |
19 /// <summary> | |
20 /// Gets or sets a value indicating whether snap in is enabled. | |
21 /// </summary> | |
22 /// <value><c>true</c> if snap in is enabled; otherwise, <c>false</c>.</value> | |
23 public bool SnapinEnabled { get; set; } | |
24 | |
25 /// <summary> | |
26 /// Gets or sets snap in bounds. | |
27 /// </summary> | |
28 /// <value>Snap in bounds.</value> | |
29 public IEnumerable<Rect> SnapinBounds { get; set; } | |
30 | |
31 /// <summary> | |
32 /// Gets or sets snap in distance. | |
33 /// </summary> | |
34 /// <value>Snap in distance.</value> | |
35 public double SnapinDistance { get; set; } | |
36 | |
37 /// <summary> | |
38 /// Gets or sets a value snap in margin - distance between adjacent edges. | |
39 /// </summary> | |
40 /// <value>Snap in margin.</value> | |
41 public double SnapinMargin { get; set; } | |
42 | |
43 /// <summary> | |
44 /// Gets calculations accuracy. | |
45 /// </summary> | |
46 /// <value>Accuracy.</value> | |
47 private double Accuracy | |
48 { | |
49 get { return SnapinDistance + SnapinMargin; } | |
50 } | |
51 | |
52 /// <summary> | |
53 /// Returns new position of the specified rectangle | |
54 /// taking into account bounds the rectangle can be attracted to. | |
55 /// </summary> | |
56 /// <param name="rect">The rectangle.</param> | |
57 /// <returns>New position.</returns> | |
58 public Point SnapRectangle(Rect rect) | |
59 { | |
60 Point point = rect.Position(); | |
61 | |
62 if (SnapinEnabled) | |
63 { | |
64 Distance minDistance = new Distance(); | |
65 foreach (var bound in SnapinBounds) | |
66 { | |
67 Distance distance = DistanceBetweenRectangles(rect, bound); | |
68 minDistance = Distance.Min(distance, minDistance); | |
69 } | |
70 | |
71 point = point.Add(minDistance); | |
72 } | |
73 | |
74 return point; | |
75 } | |
76 | |
77 /// <summary> | |
78 /// Snaps the bottom right corner of the specified rectangle to the nearest bounds. | |
79 /// </summary> | |
80 /// <param name="rect">The rectangle.</param> | |
81 /// <returns>New position.</returns> | |
82 public Point SnapBottomRightCorner(Rect rect) | |
83 { | |
84 Point point = rect.BottomRight(); | |
85 | |
86 if (SnapinEnabled) | |
87 { | |
88 Distance minDistance = new Distance(); | |
89 foreach (var bound in SnapinBounds) | |
90 { | |
91 Distance distance = new Distance() | |
92 { | |
93 X = DistanceBetweenRightEdgeAndRectangle(rect, bound), | |
94 Y = DistanceBetweenBottomEdgeAndRectangle(rect, bound) | |
95 }; | |
96 | |
97 minDistance = Distance.Min(distance, minDistance); | |
98 } | |
99 | |
100 point = point.Add(minDistance); | |
101 } | |
102 | |
103 return point; | |
104 } | |
105 | |
106 /// <summary> | |
107 /// Snaps the upper left corner of the specified rectangle to the nearest bounds. | |
108 /// </summary> | |
109 /// <param name="rect">The rectangle.</param> | |
110 /// <returns>New position.</returns> | |
111 public Point SnapTopLeftCorner(Rect rect) | |
112 { | |
113 Point point = rect.Position(); | |
114 | |
115 if (SnapinEnabled) | |
116 { | |
117 Distance minDistance = new Distance(); | |
118 foreach (var bound in SnapinBounds) | |
119 { | |
120 Distance distance = new Distance() | |
121 { | |
122 X = DistanceBetweenLeftEdgeAndRectangle(rect, bound), | |
123 Y = DistanceBetweenTopEdgeAndRectangle(rect, bound) | |
124 }; | |
125 | |
126 minDistance = Distance.Min(distance, minDistance); | |
127 } | |
128 | |
129 point = point.Add(minDistance); | |
130 } | |
131 | |
132 return point; | |
133 } | |
134 | |
135 /// <summary> | |
136 /// Snaps the lower left corner of the specified rectangle to the nearest bounds. | |
137 /// </summary> | |
138 /// <param name="rect">The rectangle.</param> | |
139 /// <returns>New position.</returns> | |
140 public Point SnapBottomLeftCorner(Rect rect) | |
141 { | |
142 Point point = rect.BottomLeft(); | |
143 | |
144 if (SnapinEnabled) | |
145 { | |
146 Distance minDistance = new Distance(); | |
147 foreach (var bound in SnapinBounds) | |
148 { | |
149 Distance distance = new Distance() | |
150 { | |
151 X = DistanceBetweenLeftEdgeAndRectangle(rect, bound), | |
152 Y = DistanceBetweenBottomEdgeAndRectangle(rect, bound) | |
153 }; | |
154 | |
155 minDistance = Distance.Min(distance, minDistance); | |
156 } | |
157 | |
158 point = point.Add(minDistance); | |
159 } | |
160 | |
161 return point; | |
162 } | |
163 | |
164 /// <summary> | |
165 /// Snaps the upper right corner of the specified rectangle to the nearest bounds. | |
166 /// </summary> | |
167 /// <param name="rect">The rectangle.</param> | |
168 /// <returns>New position.</returns> | |
169 public Point SnapTopRightCorner(Rect rect) | |
170 { | |
171 Point point = rect.TopRight(); | |
172 | |
173 if (SnapinEnabled) | |
174 { | |
175 Distance minDistance = new Distance(); | |
176 foreach (var bound in SnapinBounds) | |
177 { | |
178 Distance distance = new Distance() | |
179 { | |
180 X = DistanceBetweenRightEdgeAndRectangle(rect, bound), | |
181 Y = DistanceBetweenTopEdgeAndRectangle(rect, bound) | |
182 }; | |
183 | |
184 minDistance = Distance.Min(distance, minDistance); | |
185 } | |
186 | |
187 point = point.Add(minDistance); | |
188 } | |
189 | |
190 return point; | |
191 } | |
192 | |
193 /// <summary> | |
194 /// Returns mininal distance between two rectangles. | |
195 /// </summary> | |
196 /// <param name="first">First rectangle.</param> | |
197 /// <param name="second">Second rectangle.</param> | |
198 /// <returns>Minimal distance.</returns> | |
199 private Distance DistanceBetweenRectangles(Rect first, Rect second) | |
200 { | |
201 double x1 = DistanceBetweenRightEdgeAndRectangle(first, second); | |
202 double x2 = DistanceBetweenLeftEdgeAndRectangle(first, second); | |
203 double y1 = DistanceBetweenBottomEdgeAndRectangle(first, second); | |
204 double y2 = DistanceBetweenTopEdgeAndRectangle(first, second); | |
205 | |
206 Distance distance = new Distance() | |
207 { | |
208 X = MathExtensions.AbsMin(x1, x2), | |
209 Y = MathExtensions.AbsMin(y1, y2) | |
210 }; | |
211 | |
212 return distance; | |
213 } | |
214 | |
215 /// <summary> | |
216 /// Returns distance between the right edge of the rectangle and another rectangle. | |
217 /// </summary> | |
218 /// <param name="first">First rectangle.</param> | |
219 /// <param name="second">Second rectangle.</param> | |
220 /// <returns>Minimal distance.</returns> | |
221 private double DistanceBetweenRightEdgeAndRectangle(Rect first, Rect second) | |
222 { | |
223 double snap; | |
224 double distance = double.NaN; | |
225 double x = first.X + first.Width - 1; | |
226 | |
227 if (first.OverlapsVertically(second, Accuracy)) | |
228 { | |
229 snap = second.X - 1 - SnapinMargin; | |
230 if (x.IsNear(snap, SnapinDistance)) | |
231 { | |
232 distance = MathExtensions.AbsMin(snap - x, distance); | |
233 } | |
234 | |
235 snap = second.X + second.Width - 1; | |
236 if (x.IsNear(snap, SnapinDistance)) | |
237 { | |
238 distance = MathExtensions.AbsMin(snap - x, distance); | |
239 } | |
240 } | |
241 | |
242 return distance; | |
243 } | |
244 | |
245 /// <summary> | |
246 /// Returns distance between the left edge of the rectangle and another rectangle. | |
247 /// </summary> | |
248 /// <param name="first">First rectangle.</param> | |
249 /// <param name="second">Second rectangle.</param> | |
250 /// <returns>Minimal distance.</returns> | |
251 private double DistanceBetweenLeftEdgeAndRectangle(Rect first, Rect second) | |
252 { | |
253 double snap; | |
254 double distance = double.NaN; | |
255 | |
256 if (first.OverlapsVertically(second, Accuracy)) | |
257 { | |
258 snap = second.X; | |
259 if (first.X.IsNear(snap, SnapinDistance)) | |
260 { | |
261 distance = MathExtensions.AbsMin(snap - first.X, distance); | |
262 } | |
263 | |
264 snap = second.X + second.Width + SnapinMargin; | |
265 if (first.X.IsNear(snap, SnapinDistance)) | |
266 { | |
267 distance = MathExtensions.AbsMin(snap - first.X, distance); | |
268 } | |
269 } | |
270 | |
271 return distance; | |
272 } | |
273 | |
274 /// <summary> | |
275 /// Returns distance between the bottom edge of the rectangle and another rectangle. | |
276 /// </summary> | |
277 /// <param name="first">First rectangle.</param> | |
278 /// <param name="second">Second rectangle.</param> | |
279 /// <returns>Minimal distance.</returns> | |
280 private double DistanceBetweenBottomEdgeAndRectangle(Rect first, Rect second) | |
281 { | |
282 double snap; | |
283 double distance = double.NaN; | |
284 double y = first.Y + first.Height - 1; | |
285 | |
286 if (first.OverlapsHorizontally(second, Accuracy)) | |
287 { | |
288 snap = second.Y - 1 - SnapinMargin; | |
289 if (y.IsNear(snap, SnapinDistance)) | |
290 { | |
291 distance = MathExtensions.AbsMin(snap - y, distance); | |
292 } | |
293 | |
294 snap = second.Y + second.Height - 1; | |
295 if (y.IsNear(snap, SnapinDistance)) | |
296 { | |
297 distance = MathExtensions.AbsMin(snap - y, distance); | |
298 } | |
299 } | |
300 | |
301 return distance; | |
302 } | |
303 | |
304 /// <summary> | |
305 /// Returns distance between the top edge of the rectangle and another rectangle. | |
306 /// </summary> | |
307 /// <param name="first">First rectangle.</param> | |
308 /// <param name="second">Second rectangle.</param> | |
309 /// <returns>Minimal distance.</returns> | |
310 private double DistanceBetweenTopEdgeAndRectangle(Rect first, Rect second) | |
311 { | |
312 double snap; | |
313 double distance = double.NaN; | |
314 | |
315 if (first.OverlapsHorizontally(second, Accuracy)) | |
316 { | |
317 snap = second.Y; | |
318 if (first.Y.IsNear(snap, SnapinDistance)) | |
319 { | |
320 distance = MathExtensions.AbsMin(snap - first.Y, distance); | |
321 } | |
322 | |
323 snap = second.Y + second.Height + SnapinMargin; | |
324 if (first.Y.IsNear(snap, SnapinDistance)) | |
325 { | |
326 distance = MathExtensions.AbsMin(snap - first.Y, distance); | |
327 } | |
328 } | |
329 | |
330 return distance; | |
331 } | |
332 } | |
333 } |