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 args)
76 Draw (args.ClipRectangle);
77 args.Graphics.DrawImage (ImageBuffer, 0, 0);
80 protected override void OnLayout (LayoutEventArgs args)
83 Rectangle bounds = Bounds;
85 up = new Rectangle (0, 0, bounds.Width, bounds.Height/2);
86 down = new Rectangle (0, bounds.Height/2, bounds.Width, bounds.Height/2);
89 protected override void OnMouseDown (MouseEventArgs args)
91 base.OnMouseDown (args);
93 if (args.Button != MouseButtons.Left)
96 if (up.Contains (args.X, args.Y)){
99 } else if (down.Contains (args.X, args.Y)){
106 Invalidate (pressed);
110 mouse_in = down_pressed | up_pressed;
113 protected override void OnMouseUp (MouseEventArgs args)
121 down_pressed = false;
126 timer.Enabled = false;
130 // Sets up the auto-repeat timer, we give a one second
131 // delay, and then we use the keyboard settings for auto-repeat.
136 timer.Interval = StartInterval;
137 timer.Enabled = true;
141 timer = new Timer ();
142 int kd = SystemInformation.KeyboardDelay;
143 kd = kd < 0 ? 0 : (kd > 4 ? 4 : kd);
144 timer.Interval = StartInterval;
145 timer.Tick += new EventHandler (ClockTick);
146 timer.Enabled = true;
149 void ClockTick (object o, EventArgs a)
152 throw new Exception ("The timer that owns this callback is null!");
154 int interval = timer.Interval;
156 if (interval == StartInterval)
157 interval = RepeatInterval;
159 interval -= ChangeInterval;
161 if (interval < MinimumInterval)
162 interval = MinimumInterval;
163 timer.Interval = interval;
171 updownbase.UpButton ();
174 updownbase.DownButton ();
177 protected override void OnMouseMove (MouseEventArgs args)
179 base.OnMouseMove (args);
183 if (pressed.Contains (args.X, args.Y)){
189 timer.Enabled = false;
196 Console.WriteLine ("STATE CHANGE");
199 Invalidate (pressed);
208 bs = mouse_in && up_pressed ? ButtonState.Pushed : ButtonState.Normal;
209 ThemeEngine.Current.CPDrawScrollButton (DeviceContext, up, ScrollButton.Up, bs);
216 bs = mouse_in && down_pressed ? ButtonState.Pushed : ButtonState.Normal;
217 ThemeEngine.Current.CPDrawScrollButton (DeviceContext, down, ScrollButton.Down, bs);
220 void Draw (Rectangle clip)
222 if (clip.Contains (up))
224 if (clip.Contains (down))
228 void IDisposable.Dispose ()
239 BorderStyle border_style = BorderStyle.Fixed3D;
240 int desired_height = 0;
244 int scrollbar_button_size = ThemeEngine.Current.ScrollBarButtonSize;
245 LeftRightAlignment updown_align = LeftRightAlignment.Right;
246 bool changing_text = false;
247 bool user_edit = false;
248 bool intercept = true;
250 public UpDownBase () : base ()
254 entry = new TextBox ();
256 entry.Size = new Size (120, Font.Height);
257 entry.LostFocus += new EventHandler (EntryOnLostFocus);
258 entry.TextChanged += new EventHandler (OnTextBoxTextChanged);
259 entry.KeyDown += new KeyEventHandler (OnTextBoxKeyDown);
260 entry.KeyPress += new KeyPressEventHandler (OnTextBoxKeyPress);
261 entry.LostFocus += new EventHandler (OnTextBoxLostFocus);
262 entry.Resize += new EventHandler (OnTextBoxResize);
263 entry.TextChanged += new EventHandler (OnTextBoxTextChanged);
264 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
266 entry.ReadOnly = false;
267 Controls.Add (entry);
269 spinner = new Spinner (this);
270 Controls.Add (spinner);
272 ComputeSizeAndLocation ();
276 void EntryOnLostFocus (object sender, EventArgs e)
281 void ComputeSizeAndLocation ()
283 if (BorderStyle == BorderStyle.Fixed3D)
285 else if (BorderStyle == BorderStyle.FixedSingle)
290 Size = (entry.Size + spinner.Size + new Size (border, border));
292 entry.Location = new Point (border, border);
296 #region UpDownBase overwritten methods
298 protected override void OnMouseWheel (MouseEventArgs args)
300 base.OnMouseWheel (args);
304 else if (args.Delta < 0)
308 protected virtual void OnChanged (object source, EventArgs e)
310 // Not clear, the docs state that this will raise the
311 // Changed event, but that event is not listed anywhere.
314 protected override void OnFontChanged (EventArgs e)
316 base.OnFontChanged (e);
319 desired_height = entry.Height;
320 Height = desired_height;
323 protected override void OnHandleCreated (EventArgs e)
325 base.OnHandleCreated (e);
326 desired_height = entry.Height;
329 protected override void OnLayout (LayoutEventArgs args)
331 base.OnLayout (args);
333 Rectangle bounds = Bounds;
334 int entry_width = bounds.Right - scrollbar_button_size - 1;
336 entry.SetBounds (bounds.X, bounds.Y, entry_width, bounds.Height);
337 spinner.SetBounds (entry_width + 1, bounds.Y, scrollbar_button_size, bounds.Height);
341 protected override void OnPaint (PaintEventArgs e)
344 ThemeEngine.Current.CPDrawBorderStyle (e.Graphics, ClientRectangle, BorderStyle.Fixed3D);
345 e.Graphics.DrawImage (ImageBuffer, 0, 0);
348 protected override void SetVisibleCore (bool state)
350 base.SetVisibleCore (state);
354 [EditorBrowsable(EditorBrowsableState.Advanced)]
355 protected override void WndProc (ref Message m)
357 base.WndProc (ref m);
360 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
363 // Force the size to be our height.
365 base.SetBoundsCore (x, y, width, desired_height, specified);
368 protected override void Dispose (bool disposing)
370 if (spinner != null){
383 #region UpDownBase virtual methods
385 // These are hooked up to the various events from the Entry line that
386 // we do not have yet, and implement the keyboard behavior (use a different
389 protected virtual void OnTextBoxKeyDown (object source, KeyEventArgs e)
394 protected virtual void OnTextBoxKeyPress (object source, KeyPressEventArgs e)
399 protected virtual void OnTextBoxLostFocus (object source, EventArgs e)
404 protected virtual void OnTextBoxResize (object source, EventArgs e)
409 protected virtual void OnTextBoxTextChanged (object source, EventArgs e)
415 changing_text = false;
417 OnChanged (source, e);
423 #region UpDownBase Properties
425 /* FIXME: Do not know what Autoscroll should do */
426 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
427 [EditorBrowsable(EditorBrowsableState.Never)]
429 public virtual bool AutoScroll {
431 return base.AutoScroll;
435 base.AutoScroll = value;
439 /* FIXME: Do not know what AutoscrollMargin does */
440 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
441 [EditorBrowsable(EditorBrowsableState.Never)]
443 public new Size AutoScrollMargin {
445 return base.AutoScrollMargin;
449 base.AutoScrollMargin = value;
453 /* FIXME: Do not know what AutoscrollMinSize does */
454 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
455 [EditorBrowsable(EditorBrowsableState.Never)]
457 public new Size AutoScrollMinSize {
459 return base.AutoScrollMinSize;
463 base.AutoScrollMinSize = value;
467 public override Color BackColor {
469 return base.BackColor;
473 entry.BackColor = value;
477 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
478 [EditorBrowsable(EditorBrowsableState.Never)]
480 public override Image BackgroundImage {
482 return entry.BackgroundImage;
486 entry.BackgroundImage = value;
490 [DefaultValue(BorderStyle.Fixed3D)]
492 public BorderStyle BorderStyle {
498 border_style = value;
501 ComputeSizeAndLocation ();
507 // Used internally to flag when the derivative classes are changing
508 // the Text property as opposed to the user
510 protected bool ChangingText {
512 return changing_text;
516 changing_text = value;
520 // TODO: What should this do?
521 public override ContextMenu ContextMenu {
531 protected override CreateParams CreateParams {
533 return base.CreateParams;
537 protected bool UserEdit {
547 public override string Text {
557 // The documentation is conflicts with itself, we can
558 // not call UpdateEditText, as this will call Text to
567 ChangingText = false;
571 public LeftRightAlignment UpDownAlign
578 updown_align = value;
582 [DefaultValue(false)]
583 public bool ReadOnly {
585 return entry.ReadOnly;
589 entry.ReadOnly = value;
593 public override bool Focused {
595 return entry.Focused;
599 public override Color ForeColor {
601 return base.ForeColor;
605 base.ForeColor = value;
606 entry.ForeColor = value;
611 public bool InterceptArrowKeys {
622 #region UpDownBase standard methods
623 public void Select (int start, int length)
625 entry.Select (start, length);
628 protected virtual void ValidateEditText ()
636 // All these events are just a proxy to the base class,
637 // we must overwrite them for API compatibility
640 public new event EventHandler MouseEnter {
642 base.MouseEnter += value;
646 base.MouseEnter -= value;
650 public new event EventHandler MouseHover {
652 base.MouseHover += value;
656 base.MouseHover -= value;
660 public new event EventHandler MouseLeave {
662 base.MouseLeave += value;
666 base.MouseLeave -= value;
670 public new event EventHandler BackgroundImageChanged {
672 base.BackgroundImageChanged += value;
676 base.BackgroundImageChanged -= value;
681 #region Abstract methods
682 public abstract void DownButton ();
683 public abstract void UpButton ();
684 public abstract void UpdateEditText ();