New test.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MdiClient.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 //      Peter Bartok    pbartok@novell.com
24 //
25 //
26
27 // NOT COMPLETE
28
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Drawing;
32
33 namespace System.Windows.Forms {
34         [DesignTimeVisible(false)]
35         [ToolboxItem(false)]
36         public sealed class MdiClient : Control {
37                 #region Local Variables
38                 private int mdi_created;
39                 private HScrollBar hbar;
40                 private VScrollBar vbar;
41                 private SizeGrip sizegrip;
42                 private int hbar_value;
43                 private int vbar_value;
44                 private bool lock_sizing;
45                 private int prev_bottom;
46                 private LayoutEventHandler initial_layout_handler;
47                 internal ArrayList mdi_child_list;
48
49                 #endregion      // Local Variables
50
51                 #region Public Classes
52                 public new class ControlCollection : Control.ControlCollection {
53
54                         private MdiClient owner;
55                         
56                         public ControlCollection(MdiClient owner) : base(owner) {
57                                 this.owner = owner;
58                                 owner.mdi_child_list = new ArrayList ();
59                         }
60
61                         public override void Add(Control value) {
62                                 if ((value is Form) == false || !(((Form)value).IsMdiChild)) {
63                                         throw new ArgumentException("Form must be MdiChild");
64                                 }
65                                 owner.mdi_child_list.Add (value);
66                                 base.Add (value);
67
68                                 // newest member is the active one
69                                 Form form = (Form) value;
70                                 owner.ActiveMdiChild = form;
71                         }
72
73                         public override void Remove(Control value)
74                         {
75                                 Form form = value as Form;
76                                 if (form != null) {
77                                         MdiWindowManager wm = form.WindowManager as MdiWindowManager;
78                                         if (wm != null) {
79                                                 form.Closed -= wm.form_closed_handler;
80                                         }
81                                 }
82
83                                 owner.mdi_child_list.Remove (value);
84                                 base.Remove (value);
85                         }
86                 }
87                 #endregion      // Public Classes
88
89                 #region Public Constructors
90                 public MdiClient()
91                 {
92                         BackColor = SystemColors.AppWorkspace;
93                         Dock = DockStyle.Fill;
94                         SetStyle (ControlStyles.Selectable, false);
95                 }
96                 #endregion      // Public Constructors
97
98                 internal override void OnPaintBackgroundInternal (PaintEventArgs pe)
99                 {
100                         if (BackgroundImage != null)
101                                 return;
102
103                         if (Parent == null || Parent.BackgroundImage == null)
104                                 return;
105                         Parent.PaintControlBackground (pe);
106                 }
107
108                 internal Form ParentForm {
109                         get { return (Form) Parent; }
110                 }
111
112                 protected override Control.ControlCollection CreateControlsInstance ()
113                 {
114                         return new MdiClient.ControlCollection (this);
115                 }
116
117                 protected override void WndProc(ref Message m) {
118                         /*
119                         switch ((Msg) m.Msg) {
120                                 case Msg.WM_PAINT: {                            
121                                         Console.WriteLine ("ignoring paint");
122                                         return;
123                                 }
124                         }
125                         */
126                         base.WndProc (ref m);
127                 }
128
129                 protected override void OnResize (EventArgs e)
130                 {
131                         base.OnResize (e);
132
133                         // Should probably make this into one loop
134                         SizeScrollBars ();
135                         ArrangeWindows ();
136                 }
137
138                 protected override void ScaleCore (float dx, float dy)
139                 {
140                         base.ScaleCore (dx, dy);
141                 }
142
143                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
144                 {
145                         base.SetBoundsCore (x, y, width, height, specified);
146                 }
147
148                 #region Public Instance Properties
149                 [Localizable(true)]
150                 public override System.Drawing.Image BackgroundImage {
151                         get {
152                                 return base.BackgroundImage;
153                         }
154                         set {
155                                 base.BackgroundImage = value;
156                         }
157                 }
158
159                 public Form [] MdiChildren {
160                         get {
161                                 if (mdi_child_list == null)
162                                         return new Form [0];
163                                 return (Form []) mdi_child_list.ToArray (typeof (Form));
164                         }
165                 }
166                 #endregion      // Public Instance Properties
167
168 #region Protected Instance Properties
169                 protected override CreateParams CreateParams {
170                         get {
171                                 return base.CreateParams;
172                         }
173                 }
174                 #endregion      // Protected Instance Properties
175
176                 #region Public Instance Methods
177                 public void LayoutMdi (MdiLayout value) {
178
179                         int max_width = Int32.MaxValue;
180                         int max_height = Int32.MaxValue;
181
182                         if (Parent != null) {
183                                 max_width = Parent.Width;
184                                 max_height = Parent.Height;
185                         }
186
187                         switch (value) {
188                         case MdiLayout.Cascade:
189                                 int i = 0;
190                                 for (int c = Controls.Count - 1; c >= 0; c--) {
191                                         Form form = (Form) Controls [c];
192
193                                         int l = 22 * i;
194                                         int t = 22 * i;
195
196                                         if (i != 0 && (l + form.Width > max_width || t + form.Height > max_height)) {
197                                                 i = 0;
198                                                 l = 22 * i;
199                                                 t = 22 * i;
200                                         }
201
202                                         form.Left = l;
203                                         form.Top = t;
204
205                                         i++;
206                                 }
207                                 break;
208                         default:
209                                 throw new NotImplementedException();
210                         }
211                 }
212                 #endregion      // Public Instance Methods
213
214                 #region Protected Instance Methods
215                 #endregion      // Protected Instance Methods
216
217                 private void SizeScrollBars ()
218                 {
219                         if (lock_sizing)
220                                 return;
221
222                         if (Controls.Count == 0 || ((Form) Controls [0]).WindowState == FormWindowState.Maximized) {
223                                 if (hbar != null)
224                                         hbar.Visible = false;
225                                 if (vbar != null)
226                                         vbar.Visible = false;
227                                 return;
228                         }
229                                 
230                         bool hbar_required = false;
231                         bool vbar_required = false;
232
233                         int right = 0;
234                         int left = 0;
235                         foreach (Form child in Controls) {
236                                 if (!child.Visible)
237                                         continue;
238                                 if (child.Right > right)
239                                         right = child.Right;
240                                 if (child.Left < left) {
241                                         hbar_required = true;
242                                         left = child.Left;
243                                 }
244                         }
245
246                         int top = 0;
247                         int bottom = 0;
248                         foreach (Form child in Controls) {
249                                 if (!child.Visible)
250                                         continue;
251                                 if (child.Bottom > bottom)
252                                         bottom = child.Bottom;
253                                 if (child.Top < 0) {
254                                         vbar_required = true;
255                                         top = child.Top;
256                                 }
257                         }
258
259                         int right_edge = Right;
260                         int bottom_edge = Bottom;
261                         int prev_right_edge;
262                         int prev_bottom_edge;
263
264                         bool need_hbar = false;
265                         bool need_vbar = false;
266
267                         do {
268                                 prev_right_edge = right_edge;
269                                 prev_bottom_edge = bottom_edge;
270
271                                 if (hbar_required || right > right_edge) {
272                                         need_hbar = true;
273                                         bottom_edge = Bottom - SystemInformation.HorizontalScrollBarHeight;
274                                 } else {
275                                         need_hbar = false;
276                                         bottom_edge = Bottom;
277                                 }
278
279                                 if (vbar_required || bottom > bottom_edge) {
280                                         need_vbar = true;
281                                         right_edge = Right - SystemInformation.VerticalScrollBarWidth;
282                                 } else {
283                                         need_vbar = false;
284                                         right_edge = Right;
285                                 }
286
287                         } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge);
288
289                         if (need_hbar) {
290                                 if (hbar == null) {
291                                         hbar = new HScrollBar ();
292                                         Controls.AddImplicit (hbar);
293                                 }
294                                 hbar.Visible = true;
295                                 CalcHBar (left, right, right_edge, need_vbar);
296                         } else if (hbar != null)
297                                 hbar.Visible = false;
298
299                         if (need_vbar) {
300                                 if (vbar == null) {
301                                         vbar = new VScrollBar ();
302                                         Controls.AddImplicit (vbar);
303                                 }
304                                 vbar.Visible = true;
305                                 CalcVBar (top, bottom, bottom_edge, need_hbar);
306                         } else if (vbar != null)
307                                 vbar.Visible = false;
308
309                         if (need_hbar && need_vbar) {
310                                 if (sizegrip == null) {
311                                         sizegrip = new SizeGrip ();
312                                         Controls.AddImplicit (sizegrip);
313                                 }
314                                 sizegrip.Location = new Point (hbar.Right, vbar.Bottom);
315                                 sizegrip.Width = vbar.Width;
316                                 sizegrip.Height = hbar.Height;
317                                 sizegrip.Visible = true;
318                         } else if (sizegrip != null) {
319                                 sizegrip.Visible = false;
320                         }
321                 }
322
323                 private void CalcHBar (int left, int right, int right_edge, bool vert_vis)
324                 {
325                         int virtual_left = Math.Min (left, 0);
326                         int virtual_right = Math.Max (right, right_edge);
327                         int diff = (virtual_right - virtual_left) - right_edge;
328                         hbar.Left = 0;
329                         hbar.Top = Height - hbar.Height;
330                         hbar.Width = Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
331                         hbar.LargeChange = 50;
332                         hbar.Maximum = diff + 51;
333                         hbar.Value = -virtual_left;
334
335                         hbar.ValueChanged += new EventHandler (HBarValueChanged);
336                 }
337
338                 private void CalcVBar (int top, int bottom, int bottom_edge, bool horz_vis)
339                 {
340                         int virtual_top = Math.Min (top, 0);
341                         int virtual_bottom = Math.Max (bottom, bottom_edge);
342                         int diff = (virtual_bottom - virtual_top) - bottom_edge;
343                         vbar.Top = 0;
344                         vbar.Left = Width - vbar.Width;
345                         vbar.Height = Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
346                         vbar.LargeChange = 50;
347                         vbar.Maximum = diff + 51;
348                         vbar.Value = -virtual_top;
349                         vbar.ValueChanged += new EventHandler (VBarValueChanged);
350                         
351                 }
352
353                 private void HBarValueChanged (object sender, EventArgs e)
354                 {
355                         if (hbar.Value == hbar_value)
356                                 return;
357
358                         lock_sizing = true;
359
360                         try {
361                                 foreach (Form child in Controls) {
362                                         child.Left += hbar_value - hbar.Value;
363                                 }
364                         } finally {
365                                 lock_sizing = false;
366                         }
367
368                         hbar_value = hbar.Value;
369                         lock_sizing = false;
370                 }
371
372                 private void VBarValueChanged (object sender, EventArgs e)
373                 {
374                         if (vbar.Value == vbar_value)
375                                 return;
376
377                         lock_sizing = true;
378
379                         try {
380                                 foreach (Form child in Controls) {
381                                         child.Top += vbar_value - vbar.Value;
382                                 }
383                         } finally {
384                                 lock_sizing = false;
385                         }
386
387                         vbar_value = vbar.Value;
388                         lock_sizing = false;
389                 }
390
391                 private void ArrangeWindows ()
392                 {
393                         int change = 0;
394                         if (prev_bottom != -1)
395                                 change = Bottom - prev_bottom;
396
397                         foreach (Control c in Controls) {
398                                 Form child = c as Form;
399
400                                 if (c == null || !child.Visible)
401                                         continue;
402
403                                 MdiWindowManager wm = child.WindowManager as MdiWindowManager;
404                                 if (wm.GetWindowState () == FormWindowState.Maximized)
405                                         wm.SizeMaximized ();
406
407                                 if (wm.GetWindowState () == FormWindowState.Minimized) {
408                                         child.Top += change;
409                                 }
410                                         
411                         }
412
413                         prev_bottom = Bottom;
414                 }
415
416                 private void FormLocationChanged (object sender, EventArgs e)
417                 {
418                         SizeScrollBars ();
419                 }
420
421                 private int iconic_x = -1;
422                 private int iconic_y = -1;
423                 internal void ArrangeIconicWindows ()
424                 {
425                         int xspacing = 160;
426                         int yspacing = 25;
427
428                         if (iconic_x == -1 && iconic_y == -1) {
429                                 iconic_x = Left;
430                                 iconic_y = Bottom - yspacing;
431                         }
432
433                         lock_sizing = true;
434                         foreach (Form form in Controls) {
435                                 if (form.WindowState != FormWindowState.Minimized)
436                                         continue;
437
438                                 MdiWindowManager wm = (MdiWindowManager) form.WindowManager;
439                                 // Need to get the width in the loop cause some themes might have
440                                 // different widths for different styles
441                                 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (wm);
442                                 
443                                 if (wm.IconicBounds != Rectangle.Empty) {
444                                         form.Bounds = wm.IconicBounds;
445                                         continue;
446                                 }
447                                         
448                                 // The extra one pixel is a cheap hack for now until we
449                                 // handle 0 client sizes properly in the driver
450                                 int height = wm.TitleBarHeight + (bw * 2) + 1; 
451                                 Rectangle rect = new Rectangle (iconic_x, iconic_y, xspacing, height);
452                                 form.Bounds = wm.IconicBounds = rect;
453
454                                 iconic_x += xspacing;
455                                 if (iconic_x >= Right) {
456                                         iconic_x = Left;
457                                         iconic_y -= height;
458                                 }
459                         }
460                         lock_sizing = false;
461                 }
462
463                 internal void CloseChildForm (Form form)
464                 {
465                         if (Controls.Count > 1) {
466                                 Form next = (Form) Controls [1];
467                                 if (form.WindowState == FormWindowState.Maximized)
468                                         next.WindowState = FormWindowState.Maximized;
469                                 ActivateChild (next);
470                         }
471
472                         Controls.Remove (form);
473                         form.Close ();
474                 }
475
476                 internal void ActivateNextChild ()
477                 {
478                         if (Controls.Count < 1)
479                                 return;
480
481                         Form front = (Form) Controls [0];
482                         Form form = (Form) Controls [1];
483
484                         front.SendToBack ();
485                         ActivateChild (form);
486                 }
487
488                 internal void ActivateChild (Form form)
489                 {
490                         if (Controls.Count < 1)
491                                 return;
492
493                         Form current = (Form) Controls [0];
494
495                         form.BringToFront ();
496
497                         if (current != form) {
498                                 Message m = new Message ();
499                                 m.Msg = (int) Msg.WM_NCPAINT;
500                                 m.HWnd = current.Handle;
501                                 m.LParam = IntPtr.Zero;
502                                 m.WParam = new IntPtr (1);
503                                 XplatUI.SendMessage (ref m);
504
505                                 m.HWnd = form.Handle;
506                                 XplatUI.SendMessage (ref m);
507                         }
508                 }
509
510                 internal int ChildrenCreated {
511                         get { return mdi_created; }
512                         set { mdi_created = value; }
513                 }
514
515                 internal Form ActiveMdiChild {
516                         get {
517                                 if (Controls.Count < 1)
518                                         return null;
519                                 return (Form) Controls [0];
520                         }
521                         set {
522                                 ActivateChild (value);
523                         }
524                 }
525         }
526 }
527