**** Merged from MCS ****
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TrackBar.cs
blob65221d38e3fc427b8fb70a11cd2ca92de96c3e79
1 //
2 // System.Windows.Forms.TrackBar.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:
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 // Autors:
24 // Jordi Mas i Hernandez, jordi@ximian.com
26 // TODO:
27 // - The AutoSize functionality seems quite broken for vertical controls in .Net 1.1. Not
28 // sure if we are implementing it the right way.
30 // Copyright (C) Novell Inc., 2004
33 // $Revision: 1.15 $
34 // $Modtime: $
35 // $Log: TrackBar.cs,v $
36 // Revision 1.15 2004/10/05 04:56:12 jackson
37 // Let the base Control handle the buffers, derived classes should not have to CreateBuffers themselves.
39 // Revision 1.14 2004/09/28 18:44:25 pbartok
40 // - Streamlined Theme interfaces:
41 // * Each DrawXXX method for a control now is passed the object for the
42 // control to be drawn in order to allow accessing any state the theme
43 // might require
45 // * ControlPaint methods for the theme now have a CP prefix to avoid
46 // name clashes with the Draw methods for controls
48 // * Every control now retrieves it's DefaultSize from the current theme
50 // Revision 1.13 2004/08/23 20:10:03 jordi
51 // fixes properties and methods
53 // Revision 1.12 2004/08/21 20:21:48 pbartok
54 // - Replaced direct XplatUI calls with their Control counterpart
56 // Revision 1.11 2004/08/20 19:45:50 jordi
57 // fixes timer, new properties and methods
59 // Revision 1.10 2004/08/13 20:55:20 jordi
60 // change from wndproc to events
62 // Revision 1.9 2004/08/13 18:46:26 jordi
63 // adds timer and grap window
65 // Revision 1.8 2004/08/12 20:29:01 jordi
66 // Trackbar enhancement, fix mouse problems, highli thumb, etc
68 // Revision 1.7 2004/08/10 23:27:12 jordi
69 // add missing methods, properties, and restructure to hide extra ones
71 // Revision 1.6 2004/08/10 15:47:11 jackson
72 // Allow control to handle buffering
74 // Revision 1.5 2004/08/07 23:32:26 jordi
75 // throw exceptions of invalid enums values
77 // Revision 1.4 2004/08/06 23:18:06 pbartok
78 // - Fixed some rounding issues with float/int
80 // Revision 1.3 2004/07/27 15:53:02 jordi
81 // fixes trackbar events, def classname, methods signature
83 // Revision 1.2 2004/07/26 17:42:03 jordi
84 // Theme support
86 // Revision 1.1 2004/07/15 09:38:02 jordi
87 // Horizontal and Vertical TrackBar control implementation
91 // NOT COMPLETE
93 using System.ComponentModel;
94 using System.Drawing;
95 using System.Drawing.Imaging;
96 using System.Drawing.Drawing2D;
97 using System.Timers;
99 namespace System.Windows.Forms
102 [DefaultEvent ("Scroll")]
103 public class TrackBar : Control, ISupportInitialize
105 private int minimum;
106 private int maximum;
107 internal int tickFrequency;
108 private bool autosize;
109 private int position;
110 private int smallChange;
111 private int largeChange;
112 private Orientation orientation;
113 private TickStyle tickStyle;
114 internal Rectangle paint_area = new Rectangle ();
115 private Rectangle thumb_pos = new Rectangle (); /* Current position and size of the thumb */
116 private Rectangle thumb_area = new Rectangle (); /* Area where the thumb can scroll */
117 internal bool thumb_pressed = false;
118 private System.Timers.Timer holdclick_timer = new System.Timers.Timer ();
119 internal int thumb_mouseclick;
120 private bool mouse_clickmove;
122 #region Events
123 public event EventHandler Scroll;
124 public event EventHandler ValueChanged;
125 public new event EventHandler ImeModeChanged;
126 public new event EventHandler ForeColorChanged;
127 public new event EventHandler TextChanged;
128 public new event EventHandler BackgroundImageChanged;
129 #endregion // Events
131 public TrackBar ()
133 orientation = Orientation.Horizontal;
134 minimum = 0;
135 maximum = 10;
136 tickFrequency = 1;
137 autosize = true;
138 position = 0;
139 tickStyle = TickStyle.BottomRight;
140 smallChange = 1;
141 largeChange = 5;
142 Scroll = null;
143 ValueChanged = null;
144 mouse_clickmove = false;
145 SizeChanged += new System.EventHandler (OnResizeTB);
146 MouseDown += new MouseEventHandler (OnMouseDownTB);
147 MouseUp += new MouseEventHandler (OnMouseUpTB);
148 MouseMove += new MouseEventHandler (OnMouseMoveTB);
149 holdclick_timer.Elapsed += new ElapsedEventHandler (OnFirstClickTimer);
151 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
152 SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
155 #region Private & Internal Properties
156 internal Rectangle ThumbPos {
157 get {
158 return thumb_pos;
161 set {
162 thumb_pos = value;
166 internal Rectangle ThumbArea {
167 get {
168 return thumb_area;
171 set {
172 thumb_area = value;
175 #endregion // Private & Internal Properties
177 #region Public Properties
179 [DefaultValue (true)]
180 public bool AutoSize {
181 get { return autosize; }
182 set { autosize = value;}
185 [EditorBrowsable (EditorBrowsableState.Never)]
186 public override Image BackgroundImage {
187 get { return base.BackgroundImage; }
188 set {
189 if (base.BackgroundImage == value)
190 return;
192 if (BackgroundImageChanged != null)
193 BackgroundImageChanged (this, EventArgs.Empty);
195 base.BackgroundImage = value;
199 protected override CreateParams CreateParams {
200 get {
201 CreateParams createParams = base.CreateParams;
202 createParams.ClassName = XplatUI.DefaultClassName;
204 createParams.Style = (int) (
205 WindowStyles.WS_CHILD |
206 WindowStyles.WS_VISIBLE);
208 return createParams;
212 protected override ImeMode DefaultImeMode {
213 get {return ImeMode.Disable; }
216 protected override Size DefaultSize {
217 get { return ThemeEngine.Current.TrackBarDefaultSize; }
220 [EditorBrowsable (EditorBrowsableState.Never)]
221 public override Font Font {
222 get { return base.Font; }
223 set { base.Font = value; }
226 [EditorBrowsable (EditorBrowsableState.Never)]
227 public override Color ForeColor {
228 get { return base.ForeColor; }
229 set {
230 if (value == base.ForeColor)
231 return;
233 if (ForeColorChanged != null)
234 ForeColorChanged (this, EventArgs.Empty);
236 Refresh ();
240 [EditorBrowsable (EditorBrowsableState.Never)]
241 public new ImeMode ImeMode {
242 get { return base.ImeMode; }
243 set {
244 if (value == base.ImeMode)
245 return;
247 base.ImeMode = value;
248 if (ImeModeChanged != null)
249 ImeModeChanged (this, EventArgs.Empty);
253 [DefaultValue (5)]
254 public int LargeChange
256 get { return largeChange; }
257 set {
258 if (value < 0)
259 throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
261 largeChange = value;
262 Refresh ();
266 [DefaultValue (10)]
267 [RefreshProperties (RefreshProperties.All)]
268 public int Maximum {
269 get { return maximum; }
270 set {
271 if (maximum != value) {
272 maximum = value;
274 if (maximum < minimum)
275 minimum = maximum;
277 Refresh ();
282 [DefaultValue (0)]
283 [RefreshProperties (RefreshProperties.All)]
284 public int Minimum {
285 get { return minimum; }
286 set {
288 if (Minimum != value) {
289 minimum = value;
291 if (minimum > maximum)
292 maximum = minimum;
294 Refresh ();
299 [DefaultValue (Orientation.Horizontal)]
300 [Localizable (true)]
301 public Orientation Orientation {
302 get { return orientation; }
303 set {
304 if (!Enum.IsDefined (typeof (Orientation), value))
305 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Orientation", value));
307 /* Orientation can be changed once the control has been created */
308 if (orientation != value) {
309 orientation = value;
311 int old_witdh = Width;
312 Width = Height;
313 Height = old_witdh;
314 Refresh ();
319 [DefaultValue (1)]
320 public int SmallChange {
321 get { return smallChange;}
322 set {
323 if ( value < 0 )
324 throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
326 if (smallChange != value) {
327 smallChange = value;
328 Refresh ();
333 [EditorBrowsable (EditorBrowsableState.Never)]
334 [Bindable (false)]
335 public override string Text {
336 get { return base.Text; }
337 set {
338 if (value == base.Text)
339 return;
341 if (TextChanged != null)
342 TextChanged (this, EventArgs.Empty);
344 Refresh ();
348 [DefaultValue (1)]
349 public int TickFrequency {
350 get { return tickFrequency; }
351 set {
352 if ( value > 0 ) {
353 tickFrequency = value;
354 Refresh ();
359 [DefaultValue (TickStyle.BottomRight)]
360 public TickStyle TickStyle {
361 get { return tickStyle; }
362 set {
363 if (!Enum.IsDefined (typeof (TickStyle), value))
364 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for TickStyle", value));
366 if (tickStyle != value) {
367 tickStyle = value;
368 Refresh ();
373 [DefaultValue (0)]
374 [Bindable (false)]
375 public int Value {
376 get { return position; }
377 set {
378 if (value < Minimum || value > Maximum)
379 throw new ArgumentException(
380 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
382 if (position != value) {
383 position = value;
385 if (ValueChanged != null)
386 ValueChanged (this, new EventArgs ());
388 Refresh ();
393 #endregion //Public Properties
395 #region Public Methods
397 public virtual void BeginInit ()
402 protected override void CreateHandle ()
404 base.CreateHandle ();
408 public virtual void EndInit ()
413 protected override bool IsInputKey (Keys keyData)
415 return false;
418 protected override void OnBackColorChanged (EventArgs e)
423 protected override void OnHandleCreated (EventArgs e)
425 if (AutoSize)
426 if (Orientation == Orientation.Horizontal)
427 Size = new Size (Width, 40);
428 else
429 Size = new Size (50, Height);
431 UpdateArea ();
432 UpdatePos (Value, true);
435 [EditorBrowsable (EditorBrowsableState.Advanced)]
436 protected override void OnMouseWheel (MouseEventArgs e)
438 if (!Enabled) return;
440 if (e.Delta > 0)
441 SmallDecrement ();
442 else
443 SmallIncrement ();
445 base.OnMouseWheel (e);
449 protected virtual void OnScroll (EventArgs e)
451 if (Scroll != null)
452 Scroll (this, e);
455 protected virtual void OnValueChanged (EventArgs e)
457 if (ValueChanged != null)
458 ValueChanged (this, e);
461 public void SetRange (int minValue, int maxValue)
463 Minimum = minValue;
464 Maximum = maxValue;
466 Refresh ();
469 public override string ToString()
471 return string.Format("System.Windows.Forms.Trackbar, Minimum: {0}, Maximum: {1}, Value: {2}",
472 Minimum, Maximum, Value);
476 protected override void WndProc (ref Message m)
478 switch ((Msg) m.Msg) {
480 case Msg.WM_PAINT: {
481 PaintEventArgs paint_event;
483 paint_event = XplatUI.PaintEventStart (Handle);
484 OnPaintTB (paint_event);
485 XplatUI.PaintEventEnd (Handle);
486 return;
489 case Msg.WM_KEYDOWN:
490 OnKeyDownTB (new KeyEventArgs ((Keys)m.WParam.ToInt32 ()));
491 return;
493 case Msg.WM_ERASEBKGND:
494 m.Result = (IntPtr) 1; /* Disable background painting to avoid flickering */
495 return;
497 default:
498 break;
501 base.WndProc (ref m);
504 #endregion Public Methods
506 #region Private Methods
508 private void UpdateArea ()
510 paint_area.X = paint_area.Y = 0;
511 paint_area.Width = Width;
512 paint_area.Height = Height;
515 private void UpdatePos (int newPos, bool update_trumbpos)
517 int old = position;
519 if (newPos < minimum)
520 Value = minimum;
521 else
522 if (newPos > maximum)
523 Value = maximum;
524 else
525 Value = newPos;
528 private void LargeIncrement ()
530 UpdatePos (position + LargeChange, true);
531 Refresh ();
532 OnScroll (new EventArgs ());
535 private void LargeDecrement ()
537 UpdatePos (position - LargeChange, true);
538 Refresh ();
539 OnScroll (new EventArgs ());
542 private void SmallIncrement ()
544 UpdatePos (position + SmallChange, true);
545 Refresh ();
546 OnScroll (new EventArgs ());
549 private void SmallDecrement ()
551 UpdatePos (position - SmallChange, true);
552 Refresh ();
553 OnScroll (new EventArgs ());
556 private void Draw ()
558 float ticks = (Maximum - Minimum) / tickFrequency; /* N of ticks draw*/
560 ThemeEngine.Current.DrawTrackBar(DeviceContext, this.ClientRectangle, this);
563 private void OnMouseUpTB (object sender, MouseEventArgs e)
565 if (!Enabled) return;
567 if (thumb_pressed == true || mouse_clickmove == true) {
568 thumb_pressed = false;
569 holdclick_timer.Enabled = false;
570 this.Capture = false;
571 Refresh ();
575 private void OnMouseDownTB (object sender, MouseEventArgs e)
577 if (!Enabled) return;
579 bool fire_timer = false;
581 Point point = new Point (e.X, e.Y);
583 if (orientation == Orientation.Horizontal) {
585 if (thumb_pos.Contains (point)) {
586 this.Capture = true;
587 thumb_pressed = true;
588 thumb_mouseclick = e.X;
589 Refresh ();
591 else {
592 if (paint_area.Contains (point)) {
593 if (e.X > thumb_pos.X + thumb_pos.Width)
594 LargeIncrement ();
595 else
596 LargeDecrement ();
598 Refresh ();
599 fire_timer = true;
600 mouse_clickmove = true;
604 else {
605 if (thumb_pos.Contains (point)) {
606 this.Capture = true;
607 thumb_pressed = true;
608 thumb_mouseclick = e.Y;
609 Refresh ();
612 else {
613 if (paint_area.Contains (point)) {
614 if (e.Y > thumb_pos.Y + thumb_pos.Height)
615 LargeIncrement ();
616 else
617 LargeDecrement ();
619 Refresh ();
620 fire_timer = true;
621 mouse_clickmove = true;
626 if (fire_timer) {
627 holdclick_timer.Interval = 300;
628 holdclick_timer.Enabled = true;
632 private void OnMouseMoveTB (object sender, MouseEventArgs e)
634 if (!Enabled) return;
636 Point pnt = new Point (e.X, e.Y);
638 /* Moving the thumb */
639 if (thumb_pressed) {
641 if (orientation == Orientation.Horizontal){
642 if (paint_area.Contains (e.X, thumb_pos.Y))
643 thumb_mouseclick = e.X;
645 else {
646 if (paint_area.Contains (thumb_pos.X, e.Y))
647 thumb_mouseclick = e.Y;
650 Refresh ();
651 OnScroll (new EventArgs ());
655 private void OnResizeTB (object sender, System.EventArgs e)
657 if (Width <= 0 || Height <= 0)
658 return;
660 UpdateArea ();
663 private void OnPaintTB (PaintEventArgs pevent)
665 if (Width <= 0 || Height <= 0 || Visible == false)
666 return;
668 /* Copies memory drawing buffer to screen*/
669 UpdateArea ();
670 Draw ();
671 pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
674 private void OnKeyDownTB (KeyEventArgs e)
676 switch (e.KeyCode) {
677 case Keys.Up:
678 case Keys.Right:
679 SmallIncrement ();
680 break;
682 case Keys.Down:
683 case Keys.Left:
684 SmallDecrement ();
685 break;
687 default:
688 break;
692 private void OnFirstClickTimer (Object source, ElapsedEventArgs e)
694 Point pnt;
695 pnt = PointToClient (MousePosition);
697 if (thumb_area.Contains (pnt)) {
698 if (orientation == Orientation.Horizontal) {
699 if (pnt.X > thumb_pos.X + thumb_pos.Width)
700 LargeIncrement ();
702 if (pnt.X < thumb_pos.X)
703 LargeDecrement ();
705 else {
706 if (pnt.Y > thumb_pos.Y + thumb_pos.Height)
707 LargeIncrement ();
709 if (pnt.Y < thumb_pos.Y)
710 LargeDecrement ();
713 Refresh ();
718 protected override void SetBoundsCore (int x, int y,int width, int height, BoundsSpecified specified)
720 base.SetBoundsCore (x, y,width, height, specified);
724 #endregion // Private Methods