* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ScrollBar.cs
index 8dab1dfe0da151161ee29bca542193314f226275..bbae6315d5b16e77985c3ee7e306033ec7b0912b 100644 (file)
@@ -48,7 +48,7 @@ namespace System.Windows.Forms
                private int large_change;
                private int small_change;
                internal int scrollbutton_height;
-               internal int scrollbutton_width;                
+               internal int scrollbutton_width;
                private ScrollBars type;
                private Rectangle first_arrow_area = new Rectangle ();          // up or left
                private Rectangle second_arrow_area = new Rectangle ();         // down or right
@@ -62,17 +62,14 @@ namespace System.Windows.Forms
                private float pixel_per_pos = 0;
                private Timer timer = new Timer ();
                private TimerType timer_type;
-               private int thumb_pixel_click_move;
-               private int thumb_pixel_click_move_prev;
                private int thumb_size = 40;
                private const int thumb_min_size = 8;
                private const int thumb_notshown_size = 40;
                internal bool vert;
-               private int lastclick_pos;      // Position of the last button-down event
-               private int lastclick_pos_thumb;      // Position of the last button-down event relative to the thumb           
-               private bool outside_thumbarea_right = false;
-               private bool outside_thumbarea_left = false;
-
+               internal bool implicit_control;
+               private int lastclick_pos;              // Position of the last button-down event
+               private int lastclick_pos_thumb;        // Position of the last button-down event relative to the thumb
+               private int thumbclick_offset;          // Position of the last button-down event relative to the thumb edge
                private Rectangle dirty;
 
                internal ThumbMoving thumb_moving = ThumbMoving.None;
@@ -85,7 +82,7 @@ namespace System.Windows.Forms
                        HoldThumbArea,
                        RepeatThumbArea
                }
-               
+
                internal enum ThumbMoving
                {
                        None,
@@ -94,57 +91,93 @@ namespace System.Windows.Forms
                }
 
                #region events
-               
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler BackColorChanged;
-               
+               public new event EventHandler BackColorChanged {
+                       add { base.BackColorChanged += value; }
+                       remove { base.BackColorChanged -= value; }
+               }
+
                [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 Click;
-               
+               public new event EventHandler Click {
+                       add { base.Click += value; }
+                       remove { base.Click -= value; }
+               }
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler DoubleClick;
-               
+               public new event EventHandler DoubleClick {
+                       add { base.DoubleClick += value; }
+                       remove { base.DoubleClick -= 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 MouseEventHandler MouseDown;
-               
+               public new event MouseEventHandler MouseDown {
+                       add { base.MouseDown += value; }
+                       remove { base.MouseDown -= value; }
+               }
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event MouseEventHandler MouseMove;
-               
+               public new event MouseEventHandler MouseMove {
+                       add { base.MouseMove += value; }
+                       remove { base.MouseMove -= value; }
+               }
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event MouseEventHandler MouseUp;
-               
+               public new event MouseEventHandler MouseUp {
+                       add { base.MouseUp += value; }
+                       remove { base.MouseUp -= value; }
+               }
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event PaintEventHandler Paint;
-               
+               public new event PaintEventHandler Paint {
+                       add { base.Paint += value; }
+                       remove { base.Paint -= value; }
+               }
+
                public event ScrollEventHandler Scroll;
-               
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler TextChanged;
-               
+               public new event EventHandler TextChanged {
+                       add { base.TextChanged += value; }
+                       remove { base.TextChanged -= value; }
+               }
+
                public event EventHandler ValueChanged;
                #endregion Events
 
@@ -163,7 +196,8 @@ namespace System.Windows.Forms
                        base.MouseMove += new MouseEventHandler (OnMouseMoveSB);
                        base.Resize += new EventHandler (OnResizeSB);
                        base.TabStop = false;
-                        
+                       base.cursor = Cursors.Default;
+
                        SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
                }
 
@@ -209,10 +243,6 @@ namespace System.Windows.Forms
                        set {
                                if (base.BackColor == value)
                                        return;
-
-                               if (BackColorChanged != null)
-                                       BackColorChanged (this, EventArgs.Empty);
-
                                base.BackColor = value;
                                Refresh ();
                        }
@@ -227,9 +257,6 @@ namespace System.Windows.Forms
                                if (base.BackgroundImage == value)
                                        return;
 
-                               if (BackgroundImageChanged != null)
-                                       BackgroundImageChanged (this, EventArgs.Empty);
-
                                base.BackgroundImage = value;
                        }
                }
@@ -253,9 +280,6 @@ namespace System.Windows.Forms
                                if (base.Font.Equals (value))
                                        return;
 
-                               if (FontChanged != null)
-                                       FontChanged (this, EventArgs.Empty);
-
                                base.Font = value;
                        }
                }
