2007-04-02 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Splitter.cs
index 17cfca1e8782bc50c07704c1cdea5df9fcad523e..677279fd28ff7c048487027899aca19088e67e27 100644 (file)
@@ -17,7 +17,7 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
 //
 // Authors:
 //     Peter Dennis Bartok     (pbartok@novell.com)
@@ -38,7 +38,11 @@ namespace System.Windows.Forms {
        [DefaultEvent("SplitterMoved")]
        [Designer("System.Windows.Forms.Design.SplitterDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
        [DefaultProperty("Dock")]
-       public class Splitter : Control, IMessageFilter {
+       public class Splitter : Control
+#if !NET_2_0
+       , IMessageFilter
+#endif
+       {
                #region Enums
                private enum DrawType {
                        Initial,
@@ -50,7 +54,8 @@ namespace System.Windows.Forms {
                #region Local Variables
                static private Cursor           splitter_ns;
                static private Cursor           splitter_we;
-               private BorderStyle             border_style;
+               // XXX this "new" shouldn't be here.  Control shouldn't define border_style as internal.
+               new private BorderStyle         border_style;
                private int                     min_extra;
                private int                     min_size;
                private int                     split_position;         // Current splitter position
@@ -63,25 +68,13 @@ namespace System.Windows.Forms {
                private SplitterEventArgs       sevent;                 // We cache the object, prevents fragmentation
                private int                     limit_min;              // The max we're allowed to move the splitter left/up
                private int                     limit_max;              // The max we're allowed to move the splitter right/down
+               private int                     split_requested;        // If the user requests a position before we have ever laid out the doc
                #endregion      // Local Variables
 
                #region Constructors
                static Splitter() {
-                       try {
-                               splitter_ns = new Cursor(typeof(Splitter), "SpliterNS.cur");
-                       }
-
-                       catch (System.IO.FileNotFoundException) {
-                               splitter_ns = Cursors.SizeNS;
-                       }
-
-                       try {
-                               splitter_we = new Cursor(typeof(Splitter), "SplitterWE.cur");
-                       }
-
-                       catch (System.IO.FileNotFoundException) {
-                               splitter_we = Cursors.SizeWE;
-                       }
+                       splitter_ns = Cursors.HSplit;
+                       splitter_we = Cursors.VSplit;
                }
 
                public Splitter() {
@@ -89,15 +82,17 @@ namespace System.Windows.Forms {
                        min_extra = 25;
                        min_size = 25;
                        split_position = -1;
+                       split_requested = -1;
                        splitter_size = 3;
                        horizontal = false;
                        sevent = new SplitterEventArgs(0, 0, 0, 0);
 
                        SetStyle(ControlStyles.Selectable, false);
                        Anchor = AnchorStyles.None;
+                       Dock = DockStyle.Left;
 
-                       Paint += new PaintEventHandler(PaintSplitter);
                        Layout += new LayoutEventHandler(LayoutSplitter);
+                       this.ParentChanged += new EventHandler(ReparentSplitter);
                        Cursor = splitter_we;
                }
                #endregion      // Constructors
@@ -153,25 +148,21 @@ namespace System.Windows.Forms {
                                border_style = value;
 
                                switch(value) {
-                                       case BorderStyle.FixedSingle: {
-                                               splitter_size = 4;      // We don't get motion events for 1px wide windows on X11. sigh.
-                                               break;
-                                       }
+                               case BorderStyle.FixedSingle:
+                                       splitter_size = 4;      // We don't get motion events for 1px wide windows on X11. sigh.
+                                       break;
 
-                                       case BorderStyle.Fixed3D: {
-                                               value = BorderStyle.None;
-                                               splitter_size = 3;
-                                               break;
-                                       }
+                               case BorderStyle.Fixed3D:
+                                       value = BorderStyle.None;
+                                       splitter_size = 3;
+                                       break;
 
-                                       case BorderStyle.None: {
-                                               splitter_size = 3;
-                                               break;
-                                       }
+                               case BorderStyle.None:
+                                       splitter_size = 3;
+                                       break;
 
-                                       default: {
-                                               throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for BorderStyle", value));
-                                       }
+                               default:
+                                       throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for BorderStyle", value));
                                }
 
                                base.InternalBorderStyle = value;
@@ -272,6 +263,7 @@ namespace System.Windows.Forms {
                [MWFCategory("Layout")]
                public int SplitPosition {
                        get {
+                               affected = AffectedControl;
                                if (affected == null) {
                                        return -1;
                                }
@@ -288,28 +280,26 @@ namespace System.Windows.Forms {
                        }
 
                        set {
-                               if (Capture || (affected == null)) {
-                                       return;
-                               }
+                               affected = AffectedControl;
 
-                               if (horizontal) {
-                                       affected.Height = value;
-                               } else {
-                                       affected.Width = value;
+                               if (affected == null) {
+                                       split_requested = value;
+                               }
+                               else {
+                                       if (horizontal) {
+                                               affected.Height = value;
+                                       } else {
+                                               affected.Width = value;
+                                       }
                                }
                        }
                }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public bool TabStop {
-                       get {
-                               return base.TabStop;
-                       }
-
-                       set {
-                               base.TabStop = value;
-                       }
+               public new bool TabStop {
+                       get { return base.TabStop; }
+                       set { base.TabStop = value; }
                }
 
                [Bindable(false)]
@@ -349,9 +339,11 @@ namespace System.Windows.Forms {
                #endregion      // Protected Instance Properties
 
                #region Public Instance Methods
+#if !NET_2_0
                public bool PreFilterMessage(ref Message m) {
                        return false;
                }
+#endif
 
                public override string ToString() {
                        return base.ToString () + String.Format(", MinExtra: {0}, MinSize: {1}", min_extra, min_size);
@@ -373,6 +365,11 @@ namespace System.Windows.Forms {
                        base.OnMouseDown (e);
 
                        // Only allow if we are set up properly
+                       if ((affected == null) || (filler == null)) {
+                               affected = AffectedControl;
+                               filler = FillerControl;
+                       }
+
                        if (affected == null || e.Button != MouseButtons.Left) {
                                return;
                        }
@@ -383,7 +380,7 @@ namespace System.Windows.Forms {
                        // Calculate limits
                        if (filler != null) {
                                if (horizontal) {
-                                       if (dock_style == DockStyle.Top) {
+                                       if (Dock == DockStyle.Top) {
                                                limit_min = affected.Bounds.Top + min_size;
                                                limit_max = filler.Bounds.Bottom - min_extra + this.bounds.Top - filler.Bounds.Top;
                                        } else {
@@ -391,7 +388,7 @@ namespace System.Windows.Forms {
                                                limit_max = affected.Bounds.Bottom - min_size - this.Height;
                                        }
                                } else {
-                                       if (dock_style == DockStyle.Left) {
+                                       if (Dock == DockStyle.Left) {
                                                limit_min = affected.Bounds.Left + min_size;
                                                limit_max = filler.Bounds.Right - min_extra + this.bounds.Left - filler.Bounds.Left;
                                        } else {
@@ -412,18 +409,18 @@ namespace System.Windows.Forms {
                                Console.WriteLine("Sizing limits: Min:{0}, Max:{1}", limit_min, limit_max);
                        #endif
 
-                       pt = PointToScreen(parent.PointToClient(new Point(e.X, e.Y)));
+                       pt = PointToScreen(Parent.PointToClient(new Point(e.X, e.Y)));
 
                        if (horizontal) {
                                split_position = pt.Y;
-                               if (dock_style == DockStyle.Top) {
+                               if (Dock == DockStyle.Top) {
                                        click_offset = e.Y;
                                } else {
                                        click_offset = -e.Y;
                                }
                        } else {
                                split_position = pt.X;
-                               if (dock_style == DockStyle.Left) {
+                               if (Dock == DockStyle.Left) {
                                        click_offset = e.X;
                                } else {
                                        click_offset = -e.X;
@@ -446,20 +443,34 @@ namespace System.Windows.Forms {
 
                        base.OnMouseMove (e);
 
-                       if (!Capture  || e.Button != MouseButtons.Left) {
+                       if (!Capture  || e.Button != MouseButtons.Left || affected == null) {
                                return;
                        }
 
                        // We need our mouse coordinates relative to our parent
-                       pt = PointToScreen(parent.PointToClient(new Point(e.X, e.Y)));
+                       pt = PointToScreen(Parent.PointToClient(new Point(e.X, e.Y)));
 
                        // Grab our new coordinates
                        prev_split_position = split_position;
-                       if (horizontal) {
-                               split_position = pt.Y;
-                       } else {
-                               split_position = pt.X;
-                       }
+
+                       int candidate = horizontal ? pt.Y : pt.X;
+
+                       // Enforce limit on what we send to the event
+                       if (candidate < limit_min)
+                               candidate = limit_min;
+                       else if (candidate > limit_max)
+                               candidate = limit_max;
+
+                       sevent.x = pt.X;
+                       sevent.y = pt.Y;
+                       sevent.split_x = horizontal ? 0 : candidate;
+                       sevent.split_y = horizontal ? candidate : 0;
+
+                       // Fire the event
+                       OnSplitterMoving(sevent);
+
+                       split_position = horizontal ? sevent.split_y : sevent.split_x;
+
                        // Enforce limits
                        if (split_position < limit_min) {
                                #if Debug
@@ -473,30 +484,12 @@ namespace System.Windows.Forms {
                                split_position = limit_max;
                        }
 
-                       // Don't waste cycles
-                       if (prev_split_position != split_position) {
-                               // Update our handle location
-                               DrawDragHandle(DrawType.Redraw);
-                       }
-
-                       // Prepare the event
-                       if (horizontal) {
-                               sevent.split_x = 0;
-                               sevent.split_y = split_position;
-                       } else {
-                               sevent.split_x = split_position;
-                               sevent.split_y = 0;
-                       }
-
-                       sevent.x = pt.X;
-                       sevent.y = pt.Y;
-
-                       // Fire the event
-                       OnSplitterMoving(sevent);
+                       // Update our handle location
+                       DrawDragHandle(DrawType.Redraw);
                }
 
                protected override void OnMouseUp(MouseEventArgs e) {
-                       if (!Capture || e.Button != MouseButtons.Left) {
+                       if (!Capture || e.Button != MouseButtons.Left || affected == null) {
                                base.OnMouseUp (e);
                                return;
                        }
@@ -541,22 +534,30 @@ namespace System.Windows.Forms {
                }
 
                protected virtual void OnSplitterMoved(SplitterEventArgs sevent) {
-                       if (SplitterMoved != null) {
-                               SplitterMoved(this, sevent);
-                       }
+                       SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovedEvent]);
+                       if (eh != null)
+                               eh (this, sevent);
                }
 
                protected virtual void OnSplitterMoving(SplitterEventArgs sevent) {
-                       if (SplitterMoving != null) {
-                               SplitterMoving(this, sevent);
-                       }
+                       SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovingEvent]);
+                       if (eh != null)
+                               eh (this, sevent);
                }
 
                protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
                        // enforce our width / height
                        if (horizontal) {
+                               splitter_size = height;
+                               if (splitter_size < 1) {
+                                       splitter_size = 3;
+                               }
                                base.SetBoundsCore (x, y, width, splitter_size, specified);
                        } else {
+                               splitter_size = width;
+                               if (splitter_size < 1) {
+                                       splitter_size = 3;
+                               }
                                base.SetBoundsCore (x, y, splitter_size, height, specified);
                        }
                }
@@ -565,40 +566,28 @@ namespace System.Windows.Forms {
                #region Private Properties and Methods
                private Control AffectedControl {
                        get {
-                               if (parent == null) {
+                               if (Parent == null)
                                        return null;
-                               }
 
                                // Doc says the first control preceeding us in the zorder 
-                               for (int i = parent.Controls.GetChildIndex(this) + 1; i < parent.Controls.Count; i++) {
-                                       switch(this.Dock) {
-                                               case DockStyle.Top: {
-                                                       if (Top == parent.Controls[i].Bottom) {
-                                                               return parent.Controls[i];
-                                                       }
-                                                       break;
-                                               }
-
-                                               case DockStyle.Bottom: {
-                                                       if (Bottom == parent.Controls[i].Top) {
-                                                               return parent.Controls[i];
-                                                       }
-                                                       break;
-                                               }
-
-                                               case DockStyle.Left: {
-                                                       if (Left == parent.Controls[i].Right) {
-                                                               return parent.Controls[i];
-                                                       }
-                                                       break;
-                                               }
-
-                                               case DockStyle.Right: {
-                                                       if (Right == parent.Controls[i].Left) {
-                                                               return parent.Controls[i];
-                                                       }
-                                                       break;
-                                               }
+                               for (int i = Parent.Controls.GetChildIndex(this) + 1; i < Parent.Controls.Count; i++) {
+                                       switch (Dock) {
+                                       case DockStyle.Top:
+                                               if (Top == Parent.Controls[i].Bottom)
+                                                       return Parent.Controls[i];
+                                               break;
+                                       case DockStyle.Bottom:
+                                               if (Bottom == Parent.Controls[i].Top)
+                                                       return Parent.Controls[i];
+                                               break;
+                                       case DockStyle.Left:
+                                               if (Left == Parent.Controls[i].Right)
+                                                       return Parent.Controls[i];
+                                               break;
+                                       case DockStyle.Right:
+                                               if (Right == Parent.Controls[i].Left)
+                                                       return Parent.Controls[i];
+                                               break;
                                        }
                                }
                                return null;
@@ -607,14 +596,13 @@ namespace System.Windows.Forms {
 
                private Control FillerControl {
                        get {
-                               if (parent == null) {
+                               if (Parent == null)
                                        return null;
-                               }
 
                                // Doc says the first control preceeding us in the zorder 
-                               for (int i = parent.Controls.GetChildIndex(this) - 1; i >= 0; i--) {
-                                       if (parent.Controls[i].Dock == DockStyle.Fill) {
-                                               return parent.Controls[i];
+                               for (int i = Parent.Controls.GetChildIndex(this) - 1; i >= 0; i--) {
+                                       if (Parent.Controls[i].Dock == DockStyle.Fill) {
+                                               return Parent.Controls[i];
                                        }
                                }
                                return null;
@@ -623,27 +611,34 @@ namespace System.Windows.Forms {
 
                private int CalculateSplitPosition() {
                        if (horizontal) {
-                               if (dock_style == DockStyle.Top) {
-                                       return split_position;
-                               } else {
+                               if (Dock == DockStyle.Top)
+                                       return split_position - affected.Top;
+                               else
                                        return affected.Bottom - split_position - splitter_size;
-                               }
                        } else {
-                               if (dock_style == DockStyle.Left) {
-                                       return split_position;
-                               } else {
+                               if (Dock == DockStyle.Left)
+                                       return split_position - affected.Left;
+                               else
                                        return affected.Right - split_position - splitter_size;
-                               }
                        }
                }
 
-               private void PaintSplitter(object sender, PaintEventArgs e) {
+               internal override void OnPaintInternal (PaintEventArgs e) {
                        e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(this.BackColor), e.ClipRectangle);
                }
 
                private void LayoutSplitter(object sender, LayoutEventArgs e) {
                        affected = AffectedControl;
                        filler = FillerControl;
+                       if (split_requested != -1) {
+                               SplitPosition = split_requested;
+                               split_requested = -1;
+                       }
+               }
+
+               private void ReparentSplitter(object sender, EventArgs e) {
+                       affected = null;
+                       filler = null;
                }
 
                private void DrawDragHandle(DrawType type) {
@@ -651,33 +646,29 @@ namespace System.Windows.Forms {
                        Rectangle       current;
 
                        if (horizontal) {
-                               prev = new Rectangle(0, prev_split_position - click_offset + 1, Width, 0);
-                               current = new Rectangle(0, split_position - click_offset + 1, Width, 0);
+                               prev = new Rectangle(Location.X, prev_split_position - click_offset + 1, Width, 0);
+                               current = new Rectangle(Location.X, split_position - click_offset + 1, Width, 0);
                        } else {
-                               prev = new Rectangle(prev_split_position - click_offset + 1, 0, 0, Height);
-                               current = new Rectangle(split_position - click_offset + 1, 0, 0, Height);
+                               prev = new Rectangle(prev_split_position - click_offset + 1, Location.Y, 0, Height);
+                               current = new Rectangle(split_position - click_offset + 1, Location.Y, 0, Height);
                        }
 
                        switch(type) {
-                               case DrawType.Initial: {
-                                       XplatUI.DrawReversibleRectangle(Parent.window.Handle, current, 3);
-                                       return;
-                               }
-
-                               case DrawType.Redraw: {
-                                       if (prev.X == current.X && prev.Y == current.Y) {
-                                               return;
-                                       }
+                       case DrawType.Initial:
+                               XplatUI.DrawReversibleRectangle(Parent.window.Handle, current, 3);
+                               return;
 
-                                       XplatUI.DrawReversibleRectangle(Parent.window.Handle, prev, 3);
-                                       XplatUI.DrawReversibleRectangle(Parent.window.Handle, current, 3);
+                       case DrawType.Redraw:
+                               if (prev.X == current.X && prev.Y == current.Y)
                                        return;
-                               }
 
-                               case DrawType.Finish: {
-                                       XplatUI.DrawReversibleRectangle(Parent.window.Handle, prev, 3);
-                                       return;
-                               }
+                               XplatUI.DrawReversibleRectangle(Parent.window.Handle, prev, 3);
+                               XplatUI.DrawReversibleRectangle(Parent.window.Handle, current, 3);
+                               return;
+
+                       case DrawType.Finish:
+                               XplatUI.DrawReversibleRectangle(Parent.window.Handle, current, 3);
+                               return;
                        }
                }
                #endregion      // Private Properties and Methods
@@ -685,50 +676,93 @@ namespace System.Windows.Forms {
                #region Events
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler BackgroundImageChanged;
+               public new event EventHandler BackgroundImageChanged {
+                       add { base.BackgroundImageChanged += value; }
+                       remove { base.BackgroundImageChanged -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler Enter;
+               public new event EventHandler Enter {
+                       add { base.Enter += value; }
+                       remove { base.Enter -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler FontChanged;
+               public new event EventHandler FontChanged {
+                       add { base.FontChanged += value; }
+                       remove { base.FontChanged -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler ForeColorChanged;
+               public new event EventHandler ForeColorChanged {
+                       add { base.ForeColorChanged += value; }
+                       remove { base.ForeColorChanged -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler ImeModeChanged;
+               public new event EventHandler ImeModeChanged {
+                       add { base.ImeModeChanged += value; }
+                       remove { base.ImeModeChanged -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event KeyEventHandler KeyDown;
+               public new event KeyEventHandler KeyDown {
+                       add { base.KeyDown += value; }
+                       remove { base.KeyDown -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event KeyPressEventHandler KeyPress;
+               public new event KeyPressEventHandler KeyPress {
+                       add { base.KeyPress += value; }
+                       remove { base.KeyPress -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event KeyEventHandler KeyUp;
+               public new event KeyEventHandler KeyUp {
+                       add { base.KeyUp += value; }
+                       remove { base.KeyUp -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler Leave;
+               public new event EventHandler Leave {
+                       add { base.Leave += value; }
+                       remove { base.Leave -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler TabStopChanged;
+               public new event EventHandler TabStopChanged {
+                       add { base.TabStopChanged += value; }
+                       remove { base.TabStopChanged -= value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
-               public new event EventHandler TextChanged;
+               public new event EventHandler TextChanged {
+                       add { base.TextChanged += value; }
+                       remove { base.TextChanged -= value; }
+               }
+
+               static object SplitterMovedEvent = new object ();
+               static object SplitterMovingEvent = new object ();
 
-               public event SplitterEventHandler SplitterMoved;
-               public event SplitterEventHandler SplitterMoving;
+               public event SplitterEventHandler SplitterMoved {
+                       add { Events.AddHandler (SplitterMovedEvent, value); }
+                       remove { Events.RemoveHandler (SplitterMovedEvent, value); }
+               }
+
+               public event SplitterEventHandler SplitterMoving {
+                       add { Events.AddHandler (SplitterMovingEvent, value); }
+                       remove { Events.RemoveHandler (SplitterMovingEvent, value); }
+               }
                #endregion      // Events
        }
 }