Make a copy of the old ZipLib
[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         [DefaultEvent ("Scroll")]
41         [DefaultProperty ("Value")]
42         public abstract class ScrollBar : Control
43         {
44                 #region Local Variables
45                 private int position;
46                 private int minimum;
47                 private int maximum;
48                 private int large_change;
49                 private int small_change;
50                 internal int scrollbutton_height;
51                 internal int scrollbutton_width;                
52                 private ScrollBars type;
53                 private Rectangle first_arrow_area = new Rectangle ();          // up or left
54                 private Rectangle second_arrow_area = new Rectangle ();         // down or right
55                 private Rectangle thumb_pos = new Rectangle ();
56                 private Rectangle thumb_area = new Rectangle ();
57                 internal ButtonState firstbutton_state = ButtonState.Normal;
58                 internal ButtonState secondbutton_state = ButtonState.Normal;
59                 private bool firstbutton_pressed = false;
60                 private bool secondbutton_pressed = false;
61                 private bool thumb_pressed = false;
62                 private float pixel_per_pos = 0;
63                 private Timer timer = new Timer ();
64                 private TimerType timer_type;
65                 private int thumb_pixel_click_move;
66                 private int thumb_pixel_click_move_prev;
67                 private int thumb_size = 40;
68                 private const int thumb_min_size = 8;
69                 private const int thumb_notshown_size = 40;
70                 internal bool vert;
71                 private int lastclick_pos;      // Position of the last button-down event
72                 private int lastclick_pos_thumb;      // Position of the last button-down event relative to the thumb           
73                 private bool outside_thumbarea_right = false;
74                 private bool outside_thumbarea_left = false;
75
76                 private Rectangle dirty;
77
78                 internal ThumbMoving thumb_moving = ThumbMoving.None;
79                 #endregion      // Local Variables
80
81                 private enum TimerType
82                 {
83                         HoldButton,
84                         RepeatButton,
85                         HoldThumbArea,
86                         RepeatThumbArea
87                 }
88                 
89                 internal enum ThumbMoving
90                 {
91                         None,
92                         Forward,
93                         Backwards,
94                 }
95
96                 #region events
97                 
98                 [Browsable (false)]
99                 [EditorBrowsable (EditorBrowsableState.Never)]
100                 public new event EventHandler BackColorChanged;
101                 
102                 [Browsable (false)]
103                 [EditorBrowsable (EditorBrowsableState.Never)]
104                 public new event EventHandler BackgroundImageChanged;
105                 
106                 [Browsable (false)]
107                 [EditorBrowsable (EditorBrowsableState.Never)]
108                 public new event EventHandler Click;
109                 
110                 [Browsable (false)]
111                 [EditorBrowsable (EditorBrowsableState.Never)]
112                 public new event EventHandler DoubleClick;
113                 
114                 [Browsable (false)]
115                 [EditorBrowsable (EditorBrowsableState.Never)]
116                 public new event EventHandler FontChanged;
117                 
118                 [Browsable (false)]
119                 [EditorBrowsable (EditorBrowsableState.Never)]
120                 public new event EventHandler ForeColorChanged;
121                 
122                 [Browsable (false)]
123                 [EditorBrowsable (EditorBrowsableState.Never)]
124                 public new event EventHandler ImeModeChanged;
125                 
126                 [Browsable (false)]
127                 [EditorBrowsable (EditorBrowsableState.Never)]
128                 public new event MouseEventHandler MouseDown;
129                 
130                 [Browsable (false)]
131                 [EditorBrowsable (EditorBrowsableState.Never)]
132                 public new event MouseEventHandler MouseMove;
133                 
134                 [Browsable (false)]
135                 [EditorBrowsable (EditorBrowsableState.Never)]
136                 public new event MouseEventHandler MouseUp;
137                 
138                 [Browsable (false)]
139                 [EditorBrowsable (EditorBrowsableState.Never)]
140                 public new event PaintEventHandler Paint;
141                 
142                 public event ScrollEventHandler Scroll;
143                 
144                 [Browsable (false)]
145                 [EditorBrowsable (EditorBrowsableState.Never)]
146                 public new event EventHandler TextChanged;
147                 
148                 public event EventHandler ValueChanged;
149                 #endregion Events
150
151                 public ScrollBar ()
152                 {
153                         position = 0;
154                         minimum = 0;
155                         maximum = 100;
156                         large_change = 10;
157                         small_change = 1;
158
159                         timer.Tick += new EventHandler (OnTimer);
160                         base.KeyDown += new KeyEventHandler (OnKeyDownSB);
161                         base.MouseDown += new MouseEventHandler (OnMouseDownSB);
162                         base.MouseUp += new MouseEventHandler (OnMouseUpSB);
163                         base.MouseMove += new MouseEventHandler (OnMouseMoveSB);
164                         base.Resize += new EventHandler (OnResizeSB);
165                         base.TabStop = false;
166                         
167                         SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
168                 }
169
170                 #region Internal & Private Properties
171                 internal Rectangle FirstArrowArea {
172                         get {
173                                 return this.first_arrow_area;
174                         }
175
176                         set {
177                                 this.first_arrow_area = value;
178                         }
179                 }
180
181                 internal Rectangle SecondArrowArea {
182                         get {
183                                 return this.second_arrow_area;
184                         }
185
186                         set {
187                                 this.second_arrow_area = value;
188                         }
189                 }
190
191                 internal Rectangle ThumbPos {
192                         get {
193                                 return thumb_pos;
194                         }
195
196                         set {
197                                 thumb_pos = value;
198                         }
199                 }
200                 #endregion      // Internal & Private Properties
201
202                 #region Public Properties
203
204                 [EditorBrowsable (EditorBrowsableState.Never)]
205                 [Browsable (false)]
206                 public override Color BackColor
207                 {
208                         get { return base.BackColor; }
209                         set {
210                                 if (base.BackColor == value)
211                                         return;
212
213                                 if (BackColorChanged != null)
214                                         BackColorChanged (this, EventArgs.Empty);
215
216                                 base.BackColor = value;
217                                 Refresh ();
218                         }
219                 }
220
221                 [EditorBrowsable (EditorBrowsableState.Never)]
222                 [Browsable (false)]
223                 public override Image BackgroundImage
224                 {
225                         get { return base.BackgroundImage; }
226                         set {
227                                 if (base.BackgroundImage == value)
228                                         return;
229
230                                 if (BackgroundImageChanged != null)
231                                         BackgroundImageChanged (this, EventArgs.Empty);
232
233                                 base.BackgroundImage = value;
234                         }
235                 }
236
237                 protected override CreateParams CreateParams
238                 {
239                         get {   return base.CreateParams; }
240                 }
241
242                 protected override ImeMode DefaultImeMode
243                 {
244                         get { return ImeMode.Disable; }
245                 }
246
247                 [EditorBrowsable (EditorBrowsableState.Never)]
248                 [Browsable (false)]
249                 public override Font Font
250                 {
251                         get { return base.Font; }
252                         set {
253                                 if (base.Font.Equals (value))
254                                         return;
255
256                                 if (FontChanged != null)
257                                         FontChanged (this, EventArgs.Empty);
258
259                                 base.Font = value;
260                         }
261                 }
262
263                 [EditorBrowsable (EditorBrowsableState.Never)]
264                 [Browsable (false)]
265                 public override Color ForeColor
266                 {
267                         get { return base.ForeColor; }
268                         set {
269                                 if (base.ForeColor == value)
270                                         return;
271
272                                 if (ForeColorChanged != null)
273                                         ForeColorChanged (this, EventArgs.Empty);
274
275                                 base.ForeColor = value;
276                                 Refresh ();
277                         }
278                 }
279
280                 [EditorBrowsable (EditorBrowsableState.Never)]
281                 [Browsable (false)]
282                 public new ImeMode ImeMode
283                 {
284                         get { return base.ImeMode; }
285                         set {
286                                 if (base.ImeMode == value)
287                                         return;
288
289                                 if (ImeModeChanged != null)
290                                         ImeModeChanged (this, EventArgs.Empty);
291
292                                 base.ImeMode = value;
293                         }
294                 }
295
296                 [DefaultValue (10)]
297                 [RefreshProperties(RefreshProperties.Repaint)]
298                 [MWFDescription("Scroll amount when clicking in the scroll area"), MWFCategory("Behaviour")]
299                 public int LargeChange {
300                         get {
301                                 if (large_change > maximum)
302                                         return (maximum + 1);
303                                 else
304                                         return large_change;
305                         }
306                         set {
307                                 if (value < 0)
308                                         throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
309
310                                 if (large_change != value) {
311                                         large_change = value;
312
313                                         // thumb area depends on large change value,
314                                         // so we need to recalculate it.
315                                         CalcThumbArea ();
316                                         UpdatePos (Value, true);
317                                         Refresh ();
318                                 }
319                         }
320                 }
321
322                 [DefaultValue (100)]
323                 [RefreshProperties(RefreshProperties.Repaint)]
324                 [MWFDescription("Highest value for scrollbar"), MWFCategory("Behaviour")]
325                 public int Maximum {
326                         get { return maximum; }
327                         set {
328                                 if (maximum == value)
329                                         return;
330                                         
331                                 maximum = value;
332
333                                 if (maximum < minimum)
334                                         minimum = maximum;
335
336                                 // thumb area depends on maximum value,
337                                 // so we need to recalculate it.
338                                 CalcThumbArea ();
339                                 UpdatePos (Value, true);
340                                 Refresh ();
341                         }
342                 }
343
344                 [DefaultValue (0)]
345                 [RefreshProperties(RefreshProperties.Repaint)]
346                 [MWFDescription("Smallest value for scrollbar"), MWFCategory("Behaviour")]
347                 public int Minimum {
348                         get { return minimum; }
349                         set {
350                                 if (minimum == value)
351                                         return;
352                                         
353                                 minimum = value;
354
355                                 if (minimum > maximum)
356                                         maximum = minimum;
357
358                                 // thumb area depends on minimum value,
359                                 // so we need to recalculate it.
360                                 CalcThumbArea ();
361                                 UpdatePos (Value, true);
362                                 Refresh ();
363                         }
364                 }
365
366                 [DefaultValue (1)]
367                 [MWFDescription("Scroll amount when clicking scroll arrows"), MWFCategory("Behaviour")]
368                 public int SmallChange {
369                         get { return small_change; }
370                         set {
371                                 if ( value < 0 )
372                                         throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
373
374                                 if (small_change != value) {
375                                         small_change = value;
376                                         UpdatePos (Value, true);
377                                         Refresh ();
378                                 }
379                         }
380                 }
381
382                 [DefaultValue (false)]
383                 public new bool TabStop {
384                         get { return base.TabStop; }
385                         set { base.TabStop = value; }
386                 }
387
388                 [EditorBrowsable (EditorBrowsableState.Never)]
389                 [Bindable (false)]
390                 [Browsable (false)]
391                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
392                 public override string Text {
393                          get { return base.Text;  }
394                          set { base.Text = value; }
395                 }
396
397                 [Bindable(true)]
398                 [DefaultValue (0)]
399                 [MWFDescription("Current value for scrollbar"), MWFCategory("Behaviour")]
400                 public int Value {
401                         get { return position; }
402                         set {
403                                 if ( value < minimum || value > maximum )
404                                         throw new ArgumentException(
405                                                 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
406
407                                 if (position != value){
408                                         position = value;
409
410                                         OnValueChanged (EventArgs.Empty);
411
412                                         ClearDirty ();
413                                         
414                                         if (IsHandleCreated) {
415                                                 UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), false);
416                                         }
417                                         
418                                         InvalidateDirty ();
419                                 }
420                         }
421                 }
422
423                 #endregion //Public Properties
424
425                 #region Public Methods
426                 
427                 protected override void OnEnabledChanged (EventArgs e)
428                 {
429                         base.OnEnabledChanged (e);
430
431                         if (Enabled)
432                                 firstbutton_state = secondbutton_state = ButtonState.Normal;
433                         else
434                                 firstbutton_state = secondbutton_state = ButtonState.Inactive;
435
436                         Refresh ();
437                 }
438                 
439                 protected override void OnHandleCreated (System.EventArgs e)
440                 {
441                         base.OnHandleCreated (e);               
442
443                         CalcButtonSizes ();
444                         CalcThumbArea ();                       
445                         UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), false);                    
446                 }
447
448                 protected virtual void OnScroll (ScrollEventArgs event_args)
449                 {
450                         if (Scroll == null)
451                                 return;
452                                 
453                         if (event_args.NewValue < Minimum) {
454                                 event_args.NewValue = Minimum;
455                         }
456                         
457                         if (event_args.NewValue > Maximum) {
458                                 event_args.NewValue = Maximum;
459                         }
460
461                         Scroll (this, event_args);
462                 }
463
464                 protected virtual void OnValueChanged (EventArgs e)
465                 {
466                         if (ValueChanged != null)
467                                 ValueChanged (this, e);
468                 }
469
470                 public override string ToString()
471                 {
472                         return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
473                                                 GetType( ).FullName.ToString( ), minimum, maximum, position);
474                 }
475
476                 protected void UpdateScrollInfo ()
477                 {
478                         Refresh ();
479                 }
480
481                 protected override void WndProc (ref Message m)
482                 {
483                         switch ((Msg) m.Msg)
484                         {
485                                 case Msg.WM_PAINT:
486                                 {
487                                         PaintEventArgs  paint_event;
488
489                                         paint_event = XplatUI.PaintEventStart (Handle, true);
490                                         OnPaintSB (paint_event);
491                                         XplatUI.PaintEventEnd (Handle, true);
492                                         return;
493                                 }
494
495                                 case Msg.WM_ERASEBKGND:
496                                         m.Result = (IntPtr) 1; /// Disable background painting to avoid flickering
497                                         return;
498
499                                 default:
500                                         break;
501                         }
502
503                         base.WndProc (ref m);
504                 }
505
506                 #endregion //Public Methods
507
508                 #region Private Methods
509                 
510                 private void CalcButtonSizes ()
511                 {               
512                         if (vert) {
513                                 if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2)
514                                         scrollbutton_height = Height /2;
515                                 else
516                                         scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
517                                 
518                         } else {
519                                 if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2)
520                                         scrollbutton_width = Width /2;
521                                 else
522                                         scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
523                         }
524                 }
525                                 
526                 private void CalcThumbArea ()
527                 {
528                         // Thumb area
529                         if (vert) {
530
531                                 thumb_area.Height = Height - scrollbutton_height -  scrollbutton_height;
532                                 thumb_area.X = 0;
533                                 thumb_area.Y = scrollbutton_height;
534                                 thumb_area.Width = Width;
535
536                                 if (Height < thumb_notshown_size)
537                                         thumb_size = 0;
538                                 else {
539                                         double per =  ((double) this.LargeChange / (double)((1 + maximum - minimum)));
540                                         thumb_size = 1 + (int) (thumb_area.Height * per);                                       
541                                         
542                                         if (thumb_size < thumb_min_size)
543                                                 thumb_size = thumb_min_size;
544                                 }                               
545
546                                 pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
547
548                         } else  {
549
550                                 thumb_area.Y = 0;
551                                 thumb_area.X = scrollbutton_width;
552                                 thumb_area.Height = Height;
553                                 thumb_area.Width = Width - scrollbutton_width -  scrollbutton_width;    
554                                 
555                                 if (Width < thumb_notshown_size)
556                                         thumb_size = 0;
557                                 else {
558                                         double per =  ((double) this.LargeChange / (double)((1 + maximum - minimum)));
559                                         thumb_size = 1 + (int) (thumb_area.Width * per);
560                                         
561                                         if (thumb_size < thumb_min_size)
562                                                 thumb_size = thumb_min_size;
563                                 }
564                                 
565                                 pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
566                         }
567                 }
568
569                 private void LargeIncrement ()
570                 {                       
571                         ScrollEventArgs event_args;
572                         int pos = position + large_change;
573                         
574                         event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos);
575                         OnScroll (event_args);                          
576                         pos = event_args.NewValue;                      
577                         
578                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
579                         OnScroll (event_args);          
580                         pos = event_args.NewValue;                      
581
582                         UpdatePos (pos, true);
583                 }
584
585                 private void LargeDecrement ()
586                 {                       
587                         ScrollEventArgs event_args;
588                         int pos = position - large_change;
589                         
590                         event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos);
591                         OnScroll (event_args);
592                         pos = event_args.NewValue;                      
593                         
594                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
595                         OnScroll (event_args);
596                         pos = event_args.NewValue;
597                         
598
599                         UpdatePos (pos, true);
600                 }               
601                 
602                 private void OnResizeSB (Object o, EventArgs e)
603                 {                       
604                         if (Width <= 0 || Height <= 0)
605                                 return;
606                         
607                         CalcButtonSizes ();
608                         CalcThumbArea ();
609                         UpdatePos (position, true);
610                 }
611
612                 private void OnPaintSB (PaintEventArgs pevent)
613                 {
614                         if (Paint != null) {
615                                 Paint (this, pevent);
616                         }
617                         ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this);
618                 }
619
620                 private void OnTimer (Object source, EventArgs e)
621                 {
622                         ClearDirty ();
623
624                         switch (timer_type) {
625
626                         case TimerType.HoldButton:
627                                 SetRepeatButtonTimer ();
628                                 break;
629
630                         case TimerType.RepeatButton:
631                         {
632                                 if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed &&
633                                                 position != Minimum)
634                                         SmallDecrement();
635
636                                 if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed &&
637                                         position != Maximum)
638                                         SmallIncrement();
639
640                                 break;
641                         }
642
643                         case TimerType.HoldThumbArea:
644                                 SetRepeatThumbAreaTimer ();
645                                 break;
646
647                         case TimerType.RepeatThumbArea:
648                         {
649                                 Point pnt, pnt_screen;
650                                 Rectangle thumb_area_screen = thumb_area;
651
652                                 pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y));
653                                 thumb_area_screen.X = pnt_screen.X;
654                                 thumb_area_screen.Y = pnt_screen.Y;
655                                 
656                                 if (thumb_area_screen.Contains (MousePosition) == false) {                                      
657                                         timer.Enabled = false;
658                                         thumb_moving = ThumbMoving.None;
659                                         DirtyThumbArea ();
660                                         InvalidateDirty ();
661                                 }                               
662                                 
663                                 pnt = PointToClient (MousePosition);
664                                 
665                                 if (vert)
666                                         lastclick_pos = pnt.Y;
667                                 else
668                                         lastclick_pos = pnt.X;
669
670                                 if (thumb_moving == ThumbMoving.Forward) {
671                                         if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) ||
672                                                 (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
673                                                 (thumb_area.Contains (pnt) == false)){
674                                                 timer.Enabled = false;                                          
675                                                 thumb_moving = ThumbMoving.None;
676                                                 Refresh ();                     
677                                                 return;
678                                         } else {
679                                                 LargeIncrement ();
680                                 }
681                                 }
682                                 else
683                                         if ((vert && (thumb_pos.Y < lastclick_pos)) ||
684                                                 (!vert && (thumb_pos.X  < lastclick_pos))){
685                                                 timer.Enabled = false;
686                                                 thumb_moving = ThumbMoving.None;
687                                                 Refresh ();                                             
688                                         } else {
689                                                 LargeDecrement ();
690                                         }
691
692                                 break;
693                         }
694                         default:
695                                 break;
696                         }
697
698                         InvalidateDirty ();
699                 }               
700
701                 private void OnMouseMoveSB (object sender, MouseEventArgs e)
702                 {
703                         if (MouseMove != null) {
704                                 MouseMove (this, e);
705                         }
706                                 
707                         if (Enabled == false || thumb_size == 0)
708                                 return;
709
710                         if (firstbutton_pressed) {
711                                 if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
712                                         firstbutton_state = ButtonState.Normal;
713                                         Invalidate (first_arrow_area);
714                                         return;
715                                 } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
716                                         firstbutton_state = ButtonState.Pushed;
717                                         Invalidate (first_arrow_area);
718                                         return;
719                                 }
720                         } else if (secondbutton_pressed) {
721                                 if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
722                                         secondbutton_state = ButtonState.Normal;
723                                         Invalidate (second_arrow_area);
724                                         return;
725                                 } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
726                                         secondbutton_state = ButtonState.Pushed;
727                                         Invalidate (second_arrow_area);
728                                         return;
729                                 }
730                         } else if (thumb_pressed == true) {
731                                 int pixel_pos;
732
733                                 if (vert) {
734
735                                         int mouse_click = e.Y;
736                                         int outside_curpos = thumb_area.Y + thumb_area.Height - thumb_size + lastclick_pos_thumb;
737                                         
738                                         
739                                         if (mouse_click > thumb_area.Y + thumb_area.Height) {
740                                                 outside_thumbarea_right = true;
741                                                 mouse_click = thumb_area.Y + thumb_area.Height;
742                                         }
743
744                                         if (mouse_click < thumb_area.Y) {
745                                                 outside_thumbarea_left = true;
746                                                 mouse_click = thumb_area.Y;
747                                         }
748
749                                         if (outside_thumbarea_right && mouse_click < outside_curpos) {
750                                                 outside_thumbarea_right = false;
751                                                 thumb_pixel_click_move_prev =
752                                                 thumb_pixel_click_move = outside_curpos;
753                                         }
754
755                                         if (outside_thumbarea_left && mouse_click > thumb_area.Y + lastclick_pos_thumb) {
756                                                 outside_thumbarea_left = false;
757                                                 thumb_pixel_click_move_prev =
758                                                 thumb_pixel_click_move = thumb_area.Y + lastclick_pos_thumb;
759                                         }
760
761                                         if (outside_thumbarea_right == false && outside_thumbarea_left == false) {
762                                                 pixel_pos = thumb_pos.Y + (thumb_pixel_click_move - thumb_pixel_click_move_prev);
763                                                 thumb_pixel_click_move_prev = thumb_pixel_click_move;
764                                                 thumb_pixel_click_move = mouse_click;
765                                                 
766                                                 UpdateThumbPos (pixel_pos, true);
767                                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
768                                         }
769
770                                 }
771                                 else {
772                                         int mouse_click = e.X;
773                                         int outside_curpos = thumb_area.X + thumb_area.Width - thumb_size + lastclick_pos_thumb;
774                                                                                 
775                                         if (mouse_click >  thumb_area.X + thumb_area.Width) {
776                                                 outside_thumbarea_right = true;
777                                                 mouse_click = thumb_area.X + thumb_area.Width;
778                                         }
779
780                                         if (mouse_click <  thumb_area.X) {
781                                                 outside_thumbarea_left = true;
782                                                 mouse_click = thumb_area.X;
783                                         }
784
785                                         if (outside_thumbarea_right && mouse_click < outside_curpos) {
786                                                 outside_thumbarea_right = false;
787                                                 thumb_pixel_click_move_prev =
788                                                 thumb_pixel_click_move = outside_curpos;
789                                         }
790
791                                         if (outside_thumbarea_left && mouse_click > thumb_area.X + lastclick_pos_thumb) {
792                                                 outside_thumbarea_left = false;
793                                                 thumb_pixel_click_move_prev =
794                                                 thumb_pixel_click_move = thumb_area.X + lastclick_pos_thumb;
795                                         }
796
797                                         if (outside_thumbarea_right == false && outside_thumbarea_left == false) {
798                                                 pixel_pos = thumb_pos.X + (thumb_pixel_click_move - thumb_pixel_click_move_prev);
799                                                 thumb_pixel_click_move_prev = thumb_pixel_click_move;
800                                                 thumb_pixel_click_move = mouse_click;
801                                                 UpdateThumbPos (pixel_pos, true);                                               
802                                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
803                                         }
804
805                                 }
806
807                                 Refresh ();
808                         }
809
810                 }
811
812                 private void OnMouseDownSB (object sender, MouseEventArgs e)
813                 {
814                         ClearDirty ();
815                         
816                         if (e.Button == MouseButtons.Right) {
817                                 if (MouseDown != null) {
818                                         MouseDown (this, e);
819                                 }
820                         }
821                         
822                         if (Enabled == false)
823                                 return;
824
825                         if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) {
826                                 this.Capture = true;                            
827                                 firstbutton_state = ButtonState.Pushed;
828                                 firstbutton_pressed = true;
829                                 Invalidate (first_arrow_area);
830                                 if (!timer.Enabled) {
831                                         SetHoldButtonClickTimer ();
832                                         timer.Enabled = true;
833                                 }
834                         }
835
836                         if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) {
837                                 this.Capture = true;                            
838                                 secondbutton_state = ButtonState.Pushed;
839                                 secondbutton_pressed = true;
840                                 Invalidate (second_arrow_area);
841                                 if (!timer.Enabled) {
842                                         SetHoldButtonClickTimer ();
843                                         timer.Enabled = true;
844                                 }
845                         }
846
847                         if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) {
848                                 thumb_pressed = true;
849                                 this.Capture = true;
850                                 if (vert) {
851                                         lastclick_pos_thumb = e.Y - thumb_pos.Y;
852                                         lastclick_pos = e.Y;                                    
853                                         thumb_pixel_click_move_prev = thumb_pixel_click_move = e.Y;
854                                 }
855                                 else {
856                                         lastclick_pos_thumb = e.X - thumb_pos.X;
857                                         lastclick_pos = e.X;
858                                         thumb_pixel_click_move_prev = thumb_pixel_click_move = e.X;
859                                 }
860                         } else {
861                                 if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) {
862
863                                         if (vert) {
864                                                 lastclick_pos_thumb = e.Y - thumb_pos.Y;
865                                                 lastclick_pos = e.Y;
866
867                                                 if (e.Y > thumb_pos.Y + thumb_pos.Height) {
868                                                         LargeIncrement ();                                                      
869                                                         thumb_moving = ThumbMoving.Forward;                                                     
870                                                         Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
871                                                                                       ClientRectangle.Width,
872                                                                                       ClientRectangle.Height -  (thumb_pos.Y + thumb_pos.Height) -
873                                                                                       scrollbutton_height));
874                                                 } else {
875                                                         LargeDecrement ();                                                      
876                                                         thumb_moving = ThumbMoving.Backwards;
877                                                         Dirty (new Rectangle (0,  scrollbutton_height,
878                                                                                       ClientRectangle.Width,
879                                                                                       thumb_pos.Y - scrollbutton_height));
880                                                 }
881                                         } else {
882
883                                                 lastclick_pos_thumb = e.X - thumb_pos.X;
884                                                 lastclick_pos = e.X;
885
886                                                 if (e.X > thumb_pos.X + thumb_pos.Width) {
887                                                         thumb_moving = ThumbMoving.Forward;
888                                                         LargeIncrement ();                                                      
889                                                         Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
890                                                                                       ClientRectangle.Width -  (thumb_pos.X + thumb_pos.Width) -
891                                                                                       scrollbutton_width,
892                                                                                       ClientRectangle.Height));
893                                                 } else {
894                                                         thumb_moving = ThumbMoving.Backwards;
895                                                         LargeDecrement ();                                                      
896                                                         Dirty (new Rectangle (scrollbutton_width,  0,
897                                                                                       thumb_pos.X - scrollbutton_width,
898                                                                                       ClientRectangle.Height));
899                                                 }
900                                         }
901
902                                         SetHoldThumbAreaTimer ();
903                                         timer.Enabled = true;
904                                         InvalidateDirty ();
905                                 }
906                         }
907                 }
908                 
909                 private void OnMouseUpSB (object sender, MouseEventArgs e)
910                 {
911                         ClearDirty ();
912
913                         if (e.Button == MouseButtons.Right) {
914                                 if (MouseUp != null) {
915                                         MouseUp (this, e);
916                                 }
917                         }
918                         
919                         if (Enabled == false)
920                                 return;
921
922                         timer.Enabled = false;
923                         if (thumb_moving != ThumbMoving.None) {
924                                 DirtyThumbArea ();
925                                 thumb_moving = ThumbMoving.None;
926                         }                       
927                         this.Capture = false;
928
929                         if (firstbutton_pressed) {
930                                 firstbutton_state = ButtonState.Normal;
931                                 if (first_arrow_area.Contains (e.X, e.Y)) {
932                                         SmallDecrement ();
933                                 }
934                                 firstbutton_pressed = false;
935                                 Dirty (first_arrow_area);
936                         } else if (secondbutton_pressed) {
937                                 secondbutton_state = ButtonState.Normal;
938                                 if (second_arrow_area.Contains (e.X, e.Y)) {
939                                         SmallIncrement ();
940                                 }
941                                 Dirty (second_arrow_area);
942                                 secondbutton_pressed = false;
943                         } else if (thumb_pressed == true) {
944                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
945                                 OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
946                                 thumb_pressed = false;
947                                 Refresh ();
948                                 return;
949                         }
950
951                         InvalidateDirty ();
952                 }
953
954                 private void OnKeyDownSB (Object o, KeyEventArgs key)
955                 {
956                         if (Enabled == false)
957                                 return;
958
959                         ClearDirty ();
960
961                         switch (key.KeyCode){
962                         case Keys.Up:
963                         {
964                                 SmallDecrement ();
965                                 break;
966                         }
967                         case Keys.Down:
968                         {
969                                 SmallIncrement ();
970                                 break;
971                         }
972                         case Keys.PageUp:
973                         {
974                                 LargeDecrement ();
975                                 break;
976                         }
977                         case Keys.PageDown:
978                         {
979                                 LargeIncrement ();
980                                 break;
981                         }
982                         case Keys.Home:
983                         {               
984                                 SetHomePosition ();                             
985                                 break;
986                         }                       
987                         case Keys.End:
988                         {       
989                                 SetEndPosition ();
990                                 break;
991                         }
992                         default:
993                                 break;
994                         }
995
996                         InvalidateDirty ();
997                 }               
998                 
999                 private void SetEndPosition () 
1000                 {                       
1001                         ScrollEventArgs event_args;
1002                         int pos = Maximum;
1003                         
1004                         event_args = new ScrollEventArgs (ScrollEventType.Last, pos);
1005                         OnScroll (event_args);
1006                         pos = event_args.NewValue;                      
1007                         
1008                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1009                         OnScroll (event_args);                  
1010                         pos = event_args.NewValue;                      
1011
1012                         SetValue (pos);
1013                 }
1014                 
1015                 private void SetHomePosition ()
1016                 {
1017                         ScrollEventArgs event_args;
1018                         int pos = Minimum;
1019                         
1020                         event_args = new ScrollEventArgs (ScrollEventType.First, pos);
1021                         OnScroll (event_args);
1022                         pos = event_args.NewValue;
1023                                                 
1024                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1025                         OnScroll (event_args);                  
1026                         pos = event_args.NewValue;                      
1027                         
1028                         SetValue (pos);
1029                 }               
1030
1031                 private void SmallIncrement ()
1032                 {
1033                         ScrollEventArgs event_args;
1034                         int pos = position + small_change;
1035                         
1036                         event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos);
1037                         OnScroll (event_args);                          
1038                         pos = event_args.NewValue;                      
1039                         
1040                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1041                         OnScroll (event_args);                  
1042                         pos = event_args.NewValue;                      
1043
1044                         UpdatePos (pos, true);
1045                 }
1046
1047                 private void SmallDecrement ()
1048                 {                       
1049                         ScrollEventArgs event_args;
1050                         int pos = position - small_change;
1051                         
1052                         event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos);
1053                         OnScroll (event_args);
1054                         pos = event_args.NewValue;
1055                                                 
1056                         event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1057                         OnScroll (event_args);                  
1058                         pos = event_args.NewValue;                      
1059
1060                         UpdatePos (pos, true);
1061                 }
1062                 
1063                 private void SetHoldButtonClickTimer ()
1064                 {
1065                         timer.Enabled = false;
1066                         timer.Interval = 200;
1067                         timer_type = TimerType.HoldButton;
1068                         timer.Enabled = true;
1069                 }
1070
1071                 private void SetRepeatButtonTimer ()
1072                 {
1073                         timer.Enabled = false;
1074                         timer.Interval = 50;
1075                         timer_type = TimerType.RepeatButton;
1076                         timer.Enabled = true;
1077                 }
1078
1079                 private void SetHoldThumbAreaTimer ()
1080                 {
1081                         timer.Enabled = false;
1082                         timer.Interval = 200;
1083                         timer_type = TimerType.HoldThumbArea;
1084                         timer.Enabled = true;
1085                 }
1086
1087                 private void SetRepeatThumbAreaTimer ()
1088                 {
1089                         timer.Enabled = false;
1090                         timer.Interval = 50;
1091                         timer_type = TimerType.RepeatThumbArea;
1092                         timer.Enabled = true;
1093                 }                               
1094                 
1095                 private void UpdatePos (int newPos, bool update_thumbpos)
1096                 {                       
1097                         int pos;
1098
1099                         if (newPos < minimum)
1100                                 pos = minimum;
1101                         else
1102                                 if (newPos > maximum + 1 - large_change)
1103                                         pos = maximum + 1 - large_change;
1104                                 else
1105                                         pos = newPos;
1106
1107                         // pos can't be less than minimum
1108                         if (pos < minimum)
1109                                 pos = minimum;
1110
1111                         if (update_thumbpos) {
1112                                 if (vert)
1113                                         UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), false);
1114                                 else
1115                                         UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), false);
1116                                 SetValue (pos);
1117                         }
1118                         else {
1119                                 position = pos; // Updates directly the value to avoid thumb pos update
1120                                 
1121                                 if (ValueChanged != null)
1122                                         ValueChanged (this, EventArgs.Empty);
1123                         }                       
1124                 }
1125
1126                 private void UpdateThumbPos (int pixel, bool update_value)
1127                 {
1128                         float new_pos = 0;
1129
1130                         if (vert) {
1131                                 Dirty (thumb_pos);
1132                                 if (pixel < thumb_area.Y)
1133                                         thumb_pos.Y = thumb_area.Y;
1134                                 else
1135                                         if (pixel > thumb_area.Y + thumb_area.Height - thumb_size)
1136                                                 thumb_pos.Y = thumb_area.Y +  thumb_area.Height - thumb_size;
1137                                         else
1138                                                 thumb_pos.Y = pixel;
1139
1140                                 thumb_pos.X = 0;
1141                                 thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize;
1142                                 thumb_pos.Height = thumb_size;
1143                                 new_pos = (float) (thumb_pos.Y - thumb_area.Y);
1144                                 new_pos = new_pos / pixel_per_pos;
1145
1146                                 Dirty (thumb_pos);
1147                         } else  {
1148                                 Dirty (thumb_pos);
1149                                 if (pixel < thumb_area.X)
1150                                         thumb_pos.X = thumb_area.X;
1151                                 else
1152                                         if (pixel > thumb_area.X + thumb_area.Width - thumb_size)
1153                                                 thumb_pos.X = thumb_area.X +  thumb_area.Width - thumb_size;
1154                                         else
1155                                                 thumb_pos.X = pixel;
1156
1157                                 thumb_pos.Y = 0;
1158                                 thumb_pos.Width =  thumb_size;
1159                                 thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize;
1160                                 new_pos = (float) (thumb_pos.X - thumb_area.X);
1161                                 new_pos = new_pos / pixel_per_pos;
1162
1163                                 Dirty (thumb_pos);
1164                         }
1165
1166                         if (update_value)
1167                                 UpdatePos ((int) new_pos + minimum, false);
1168                 }
1169
1170                 private void SetValue (int value)
1171                 {
1172                         if ( value < minimum || value > maximum )
1173                                 throw new ArgumentException(
1174                                         String.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
1175
1176                         if (position != value){
1177                                 position = value;
1178
1179                                 OnValueChanged (EventArgs.Empty);
1180                                 UpdatePos (value, true);
1181                         }
1182                 }
1183
1184                 private void ClearDirty ()
1185                 {
1186                         dirty = Rectangle.Empty;
1187                 }
1188
1189                 private void Dirty (Rectangle r)
1190                 {
1191                         if (dirty == Rectangle.Empty) {
1192                                 dirty = r;
1193                                 return;
1194                         }
1195                         dirty = Rectangle.Union (dirty, r);
1196                 }
1197
1198                 private void DirtyThumbArea ()
1199                 {
1200                         if (thumb_moving == ThumbMoving.Forward) {
1201                                 if (vert) {
1202                                         Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
1203                                                                       ClientRectangle.Width,
1204                                                                       ClientRectangle.Height -  (thumb_pos.Y + thumb_pos.Height) -
1205                                                                       scrollbutton_height));
1206                                 } else {
1207                                         Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
1208                                                                       ClientRectangle.Width -  (thumb_pos.X + thumb_pos.Width) -
1209                                                                       scrollbutton_width,
1210                                                                       ClientRectangle.Height));
1211                                 }
1212                         } else if (thumb_moving == ThumbMoving.Backwards) {
1213                                 if (vert) {
1214                                         Dirty(new Rectangle (0,  scrollbutton_height,
1215                                                                       ClientRectangle.Width,
1216                                                                       thumb_pos.Y - scrollbutton_height));
1217                                 } else {
1218                                         Dirty (new Rectangle (scrollbutton_width,  0,
1219                                                                       thumb_pos.X - scrollbutton_width,
1220                                                                       ClientRectangle.Height));
1221                                 }
1222                         }
1223                 }
1224
1225                 private void InvalidateDirty ()
1226                 {
1227                         Invalidate (dirty);
1228                         dirty = Rectangle.Empty;
1229                 }
1230
1231                 #endregion //Private Methods
1232          }
1233 }
1234
1235