@@ -269,9 +293,6 @@ namespace System.Windows.Forms
                                if (base.ForeColor == value)
                                        return;
 
-                               if (ForeColorChanged != null)
-                                       ForeColorChanged (this, EventArgs.Empty);
-
                                base.ForeColor = value;
                                Refresh ();
                        }
@@ -286,9 +307,6 @@ namespace System.Windows.Forms
                                if (base.ImeMode == value)
                                        return;
 
-                               if (ImeModeChanged != null)
-                                       ImeModeChanged (this, EventArgs.Empty);
-
                                base.ImeMode = value;
                        }
                }
@@ -314,7 +332,7 @@ namespace System.Windows.Forms
                                        // so we need to recalculate it.
                                        CalcThumbArea ();
                                        UpdatePos (Value, true);
-                                       Refresh ();
+                                       InvalidateDirty ();
                                }
                        }
                }
@@ -327,7 +345,7 @@ namespace System.Windows.Forms
                        set {
                                if (maximum == value)
                                        return;
-                                       
+
                                maximum = value;
 
                                if (maximum < minimum)
@@ -337,7 +355,48 @@ namespace System.Windows.Forms
                                // so we need to recalculate it.
                                CalcThumbArea ();
                                UpdatePos (Value, true);
-                               Refresh ();
+                               InvalidateDirty ();
+                       }
+               }
+
+               internal void SetValues (int maximum, int large_change)
+               {
+                       SetValues (-1, maximum, -1, large_change);
+               }
+
+               internal void SetValues (int minimum, int maximum, int small_change, int large_change)
+               {
+                       bool update = false;
+
+                       if (-1 != minimum && this.minimum != minimum) {
+                               this.minimum = minimum;
+
+                               if (minimum > this.maximum)
+                                       this.maximum = minimum;
+                               update = true;
+                       }
+
+                       if (-1 != maximum && this.maximum != maximum) {
+                               this.maximum = maximum;
+
+                               if (maximum < this.minimum)
+                                       this.minimum = maximum;
+                               update = true;
+                       }
+
+                       if (-1 != small_change && this.small_change != small_change) {
+                               this.small_change = small_change;
+                       }
+
+                       if (this.large_change != large_change) {
+                               this.large_change = large_change;
+                               update = true;
+                       }
+
+                       if (update) {
+                               CalcThumbArea ();
+                               UpdatePos (Value, true);
+                               InvalidateDirty ();
                        }
                }
 
@@ -349,7 +408,7 @@ namespace System.Windows.Forms
                        set {
                                if (minimum == value)
                                        return;
-                                       
+
                                minimum = value;
 
                                if (minimum > maximum)
@@ -359,7 +418,7 @@ namespace System.Windows.Forms
                                // so we need to recalculate it.
                                CalcThumbArea ();
                                UpdatePos (Value, true);
-                               Refresh ();
+                               InvalidateDirty ();
                        }
                }
 
@@ -374,7 +433,7 @@ namespace System.Windows.Forms
                                if (small_change != value) {
                                        small_change = value;
                                        UpdatePos (Value, true);
-                                       Refresh ();
+                                       InvalidateDirty ();
                                }
                        }
                }
@@ -409,13 +468,13 @@ namespace System.Windows.Forms
 
                                        OnValueChanged (EventArgs.Empty);
 
-                                       ClearDirty ();
-                                       
                                        if (IsHandleCreated) {
-                                               UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), false);
+                                               Rectangle thumb_rect = thumb_pos;
+
+                                               UpdateThumbPos ((vert ? thumb_area.Y : thumb_area.X) + (int)(((float)(position - minimum)) * pixel_per_pos), false, false);
+
+                                               MoveThumb (thumb_rect, vert ? thumb_pos.Y : thumb_pos.X);
                                        }
-                                       
-                                       InvalidateDirty ();
                                }
                        }
                }
@@ -423,7 +482,7 @@ namespace System.Windows.Forms
                #endregion //Public Properties
 
                #region Public Methods
-               
+
                protected override void OnEnabledChanged (EventArgs e)
                {
                        base.OnEnabledChanged (e);
@@ -435,25 +494,25 @@ namespace System.Windows.Forms
 
                        Refresh ();
                }
-               
+
                protected override void OnHandleCreated (System.EventArgs e)
                {
-                       base.OnHandleCreated (e);               
+                       base.OnHandleCreated (e);
 
                        CalcButtonSizes ();
-                       CalcThumbArea ();                       
-                       UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), false);                    
+                       CalcThumbArea ();
+                       UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), true, false);
                }
 
                protected virtual void OnScroll (ScrollEventArgs event_args)
                {
                        if (Scroll == null)
                                return;
-                               
+
                        if (event_args.NewValue < Minimum) {
                                event_args.NewValue = Minimum;
                        }
-                       
+
                        if (event_args.NewValue > Maximum) {
                                event_args.NewValue = Maximum;
                        }
@@ -461,10 +520,21 @@ namespace System.Windows.Forms
                        Scroll (this, event_args);
                }
 
