* MdiClient.cs:
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MdiClient.cs
index 365ca8c2469c7399b4b5ceb8f17d27784c7caaa1..248d05b777e92691252aecea90db346d9e90a8ca 100644 (file)
@@ -29,6 +29,7 @@
 using System.Collections;
 using System.ComponentModel;
 using System.Drawing;
+using System.Runtime.InteropServices;
 
 namespace System.Windows.Forms {
        [DesignTimeVisible(false)]
@@ -36,15 +37,19 @@ namespace System.Windows.Forms {
        public sealed class MdiClient : Control {
                #region Local Variables
                private int mdi_created;
-               private HScrollBar hbar;
-               private VScrollBar vbar;
+               private ImplicitHScrollBar hbar;
+               private ImplicitVScrollBar vbar;
                private SizeGrip sizegrip;
                private int hbar_value;
                private int vbar_value;
                private bool lock_sizing;
+               private bool initializing_scrollbars;
                private int prev_bottom;
-               private LayoutEventHandler initial_layout_handler;
+               private bool setting_windowstates = false;
                internal ArrayList mdi_child_list;
+               private string form_text;
+               private bool setting_form_text;
+               private Form active_child;
 
                #endregion      // Local Variables
 
@@ -55,7 +60,6 @@ namespace System.Windows.Forms {
                        
                        public ControlCollection(MdiClient owner) : base(owner) {
                                this.owner = owner;
-                               owner.mdi_child_list = new ArrayList ();
                        }
 
                        public override void Add(Control value) {
@@ -89,12 +93,38 @@ namespace System.Windows.Forms {
                #region Public Constructors
                public MdiClient()
                {
+                       mdi_child_list = new ArrayList ();
                        BackColor = SystemColors.AppWorkspace;
                        Dock = DockStyle.Fill;
                        SetStyle (ControlStyles.Selectable, false);
                }
                #endregion      // Public Constructors
 
+
+               internal void SetParentText(bool text_changed)
+               {
+                       if (setting_form_text)
+                               return;
+
+                       setting_form_text = true;
+
+                       if (text_changed)
+                               form_text = ParentForm.Text;
+
+                       if (ParentForm.ActiveMaximizedMdiChild == null) {
+                               ParentForm.Text = form_text;
+                       } else {
+                               string childText = ParentForm.ActiveMaximizedMdiChild.form.Text;
+                               if (childText.Length > 0) {
+                                       ParentForm.Text = form_text + " - [" + ParentForm.ActiveMaximizedMdiChild.form.Text + "]";
+                               } else {
+                                       ParentForm.Text = form_text;
+                               }
+                       }
+
+                       setting_form_text = false;
+               }
+
                internal override void OnPaintBackgroundInternal (PaintEventArgs pe)
                {
                        if (BackgroundImage != null)
@@ -123,6 +153,38 @@ namespace System.Windows.Forms {
                                }
                        }
                        */
+                       switch ((Msg)m.Msg) {
+                       case Msg.WM_NCCALCSIZE:
+                               XplatUIWin32.NCCALCSIZE_PARAMS  ncp;
+
+                               if (m.WParam == (IntPtr) 1) {
+                                       ncp = (XplatUIWin32.NCCALCSIZE_PARAMS) Marshal.PtrToStructure (m.LParam,
+                                                       typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
+
+                                       int bw = 2;
+
+                                       ncp.rgrc1.top += bw;
+                                       ncp.rgrc1.bottom -= bw;
+                                       ncp.rgrc1.left += bw;
+                                       ncp.rgrc1.right -= bw;
+                                       
+                                       Marshal.StructureToPtr (ncp, m.LParam, true);
+                               }
+
+                               break;
+
+                       case Msg.WM_NCPAINT:
+                               PaintEventArgs pe = XplatUI.PaintEventStart (Handle, false);
+
+                               Rectangle clip;
+                               clip = new Rectangle (0, 0, Width, Height);
+
+                               ControlPaint.DrawBorder3D (pe.Graphics, clip, Border3DStyle.Sunken);
+                               XplatUI.PaintEventEnd (Handle, false);
+                               m.Result = IntPtr.Zero;
+                               return ;
+                       }
+
                        base.WndProc (ref m);
                }
 
@@ -130,6 +192,8 @@ namespace System.Windows.Forms {
                {
                        base.OnResize (e);
 
+                       if (Parent != null)
+                               XplatUI.InvalidateNC (Parent.Handle);
                        // Should probably make this into one loop
                        SizeScrollBars ();
                        ArrangeWindows ();
@@ -214,7 +278,7 @@ namespace System.Windows.Forms {
                #region Protected Instance Methods
                #endregion      // Protected Instance Methods
 
-               private void SizeScrollBars ()
+               internal void SizeScrollBars ()
                {
                        if (lock_sizing)
                                return;
@@ -224,6 +288,8 @@ namespace System.Windows.Forms {
                                        hbar.Visible = false;
                                if (vbar != null)
                                        vbar.Visible = false;
+                               if (sizegrip != null)
+                                       sizegrip.Visible = false;
                                return;
                        }
                                
@@ -232,6 +298,9 @@ namespace System.Windows.Forms {
 
                        int right = 0;
                        int left = 0;
+                       int top = 0;
+                       int bottom = 0;
+
                        foreach (Form child in Controls) {
                                if (!child.Visible)
                                        continue;
@@ -241,13 +310,7 @@ namespace System.Windows.Forms {
                                        hbar_required = true;
                                        left = child.Left;
                                }
-                       }
-
-                       int top = 0;
-                       int bottom = 0;
-                       foreach (Form child in Controls) {
-                               if (!child.Visible)
-                                       continue;
+                               
                                if (child.Bottom > bottom)
                                        bottom = child.Bottom;
                                if (child.Top < 0) {
@@ -256,8 +319,10 @@ namespace System.Windows.Forms {
                                }
                        }
 
-                       int right_edge = Right;
-                       int bottom_edge = Bottom;
+                       int first_right = Width;
+                       int first_bottom = Height;
+                       int right_edge = first_right;
+                       int bottom_edge = first_bottom;
                        int prev_right_edge;
                        int prev_bottom_edge;
 
@@ -270,25 +335,25 @@ namespace System.Windows.Forms {
 
                                if (hbar_required || right > right_edge) {
                                        need_hbar = true;
-                                       bottom_edge = Bottom - SystemInformation.HorizontalScrollBarHeight;
+                                       bottom_edge = first_bottom - SystemInformation.HorizontalScrollBarHeight;
                                } else {
                                        need_hbar = false;
-                                       bottom_edge = Bottom;
+                                       bottom_edge = first_bottom;
                                }
 
                                if (vbar_required || bottom > bottom_edge) {
                                        need_vbar = true;
-                                       right_edge = Right - SystemInformation.VerticalScrollBarWidth;
+                                       right_edge = first_right - SystemInformation.VerticalScrollBarWidth;
                                } else {
                                        need_vbar = false;
-                                       right_edge = Right;
+                                       right_edge = first_right;
                                }
 
                        } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge);
 
                        if (need_hbar) {
                                if (hbar == null) {
-                                       hbar = new HScrollBar ();
+                                       hbar = new ImplicitHScrollBar ();
                                        Controls.AddImplicit (hbar);
                                }
                                hbar.Visible = true;
@@ -298,7 +363,7 @@ namespace System.Windows.Forms {
 
                        if (need_vbar) {
                                if (vbar == null) {
-                                       vbar = new VScrollBar ();
+                                       vbar = new ImplicitVScrollBar ();
                                        Controls.AddImplicit (vbar);
                                }
                                vbar.Visible = true;
@@ -322,36 +387,45 @@ namespace System.Windows.Forms {
 
                private void CalcHBar (int left, int right, int right_edge, bool vert_vis)
                {
+                       initializing_scrollbars = true;
                        int virtual_left = Math.Min (left, 0);
                        int virtual_right = Math.Max (right, right_edge);
                        int diff = (virtual_right - virtual_left) - right_edge;
+
                        hbar.Left = 0;
-                       hbar.Top = Height - hbar.Height;
-                       hbar.Width = Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
+                       hbar.Top = ClientRectangle.Bottom - hbar.Height;
+                       hbar.Width = ClientRectangle.Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
                        hbar.LargeChange = 50;
-                       hbar.Maximum = diff + 51;
+                       hbar.Maximum = diff + 51 + (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
                        hbar.Value = -virtual_left;
-
                        hbar.ValueChanged += new EventHandler (HBarValueChanged);
+                       XplatUI.SetZOrder (hbar.Handle, IntPtr.Zero, true, false);
+                       initializing_scrollbars = false;
                }
 
                private void CalcVBar (int top, int bottom, int bottom_edge, bool horz_vis)
                {
+                       initializing_scrollbars = true;
                        int virtual_top = Math.Min (top, 0);
                        int virtual_bottom = Math.Max (bottom, bottom_edge);
                        int diff = (virtual_bottom - virtual_top) - bottom_edge;
+                       
                        vbar.Top = 0;
-                       vbar.Left = Width - vbar.Width;
-                       vbar.Height = Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
+                       vbar.Left = ClientRectangle.Right - vbar.Width;
+                       vbar.Height = ClientRectangle.Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
                        vbar.LargeChange = 50;
-                       vbar.Maximum = diff + 51;
-                       vbar.Value = -virtual_top;
+                       vbar.Minimum = virtual_top;
+                       vbar.Maximum = diff + 51 + (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
                        vbar.ValueChanged += new EventHandler (VBarValueChanged);
-                       
+                       XplatUI.SetZOrder (vbar.Handle, IntPtr.Zero, true, false);
+                       initializing_scrollbars = false;
                }
 
                private void HBarValueChanged (object sender, EventArgs e)
                {
+                       if (initializing_scrollbars)
+                               return;
+                       
                        if (hbar.Value == hbar_value)
                                return;
 
@@ -371,6 +445,9 @@ namespace System.Windows.Forms {
 
                private void VBarValueChanged (object sender, EventArgs e)
                {
+                       if (initializing_scrollbars)
+                               return;
+                               
                        if (vbar.Value == vbar_value)
                                return;
 
@@ -413,22 +490,12 @@ namespace System.Windows.Forms {
                        prev_bottom = Bottom;
                }
 
-               private void FormLocationChanged (object sender, EventArgs e)
-               {
-                       SizeScrollBars ();
-               }
-
-               private int iconic_x = -1;
-               private int iconic_y = -1;
                internal void ArrangeIconicWindows ()
                {
                        int xspacing = 160;
                        int yspacing = 25;
 
-                       if (iconic_x == -1 && iconic_y == -1) {
-                               iconic_x = Left;
-                               iconic_y = Bottom - yspacing;
-                       }
+                       Rectangle rect = new Rectangle (0, 0, xspacing, yspacing);
 
                        lock_sizing = true;
                        foreach (Form form in Controls) {
@@ -436,26 +503,55 @@ namespace System.Windows.Forms {
                                        continue;
 
                                MdiWindowManager wm = (MdiWindowManager) form.WindowManager;
-                               // Need to get the width in the loop cause some themes might have
-                               // different widths for different styles
-                               int bw = ThemeEngine.Current.ManagedWindowBorderWidth (wm);
                                
                                if (wm.IconicBounds != Rectangle.Empty) {
-                                       form.Bounds = wm.IconicBounds;
+                                       if (form.Bounds != wm.IconicBounds)
+                                               form.Bounds = wm.IconicBounds;
                                        continue;
                                }
-                                       
+                               
+                               // Need to get the width in the loop cause some themes might have
+                               // different widths for different styles
+                               int bw = ThemeEngine.Current.ManagedWindowBorderWidth (wm);
+                               
                                // The extra one pixel is a cheap hack for now until we
                                // handle 0 client sizes properly in the driver
-                               int height = wm.TitleBarHeight + (bw * 2) + 1; 
-                               Rectangle rect = new Rectangle (iconic_x, iconic_y, xspacing, height);
-                               form.Bounds = wm.IconicBounds = rect;
-
-                               iconic_x += xspacing;
-                               if (iconic_x >= Right) {
-                                       iconic_x = Left;
-                                       iconic_y -= height;
-                               }
+                               int height = wm.TitleBarHeight + (bw * 2) + 1;
+                               
+                               bool success = true;
+                               int startx, starty, currentx, currenty;
+                               
+                               startx = 0;
+                               starty = Bottom - yspacing - 1;
+                               if (this.hbar != null && this.hbar.Visible)
+                                       starty -= this.hbar.Height;
+                               currentx = startx;
+                               currenty = starty;
+                               
+                               do {
+                                       rect.X = currentx;
+                                       rect.Y = currenty;
+                                       rect.Height = height;
+                                       success = true;
+                                       foreach (Form form2 in Controls) {
+                                               if (form2 == form || form2.window_state != FormWindowState.Minimized)
+                                                       continue;
+                                               
+                                               if (form2.Bounds.IntersectsWith(rect)) {
+                                                       success = false;
+                                                       break;
+                                               }
+                                       }
+                                       if (!success) { 
+                                               currentx += xspacing;
+                                               if (currentx + xspacing > Right) {
+                                                       currentx = startx;
+                                                       currenty -= Math.Max(yspacing, height);
+                                               } 
+                                       }
+                               } while (!success);
+                               wm.IconicBounds = rect;
+                               form.Bounds = wm.IconicBounds;
                        }
                        lock_sizing = false;
                }
@@ -471,13 +567,23 @@ namespace System.Windows.Forms {
 
                        Controls.Remove (form);
                        form.Close ();
+
+                       XplatUI.RequestNCRecalc (Handle);
+                       if (Controls.Count == 0) {
+                               XplatUI.RequestNCRecalc (Parent.Handle);
+                               ParentForm.PerformLayout ();
+                       }
+                       SizeScrollBars ();
+                       SetParentText (false);
                }
 
                internal void ActivateNextChild ()
                {
                        if (Controls.Count < 1)
                                return;
-
+                       if (Controls.Count == 1 && Controls[0] == ActiveMdiChild)
+                               return;
+                               
                        Form front = (Form) Controls [0];
                        Form form = (Form) Controls [1];
 
@@ -489,22 +595,83 @@ namespace System.Windows.Forms {
                {
                        if (Controls.Count < 1)
                                return;
-
+                       
+                       if (ParentForm.is_changing_visible_state)
+                               return;
+                               
                        Form current = (Form) Controls [0];
-
+                       form.SuspendLayout ();
                        form.BringToFront ();
-
+                       if (vbar != null && vbar.Visible)
+                               XplatUI.SetZOrder (vbar.Handle, IntPtr.Zero, true, false);
+                       if (hbar != null && hbar.Visible)
+                               XplatUI.SetZOrder (hbar.Handle, IntPtr.Zero, true, false);
+                       SetWindowStates ((MdiWindowManager) form.window_manager);
+                       form.ResumeLayout (false);
                        if (current != form) {
-                               Message m = new Message ();
-                               m.Msg = (int) Msg.WM_NCPAINT;
-                               m.HWnd = current.Handle;
-                               m.LParam = IntPtr.Zero;
-                               m.WParam = new IntPtr (1);
-                               XplatUI.SendMessage (ref m);
-
-                               m.HWnd = form.Handle;
-                               XplatUI.SendMessage (ref m);
+                               form.has_focus = false;
+                               XplatUI.InvalidateNC (current.Handle);
+                               XplatUI.InvalidateNC (form.Handle);
                        }
+                       active_child = (Form) Controls [0];
+               }
+               
+               internal bool SetWindowStates (MdiWindowManager wm)
+               {
+               /*
+                       MDI WindowState behaviour:
+                       - If the active window is maximized, all other maximized windows are normalized.
+                       - If a normal window gets focus and the original active window was maximized, 
+                         the normal window gets maximized and the original window gets normalized.
+                       - If a minimized window gets focus and the original window was maximized, 
+                         the minimzed window gets maximized and the original window gets normalized. 
+                         If the ex-minimized window gets deactivated, it will be normalized.
+               */
+                       Form form = wm.form;
+
+                       if (setting_windowstates) {
+                               return false;
+                       }
+                       
+                       if (!form.Visible)
+                               return false;
+                       
+                       bool is_active = wm.IsActive();
+                       bool maximize_this = false;
+                       
+                       if (!is_active){
+                               return false;
+                       }
+
+                       setting_windowstates = true;
+                       foreach (Form frm in mdi_child_list) {
+                               if (frm == form) {
+                                       continue;
+                               } else if (!frm.Visible){
+                                       continue;
+                               }
+                               if (frm.WindowState == FormWindowState.Maximized && is_active) {
+                                       maximize_this = true;   
+                                       if (((MdiWindowManager) frm.window_manager).was_minimized)
+                                               frm.WindowState = FormWindowState.Minimized;
+                                       else
+                                               frm.WindowState = FormWindowState.Normal;//
+                               }
+                       }
+                       if (maximize_this) {
+                               wm.was_minimized = form.window_state == FormWindowState.Minimized;
+                               form.WindowState = FormWindowState.Maximized;
+                       }
+                       SetParentText(false);
+                       
+                       XplatUI.RequestNCRecalc(ParentForm.Handle);
+                       XplatUI.RequestNCRecalc (Handle);
+
+                       SizeScrollBars ();
+
+                       setting_windowstates = false;
+
+                       return maximize_this;
                }
 
                internal int ChildrenCreated {
@@ -514,14 +681,48 @@ namespace System.Windows.Forms {
 
                internal Form ActiveMdiChild {
                        get {
+#if NET_2_0
+                               if (!ParentForm.Visible)
+                                       return null;
+#endif
                                if (Controls.Count < 1)
                                        return null;
-                               return (Form) Controls [0];
+                                       
+                               if (!ParentForm.IsHandleCreated)
+                                       return null;
+                               
+                               if (!ParentForm.has_been_visible)
+                                       return null;
+                                       
+                               if (!ParentForm.Visible)
+                                       return active_child;
+                               
+                               active_child = null;
+                               for (int i = 0; i < Controls.Count; i++) {
+                                       if (Controls [i].Visible) {
+                                               active_child = (Form) Controls [i];
+                                               break;
+                                       }
+                               }
+                               return active_child;
                        }
                        set {
                                ActivateChild (value);
                        }
                }
+               
+               internal void ActivateActiveMdiChild ()
+               {
+                       if (ParentForm.is_changing_visible_state)
+                               return;
+                               
+                       for (int i = 0; i < Controls.Count; i++) {
+                               if (Controls [i].Visible) {
+                                       ActivateChild ((Form) Controls [i]);
+                                       return;
+                               }
+                       }
+               }
        }
 }