2008-03-27 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ScrollBar.cs
1 //
2 // System.Windows.Forms.ScrollBar.cs
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Copyright (C) 2004-2005, Novell, Inc.
24 //
25 // Authors:
26 //      Jordi Mas i Hernandez   jordi@ximian.com
27 //
28 //
29
30 // COMPLETE
31
32 using System.Drawing;
33 using System.Drawing.Imaging;
34 using System.Drawing.Drawing2D;
35 using System.ComponentModel;
36 using System.Runtime.InteropServices;
37
38 namespace System.Windows.Forms
39 {
40 #if NET_2_0
41         [ComVisible (true)]
42         [ClassInterface (ClassInterfaceType.AutoDispatch)]
43 #endif
44         [DefaultEvent ("Scroll")]
45         [DefaultProperty ("Value")]
46         public abstract class ScrollBar : Control
47         {
48                 #region Local Variables
49                 private int position;
50                 private int minimum;
51                 private int maximum;
52                 private int large_change;
53                 private int small_change;
54                 internal int scrollbutton_height;
55                 internal int scrollbutton_width;
56                 private Rectangle first_arrow_area = new Rectangle ();          // up or left
57                 private Rectangle second_arrow_area = new Rectangle ();         // down or right
58                 private Rectangle thumb_pos = new Rectangle ();
59                 private Rectangle thumb_area = new Rectangle ();
60                 internal ButtonState firstbutton_state = ButtonState.Normal;
61                 internal ButtonState secondbutton_state = ButtonState.Normal;
62                 private bool firstbutton_pressed = false;
63                 private bool secondbutton_pressed = false;
64                 private bool thumb_pressed = false;
65                 private float pixel_per_pos = 0;
66                 private Timer timer = new Timer ();
67                 private TimerType timer_type;
68                 private int thumb_size = 40;
69                 private const int thumb_min_size = 8;
70                 private const int thumb_notshown_size = 40;
71                 internal bool vert;
72                 internal bool implicit_control;
73                 private int lastclick_pos;              // Position of the last button-down event
74                 private int thumbclick_offset;          // Position of the last button-down event relative to the thumb edge
75                 private Rectangle dirty;
76
77                 internal ThumbMoving thumb_moving = ThumbMoving.None;
78                 #endregion      // Local Variables
79
80                 private enum TimerType
81                 {
82                         HoldButton,
83                         RepeatButton,
84                         HoldThumbArea,
85                         RepeatThumbArea
86                 }
87
88                 internal enum ThumbMoving
89                 {
90                         None,
91                         Forward,
92                         Backwards,
93                 }
94
95                 #region events
96 #if NET_2_0
97                 [Browsable (false)]
98                 [EditorBrowsable (EditorBrowsableState.Never)]
99                 public new event EventHandler AutoSizeChanged {
100                         add { base.AutoSizeChanged += value; }
101                         remove { base.AutoSizeChanged -= value; }
102                 }
103 #endif
104
105                 [Browsable (false)]
106                 [EditorBrowsable (EditorBrowsableState.Never)]
107                 public new event EventHandler BackColorChanged {
108                         add { base.BackColorChanged += value; }
109                         remove { base.BackColorChanged -= value; }
110                 }
111
112                 [Browsable (false)]
113                 [EditorBrowsable (EditorBrowsableState.Never)]
114                 public new event EventHandler BackgroundImageChanged {
115                         add { base.BackgroundImageChanged += value; }
116                         remove { base.BackgroundImageChanged -= value; }
117                 }
118
119 #if NET_2_0
120                 [Browsable (false)]
121                 [EditorBrowsable (EditorBrowsableState.Never)]
122                 public new event EventHandler BackgroundImageLayoutChanged {
123                         add { base.BackgroundImageLayoutChanged += value; }
124                         remove { base.BackgroundImageLayoutChanged -= value; }
125                 }
126 #endif
127
128                 [Browsable (false)]
129                 [EditorBrowsable (EditorBrowsableState.Never)]
130                 public new event EventHandler Click {
131                         add { base.Click += value; }
132                         remove { base.Click -= value; }
133                 }
134
135                 [Browsable (false)]
136                 [EditorBrowsable (EditorBrowsableState.Never)]
137                 public new event EventHandler DoubleClick {
138                         add { base.DoubleClick += value; }
139                         remove { base.DoubleClick -= value; }
140                 }
141
142                 [Browsable (false)]
143                 [EditorBrowsable (EditorBrowsableState.Never)]
144                 public new event EventHandler FontChanged {
145                         add { base.FontChanged += value; }
146                         remove { base.FontChanged -= value; }
147                 }
148
149                 [Browsable (false)]
150                 [EditorBrowsable (EditorBrowsableState.Never)]
151                 public new event EventHandler ForeColorChanged {
152                         add { base.ForeColorChanged += value; }
153                         remove { base.ForeColorChanged -= value; }
154                 }
155
156                 [Browsable (false)]
157                 [EditorBrowsable (EditorBrowsableState.Never)]
158                 public new event EventHandler ImeModeChanged {
159                         add { base.ImeModeChanged += value; }
160                         remove { base.ImeModeChanged -= value; }
161                 }
162
163 #if NET_2_0
164                 [Browsable (false)]
165                 [EditorBrowsable (EditorBrowsableState.Never)]
166                 public new event MouseEventHandler MouseClick {
167                         add { base.MouseClick += value; }
168                         remove { base.MouseClick -= value; }
169                 }
170
171                 [Browsable (false)]
172                 [EditorBrowsable (EditorBrowsableState.Never)]
173                 public new event MouseEventHandler MouseDoubleClick {
174                         add { base.MouseDoubleClick += value; }
175                         remove { base.MouseDoubleClick -= value; }
176                 }
177 #endif
178
179                 [Browsable (false)]
180                 [EditorBrowsable (EditorBrowsableState.Never)]
181                 public new event MouseEventHandler MouseDown {
182                         add { base.MouseDown += value; }
183                         remove { base.MouseDown -= value; }
184                 }
185
186                 [Browsable (false)]
187                 [EditorBrowsable (EditorBrowsableState.Never)]
188                 public new event MouseEventHandler MouseMove {
189                         add { base.MouseMove += value; }
190                         remove { base.MouseMove -= value; }
191                 }
192
193                 [Browsable (false)]
194                 [EditorBrowsable (EditorBrowsableState.Never)]
195                 public new event MouseEventHandler MouseUp {
196                         add { base.MouseUp += value; }
197                         remove { base.MouseUp -= value; }
198                 }
199
200                 [Browsable (false)]
201                 [EditorBrowsable (EditorBrowsableState.Never)]
202                 public new event PaintEventHandler Paint {
203                         add { base.Paint += value; }
204                         remove { base.Paint -= value; }
205                 }
206
207                 static object ScrollEvent = new object ();
208                 static object ValueChangedEvent = new object ();
209
210                 public event ScrollEventHandler Scroll {
211                         add { Events.AddHandler (ScrollEvent, value); }
212                         remove { Events.RemoveHandler (ScrollEvent, value); }
213                 }
214
215                 [Browsable (false)]
216                 [EditorBrowsable (EditorBrowsableState.Never)]
217                 public new event EventHandler TextChanged {
218                         add { base.TextChanged += value; }
219                         remove { base.TextChanged -= value; }
220                 }
221
222                 public event EventHandler ValueChanged {
223                         add { Events.AddHandler (ValueChangedEvent, value); }
224                         remove { Events.RemoveHandler (ValueChangedEvent, value); }
225                 }
226                 #endregion Events
227
228                 public ScrollBar ()
229                 {
230                         position = 0;
231                         minimum = 0;
232                         maximum = 100;
233                         large_change = 10;
234                         small_change = 1;
235
236                         timer.Tick += new EventHandler (OnTimer);
237                         base.KeyDown += new KeyEventHandler (OnKeyDownSB);
238                         base.MouseDown += new MouseEventHandler (OnMouseDownSB);
239                         base.MouseUp += new MouseEventHandler (OnMouseUpSB);
240                         base.MouseMove += new MouseEventHandler (OnMouseMoveSB);
241                         base.Resize += new EventHandler (OnResizeSB);
242                         base.TabStop = false;
243                         base.Cursor = Cursors.Default;
244
245                         SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
246 #if NET_2_0
247                                 | ControlStyles.UseTextForAccessibility
248 #endif
249                                 , false);
250                 }
251
252                 #region Internal & Private Properties
253                 internal Rectangle FirstArrowArea {
254                         get {
255                                 return this.first_arrow_area;
256                         }
257
258                         set {
259                                 this.first_arrow_area = value;
260                         }
261                 }
262
263                 internal Rectangle SecondArrowArea {
264                         get {
265                                 return this.second_arrow_area;
266                         }
267
268                         set {
269                                 this.second_arrow_area = value;
270                         }
271                 }
272
273                 internal Rectangle ThumbPos {
274                         get {
275                                 return thumb_pos;
276                         }
277
278                         set {
279                                 thumb_pos = value;
280                         }
281                 }
282                 #endregion      // Internal & Private Properties
283
284                 #region Public Properties
285 #if NET_2_0
286                 [EditorBrowsable (EditorBrowsableState.Never)]
287                 [Browsable (false)]
288                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
289                 public override bool AutoSize {
290                         get { return base.AutoSize; }
291                         set { base.AutoSize = value; }
292                 }
293 #endif
294
295                 [EditorBrowsable (EditorBrowsableState.Never)]
296                 [Browsable (false)]
297                 public override Color BackColor
298                 {
299                         get { return base.BackColor; }
300                         set {
301                                 if (base.BackColor == value)
302                                         return;
303                                 base.BackColor = value;
304                                 Refresh ();
305                         }
306                 }
307
308                 [EditorBrowsable (EditorBrowsableState.Never)]
309                 [Browsable (false)]
310                 public override Image BackgroundImage
311                 {
312                         get { return base.BackgroundImage; }
313                         set {
314                                 if (base.BackgroundImage == value)
315                                         return;
316
317                                 base.BackgroundImage = value;
318                         }
319                 }
320
321 #if NET_2_0
322                 [EditorBrowsable (EditorBrowsableState.Never)]
323                 [Browsable (false)]
324                 public override ImageLayout BackgroundImageLayout {
325                         get { return base.BackgroundImageLayout; }
326                         set { base.BackgroundImageLayout = value; }
327                 }
328 #endif
329
330                 protected override CreateParams CreateParams
331                 {
332                         get {   return base.CreateParams; }
333                 }
334
335 #if NET_2_0
336                 protected override Padding DefaultMargin {
337                         get { return Padding.Empty; }
338                 }
339 #endif
340
341                 protected override ImeMode DefaultImeMode
342                 {
343                         get { return ImeMode.Disable; }
344                 }
345
346                 [EditorBrowsable (EditorBrowsableState.Never)]
347                 [Browsable (false)]
348                 public override Font Font
349                 {
350                         get { return base.Font; }
351                         set {
352                                 if (base.Font.Equals (value))
353                                         return;
354
355                                 base.Font = value;
356                         }
357                 }
358
359                 [EditorBrowsable (EditorBrowsableState.Never)]
360                 [Browsable (false)]
361                 public override Color ForeColor
362                 {
363                         get { return base.ForeColor; }
364                         set {
365                                 if (base.ForeColor == value)
366                                         return;
367
368                                 base.ForeColor = value;
369                                 Refresh ();
370                         }
371                 }
372
373                 [EditorBrowsable (EditorBrowsableState.Never)]
374                 [Browsable (false)]
375                 public new ImeMode ImeMode
376                 {
377                         get { return base.ImeMode; }
378                         set {
379                                 if (base.ImeMode == value)
380                                         return;
381
382                                 base.ImeMode = value;
383                         }
384                 }
385
386                 [DefaultValue (10)]
387                 [RefreshProperties(RefreshProperties.Repaint)]
388                 [MWFDescription("Scroll amount when clicking in the scroll area"), MWFCategory("Behaviour")]
389                 public int LargeChange {
390                         get {
391                                 if (large_change > maximum)
392                                         return (maximum + 1);
393                                 else
394                                         return large_change;
395                         }
396                         set {
397                                 if (value < 0)
398 #if NET_2_0
399                                         throw new ArgumentOutOfRangeException ("LargeChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value));
400 #else
401                                         throw new ArgumentException( string.Format("Value '{0}' must be greater than or equal to 0.", value));
402 #endif
403
404                                 if (large_change != value) {
405                                         large_change = value;
406
407                                         // thumb area depends on large change value,
408                                         // so we need to recalculate it.
409                                         CalcThumbArea ();
410                                         UpdatePos (Value, true);
411                                         InvalidateDirty ();
412                                 }
413                         }
414                 }
415
416                 [DefaultValue (100)]
417                 [RefreshProperties(RefreshProperties.Repaint)]
418                 [MWFDescription("Highest value for scrollbar"), MWFCategory("Behaviour")]
419                 public int Maximum {
420                         get { return maximum; }
421                         set {
422                                 if (maximum == value)
423                                         return;
424
425                                 maximum = value;
426
427                                 if (maximum < minimum)
428                                         minimum = maximum;
429                                 if (Value > maximum)
430                                         Value = maximum;
431                                         
432                                 // thumb area depends on maximum value,
433                                 // so we need to recalculate it.
434                                 CalcThumbArea ();
435                                 UpdatePos (Value, true);
436                                 InvalidateDirty ();
437                         }
438                 }
439
440                 internal void SetValues (int maximum, int large_change)
441                 {
442                         SetValues (-1, maximum, -1, large_change);
443                 }
444
445                 internal void SetValues (int minimum, int maximum, int small_change, int large_change)
446                 {
447                         bool update = false;
448
449                         if (-1 != minimum && this.minimum != minimum) {
450                                 this.minimum = minimum;
451
452                                 if (minimum > this.maximum)
453                                         this.maximum = minimum;
454                                 update = true;
455
456                                 // change the position if it is out of range now
457                                 position = Math.Max (position, minimum);
458                         }
459
460                         if (-1 != maximum && this.maximum != maximum) {
461                                 this.maximum = maximum;
462
463                                 if (maximum < this.minimum)
464                                         this.minimum = maximum;
465                                 update = true;
466
467                                 // change the position if it is out of range now
468                                 position = Math.Min (position, maximum);
469                         }
470
471                         if (-1 != small_change && this.small_change != small_change) {
472                                 this.small_change = small_change;
473                         }
474
475                         if (this.large_change != large_change) {
476                                 this.large_change = large_change;
477                                 update = true;
478                         }
479
480                         if (update) {
481                                 CalcThumbArea ();
482                                 UpdatePos (Value, true);
483                                 InvalidateDirty ();
484                         }
485                 }
486
487                 [DefaultValue (0)]
488                 [RefreshProperties(RefreshProperties.Repaint)]
489                 [MWFDescription("Smallest value for scrollbar"), MWFCategory("Behaviour")]
490                 public int Minimum {
491                         get { return minimum; }
492                         set {
493                                 if (minimum == value)
494                                         return;
495
496                                 minimum = value;
497
498                                 if (minimum > maximum)
499                                         maximum = minimum;
500
501                                 // thumb area depends on minimum value,
502                                 // so we need to recalculate it.
503                                 CalcThumbArea ();
504                                 UpdatePos (Value, true);
505                                 InvalidateDirty ();
506                         }
507                 }
508
509                 [DefaultValue (1)]
510                 [MWFDescription("Scroll amount when clicking scroll arrows"), MWFCategory("Behaviour")]
511                 public int SmallChange {
512                         get { return small_change; }
513                         set {
514                                 if ( value < 0 )
515 #if NET_2_0
516                                         throw new ArgumentOutOfRangeException ("SmallChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value));
517 #else
518                                         throw new ArgumentException( string.Format("Value '{0}' must be greater than or equal to 0.", value));
519 #endif
520
521                                 if (small_change != value) {
522                                         small_change = value;
523                                         UpdatePos (Value, true);
524                                         InvalidateDirty ();
525                                 }
526                         }
527                 }
528
529                 [DefaultValue (false)]
530                 public new bool TabStop {
531                         get { return base.TabStop; }
532                         set { base.TabStop = value; }
533                 }
534
535                 [EditorBrowsable (EditorBrowsableState.Never)]
536                 [Bindable (false)]
537                 [Browsable (false)]
538                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
539                 public override string Text {
540                          get { return base.Text;  }
541                          set { base.Text = value; }
542                 }
543
544                 [Bindable(true)]
545                 [DefaultValue (0)]
546                 [MWFDescription("Current value for scrollbar"), MWFCategory("Behaviour")]
547                 public int Value {
548                         get { return position; }
549                         set {
550                                 if ( value < minimum || value > maximum )
551 #if NET_2_0
552                                         throw new ArgumentOutOfRangeException ("Value", string.Format ("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
553 #else
554                                         throw new ArgumentException (string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
555 #endif                                  
556
557                                 if (position != value){
558                                         position = value;
559
560                                         OnValueChanged (EventArgs.Empty);
561
562                                         if (IsHandleCreated) {
563                                                 Rectangle thumb_rect = thumb_pos;
564
565                                                 UpdateThumbPos ((vert ? thumb_area.Y : thumb_area.X) + (int)(((float)(position - minimum)) * pixel_per_pos), false, false);
566
567                                                 MoveThumb (thumb_rect, vert ? thumb_pos.Y : thumb_pos.X);
568                                         }
569                                 }
570                         }
571                 }
572
573                 #endregion //Public Properties
574
575                 #region Public Methods
576 #if NET_2_0
577                 protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
578                 {
579                         // Basically, we want to keep our small edge and scale the long edge
580                         // ie: if we are vertical, don't scale our width
581                         if (vert)
582                                 return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Height) | (specified & BoundsSpecified.Location));
583                         else
584                                 return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Width) | (specified & BoundsSpecified.Location));
585                 }
586 #endif          
587                 
588                 protected override void OnEnabledChanged (EventArgs e)
589                 {
590                         base.OnEnabledChanged (e);
591
592                         if (Enabled)
593                                 firstbutton_state = secondbutton_state = ButtonState.Normal;
594                         else
595                                 firstbutton_state = secondbutton_state = ButtonState.Inactive;
596
597                         Refresh ();
598                 }
599
600                 protected override void OnHandleCreated (System.EventArgs e)
601                 {
602                         base.OnHandleCreated (e);
603
604                         CalcButtonSizes ();
605                         CalcThumbArea ();
606                         UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), true, false);
607                 }
608
609                 protected virtual void OnScroll (ScrollEventArgs se)
610                 {
611                         ScrollEventHandler eh = (ScrollEventHandler)(Events [ScrollEvent]);
612                         if (eh == null)
613                                 return;
614
615                         if (se.NewValue < Minimum) {
616                                 se.NewValue = Minimum;
617                         }
618
619                         if (se.NewValue > Maximum) {
620                                 se.NewValue = Maximum;
621                         }
622
623                         eh (this, se);
624                 }
625
626                 private void SendWMScroll(ScrollBarCommands cmd) {
627                         if ((Parent != null) && Parent.IsHandleCreated) {
628                                 if (vert) {
629                                         XplatUI.SendMessage(Parent.Handle, Msg.WM_VSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle);
630                                 } else {
631                                         XplatUI.SendMessage(Parent.Handle, Msg.WM_HSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle);
632                                 }
633                         }
634                 }
635
636                 protected virtual void OnValueChanged (EventArgs e)
637                 {
638                         EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
639                         if (eh != null)
640                                 eh (this, e);
641                 }
642
643                 public override string ToString()
644                 {
645                         return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
646                                                 GetType( ).FullName.ToString( ), minimum, maximum, position);
647                 }
648
649                 protected void UpdateScrollInfo ()
650                 {
651                         Refresh ();
652                 }
653
654                 protected override void WndProc (ref Message m)
655                 {
656                         base.WndProc (ref m);
657                 }
658
659                 #endregion //Public Methods
660
661                 #region Private Methods
662
663                 private void CalcButtonSizes ()
664                 {
665                         if (vert) {
666                                 if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2)
667                                         scrollbutton_height = Height /2;
668                                 else
669                                         scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
670
671                         } else {
672                                 if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2)
673                                         scrollbutton_width = Width /2;
674                                 else
675                                         scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
676                         }
677                 }
678
679                 private void CalcThumbArea ()
680                 {
681                         // Thumb area
682                         if (vert) {
683
684                                 thumb_area.Height = Height - scrollbutton_height -  scrollbutton_height;
685                                 thumb_area.X = 0;
686                                 thumb_area.Y = scrollbutton_height;
687                                 thumb_area.Width = Width;
688
689                                 if (Height < thumb_notshown_size)
690                                         thumb_size = 0;
691                                 else {
692                                         double per =  ((double) this.LargeChange / (double)((1 + maximum - minimum)));
693                                         thumb_size = 1 + (int) (thumb_area.Height * per);
694
695                                         if (thumb_size < thumb_min_size)
696                                                 thumb_size = thumb_min_size;
697                                 }
698
699                                 pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
700
701                         } else  {
702
703                                 thumb_area.Y = 0;
704                                 thumb_area.X = scrollbutton_width;
705                                 thumb_area.Height = Height;
706                                 thumb_area.Width = Width - scrollbutton_width -  scrollbutton_width;
707
708                                 if (Width < thumb_notshown_size)
709                                         thumb_size = 0;
710                                 else {
711                                         double per =  ((double) this.LargeChange / (double)((1 + maximum - minimum)));
712                                         thumb_size = 1 + (int) (thumb_area.Width * per);
713
714                                         if (thumb_size < thumb_min_size)
715                                                 thumb_size = thumb_min_size;
716                                 }
717
718                                 pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
719                         }
720                 }
721
722                 private void LargeIncrement ()
723                 {
724                         ScrollEventArgs event_args;
725                         int pos = Math.Min (Maximum - large_change + 1, position + large_change);
726
727                         event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos);
728                         OnScroll (event_args);
729                         Value = event_args.NewValue;
730
731                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
732                         OnScroll (event_args);
733                         Value = event_args.NewValue;
734                 }
735
736                 private void LargeDecrement ()
737                 {
738                         ScrollEventArgs event_args;
739                         int pos = Math.Max (Minimum, position - large_change);
740
741                         event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos);
742                         OnScroll (event_args);
743                         Value = event_args.NewValue;
744
745                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
746                         OnScroll (event_args);
747                         Value = event_args.NewValue;
748                 }
749
750                 private void OnResizeSB (Object o, EventArgs e)
751                 {
752                         if (Width <= 0 || Height <= 0)
753                                 return;
754
755                         CalcButtonSizes ();
756                         CalcThumbArea ();
757                         UpdatePos (position, true);
758
759                         Refresh ();
760                 }
761
762                 internal override void OnPaintInternal (PaintEventArgs pevent)
763                 {
764                         ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this);
765                 }
766
767                 private void OnTimer (Object source, EventArgs e)
768                 {
769                         ClearDirty ();
770
771                         switch (timer_type) {
772
773                         case TimerType.HoldButton:
774                                 SetRepeatButtonTimer ();
775                                 break;
776
777                         case TimerType.RepeatButton:
778                         {
779                                 if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Minimum) {
780                                         SmallDecrement();
781                                         SendWMScroll(ScrollBarCommands.SB_LINEUP);
782                                 }
783
784                                 if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Maximum) {
785                                         SmallIncrement();
786                                         SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
787                                 }
788
789                                 break;
790                         }
791
792                         case TimerType.HoldThumbArea:
793                                 SetRepeatThumbAreaTimer ();
794                                 break;
795
796                         case TimerType.RepeatThumbArea:
797                         {
798                                 Point pnt, pnt_screen;
799                                 Rectangle thumb_area_screen = thumb_area;
800
801                                 pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y));
802                                 thumb_area_screen.X = pnt_screen.X;
803                                 thumb_area_screen.Y = pnt_screen.Y;
804
805                                 if (thumb_area_screen.Contains (MousePosition) == false) {
806                                         timer.Enabled = false;
807                                         thumb_moving = ThumbMoving.None;
808                                         DirtyThumbArea ();
809                                         InvalidateDirty ();
810                                 }
811
812                                 pnt = PointToClient (MousePosition);
813
814                                 if (vert)
815                                         lastclick_pos = pnt.Y;
816                                 else
817                                         lastclick_pos = pnt.X;
818
819                                 if (thumb_moving == ThumbMoving.Forward) {
820                                         if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) ||
821                                            (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
822                                            (thumb_area.Contains (pnt) == false)) {
823                                                 timer.Enabled = false;
824                                                 thumb_moving = ThumbMoving.None;
825                                                 Refresh ();
826                                                 return;
827                                         } else {
828                                                 LargeIncrement ();
829                                                 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
830                                         }
831                                 } else {
832                                         if ((vert && (thumb_pos.Y < lastclick_pos)) ||
833                                            (!vert && (thumb_pos.X  < lastclick_pos))){
834                                                 timer.Enabled = false;
835                                                 thumb_moving = ThumbMoving.None;
836                                                 SendWMScroll(ScrollBarCommands.SB_PAGEUP);
837                                                 Refresh ();
838                                         } else {
839                                                 LargeDecrement ();
840                                                 SendWMScroll(ScrollBarCommands.SB_PAGEUP);
841                                         }
842                                 }
843
844                                 break;
845                         }
846                         default:
847                                 break;
848                         }
849
850                         InvalidateDirty ();
851                 }
852
853                 private void MoveThumb (Rectangle original_thumbpos, int value)
854                 {
855                         /* so, the reason this works can best be
856                          * described by the following 1 dimensional
857                          * pictures
858                          *
859                          * say you have a scrollbar thumb positioned
860                          * thusly:
861                          *
862                          * <---------------------|          |------------------------------>
863                          *
864                          * and you want it to end up looking like this:
865                          *
866                          * <-----------------------------|          |---------------------->
867                          *
868                          * that can be done with the scrolling api by
869                          * extending the rectangle to encompass both
870                          * positions:
871                          *
872                          *               start of range          end of range
873                          *                       \                  /
874                          * <---------------------|          |-------|---------------------->
875                          *
876                          * so, we end up scrolling just this little region:
877                          *
878                          *                       |          |-------|
879                          *
880                          * and end up with       ********|          |
881                          *
882                          * where ****** is space that is automatically
883                          * redrawn.
884                          *
885                          * It's clear that in both cases (left to
886                          * right, right to left) we need to extend the
887                          * size of the scroll rectangle to encompass
888                          * both.  In the right to left case, we also
889                          * need to decrement the X coordinate.
890                          *
891                          * We call Update after scrolling to make sure
892                          * there's no garbage left in the window to be
893                          * copied again if we're called before the
894                          * paint events have been handled.
895                          *
896                          */
897                         int delta;
898
899                         if (vert) {
900                                 delta = value - original_thumbpos.Y;
901
902                                 if (delta < 0) {
903                                         original_thumbpos.Y += delta;
904                                         original_thumbpos.Height -= delta;
905                                 }
906                                 else {
907                                         original_thumbpos.Height += delta;
908                                 }
909
910                                 XplatUI.ScrollWindow (Handle, original_thumbpos, 0, delta, false);
911                         }
912                         else {
913                                 delta = value - original_thumbpos.X;
914
915                                 if (delta < 0) {
916                                         original_thumbpos.X += delta;
917                                         original_thumbpos.Width -= delta;
918                                 }
919                                 else {
920                                         original_thumbpos.Width += delta;
921                                 }
922
923                                 XplatUI.ScrollWindow (Handle, original_thumbpos, delta, 0, false);
924                         }
925
926                         Update ();
927                 }
928
929                 private void OnMouseMoveSB (object sender, MouseEventArgs e)
930                 {
931                         if (Enabled == false || thumb_size == 0)
932                                 return;
933
934                         if (firstbutton_pressed) {
935                                 if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
936                                         firstbutton_state = ButtonState.Normal;
937                                         Invalidate (first_arrow_area);
938                                         Update();
939                                         return;
940                                 } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
941                                         firstbutton_state = ButtonState.Pushed;
942                                         Invalidate (first_arrow_area);
943                                         Update();
944                                         return;
945                                 }
946                         } else if (secondbutton_pressed) {
947                                 if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
948                                         secondbutton_state = ButtonState.Normal;
949                                         Invalidate (second_arrow_area);
950                                         Update();
951                                         return;
952                                 } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
953                                         secondbutton_state = ButtonState.Pushed;
954                                         Invalidate (second_arrow_area);
955                                         Update();
956                                         return;
957                                 }
958                         } else if (thumb_pressed == true) {
959                                 if (vert) {
960                                         int thumb_edge = e.Y - thumbclick_offset;
961
962                                         if (thumb_edge < thumb_area.Y)
963                                                 thumb_edge = thumb_area.Y;
964                                         else if (thumb_edge > thumb_area.Bottom - thumb_size)
965                                                 thumb_edge = thumb_area.Bottom - thumb_size;
966
967                                         if (thumb_edge != thumb_pos.Y) {
968                                                 Rectangle thumb_rect = thumb_pos;
969
970                                                 UpdateThumbPos (thumb_edge, false, true);
971
972                                                 MoveThumb (thumb_rect, thumb_pos.Y);
973
974                                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
975                                         }
976                                         SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
977                                 } else {
978                                         int thumb_edge = e.X - thumbclick_offset;
979
980                                         if (thumb_edge < thumb_area.X)
981                                                 thumb_edge = thumb_area.X;
982                                         else if (thumb_edge > thumb_area.Right - thumb_size)
983                                                 thumb_edge = thumb_area.Right - thumb_size;
984
985                                         if (thumb_edge != thumb_pos.X) {
986                                                 Rectangle thumb_rect = thumb_pos;
987
988                                                 UpdateThumbPos (thumb_edge, false, true);
989
990                                                 MoveThumb (thumb_rect, thumb_pos.X);
991
992                                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
993                                         }
994                                         SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
995                                 }
996
997                         }
998
999                 }
1000
1001                 private void OnMouseDownSB (object sender, MouseEventArgs e)
1002                 {
1003                         ClearDirty ();
1004
1005                         if (Enabled == false)
1006                                 return;
1007
1008                         if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) {
1009                                 SendWMScroll(ScrollBarCommands.SB_LINEUP);
1010                                 firstbutton_state = ButtonState.Pushed;
1011                                 firstbutton_pressed = true;
1012                                 Invalidate (first_arrow_area);
1013                                 Update();
1014                                 if (!timer.Enabled) {
1015                                         SetHoldButtonClickTimer ();
1016                                         timer.Enabled = true;
1017                                 }
1018                         }
1019
1020                         if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) {
1021                                 SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
1022                                 secondbutton_state = ButtonState.Pushed;
1023                                 secondbutton_pressed = true;
1024                                 Invalidate (second_arrow_area);
1025                                 Update();
1026                                 if (!timer.Enabled) {
1027                                         SetHoldButtonClickTimer ();
1028                                         timer.Enabled = true;
1029                                 }
1030                         }
1031
1032                         if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) {
1033                                 thumb_pressed = true;
1034                                 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
1035                                 if (vert) {
1036                                         thumbclick_offset = e.Y - thumb_pos.Y;
1037                                         lastclick_pos = e.Y;
1038                                 }
1039                                 else {
1040                                         thumbclick_offset = e.X - thumb_pos.X;
1041                                         lastclick_pos = e.X;
1042                                 }
1043                         } else {
1044                                 if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) {
1045
1046                                         if (vert) {
1047                                                 lastclick_pos = e.Y;
1048
1049                                                 if (e.Y > thumb_pos.Y + thumb_pos.Height) {
1050                                                         SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
1051                                                         LargeIncrement ();
1052                                                         thumb_moving = ThumbMoving.Forward;
1053                                                         Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
1054                                                                                       ClientRectangle.Width,
1055                                                                                       ClientRectangle.Height -  (thumb_pos.Y + thumb_pos.Height) -
1056                                                                                       scrollbutton_height));
1057                                                 } else {
1058                                                         SendWMScroll(ScrollBarCommands.SB_PAGEUP);
1059                                                         LargeDecrement ();
1060                                                         thumb_moving = ThumbMoving.Backwards;
1061                                                         Dirty (new Rectangle (0,  scrollbutton_height,
1062                                                                                       ClientRectangle.Width,
1063                                                                                       thumb_pos.Y - scrollbutton_height));
1064                                                 }
1065                                         } else {
1066
1067                                                 lastclick_pos = e.X;
1068
1069                                                 if (e.X > thumb_pos.X + thumb_pos.Width) {
1070                                                         SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
1071                                                         thumb_moving = ThumbMoving.Forward;
1072                                                         LargeIncrement ();
1073                                                         Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
1074                                                                                       ClientRectangle.Width -  (thumb_pos.X + thumb_pos.Width) -
1075                                                                                       scrollbutton_width,
1076                                                                                       ClientRectangle.Height));
1077                                                 } else {
1078                                                         SendWMScroll(ScrollBarCommands.SB_PAGEUP);
1079                                                         thumb_moving = ThumbMoving.Backwards;
1080                                                         LargeDecrement ();
1081                                                         Dirty (new Rectangle (scrollbutton_width,  0,
1082                                                                                       thumb_pos.X - scrollbutton_width,
1083                                                                                       ClientRectangle.Height));
1084                                                 }
1085                                         }
1086
1087                                         SetHoldThumbAreaTimer ();
1088                                         timer.Enabled = true;
1089                                         InvalidateDirty ();
1090                                 }
1091                         }
1092                 }
1093
1094                 private void OnMouseUpSB (object sender, MouseEventArgs e)
1095                 {
1096                         ClearDirty ();
1097
1098                         if (Enabled == false)
1099                                 return;
1100
1101                         timer.Enabled = false;
1102                         if (thumb_moving != ThumbMoving.None) {
1103                                 DirtyThumbArea ();
1104                                 thumb_moving = ThumbMoving.None;
1105                         }
1106
1107                         if (firstbutton_pressed) {
1108                                 firstbutton_state = ButtonState.Normal;
1109                                 if (first_arrow_area.Contains (e.X, e.Y)) {
1110                                         SmallDecrement ();
1111                                 }
1112                                 SendWMScroll(ScrollBarCommands.SB_LINEUP);
1113                                 firstbutton_pressed = false;
1114                                 Dirty (first_arrow_area);
1115                         } else if (secondbutton_pressed) {
1116                                 secondbutton_state = ButtonState.Normal;
1117                                 if (second_arrow_area.Contains (e.X, e.Y)) {
1118                                         SmallIncrement ();
1119                                 }
1120                                 SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
1121                                 Dirty (second_arrow_area);
1122                                 secondbutton_pressed = false;
1123                         } else if (thumb_pressed == true) {
1124                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
1125                                 OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
1126                                 SendWMScroll(ScrollBarCommands.SB_THUMBPOSITION);
1127                                 thumb_pressed = false;
1128                                 return;
1129                         }
1130
1131                         InvalidateDirty ();
1132                 }
1133
1134                 private void OnKeyDownSB (Object o, KeyEventArgs key)
1135                 {
1136                         if (Enabled == false)
1137                                 return;
1138
1139                         ClearDirty ();
1140
1141                         switch (key.KeyCode){
1142                         case Keys.Up:
1143                         {
1144                                 SmallDecrement ();
1145                                 break;
1146                         }
1147                         case Keys.Down:
1148                         {
1149                                 SmallIncrement ();
1150                                 break;
1151                         }
1152                         case Keys.PageUp:
1153                         {
1154                                 LargeDecrement ();
1155                                 break;
1156                         }
1157                         case Keys.PageDown:
1158                         {
1159                                 LargeIncrement ();
1160                                 break;
1161                         }
1162                         case Keys.Home:
1163                         {
1164                                 SetHomePosition ();
1165                                 break;
1166                         }
1167                         case Keys.End:
1168                         {
1169                                 SetEndPosition ();
1170                                 break;
1171                         }
1172                         default:
1173                                 break;
1174                         }
1175
1176                         InvalidateDirty ();
1177                 }
1178
1179                 // I hate to do this, but we don't have the resources to track
1180                 // down everything internal that is setting a value outside the
1181                 // correct range, so we'll clamp it to the acceptable values.
1182                 internal void SafeValueSet (int value)
1183                 {
1184                         value = Math.Min (value, maximum);
1185                         value = Math.Max (value, minimum);
1186                         
1187                         Value = value;
1188                 }
1189                 
1190                 private void SetEndPosition ()
1191                 {
1192                         ScrollEventArgs event_args;
1193                         int pos = Maximum - large_change + 1;
1194
1195                         event_args = new ScrollEventArgs (ScrollEventType.Last, pos);
1196                         OnScroll (event_args);
1197                         pos = event_args.NewValue;
1198
1199                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1200                         OnScroll (event_args);
1201                         pos = event_args.NewValue;
1202
1203                         SetValue (pos);
1204                 }
1205
1206                 private void SetHomePosition ()
1207                 {
1208                         ScrollEventArgs event_args;
1209                         int pos = Minimum;
1210
1211                         event_args = new ScrollEventArgs (ScrollEventType.First, pos);
1212                         OnScroll (event_args);
1213                         pos = event_args.NewValue;
1214
1215                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1216                         OnScroll (event_args);
1217                         pos = event_args.NewValue;
1218
1219                         SetValue (pos);
1220                 }
1221
1222                 private void SmallIncrement ()
1223                 {
1224                         ScrollEventArgs event_args;
1225                         int pos = Math.Min (Maximum - large_change + 1, position + small_change);
1226
1227                         event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos);
1228                         OnScroll (event_args);
1229                         Value = event_args.NewValue;
1230
1231                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
1232                         OnScroll (event_args);
1233                         Value = event_args.NewValue;
1234                 }
1235
1236                 private void SmallDecrement ()
1237                 {
1238                         ScrollEventArgs event_args;
1239                         int pos = Math.Max (Minimum, position - small_change);
1240
1241                         event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos);
1242                         OnScroll (event_args);
1243                         Value = event_args.NewValue;
1244
1245                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
1246                         OnScroll (event_args);
1247                         Value = event_args.NewValue;
1248                 }
1249
1250                 private void SetHoldButtonClickTimer ()
1251                 {
1252                         timer.Enabled = false;
1253                         timer.Interval = 200;
1254                         timer_type = TimerType.HoldButton;
1255                         timer.Enabled = true;
1256                 }
1257
1258                 private void SetRepeatButtonTimer ()
1259                 {
1260                         timer.Enabled = false;
1261                         timer.Interval = 50;
1262                         timer_type = TimerType.RepeatButton;
1263                         timer.Enabled = true;
1264                 }
1265
1266                 private void SetHoldThumbAreaTimer ()
1267                 {
1268                         timer.Enabled = false;
1269                         timer.Interval = 200;
1270                         timer_type = TimerType.HoldThumbArea;
1271                         timer.Enabled = true;
1272                 }
1273
1274                 private void SetRepeatThumbAreaTimer ()
1275                 {
1276                         timer.Enabled = false;
1277                         timer.Interval = 50;
1278                         timer_type = TimerType.RepeatThumbArea;
1279                         timer.Enabled = true;
1280                 }
1281
1282                 private void UpdatePos (int newPos, bool update_thumbpos)
1283                 {
1284                         int pos;
1285
1286                         if (newPos < minimum)
1287                                 pos = minimum;
1288                         else
1289                                 if (newPos > maximum + 1 - large_change)
1290                                         pos = maximum + 1 - large_change;
1291                                 else
1292                                         pos = newPos;
1293
1294                         // pos can't be less than minimum
1295                         if (pos < minimum)
1296                                 pos = minimum;
1297
1298                         if (update_thumbpos) {
1299                                 if (vert)
1300                                         UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
1301                                 else
1302                                         UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
1303                                 SetValue (pos);
1304                         }
1305                         else {
1306                                 position = pos; // Updates directly the value to avoid thumb pos update
1307
1308
1309                                 // XXX some reason we don't call OnValueChanged?
1310                                 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
1311                                 if (eh != null)
1312                                         eh (this, EventArgs.Empty);
1313                         }
1314                 }
1315
1316                 private void UpdateThumbPos (int pixel, bool dirty, bool update_value)
1317                 {
1318                         float new_pos = 0;
1319
1320                         if (vert) {
1321                                 if (dirty)
1322                                         Dirty (thumb_pos);
1323                                 if (pixel < thumb_area.Y)
1324                                         thumb_pos.Y = thumb_area.Y;
1325                                 else if (pixel > thumb_area.Bottom - thumb_size)
1326                                         thumb_pos.Y = thumb_area.Bottom - thumb_size;
1327                                 else
1328                                         thumb_pos.Y = pixel;
1329
1330                                 thumb_pos.X = 0;
1331                                 thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize;
1332                                 thumb_pos.Height = thumb_size;
1333                                 new_pos = (float) (thumb_pos.Y - thumb_area.Y);
1334                                 new_pos = new_pos / pixel_per_pos;
1335                                 if (dirty)
1336                                         Dirty (thumb_pos);
1337                         } else  {
1338                                 if (dirty)
1339                                         Dirty (thumb_pos);
1340                                 if (pixel < thumb_area.X)
1341                                         thumb_pos.X = thumb_area.X;
1342                                 else if (pixel > thumb_area.Right - thumb_size)
1343                                         thumb_pos.X = thumb_area.Right - thumb_size;
1344                                 else
1345                                         thumb_pos.X = pixel;
1346
1347                                 thumb_pos.Y = 0;
1348                                 thumb_pos.Width =  thumb_size;
1349                                 thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize;
1350                                 new_pos = (float) (thumb_pos.X - thumb_area.X);
1351                                 new_pos = new_pos / pixel_per_pos;
1352
1353                                 if (dirty)
1354                                         Dirty (thumb_pos);
1355                         }
1356
1357                         if (update_value)
1358                                 UpdatePos ((int) new_pos + minimum, false);
1359                 }
1360
1361                 private void SetValue (int value)
1362                 {
1363                         if ( value < minimum || value > maximum )
1364                                 throw new ArgumentException(
1365                                         String.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
1366
1367                         if (position != value){
1368                                 position = value;
1369
1370                                 OnValueChanged (EventArgs.Empty);
1371                                 UpdatePos (value, true);
1372                         }
1373                 }
1374
1375                 private void ClearDirty ()
1376                 {
1377                         dirty = Rectangle.Empty;
1378                 }
1379
1380                 private void Dirty (Rectangle r)
1381                 {
1382                         if (dirty == Rectangle.Empty) {
1383                                 dirty = r;
1384                                 return;
1385                         }
1386                         dirty = Rectangle.Union (dirty, r);
1387                 }
1388
1389                 private void DirtyThumbArea ()
1390                 {
1391                         if (thumb_moving == ThumbMoving.Forward) {
1392                                 if (vert) {
1393                                         Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
1394                                                                       ClientRectangle.Width,
1395                                                                       ClientRectangle.Height -  (thumb_pos.Y + thumb_pos.Height) -
1396                                                                       scrollbutton_height));
1397                                 } else {
1398                                         Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
1399                                                                       ClientRectangle.Width -  (thumb_pos.X + thumb_pos.Width) -
1400                                                                       scrollbutton_width,
1401                                                                       ClientRectangle.Height));
1402                                 }
1403                         } else if (thumb_moving == ThumbMoving.Backwards) {
1404                                 if (vert) {
1405                                         Dirty(new Rectangle (0,  scrollbutton_height,
1406                                                                       ClientRectangle.Width,
1407                                                                       thumb_pos.Y - scrollbutton_height));
1408                                 } else {
1409                                         Dirty (new Rectangle (scrollbutton_width,  0,
1410                                                                       thumb_pos.X - scrollbutton_width,
1411                                                                       ClientRectangle.Height));
1412                                 }
1413                         }
1414                 }
1415
1416                 private void InvalidateDirty ()
1417                 {
1418                         Invalidate (dirty);
1419                         Update();
1420                         dirty = Rectangle.Empty;
1421                 }
1422
1423                 #endregion //Private Methods
1424 #if NET_2_0
1425                 protected override void OnMouseWheel (MouseEventArgs e)
1426                 {
1427                         base.OnMouseWheel (e);
1428                 }
1429 #endif
1430          }
1431 }
1432
1433