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) 2005 Novell, Inc.
23 // Jonathan Gilbert <logic@deltaq.org>
25 // Integration into MWF:
26 // Peter Bartok <pbartok@novell.com>
30 using System.Collections;
31 using System.ComponentModel;
33 using System.Runtime.InteropServices;
34 using System.Windows.Forms;
36 namespace System.Windows.Forms
39 [ClassInterface (ClassInterfaceType.AutoDispatch)]
42 [Designer("System.Windows.Forms.Design.UpDownBaseDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43 public abstract class UpDownBase : ContainerControl {
44 #region UpDownSpinner Sub-class
45 internal sealed class UpDownSpinner : Control {
46 #region Local Variables
47 private const int InitialRepeatDelay = 50;
48 private UpDownBase owner;
49 private Timer tmrRepeat;
50 private Rectangle top_button_rect;
51 private Rectangle bottom_button_rect;
52 private int mouse_pressed;
55 private int repeat_delay;
56 private int repeat_counter;
57 #endregion // Local Variables
60 public UpDownSpinner(UpDownBase owner)
66 SetStyle(ControlStyles.AllPaintingInWmPaint, true);
67 SetStyle(ControlStyles.DoubleBuffer, true);
68 SetStyle(ControlStyles.Opaque, true);
69 SetStyle(ControlStyles.ResizeRedraw, true);
70 SetStyle(ControlStyles.UserPaint, true);
71 SetStyle(ControlStyles.FixedHeight, true);
72 SetStyle(ControlStyles.Selectable, false);
74 tmrRepeat = new Timer();
76 tmrRepeat.Enabled = false;
77 tmrRepeat.Interval = 10;
78 tmrRepeat.Tick += new EventHandler(tmrRepeat_Tick);
82 #endregion // Constructors
84 #region Private & Internal Methods
85 private void compute_rects ()
87 int top_button_height;
88 int bottom_button_height;
90 top_button_height = ClientSize.Height / 2;
91 bottom_button_height = ClientSize.Height - top_button_height;
93 top_button_rect = new Rectangle(0, 0, ClientSize.Width, top_button_height);
94 bottom_button_rect = new Rectangle(0, top_button_height, ClientSize.Width, bottom_button_height);
97 private void redraw (Graphics graphics)
99 ButtonState top_button_state;
100 ButtonState bottom_button_state;
102 top_button_state = bottom_button_state = ButtonState.Normal;
104 if (mouse_pressed != 0) {
105 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y)) {
106 top_button_state = ButtonState.Pushed;
109 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y)) {
110 bottom_button_state = ButtonState.Pushed;
114 ControlPaint.DrawScrollButton(graphics, top_button_rect, ScrollButton.Up, top_button_state);
115 ControlPaint.DrawScrollButton(graphics, bottom_button_rect, ScrollButton.Down, bottom_button_state);
118 private void tmrRepeat_Tick (object sender, EventArgs e)
120 if (repeat_delay > 1) {
123 if (repeat_counter < repeat_delay) {
128 repeat_delay = (repeat_delay * 3 / 4);
131 if (mouse_pressed == 0) {
132 tmrRepeat.Enabled = false;
135 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y)) {
139 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y)) {
143 #endregion // Private & Internal Methods
145 #region Protected Instance Methods
146 protected override void OnMouseDown (MouseEventArgs e)
148 if (e.Button != MouseButtons.Left) {
152 if (top_button_rect.Contains(e.X, e.Y)) {
155 } else if (bottom_button_rect.Contains(e.X, e.Y)) {
164 tmrRepeat.Enabled = true;
166 repeat_delay = InitialRepeatDelay;
171 protected override void OnMouseMove (MouseEventArgs e)
173 ButtonState before, after;
175 before = ButtonState.Normal;
176 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y))
177 before = ButtonState.Pushed;
178 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y))
179 before = ButtonState.Pushed;
184 after = ButtonState.Normal;
185 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y))
186 after = ButtonState.Pushed;
187 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y))
188 after = ButtonState.Pushed;
190 if (before != after) {
191 if (after == ButtonState.Pushed) {
192 tmrRepeat.Enabled = true;
194 repeat_delay = InitialRepeatDelay;
196 // fire off one right now too for good luck
197 if (mouse_pressed == 1)
199 if (mouse_pressed == 2)
203 tmrRepeat.Enabled = false;
209 protected override void OnMouseUp(MouseEventArgs e)
217 protected override void OnMouseWheel(MouseEventArgs e)
221 else if (e.Delta < 0)
225 protected override void OnPaint(PaintEventArgs e)
230 protected override void OnResize(EventArgs e)
235 #endregion // Protected Instance Methods
237 #endregion // UpDownSpinner Sub-class
239 internal class UpDownTextBox : TextBox {
241 private UpDownBase owner;
243 public UpDownTextBox (UpDownBase owner)
247 SetStyle (ControlStyles.FixedWidth, false);
248 SetStyle (ControlStyles.Selectable, false);
252 // The following can be shown to be present by
253 // adding events to both the UpDown and the
254 // internal textbox. the textbox doesn't
255 // generate any, and the updown generates them
257 protected override void OnGotFocus (EventArgs e)
259 ShowSelection = true;
260 owner.OnGotFocus (e);
264 protected override void OnLostFocus (EventArgs e)
266 ShowSelection = false;
267 owner.OnLostFocus (e);
271 protected override void OnMouseDown (MouseEventArgs e)
273 // XXX look into whether or not the
274 // mouse event args are altered in
277 owner.OnMouseDown (e);
281 protected override void OnMouseUp (MouseEventArgs e)
283 // XXX look into whether or not the
284 // mouse event args are altered in
291 // XXX there are likely more events that forward up to the UpDown
294 #region Local Variables
295 internal UpDownTextBox txtView;
296 private UpDownSpinner spnSpinner;
297 private bool _InterceptArrowKeys = true;
298 private LeftRightAlignment _UpDownAlign;
299 private bool changing_text;
300 private bool user_edit;
301 #endregion // Local Variables
303 #region Public Constructors
306 _UpDownAlign = LeftRightAlignment.Right;
307 border_style = BorderStyle.Fixed3D;
309 spnSpinner = new UpDownSpinner(this);
311 txtView = new UpDownTextBox (this);
312 txtView.ModifiedChanged += new EventHandler(OnChanged);
313 txtView.AcceptsReturn = true;
314 txtView.AutoSize = false;
315 txtView.BorderStyle = BorderStyle.None;
316 txtView.Location = new System.Drawing.Point(17, 17);
317 txtView.TabIndex = TabIndex;
320 Controls.Add (spnSpinner);
321 Controls.Add (txtView);
324 Height = PreferredHeight;
325 base.BackColor = txtView.BackColor;
327 TabIndexChanged += new EventHandler (TabIndexChangedHandler);
329 txtView.KeyDown += new KeyEventHandler(OnTextBoxKeyDown);
330 txtView.KeyPress += new KeyPressEventHandler(OnTextBoxKeyPress);
331 // txtView.LostFocus += new EventHandler(OnTextBoxLostFocus);
332 txtView.Resize += new EventHandler(OnTextBoxResize);
333 txtView.TextChanged += new EventHandler(OnTextBoxTextChanged);
335 txtView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
337 // So the child controls don't get auto selected when the updown is selected
338 auto_select_child = false;
339 SetStyle(ControlStyles.FixedHeight, true);
340 SetStyle(ControlStyles.Selectable, true);
342 SetStyle (ControlStyles.Opaque | ControlStyles.ResizeRedraw, true);
343 SetStyle (ControlStyles.StandardClick | ControlStyles.UseTextForAccessibility, false);
348 #region Private Methods
349 void reseat_controls()
351 int text_displacement = 0;
353 int spinner_width = 16;
354 //int spinner_width = ClientSize.Height;
356 if (_UpDownAlign == LeftRightAlignment.Left) {
357 spnSpinner.Bounds = new Rectangle(0, 0, spinner_width, ClientSize.Height);
358 text_displacement = spnSpinner.Width;
360 spnSpinner.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
362 spnSpinner.Bounds = new Rectangle(ClientSize.Width - spinner_width, 0, spinner_width, ClientSize.Height);
364 spnSpinner.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;
367 txtView.Bounds = new Rectangle(text_displacement, 0, ClientSize.Width - spinner_width, Height);
370 private void TabIndexChangedHandler (object sender, EventArgs e)
372 txtView.TabIndex = TabIndex;
375 internal override void OnPaintInternal (PaintEventArgs e)
377 e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), ClientRectangle);
380 #endregion // Private Methods
382 #region Public Instance Properties
384 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
385 [EditorBrowsable(EditorBrowsableState.Never)]
386 public override bool AutoScroll {
388 return base.AutoScroll;
392 base.AutoScroll = value;
397 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
398 [EditorBrowsable(EditorBrowsableState.Never)]
399 public new Size AutoScrollMargin {
400 get { return base.AutoScrollMargin; }
401 set { base.AutoScrollMargin = value; }
405 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
406 [EditorBrowsable(EditorBrowsableState.Never)]
407 public new Size AutoScrollMinSize {
408 get { return base.AutoScrollMinSize; }
409 set { base.AutoScrollMinSize = value; }
412 public override Color BackColor {
414 return base.BackColor;
418 base.BackColor = value;
419 txtView.BackColor = value;
424 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
425 [EditorBrowsable(EditorBrowsableState.Never)]
426 public override Image BackgroundImage {
428 return base.BackgroundImage;
431 base.BackgroundImage = value;
432 txtView.BackgroundImage = value;
437 [DefaultValue(BorderStyle.Fixed3D)]
439 public BorderStyle BorderStyle {
440 get { return InternalBorderStyle; }
441 set { InternalBorderStyle = value; }
444 public override ContextMenu ContextMenu {
446 return base.ContextMenu;
449 base.ContextMenu = value;
450 txtView.ContextMenu = value;
451 spnSpinner.ContextMenu = value;
456 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
457 [EditorBrowsable(EditorBrowsableState.Never)]
458 public new DockPaddingEdges DockPadding {
459 get { return base.DockPadding; }
463 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
464 public override bool Focused {
466 return txtView.Focused;
470 public override Color ForeColor {
472 return base.ForeColor;
475 base.ForeColor = value;
476 txtView.ForeColor = value;
481 public bool InterceptArrowKeys {
483 return _InterceptArrowKeys;
486 _InterceptArrowKeys = value;
491 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
492 [EditorBrowsable(EditorBrowsableState.Advanced)]
493 public int PreferredHeight {
495 // For some reason, the TextBox's PreferredHeight does not
496 // change when the Font property is assigned. Without a
497 // border, it will always be Font.Height anyway.
498 //int text_box_preferred_height = (txtView != null) ? txtView.PreferredHeight : Font.Height;
499 int text_box_preferred_height = Font.Height;
501 switch (border_style) {
502 case BorderStyle.FixedSingle:
503 case BorderStyle.Fixed3D:
504 text_box_preferred_height += 3; // magic number? :-)
506 return text_box_preferred_height + 4;
508 case BorderStyle.None:
510 return text_box_preferred_height;
515 [DefaultValue(false)]
516 public bool ReadOnly {
518 return txtView.ReadOnly;
521 txtView.ReadOnly = value;
526 public override string Text {
528 if (txtView != null) {
534 bool suppress_validation = changing_text;
536 txtView.Text = value;
538 if (!suppress_validation)
541 txtView.SelectionLength = 0;
545 [DefaultValue(HorizontalAlignment.Left)]
547 public HorizontalAlignment TextAlign {
549 return txtView.TextAlign;
552 txtView.TextAlign = value;
556 [DefaultValue(LeftRightAlignment.Right)]
558 public LeftRightAlignment UpDownAlign {
563 _UpDownAlign = value;
568 #endregion // Public Instance Properties
570 #region Protected Instance Properties
571 protected bool ChangingText {
573 return changing_text;
576 changing_text = value;
580 protected override CreateParams CreateParams {
582 return base.CreateParams;
586 protected override Size DefaultSize {
588 return new Size(120, this.PreferredHeight);
592 protected bool UserEdit {
600 #endregion // Protected Instance Properties
602 #region Public Instance Methods
603 public abstract void DownButton ();
604 public void Select(int start, int length)
606 txtView.Select(start, length);
609 public abstract void UpButton ();
610 #endregion // Public Instance Methods
612 #region Protected Instance Methods
613 protected override void Dispose (bool disposing)
619 spnSpinner.Dispose();
622 base.Dispose (disposing);
625 protected virtual void OnChanged (object source, EventArgs e)
629 protected override void OnFontChanged (EventArgs e)
631 txtView.Font = this.Font;
632 Height = PreferredHeight;
635 protected override void OnHandleCreated (EventArgs e)
637 base.OnHandleCreated (e);
640 protected override void OnLayout (LayoutEventArgs e)
645 protected override void OnMouseWheel (MouseEventArgs e)
649 else if (e.Delta < 0)
653 protected virtual void OnTextBoxKeyDown (object source, KeyEventArgs e)
655 if (_InterceptArrowKeys) {
656 if ((e.KeyCode == Keys.Up) || (e.KeyCode == Keys.Down)) {
659 if (e.KeyCode == Keys.Up)
661 if (e.KeyCode == Keys.Down)
669 protected virtual void OnTextBoxKeyPress (object source, KeyPressEventArgs e)
671 if (e.KeyChar == '\r') {
678 protected virtual void OnTextBoxLostFocus (object source, EventArgs e)
685 protected virtual void OnTextBoxResize (object source, EventArgs e)
687 // compute the new height, taking the border into account
688 Height = PreferredHeight;
690 // let anchoring reposition the controls
693 protected virtual void OnTextBoxTextChanged (object source, EventArgs e)
696 ChangingText = false;
703 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
705 base.SetBoundsCore(x, y, width, height, specified);
707 if ((specified & BoundsSpecified.Size) != BoundsSpecified.None)
711 protected abstract void UpdateEditText ();
713 protected virtual void ValidateEditText ()
715 // to be overridden by subclassers
718 [EditorBrowsable(EditorBrowsableState.Advanced)]
719 protected override void WndProc (ref Message m)
721 switch((Msg) m.Msg) {
725 XplatUI.SendMessage (txtView.Handle, (Msg) m.Msg, m.WParam, m.LParam);
727 case Msg.WM_SETFOCUS:
728 ActiveControl = txtView;
730 case Msg.WM_KILLFOCUS:
731 ActiveControl = null;
734 base.WndProc (ref m);
738 #endregion // Protected Instance Methods
742 [EditorBrowsable(EditorBrowsableState.Never)]
743 public new event EventHandler BackgroundImageChanged {
744 add { base.BackgroundImageChanged += value; }
745 remove { base.BackgroundImageChanged -= value; }
749 [EditorBrowsable(EditorBrowsableState.Never)]
750 public new event EventHandler MouseEnter {
751 add { base.MouseEnter += value; }
752 remove { base.MouseEnter -= value; }
756 [EditorBrowsable(EditorBrowsableState.Never)]
757 public new event EventHandler MouseHover {
758 add { base.MouseHover += value; }
759 remove { base.MouseHover -= value; }
763 [EditorBrowsable(EditorBrowsableState.Never)]
764 public new event EventHandler MouseLeave {
765 add { base.MouseLeave += value; }
766 remove { base.MouseLeave -= value; }
770 [EditorBrowsable(EditorBrowsableState.Never)]
771 public new event MouseEventHandler MouseMove {
772 add { base.MouseMove += value; }
773 remove { base.MouseMove -= value; }