2007-03-19 Chris Toshok <toshok@ximian.com>
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MdiWindowManager.cs
blobc991b31f9ddae6ce4fd8e13562366d4f5e2afdae
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
22 // Authors:
23 // Jackson Harper (jackson@ximian.com)
28 using System;
29 using System.Drawing;
30 using System.Drawing.Drawing2D;
31 using System.Runtime.InteropServices;
33 namespace System.Windows.Forms {
35 internal class MdiWindowManager : InternalWindowManager {
37 private MainMenu merged_menu;
38 private MainMenu maximized_menu;
39 private MenuItem icon_menu;
40 private ContextMenu icon_popup_menu;
41 internal bool was_minimized;
43 private PaintEventHandler draw_maximized_buttons;
44 internal EventHandler form_closed_handler;
46 private MdiClient mdi_container;
47 private Rectangle prev_virtual_position;
49 private Point icon_clicked;
50 private DateTime icon_clicked_time;
51 private bool icon_dont_show_popup;
53 private TitleButtons maximized_title_buttons;
54 private bool is_visible_pending;
56 internal bool IsVisiblePending {
57 get {
58 return is_visible_pending;
60 set {
61 is_visible_pending = value;
65 private TitleButtons MaximizedTitleButtons {
66 get {
67 if (maximized_title_buttons == null) {
68 maximized_title_buttons = new TitleButtons (this.Form);
69 maximized_title_buttons.CloseButton.Visible = true;
70 maximized_title_buttons.RestoreButton.Visible = true;
71 maximized_title_buttons.MinimizeButton.Visible = true;
73 return maximized_title_buttons;
77 internal override Rectangle MaximizedBounds {
78 get {
79 Rectangle pb = mdi_container.ClientRectangle;
80 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
81 int tw = TitleBarHeight;
83 Rectangle new_bounds = new Rectangle (pb.Left - bw,
84 pb.Top - tw - bw,
85 pb.Width + bw * 2,
86 pb.Height + tw + bw * 2);
87 return new_bounds;
93 public MdiWindowManager (Form form, MdiClient mdi_container) : base (form)
95 this.mdi_container = mdi_container;
96 if (form.WindowState == FormWindowState.Normal) {
97 NormalBounds = form.Bounds;
99 form_closed_handler = new EventHandler (FormClosed);
100 form.Closed += form_closed_handler;
101 form.TextChanged += new EventHandler (FormTextChangedHandler);
102 form.SizeChanged += new EventHandler (FormSizeChangedHandler);
103 form.LocationChanged += new EventHandler (FormLocationChangedHandler);
104 form.VisibleChanged += new EventHandler (FormVisibleChangedHandler);
105 draw_maximized_buttons = new PaintEventHandler (DrawMaximizedButtons);
106 CreateIconMenus ();
109 private void FormVisibleChangedHandler (object sender, EventArgs e)
111 if (mdi_container == null)
112 return;
114 if (form.Visible) {
115 mdi_container.ActivateChild (form);
116 } else if (mdi_container.Controls.Count > 1) {
117 mdi_container.ActivateActiveMdiChild ();
121 private void FormTextChangedHandler (object sender, EventArgs e)
123 mdi_container.SetParentText (false);
125 #if NET_2_0
126 if (form.MdiParent.MainMenuStrip != null)
127 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
128 #endif
131 private void FormLocationChangedHandler (object sender, EventArgs e)
133 if (form.window_state == FormWindowState.Minimized)
134 IconicBounds = form.Bounds;
135 form.MdiParent.MdiContainer.SizeScrollBars ();
138 private void FormSizeChangedHandler (object sender, EventArgs e)
140 if (form.window_state == FormWindowState.Maximized && form.Bounds != MaximizedBounds)
141 form.Bounds = MaximizedBounds;
143 form.MdiParent.MdiContainer.SizeScrollBars ();
146 public MainMenu MergedMenu {
147 get {
148 if (merged_menu == null)
149 merged_menu = CreateMergedMenu ();
150 return merged_menu;
154 private MainMenu CreateMergedMenu ()
156 Form parent = (Form) mdi_container.Parent;
157 MainMenu clone;
158 if (parent.Menu != null)
159 clone = (MainMenu) parent.Menu.CloneMenu ();
160 else
161 clone = new MainMenu ();
163 if (form.WindowState == FormWindowState.Maximized) {
166 clone.MergeMenu (form.Menu);
167 clone.MenuChanged += new EventHandler (MenuChangedHandler);
168 clone.SetForm (parent);
169 return clone;
172 public MainMenu MaximizedMenu {
173 get {
174 if (maximized_menu == null)
175 maximized_menu = CreateMaximizedMenu ();
176 return maximized_menu;
180 private MainMenu CreateMaximizedMenu ()
182 Form parent = (Form) mdi_container.Parent;
183 MainMenu res = new MainMenu ();
185 if (parent.Menu != null) {
186 MainMenu clone = (MainMenu) parent.Menu.CloneMenu ();
187 res.MergeMenu (clone);
190 if (form.Menu != null) {
191 MainMenu clone = (MainMenu) form.Menu.CloneMenu ();
192 res.MergeMenu (clone);
195 if (res.MenuItems.Count == 0)
196 res.MenuItems.Add (new MenuItem ()); // Dummy item to get the menu height correct
198 res.MenuItems.Insert (0, icon_menu);
200 res.SetForm (parent);
201 return res;
204 private void CreateIconMenus ()
206 icon_menu = new MenuItem ();
207 icon_popup_menu = new ContextMenu ();
209 icon_menu.OwnerDraw = true;
210 icon_menu.MeasureItem += new MeasureItemEventHandler (MeasureIconMenuItem);
211 icon_menu.DrawItem += new DrawItemEventHandler (DrawIconMenuItem);
212 icon_menu.Click += new EventHandler (ClickIconMenuItem);
214 MenuItem restore = new MenuItem ("Restore", new EventHandler (RestoreItemHandler));
215 MenuItem move = new MenuItem ("Move", new EventHandler (MoveItemHandler));
216 MenuItem size = new MenuItem ("Size", new EventHandler (SizeItemHandler));
217 MenuItem minimize = new MenuItem ("Minimize", new EventHandler (MinimizeItemHandler));
218 MenuItem maximize = new MenuItem ("Maximize", new EventHandler (MaximizeItemHandler));
219 MenuItem close = new MenuItem ("Close", new EventHandler (CloseItemHandler));
220 MenuItem next = new MenuItem ("Next", new EventHandler (NextItemHandler));
222 icon_menu.MenuItems.AddRange (new MenuItem [] { restore, move, size, minimize,
223 maximize, close, next });
224 icon_popup_menu.MenuItems.AddRange (new MenuItem [] { restore, move, size, minimize,
225 maximize, close, next });
228 private void ClickIconMenuItem(object sender, EventArgs e)
230 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds < 500) {
231 form.Close ();
232 return;
234 icon_clicked_time = DateTime.Now;
235 Point pnt = Point.Empty;
236 pnt = form.MdiParent.PointToScreen (pnt);
237 pnt = form.PointToClient (pnt);
238 ShowPopup (pnt);
241 private void ShowPopup (Point pnt)
243 icon_popup_menu.MenuItems[0].Enabled = form.window_state != FormWindowState.Normal; // restore
244 icon_popup_menu.MenuItems[1].Enabled = form.window_state != FormWindowState.Maximized; // move
245 icon_popup_menu.MenuItems[2].Enabled = form.window_state != FormWindowState.Maximized; // size
246 icon_popup_menu.MenuItems[3].Enabled = form.window_state != FormWindowState.Minimized; // minimize
247 icon_popup_menu.MenuItems[4].Enabled = form.window_state != FormWindowState.Maximized; // maximize
248 icon_popup_menu.MenuItems[5].Enabled = true; // close
249 icon_popup_menu.MenuItems[6].Enabled = true; // next
251 icon_popup_menu.Show(form, pnt);
254 private void RestoreItemHandler (object sender, EventArgs e)
256 form.WindowState = FormWindowState.Normal;
259 private void MoveItemHandler (object sender, EventArgs e)
261 int x = 0;
262 int y = 0;
264 PointToScreen (ref x, ref y);
265 Cursor.Position = new Point (x, y);
266 form.Cursor = Cursors.Cross;
267 state = State.Moving;
268 form.Capture = true;
271 private void SizeItemHandler (object sender, EventArgs e)
273 int x = 0;
274 int y = 0;
276 PointToScreen (ref x, ref y);
277 Cursor.Position = new Point (x, y);
278 form.Cursor = Cursors.Cross;
279 state = State.Sizing;
280 form.Capture = true;
283 private void MinimizeItemHandler (object sender, EventArgs e)
285 form.WindowState = FormWindowState.Minimized;
288 private void MaximizeItemHandler (object sender, EventArgs e)
290 if (form.WindowState != FormWindowState.Maximized)
291 form.WindowState = FormWindowState.Maximized;
294 private void CloseItemHandler (object sender, EventArgs e)
296 form.Close ();
299 private void NextItemHandler (object sender, EventArgs e)
301 mdi_container.ActivateNextChild ();
304 private void DrawIconMenuItem (object sender, DrawItemEventArgs de)
306 de.Graphics.DrawIcon (form.Icon, new Rectangle (de.Bounds.X + 2, de.Bounds.Y + 2,
307 de.Bounds.Height - 4, de.Bounds.Height - 4));
310 private void MeasureIconMenuItem (object sender, MeasureItemEventArgs me)
312 int size = SystemInformation.MenuHeight;
313 me.ItemHeight = size;
314 me.ItemWidth = size + 2; // some padding
317 private void MenuChangedHandler (object sender, EventArgs e)
319 CreateMergedMenu ();
322 public override void PointToClient (ref int x, ref int y)
324 XplatUI.ScreenToClient (mdi_container.Handle, ref x, ref y);
327 public override void PointToScreen (ref int x, ref int y)
329 XplatUI.ClientToScreen (mdi_container.Handle, ref x, ref y);
332 public override void UpdateWindowDecorations (FormWindowState window_state)
334 switch (window_state) {
335 case FormWindowState.Minimized:
336 case FormWindowState.Normal:
337 MaximizedMenu.Paint -= draw_maximized_buttons;
338 MaximizedTitleButtons.Visible = false;
339 TitleButtons.Visible = true;
340 break;
341 case FormWindowState.Maximized:
342 MaximizedMenu.Paint += draw_maximized_buttons;
343 MaximizedTitleButtons.Visible = true;
344 TitleButtons.Visible = false;
345 break;
348 base.UpdateWindowDecorations (window_state);
351 public override void SetWindowState (FormWindowState old_state, FormWindowState window_state)
353 mdi_container.SetWindowState (form, old_state, window_state, false);
356 private void FormClosed (object sender, EventArgs e)
358 mdi_container.CloseChildForm (form);
360 #if NET_2_0
361 if (form.MdiParent.MainMenuStrip != null)
362 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
363 #endif
366 public override void DrawMaximizedButtons (object sender, PaintEventArgs pe)
368 Size bs = ThemeEngine.Current.ManagedWindowButtonSize (this);
369 Point pnt = XplatUI.GetMenuOrigin (mdi_container.ParentForm.Handle);
370 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
371 TitleButtons buttons = MaximizedTitleButtons;
373 buttons.Visible = true;
374 TitleButtons.Visible = false;
376 buttons.CloseButton.Rectangle = new Rectangle (mdi_container.ParentForm.Size.Width - 1 - bw - bs.Width - 2,
377 pnt.Y + 2, bs.Width, bs.Height);
379 buttons.RestoreButton.Rectangle = new Rectangle (buttons.CloseButton.Rectangle.Left - 2 - bs.Width,
380 pnt.Y + 2, bs.Width, bs.Height);
382 buttons.MinimizeButton.Rectangle = new Rectangle (buttons.RestoreButton.Rectangle.Left - bs.Width,
383 pnt.Y + 2, bs.Width, bs.Height);
385 DrawTitleButton (pe.Graphics, buttons.MinimizeButton, pe.ClipRectangle);
386 DrawTitleButton (pe.Graphics, buttons.RestoreButton, pe.ClipRectangle);
387 DrawTitleButton (pe.Graphics, buttons.CloseButton, pe.ClipRectangle);
389 buttons.MinimizeButton.Rectangle.Y -= pnt.Y;
390 buttons.RestoreButton.Rectangle.Y -= pnt.Y;
391 buttons.CloseButton.Rectangle.Y -= pnt.Y;
394 public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
396 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
398 HandleTitleBarDown (pt.X, pt.Y);
399 return TitleButtons.AnyPushedTitleButtons;
402 public void HandleMenuMouseUp (MainMenu menu, int x, int y)
404 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
406 HandleTitleBarUp (pt.X, pt.Y);
409 public void HandleMenuMouseLeave (MainMenu menu, int x, int y)
411 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
412 HandleTitleBarLeave (pt.X, pt.Y);
416 public void HandleMenuMouseMove (MainMenu menu, int x, int y)
418 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
420 HandleTitleBarMouseMove (pt.X, pt.Y);
424 protected override void HandleTitleBarLeave (int x, int y)
426 base.HandleTitleBarLeave (x, y);
428 if (maximized_title_buttons != null) {
429 maximized_title_buttons.MouseLeave (x, y);
432 if (IsMaximized)
433 XplatUI.InvalidateNC (form.MdiParent.Handle);
436 protected override void HandleTitleBarUp (int x, int y)
438 if (IconRectangleContains (x, y)) {
439 if (!icon_dont_show_popup) {
440 if (IsMaximized)
441 ClickIconMenuItem (null, null);
442 else
443 ShowPopup (Point.Empty);
444 } else {
445 icon_dont_show_popup = false;
447 return;
450 bool was_maximized = IsMaximized;
451 base.HandleTitleBarUp (x, y);
452 if (maximized_title_buttons != null && was_maximized) {
453 maximized_title_buttons.MouseUp (x, y);
456 if (IsMaximized)
457 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
460 protected override void HandleTitleBarDoubleClick (int x, int y)
462 if (IconRectangleContains (x, y)) {
463 form.Close ();
464 } else {
465 form.WindowState = FormWindowState.Maximized;
467 base.HandleTitleBarDoubleClick (x, y);
470 protected override void HandleTitleBarDown (int x, int y)
472 if (IconRectangleContains (x, y)) {
473 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds < 500 && icon_clicked.X == x && icon_clicked.Y == y) {
474 form.Close ();
475 } else {
476 icon_clicked_time = DateTime.Now;
477 icon_clicked.X = x;
478 icon_clicked.Y = y;
481 return;
484 base.HandleTitleBarDown (x, y);
486 if (maximized_title_buttons != null) {
487 maximized_title_buttons.MouseDown (x, y);
490 if (IsMaximized) {
491 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
495 protected override void HandleTitleBarMouseMove (int x, int y)
497 base.HandleTitleBarMouseMove (x, y);
499 if (maximized_title_buttons != null) {
500 maximized_title_buttons.MouseMove (x, y);
504 protected override bool HandleLButtonDblClick (ref Message m)
507 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
508 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
510 // Correct since we are in NC land.
511 NCClientToNC (ref x, ref y);
513 if (IconRectangleContains (x, y)) {
514 icon_popup_menu.Wnd.Hide ();
515 form.Close ();
516 return true;
519 return base.HandleLButtonDblClick (ref m);
522 protected override bool HandleLButtonDown (ref Message m)
525 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
526 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
528 // Correct y since we are in NC land.
529 NCClientToNC(ref x, ref y);
531 if (IconRectangleContains (x, y)){
532 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds < 500) {
533 if (icon_popup_menu != null && icon_popup_menu.Wnd != null) {
534 icon_popup_menu.Wnd.Hide ();
536 form.Close ();
537 return true;
538 } else if (form.Capture) {
539 icon_dont_show_popup = true;
542 return base.HandleLButtonDown (ref m);
545 protected override bool ShouldRemoveWindowManager (FormBorderStyle style)
547 return false;
550 protected override void HandleWindowMove (Message m)
552 Point move = MouseMove (m);
554 if (move.X == 0 && move.Y == 0)
555 return;
557 int x = virtual_position.X + move.X;
558 int y = virtual_position.Y + move.Y;
560 Rectangle client = mdi_container.ClientRectangle;
561 if (mdi_container.VerticalScrollbarVisible)
562 client.Width -= SystemInformation.VerticalScrollBarWidth;
563 if (mdi_container.HorizontalScrollbarVisible)
564 client.Height -= SystemInformation.HorizontalScrollBarHeight;
565 if (!client.Contains (new Point(x + clicked_point.X, y + clicked_point.Y)))
566 return;
568 UpdateVP (x, y, form.Width, form.Height);
569 start = Cursor.Position;
572 protected override bool HandleNCMouseMove (ref Message m)
574 XplatUI.RequestAdditionalWM_NCMessages (form.Handle, true, true);
575 return base.HandleNCMouseMove (ref m);
578 protected override void DrawVirtualPosition (Rectangle virtual_position)
580 ClearVirtualPosition ();
582 if (form.Parent != null)
583 XplatUI.DrawReversibleRectangle (form.Parent.Handle, virtual_position, 2);
584 prev_virtual_position = virtual_position;
587 protected override void ClearVirtualPosition ()
589 if (prev_virtual_position != Rectangle.Empty && form.Parent != null)
590 XplatUI.DrawReversibleRectangle (form.Parent.Handle,
591 prev_virtual_position, 2);
592 prev_virtual_position = Rectangle.Empty;
595 protected override void OnWindowFinishedMoving ()
597 form.Refresh ();
600 public override bool IsActive {
601 get {
602 return mdi_container.ActiveMdiChild == form;
606 protected override void Activate ()
608 if (mdi_container.ActiveMdiChild != form) {
609 mdi_container.ActivateChild (form);
611 base.Activate ();