1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004 Novell, Inc.
23 // Miguel de Icaza (miguel@novell.com).
30 - Actually paint the border, could not get it to work.
32 - Implement ContextMenu property.
34 - Force the size of the entry: it can not be resized vertically
35 ever, the size is set by the size of the font
37 - Add defaults with [DefautValue ]
39 - Audit every place where ChangingText is used, whose meaning is
40 `Me, the library is changing the text'. Kind of hack to deal with
43 - Hook up the keyboard events.
48 using System.ComponentModel;
49 using System.Runtime.InteropServices;
51 namespace System.Windows.Forms {
52 public abstract class UpDownBase : ContainerControl {
54 internal class Spinner : Control, IDisposable {
55 UpDownBase updownbase;
56 Rectangle up, down, pressed;
58 bool up_pressed, down_pressed;
59 bool captured, mouse_in;
64 const int StartInterval = 1000;
65 const int RepeatInterval = 400;
66 const int ChangeInterval = 75;
67 const int MinimumInterval = 100;
69 internal Spinner (UpDownBase updownbase)
71 this.updownbase = updownbase;
74 protected override void OnPaint (PaintEventArgs pe)
78 if (pe.ClipRectangle.Contains (up))
80 if (pe.ClipRectangle.Contains (down))
81 DrawDown (pe.Graphics);
84 protected override void OnLayout (LayoutEventArgs args)
87 Rectangle bounds = Bounds;
89 up = new Rectangle (0, 0, bounds.Width, bounds.Height/2);
90 down = new Rectangle (0, bounds.Height/2, bounds.Width, bounds.Height/2);
93 protected override void OnMouseDown (MouseEventArgs args)
95 base.OnMouseDown (args);
97 if (args.Button != MouseButtons.Left)
100 if (up.Contains (args.X, args.Y)){
103 } else if (down.Contains (args.X, args.Y)){
110 Invalidate (pressed);
114 mouse_in = down_pressed | up_pressed;
117 protected override void OnMouseUp (MouseEventArgs args)
125 down_pressed = false;
130 timer.Enabled = false;
134 // Sets up the auto-repeat timer, we give a one second
135 // delay, and then we use the keyboard settings for auto-repeat.
140 timer.Interval = StartInterval;
141 timer.Enabled = true;
145 timer = new Timer ();
146 int kd = SystemInformation.KeyboardDelay;
147 kd = kd < 0 ? 0 : (kd > 4 ? 4 : kd);
148 timer.Interval = StartInterval;
149 timer.Tick += new EventHandler (ClockTick);
150 timer.Enabled = true;
153 void ClockTick (object o, EventArgs a)
156 throw new Exception ("The timer that owns this callback is null!");
158 int interval = timer.Interval;
160 if (interval == StartInterval)
161 interval = RepeatInterval;
163 interval -= ChangeInterval;
165 if (interval < MinimumInterval)
166 interval = MinimumInterval;
167 timer.Interval = interval;
175 updownbase.UpButton ();
178 updownbase.DownButton ();
181 protected override void OnMouseMove (MouseEventArgs args)
183 base.OnMouseMove (args);
187 if (pressed.Contains (args.X, args.Y)){
193 timer.Enabled = false;
200 Console.WriteLine ("STATE CHANGE");
203 Invalidate (pressed);
208 void DrawUp (Graphics dc)
212 bs = mouse_in && up_pressed ? ButtonState.Pushed : ButtonState.Normal;
213 ThemeEngine.Current.CPDrawScrollButton (dc, up, ScrollButton.Up, bs);
216 void DrawDown (Graphics dc)
220 bs = mouse_in && down_pressed ? ButtonState.Pushed : ButtonState.Normal;
221 ThemeEngine.Current.CPDrawScrollButton (dc, down, ScrollButton.Down, bs);
224 void IDisposable.Dispose ()
235 BorderStyle border_style = BorderStyle.Fixed3D;
236 int desired_height = 0;
240 int scrollbar_button_size = ThemeEngine.Current.ScrollBarButtonSize;
241 LeftRightAlignment updown_align = LeftRightAlignment.Right;
242 bool changing_text = false;
243 bool user_edit = false;
244 bool intercept = true;
246 public UpDownBase () : base ()
250 entry = new TextBox ();
252 entry.Size = new Size (120, Font.Height);
253 entry.LostFocus += new EventHandler (EntryOnLostFocus);
254 entry.TextChanged += new EventHandler (OnTextBoxTextChanged);
255 entry.KeyDown += new KeyEventHandler (OnTextBoxKeyDown);
256 entry.KeyPress += new KeyPressEventHandler (OnTextBoxKeyPress);
257 entry.LostFocus += new EventHandler (OnTextBoxLostFocus);
258 entry.Resize += new EventHandler (OnTextBoxResize);
259 entry.TextChanged += new EventHandler (OnTextBoxTextChanged);
260 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
262 entry.ReadOnly = false;
263 Controls.Add (entry);
265 spinner = new Spinner (this);
266 Controls.Add (spinner);
268 ComputeSizeAndLocation ();
272 void EntryOnLostFocus (object sender, EventArgs e)
277 void ComputeSizeAndLocation ()
279 if (BorderStyle == BorderStyle.Fixed3D)
281 else if (BorderStyle == BorderStyle.FixedSingle)
286 Size = (entry.Size + spinner.Size + new Size (border, border));
288 entry.Location = new Point (border, border);
292 #region UpDownBase overwritten methods
294 protected override void OnMouseWheel (MouseEventArgs args)
296 base.OnMouseWheel (args);
300 else if (args.Delta < 0)
304 protected virtual void OnChanged (object source, EventArgs e)
306 // Not clear, the docs state that this will raise the
307 // Changed event, but that event is not listed anywhere.
310 protected override void OnFontChanged (EventArgs e)
312 base.OnFontChanged (e);
315 desired_height = entry.Height;
316 Height = desired_height;
319 protected override void OnHandleCreated (EventArgs e)
321 base.OnHandleCreated (e);
322 desired_height = entry.Height;
325 protected override void OnLayout (LayoutEventArgs args)
327 base.OnLayout (args);
329 Rectangle bounds = Bounds;
330 int entry_width = bounds.Right - scrollbar_button_size - 1;
332 entry.SetBounds (bounds.X, bounds.Y, entry_width, bounds.Height);
333 spinner.SetBounds (entry_width + 1, bounds.Y, scrollbar_button_size, bounds.Height);
338 protected override void OnPaint (PaintEventArgs pe)
342 if (pe.ClipRectangle.Contains (up))
343 DrawUp (pe.Graphics);
344 if (pe.ClipRectangle.Contains (down))
345 DrawDown (pe.Graphics);
348 protected override void SetVisibleCore (bool state)
350 base.SetVisibleCore (state);
355 [EditorBrowsable(EditorBrowsableState.Advanced)]
356 protected override void WndProc (ref Message m)
358 base.WndProc (ref m);
361 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
364 // Force the size to be our height.
366 base.SetBoundsCore (x, y, width, desired_height, specified);
369 protected override void Dispose (bool disposing)
371 if (spinner != null){
384 #region UpDownBase virtual methods
386 // These are hooked up to the various events from the Entry line that
387 // we do not have yet, and implement the keyboard behavior (use a different
390 protected virtual void OnTextBoxKeyDown (object source, KeyEventArgs e)
395 protected virtual void OnTextBoxKeyPress (object source, KeyPressEventArgs e)
400 protected virtual void OnTextBoxLostFocus (object source, EventArgs e)
405 protected virtual void OnTextBoxResize (object source, EventArgs e)
410 protected virtual void OnTextBoxTextChanged (object source, EventArgs e)
416 changing_text = false;
418 OnChanged (source, e);
424 #region UpDownBase Properties
426 /* FIXME: Do not know what Autoscroll should do */
427 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
428 [EditorBrowsable(EditorBrowsableState.Never)]
430 public virtual bool AutoScroll {
432 return base.AutoScroll;
436 base.AutoScroll = value;
440 /* FIXME: Do not know what AutoscrollMargin does */
441 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
442 [EditorBrowsable(EditorBrowsableState.Never)]
444 public new Size AutoScrollMargin {
446 return base.AutoScrollMargin;
450 base.AutoScrollMargin = value;
454 /* FIXME: Do not know what AutoscrollMinSize does */
455 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
456 [EditorBrowsable(EditorBrowsableState.Never)]
458 public new Size AutoScrollMinSize {
460 return base.AutoScrollMinSize;
464 base.AutoScrollMinSize = value;
468 public override Color BackColor {
470 return base.BackColor;
474 entry.BackColor = value;
478 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
479 [EditorBrowsable(EditorBrowsableState.Never)]
481 public override Image BackgroundImage {
483 return entry.BackgroundImage;
487 entry.BackgroundImage = value;
491 [DefaultValue(BorderStyle.Fixed3D)]
493 public BorderStyle BorderStyle {
499 border_style = value;
502 ComputeSizeAndLocation ();
508 // Used internally to flag when the derivative classes are changing
509 // the Text property as opposed to the user
511 protected bool ChangingText {
513 return changing_text;
517 changing_text = value;
521 // TODO: What should this do?
522 public override ContextMenu ContextMenu {
532 protected override CreateParams CreateParams {
534 return base.CreateParams;
538 protected bool UserEdit {
548 public override string Text {
558 // The documentation is conflicts with itself, we can
559 // not call UpdateEditText, as this will call Text to
568 ChangingText = false;
572 public LeftRightAlignment UpDownAlign
579 updown_align = value;
583 [DefaultValue(false)]
584 public bool ReadOnly {
586 return entry.ReadOnly;
590 entry.ReadOnly = value;
594 public override bool Focused {
596 return entry.Focused;
600 public override Color ForeColor {
602 return base.ForeColor;
606 base.ForeColor = value;
607 entry.ForeColor = value;
612 public bool InterceptArrowKeys {
623 #region UpDownBase standard methods
624 public void Select (int start, int length)
626 entry.Select (start, length);
629 protected virtual void ValidateEditText ()
637 // All these events are just a proxy to the base class,
638 // we must overwrite them for API compatibility
641 public new event EventHandler MouseEnter {
643 base.MouseEnter += value;
647 base.MouseEnter -= value;
651 public new event EventHandler MouseHover {
653 base.MouseHover += value;
657 base.MouseHover -= value;
661 public new event EventHandler MouseLeave {
663 base.MouseLeave += value;
667 base.MouseLeave -= value;
671 public new event EventHandler BackgroundImageChanged {
673 base.BackgroundImageChanged += value;
677 base.BackgroundImageChanged -= value;
682 #region Abstract methods
683 public abstract void DownButton ();
684 public abstract void UpButton ();
685 public abstract void UpdateEditText ();