- Streamlined Theme interfaces:
[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, Novell, Inc.
24 //
25 // Authors:
26 //      Jordi Mas i Hernandez   jordi@ximian.com
27 //
28 //
29 // $Revision: 1.22 $
30 // $Modtime: $
31 // $Log: ScrollBar.cs,v $
32 // Revision 1.22  2004/09/28 18:44:25  pbartok
33 // - Streamlined Theme interfaces:
34 //   * Each DrawXXX method for a control now is passed the object for the
35 //     control to be drawn in order to allow accessing any state the theme
36 //     might require
37 //
38 //   * ControlPaint methods for the theme now have a CP prefix to avoid
39 //     name clashes with the Draw methods for controls
40 //
41 //   * Every control now retrieves it's DefaultSize from the current theme
42 //
43 // Revision 1.21  2004/09/17 16:43:27  pbartok
44 // - Fixed behaviour of arrow buttons. Now properly behaves like Buttons (and
45 //   like Microsoft's scrollbar arrow buttons)
46 //
47 // Revision 1.20  2004/09/17 16:14:36  pbartok
48 // - Added missing release of keyboard/mouse capture
49 //
50 // Revision 1.19  2004/09/05 08:03:51  jordi
51 // fixes bugs, adds flashing on certain situations
52 //
53 // Revision 1.18  2004/08/31 10:35:04  jordi
54 // adds autorepeat timer, uses a single timer, fixes scrolling bugs, adds new methods
55 //
56 // Revision 1.17  2004/08/25 21:35:18  jordi
57 // more fixes to scrollbar
58 //
59 // Revision 1.16  2004/08/25 19:20:13  jordi
60 // small bug fix regarding bar position
61 //
62 // Revision 1.15  2004/08/24 18:37:02  jordi
63 // fixes formmating, methods signature, and adds missing events
64 //
65 // Revision 1.14  2004/08/23 22:53:15  jordi
66 // small fix
67 //
68 // Revision 1.13  2004/08/23 22:43:46  jordi
69 // *** empty log message ***
70 //
71 // Revision 1.11  2004/08/22 19:34:22  jackson
72 // Update the position through the Value property so the OnValueChanged event is raised.
73 //
74 // Revision 1.10  2004/08/21 20:22:21  pbartok
75 // - Replaced direct XplatUI calls with their Control counterpart
76 //
77 // Revision 1.9  2004/08/20 19:35:33  jackson
78 // Use the SWF timer so callbacks are run in the correct thread
79 //
80 // Revision 1.8  2004/08/20 19:34:26  jackson
81 // Use the SWF timer so callbacks are run in the correct thread
82 //
83 // Revision 1.7  2004/08/19 22:25:31  jordi
84 // theme enhancaments
85 //
86 // Revision 1.6  2004/08/18 15:56:12  jordi
87 // fixes to scrollbar: steps and multiple timers
88 //
89 // Revision 1.5  2004/08/10 19:21:27  jordi
90 // scrollbar enhancements and standarize on win colors defaults
91 //
92 // Revision 1.4  2004/08/10 15:41:50  jackson
93 // Allow control to handle buffering
94 //
95 // Revision 1.3  2004/07/27 15:29:40  jordi
96 // fixes scrollbar events
97 //
98 // Revision 1.2  2004/07/26 17:42:03  jordi
99 // Theme support
100 //
101
102 // COMPLETE
103
104 using System.Drawing;
105 using System.Drawing.Imaging;
106 using System.Drawing.Drawing2D;
107 using System.ComponentModel;
108 using System.Runtime.InteropServices;
109
110 namespace System.Windows.Forms
111 {
112         [DefaultEvent ("Scroll")]
113         [DefaultProperty ("Value")]
114         public class ScrollBar : Control
115         {
116                 #region Local Variables
117                 private int position;
118                 private int minimum;
119                 private int maximum;
120                 private int large_change;
121                 private int small_change;
122                 internal int scrollbutton_height;
123                 internal int scrollbutton_width;
124                 internal Rectangle paint_area = new Rectangle ();
125                 private ScrollBars type;
126                 private Rectangle first_arrow_area = new Rectangle ();          // up or left
127                 private Rectangle second_arrow_area = new Rectangle ();         // down or right
128                 private Rectangle thumb_pos = new Rectangle ();
129                 private Rectangle thumb_area = new Rectangle ();
130                 internal ButtonState firstbutton_state = ButtonState.Normal;
131                 internal ButtonState secondbutton_state = ButtonState.Normal;
132                 private bool firstbutton_pressed = false;
133                 private bool secondbutton_pressed = false;
134                 private bool thumb_pressed = false;
135                 private float pixel_per_pos = 0;
136                 private Timer timer = new Timer ();
137                 private TimerType timer_type;
138                 private int thumb_pixel_click_move;
139                 private int thumb_pixel_click_move_prev;
140                 private int thumb_size = 0;
141                 private const int thumb_min_size = 8;
142                 internal bool vert;
143                 private int lastclick_pos;      // Position of the last button-down event
144                 private int lastclick_pos_thumb;      // Position of the last button-down event relative to the thumb           
145                 private bool outside_thumbarea_right = false;
146                 private bool outside_thumbarea_left = false;
147                 internal ThumbMoving thumb_moving = ThumbMoving.None;
148                 #endregion      // Local Variables
149
150                 private enum TimerType
151                 {
152                         HoldButton,
153                         RepeatButton,
154                         HoldThumbArea,
155                         RepeatThumbArea
156                 }
157                 
158                 internal enum ThumbMoving
159                 {
160                         None,
161                         Forward,
162                         Backwards,
163                 }
164
165                 #region Events
166                 public new event EventHandler BackColorChanged;
167                 public new event EventHandler BackgroundImageChanged;
168                 public new event EventHandler Click;
169                 public new event EventHandler DoubleClick;
170                 public new event EventHandler FontChanged;
171                 public new event EventHandler ForeColorChanged;
172                 public new event EventHandler ImeModeChanged;
173                 public new event MouseEventHandler MouseDown;
174                 public new event MouseEventHandler MouseMove;
175                 public new event MouseEventHandler MouseUp;
176                 public new event PaintEventHandler Paint;
177                 public event ScrollEventHandler Scroll;
178                 public new event EventHandler TextChanged;
179                 public event EventHandler ValueChanged;
180                 #endregion Events
181
182                 public ScrollBar ()
183                 {
184                         position = 0;
185                         minimum = 0;
186                         maximum = 100;
187                         large_change = 10;
188                         small_change = 1;
189
190                         timer.Tick += new EventHandler (OnTimer);
191                         base.KeyDown += new KeyEventHandler (OnKeyDownSB);
192                         base.MouseDown += new MouseEventHandler (OnMouseDownSB);
193                         base.MouseUp += new MouseEventHandler (OnMouseUpSB);
194                         base.MouseMove += new MouseEventHandler (OnMouseMoveSB);
195                         base.Resize += new EventHandler (OnResizeSB);
196                         base.TabStop = false;
197
198                         if (ThemeEngine.Current.DoubleBufferingSupported == true) {
199                                 double_buffering = true;
200                         } else {
201                                 double_buffering = false;
202                         }
203
204                         SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
205                         SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
206                 }
207
208                 #region Internal & Private Properties
209                 internal Rectangle FirstArrowArea {
210                         get {
211                                 return this.first_arrow_area;
212                         }
213
214                         set {
215                                 this.first_arrow_area = value;
216                         }
217                 }
218
219                 internal Rectangle SecondArrowArea {
220                         get {
221                                 return this.second_arrow_area;
222                         }
223
224                         set {
225                                 this.second_arrow_area = value;
226                         }
227                 }
228
229                 internal Rectangle ThumbPos {
230                         get {
231                                 return thumb_pos;
232                         }
233
234                         set {
235                                 thumb_pos = value;
236                         }
237                 }
238                 #endregion      // Internal & Private Properties
239
240                 #region Public Properties
241
242                 [EditorBrowsable (EditorBrowsableState.Never)]
243                 public override Color BackColor
244                 {
245                         get { return base.BackColor; }
246                         set {
247                                 if (base.BackColor == value)
248                                         return;
249
250                                 if (BackColorChanged != null)
251                                         BackColorChanged (this, EventArgs.Empty);
252
253                                 base.BackColor = value;
254                                 Refresh ();
255                         }
256                 }
257
258                 [EditorBrowsable (EditorBrowsableState.Never)]
259                 public override Image BackgroundImage
260                 {
261                         get { return base.BackgroundImage; }
262                         set {
263                                 if (base.BackgroundImage == value)
264                                         return;
265
266                                 if (BackgroundImageChanged != null)
267                                         BackgroundImageChanged (this, EventArgs.Empty);
268
269                                 base.BackgroundImage = value;
270                         }
271                 }
272
273                 protected override CreateParams CreateParams
274                 {
275                         get {   return base.CreateParams; }
276                 }
277
278                 protected override ImeMode DefaultImeMode
279                 {
280                         get { return ImeMode.Disable; }
281                 }
282
283                 public override Font Font
284                 {
285                         get { return base.Font; }
286                         set {
287                                 if (base.Font == value)
288                                         return;
289
290                                 if (FontChanged != null)
291                                         FontChanged (this, EventArgs.Empty);
292
293                                 base.Font = value;
294                         }
295                 }
296
297                 [EditorBrowsable (EditorBrowsableState.Never)]
298                 public override Color ForeColor
299                 {
300                         get { return base.ForeColor; }
301                         set {
302                                 if (base.ForeColor == value)
303                                         return;
304
305                                 if (ForeColorChanged != null)
306                                         ForeColorChanged (this, EventArgs.Empty);
307
308                                 base.ForeColor = value;
309                                 Refresh ();
310                         }
311                 }
312
313                 [EditorBrowsable (EditorBrowsableState.Never)]
314                 public new ImeMode ImeMode
315                 {
316                         get { return base.ImeMode; }
317                         set {
318                                 if (base.ImeMode == value)
319                                         return;
320
321                                 if (ImeModeChanged != null)
322                                         ImeModeChanged (this, EventArgs.Empty);
323
324                                 base.ImeMode = value;
325                         }
326                 }
327
328                 public int LargeChange {
329                         get { return large_change; }
330                         set {
331                                 if (value < 0)
332                                         throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
333
334                                 if (large_change != value) {
335                                         large_change = value;
336                                         Refresh ();
337                                 }
338                         }
339                 }
340
341                 public int Maximum {
342                         get { return maximum; }
343                         set {
344                                 maximum = value;
345
346                                 if (maximum < minimum)
347                                         minimum = maximum;
348
349                                 Refresh ();
350                         }
351                 }
352
353                 public int Minimum {
354                         get { return minimum; }
355                         set {
356                                 minimum = value;
357
358                                 if (minimum > maximum)
359                                         maximum = minimum;
360
361                                 Refresh ();
362                         }
363                 }
364
365                 public int SmallChange {
366                         get { return small_change; }
367                         set {
368                                 if ( value < 0 )
369                                         throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
370
371                                 if (small_change != value) {
372                                         small_change = value;
373                                         Refresh ();
374                                 }
375                         }
376                 }
377
378                 public new bool TabStop {
379                         get { return base.TabStop; }
380                         set { base.TabStop = value; }
381                 }
382
383                 [EditorBrowsable (EditorBrowsableState.Never)]
384                 public override string Text {
385                          get { return base.Text;  }
386                          set { base.Text = value; }
387                 }
388
389                 public int Value {
390                         get { return position; }
391                         set {
392                                 if ( value < minimum || value > maximum )
393                                         throw new ArgumentException(
394                                                 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
395
396                                 if (position != value){
397                                         position = value;
398
399                                         if (ValueChanged != null)
400                                                 ValueChanged (this, EventArgs.Empty);
401
402                                         UpdatePos (Value, true);
403                                         Refresh ();
404                                 }
405                         }
406                 }
407
408                 #endregion //Public Properties
409
410                 #region Public Methods
411                 
412                 protected override void OnEnabledChanged (EventArgs e)
413                 {
414                         base.OnEnabledChanged (e);
415
416                         if (Enabled)
417                                 firstbutton_state = secondbutton_state = ButtonState.Normal;
418                         else
419                                 firstbutton_state = secondbutton_state = ButtonState.Inactive;
420
421                         Refresh ();
422                 }
423                 
424                 protected override void OnHandleCreated (System.EventArgs e)
425                 {
426                         base.OnHandleCreated (e);
427
428                         scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
429                         scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
430
431                         CreateBuffers (Width, Height);
432
433                         CalcThumbArea ();
434                         UpdatePos (Value, true);
435                 }
436
437                 protected virtual void OnScroll (ScrollEventArgs event_args)
438                 {
439                         if (Scroll == null)
440                                 return;
441
442                         Scroll (this, event_args);
443                 }
444
445                 protected virtual void OnValueChanged (EventArgs e)
446                 {
447                         if (ValueChanged != null)
448                                 ValueChanged (this, e);
449                 }
450
451                 public override string ToString()
452                 {
453                         return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
454                                                 GetType( ).FullName.ToString( ), minimum, maximum, position);
455                 }
456
457                 protected void UpdateScrollInfo ()
458                 {
459                         Refresh ();
460                 }
461
462                 protected override void WndProc (ref Message m)
463                 {
464                         switch ((Msg) m.Msg)
465                         {
466                                 case Msg.WM_PAINT:
467                                 {
468                                         PaintEventArgs  paint_event;
469
470                                         paint_event = XplatUI.PaintEventStart (Handle);
471                                         OnPaintSB (paint_event);
472                                         XplatUI.PaintEventEnd (Handle);
473                                         return;
474                                 }
475
476
477                                 case Msg.WM_ERASEBKGND:
478                                         m.Result = (IntPtr) 1; /// Disable background painting to avoid flickering
479                                         return;
480
481                                 default:
482                                         break;
483                         }
484
485                         base.WndProc (ref m);
486                 }
487
488                 #endregion //Public Methods
489
490                 #region Private Methods
491                 
492                 private void CalcThumbArea ()
493                 {
494                         // Thumb area
495                         if (vert) {
496
497                                 thumb_area.Height = Height - scrollbutton_height -  scrollbutton_height;
498                                 thumb_area.X = 0;
499                                 thumb_area.Y = scrollbutton_height;
500                                 thumb_area.Width = Width;
501
502                                 if (Height < scrollbutton_height * 2)
503                                         thumb_size = 0;
504                                 else {
505                                         double per =  ((double) large_change / (double)((1 + maximum - minimum)));
506                                         thumb_size = 1 + (int) (thumb_area.Height * per);
507
508                                         if (thumb_size < thumb_min_size)
509                                                 thumb_size = thumb_min_size;
510                                 }
511
512
513                                 pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - large_change) + 1));
514
515                         } else  {
516
517                                 thumb_area.Y = 0;
518                                 thumb_area.X = scrollbutton_width;
519                                 thumb_area.Height = Height;
520                                 thumb_area.Width = Width - scrollbutton_width -  scrollbutton_width;
521
522                                 if (Width < scrollbutton_width * 2)
523                                         thumb_size = 0;
524                                 else {
525                                         double per =  ((double) large_change / (double)((1 + maximum - minimum)));
526                                         thumb_size = 1 + (int) (thumb_area.Width * per);
527
528                                         if (thumb_size < thumb_min_size)
529                                                 thumb_size = thumb_min_size;
530                                 }
531                                 pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - large_change) + 1));
532                         }
533                 }
534                 
535                 private void Draw ()
536                 {
537                         ThemeEngine.Current.DrawScrollBar(DeviceContext, this.ClientRectangle, this);
538                 }
539
540                 private void LargeIncrement ()
541                 {
542                         UpdatePos (position + large_change, true);
543
544                         Refresh ();
545                         OnScroll (new ScrollEventArgs (ScrollEventType.LargeIncrement, position));
546                         OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
547                 }
548
549                 private void LargeDecrement ()
550                 {
551                         UpdatePos (position - large_change, true);
552
553                         Refresh ();
554                         OnScroll (new ScrollEventArgs (ScrollEventType.LargeDecrement, position));
555                         OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
556                 }
557
558                 private void OnResizeSB (Object o, EventArgs e)
559                 {
560                         if (Width <= 0 || Height <= 0)
561                                 return;
562
563                         paint_area.X = paint_area. Y = 0;
564                         paint_area.Width = Width;
565                         paint_area.Height = Height;
566
567                         CreateBuffers (Width, Height);
568
569                         CalcThumbArea ();
570                         UpdatePos (position, true);
571                 }
572
573                 private void OnPaintSB (PaintEventArgs pevent)
574                 {
575                         if (Width <= 0 || Height <=  0 || Visible == false)
576                                 return;
577
578                         /* Copies memory drawing buffer to screen*/
579                         Draw ();
580
581                         if (double_buffering)
582                                 pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
583
584                 }
585
586                 private void OnTimer (Object source, EventArgs e)
587                 {
588                         switch (timer_type) {
589
590                         case TimerType.HoldButton:
591                                 SetRepeatButtonTimer ();
592                                 break;
593
594                         case TimerType.RepeatButton:
595                         {
596                                 if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
597                                         SmallDecrement();
598
599                                 if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
600                                         SmallIncrement();
601
602                                 break;
603                         }
604
605                         case TimerType.HoldThumbArea:
606                                 SetRepeatThumbAreaTimer ();
607                                 break;
608
609                         case TimerType.RepeatThumbArea:
610                         {
611                                 Point pnt;\r
612                                 pnt = PointToClient (MousePosition);
613                                 
614                                 if (vert)
615                                         lastclick_pos = pnt.Y;
616                                 else
617                                         lastclick_pos = pnt.X;
618
619                                 if (thumb_moving == ThumbMoving.Forward) {
620                                         if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) ||
621                                                 (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
622                                                 (thumb_area.Contains (pnt) == false)){
623                                                 timer.Enabled = false;                                          
624                                                 thumb_moving = ThumbMoving.None;
625                                                 Refresh ();                     
626                                         } else
627                                                 LargeIncrement ();
628                                 }
629                                 else
630                                         if ((vert && (thumb_pos.Y < lastclick_pos)) ||
631                                                 (!vert && (thumb_pos.X  < lastclick_pos))){
632                                                 timer.Enabled = false;
633                                                 thumb_moving = ThumbMoving.None;
634                                                 Refresh ();                                             
635                                         } else
636                                                 LargeDecrement ();
637
638                                 break;
639                         }
640                         default:
641                                 break;
642                         }
643
644                 }               
645
646                 private void OnMouseMoveSB (object sender, MouseEventArgs e)
647                 {
648                         if (firstbutton_pressed) {
649                                 if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
650                                         firstbutton_state = ButtonState.Normal;
651                                         Refresh ();
652                                         return;
653                                 } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
654                                         firstbutton_state = ButtonState.Pushed;
655                                         Refresh ();
656                                         return;
657                                 }
658                         } else if (secondbutton_pressed) {
659                                 if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
660                                         secondbutton_state = ButtonState.Normal;
661                                         Refresh ();
662                                         return;
663                                 } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
664                                         secondbutton_state = ButtonState.Pushed;
665                                         Refresh ();
666                                         return;
667                                 }
668                         } else if (thumb_pressed == true) {
669                                 int pixel_pos;
670
671                                 if (vert) {
672
673                                         int mouse_click = e.Y;
674                                         int outside_curpos = thumb_area.Y + thumb_area.Height - thumb_size + lastclick_pos_thumb;
675                                         
676                                         
677                                         if (mouse_click > thumb_area.Y + thumb_area.Height) {
678                                                 outside_thumbarea_right = true;
679                                                 mouse_click = thumb_area.Y + thumb_area.Height;
680                                         }
681
682                                         if (mouse_click < thumb_area.Y) {
683                                                 outside_thumbarea_left = true;
684                                                 mouse_click = thumb_area.Y;
685                                         }
686
687                                         if (outside_thumbarea_right && mouse_click < outside_curpos) {
688                                                 outside_thumbarea_right = false;
689                                                 thumb_pixel_click_move_prev =
690                                                 thumb_pixel_click_move = outside_curpos;
691                                         }
692
693                                         if (outside_thumbarea_left && mouse_click > thumb_area.Y + lastclick_pos_thumb) {
694                                                 outside_thumbarea_left = false;
695                                                 thumb_pixel_click_move_prev =
696                                                 thumb_pixel_click_move = thumb_area.Y + lastclick_pos_thumb;
697                                         }
698
699                                         if (outside_thumbarea_right == false && outside_thumbarea_left == false) {
700                                                 pixel_pos = thumb_pos.Y + (thumb_pixel_click_move - thumb_pixel_click_move_prev);
701                                                 thumb_pixel_click_move_prev = thumb_pixel_click_move;
702                                                 thumb_pixel_click_move = mouse_click;
703                                                 UpdateThumbPos (pixel_pos, true);
704                                         }
705
706                                 }
707                                 else {
708                                         int mouse_click = e.X;
709                                         int outside_curpos = thumb_area.X + thumb_area.Width - thumb_size + lastclick_pos_thumb;
710                                                                                 
711                                         if (mouse_click >  thumb_area.X + thumb_area.Width) {
712                                                 outside_thumbarea_right = true;
713                                                 mouse_click = thumb_area.X + thumb_area.Width;
714                                         }
715
716                                         if (mouse_click <  thumb_area.X) {
717                                                 outside_thumbarea_left = true;
718                                                 mouse_click = thumb_area.X;
719                                         }
720
721                                         if (outside_thumbarea_right && mouse_click < outside_curpos) {
722                                                 outside_thumbarea_right = false;
723                                                 thumb_pixel_click_move_prev =
724                                                 thumb_pixel_click_move = outside_curpos;
725                                         }
726
727                                         if (outside_thumbarea_left && mouse_click > thumb_area.X + lastclick_pos_thumb) {
728                                                 outside_thumbarea_left = false;
729                                                 thumb_pixel_click_move_prev =
730                                                 thumb_pixel_click_move = thumb_area.X + lastclick_pos_thumb;
731                                         }
732
733                                         if (outside_thumbarea_right == false && outside_thumbarea_left == false) {
734                                                 pixel_pos = thumb_pos.X + (thumb_pixel_click_move - thumb_pixel_click_move_prev);
735                                                 thumb_pixel_click_move_prev = thumb_pixel_click_move;
736                                                 thumb_pixel_click_move = mouse_click;
737                                                 UpdateThumbPos (pixel_pos, true);
738                                         }
739
740                                 }
741
742                                 Refresh ();
743                         }
744
745                 }
746
747                 private void OnMouseDownSB (object sender, MouseEventArgs e)
748                 {
749                         if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) {
750                                 this.Capture = true;                            
751                                 firstbutton_state = ButtonState.Pushed;
752                                 firstbutton_pressed = true;
753                                 Refresh ();                             
754                         }
755
756                         if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) {
757                                 this.Capture = true;                            
758                                 secondbutton_state = ButtonState.Pushed;
759                                 secondbutton_pressed = true;
760                                 Refresh ();
761                         }
762
763                         if (thumb_pos.Contains (e.X, e.Y)) {
764                                 thumb_pressed = true;
765                                 this.Capture = true;
766                                 Refresh ();
767                                 if (vert) {
768                                         lastclick_pos_thumb = e.Y - thumb_pos.Y;
769                                         lastclick_pos = e.Y;                                    
770                                         thumb_pixel_click_move_prev = thumb_pixel_click_move = e.Y;
771                                 }
772                                 else {
773                                         lastclick_pos_thumb = e.X - thumb_pos.X;
774                                         lastclick_pos = e.X;
775                                         thumb_pixel_click_move_prev = thumb_pixel_click_move = e.X;
776                                 }
777                         }
778                         else {
779                                 if (thumb_area.Contains (e.X, e.Y)) {
780
781                                         if (vert) {
782                                                 lastclick_pos_thumb = e.Y - thumb_pos.Y;
783                                                 lastclick_pos = e.Y;
784
785                                                 if (e.Y > thumb_pos.Y + thumb_pos.Height) {
786                                                         LargeIncrement ();                                                      
787                                                         thumb_moving = ThumbMoving.Forward;                                                     
788                                                 }
789                                                 else {
790                                                         LargeDecrement ();                                                      
791                                                         thumb_moving = ThumbMoving.Backwards;
792                                                 }
793                                         }
794                                         else    {
795
796                                                 lastclick_pos_thumb = e.X - thumb_pos.X;
797                                                 lastclick_pos = e.X;
798
799                                                 if (e.X > thumb_pos.X + thumb_pos.Width) {
800                                                         thumb_moving = ThumbMoving.Forward;
801                                                         LargeIncrement ();                                                      
802                                                 }
803                                                 else {
804                                                         thumb_moving = ThumbMoving.Backwards;
805                                                         LargeDecrement ();                                                      
806                                                 }
807                                         }
808
809                                         SetHoldThumbAreaTimer ();
810                                         timer.Enabled = true;
811                                         Refresh ();
812                                 }
813                         }
814                                 
815                         
816
817                         /* If arrows are pressed, fire timer for auto-repeat */
818                         if ((((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
819                         || ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) &&
820                                 timer.Enabled == false) {
821                                 SetHoldButtonClickTimer ();
822                                 timer.Enabled = true;
823                         }
824                 }
825                 
826                 private void OnMouseUpSB (object sender, MouseEventArgs e)
827                 {
828                         timer.Enabled = false;
829                         
830                         if (thumb_moving != ThumbMoving.None) {
831                                 thumb_moving = ThumbMoving.None;
832                                 Refresh ();
833                         }                       
834
835                         this.Capture = false;
836
837                         if (firstbutton_pressed) {
838                                 firstbutton_state = ButtonState.Normal;
839                                 if (first_arrow_area.Contains (e.X, e.Y)) {
840                                         SmallDecrement ();
841                                 }
842                                 firstbutton_pressed = false;
843                                 return;
844                         } else if (secondbutton_pressed) {
845                                 secondbutton_state = ButtonState.Normal;
846                                 if (second_arrow_area.Contains (e.X, e.Y)) {
847                                         SmallIncrement ();
848                                 }
849                                 secondbutton_pressed = false;
850                                 return;
851                         } else if (thumb_pressed == true) {
852                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
853                                 OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
854                                 thumb_pressed = false;
855                                 Refresh ();
856                         }
857                 }
858
859                 private void OnKeyDownSB (Object o, KeyEventArgs key)
860                 {
861                         switch (key.KeyCode){
862                         case Keys.Up:
863                         {
864                                 SmallDecrement ();
865                                 break;
866                         }
867                         case Keys.Down:
868                         {
869                                 SmallIncrement ();
870                                 break;
871                         }
872                         case Keys.PageUp:
873                         {
874                                 LargeDecrement ();
875                                 break;
876                         }
877                         case Keys.PageDown:
878                         {
879                                 LargeIncrement ();
880                                 break;
881                         }
882                         default:
883                                 break;
884                         }
885
886                 }
887
888                 private void SmallIncrement ()
889                 {
890                         UpdatePos (position + small_change, true);
891
892                         Refresh ();
893                         OnScroll (new ScrollEventArgs (ScrollEventType.SmallIncrement, position));
894                         OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
895                 }
896
897                 private void SmallDecrement ()
898                 {
899                         UpdatePos (position - small_change, true);
900
901                         Refresh ();
902                         OnScroll (new ScrollEventArgs (ScrollEventType.SmallDecrement, position));
903                         OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
904                 }
905                 
906                 private void SetHoldButtonClickTimer ()
907                 {
908                         timer.Enabled = false;
909                         timer.Interval = 200;
910                         timer_type = TimerType.HoldButton;
911                         timer.Enabled = true;
912                 }
913
914                 private void SetRepeatButtonTimer ()
915                 {
916                         timer.Enabled = false;
917                         timer.Interval = 50;
918                         timer_type = TimerType.RepeatButton;
919                         timer.Enabled = true;
920                 }
921
922                 private void SetHoldThumbAreaTimer ()
923                 {
924                         timer.Enabled = false;
925                         timer.Interval = 200;
926                         timer_type = TimerType.HoldThumbArea;
927                         timer.Enabled = true;
928                 }
929
930                 private void SetRepeatThumbAreaTimer ()
931                 {
932                         timer.Enabled = false;
933                         timer.Interval = 50;
934                         timer_type = TimerType.RepeatThumbArea;
935                         timer.Enabled = true;
936                 }               
937                 
938                 private void UpdatePos (int newPos, bool update_thumbpos)
939                 {
940                         int old = position;
941                         int pos;
942
943                         if (newPos < minimum)
944                                 pos = minimum;
945                         else
946                                 if (newPos > maximum + 1 - large_change)
947                                         pos = maximum + 1 - large_change;
948                                         else
949                                                 pos = newPos;
950
951                         if (update_thumbpos) {
952                                 if (vert)
953                                         UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), false);
954                                 else
955                                         UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), false);
956
957                                 Value = pos;
958                         }
959                         else {
960                                 position = pos; // Updates directly the value to avoid thumb pos update
961                                 
962                                 if (ValueChanged != null)
963                                         ValueChanged (this, EventArgs.Empty);
964                         }
965
966                         if (pos != old) // Fire event
967                                 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, pos));
968
969                 }
970
971                 private void UpdateThumbPos (int pixel, bool update_value)
972                 {
973                         float new_pos = 0;
974
975                         if (vert) {
976                                 if (pixel < thumb_area.Y)
977                                         thumb_pos.Y = thumb_area.Y;
978                                 else
979                                         if (pixel > thumb_area.Y + thumb_area.Height - thumb_size)
980                                                 thumb_pos.Y = thumb_area.Y +  thumb_area.Height - thumb_size;
981                                         else
982                                                 thumb_pos.Y = pixel;
983
984                                 thumb_pos.X = 0;
985                                 thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize;
986                                 thumb_pos.Height = thumb_size;
987                                 new_pos = (float) (thumb_pos.Y - thumb_area.Y);
988                                 new_pos = new_pos / pixel_per_pos;
989
990                         } else  {
991
992                                 if (pixel < thumb_area.X)
993                                         thumb_pos.X = thumb_area.X;
994                                 else
995                                         if (pixel > thumb_area.X + thumb_area.Width - thumb_size)
996                                                 thumb_pos.X = thumb_area.X +  thumb_area.Width - thumb_size;
997                                         else
998                                                 thumb_pos.X = pixel;
999
1000                                 thumb_pos.Y = 0;
1001                                 thumb_pos.Width =  thumb_size;
1002                                 thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize;
1003                                 new_pos = (float) (thumb_pos.X - thumb_area.X);
1004                                 new_pos = new_pos / pixel_per_pos;
1005                         }
1006
1007                         if (update_value)
1008                                 UpdatePos ((int) new_pos + minimum, false);
1009                 }
1010
1011
1012                 #endregion //Private Methods
1013          }
1014 }
1015
1016