2 // System.Windows.Forms.ScrollBar.cs
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:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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.
23 // Copyright (C) 2004-2005, Novell, Inc.
26 // Jordi Mas i Hernandez jordi@ximian.com
33 using System.Drawing.Imaging;
34 using System.Drawing.Drawing2D;
35 using System.ComponentModel;
36 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms
40 [DefaultEvent ("Scroll")]
41 [DefaultProperty ("Value")]
42 public abstract class ScrollBar : Control
44 #region Local Variables
48 private int large_change;
49 private int small_change;
50 internal int scrollbutton_height;
51 internal int scrollbutton_width;
52 private Rectangle first_arrow_area = new Rectangle (); // up or left
53 private Rectangle second_arrow_area = new Rectangle (); // down or right
54 private Rectangle thumb_pos = new Rectangle ();
55 private Rectangle thumb_area = new Rectangle ();
56 internal ButtonState firstbutton_state = ButtonState.Normal;
57 internal ButtonState secondbutton_state = ButtonState.Normal;
58 private bool firstbutton_pressed = false;
59 private bool secondbutton_pressed = false;
60 private bool thumb_pressed = false;
61 private float pixel_per_pos = 0;
62 private Timer timer = new Timer ();
63 private TimerType timer_type;
64 private int thumb_size = 40;
65 private const int thumb_min_size = 8;
66 private const int thumb_notshown_size = 40;
68 internal bool implicit_control;
69 private int lastclick_pos; // Position of the last button-down event
70 private int thumbclick_offset; // Position of the last button-down event relative to the thumb edge
71 private Rectangle dirty;
73 internal ThumbMoving thumb_moving = ThumbMoving.None;
74 #endregion // Local Variables
76 private enum TimerType
84 internal enum ThumbMoving
94 [EditorBrowsable (EditorBrowsableState.Never)]
95 public new event EventHandler BackColorChanged {
96 add { base.BackColorChanged += value; }
97 remove { base.BackColorChanged -= value; }
101 [EditorBrowsable (EditorBrowsableState.Never)]
102 public new event EventHandler BackgroundImageChanged {
103 add { base.BackgroundImageChanged += value; }
104 remove { base.BackgroundImageChanged -= value; }
108 [EditorBrowsable (EditorBrowsableState.Never)]
109 public new event EventHandler Click {
110 add { base.Click += value; }
111 remove { base.Click -= value; }
115 [EditorBrowsable (EditorBrowsableState.Never)]
116 public new event EventHandler DoubleClick {
117 add { base.DoubleClick += value; }
118 remove { base.DoubleClick -= value; }
122 [EditorBrowsable (EditorBrowsableState.Never)]
123 public new event EventHandler FontChanged {
124 add { base.FontChanged += value; }
125 remove { base.FontChanged -= value; }
129 [EditorBrowsable (EditorBrowsableState.Never)]
130 public new event EventHandler ForeColorChanged {
131 add { base.ForeColorChanged += value; }
132 remove { base.ForeColorChanged -= value; }
136 [EditorBrowsable (EditorBrowsableState.Never)]
137 public new event EventHandler ImeModeChanged {
138 add { base.ImeModeChanged += value; }
139 remove { base.ImeModeChanged -= value; }
143 [EditorBrowsable (EditorBrowsableState.Never)]
144 public new event MouseEventHandler MouseDown {
145 add { base.MouseDown += value; }
146 remove { base.MouseDown -= value; }
150 [EditorBrowsable (EditorBrowsableState.Never)]
151 public new event MouseEventHandler MouseMove {
152 add { base.MouseMove += value; }
153 remove { base.MouseMove -= value; }
157 [EditorBrowsable (EditorBrowsableState.Never)]
158 public new event MouseEventHandler MouseUp {
159 add { base.MouseUp += value; }
160 remove { base.MouseUp -= value; }
164 [EditorBrowsable (EditorBrowsableState.Never)]
165 public new event PaintEventHandler Paint {
166 add { base.Paint += value; }
167 remove { base.Paint -= value; }
170 static object ScrollEvent = new object ();
171 static object ValueChangedEvent = new object ();
173 public event ScrollEventHandler Scroll {
174 add { Events.AddHandler (ScrollEvent, value); }
175 remove { Events.RemoveHandler (ScrollEvent, value); }
179 [EditorBrowsable (EditorBrowsableState.Never)]
180 public new event EventHandler TextChanged {
181 add { base.TextChanged += value; }
182 remove { base.TextChanged -= value; }
185 public event EventHandler ValueChanged {
186 add { Events.AddHandler (ValueChangedEvent, value); }
187 remove { Events.RemoveHandler (ValueChangedEvent, value); }
199 timer.Tick += new EventHandler (OnTimer);
200 base.KeyDown += new KeyEventHandler (OnKeyDownSB);
201 base.MouseDown += new MouseEventHandler (OnMouseDownSB);
202 base.MouseUp += new MouseEventHandler (OnMouseUpSB);
203 base.MouseMove += new MouseEventHandler (OnMouseMoveSB);
204 base.Resize += new EventHandler (OnResizeSB);
205 base.TabStop = false;
206 base.Cursor = Cursors.Default;
208 SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
210 | ControlStyles.UseTextForAccessibility
215 #region Internal & Private Properties
216 internal Rectangle FirstArrowArea {
218 return this.first_arrow_area;
222 this.first_arrow_area = value;
226 internal Rectangle SecondArrowArea {
228 return this.second_arrow_area;
232 this.second_arrow_area = value;
236 internal Rectangle ThumbPos {
245 #endregion // Internal & Private Properties
247 #region Public Properties
249 [EditorBrowsable (EditorBrowsableState.Never)]
251 public override Color BackColor
253 get { return base.BackColor; }
255 if (base.BackColor == value)
257 base.BackColor = value;
262 [EditorBrowsable (EditorBrowsableState.Never)]
264 public override Image BackgroundImage
266 get { return base.BackgroundImage; }
268 if (base.BackgroundImage == value)
271 base.BackgroundImage = value;
275 protected override CreateParams CreateParams
277 get { return base.CreateParams; }
280 protected override ImeMode DefaultImeMode
282 get { return ImeMode.Disable; }
285 [EditorBrowsable (EditorBrowsableState.Never)]
287 public override Font Font
289 get { return base.Font; }
291 if (base.Font.Equals (value))
298 [EditorBrowsable (EditorBrowsableState.Never)]
300 public override Color ForeColor
302 get { return base.ForeColor; }
304 if (base.ForeColor == value)
307 base.ForeColor = value;
312 [EditorBrowsable (EditorBrowsableState.Never)]
314 public new ImeMode ImeMode
316 get { return base.ImeMode; }
318 if (base.ImeMode == value)
321 base.ImeMode = value;
326 [RefreshProperties(RefreshProperties.Repaint)]
327 [MWFDescription("Scroll amount when clicking in the scroll area"), MWFCategory("Behaviour")]
328 public int LargeChange {
330 if (large_change > maximum)
331 return (maximum + 1);
337 throw new ArgumentException( string.Format("Value '{0}' must be greater than or equal to 0.", value));
339 if (large_change != value) {
340 large_change = value;
342 // thumb area depends on large change value,
343 // so we need to recalculate it.
345 UpdatePos (Value, true);
352 [RefreshProperties(RefreshProperties.Repaint)]
353 [MWFDescription("Highest value for scrollbar"), MWFCategory("Behaviour")]
355 get { return maximum; }
357 if (maximum == value)
362 if (maximum < minimum)
365 // thumb area depends on maximum value,
366 // so we need to recalculate it.
368 UpdatePos (Value, true);
373 internal void SetValues (int maximum, int large_change)
375 SetValues (-1, maximum, -1, large_change);
378 internal void SetValues (int minimum, int maximum, int small_change, int large_change)
382 if (-1 != minimum && this.minimum != minimum) {
383 this.minimum = minimum;
385 if (minimum > this.maximum)
386 this.maximum = minimum;
390 if (-1 != maximum && this.maximum != maximum) {
391 this.maximum = maximum;
393 if (maximum < this.minimum)
394 this.minimum = maximum;
398 if (-1 != small_change && this.small_change != small_change) {
399 this.small_change = small_change;
402 if (this.large_change != large_change) {
403 this.large_change = large_change;
409 UpdatePos (Value, true);
415 [RefreshProperties(RefreshProperties.Repaint)]
416 [MWFDescription("Smallest value for scrollbar"), MWFCategory("Behaviour")]
418 get { return minimum; }
420 if (minimum == value)
425 if (minimum > maximum)
428 // thumb area depends on minimum value,
429 // so we need to recalculate it.
431 UpdatePos (Value, true);
437 [MWFDescription("Scroll amount when clicking scroll arrows"), MWFCategory("Behaviour")]
438 public int SmallChange {
439 get { return small_change; }
442 throw new ArgumentException( string.Format("Value '{0}' must be greater than or equal to 0.", value));
444 if (small_change != value) {
445 small_change = value;
446 UpdatePos (Value, true);
452 [DefaultValue (false)]
453 public new bool TabStop {
454 get { return base.TabStop; }
455 set { base.TabStop = value; }
458 [EditorBrowsable (EditorBrowsableState.Never)]
461 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
462 public override string Text {
463 get { return base.Text; }
464 set { base.Text = value; }
469 [MWFDescription("Current value for scrollbar"), MWFCategory("Behaviour")]
471 get { return position; }
473 if ( value < minimum || value > maximum )
474 throw new ArgumentException(
475 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
477 if (position != value){
480 OnValueChanged (EventArgs.Empty);
482 if (IsHandleCreated) {
483 Rectangle thumb_rect = thumb_pos;
485 UpdateThumbPos ((vert ? thumb_area.Y : thumb_area.X) + (int)(((float)(position - minimum)) * pixel_per_pos), false, false);
487 MoveThumb (thumb_rect, vert ? thumb_pos.Y : thumb_pos.X);
493 #endregion //Public Properties
495 #region Public Methods
497 protected override void OnEnabledChanged (EventArgs e)
499 base.OnEnabledChanged (e);
502 firstbutton_state = secondbutton_state = ButtonState.Normal;
504 firstbutton_state = secondbutton_state = ButtonState.Inactive;
509 protected override void OnHandleCreated (System.EventArgs e)
511 base.OnHandleCreated (e);
515 UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), true, false);
518 protected virtual void OnScroll (ScrollEventArgs event_args)
520 ScrollEventHandler eh = (ScrollEventHandler)(Events [ScrollEvent]);
524 if (event_args.NewValue < Minimum) {
525 event_args.NewValue = Minimum;
528 if (event_args.NewValue > Maximum) {
529 event_args.NewValue = Maximum;
532 eh (this, event_args);
535 private void SendWMScroll(ScrollBarCommands cmd) {
536 if ((Parent != null) && Parent.IsHandleCreated) {
538 XplatUI.SendMessage(Parent.Handle, Msg.WM_VSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle);
540 XplatUI.SendMessage(Parent.Handle, Msg.WM_HSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle);
545 protected virtual void OnValueChanged (EventArgs e)
547 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
552 public override string ToString()
554 return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
555 GetType( ).FullName.ToString( ), minimum, maximum, position);
558 protected void UpdateScrollInfo ()
563 protected override void WndProc (ref Message m)
565 base.WndProc (ref m);
568 #endregion //Public Methods
570 #region Private Methods
572 private void CalcButtonSizes ()
575 if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2)
576 scrollbutton_height = Height /2;
578 scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
581 if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2)
582 scrollbutton_width = Width /2;
584 scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
588 private void CalcThumbArea ()
593 thumb_area.Height = Height - scrollbutton_height - scrollbutton_height;
595 thumb_area.Y = scrollbutton_height;
596 thumb_area.Width = Width;
598 if (Height < thumb_notshown_size)
601 double per = ((double) this.LargeChange / (double)((1 + maximum - minimum)));
602 thumb_size = 1 + (int) (thumb_area.Height * per);
604 if (thumb_size < thumb_min_size)
605 thumb_size = thumb_min_size;
608 pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
613 thumb_area.X = scrollbutton_width;
614 thumb_area.Height = Height;
615 thumb_area.Width = Width - scrollbutton_width - scrollbutton_width;
617 if (Width < thumb_notshown_size)
620 double per = ((double) this.LargeChange / (double)((1 + maximum - minimum)));
621 thumb_size = 1 + (int) (thumb_area.Width * per);
623 if (thumb_size < thumb_min_size)
624 thumb_size = thumb_min_size;
627 pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - this.LargeChange) + 1));
631 private void LargeIncrement ()
633 ScrollEventArgs event_args;
634 int pos = Math.Min (Maximum - large_change + 1, position + large_change);
636 event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos);
637 OnScroll (event_args);
638 Value = event_args.NewValue;
640 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
641 OnScroll (event_args);
642 Value = event_args.NewValue;
645 private void LargeDecrement ()
647 ScrollEventArgs event_args;
648 int pos = Math.Max (Minimum, position - large_change);
650 event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos);
651 OnScroll (event_args);
652 Value = event_args.NewValue;
654 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
655 OnScroll (event_args);
656 Value = event_args.NewValue;
659 private void OnResizeSB (Object o, EventArgs e)
661 if (Width <= 0 || Height <= 0)
666 UpdatePos (position, true);
671 internal override void OnPaintInternal (PaintEventArgs pevent)
673 ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this);
676 private void OnTimer (Object source, EventArgs e)
680 switch (timer_type) {
682 case TimerType.HoldButton:
683 SetRepeatButtonTimer ();
686 case TimerType.RepeatButton:
688 if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Minimum) {
690 SendWMScroll(ScrollBarCommands.SB_LINEUP);
693 if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Maximum) {
695 SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
701 case TimerType.HoldThumbArea:
702 SetRepeatThumbAreaTimer ();
705 case TimerType.RepeatThumbArea:
707 Point pnt, pnt_screen;
708 Rectangle thumb_area_screen = thumb_area;
710 pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y));
711 thumb_area_screen.X = pnt_screen.X;
712 thumb_area_screen.Y = pnt_screen.Y;
714 if (thumb_area_screen.Contains (MousePosition) == false) {
715 timer.Enabled = false;
716 thumb_moving = ThumbMoving.None;
721 pnt = PointToClient (MousePosition);
724 lastclick_pos = pnt.Y;
726 lastclick_pos = pnt.X;
728 if (thumb_moving == ThumbMoving.Forward) {
729 if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) ||
730 (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
731 (thumb_area.Contains (pnt) == false)) {
732 timer.Enabled = false;
733 thumb_moving = ThumbMoving.None;
738 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
741 if ((vert && (thumb_pos.Y < lastclick_pos)) ||
742 (!vert && (thumb_pos.X < lastclick_pos))){
743 timer.Enabled = false;
744 thumb_moving = ThumbMoving.None;
745 SendWMScroll(ScrollBarCommands.SB_PAGEUP);
749 SendWMScroll(ScrollBarCommands.SB_PAGEUP);
762 private void MoveThumb (Rectangle original_thumbpos, int value)
764 /* so, the reason this works can best be
765 * described by the following 1 dimensional
768 * say you have a scrollbar thumb positioned
771 * <---------------------| |------------------------------>
773 * and you want it to end up looking like this:
775 * <-----------------------------| |---------------------->
777 * that can be done with the scrolling api by
778 * extending the rectangle to encompass both
781 * start of range end of range
783 * <---------------------| |-------|---------------------->
785 * so, we end up scrolling just this little region:
789 * and end up with ********| |
791 * where ****** is space that is automatically
794 * It's clear that in both cases (left to
795 * right, right to left) we need to extend the
796 * size of the scroll rectangle to encompass
797 * both. In the right to left case, we also
798 * need to decrement the X coordinate.
800 * We call Update after scrolling to make sure
801 * there's no garbage left in the window to be
802 * copied again if we're called before the
803 * paint events have been handled.
809 delta = value - original_thumbpos.Y;
812 original_thumbpos.Y += delta;
813 original_thumbpos.Height -= delta;
816 original_thumbpos.Height += delta;
819 XplatUI.ScrollWindow (Handle, original_thumbpos, 0, delta, false);
822 delta = value - original_thumbpos.X;
825 original_thumbpos.X += delta;
826 original_thumbpos.Width -= delta;
829 original_thumbpos.Width += delta;
832 XplatUI.ScrollWindow (Handle, original_thumbpos, delta, 0, false);
838 private void OnMouseMoveSB (object sender, MouseEventArgs e)
840 if (Enabled == false || thumb_size == 0)
843 if (firstbutton_pressed) {
844 if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
845 firstbutton_state = ButtonState.Normal;
846 Invalidate (first_arrow_area);
849 } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
850 firstbutton_state = ButtonState.Pushed;
851 Invalidate (first_arrow_area);
855 } else if (secondbutton_pressed) {
856 if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
857 secondbutton_state = ButtonState.Normal;
858 Invalidate (second_arrow_area);
861 } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
862 secondbutton_state = ButtonState.Pushed;
863 Invalidate (second_arrow_area);
867 } else if (thumb_pressed == true) {
869 int thumb_edge = e.Y - thumbclick_offset;
871 if (thumb_edge < thumb_area.Y)
872 thumb_edge = thumb_area.Y;
873 else if (thumb_edge > thumb_area.Bottom - thumb_size)
874 thumb_edge = thumb_area.Bottom - thumb_size;
876 if (thumb_edge != thumb_pos.Y) {
877 Rectangle thumb_rect = thumb_pos;
879 UpdateThumbPos (thumb_edge, false, true);
881 MoveThumb (thumb_rect, thumb_pos.Y);
883 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
885 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
887 int thumb_edge = e.X - thumbclick_offset;
889 if (thumb_edge < thumb_area.X)
890 thumb_edge = thumb_area.X;
891 else if (thumb_edge > thumb_area.Right - thumb_size)
892 thumb_edge = thumb_area.Right - thumb_size;
894 if (thumb_edge != thumb_pos.X) {
895 Rectangle thumb_rect = thumb_pos;
897 UpdateThumbPos (thumb_edge, false, true);
899 MoveThumb (thumb_rect, thumb_pos.X);
901 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
903 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
910 private void OnMouseDownSB (object sender, MouseEventArgs e)
914 if (Enabled == false)
917 if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) {
918 SendWMScroll(ScrollBarCommands.SB_LINEUP);
919 firstbutton_state = ButtonState.Pushed;
920 firstbutton_pressed = true;
921 Invalidate (first_arrow_area);
923 if (!timer.Enabled) {
924 SetHoldButtonClickTimer ();
925 timer.Enabled = true;
929 if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) {
930 SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
931 secondbutton_state = ButtonState.Pushed;
932 secondbutton_pressed = true;
933 Invalidate (second_arrow_area);
935 if (!timer.Enabled) {
936 SetHoldButtonClickTimer ();
937 timer.Enabled = true;
941 if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) {
942 thumb_pressed = true;
943 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
945 thumbclick_offset = e.Y - thumb_pos.Y;
949 thumbclick_offset = e.X - thumb_pos.X;
953 if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) {
958 if (e.Y > thumb_pos.Y + thumb_pos.Height) {
959 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
961 thumb_moving = ThumbMoving.Forward;
962 Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
963 ClientRectangle.Width,
964 ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) -
965 scrollbutton_height));
967 SendWMScroll(ScrollBarCommands.SB_PAGEUP);
969 thumb_moving = ThumbMoving.Backwards;
970 Dirty (new Rectangle (0, scrollbutton_height,
971 ClientRectangle.Width,
972 thumb_pos.Y - scrollbutton_height));
978 if (e.X > thumb_pos.X + thumb_pos.Width) {
979 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
980 thumb_moving = ThumbMoving.Forward;
982 Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
983 ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) -
985 ClientRectangle.Height));
987 SendWMScroll(ScrollBarCommands.SB_PAGEUP);
988 thumb_moving = ThumbMoving.Backwards;
990 Dirty (new Rectangle (scrollbutton_width, 0,
991 thumb_pos.X - scrollbutton_width,
992 ClientRectangle.Height));
996 SetHoldThumbAreaTimer ();
997 timer.Enabled = true;
1003 private void OnMouseUpSB (object sender, MouseEventArgs e)
1007 if (Enabled == false)
1010 timer.Enabled = false;
1011 if (thumb_moving != ThumbMoving.None) {
1013 thumb_moving = ThumbMoving.None;
1016 if (firstbutton_pressed) {
1017 firstbutton_state = ButtonState.Normal;
1018 if (first_arrow_area.Contains (e.X, e.Y)) {
1021 SendWMScroll(ScrollBarCommands.SB_LINEUP);
1022 firstbutton_pressed = false;
1023 Dirty (first_arrow_area);
1024 } else if (secondbutton_pressed) {
1025 secondbutton_state = ButtonState.Normal;
1026 if (second_arrow_area.Contains (e.X, e.Y)) {
1029 SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
1030 Dirty (second_arrow_area);
1031 secondbutton_pressed = false;
1032 } else if (thumb_pressed == true) {
1033 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
1034 OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
1035 SendWMScroll(ScrollBarCommands.SB_THUMBPOSITION);
1036 thumb_pressed = false;
1043 private void OnKeyDownSB (Object o, KeyEventArgs key)
1045 if (Enabled == false)
1050 switch (key.KeyCode){
1088 private void SetEndPosition ()
1090 ScrollEventArgs event_args;
1091 int pos = Maximum - large_change + 1;
1093 event_args = new ScrollEventArgs (ScrollEventType.Last, pos);
1094 OnScroll (event_args);
1095 pos = event_args.NewValue;
1097 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1098 OnScroll (event_args);
1099 pos = event_args.NewValue;
1104 private void SetHomePosition ()
1106 ScrollEventArgs event_args;
1109 event_args = new ScrollEventArgs (ScrollEventType.First, pos);
1110 OnScroll (event_args);
1111 pos = event_args.NewValue;
1113 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
1114 OnScroll (event_args);
1115 pos = event_args.NewValue;
1120 private void SmallIncrement ()
1122 ScrollEventArgs event_args;
1123 int pos = Math.Min (Maximum - large_change + 1, position + small_change);
1125 event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos);
1126 OnScroll (event_args);
1127 Value = event_args.NewValue;
1129 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
1130 OnScroll (event_args);
1131 Value = event_args.NewValue;
1134 private void SmallDecrement ()
1136 ScrollEventArgs event_args;
1137 int pos = Math.Max (Minimum, position - small_change);
1139 event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos);
1140 OnScroll (event_args);
1141 Value = event_args.NewValue;
1143 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
1144 OnScroll (event_args);
1145 Value = event_args.NewValue;
1148 private void SetHoldButtonClickTimer ()
1150 timer.Enabled = false;
1151 timer.Interval = 200;
1152 timer_type = TimerType.HoldButton;
1153 timer.Enabled = true;
1156 private void SetRepeatButtonTimer ()
1158 timer.Enabled = false;
1159 timer.Interval = 50;
1160 timer_type = TimerType.RepeatButton;
1161 timer.Enabled = true;
1164 private void SetHoldThumbAreaTimer ()
1166 timer.Enabled = false;
1167 timer.Interval = 200;
1168 timer_type = TimerType.HoldThumbArea;
1169 timer.Enabled = true;
1172 private void SetRepeatThumbAreaTimer ()
1174 timer.Enabled = false;
1175 timer.Interval = 50;
1176 timer_type = TimerType.RepeatThumbArea;
1177 timer.Enabled = true;
1180 private void UpdatePos (int newPos, bool update_thumbpos)
1184 if (newPos < minimum)
1187 if (newPos > maximum + 1 - large_change)
1188 pos = maximum + 1 - large_change;
1192 // pos can't be less than minimum
1196 if (update_thumbpos) {
1198 UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
1200 UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
1204 position = pos; // Updates directly the value to avoid thumb pos update
1207 // XXX some reason we don't call OnValueChanged?
1208 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
1210 eh (this, EventArgs.Empty);
1214 private void UpdateThumbPos (int pixel, bool dirty, bool update_value)
1221 if (pixel < thumb_area.Y)
1222 thumb_pos.Y = thumb_area.Y;
1223 else if (pixel > thumb_area.Bottom - thumb_size)
1224 thumb_pos.Y = thumb_area.Bottom - thumb_size;
1226 thumb_pos.Y = pixel;
1229 thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize;
1230 thumb_pos.Height = thumb_size;
1231 new_pos = (float) (thumb_pos.Y - thumb_area.Y);
1232 new_pos = new_pos / pixel_per_pos;
1238 if (pixel < thumb_area.X)
1239 thumb_pos.X = thumb_area.X;
1240 else if (pixel > thumb_area.Right - thumb_size)
1241 thumb_pos.X = thumb_area.Right - thumb_size;
1243 thumb_pos.X = pixel;
1246 thumb_pos.Width = thumb_size;
1247 thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize;
1248 new_pos = (float) (thumb_pos.X - thumb_area.X);
1249 new_pos = new_pos / pixel_per_pos;
1256 UpdatePos ((int) new_pos + minimum, false);
1259 private void SetValue (int value)
1261 if ( value < minimum || value > maximum )
1262 throw new ArgumentException(
1263 String.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
1265 if (position != value){
1268 OnValueChanged (EventArgs.Empty);
1269 UpdatePos (value, true);
1273 private void ClearDirty ()
1275 dirty = Rectangle.Empty;
1278 private void Dirty (Rectangle r)
1280 if (dirty == Rectangle.Empty) {
1284 dirty = Rectangle.Union (dirty, r);
1287 private void DirtyThumbArea ()
1289 if (thumb_moving == ThumbMoving.Forward) {
1291 Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
1292 ClientRectangle.Width,
1293 ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) -
1294 scrollbutton_height));
1296 Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
1297 ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) -
1299 ClientRectangle.Height));
1301 } else if (thumb_moving == ThumbMoving.Backwards) {
1303 Dirty(new Rectangle (0, scrollbutton_height,
1304 ClientRectangle.Width,
1305 thumb_pos.Y - scrollbutton_height));
1307 Dirty (new Rectangle (scrollbutton_width, 0,
1308 thumb_pos.X - scrollbutton_width,
1309 ClientRectangle.Height));
1314 private void InvalidateDirty ()
1318 dirty = Rectangle.Empty;
1321 #endregion //Private Methods
1323 protected override void OnMouseWheel (MouseEventArgs e)
1325 base.OnMouseWheel (e);