// // System.Windows.Forms.Design.SelectionFrame // // Authors: // Ivan N. Zlatev (contact i-nZ.net) // // (C) 2006-2007 Ivan N. Zlatev // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace System.Windows.Forms.Design { // This is not a control! // internal class SelectionFrame { public SelectionFrame (Control control) { if (control == null) throw new ArgumentNullException ("control"); _control = control; } private Rectangle _bounds; private Control _control; private Rectangle[] _handles = new Rectangle[8]; private GrabHandle _handle = GrabHandle.None; private const int BORDER_SIZE = 7; #region Properties private enum GrabHandle { None = -1, TopLeft = 0, TopMiddle, TopRight, Right, BottomRight, BottomMiddle, BottomLeft, Left, Border // the border surrounding the control. } public Rectangle Bounds { get { _bounds.X = _control.Location.X - BORDER_SIZE; _bounds.Y = _control.Location.Y - BORDER_SIZE; _bounds.Width = _control.Width + BORDER_SIZE *2; _bounds.Height = _control.Height + BORDER_SIZE *2; return _bounds; } set { _bounds = value; _control.Bounds = _bounds; } } private SelectionRules SelectionRules { get { SelectionRules result = SelectionRules.AllSizeable; if (_control.Site != null) { IDesignerHost host = _control.Site.GetService (typeof (IDesignerHost)) as IDesignerHost; if (host != null) { ControlDesigner designer = host.GetDesigner (_control) as ControlDesigner; if (designer != null) result = designer.SelectionRules; } } return result; } } public Control Control { get { return _control; } set { if (value != null) _control = value; } } public Control Parent { get { if (_control.Parent == null) return _control; else return _control.Parent; } } private GrabHandle GrabHandleSelected { get { return _handle; } set { _handle = value; } } private bool PrimarySelection{ get { bool result = false; if (this.Control != null && this.Control.Site != null) { ISelectionService selection = this.Control.Site.GetService (typeof (ISelectionService)) as ISelectionService; if (selection != null && selection.PrimarySelection == this.Control) result = true; } return result; } } #endregion #region Drawing public void OnPaint (Graphics gfx) { DrawFrame (gfx); DrawGrabHandles (gfx); } private void DrawGrabHandles (Graphics gfx) { GraphicsState state = gfx.Save(); gfx.TranslateTransform (this.Bounds.X, this.Bounds.Y); for (int i = 0; i < _handles.Length; i++) { _handles[i].Width = BORDER_SIZE; _handles[i].Height = BORDER_SIZE; } SelectionRules rules = this.SelectionRules; bool primarySelection = this.PrimarySelection; bool enabled = false; _handles[(int) GrabHandle.TopLeft].Location = new Point (0,0); if (this.CheckSelectionRules (rules, SelectionRules.TopSizeable | SelectionRules.LeftSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.TopLeft], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.TopMiddle].Location = new Point ((this.Bounds.Width - BORDER_SIZE) / 2, 0); if (this.CheckSelectionRules (rules, SelectionRules.TopSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.TopMiddle], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.TopRight].Location = new Point (this.Bounds.Width - BORDER_SIZE, 0); if (this.CheckSelectionRules (rules, SelectionRules.TopSizeable | SelectionRules.RightSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.TopRight], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.Right].Location = new Point (this.Bounds.Width - BORDER_SIZE, (this.Bounds.Height - BORDER_SIZE) / 2); if (this.CheckSelectionRules (rules, SelectionRules.RightSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.Right], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.BottomRight].Location = new Point (this.Bounds.Width - BORDER_SIZE, this.Bounds.Height - BORDER_SIZE); if (this.CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.RightSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.BottomRight], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.BottomMiddle].Location = new Point ((this.Bounds.Width - BORDER_SIZE) / 2, this.Bounds.Height - BORDER_SIZE); if (this.CheckSelectionRules (rules, SelectionRules.BottomSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.BottomMiddle], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.BottomLeft].Location = new Point (0, this.Bounds.Height - BORDER_SIZE); if (this.CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.LeftSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.BottomLeft], primarySelection, enabled); enabled = false; _handles[(int) GrabHandle.Left].Location = new Point (0, (this.Bounds.Height - BORDER_SIZE) / 2); if (this.CheckSelectionRules (rules, SelectionRules.LeftSizeable)) enabled = true; ControlPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.Left], primarySelection, enabled); gfx.Restore (state); } protected void DrawFrame (Graphics gfx) { Color negativeColor = Color.FromArgb ((byte)~(_control.Parent.BackColor.R), (byte)~(_control.Parent.BackColor.G), (byte)~(_control.Parent.BackColor.B)); Pen pen = new Pen (new HatchBrush (HatchStyle.Percent30, negativeColor, Color.FromArgb (0)), BORDER_SIZE); gfx.DrawRectangle (pen, this.Control.Bounds); } #endregion #region Dragging private bool _resizing = false; public bool SetCursor (int x, int y) { bool modified = false; if (!_resizing) { GrabHandle handle = PointToGrabHandle (this.PointToClient (Control.MousePosition)); if (handle != GrabHandle.None) modified = true; if (handle == GrabHandle.TopLeft) Cursor.Current = Cursors.SizeNWSE; else if (handle == GrabHandle.TopMiddle) Cursor.Current = Cursors.SizeNS; else if (handle == GrabHandle.TopRight) Cursor.Current = Cursors.SizeNESW; else if (handle == GrabHandle.Right) Cursor.Current = Cursors.SizeWE; else if (handle == GrabHandle.BottomRight) Cursor.Current = Cursors.SizeNWSE; else if (handle == GrabHandle.BottomMiddle) Cursor.Current = Cursors.SizeNS; else if (handle == GrabHandle.BottomLeft) Cursor.Current = Cursors.SizeNESW; else if (handle == GrabHandle.Left) Cursor.Current = Cursors.SizeWE; else Cursor.Current = Cursors.Default; } return modified; } // container coordinates public void ResizeBegin (int x, int y) { this.GrabHandleSelected = PointToGrabHandle (this.PointToClient (this.Parent.PointToScreen (new Point (x, y)))); if (this.GrabHandleSelected != GrabHandle.None) _resizing = true; } private bool CheckSelectionRules (SelectionRules rules, SelectionRules toCheck) { return ((rules & toCheck) == toCheck); } // container coordinates returns deltaBounds public Rectangle ResizeContinue (int x, int y) { //Console.WriteLine ("ResizeContinue: " + x + " : " + y); //Console.WriteLine ("GrabHandleSelected: " + GrabHandleSelected); Rectangle bounds = (Rectangle)TypeDescriptor.GetProperties (_control)["Bounds"].GetValue (_control); Rectangle deltaBounds = bounds; Point pointerLocation = new Point (x, y); SelectionRules rules = this.SelectionRules; int top, height, left, width = 0; if (_resizing && this.GrabHandleSelected != GrabHandle.None && rules != SelectionRules.Locked) { if (this.GrabHandleSelected == GrabHandle.TopLeft && CheckSelectionRules (rules, SelectionRules.LeftSizeable | SelectionRules.TopSizeable)) { top = _control.Top; height = _control.Height; left = _control.Left; width = _control.Width; if (pointerLocation.Y < _control.Bottom) { top = pointerLocation.Y; height = _control.Bottom - pointerLocation.Y; } if (pointerLocation.X < _control.Right) { left = pointerLocation.X; width = _control.Right - pointerLocation.X; bounds = new Rectangle (left, top, width, height); } } else if (this.GrabHandleSelected == GrabHandle.TopRight && CheckSelectionRules (rules, SelectionRules.TopSizeable | SelectionRules.RightSizeable)) { top = _control.Top; height = _control.Height; width = _control.Width; if (pointerLocation.Y < _control.Bottom) { top = pointerLocation.Y; height = _control.Bottom - pointerLocation.Y; } width = pointerLocation.X - _control.Left; bounds = new Rectangle (_control.Left, top, width, height); } else if (GrabHandleSelected == GrabHandle.TopMiddle && CheckSelectionRules (rules, SelectionRules.TopSizeable)) { if (pointerLocation.Y < _control.Bottom) { top = pointerLocation.Y; height = _control.Bottom - pointerLocation.Y; bounds = new Rectangle (_control.Left, top, _control.Width, height); } } else if (this.GrabHandleSelected == GrabHandle.Right && CheckSelectionRules (rules, SelectionRules.RightSizeable)) { width = pointerLocation.X - _control.Left; bounds = new Rectangle (_control.Left, _control.Top, width, _control.Height); } else if (this.GrabHandleSelected == GrabHandle.BottomRight && CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.RightSizeable)) { width = pointerLocation.X - _control.Left; height = pointerLocation.Y - _control.Top; bounds = new Rectangle (_control.Left, _control.Top, width, height); } else if (GrabHandleSelected == GrabHandle.BottomMiddle && CheckSelectionRules (rules, SelectionRules.BottomSizeable)) { height = pointerLocation.Y - _control.Top; bounds = new Rectangle (_control.Left, _control.Top, _control.Width, height); } else if (GrabHandleSelected == GrabHandle.BottomLeft && CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.LeftSizeable)) { height = _control.Height; left = _control.Left; width = _control.Width; if (pointerLocation.X < _control.Right) { left = pointerLocation.X; width = _control.Right - pointerLocation.X; } height = pointerLocation.Y - _control.Top; bounds = new Rectangle (left, _control.Top, width, height); } else if (GrabHandleSelected == GrabHandle.Left && CheckSelectionRules (rules, SelectionRules.LeftSizeable)) { if (pointerLocation.X < _control.Right) { left = pointerLocation.X; width = _control.Right - pointerLocation.X; bounds = new Rectangle (left, _control.Top, width, _control.Height); } } //Console.WriteLine ("bounds: " + bounds.ToString ()); TypeDescriptor.GetProperties (_control)["Bounds"].SetValue (_control, bounds); } this.Parent.Refresh (); deltaBounds.X = bounds.X - deltaBounds.X; deltaBounds.Y = bounds.Y - deltaBounds.Y; deltaBounds.Height = bounds.Height - deltaBounds.Height; deltaBounds.Width = bounds.Width - deltaBounds.Width; return deltaBounds; } public void ResizeEnd (bool cancel) { this.GrabHandleSelected = GrabHandle.None; _resizing = false; } public void Resize (Rectangle deltaBounds) { SelectionRules rules = this.SelectionRules; if (this.CheckSelectionRules (rules, SelectionRules.Locked) || !this.CheckSelectionRules (rules, SelectionRules.Moveable)) return; Rectangle bounds = (Rectangle)TypeDescriptor.GetProperties (_control)["Bounds"].GetValue (_control); if (CheckSelectionRules (rules, SelectionRules.LeftSizeable)) { bounds.X += deltaBounds.X; bounds.Width += deltaBounds.Width; } if (CheckSelectionRules (rules, SelectionRules.RightSizeable) && !CheckSelectionRules (rules, SelectionRules.LeftSizeable)) { bounds.Y += deltaBounds.Y; bounds.Width += deltaBounds.Width; } if (CheckSelectionRules (rules, SelectionRules.TopSizeable)) { bounds.Y += deltaBounds.Y; bounds.Height += deltaBounds.Height; } if (CheckSelectionRules (rules, SelectionRules.BottomSizeable) && !CheckSelectionRules (rules, SelectionRules.TopSizeable)) { bounds.Height += deltaBounds.Height; } TypeDescriptor.GetProperties (_control)["Bounds"].SetValue (_control, bounds); } #endregion #region Utility methods public bool HitTest (int x, int y) { if (PointToGrabHandle (this.PointToClient (this.Parent.PointToScreen (new Point (x, y)))) != GrabHandle.None) return true; else return false; } private GrabHandle PointToGrabHandle (Point pointerLocation) { GrabHandle result = GrabHandle.None; if (IsCursorOnGrabHandle (pointerLocation, _handles[0])) result = GrabHandle.TopLeft; else if (IsCursorOnGrabHandle (pointerLocation, _handles[1])) result = GrabHandle.TopMiddle; else if (IsCursorOnGrabHandle (pointerLocation, _handles[2])) result = GrabHandle.TopRight; else if (IsCursorOnGrabHandle (pointerLocation, _handles[3])) result = GrabHandle.Right; else if (IsCursorOnGrabHandle (pointerLocation, _handles[4])) result = GrabHandle.BottomRight; else if (IsCursorOnGrabHandle (pointerLocation, _handles[5])) result = GrabHandle.BottomMiddle; else if (IsCursorOnGrabHandle (pointerLocation, _handles[6])) result = GrabHandle.BottomLeft; else if (IsCursorOnGrabHandle (pointerLocation, _handles[7])) result = GrabHandle.Left; else result = GrabHandle.None; return result; } private bool IsCursorOnGrabHandle (Point pointerLocation, Rectangle handleRectangle) { if (pointerLocation.X >= handleRectangle.X && pointerLocation.X <= handleRectangle.X + handleRectangle.Width && pointerLocation.Y >= handleRectangle.Y && pointerLocation.Y <= handleRectangle.Y + handleRectangle.Height) { return true; } return false; } private Point PointToClient (Point screenPoint) { Point pointerLocation = this.Parent.PointToClient (screenPoint); pointerLocation.X = pointerLocation.X - this.Bounds.X; pointerLocation.Y = pointerLocation.Y - this.Bounds.Y; return pointerLocation; } #endregion } }