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