+               private void SendWMScroll(ScrollBarCommands cmd) {
+                       if ((parent != null) && parent.IsHandleCreated) {
+                               if (vert) {
+                                       XplatUI.SendMessage(parent.Handle, Msg.WM_VSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle);
+                               } else {
+                                       XplatUI.SendMessage(parent.Handle, Msg.WM_HSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle);
+                               }
+                       }
+               }
+
                protected virtual void OnValueChanged (EventArgs e)
                {
-                       if (ValueChanged != null)
+                       if (ValueChanged != null) {
                                ValueChanged (this, e);
+                       }
                }
 
                public override string ToString()
@@ -480,41 +550,21 @@ namespace System.Windows.Forms
 
                protected override void WndProc (ref Message m)
                {
-                       switch ((Msg) m.Msg)
-                       {
-                               case Msg.WM_PAINT:
-                               {
-                                       PaintEventArgs  paint_event;
-
-                                       paint_event = XplatUI.PaintEventStart (Handle, true);
-                                       OnPaintSB (paint_event);
-                                       XplatUI.PaintEventEnd (Handle, true);
-                                       return;
-                               }
-
-                               case Msg.WM_ERASEBKGND:
-                                       m.Result = (IntPtr) 1; /// Disable background painting to avoid flickering
-                                       return;
-
-                               default:
-                                       break;
-                       }
-
                        base.WndProc (ref m);
                }
 
                #endregion //Public Methods
 
                #region Private Methods
-               
+
                private void CalcButtonSizes ()
-               {               
+               {
                        if (vert) {
                                if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2)
                                        scrollbutton_height = Height /2;
                                else
                                        scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
-                               
+
                        } else {
                                if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2)
                                        scrollbutton_width = Width /2;
@@ -522,7 +572,7 @@ namespace System.Windows.Forms
                                        scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
                        }
                }
-                               
+
                private void CalcThumbArea ()
                {
                        // Thumb area
@@ -537,11 +587,11 @@ namespace System.Windows.Forms
                                        thumb_size = 0;
                                else {
                                        double per =  ((double) this.LargeChange / (double)((1 + maximum - minimum)));
-                                       thumb_size = 1 + (int) (thumb_area.Height * per);                                       
-                                       
+                                       thumb_size = 1 + (int) (thumb_area.Height * per);
+
                                        if (thumb_size < thumb_min_size)
                                                thumb_size = thumb_min_size;
-                               }                               
+                               }
 
                                pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
 
@@ -550,70 +600,64 @@ namespace System.Windows.Forms
                                thumb_area.Y = 0;
                                thumb_area.X = scrollbutton_width;
                                thumb_area.Height = Height;
-                               thumb_area.Width = Width - scrollbutton_width -  scrollbutton_width;    
-                               
+                               thumb_area.Width = Width - scrollbutton_width -  scrollbutton_width;
+
                                if (Width < thumb_notshown_size)
                                        thumb_size = 0;
                                else {
                                        double per =  ((double) this.LargeChange / (double)((1 + maximum - minimum)));
                                        thumb_size = 1 + (int) (thumb_area.Width * per);
-                                       
+
                                        if (thumb_size < thumb_min_size)
                                                thumb_size = thumb_min_size;
                                }
-                               
+
                                pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
                        }
                }
 
                private void LargeIncrement ()
-               {                       
+               {
                        ScrollEventArgs event_args;
-                       int pos = position + large_change;
-                       
+                       int pos = Math.Min (Maximum - large_change + 1, position + large_change);
+
                        event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos);
-                       OnScroll (event_args);                          
-                       pos = event_args.NewValue;                      
-                       
-                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
-                       OnScroll (event_args);          
-                       pos = event_args.NewValue;                      
+                       OnScroll (event_args);
+                       Value = event_args.NewValue;
 
-                       UpdatePos (pos, true);
+                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+                       OnScroll (event_args);
+                       Value = event_args.NewValue;
                }
 
                private void LargeDecrement ()
-               {                       
+               {
                        ScrollEventArgs event_args;
-                       int pos = position - large_change;
-                       
+                       int pos = Math.Max (Minimum, position - large_change);
+
                        event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos);
                        OnScroll (event_args);
-                       pos = event_args.NewValue;                      
-                       
-                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
+                       Value = event_args.NewValue;
+
+                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
                        OnScroll (event_args);
-                       pos = event_args.NewValue;
-                       
+                       Value = event_args.NewValue;
+               }
 
