change from wndproc to events
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TrackBar.cs
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:
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 // Autors:
24 //              Jordi Mas i Hernandez, jordi@ximian.com
25 //
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.
29 //
30 // Copyright (C) Novell Inc., 2004
31 //
32 //
33 // $Revision: 1.10 $
34 // $Modtime: $
35 // $Log: TrackBar.cs,v $
36 // Revision 1.10  2004/08/13 20:55:20  jordi
37 // change from wndproc to events
38 //
39 // Revision 1.9  2004/08/13 18:46:26  jordi
40 // adds timer and grap window
41 //
42 // Revision 1.8  2004/08/12 20:29:01  jordi
43 // Trackbar enhancement, fix mouse problems, highli thumb, etc
44 //
45 // Revision 1.7  2004/08/10 23:27:12  jordi
46 // add missing methods, properties, and restructure to hide extra ones
47 //
48 // Revision 1.6  2004/08/10 15:47:11  jackson
49 // Allow control to handle buffering
50 //
51 // Revision 1.5  2004/08/07 23:32:26  jordi
52 // throw exceptions of invalid enums values
53 //
54 // Revision 1.4  2004/08/06 23:18:06  pbartok
55 // - Fixed some rounding issues with float/int
56 //
57 // Revision 1.3  2004/07/27 15:53:02  jordi
58 // fixes trackbar events, def classname, methods signature
59 //
60 // Revision 1.2  2004/07/26 17:42:03  jordi
61 // Theme support
62 //
63 // Revision 1.1  2004/07/15 09:38:02  jordi
64 // Horizontal and Vertical TrackBar control implementation
65 //
66 //
67
68 // NOT COMPLETE
69
70 using System.ComponentModel;
71 using System.Drawing;
72 using System.Drawing.Imaging;
73 using System.Drawing.Drawing2D;
74 using System.Timers;
75
76 namespace System.Windows.Forms
77 {       
78         public class TrackBar : Control, ISupportInitialize
79         {
80                 private int minimum;
81                 private int maximum;
82                 private int tickFrequency;
83                 private bool autosize;
84                 private int position;
85                 private int smallChange;
86                 private int largeChange;
87                 private Orientation orientation;
88                 private TickStyle tickStyle;
89                 private Rectangle paint_area = new Rectangle ();
90                 private Rectangle thumb_pos = new Rectangle ();  /* Current position and size of the thumb */
91                 private Rectangle thumb_area = new Rectangle (); /* Area where the thumb can scroll */
92                 private bool thumb_pressed = false;              
93                 private System.Timers.Timer holdclick_timer = new System.Timers.Timer ();
94                 private int thumb_mouseclick;           
95                 private bool mouse_clickmove;
96
97                 #region Events
98                 public event EventHandler Scroll;
99                 public event EventHandler ValueChanged;         
100                 #endregion // Events
101
102                 public TrackBar ()
103                 {
104                         orientation = Orientation.Horizontal;
105                         minimum = 0;
106                         maximum = 10;
107                         tickFrequency = 1;
108                         autosize = true;
109                         position = 0;
110                         tickStyle = TickStyle.BottomRight;
111                         smallChange = 1;
112                         largeChange = 5;
113                         Scroll = null;
114                         ValueChanged  = null;           
115                         mouse_clickmove = false;
116                         SizeChanged += new System.EventHandler (OnResizeTB);
117                         MouseDown += new MouseEventHandler (OnMouseDownTB); 
118                         MouseUp += new MouseEventHandler (OnMouseUpTB); 
119
120                         SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
121                         SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);                     
122                 }
123
124                 #region Public Properties
125
126                 public bool AutoSize {
127                         get { return autosize; }
128                         set { autosize = value;}
129                 }
130
131                 [EditorBrowsable (EditorBrowsableState.Never)]
132                 public override Image BackgroundImage {
133                         get { return base.BackgroundImage; }
134                         set { base.BackgroundImage = value; }
135                 }
136
137                 protected override CreateParams CreateParams {
138                         get {
139                                 CreateParams createParams = base.CreateParams;
140                                 createParams.ClassName = XplatUI.DefaultClassName;
141
142                                 createParams.Style = (int) (
143                                         WindowStyles.WS_CHILD |
144                                         WindowStyles.WS_VISIBLE);
145
146                                 return createParams;
147                         }
148                 }
149
150                 protected override ImeMode DefaultImeMode {
151                         get {return ImeMode.Disable; }
152                 }
153
154                 protected override Size DefaultSize {
155                         get { return new System.Drawing.Size (104, 42); }
156                 }       
157
158                 [EditorBrowsable (EditorBrowsableState.Never)]   
159                 public override Font Font {
160                         get { return base.Font; }
161                         set { base.Font = value; }
162                 }
163
164                 [EditorBrowsable (EditorBrowsableState.Never)]  
165                 public override Color ForeColor {
166                         get { return base.ForeColor; }
167                         set { base.ForeColor = value; }
168                 }               
169
170                 public int LargeChange {
171                         get { return largeChange; }
172                         set {
173                                 if (value < 0)
174                                         throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
175
176                                 largeChange = value;
177                                 Refresh ();
178                         }
179                 }
180
181                 public int Maximum {
182                         get { return maximum; }
183                         set {
184                                 if (maximum != value)  {
185                                         maximum = value;
186
187                                         if (maximum < minimum)
188                                                 minimum = maximum;
189
190                                         Refresh ();
191                                 }
192                         }
193                 }
194
195                 public int Minimum {
196                         get { return minimum; }
197                         set {
198
199                                 if (Minimum != value) {
200                                         minimum = value;
201
202                                         if (minimum > maximum)
203                                                 maximum = minimum;
204
205                                         Refresh ();
206                                 }
207                         }
208                 }
209
210                 public Orientation Orientation {
211                         get { return orientation; }
212                         set {
213                                 if (!Enum.IsDefined (typeof (Orientation), value))
214                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Orientation", value));
215
216                                 /* Orientation can be changed once the control has been created */
217                                 if (orientation != value) {
218                                         orientation = value;
219                                 
220                                         int old_witdh = Width;
221                                         Width = Height;
222                                         Height = old_witdh;
223                                         Refresh (); 
224                                 }
225                         }
226                 }
227
228                 public int SmallChange {
229                         get { return smallChange;}
230                         set {
231                                 if ( value < 0 )
232                                         throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
233
234                                 if (smallChange != value) {
235                                         smallChange = value;
236                                         Refresh ();
237                                 }
238                         }
239                 }
240
241                 [EditorBrowsable (EditorBrowsableState.Never)]
242                 public override string Text {
243                         get {   return base.Text; }
244                         set {   base.Text = value; }
245                 }
246
247
248                 public int TickFrequency {
249                         get { return tickFrequency; }
250                         set {
251                                 if ( value > 0 ) {
252                                         tickFrequency = value;
253                                         Refresh ();
254                                 }
255                         }
256                 }
257
258                 public TickStyle TickStyle {
259                         get { return tickStyle; }
260                         set {                           
261                                 if (!Enum.IsDefined (typeof (TickStyle), value))
262                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for TickStyle", value));
263                                 
264                                 if (tickStyle != value) {
265                                         tickStyle = value;
266                                         Refresh ();
267                                 }
268                         }
269                 }
270
271                 public int Value {
272                         get { return position; }
273                         set {
274                                 if (value < Minimum || value > Maximum)
275                                         throw new ArgumentException(
276                                                 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
277                                 
278                                 if (position != value) {                                                                                                        
279                                         position = value;                                       
280                                         
281                                         if (ValueChanged != null)                               
282                                                 ValueChanged (this, new EventArgs ());
283                                                 
284                                         Refresh ();
285                                 }                               
286                         }
287                 }
288
289                 #endregion //Public Properties
290
291                 #region Public Methods
292
293                 public virtual void BeginInit ()                
294                 {
295
296                 }
297
298                 protected override void CreateHandle ()
299                 {
300                         base.CreateHandle ();
301                 }
302
303
304                 public virtual void EndInit ()          
305                 {
306
307                 }
308
309                 protected override bool IsInputKey (Keys keyData)
310                 {
311                         return false;
312                 }
313
314                 protected override void OnBackColorChanged (EventArgs e)
315                 {
316
317                 }
318
319                 protected override void OnHandleCreated (EventArgs e)
320                 {                       
321                         if (AutoSize)
322                                 if (Orientation == Orientation.Horizontal)
323                                         Size = new Size (Width, 40);
324                                 else
325                                         Size = new Size (50, Height);
326
327                         UpdateArea ();
328                         CreateBuffers (Width, Height);
329                         UpdatePos (Value, true);                        
330                 }
331
332                 protected override void OnMouseWheel (MouseEventArgs e)
333                 {
334                         if (!Enabled) return;
335                         
336                         if (e.Delta > 0)
337                                 SmallDecrement ();
338                         else
339                                 SmallIncrement ();
340                                         
341                 }
342
343                 protected virtual void OnScroll (EventArgs e) 
344                 {
345                         if (Scroll != null) 
346                                 Scroll (this, e);
347                 }
348
349                 protected virtual void OnValueChanged (EventArgs e) 
350                 {
351                         if (ValueChanged != null) 
352                                 ValueChanged (this, e);
353                 }
354
355                 public void SetRange (int minValue, int maxValue)
356                 {
357                         Minimum = minValue;
358                         Maximum = maxValue;
359
360                         Refresh ();
361                 }
362
363                 public override string ToString()
364                 {
365                         return string.Format("System.Windows.Forms.Trackbar, Minimum: {0}, Maximum: {1}, Value: {2}",
366                                                 Minimum, Maximum, Value);
367                 }
368                                 
369                         
370
371                 protected override void WndProc (ref Message m)
372                 {
373                         int clicks = 1;
374
375                         switch ((Msg) m.Msg) {
376                                 
377                                 
378                         case Msg.WM_MOUSEMOVE: 
379                                 OnMouseMoveTB  (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
380                                                 clicks, 
381                                                 LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
382                                                 0));
383                                 break;
384                         
385                         case Msg.WM_PAINT: {                            
386                                 PaintEventArgs  paint_event;
387
388                                 paint_event = XplatUI.PaintEventStart (Handle);
389                                 OnPaintTB (paint_event);
390                                 XplatUI.PaintEventEnd (Handle);
391                                 return;
392                         }               
393
394                         case Msg.WM_KEYDOWN: 
395                                 OnKeyDownTB (new KeyEventArgs ((Keys)m.WParam.ToInt32 ()));
396                                 return;                 
397                                 
398                         case Msg.WM_ERASEBKGND:
399                                 m.Result = (IntPtr) 1; /* Disable background painting to avoid flickering */
400                                 return;
401                                 
402                         default:
403                                 break;
404                         }
405
406                         base.WndProc (ref m);
407                 }
408                 
409                 #endregion Public Methods
410
411                 #region Private Methods
412
413                 private void UpdateArea ()
414                 {
415                         paint_area.X = paint_area.Y = 0;
416                         paint_area.Width = Width;
417                         paint_area.Height = Height;                     
418                 }
419
420                 private void UpdatePos (int newPos, bool update_trumbpos)
421                 {
422                         int old = position;
423
424                         if (newPos < minimum)
425                                 Value = minimum;
426                         else
427                                 if (newPos > maximum)
428                                 Value = maximum;
429                         else
430                                 Value = newPos;                         
431                 }
432                 
433                 private void LargeIncrement ()
434                 {                       
435                         UpdatePos (position + LargeChange, true);
436                         Refresh ();
437                         OnScroll (new EventArgs ());
438                 }
439
440                 private void LargeDecrement ()
441                 {
442                         UpdatePos (position - LargeChange, true);
443                         Refresh ();
444                         OnScroll (new EventArgs ());
445                 }
446
447                 private void SmallIncrement ()
448                 {                       
449                         UpdatePos (position + SmallChange, true);
450                         Refresh ();
451                         OnScroll (new EventArgs ());
452                 }
453
454                 private void SmallDecrement ()
455                 {
456                         UpdatePos (position - SmallChange, true);
457                         Refresh ();
458                         OnScroll (new EventArgs ());    
459                 }
460                 
461                 private void Draw ()
462                 {                                       
463                         float ticks = (Maximum - Minimum) / tickFrequency; /* N of ticks draw*/                        
464         
465                         if (thumb_pressed)
466                                 ThemeEngine.Current.DrawTrackBar (DeviceContext, paint_area, this, 
467                                         ref thumb_pos, ref thumb_area, thumb_pressed, ticks, thumb_mouseclick, true);
468                         else
469                                 ThemeEngine.Current.DrawTrackBar (DeviceContext, paint_area, this,
470                                         ref thumb_pos, ref thumb_area, thumb_pressed, ticks,  Value - Minimum, false);
471
472                 }               
473
474                 private void OnMouseUpTB (object sender, MouseEventArgs e)
475                 {       
476                         if (!Enabled) return;                   
477
478                         if (thumb_pressed == true || mouse_clickmove == true) { 
479                                 thumb_pressed = false;
480                                 holdclick_timer.Enabled = false;
481                                 XplatUI.ReleaseWindow (Handle);
482                                 Refresh ();
483                         }
484                 }
485
486                 private void OnMouseDownTB (object sender, MouseEventArgs e)
487                 {
488                         if (!Enabled) return;                                           
489
490                         bool fire_timer = false;
491                         
492                         Point point = new Point (e.X, e.Y);
493
494                         if (orientation == Orientation.Horizontal) {
495                                 
496                                 if (thumb_pos.Contains (point)) {
497                                         XplatUI.GrabWindow (Handle);
498                                         thumb_pressed = true;
499                                         thumb_mouseclick = e.X;
500                                         Refresh ();                                     
501                                 }
502                                 else {
503                                         if (paint_area.Contains (point)) {
504                                                 if (e.X > thumb_pos.X + thumb_pos.Width)
505                                                         LargeIncrement ();
506                                                 else
507                                                         LargeDecrement ();
508
509                                                 Refresh ();
510                                                 fire_timer = true;
511                                                 mouse_clickmove = true;
512                                         }
513                                 }
514                         }
515                         else {
516                                 if (thumb_pos.Contains (point)) {
517                                         XplatUI.GrabWindow (Handle);
518                                         thumb_pressed = true;
519                                         thumb_mouseclick = e.Y;
520                                         Refresh ();
521                                         
522                                 }
523                                 else {
524                                         if (paint_area.Contains (point)) {
525                                                 if (e.Y > thumb_pos.Y + thumb_pos.Height)
526                                                         LargeIncrement ();
527                                                 else
528                                                         LargeDecrement ();
529
530                                                 Refresh ();
531                                                 fire_timer = true;
532                                                 mouse_clickmove = true;
533                                         }
534                                 }
535                         }
536
537                         if (fire_timer) { 
538                                 holdclick_timer.Elapsed += new ElapsedEventHandler (OnFirstClickTimer);\r
539                                 holdclick_timer.Interval = 300;\r
540                                 holdclick_timer.Enabled = true;                         
541                         }                       
542                 }
543
544                 private void OnMouseMoveTB (MouseEventArgs e)
545                 {                       
546                         if (!Enabled) return;
547                 
548                         Point pnt = new Point (e.X, e.Y);
549
550                         /* Moving the thumb */
551                         if (thumb_pressed) {
552                                                                                                 
553                                 if (orientation == Orientation.Horizontal){
554                                         if (paint_area.Contains (e.X, thumb_pos.Y))
555                                                 thumb_mouseclick = e.X; 
556                                 }
557                                 else {
558                                         if (paint_area.Contains (thumb_pos.X, e.Y))
559                                                 thumb_mouseclick = e.Y;
560                                 }
561
562                                 Refresh ();
563                                 OnScroll (new EventArgs ());
564                         }
565                 }
566
567                 private void OnResizeTB (object sender, System.EventArgs e)
568                 {                       
569                         if (Width <= 0 || Height <= 0)
570                                 return;
571
572                         UpdateArea ();
573                         CreateBuffers (Width, Height);
574                 }               
575
576                 private void OnPaintTB (PaintEventArgs pevent)
577                 {               
578                         if (Width <= 0 || Height <=  0 || Visible == false)
579                                 return;         
580
581                         /* Copies memory drawing buffer to screen*/
582                         UpdateArea ();
583                         Draw ();
584                         pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
585                 }  
586
587                 private void OnKeyDownTB (KeyEventArgs e) \r
588                 {                       
589                         switch (e.KeyCode) {                    \r
590                         case Keys.Up:
591                         case Keys.Right:
592                                 SmallIncrement ();
593                                 break;
594
595                         case Keys.Down:
596                         case Keys.Left:
597                                 SmallDecrement ();
598                                 break;
599                         
600                         default:
601                                 break;
602                         }
603                 }
604
605                 private void OnFirstClickTimer (Object source, ElapsedEventArgs e)\r
606                 {                                               \r
607                         Point pnt;\r
608                         pnt = PointToClient (MousePosition);                    \r
609 \r
610                         if (thumb_area.Contains (pnt))  {\r
611                                 if (orientation == Orientation.Horizontal) {\r
612                                         if (pnt.X > thumb_pos.X + thumb_pos.Width)
613                                                 LargeIncrement ();
614
615                                         if (pnt.X < thumb_pos.X)
616                                                 LargeDecrement ();                                              \r
617                                 }\r
618                                 else                            {\r
619                                         if (pnt.Y > thumb_pos.Y + thumb_pos.Height)
620                                                 LargeIncrement ();
621
622                                         if (pnt.Y < thumb_pos.Y)
623                                                 LargeDecrement ();
624                                 }
625
626                                 Refresh ();
627 \r
628                         }                       \r
629                 }                                       
630                 
631                 #endregion // Private Methods
632         }
633 }
634