* MdiWindowManager.cs: Update function name.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MdiWindowManager.cs
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.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24 //
25 //
26
27
28 using System;
29 using System.Drawing;
30 using System.Drawing.Drawing2D;
31 using System.Runtime.InteropServices;
32
33 namespace System.Windows.Forms {
34
35         internal class MdiWindowManager : InternalWindowManager {
36
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;
42                 
43                 private PaintEventHandler draw_maximized_buttons;
44                 internal EventHandler form_closed_handler;
45                 
46                 private MdiClient mdi_container;
47                 private Rectangle prev_virtual_position;
48
49                 private Point icon_clicked;
50                 private DateTime icon_clicked_time;
51                 private bool icon_dont_show_popup;
52
53                 private TitleButtons maximized_title_buttons;
54                 private bool is_visible_pending;
55
56                 internal bool IsVisiblePending {
57                         get {
58                                 return is_visible_pending;
59                         }
60                         set {
61                                 is_visible_pending = value;
62                         }
63                 }
64
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;
72                                 }
73                                 return maximized_title_buttons;
74                         }
75                 }
76                 
77                 internal override Rectangle MaximizedBounds {
78                         get {
79                                 Rectangle pb = mdi_container.ClientRectangle;
80                                 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
81                                 int tw = TitleBarHeight;
82
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;
88                         }
89                 }
90                 
91                 
92                 
93                 public MdiWindowManager (Form form, MdiClient mdi_container) : base (form)
94                 {
95                         this.mdi_container = mdi_container;
96                         if (form.WindowState == FormWindowState.Normal) {
97                                 NormalBounds = form.Bounds;
98                         }
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 ();
107                 }
108
109                 private void FormVisibleChangedHandler (object sender, EventArgs e)
110                 {
111                         if (mdi_container == null)
112                                 return;
113                                 
114                         if (form.Visible) {
115                                 mdi_container.ActivateChild (form);
116                         } else if (mdi_container.Controls.Count > 1) {
117                                 mdi_container.ActivateActiveMdiChild ();
118                         }
119                 }
120
121                 private void FormTextChangedHandler (object sender, EventArgs e)
122                 {
123                         mdi_container.SetParentText (false);
124
125 #if NET_2_0
126                         if (form.MdiParent.MainMenuStrip != null)
127                                 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
128 #endif
129                 }
130
131                 private void FormLocationChangedHandler (object sender, EventArgs e)
132                 {
133                         if (form.window_state == FormWindowState.Minimized)
134                                 IconicBounds = form.Bounds;
135                         form.MdiParent.MdiContainer.SizeScrollBars ();
136                 }
137
138                 private void FormSizeChangedHandler (object sender, EventArgs e)
139                 {
140                         if (form.window_state == FormWindowState.Maximized && form.Bounds != MaximizedBounds)
141                                 form.Bounds = MaximizedBounds;
142                         
143                         form.MdiParent.MdiContainer.SizeScrollBars ();
144                 }
145         
146                 public MainMenu MergedMenu {
147                         get {
148                                 if (merged_menu == null)
149                                         merged_menu = CreateMergedMenu ();
150                                 return merged_menu;
151                         }
152                 }
153
154                 private MainMenu CreateMergedMenu ()
155                 {
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 ();
162                                 
163                         if (form.WindowState == FormWindowState.Maximized) {
164                                 
165                         }
166                         clone.MergeMenu (form.Menu);
167                         clone.MenuChanged += new EventHandler (MenuChangedHandler);
168                         clone.SetForm (parent);
169                         return clone;
170                 }
171
172                 public MainMenu MaximizedMenu {
173                         get {
174                                 if (maximized_menu == null)
175                                         maximized_menu = CreateMaximizedMenu ();
176                                 return maximized_menu;
177                         }
178                 }
179
180                 private MainMenu CreateMaximizedMenu ()
181                 {
182                         Form parent = (Form) mdi_container.Parent;
183                         MainMenu res = new MainMenu ();
184
185                         if (parent.Menu != null) {
186                                 MainMenu clone = (MainMenu) parent.Menu.CloneMenu ();
187                                 res.MergeMenu (clone);
188                         }
189                         
190                         if (form.Menu != null) {
191                                 MainMenu clone = (MainMenu) form.Menu.CloneMenu ();
192                                 res.MergeMenu (clone);
193                         }
194                         
195                         if (res.MenuItems.Count == 0)
196                                 res.MenuItems.Add (new MenuItem ()); // Dummy item to get the menu height correct
197                         
198                         res.MenuItems.Insert (0, icon_menu);
199                         
200                         res.SetForm (parent);
201                         return res;
202                 }
203
204                 private void CreateIconMenus ()
205                 {
206                         icon_menu = new MenuItem ();
207                         icon_popup_menu = new ContextMenu ();
208
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);
213
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));
221
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 });
226                 }
227
228                 private void ClickIconMenuItem(object sender, EventArgs e)
229                 {
230                         if ((DateTime.Now - icon_clicked_time).TotalMilliseconds < 500) {
231                                 form.Close ();
232                                 return;
233                         }
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);
239                 }
240                 
241                 private void ShowPopup (Point pnt)
242                 {
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
250                         
251                         icon_popup_menu.Show(form, pnt);
252                 }
253                 
254                 private void RestoreItemHandler (object sender, EventArgs e)
255                 {
256                         form.WindowState = FormWindowState.Normal;
257                 }
258
259                 private void MoveItemHandler (object sender, EventArgs e)
260                 {
261                         int x = 0;
262                         int y = 0;
263
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;
269                 }
270
271                 private void SizeItemHandler (object sender, EventArgs e)
272                 {
273                         int x = 0;
274                         int y = 0;
275
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;
281                 }               
282
283                 private void MinimizeItemHandler (object sender, EventArgs e)
284                 {
285                         form.WindowState = FormWindowState.Minimized;
286                 }
287
288                 private void MaximizeItemHandler (object sender, EventArgs e)
289                 {
290                         if (form.WindowState != FormWindowState.Maximized)
291                                 form.WindowState = FormWindowState.Maximized;
292                 }
293
294                 private void CloseItemHandler (object sender, EventArgs e)
295                 {
296                         form.Close ();
297                 }
298
299                 private void NextItemHandler (object sender, EventArgs e)
300                 {
301                         mdi_container.ActivateNextChild ();
302                 }
303
304                 private void DrawIconMenuItem (object sender, DrawItemEventArgs de)
305                 {
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));
308                 }
309
310                 private void MeasureIconMenuItem (object sender, MeasureItemEventArgs me)
311                 {
312                         int size = SystemInformation.MenuHeight;
313                         me.ItemHeight = size;
314                         me.ItemWidth = size + 2; // some padding
315                 }
316
317                 private void MenuChangedHandler (object sender, EventArgs e)
318                 {
319                         CreateMergedMenu ();
320                 }
321
322                 public override void PointToClient (ref int x, ref int y)
323                 {
324                         XplatUI.ScreenToClient (mdi_container.Handle, ref x, ref y);
325                 }
326
327                 public override void PointToScreen (ref int x, ref int y)
328                 {
329                         XplatUI.ClientToScreen (mdi_container.Handle, ref x, ref y);
330                 }
331
332                 public override void UpdateWindowDecorations (FormWindowState window_state)
333                 {                       
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;
346                         }
347                         
348                         base.UpdateWindowDecorations (window_state);
349                 }
350
351                 public override void SetWindowState (FormWindowState old_state, FormWindowState window_state)
352                 {
353                         mdi_container.SetWindowState (form, old_state, window_state, false);
354                 }
355
356                 private void FormClosed (object sender, EventArgs e)
357                 {
358                         mdi_container.ChildFormClosed (form);
359
360 #if NET_2_0
361                         if (form.MdiParent.MainMenuStrip != null)
362                                 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
363 #endif
364                 }
365
366                 public override void DrawMaximizedButtons (object sender, PaintEventArgs pe)
367                 {
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;
372                         
373                         buttons.Visible = true;
374                         TitleButtons.Visible = false;
375                         
376                         buttons.CloseButton.Rectangle = new Rectangle (mdi_container.ParentForm.Size.Width - 1 - bw - bs.Width - 2,
377                                         pnt.Y + 2, bs.Width, bs.Height);
378
379                         buttons.RestoreButton.Rectangle = new Rectangle (buttons.CloseButton.Rectangle.Left - 2 - bs.Width,
380                                         pnt.Y + 2, bs.Width, bs.Height);
381
382                         buttons.MinimizeButton.Rectangle = new Rectangle (buttons.RestoreButton.Rectangle.Left - bs.Width,
383                                         pnt.Y + 2, bs.Width, bs.Height);
384
385                         DrawTitleButton (pe.Graphics, buttons.MinimizeButton, pe.ClipRectangle);
386                         DrawTitleButton (pe.Graphics, buttons.RestoreButton, pe.ClipRectangle);
387                         DrawTitleButton (pe.Graphics, buttons.CloseButton, pe.ClipRectangle);
388
389                         buttons.MinimizeButton.Rectangle.Y -= pnt.Y;
390                         buttons.RestoreButton.Rectangle.Y -= pnt.Y;
391                         buttons.CloseButton.Rectangle.Y -= pnt.Y;
392                 }
393                 
394                 public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
395                 {
396                         Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
397
398                         HandleTitleBarDown (pt.X, pt.Y);
399                         return TitleButtons.AnyPushedTitleButtons;
400                 }
401
402                 public void HandleMenuMouseUp (MainMenu menu, int x, int y)
403                 {
404                         Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
405
406                         HandleTitleBarUp (pt.X, pt.Y);
407                 }
408
409                 public void HandleMenuMouseLeave (MainMenu menu, int x, int y)
410                 {
411                         Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
412                         HandleTitleBarLeave (pt.X, pt.Y);
413
414                 }
415
416                 public void HandleMenuMouseMove (MainMenu menu, int x, int y)
417                 {
418                         Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
419
420                         HandleTitleBarMouseMove (pt.X, pt.Y);
421
422                 }
423
424                 protected override void HandleTitleBarLeave (int x, int y)
425                 {
426                         base.HandleTitleBarLeave (x, y);
427
428                         if (maximized_title_buttons != null) {
429                                 maximized_title_buttons.MouseLeave (x, y);
430                         }
431                         
432                         if (IsMaximized)
433                                 XplatUI.InvalidateNC (form.MdiParent.Handle);
434                 }
435                 
436                 protected override void HandleTitleBarUp (int x, int y)
437                 {                       
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;
446                                 }
447                                 return;
448                         }
449                         
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);
454                         }
455
456                         if (IsMaximized)
457                                 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
458                 }
459
460                 protected override void HandleTitleBarDoubleClick (int x, int y)
461                 {
462                         if (IconRectangleContains (x, y)) {
463                                 form.Close ();
464                         } else {
465                                 form.WindowState = FormWindowState.Maximized;
466                         }
467                         base.HandleTitleBarDoubleClick (x, y);
468                 }
469                 
470                 protected override void HandleTitleBarDown (int x, int y)
471                 {                       
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;
479                                 }
480                                 
481                                 return;
482                         }
483
484                         base.HandleTitleBarDown (x, y);
485
486                         if (maximized_title_buttons != null) {
487                                 maximized_title_buttons.MouseDown (x, y);
488                         }
489                         
490                         if (IsMaximized) {
491                                 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
492                         }
493                 }
494
495                 protected override void HandleTitleBarMouseMove (int x, int y)
496                 {
497                         base.HandleTitleBarMouseMove (x, y);
498
499                         if (maximized_title_buttons != null) {
500                                 maximized_title_buttons.MouseMove (x, y);
501                         }
502                 }
503
504                 protected override bool HandleLButtonDblClick (ref Message m)
505                 {
506
507                         int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
508                         int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
509
510                         // Correct since we are in NC land.
511                         NCClientToNC (ref x, ref y);
512
513                         if (IconRectangleContains (x, y)) {
514                                 icon_popup_menu.Wnd.Hide ();
515                                 form.Close ();
516                                 return true;
517                         }
518                         
519                         return base.HandleLButtonDblClick (ref m);
520                 }
521
522                 protected override bool HandleLButtonDown (ref Message m)
523                 {
524
525                         int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
526                         int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
527
528                         // Correct y since we are in NC land.
529                         NCClientToNC(ref x, ref y);
530
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 ();
535                                         }
536                                         form.Close ();
537                                         return true;
538                                 } else if (form.Capture) {
539                                         icon_dont_show_popup = true;
540                                 }
541                         }
542                         return base.HandleLButtonDown (ref m);
543                 }
544
545                 protected override bool ShouldRemoveWindowManager (FormBorderStyle style)
546                 {
547                         return false;
548                 }
549
550                 protected override void HandleWindowMove (Message m)
551                 {
552                         Point move = MouseMove (m);
553                         
554                         if (move.X == 0 && move.Y == 0)
555                                 return;
556                         
557                         int x = virtual_position.X + move.X;
558                         int y = virtual_position.Y + move.Y;
559                 
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;
567
568                         UpdateVP (x, y, form.Width, form.Height);
569                         start = Cursor.Position;
570                 }
571
572                 protected override bool HandleNCMouseMove (ref Message m)
573                 {
574                         XplatUI.RequestAdditionalWM_NCMessages (form.Handle, true, true);
575                         return base.HandleNCMouseMove (ref m);
576                 }
577
578                 protected override void DrawVirtualPosition (Rectangle virtual_position)
579                 {
580                         ClearVirtualPosition ();
581
582                         if (form.Parent != null)
583                                 XplatUI.DrawReversibleRectangle (form.Parent.Handle, virtual_position, 2);
584                         prev_virtual_position = virtual_position;
585                 }
586
587                 protected override void ClearVirtualPosition ()
588                 {
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;
593                 }
594
595                 protected override void OnWindowFinishedMoving ()
596                 {
597                         form.Refresh ();
598                 }
599
600                 public override bool IsActive {
601                         get {
602                                 return mdi_container.ActiveMdiChild == form;
603                         }
604                 }
605
606                 protected override void Activate ()
607                 {
608                         if (mdi_container.ActiveMdiChild != form) {
609                                 mdi_container.ActivateChild (form);
610                         }
611                         base.Activate ();
612                 }       
613         }
614 }
615