-                       UpdatePos (pos, true);
-               }               
-               
                private void OnResizeSB (Object o, EventArgs e)
-               {                       
+               {
                        if (Width <= 0 || Height <= 0)
                                return;
-                       
+
                        CalcButtonSizes ();
                        CalcThumbArea ();
                        UpdatePos (position, true);
+
+                       Refresh ();
                }
 
-               private void OnPaintSB (PaintEventArgs pevent)
+               internal override void OnPaintInternal (PaintEventArgs pevent)
                {
-                       if (Paint != null) {
-                               Paint (this, pevent);
-                       }
                        ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this);
                }
 
@@ -629,13 +673,15 @@ namespace System.Windows.Forms
 
                        case TimerType.RepeatButton:
                        {
-                               if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed &&
-                                               position != Minimum)
+                               if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Minimum) {
                                        SmallDecrement();
+                                       SendWMScroll(ScrollBarCommands.SB_LINEUP);
+                               }
 
-                               if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed &&
-                                       position != Maximum)
+                               if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Maximum) {
                                        SmallIncrement();
+                                       SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
+                               }
 
                                break;
                        }
@@ -652,16 +698,16 @@ namespace System.Windows.Forms
                                pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y));
                                thumb_area_screen.X = pnt_screen.X;
                                thumb_area_screen.Y = pnt_screen.Y;
-                               
-                               if (thumb_area_screen.Contains (MousePosition) == false) {                                      
+
+                               if (thumb_area_screen.Contains (MousePosition) == false) {
                                        timer.Enabled = false;
                                        thumb_moving = ThumbMoving.None;
                                        DirtyThumbArea ();
                                        InvalidateDirty ();
-                               }                               
-                               
+                               }
+
                                pnt = PointToClient (MousePosition);
-                               
+
                                if (vert)
                                        lastclick_pos = pnt.Y;
                                else
@@ -669,25 +715,28 @@ namespace System.Windows.Forms
 
                                if (thumb_moving == ThumbMoving.Forward) {
                                        if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) ||
-                                               (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
-                                               (thumb_area.Contains (pnt) == false)){
-                                               timer.Enabled = false;                                          
+                                          (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
+                                          (thumb_area.Contains (pnt) == false)) {
+                                               timer.Enabled = false;
                                                thumb_moving = ThumbMoving.None;
-                                               Refresh ();                     
+                                               Refresh ();
                                                return;
                                        } else {
                                                LargeIncrement ();
-                               }
-                               }
-                               else
+                                               SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
+                                       }
+                               } else {
                                        if ((vert && (thumb_pos.Y < lastclick_pos)) ||
-                                               (!vert && (thumb_pos.X  < lastclick_pos))){
+                                          (!vert && (thumb_pos.X  < lastclick_pos))){
                                                timer.Enabled = false;
                                                thumb_moving = ThumbMoving.None;
-                                               Refresh ();                                             
+                                               SendWMScroll(ScrollBarCommands.SB_PAGEUP);
+                                               Refresh ();
                                        } else {
                                                LargeDecrement ();
+                                               SendWMScroll(ScrollBarCommands.SB_PAGEUP);
                                        }
+                               }
 
                                break;
                        }
@@ -696,14 +745,86 @@ namespace System.Windows.Forms
                        }
 
                        InvalidateDirty ();
