2 // System.Windows.Forms.Design.SelectionFrame
5 // Ivan N. Zlatev (contact i-nZ.net)
7 // (C) 2006-2007 Ivan N. Zlatev
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.Collections
;
32 using System
.ComponentModel
;
33 using System
.ComponentModel
.Design
;
35 using System
.Drawing
.Drawing2D
;
36 using System
.Windows
.Forms
;
39 namespace System
.Windows
.Forms
.Design
41 // This is not a control!
43 internal class SelectionFrame
46 public SelectionFrame (Control control
)
49 throw new ArgumentNullException ("control");
55 private Rectangle _bounds
;
56 private Control _control
;
57 private Rectangle
[] _handles
= new Rectangle
[8];
58 private GrabHandle _handle
= GrabHandle
.None
;
59 private const int BORDER_SIZE
= 7;
63 private enum GrabHandle
{
73 Border
// the border surrounding the control.
76 public Rectangle Bounds
{
78 _bounds
.X
= _control
.Location
.X
- BORDER_SIZE
;
79 _bounds
.Y
= _control
.Location
.Y
- BORDER_SIZE
;
80 _bounds
.Width
= _control
.Width
+ BORDER_SIZE
*2;
81 _bounds
.Height
= _control
.Height
+ BORDER_SIZE
*2;
87 _control
.Bounds
= _bounds
;
91 private SelectionRules SelectionRules
{
93 SelectionRules result
= SelectionRules
.AllSizeable
;
95 if (_control
.Site
!= null) {
96 IDesignerHost host
= _control
.Site
.GetService (typeof (IDesignerHost
)) as IDesignerHost
;
98 ControlDesigner designer
= host
.GetDesigner (_control
) as ControlDesigner
;
100 result
= designer
.SelectionRules
;
108 public Control Control
{
109 get { return _control; }
116 public Control Parent
{
118 if (_control
.Parent
== null)
121 return _control
.Parent
;
125 private GrabHandle GrabHandleSelected
{
126 get { return _handle; }
127 set { _handle = value; }
130 private bool PrimarySelection
{
133 if (this.Control
!= null && this.Control
.Site
!= null) {
134 ISelectionService selection
= this.Control
.Site
.GetService (typeof (ISelectionService
)) as ISelectionService
;
135 if (selection
!= null && selection
.PrimarySelection
== this.Control
)
145 public void OnPaint (Graphics gfx
)
148 DrawGrabHandles (gfx
);
151 private void DrawGrabHandles (Graphics gfx
)
153 GraphicsState state
= gfx
.Save();
154 gfx
.TranslateTransform (this.Bounds
.X
, this.Bounds
.Y
);
156 for (int i
= 0; i
< _handles
.Length
; i
++) {
157 _handles
[i
].Width
= BORDER_SIZE
;
158 _handles
[i
].Height
= BORDER_SIZE
;
161 SelectionRules rules
= this.SelectionRules
;
162 bool primarySelection
= this.PrimarySelection
;
163 bool enabled
= false;
165 _handles
[(int) GrabHandle
.TopLeft
].Location
= new Point (0,0);
166 if (this.CheckSelectionRules (rules
, SelectionRules
.TopSizeable
| SelectionRules
.LeftSizeable
))
169 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.TopLeft
], primarySelection
, enabled
);
172 _handles
[(int) GrabHandle
.TopMiddle
].Location
= new Point ((this.Bounds
.Width
- BORDER_SIZE
) / 2, 0);
173 if (this.CheckSelectionRules (rules
, SelectionRules
.TopSizeable
))
176 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.TopMiddle
], primarySelection
, enabled
);
179 _handles
[(int) GrabHandle
.TopRight
].Location
= new Point (this.Bounds
.Width
- BORDER_SIZE
, 0);
180 if (this.CheckSelectionRules (rules
, SelectionRules
.TopSizeable
| SelectionRules
.RightSizeable
))
183 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.TopRight
], primarySelection
, enabled
);
186 _handles
[(int) GrabHandle
.Right
].Location
= new Point (this.Bounds
.Width
- BORDER_SIZE
,
187 (this.Bounds
.Height
- BORDER_SIZE
) / 2);
188 if (this.CheckSelectionRules (rules
, SelectionRules
.RightSizeable
))
191 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.Right
], primarySelection
, enabled
);
194 _handles
[(int) GrabHandle
.BottomRight
].Location
= new Point (this.Bounds
.Width
- BORDER_SIZE
,
195 this.Bounds
.Height
- BORDER_SIZE
);
196 if (this.CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
| SelectionRules
.RightSizeable
))
199 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.BottomRight
], primarySelection
, enabled
);
202 _handles
[(int) GrabHandle
.BottomMiddle
].Location
= new Point ((this.Bounds
.Width
- BORDER_SIZE
) / 2,
203 this.Bounds
.Height
- BORDER_SIZE
);
204 if (this.CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
))
207 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.BottomMiddle
], primarySelection
, enabled
);
210 _handles
[(int) GrabHandle
.BottomLeft
].Location
= new Point (0, this.Bounds
.Height
- BORDER_SIZE
);
211 if (this.CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
| SelectionRules
.LeftSizeable
))
214 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.BottomLeft
], primarySelection
, enabled
);
217 _handles
[(int) GrabHandle
.Left
].Location
= new Point (0, (this.Bounds
.Height
- BORDER_SIZE
) / 2);
218 if (this.CheckSelectionRules (rules
, SelectionRules
.LeftSizeable
))
221 ControlPaint
.DrawGrabHandle (gfx
, _handles
[(int)GrabHandle
.Left
], primarySelection
, enabled
);
225 protected void DrawFrame (Graphics gfx
)
227 Color negativeColor
= Color
.FromArgb ((byte)~
(_control
.Parent
.BackColor
.R
),
228 (byte)~
(_control
.Parent
.BackColor
.G
),
229 (byte)~
(_control
.Parent
.BackColor
.B
));
230 Pen pen
= new Pen (new HatchBrush (HatchStyle
.Percent30
, negativeColor
, Color
.FromArgb (0)), BORDER_SIZE
);
231 gfx
.DrawRectangle (pen
, this.Control
.Bounds
);
237 private bool _resizing
= false;
240 public bool SetCursor (int x
, int y
)
242 bool modified
= false;
245 GrabHandle handle
= PointToGrabHandle (this.PointToClient (Control
.MousePosition
));
246 if (handle
!= GrabHandle
.None
)
249 if (handle
== GrabHandle
.TopLeft
)
250 Cursor
.Current
= Cursors
.SizeNWSE
;
251 else if (handle
== GrabHandle
.TopMiddle
)
252 Cursor
.Current
= Cursors
.SizeNS
;
253 else if (handle
== GrabHandle
.TopRight
)
254 Cursor
.Current
= Cursors
.SizeNESW
;
255 else if (handle
== GrabHandle
.Right
)
256 Cursor
.Current
= Cursors
.SizeWE
;
257 else if (handle
== GrabHandle
.BottomRight
)
258 Cursor
.Current
= Cursors
.SizeNWSE
;
259 else if (handle
== GrabHandle
.BottomMiddle
)
260 Cursor
.Current
= Cursors
.SizeNS
;
261 else if (handle
== GrabHandle
.BottomLeft
)
262 Cursor
.Current
= Cursors
.SizeNESW
;
263 else if (handle
== GrabHandle
.Left
)
264 Cursor
.Current
= Cursors
.SizeWE
;
266 Cursor
.Current
= Cursors
.Default
;
271 // container coordinates
272 public void ResizeBegin (int x
, int y
)
274 this.GrabHandleSelected
= PointToGrabHandle (this.PointToClient (this.Parent
.PointToScreen (new Point (x
, y
))));
276 if (this.GrabHandleSelected
!= GrabHandle
.None
)
280 private bool CheckSelectionRules (SelectionRules rules
, SelectionRules toCheck
)
282 return ((rules
& toCheck
) == toCheck
);
285 // container coordinates returns deltaBounds
286 public Rectangle
ResizeContinue (int x
, int y
)
288 //Console.WriteLine ("ResizeContinue: " + x + " : " + y);
289 //Console.WriteLine ("GrabHandleSelected: " + GrabHandleSelected);
291 Rectangle bounds
= (Rectangle
)TypeDescriptor
.GetProperties (_control
)["Bounds"].GetValue (_control
);
292 Rectangle deltaBounds
= bounds
;
293 Point pointerLocation
= new Point (x
, y
);
294 SelectionRules rules
= this.SelectionRules
;
295 int top
, height
, left
, width
= 0;
297 if (_resizing
&& this.GrabHandleSelected
!= GrabHandle
.None
&& rules
!= SelectionRules
.Locked
) {
298 if (this.GrabHandleSelected
== GrabHandle
.TopLeft
&&
299 CheckSelectionRules (rules
, SelectionRules
.LeftSizeable
| SelectionRules
.TopSizeable
)) {
302 height
= _control
.Height
;
303 left
= _control
.Left
;
304 width
= _control
.Width
;
306 if (pointerLocation
.Y
< _control
.Bottom
) {
307 top
= pointerLocation
.Y
;
308 height
= _control
.Bottom
- pointerLocation
.Y
;
310 if (pointerLocation
.X
< _control
.Right
) {
311 left
= pointerLocation
.X
;
312 width
= _control
.Right
- pointerLocation
.X
;
313 bounds
= new Rectangle (left
, top
, width
, height
);
316 else if (this.GrabHandleSelected
== GrabHandle
.TopRight
&&
317 CheckSelectionRules (rules
, SelectionRules
.TopSizeable
| SelectionRules
.RightSizeable
)) {
320 height
= _control
.Height
;
321 width
= _control
.Width
;
323 if (pointerLocation
.Y
< _control
.Bottom
) {
324 top
= pointerLocation
.Y
;
325 height
= _control
.Bottom
- pointerLocation
.Y
;
327 width
= pointerLocation
.X
- _control
.Left
;
328 bounds
= new Rectangle (_control
.Left
, top
, width
, height
);
330 else if (GrabHandleSelected
== GrabHandle
.TopMiddle
&& CheckSelectionRules (rules
, SelectionRules
.TopSizeable
)) {
331 if (pointerLocation
.Y
< _control
.Bottom
) {
332 top
= pointerLocation
.Y
;
333 height
= _control
.Bottom
- pointerLocation
.Y
;
334 bounds
= new Rectangle (_control
.Left
, top
, _control
.Width
, height
);
337 else if (this.GrabHandleSelected
== GrabHandle
.Right
&& CheckSelectionRules (rules
, SelectionRules
.RightSizeable
)) {
338 width
= pointerLocation
.X
- _control
.Left
;
339 bounds
= new Rectangle (_control
.Left
, _control
.Top
, width
, _control
.Height
);
341 else if (this.GrabHandleSelected
== GrabHandle
.BottomRight
&&
342 CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
| SelectionRules
.RightSizeable
)) {
344 width
= pointerLocation
.X
- _control
.Left
;
345 height
= pointerLocation
.Y
- _control
.Top
;
346 bounds
= new Rectangle (_control
.Left
, _control
.Top
, width
, height
);
348 else if (GrabHandleSelected
== GrabHandle
.BottomMiddle
&& CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
)) {
349 height
= pointerLocation
.Y
- _control
.Top
;
350 bounds
= new Rectangle (_control
.Left
, _control
.Top
, _control
.Width
, height
);
352 else if (GrabHandleSelected
== GrabHandle
.BottomLeft
&&
353 CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
| SelectionRules
.LeftSizeable
)) {
355 height
= _control
.Height
;
356 left
= _control
.Left
;
357 width
= _control
.Width
;
359 if (pointerLocation
.X
< _control
.Right
) {
360 left
= pointerLocation
.X
;
361 width
= _control
.Right
- pointerLocation
.X
;
363 height
= pointerLocation
.Y
- _control
.Top
;
364 bounds
= new Rectangle (left
, _control
.Top
, width
, height
);
366 else if (GrabHandleSelected
== GrabHandle
.Left
&& CheckSelectionRules (rules
, SelectionRules
.LeftSizeable
)) {
367 if (pointerLocation
.X
< _control
.Right
) {
368 left
= pointerLocation
.X
;
369 width
= _control
.Right
- pointerLocation
.X
;
370 bounds
= new Rectangle (left
, _control
.Top
, width
, _control
.Height
);
374 //Console.WriteLine ("bounds: " + bounds.ToString ());
375 TypeDescriptor
.GetProperties (_control
)["Bounds"].SetValue (_control
, bounds
);
379 this.Parent
.Refresh ();
380 deltaBounds
.X
= bounds
.X
- deltaBounds
.X
;
381 deltaBounds
.Y
= bounds
.Y
- deltaBounds
.Y
;
382 deltaBounds
.Height
= bounds
.Height
- deltaBounds
.Height
;
383 deltaBounds
.Width
= bounds
.Width
- deltaBounds
.Width
;
388 public void ResizeEnd (bool cancel
)
390 this.GrabHandleSelected
= GrabHandle
.None
;
394 public void Resize (Rectangle deltaBounds
)
396 SelectionRules rules
= this.SelectionRules
;
398 if (this.CheckSelectionRules (rules
, SelectionRules
.Locked
) || !this.CheckSelectionRules (rules
, SelectionRules
.Moveable
))
401 Rectangle bounds
= (Rectangle
)TypeDescriptor
.GetProperties (_control
)["Bounds"].GetValue (_control
);
403 if (CheckSelectionRules (rules
, SelectionRules
.LeftSizeable
)) {
404 bounds
.X
+= deltaBounds
.X
;
405 bounds
.Width
+= deltaBounds
.Width
;
407 if (CheckSelectionRules (rules
, SelectionRules
.RightSizeable
) && !CheckSelectionRules (rules
, SelectionRules
.LeftSizeable
)) {
408 bounds
.Y
+= deltaBounds
.Y
;
409 bounds
.Width
+= deltaBounds
.Width
;
411 if (CheckSelectionRules (rules
, SelectionRules
.TopSizeable
)) {
412 bounds
.Y
+= deltaBounds
.Y
;
413 bounds
.Height
+= deltaBounds
.Height
;
415 if (CheckSelectionRules (rules
, SelectionRules
.BottomSizeable
) && !CheckSelectionRules (rules
, SelectionRules
.TopSizeable
)) {
416 bounds
.Height
+= deltaBounds
.Height
;
419 TypeDescriptor
.GetProperties (_control
)["Bounds"].SetValue (_control
, bounds
);
424 #region Utility methods
426 public bool HitTest (int x
, int y
)
428 if (PointToGrabHandle (this.PointToClient (this.Parent
.PointToScreen (new Point (x
, y
)))) != GrabHandle
.None
)
434 private GrabHandle
PointToGrabHandle (Point pointerLocation
)
436 GrabHandle result
= GrabHandle
.None
;
438 if (IsCursorOnGrabHandle (pointerLocation
, _handles
[0]))
439 result
= GrabHandle
.TopLeft
;
440 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[1]))
441 result
= GrabHandle
.TopMiddle
;
442 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[2]))
443 result
= GrabHandle
.TopRight
;
444 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[3]))
445 result
= GrabHandle
.Right
;
446 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[4]))
447 result
= GrabHandle
.BottomRight
;
448 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[5]))
449 result
= GrabHandle
.BottomMiddle
;
450 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[6]))
451 result
= GrabHandle
.BottomLeft
;
452 else if (IsCursorOnGrabHandle (pointerLocation
, _handles
[7]))
453 result
= GrabHandle
.Left
;
455 result
= GrabHandle
.None
;
460 private bool IsCursorOnGrabHandle (Point pointerLocation
, Rectangle handleRectangle
)
462 if (pointerLocation
.X
>= handleRectangle
.X
&&
463 pointerLocation
.X
<= handleRectangle
.X
+ handleRectangle
.Width
&&
464 pointerLocation
.Y
>= handleRectangle
.Y
&&
465 pointerLocation
.Y
<= handleRectangle
.Y
+ handleRectangle
.Height
) {
471 private Point
PointToClient (Point screenPoint
)
473 Point pointerLocation
= this.Parent
.PointToClient (screenPoint
);
474 pointerLocation
.X
= pointerLocation
.X
- this.Bounds
.X
;
475 pointerLocation
.Y
= pointerLocation
.Y
- this.Bounds
.Y
;
476 return pointerLocation
;