2 // System.Windows.Forms.TrackBar.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.
24 // Copyright (c) 2004-2006 Novell, Inc.
27 // Jordi Mas i Hernandez, jordi@ximian.com
28 // Rolf Bjarne Kvinge, RKvinge@novell.com
31 // - The AutoSize functionality seems quite broken for vertical controls in .Net 1.1. Not
32 // sure if we are implementing it the right way.
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
40 using System.Drawing.Imaging;
41 using System.Drawing.Drawing2D;
43 using System.Runtime.InteropServices;
45 namespace System.Windows.Forms
48 [DefaultBindingProperty ("Value")]
50 [ClassInterface (ClassInterfaceType.AutoDispatch)]
52 [Designer("System.Windows.Forms.Design.TrackBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
53 [DefaultEvent ("Scroll")]
54 [DefaultProperty("Value")]
55 public class TrackBar : Control, ISupportInitialize
59 internal int tickFrequency;
60 private bool autosize;
62 private int smallChange;
63 private int largeChange;
64 private Orientation orientation;
65 private TickStyle tickStyle;
66 private Rectangle thumb_pos = new Rectangle (); /* Current position and size of the thumb */
67 private Rectangle thumb_area = new Rectangle (); /* Area where the thumb can scroll */
68 internal bool thumb_pressed = false;
69 private System.Timers.Timer holdclick_timer = new System.Timers.Timer ();
70 internal int thumb_mouseclick;
71 private bool mouse_clickmove;
72 private bool is_moving_right; // which way the thumb should move when mouse is down (right=up, left=down)
73 internal int mouse_down_x_offset; // how far from left side of thumb was the mouse clicked.
74 internal bool mouse_moved; // has the mouse moved since it was clicked?
75 private const int size_of_autosize = 45;
77 private bool right_to_left_layout;
82 [EditorBrowsable (EditorBrowsableState.Always)]
84 public new event EventHandler AutoSizeChanged {
85 add {base.AutoSizeChanged += value;}
86 remove {base.AutoSizeChanged -= value;}
91 [EditorBrowsable (EditorBrowsableState.Never)]
92 public new event EventHandler BackgroundImageChanged {
93 add { base.BackgroundImageChanged += value; }
94 remove { base.BackgroundImageChanged -= value; }
98 [EditorBrowsable (EditorBrowsableState.Never)]
100 public new event EventHandler BackgroundImageLayoutChanged
102 add { base.BackgroundImageLayoutChanged += value; }
103 remove { base.BackgroundImageLayoutChanged -= 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; }
144 [EditorBrowsable (EditorBrowsableState.Never)]
145 public new event MouseEventHandler MouseClick {
146 add {base.MouseClick += value;}
147 remove {base.MouseClick -= value;}
151 [EditorBrowsable (EditorBrowsableState.Never)]
152 public new event MouseEventHandler MouseDoubleClick
154 add { base.MouseDoubleClick += value; }
155 remove { base.MouseDoubleClick -= value; }
159 [EditorBrowsable (EditorBrowsableState.Never)]
160 public new event EventHandler PaddingChanged
162 add { base.PaddingChanged += value; }
163 remove { base.PaddingChanged -= value; }
169 [EditorBrowsable (EditorBrowsableState.Never)]
170 public new event PaintEventHandler Paint {
171 add { base.Paint += value; }
172 remove { base.Paint -= value; }
176 public new event EventHandler RightToLeftLayoutChanged {
177 add {Events.AddHandler (RightToLeftLayoutChangedEvent, value);}
178 remove {Events.RemoveHandler (RightToLeftLayoutChangedEvent, value);}
183 [EditorBrowsable (EditorBrowsableState.Never)]
184 public new event EventHandler TextChanged {
185 add { base.TextChanged += value; }
186 remove { base.TextChanged -= value; }
190 static object RightToLeftLayoutChangedEvent = new object ();
192 static object ScrollEvent = new object ();
193 static object ValueChangedEvent = new object ();
195 public event EventHandler Scroll {
196 add { Events.AddHandler (ScrollEvent, value); }
197 remove { Events.RemoveHandler (ScrollEvent, value); }
200 public event EventHandler ValueChanged {
201 add { Events.AddHandler (ValueChangedEvent, value); }
202 remove { Events.RemoveHandler (ValueChangedEvent, value); }
209 orientation = Orientation.Horizontal;
215 tickStyle = TickStyle.BottomRight;
218 mouse_clickmove = false;
219 MouseDown += new MouseEventHandler (OnMouseDownTB);
220 MouseUp += new MouseEventHandler (OnMouseUpTB);
221 MouseMove += new MouseEventHandler (OnMouseMoveTB);
222 KeyDown += new KeyEventHandler (OnKeyDownTB);
223 LostFocus += new EventHandler (OnLostFocusTB);
224 GotFocus += new EventHandler (OnGotFocusTB);
225 holdclick_timer.Elapsed += new ElapsedEventHandler (OnFirstClickTimer);
227 SetStyle (ControlStyles.UserPaint | ControlStyles.Opaque
229 | ControlStyles.UseTextForAccessibility
234 #region Private & Internal Properties
235 internal Rectangle ThumbPos {
245 internal Rectangle ThumbArea {
254 #endregion // Private & Internal Properties
256 #region Public Properties
260 [EditorBrowsable (EditorBrowsableState.Always)]
261 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
263 [DefaultValue (true)]
265 public override bool AutoSize {
267 public new bool AutoSize {
269 get { return autosize; }
270 set { autosize = value;}
273 [EditorBrowsable (EditorBrowsableState.Never)]
275 public override Image BackgroundImage {
276 get { return base.BackgroundImage; }
277 set { base.BackgroundImage = value; }
281 [EditorBrowsable (EditorBrowsableState.Never)]
283 public override ImageLayout BackgroundImageLayout {
285 return base.BackgroundImageLayout;
288 base.BackgroundImageLayout = value;
293 protected override CreateParams CreateParams {
295 return base.CreateParams;
299 protected override ImeMode DefaultImeMode {
300 get {return ImeMode.Disable; }
303 protected override Size DefaultSize {
304 get { return ThemeEngine.Current.TrackBarDefaultSize; }
308 [EditorBrowsable (EditorBrowsableState.Never)]
309 protected override bool DoubleBuffered {
311 return base.DoubleBuffered;
314 base.DoubleBuffered = value;
320 [EditorBrowsable (EditorBrowsableState.Never)]
321 public override Font Font {
322 get { return base.Font; }
323 set { base.Font = value; }
326 [EditorBrowsable (EditorBrowsableState.Never)]
328 public override Color ForeColor {
329 get { return base.ForeColor; }
330 set { base.ForeColor = value; }
333 [EditorBrowsable (EditorBrowsableState.Never)]
335 public new ImeMode ImeMode {
336 get { return base.ImeMode; }
337 set { base.ImeMode = value; }
341 public int LargeChange
343 get { return largeChange; }
347 throw new ArgumentOutOfRangeException (string.Format ("Value '{0}' must be greater than or equal to 0.", value));
350 throw new ArgumentException( string.Format("Value '{0}' must be greater than or equal to 0.", value));
358 [RefreshProperties (RefreshProperties.All)]
360 get { return maximum; }
362 if (maximum != value) {
365 if (maximum < minimum)
374 [RefreshProperties (RefreshProperties.All)]
376 get { return minimum; }
379 if (Minimum != value) {
382 if (minimum > maximum)
390 [DefaultValue (Orientation.Horizontal)]
392 public Orientation Orientation {
393 get { return orientation; }
395 if (!Enum.IsDefined (typeof (Orientation), value))
396 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Orientation", value));
398 /* Orientation can be changed once the control has been created */
399 if (orientation != value) {
402 if (this.IsHandleCreated) {
403 Size = new Size (Height, Width);
412 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
413 [EditorBrowsable (EditorBrowsableState.Never)]
414 public new Padding Padding {
419 base.Padding = value;
424 [DefaultValue (false)]
425 public virtual bool RightToLeftLayout {
427 return right_to_left_layout;
430 if (value != right_to_left_layout) {
431 right_to_left_layout = value;
432 OnRightToLeftLayoutChanged (EventArgs.Empty);
439 public int SmallChange {
440 get { return smallChange;}
444 throw new ArgumentOutOfRangeException (string.Format ("Value '{0}' must be greater than or equal to 0.", value));
447 throw new ArgumentException( string.Format("Value '{0}' must be greater than or equal to 0.", value));
449 if (smallChange != value) {
455 [EditorBrowsable (EditorBrowsableState.Never)]
458 public override string Text {
459 get { return base.Text; }
460 set { base.Text = value; }
464 public int TickFrequency {
465 get { return tickFrequency; }
468 tickFrequency = value;
474 [DefaultValue (TickStyle.BottomRight)]
475 public TickStyle TickStyle {
476 get { return tickStyle; }
478 if (!Enum.IsDefined (typeof (TickStyle), value))
479 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for TickStyle", value));
481 if (tickStyle != value) {
491 get { return position; }
493 if (value < Minimum || value > Maximum)
494 throw new ArgumentException(
495 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
497 if (position != value) {
500 // XXX any reason we don't call OnValueChanged here?
501 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
503 eh (this, EventArgs.Empty);
505 Invalidate (thumb_area);
510 #endregion //Public Properties
512 #region Public Methods
514 public void BeginInit ()
519 protected override void CreateHandle ()
521 base.CreateHandle ();
524 protected override void SetBoundsCore (int x, int y,int width, int height, BoundsSpecified specified)
527 if (orientation == Orientation.Vertical) {
528 width = size_of_autosize;
530 height = size_of_autosize;
533 base.SetBoundsCore (x, y, width, height, specified);
536 public void EndInit ()
541 protected override bool IsInputKey (Keys keyData)
543 if ((keyData & Keys.Alt) == 0) {
544 switch (keyData & Keys.KeyCode) {
556 return base.IsInputKey (keyData);
559 protected override void OnBackColorChanged (EventArgs e)
561 base.OnBackColorChanged (e);
564 protected override void OnHandleCreated (EventArgs e)
566 base.OnHandleCreated (e);
569 if (Orientation == Orientation.Horizontal)
570 Size = new Size (Width, 40);
572 Size = new Size (50, Height);
574 UpdatePos (Value, true);
577 [EditorBrowsable (EditorBrowsableState.Advanced)]
578 protected override void OnMouseWheel (MouseEventArgs e)
580 base.OnMouseWheel (e);
582 if (!Enabled) return;
591 [EditorBrowsable (EditorBrowsableState.Advanced)]
592 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
594 EventHandler eh = (EventHandler)Events [RightToLeftLayoutChangedEvent];
600 protected virtual void OnScroll (EventArgs e)
602 EventHandler eh = (EventHandler)(Events [ScrollEvent]);
608 protected override void OnSystemColorsChanged (EventArgs e)
610 base.OnSystemColorsChanged (e);
614 protected virtual void OnValueChanged (EventArgs e)
616 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
621 public void SetRange (int minValue, int maxValue)
627 public override string ToString()
629 return string.Format("System.Windows.Forms.TrackBar, Minimum: {0}, Maximum: {1}, Value: {2}",
630 Minimum, Maximum, Value);
634 protected override void WndProc (ref Message m)
636 base.WndProc (ref m);
639 #endregion Public Methods
641 #region Private Methods
643 private void UpdatePos (int newPos, bool update_trumbpos)
645 if (newPos < minimum){
649 if (newPos > maximum) {
658 private void LargeIncrement ()
660 UpdatePos (position + LargeChange, true);
661 Invalidate (thumb_area);
662 OnScroll (new EventArgs ());
665 private void LargeDecrement ()
667 UpdatePos (position - LargeChange, true);
668 Invalidate (thumb_area);
669 OnScroll (new EventArgs ());
672 private void SmallIncrement ()
674 UpdatePos (position + SmallChange, true);
675 Invalidate (thumb_area);
676 OnScroll (new EventArgs ());
679 private void SmallDecrement ()
681 UpdatePos (position - SmallChange, true);
682 Invalidate (thumb_area);
683 OnScroll (new EventArgs ());
686 private void OnMouseUpTB (object sender, MouseEventArgs e)
688 if (!Enabled) return;
690 if (thumb_pressed == true || mouse_clickmove == true) {
691 thumb_pressed = false;
692 holdclick_timer.Enabled = false;
693 this.Capture = false;
694 Invalidate (thumb_area);
698 private void OnMouseDownTB (object sender, MouseEventArgs e)
700 if (!Enabled) return;
704 bool fire_timer = false;
706 Point point = new Point (e.X, e.Y);
708 if (orientation == Orientation.Horizontal) {
710 if (thumb_pos.Contains (point)) {
712 thumb_pressed = true;
713 thumb_mouseclick = e.X;
714 mouse_down_x_offset = e.X - thumb_pos.X;
715 Invalidate (thumb_area);
718 if (ClientRectangle.Contains (point)) {
719 is_moving_right = e.X > thumb_pos.X + thumb_pos.Width;
725 Invalidate (thumb_area);
727 mouse_clickmove = true;
732 Rectangle vertical_thumb_pos = thumb_pos;
733 vertical_thumb_pos.Width = thumb_pos.Height;
734 vertical_thumb_pos.Height = thumb_pos.Width;
735 if (vertical_thumb_pos.Contains (point)) {
737 thumb_pressed = true;
738 thumb_mouseclick = e.Y;
739 mouse_down_x_offset = e.Y - thumb_pos.Y;
740 Invalidate (thumb_area);
743 if (ClientRectangle.Contains (point)) {
744 is_moving_right = e.Y > thumb_pos.Y + thumb_pos.Width;
750 Invalidate (thumb_area);
752 mouse_clickmove = true;
758 holdclick_timer.Interval = 300;
759 holdclick_timer.Enabled = true;
763 private void OnMouseMoveTB (object sender, MouseEventArgs e)
765 if (!Enabled) return;
769 /* Moving the thumb */
771 int old_value = Value;
772 Value = ThemeEngine.Current.TrackBarValueFromMousePosition (e.X, e.Y, this);
774 if (Value != old_value)
775 OnScroll (EventArgs.Empty);
779 internal override void OnPaintInternal (PaintEventArgs pevent)
781 ThemeEngine.Current.DrawTrackBar (pevent.Graphics, pevent.ClipRectangle, this);
784 private void OnLostFocusTB (object sender, EventArgs e)
789 private void OnGotFocusTB (object sender, EventArgs e)
793 private void OnKeyDownTB (object sender, KeyEventArgs e)
828 private void OnFirstClickTimer (Object source, ElapsedEventArgs e)
831 pnt = PointToClient (MousePosition);
833 On Win32 the thumb only moves in one direction after a click,
834 if the thumb passes the clicked point it will never go in the
835 other way unless the mouse is released and clicked again. This
836 is also true if the mouse moves while beeing hold down.
839 if (thumb_area.Contains (pnt)) {
840 bool invalidate = false;
841 if (orientation == Orientation.Horizontal) {
842 if (pnt.X > thumb_pos.X + thumb_pos.Width && is_moving_right) {
845 } else if (pnt.X < thumb_pos.X && !is_moving_right) {
850 if (pnt.Y > thumb_pos.Y + thumb_pos.Width && is_moving_right) {
853 } else if (pnt.Y < thumb_pos.Y && !is_moving_right) {
859 // A Refresh is necessary because the mouse is down and if we just invalidate
860 // we'll only get paint events once in a while.
864 #endregion // Private Methods