-               }               
+               }
+
+               private void MoveThumb (Rectangle original_thumbpos, int value)
+               {
+                       /* so, the reason this works can best be
+                        * described by the following 1 dimensional
+                        * pictures
+                        *
+                        * say you have a scrollbar thumb positioned
+                        * thusly:
+                        *
+                        * <---------------------|          |------------------------------>
+                        *
+                        * and you want it to end up looking like this:
+                        *
+                        * <-----------------------------|          |---------------------->
+                        *
+                        * that can be done with the scrolling api by
+                        * extending the rectangle to encompass both
+                        * positions:
+                        *
+                        *               start of range          end of range
+                        *                       \                  /
+                        * <---------------------|          |-------|---------------------->
+                        *
+                        * so, we end up scrolling just this little region:
+                        *
+                        *                       |          |-------|
+                        *
+                        * and end up with       ********|          |
+                        *
+                        * where ****** is space that is automatically
+                        * redrawn.
+                        *
+                        * It's clear that in both cases (left to
+                        * right, right to left) we need to extend the
+                        * size of the scroll rectangle to encompass
+                        * both.  In the right to left case, we also
+                        * need to decrement the X coordinate.
+                        *
+                        * We call Update after scrolling to make sure
+                        * there's no garbage left in the window to be
+                        * copied again if we're called before the
+                        * paint events have been handled.
+                        *
+                        */
+                       int delta;
+
+                       if (vert) {
+                               delta = value - original_thumbpos.Y;
+
+                               if (delta < 0) {
+                                       original_thumbpos.Y += delta;
+                                       original_thumbpos.Height -= delta;
+                               }
+                               else {
+                                       original_thumbpos.Height += delta;
+                               }
+
+                               XplatUI.ScrollWindow (Handle, original_thumbpos, 0, delta, false);
+                       }
+                       else {
+                               delta = value - original_thumbpos.X;
+
+                               if (delta < 0) {
+                                       original_thumbpos.X += delta;
+                                       original_thumbpos.Width -= delta;
+                               }
+                               else {
+                                       original_thumbpos.Width += delta;
+                               }
+
+                               XplatUI.ScrollWindow (Handle, original_thumbpos, delta, 0, false);
+                       }
+
+                       Update ();
+               }
 
                private void OnMouseMoveSB (object sender, MouseEventArgs e)
                {
-                       if (MouseMove != null) {
-                               MouseMove (this, e);
-                       }
-                               
                        if (Enabled == false || thumb_size == 0)
                                return;
 
@@ -711,100 +832,65 @@ namespace System.Windows.Forms
                                if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
                                        firstbutton_state = ButtonState.Normal;
                                        Invalidate (first_arrow_area);
+                                       Update();
                                        return;
                                } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
                                        firstbutton_state = ButtonState.Pushed;
                                        Invalidate (first_arrow_area);
+                                       Update();
                                        return;
                                }
                        } else if (secondbutton_pressed) {
                                if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
                                        secondbutton_state = ButtonState.Normal;
                                        Invalidate (second_arrow_area);
+                                       Update();
                                        return;
                                } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
                                        secondbutton_state = ButtonState.Pushed;
                                        Invalidate (second_arrow_area);
