context: //
  // 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)) {
  
gt: 				bounds.Height += deltaBounds.Height;