using System; using System.Drawing; using System.Drawing.Drawing2D; namespace System.Windows.Forms { internal class MdiChildContext { private static Color titlebar_color; private int BorderWidth = 3; private int TitleBarHeight = 25; private Size MinTitleBarSize = new Size (115, 25); private Form form; private MdiClient mdi_container; private Button close_button; private Button maximize_button; private Button minimize_button; // moving windows private Point start; private State state; private FormPos sizing_edge; private Rectangle virtual_position; private Rectangle prev_virtual_position; private Rectangle prev_bounds; private bool maximized; private enum State { Idle, Moving, Sizing, } [Flags] private enum FormPos { None, TitleBar = 1, Top = 2, Left = 4, Right = 8, Bottom = 16, TopLeft = Top | Left, TopRight = Top | Right, BottomLeft = Bottom | Left, BottomRight = Bottom | Right, AnyEdge = Top | Left | Right | Bottom, } public MdiChildContext (Form form, MdiClient mdi_container) { titlebar_color = Color.FromArgb (255, 0, 0, 255); this.form = form; this.mdi_container = mdi_container; form.Paint += new PaintEventHandler (PaintWindowDecorations); minimize_button = new Button (); minimize_button.Bounds = new Rectangle (form.Width - 62, BorderWidth + 2, 18, 22); minimize_button.Anchor = AnchorStyles.Top | AnchorStyles.Right; minimize_button.Paint += new PaintEventHandler (PaintButtonHandler); minimize_button.Click += new EventHandler (OnMinimizeHandler); maximize_button = new Button (); maximize_button.Bounds = new Rectangle (form.Width - 44, BorderWidth + 2, 18, 22); maximize_button.Anchor = AnchorStyles.Top | AnchorStyles.Right; maximize_button.Paint += new PaintEventHandler (PaintButtonHandler); maximize_button.Click += new EventHandler (OnMaximizeHandler); close_button = new Button (); close_button.Bounds = new Rectangle (form.Width - 24, BorderWidth + 2, 18, 22); close_button.Anchor = AnchorStyles.Top | AnchorStyles.Right; close_button.Paint += new PaintEventHandler (PaintButtonHandler); close_button.Click += new EventHandler (CloseButtonClicked); form.Controls.AddImplicit (close_button); form.Controls.AddImplicit (maximize_button); form.Controls.AddImplicit (minimize_button); } public bool HandleMessage (ref Message m) { switch ((Msg)m.Msg) { case Msg.WM_LBUTTONDOWN: return HandleLButtonDown (form, ref m); case Msg.WM_MOUSEMOVE: return HandleMouseMove (form, ref m); case Msg.WM_LBUTTONUP: HandleLButtonUp (ref m); break; } return false; } private bool HandleLButtonDown (Form form, ref Message m) { form.BringToFront (); mdi_container.ActiveMdiChild = form; int x = Control.LowOrder ((int) m.LParam.ToInt32 ()); int y = Control.HighOrder ((int) m.LParam.ToInt32 ()); FormPos pos = FormPosForCoords (x, y); start = new Point (x, y); virtual_position = form.Bounds; if (pos == FormPos.TitleBar) { HandleTitleBarDown (x, y); return true; } if (IsSizable) { SetCursorForPos (pos); if ((pos & FormPos.AnyEdge) == 0) return false; state = State.Sizing; sizing_edge = pos; form.Capture = true; return true; } return false; } private void HandleTitleBarDown (int x, int y) { state = State.Moving; form.Capture = true; } private bool HandleMouseMove (Form form, ref Message m) { switch (state) { case State.Moving: HandleWindowMove (m); return true; case State.Sizing: HandleSizing (m); return true; } if (IsSizable) { int x = Control.LowOrder ((int) m.LParam.ToInt32 ()); int y = Control.HighOrder ((int) m.LParam.ToInt32 ()); FormPos pos = FormPosForCoords (x, y); SetCursorForPos (pos); ClearVirtualPosition (); state = State.Idle; } return false; } private void SetCursorForPos (FormPos pos) { switch (pos) { case FormPos.TopLeft: case FormPos.BottomRight: form.Cursor = Cursors.SizeNWSE; break; case FormPos.TopRight: case FormPos.BottomLeft: form.Cursor = Cursors.SizeNESW; break; case FormPos.Top: case FormPos.Bottom: form.Cursor = Cursors.SizeNS; break; case FormPos.Left: case FormPos.Right: form.Cursor = Cursors.SizeWE; break; default: form.Cursor = Cursors.Default; break; } } private void HandleWindowMove (Message m) { Point move = MouseMove (m); virtual_position.X = form.Left + move.X; virtual_position.Y = form.Top + move.Y; virtual_position.Width = form.Width; virtual_position.Height = form.Height; DrawVirtualPosition (); } private void HandleSizing (Message m) { Point move = MouseMove (m); Rectangle pos = virtual_position; int mw = MinTitleBarSize.Width + (BorderWidth * 2); int mh = MinTitleBarSize.Height + (BorderWidth * 2); if ((sizing_edge & FormPos.Top) != 0) { int height = form.Height - move.Y; if (height <= mh) { move.Y += height - mh; height = mh; } pos.Y = form.Top + move.Y; pos.Height = height; } else if ((sizing_edge & FormPos.Bottom) != 0) { int height = form.Height + move.Y; if (height <= mh) move.Y -= height - mh; pos.Height = form.Height + move.Y; } if ((sizing_edge & FormPos.Left) != 0) { int width = form.Width - move.X; if (width <= mw) { move.X += width - mw; width = mw; } pos.X = form.Left + move.X; pos.Width = width; } else if ((sizing_edge & FormPos.Right) != 0) { int width = form.Width + move.X; if (width <= mw) move.X -= width - mw; pos.Width = form.Width + move.X; } UpdateVP (pos); } private bool IsSizable { get { switch (form.FormBorderStyle) { case FormBorderStyle.Sizable: case FormBorderStyle.SizableToolWindow: return true; default: return false; } } } private void UpdateVP (Rectangle r) { UpdateVP (r.X, r.Y, r.Width, r.Height); } private void UpdateVP (Point loc, int w, int h) { UpdateVP (loc.X, loc.Y, w, h); } private void UpdateVP (int x, int y, int w, int h) { virtual_position.X = x; virtual_position.Y = y; virtual_position.Width = w; virtual_position.Height = h; DrawVirtualPosition (); } private void HandleLButtonUp (ref Message m) { if (state == State.Idle) return; ClearVirtualPosition (); form.Capture = false; form.Bounds = virtual_position; state = State.Idle; } private void PaintWindowDecorations (object sender, PaintEventArgs pe) { Color color = titlebar_color; if (maximized) color = ThemeEngine.Current.ColorControl; Rectangle tb = new Rectangle (BorderWidth, BorderWidth, form.Width - BorderWidth, TitleBarHeight); pe.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (color), BorderWidth, BorderWidth, form.Width - BorderWidth, TitleBarHeight); tb.X += 18; // Room for the icon if (form.Text != null) { StringFormat format = new StringFormat (); format.LineAlignment = StringAlignment.Center; pe.Graphics.DrawString (form.Text, form.Font, ThemeEngine.Current.ResPool.GetSolidBrush (form.ForeColor), tb, format); } if (form.Icon != null) { pe.Graphics.DrawIcon (form.Icon, new Rectangle (BorderWidth + 2, BorderWidth + 2, 16, 16)); } } private void PaintButtonHandler (object sender, PaintEventArgs pe) { if (sender == close_button) { ControlPaint.DrawCaptionButton (pe.Graphics, close_button.ClientRectangle, CaptionButton.Close, close_button.ButtonState); } else if (sender == maximize_button) { ControlPaint.DrawCaptionButton (pe.Graphics, maximize_button.ClientRectangle, CaptionButton.Maximize, maximize_button.ButtonState); } else if (sender == minimize_button) { ControlPaint.DrawCaptionButton (pe.Graphics, minimize_button.ClientRectangle, CaptionButton.Minimize, minimize_button.ButtonState); } } private void CloseButtonClicked (object sender, EventArgs e) { form.Close (); // form.Close should set visibility to false somewhere // in it's closing chain but currently does not. form.Visible = false; } private void OnMinimizeHandler (object sender, EventArgs e) { form.SuspendLayout (); form.Width = MinTitleBarSize.Width + (BorderWidth * 2); form.Height = MinTitleBarSize.Height + (BorderWidth * 2); form.ResumeLayout (); } private void OnMaximizeHandler (object sender, EventArgs e) { if (maximized) { form.Bounds = prev_bounds; maximized = false; } else { prev_bounds = form.Bounds; form.Bounds = form.Parent.Bounds; maximized = true; } } private Point NewLocation (Message m) { int x = Control.LowOrder ((int) m.LParam.ToInt32 ()); int y = Control.HighOrder ((int) m.LParam.ToInt32 ()); int x_move = x - start.X; int y_move = y - start.Y; return new Point (form.Left + x_move, form.Top + y_move); } private Point MouseMove (Message m) { int x = Control.LowOrder ((int) m.LParam.ToInt32 ()); int y = Control.HighOrder ((int) m.LParam.ToInt32 ()); int x_move = x - start.X; int y_move = y - start.Y; return new Point (x_move, y_move); } private void DrawVirtualPosition () { ClearVirtualPosition (); XplatUI.DrawReversibleRectangle (mdi_container.Handle, virtual_position, 2); prev_virtual_position = virtual_position; } private void ClearVirtualPosition () { if (prev_virtual_position != Rectangle.Empty) XplatUI.DrawReversibleRectangle (mdi_container.Handle, prev_virtual_position, 2); prev_virtual_position = Rectangle.Empty; } private FormPos FormPosForCoords (int x, int y) { if (y < TitleBarHeight + BorderWidth) { if (y > BorderWidth && x > BorderWidth && x < form.Width - BorderWidth) return FormPos.TitleBar; if (x < BorderWidth || (x < 20 && y < BorderWidth)) return FormPos.TopLeft; if (x > form.Width - BorderWidth || (x > form.Width - 20 && y < BorderWidth)) return FormPos.TopRight; if (y < BorderWidth) return FormPos.Top; } else if (y > form.Height - 20) { if (x < BorderWidth || (x < 20 && y > form.Height - BorderWidth)) return FormPos.BottomLeft; if (x > form.Width - BorderWidth || (x > form.Width - 20 && y > form.Height - BorderWidth)) return FormPos.BottomRight; if (y > form.Height - BorderWidth) return FormPos.Bottom; } else if (x < BorderWidth) { return FormPos.Left; } else if (x > form.Width - BorderWidth) { return FormPos.Right; } return FormPos.None; } } }