+                                       Update();
                                        return;
                                }
                        } else if (thumb_pressed == true) {
-                               int pixel_pos;
-
                                if (vert) {
+                                       int thumb_edge = e.Y - thumbclick_offset;
 
-                                       int mouse_click = e.Y;
-                                       int outside_curpos = thumb_area.Y + thumb_area.Height - thumb_size + lastclick_pos_thumb;
-                                       
-                                       
-                                       if (mouse_click > thumb_area.Y + thumb_area.Height) {
-                                               outside_thumbarea_right = true;
-                                               mouse_click = thumb_area.Y + thumb_area.Height;
-                                       }
+                                       if (thumb_edge < thumb_area.Y)
+                                               thumb_edge = thumb_area.Y;
+                                       else if (thumb_edge > thumb_area.Bottom - thumb_size)
+                                               thumb_edge = thumb_area.Bottom - thumb_size;
 
-                                       if (mouse_click < thumb_area.Y) {
-                                               outside_thumbarea_left = true;
-                                               mouse_click = thumb_area.Y;
-                                       }
+                                       if (thumb_edge != thumb_pos.Y) {
+                                               Rectangle thumb_rect = thumb_pos;
 
-                                       if (outside_thumbarea_right && mouse_click < outside_curpos) {
-                                               outside_thumbarea_right = false;
-                                               thumb_pixel_click_move_prev =
-                                               thumb_pixel_click_move = outside_curpos;
-                                       }
+                                               UpdateThumbPos (thumb_edge, false, true);
 
-                                       if (outside_thumbarea_left && mouse_click > thumb_area.Y + lastclick_pos_thumb) {
-                                               outside_thumbarea_left = false;
-                                               thumb_pixel_click_move_prev =
-                                               thumb_pixel_click_move = thumb_area.Y + lastclick_pos_thumb;
-                                       }
+                                               MoveThumb (thumb_rect, thumb_pos.Y);
 
-                                       if (outside_thumbarea_right == false && outside_thumbarea_left == false) {
-                                               pixel_pos = thumb_pos.Y + (thumb_pixel_click_move - thumb_pixel_click_move_prev);
-                                               thumb_pixel_click_move_prev = thumb_pixel_click_move;
-                                               thumb_pixel_click_move = mouse_click;
-                                               
-                                               UpdateThumbPos (pixel_pos, true);
                                                OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
                                        }
+                                       SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
+                               } else {
+                                       int thumb_edge = e.X - thumbclick_offset;
 
-                               }
-                               else {
-                                       int mouse_click = e.X;
-                                       int outside_curpos = thumb_area.X + thumb_area.Width - thumb_size + lastclick_pos_thumb;
-                                                                               
-                                       if (mouse_click >  thumb_area.X + thumb_area.Width) {
-                                               outside_thumbarea_right = true;
-                                               mouse_click = thumb_area.X + thumb_area.Width;
-                                       }
+                                       if (thumb_edge < thumb_area.X)
+                                               thumb_edge = thumb_area.X;
+                                       else if (thumb_edge > thumb_area.Right - thumb_size)
+                                               thumb_edge = thumb_area.Right - thumb_size;
 
-                                       if (mouse_click <  thumb_area.X) {
-                                               outside_thumbarea_left = true;
-                                               mouse_click = thumb_area.X;
-                                       }
+                                       if (thumb_edge != thumb_pos.X) {
+                                               Rectangle thumb_rect = thumb_pos;
 
-                                       if (outside_thumbarea_right && mouse_click < outside_curpos) {
-                                               outside_thumbarea_right = false;
-                                               thumb_pixel_click_move_prev =
-                                               thumb_pixel_click_move = outside_curpos;
-                                       }
+                                               UpdateThumbPos (thumb_edge, false, true);
 
-                                       if (outside_thumbarea_left && mouse_click > thumb_area.X + lastclick_pos_thumb) {
-                                               outside_thumbarea_left = false;
-                                               thumb_pixel_click_move_prev =
-                                               thumb_pixel_click_move = thumb_area.X + lastclick_pos_thumb;
-                                       }
+                                               MoveThumb (thumb_rect, thumb_pos.X);
 
-                                       if (outside_thumbarea_right == false && outside_thumbarea_left == false) {
-                                               pixel_pos = thumb_pos.X + (thumb_pixel_click_move - thumb_pixel_click_move_prev);
-                                               thumb_pixel_click_move_prev = thumb_pixel_click_move;
-                                               thumb_pixel_click_move = mouse_click;
-                                               UpdateThumbPos (pixel_pos, true);                                               
                                                OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
                                        }
-
+                                       SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
                                }
 
-                               Refresh ();
                        }
 
                }
@@ -812,21 +898,16 @@ namespace System.Windows.Forms
                private void OnMouseDownSB (object sender, MouseEventArgs e)
                {
                        ClearDirty ();
-                       
-                       if (e.Button == MouseButtons.Right) {
-                               if (MouseDown != null) {
-                                       MouseDown (this, e);
-                               }
-                       }
-                       
+
                        if (Enabled == false)
                                return;
 
                        if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) {
-                               this.Capture = true;                            
+                               SendWMScroll(ScrollBarCommands.SB_LINEUP);
                                firstbutton_state = ButtonState.Pushed;
                                firstbutton_pressed = true;
                                Invalidate (first_arrow_area);
+                               Update();
                                if (!timer.Enabled) {
                                        SetHoldButtonClickTimer ();
                                        timer.Enabled = true;
@@ -834,10 +915,11 @@ namespace System.Windows.Forms
                        }
 
                        if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) {
-                               this.Capture = true;                            
+                               SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
                                secondbutton_state = ButtonState.Pushed;
                                secondbutton_pressed = true;
                                Invalidate (second_arrow_area);
+                               Update();
                                if (!timer.Enabled) {
                                        SetHoldButtonClickTimer ();
                                        timer.Enabled = true;
@@ -846,16 +928,14 @@ namespace System.Windows.Forms
 
                        if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) {
                                thumb_pressed = true;
-                               this.Capture = true;
+                               SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
                                if (vert) {
-                                       lastclick_pos_thumb = e.Y - thumb_pos.Y;
-                                       lastclick_pos = e.Y;                                    
-                                       thumb_pixel_click_move_prev = thumb_pixel_click_move = e.Y;
+                                       thumbclick_offset = e.Y - thumb_pos.Y;
+                                       lastclick_pos = e.Y;
                                }
                                else {
-                                       lastclick_pos_thumb = e.X - thumb_pos.X;
+                                       thumbclick_offset = e.X - thumb_pos.X;
                                        lastclick_pos = e.X;
-                                       thumb_pixel_click_move_prev = thumb_pixel_click_move = e.X;
                                }
                        } else {
                                if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) {
@@ -865,14 +945,16 @@ namespace System.Windows.Forms
                                                lastclick_pos = e.Y;
 
                                                if (e.Y > thumb_pos.Y + thumb_pos.Height) {
-                                                       LargeIncrement ();                                                      
-                                                       thumb_moving = ThumbMoving.Forward;                                                     
+                                                       SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
+                                                       LargeIncrement ();
+                                                       thumb_moving = ThumbMoving.Forward;
                                                        Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
                                                                                      ClientRectangle.Width,
                                                                                      ClientRectangle.Height -  (thumb_pos.Y + thumb_pos.Height) -
                                                                                      scrollbutton_height));
                                                } else {
-                                                       LargeDecrement ();                                                      
+                                                       SendWMScroll(ScrollBarCommands.SB_PAGEUP);
+                                                       LargeDecrement ();
                                                        thumb_moving = ThumbMoving.Backwards;
                                                        Dirty (new Rectangle (0,  scrollbutton_height,
                                                                                      ClientRectangle.Width,
@@ -884,15 +966,17 @@ namespace System.Windows.Forms
                                                lastclick_pos = e.X;
 
                                                if (e.X > thumb_pos.X + thumb_pos.Width) {
+                                                       SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
                                                        thumb_moving = ThumbMoving.Forward;
-                                                       LargeIncrement ();                                                      
+                                                       LargeIncrement ();
                                                        Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
                                                                                      ClientRectangle.Width -  (thumb_pos.X + thumb_pos.Width) -
                                                                                      scrollbutton_width,
                                                                                      ClientRectangle.Height));
                                                } else {
+                                                       SendWMScroll(ScrollBarCommands.SB_PAGEUP);
                                                        thumb_moving = ThumbMoving.Backwards;
-                                                       LargeDecrement ();                                                      
+                                                       LargeDecrement ();
                                                        Dirty (new Rectangle (scrollbutton_width,  0,
                                                                                      thumb_pos.X - scrollbutton_width,
                                                                                      ClientRectangle.Height));
@@ -905,17 +989,11 @@ namespace System.Windows.Forms
                                }
                        }
                }
