2 // System.Windows.Forms.ScrollBar.cs
\r
4 // Permission is hereby granted, free of charge, to any person obtaining
\r
5 // a copy of this software and associated documentation files (the
\r
6 // "Software"), to deal in the Software without restriction, including
\r
7 // without limitation the rights to use, copy, modify, merge, publish,
\r
8 // distribute, sublicense, and/or sell copies of the Software, and to
\r
9 // permit persons to whom the Software is furnished to do so, subject to
\r
10 // the following conditions:
\r
12 // The above copyright notice and this permission notice shall be
\r
13 // included in all copies or substantial portions of the Software.
\r
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 // Copyright (C) 2004, Novell, Inc.
\r
26 // Jordi Mas i Hernandez jordi@ximian.com
\r
29 // $Revision: 1.13 $
\r
31 // $Log: ScrollBar.cs,v $
32 // Revision 1.13 2004/08/23 22:43:46 jordi
33 // *** empty log message ***
35 // Revision 1.11 2004/08/22 19:34:22 jackson
36 // Update the position through the Value property so the OnValueChanged event is raised.
38 // Revision 1.10 2004/08/21 20:22:21 pbartok
39 // - Replaced direct XplatUI calls with their Control counterpart
41 // Revision 1.9 2004/08/20 19:35:33 jackson
42 // Use the SWF timer so callbacks are run in the correct thread
44 // Revision 1.8 2004/08/20 19:34:26 jackson
45 // Use the SWF timer so callbacks are run in the correct thread
47 // Revision 1.7 2004/08/19 22:25:31 jordi
50 // Revision 1.6 2004/08/18 15:56:12 jordi
51 // fixes to scrollbar: steps and multiple timers
53 // Revision 1.5 2004/08/10 19:21:27 jordi
54 // scrollbar enhancements and standarize on win colors defaults
56 // Revision 1.4 2004/08/10 15:41:50 jackson
57 // Allow control to handle buffering
59 // Revision 1.3 2004/07/27 15:29:40 jordi
60 // fixes scrollbar events
62 // Revision 1.2 2004/07/26 17:42:03 jordi
68 using System.Drawing;
\r
69 using System.Drawing.Imaging;
\r
70 using System.Drawing.Drawing2D;
\r
71 using System.ComponentModel;
\r
72 using System.Runtime.InteropServices;
\r
74 namespace System.Windows.Forms
\r
76 [DefaultEvent ("Scroll")]
77 [DefaultProperty ("Value")]
\r
78 public class ScrollBar : Control
\r
80 #region Local Variables
\r
81 private int position;
\r
82 private int minimum;
\r
83 private int maximum;
\r
84 private int largeChange;
\r
85 private int smallChange;
\r
86 private int scrollbutton_height;
\r
87 private int scrollbutton_width;
\r
88 private Rectangle paint_area = new Rectangle ();
\r
89 private ScrollBars type;
\r
90 private Rectangle first_arrow_area = new Rectangle (); // up or left
\r
91 private Rectangle second_arrow_area = new Rectangle (); // down or right
\r
92 private Rectangle thumb_pos = new Rectangle ();
\r
93 private Rectangle thumb_area = new Rectangle ();
\r
94 private ButtonState firstbutton_state = ButtonState.Normal;
\r
95 private ButtonState secondbutton_state = ButtonState.Normal;
\r
96 private bool thumb_pressed = false;
\r
97 private float pixel_per_pos = 0;
\r
98 private Timer firstclick_timer;
99 private Timer holdclick_timer;
100 private int thumb_pixel_click_move;
\r
101 private int thumb_size = 0;
\r
102 private const int thumb_min_size = 8;
\r
103 internal bool vert;
\r
106 public new event EventHandler BackColorChanged;
107 public new event EventHandler BackgroundImageChanged;
108 public new event EventHandler Click;
109 public new event EventHandler DoubleClick;
110 public new event EventHandler FontChanged;
111 public new event EventHandler ForeColorChanged;
112 public new event EventHandler ImeModeChanged;
113 public new event MouseEventHandler MouseDown;
114 public new event MouseEventHandler MouseUp;
115 public new event PaintEventHandler Paint;
116 public event ScrollEventHandler Scroll;
117 public new event EventHandler TextChanged;
\r
118 public event EventHandler ValueChanged;
120 #endregion // Local Variables
\r
122 public ScrollBar () : base ()
\r
130 holdclick_timer = new Timer ();
131 firstclick_timer = new Timer ();
132 holdclick_timer.Tick += new EventHandler (OnHoldClickTimer);
\r
133 firstclick_timer.Tick += new EventHandler (OnFirstClickTimer);
134 base.TabStop = false;
\r
136 if (ThemeEngine.Current.WriteToWindow == true)
137 double_buffering = false;
139 double_buffering = true;
\r
141 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
\r
142 SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
\r
145 [EditorBrowsable (EditorBrowsableState.Never)]
\r
146 public override Color BackColor
\r
148 get { return base.BackColor; }
\r
150 if (base.BackColor == value)
153 if (BackColorChanged != null)
154 BackColorChanged (this, EventArgs.Empty);
156 base.BackColor = value;
161 [EditorBrowsable (EditorBrowsableState.Never)]
\r
162 public override Image BackgroundImage
\r
164 get { return base.BackgroundImage; }
166 if (base.BackgroundImage == value)
169 if (BackgroundImageChanged != null)
\r
170 BackgroundImageChanged (this, EventArgs.Empty);
172 base.BackgroundImage = value;
176 public override Font Font {
177 get { return base.Font; }
179 if (base.Font == value)
182 if (FontChanged != null)
\r
183 FontChanged (this, EventArgs.Empty);
190 [EditorBrowsable (EditorBrowsableState.Never)]
\r
191 public override Color ForeColor
\r
193 get { return base.ForeColor; }
\r
195 if (base.ForeColor == value)
198 if (ForeColorChanged != null)
\r
199 ForeColorChanged (this, EventArgs.Empty);
201 base.ForeColor = value;
206 [EditorBrowsable (EditorBrowsableState.Never)]
\r
207 public new ImeMode ImeMode
\r
209 get { return base.ForeColor; }
\r
211 if (base.ImeMode == value)
214 if (ImeModeChanged != null)
\r
215 ImeModeChanged (this, EventArgs.Empty);
217 base.ImeMode = value;
221 public int LargeChange {
\r
222 get { return largeChange; }
\r
225 throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
\r
227 if (largeChange != value) {
\r
228 largeChange = value;
\r
234 public int Maximum {
\r
235 get { return maximum; }
\r
239 if (maximum < minimum)
\r
246 public int Minimum {
\r
247 get { return minimum; }
\r
251 if (minimum > maximum)
\r
252 maximum = minimum;
\r
258 public int SmallChange {
\r
259 get { return smallChange; }
\r
262 throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
\r
264 if (smallChange != value) {
\r
265 smallChange = value;
\r
272 public new bool TabStop {
273 get { return base.TabStop; }
274 set { base.TabStop = value; }
277 [EditorBrowsable (EditorBrowsableState.Never)]
\r
278 public override string Text {
\r
279 get { return base.Text; }
\r
280 set { base.Text = value; }
\r
284 get { return position; }
\r
286 if ( value < Minimum || value > Maximum )
\r
287 throw new ArgumentException(
\r
288 string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
\r
290 if (position != value){
\r
293 if (ValueChanged != null)
\r
294 ValueChanged (this, EventArgs.Empty);
\r
301 public override string ToString()
\r
303 return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
\r
304 GetType( ).FullName.ToString( ), Minimum, Maximum, position);
\r
307 protected override CreateParams CreateParams {
\r
309 CreateParams createParams = base.CreateParams;
\r
310 createParams.ClassName = XplatUI.DefaultClassName;
\r
311 createParams.Style = (int) (
\r
312 WindowStyles.WS_CHILD |
\r
313 WindowStyles.WS_VISIBLE);
\r
314 return createParams;
\r
318 protected override ImeMode DefaultImeMode {
\r
319 get { return ImeMode.Disable; }
\r
323 private void fire_Scroll (ScrollEventArgs event_args)
\r
325 if (Scroll == null)
\r
328 Scroll (this, event_args);
\r
330 //if (event_args.NewValue != position)
\r
331 // UpdatePos (event_args.NewValue, true);
\r
334 protected virtual void OnValueChanged (EventArgs e)
\r
336 if (ValueChanged != null)
\r
337 ValueChanged (this, e);
\r
340 private void Draw ()
\r
342 ThemeEngine.Current.DrawScrollBar (DeviceContext, paint_area, this, thumb_pos,
\r
343 ref first_arrow_area, ref second_arrow_area,
\r
344 firstbutton_state, secondbutton_state,
\r
345 ref scrollbutton_width, ref scrollbutton_height, vert);
\r
349 private void CalcThumbArea ()
\r
354 thumb_area.Height = Height - scrollbutton_height - scrollbutton_height;
\r
356 thumb_area.Y = scrollbutton_height;
\r
357 thumb_area.Width = Width;
\r
359 if (Height < scrollbutton_height * 2)
\r
362 double per = ((double)LargeChange / (double)((1 + Maximum - Minimum)));
\r
363 thumb_size = 1 + (int) (thumb_area.Height * per);
\r
365 if (thumb_size < thumb_min_size)
\r
366 thumb_size = thumb_min_size;
\r
370 pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((Maximum - Minimum - LargeChange) + 1));
\r
374 if (Width < scrollbutton_width * 2)
\r
380 thumb_size = Width /10;
\r
383 thumb_area.X = scrollbutton_width;
\r
384 thumb_area.Height = Height;
\r
385 thumb_area.Width = Width - scrollbutton_width - scrollbutton_width;
\r
386 pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((Maximum - Minimum - LargeChange) + 1));
\r
390 protected override void OnResize (EventArgs e)
\r
392 base.OnResize (e);
\r
394 if (Width <= 0 || Height <= 0)
\r
397 paint_area.X = paint_area. Y = 0;
\r
398 paint_area.Width = Width;
\r
399 paint_area.Height = Height;
\r
401 CreateBuffers (Width, Height);
404 UpdatePos (position, true);
\r
409 Called when the control is created
\r
411 protected override void CreateHandle()
\r
413 base.CreateHandle(); // Let control.cs create the underlying Window
\r
415 scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
\r
416 scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
\r
418 CreateBuffers (Width, Height);
\r
421 UpdatePos (Value, true);
\r
424 protected override void OnPaint (PaintEventArgs pevent)
\r
426 if (Width <= 0 || Height <= 0 || Visible == false)
\r
429 /* Copies memory drawing buffer to screen*/
\r
432 if (double_buffering)
\r
433 pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
\r
437 /* Disable background painting to avoid flickering, since we do our painting*/
440 protected override void OnPaintBackground (PaintEventArgs pevent)
\r
442 if (!double_buffering)
443 base.OnPaintBackground (pevent);
\r
446 protected override void OnClick (EventArgs e)
\r
448 //Console.WriteLine ("On click");
\r
451 private void UpdatePos (int newPos, bool update_trumbpos)
\r
453 int old = position;
\r
456 if (newPos < minimum)
\r
459 if (newPos > maximum)
\r
464 if (update_trumbpos)
\r
466 UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - Minimum)) * pixel_per_pos), false);
\r
468 UpdateThumbPos (thumb_area.X + (int)(((float)(pos - Minimum)) * pixel_per_pos), false);
471 if (pos != old) // Fire event
\r
472 fire_Scroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, pos));
\r
476 private void UpdateThumbPos (int pixel, bool update_value)
\r
481 if (pixel < thumb_area.Y)
\r
482 thumb_pos.Y = thumb_area.Y;
\r
484 if (pixel > thumb_area.Y + thumb_area.Height - thumb_size)
\r
485 thumb_pos.Y = thumb_area.Y + thumb_area.Height - thumb_size;
\r
487 thumb_pos.Y = pixel;
\r
489 thumb_pos = new Rectangle (0, thumb_pos.Y, ThemeEngine.Current.ScrollBarButtonSize, thumb_size);
\r
490 new_pos = (float) (thumb_pos.Y - thumb_area.Y);
\r
491 new_pos = new_pos / pixel_per_pos;
\r
494 if (pixel < thumb_area.X)
\r
495 thumb_pos.X = thumb_area.X;
\r
497 if (pixel > thumb_area.X + thumb_area.Width - thumb_size)
\r
498 thumb_pos.X = thumb_area.X + thumb_area.Width - thumb_size;
\r
500 thumb_pos.X = pixel;
\r
502 thumb_pos = new Rectangle (thumb_pos.X, 0, thumb_size, ThemeEngine.Current.ScrollBarButtonSize);
\r
503 new_pos = (float) (thumb_pos.X - thumb_area.X);
\r
504 new_pos = new_pos / pixel_per_pos;
\r
507 // Console.WriteLine ("UpdateThumbPos: thumb_pos.Y {0} thumb_area.Y {1} pixel_per_pos {2}, new pos {3}, pixel {4}",
\r
508 // thumb_pos.Y, thumb_area.Y, pixel_per_pos, new_pos, pixel);
\r
511 UpdatePos ((int) new_pos, false);
\r
514 private void OnHoldClickTimer (Object source, EventArgs e)
\r
516 if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
\r
519 if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
\r
524 private void OnFirstClickTimer (Object source, EventArgs e)
\r
526 firstclick_timer.Enabled = false;
\r
527 holdclick_timer.Interval = 50;
\r
528 holdclick_timer.Enabled = true;
\r
531 protected override void OnMouseMove (MouseEventArgs e)
\r
533 if (!first_arrow_area.Contains (new Point (e.X, e.Y)) &&
\r
534 ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
\r
535 firstbutton_state = ButtonState.Normal;
\r
539 if (!second_arrow_area.Contains (new Point (e.X, e.Y)) &&
\r
540 ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
\r
541 secondbutton_state = ButtonState.Normal;
\r
545 if (thumb_pressed == true) {
550 pixel_pos = e.Y - (thumb_pixel_click_move - thumb_pos.Y);
\r
552 pixel_pos = e.X - (thumb_pixel_click_move - thumb_pos.X);
\r
554 UpdateThumbPos (pixel_pos, true);
\r
557 thumb_pixel_click_move = e.Y;
\r
559 thumb_pixel_click_move = e.X;
\r
561 //System.Console.WriteLine ("OnMouseMove thumb "+ e.Y
\r
562 // + " clickpos " + thumb_pixel_click_move + " pos:" + thumb_pos.Y);
\r
569 protected override void OnMouseDown (MouseEventArgs e)
\r
571 //System.Console.WriteLine ("OnMouseDown");
\r
573 Point point = new Point (e.X, e.Y);
\r
575 if (first_arrow_area.Contains (point)) {
\r
576 firstbutton_state = ButtonState.Pushed;
\r
580 if (second_arrow_area.Contains (point)) {
\r
581 secondbutton_state = ButtonState.Pushed;
\r
585 if (thumb_pos.Contains (point)) {
\r
586 thumb_pressed = true;
\r
587 this.Capture = true;
\r
590 thumb_pixel_click_move = e.Y;
\r
592 thumb_pixel_click_move = e.X;
\r
595 if (thumb_area.Contains (point)) {
\r
597 if (e.Y > thumb_pos.Y + thumb_pos.Height)
\r
602 if (e.X > thumb_pos.X + thumb_pos.Width)
\r
611 /* If arrows are pressed, lunch timer for auto-repeat */
\r
612 if ((((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
\r
613 || ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) &&
\r
614 firstclick_timer.Enabled == false) {
\r
615 //Console.WriteLine ("Activate Timer");
\r
616 firstclick_timer.Interval = 200;
\r
617 firstclick_timer.Enabled = true;
\r
621 private void SmallIncrement ()
\r
623 UpdatePos (Value + SmallChange, true);
\r
626 fire_Scroll (new ScrollEventArgs (ScrollEventType.SmallIncrement, position));
\r
627 fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
\r
630 private void SmallDecrement ()
\r
632 UpdatePos (Value - SmallChange, true);
\r
635 fire_Scroll (new ScrollEventArgs (ScrollEventType.SmallDecrement, position));
\r
636 fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
\r
639 private void LargeIncrement ()
\r
641 UpdatePos (Value + LargeChange, true);
\r
644 fire_Scroll (new ScrollEventArgs (ScrollEventType.LargeIncrement, position));
\r
645 fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
\r
648 private void LargeDecrement ()
\r
650 UpdatePos (Value - LargeChange, true);
\r
653 fire_Scroll (new ScrollEventArgs (ScrollEventType.LargeDecrement, position));
\r
654 fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
\r
656 protected override void OnMouseUp (MouseEventArgs e)
\r
658 //System.Console.WriteLine ("OnMouseUp");
\r
660 if (first_arrow_area.Contains (new Point (e.X, e.Y))) {
\r
662 firstbutton_state = ButtonState.Normal;
\r
663 SmallDecrement ();
\r
664 holdclick_timer.Enabled = false;
\r
667 if (second_arrow_area.Contains (new Point (e.X, e.Y))) {
\r
669 secondbutton_state = ButtonState.Normal;
\r
670 SmallIncrement ();
\r
671 holdclick_timer.Enabled = false;
\r
674 if (thumb_pressed == true) {
\r
675 fire_Scroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
\r
676 fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
\r
677 this.Capture = false;
\r
678 thumb_pressed = false;
\r
685 protected override void OnKeyDown (KeyEventArgs key)
\r
687 switch (key.KeyCode){
\r
703 case Keys.PageDown:
\r
714 protected void UpdateScrollInfo ()
\r