-               
+
                private void OnMouseUpSB (object sender, MouseEventArgs e)
                {
                        ClearDirty ();
 
-                       if (e.Button == MouseButtons.Right) {
-                               if (MouseUp != null) {
-                                       MouseUp (this, e);
-                               }
-                       }
-                       
                        if (Enabled == false)
                                return;
 
@@ -923,14 +1001,14 @@ namespace System.Windows.Forms
                        if (thumb_moving != ThumbMoving.None) {
                                DirtyThumbArea ();
                                thumb_moving = ThumbMoving.None;
-                       }                       
-                       this.Capture = false;
+                       }
 
                        if (firstbutton_pressed) {
                                firstbutton_state = ButtonState.Normal;
                                if (first_arrow_area.Contains (e.X, e.Y)) {
                                        SmallDecrement ();
                                }
+                               SendWMScroll(ScrollBarCommands.SB_LINEUP);
                                firstbutton_pressed = false;
                                Dirty (first_arrow_area);
                        } else if (secondbutton_pressed) {
@@ -938,13 +1016,14 @@ namespace System.Windows.Forms
                                if (second_arrow_area.Contains (e.X, e.Y)) {
                                        SmallIncrement ();
                                }
+                               SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
                                Dirty (second_arrow_area);
                                secondbutton_pressed = false;
                        } else if (thumb_pressed == true) {
                                OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
                                OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
+                               SendWMScroll(ScrollBarCommands.SB_THUMBPOSITION);
                                thumb_pressed = false;
-                               Refresh ();
                                return;
                        }
 
@@ -980,12 +1059,12 @@ namespace System.Windows.Forms
                                break;
                        }
                        case Keys.Home:
-                       {               
-                               SetHomePosition ();                             
+                       {
+                               SetHomePosition ();
                                break;
-                       }                       
+                       }
                        case Keys.End:
-                       {       
+                       {
                                SetEndPosition ();
                                break;
                        }
@@ -994,72 +1073,68 @@ namespace System.Windows.Forms
                        }
 
                        InvalidateDirty ();
-               }               
-               
-               private void SetEndPosition () 
-               {                       
+               }
+
+               private void SetEndPosition ()
+               {
                        ScrollEventArgs event_args;
-                       int pos = Maximum;
-                       
+                       int pos = Maximum - large_change + 1;
+
                        event_args = new ScrollEventArgs (ScrollEventType.Last, pos);
                        OnScroll (event_args);
-                       pos = event_args.NewValue;                      
-                       
+                       pos = event_args.NewValue;
+
                        event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
-                       OnScroll (event_args);                  
-                       pos = event_args.NewValue;                      
+                       OnScroll (event_args);
+                       pos = event_args.NewValue;
 
                        SetValue (pos);
                }
-               
+
                private void SetHomePosition ()
                {
                        ScrollEventArgs event_args;
                        int pos = Minimum;
-                       
+
                        event_args = new ScrollEventArgs (ScrollEventType.First, pos);
                        OnScroll (event_args);
                        pos = event_args.NewValue;
-                                               
+
                        event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
-                       OnScroll (event_args);                  
-                       pos = event_args.NewValue;                      
-                       
+                       OnScroll (event_args);
+                       pos = event_args.NewValue;
+
                        SetValue (pos);
-               }               
+               }
 
                private void SmallIncrement ()
                {
                        ScrollEventArgs event_args;
-                       int pos = position + small_change;
-                       
+                       int pos = Math.Min (Maximum - large_change + 1, position + small_change);
+
                        event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos);
-                       OnScroll (event_args);                          
-                       pos = event_args.NewValue;                      
-                       
-                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
-                       OnScroll (event_args);                  
-                       pos = event_args.NewValue;                      
+                       OnScroll (event_args);
+                       Value = event_args.NewValue;
 
-                       UpdatePos (pos, true);
+                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+                       OnScroll (event_args);
+                       Value = event_args.NewValue;
                }
 
                private void SmallDecrement ()
-               {                       
+               {
                        ScrollEventArgs event_args;
-                       int pos = position - small_change;
-                       
+                       int pos = Math.Max (Minimum, position - small_change);
+
                        event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos);
                        OnScroll (event_args);
-                       pos = event_args.NewValue;
-                                               
-                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
-                       OnScroll (event_args);                  
-                       pos = event_args.NewValue;                      
+                       Value = event_args.NewValue;
 
-                       UpdatePos (pos, true);
+                       event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+                       OnScroll (event_args);
+                       Value = event_args.NewValue;
                }
-               
+
                private void SetHoldButtonClickTimer ()
                {
                        timer.Enabled = false;
@@ -1090,10 +1165,10 @@ namespace System.Windows.Forms
                        timer.Interval = 50;
                        timer_type = TimerType.RepeatThumbArea;
                        timer.Enabled = true;
-               }                               
-               
+               }
+
                private void UpdatePos (int newPos, bool update_thumbpos)
-               {                       
+               {
                        int pos;
 
                        if (newPos < minimum)
@@ -1110,49 +1185,49 @@ namespace System.Windows.Forms
 
                        if (update_thumbpos) {
                                if (vert)
-                                       UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), false);
+                                       UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
                                else
-                                       UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), false);
+                                       UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
                                SetValue (pos);
                        }
                        else {
                                position = pos; // Updates directly the value to avoid thumb pos update
-                               
+
                                if (ValueChanged != null)
                                        ValueChanged (this, EventArgs.Empty);
-                       }                       
+                       }
                }
 
-               private void UpdateThumbPos (int pixel, bool update_value)
+               private void UpdateThumbPos (int pixel, bool dirty, bool update_value)
                {
                        float new_pos = 0;
 
                        if (vert) {
-                               Dirty (thumb_pos);
+                               if (dirty)
+                                       Dirty (thumb_pos);
                                if (pixel < thumb_area.Y)
                                        thumb_pos.Y = thumb_area.Y;
+                               else if (pixel > thumb_area.Bottom - thumb_size)
+                                       thumb_pos.Y = thumb_area.Bottom - thumb_size;
                                else
-                                       if (pixel > thumb_area.Y + thumb_area.Height - thumb_size)
-                                               thumb_pos.Y = thumb_area.Y +  thumb_area.Height - thumb_size;
-                                       else
-                                               thumb_pos.Y = pixel;
+                                       thumb_pos.Y = pixel;
 
                                thumb_pos.X = 0;
                                thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize;
                                thumb_pos.Height = thumb_size;
                                new_pos = (float) (thumb_pos.Y - thumb_area.Y);
                                new_pos = new_pos / pixel_per_pos;
-
-                               Dirty (thumb_pos);
+                               if (dirty)
+                                       Dirty (thumb_pos);
                        } else  {
-                               Dirty (thumb_pos);
+                               if (dirty)
+                                       Dirty (thumb_pos);
                                if (pixel < thumb_area.X)
                                        thumb_pos.X = thumb_area.X;
+                               else if (pixel > thumb_area.Right - thumb_size)
+                                       thumb_pos.X = thumb_area.Right - thumb_size;
                                else
-                                       if (pixel > thumb_area.X + thumb_area.Width - thumb_size)
-                                               thumb_pos.X = thumb_area.X +  thumb_area.Width - thumb_size;
-                                       else
-                                               thumb_pos.X = pixel;
+                                       thumb_pos.X = pixel;
 
                                thumb_pos.Y = 0;
                                thumb_pos.Width =  thumb_size;
@@ -1160,7 +1235,8 @@ namespace System.Windows.Forms
                                new_pos = (float) (thumb_pos.X - thumb_area.X);
                                new_pos = new_pos / pixel_per_pos;
 
-                               Dirty (thumb_pos);
+                               if (dirty)
+                                       Dirty (thumb_pos);
                        }
 
                        if (update_value)
@@ -1225,6 +1301,7 @@ namespace System.Windows.Forms
                private void InvalidateDirty ()
                {
                        Invalidate (dirty);
+                       Update();
                        dirty = Rectangle.Empty;
                }