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 : System.Windows.Forms.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) {
65 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
66 this.SetStyle(ControlStyles.DoubleBuffer, true);
67 this.SetStyle(ControlStyles.Opaque, true);
68 this.SetStyle(ControlStyles.ResizeRedraw, true);
69 this.SetStyle(ControlStyles.UserPaint, true);
70 this.SetStyle(ControlStyles.FixedHeight, true);
72 tmrRepeat = new Timer();
74 tmrRepeat.Enabled = false;
75 tmrRepeat.Interval = 10;
76 tmrRepeat.Tick += new EventHandler(tmrRepeat_Tick);
80 #endregion // Constructors
82 #region Private & Internal Methods
83 private void compute_rects() {
84 int top_button_height;
85 int bottom_button_height;
87 top_button_height = ClientSize.Height / 2;
88 bottom_button_height = ClientSize.Height - top_button_height;
90 top_button_rect = new Rectangle(0, 0, ClientSize.Width, top_button_height);
91 bottom_button_rect = new Rectangle(0, top_button_height, ClientSize.Width, bottom_button_height);
94 private void redraw(Graphics graphics) {
95 ButtonState top_button_state;
96 ButtonState bottom_button_state;
98 top_button_state = bottom_button_state = ButtonState.Normal;
100 if (mouse_pressed != 0) {
101 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y)) {
102 top_button_state = ButtonState.Pushed;
105 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y)) {
106 bottom_button_state = ButtonState.Pushed;
110 ControlPaint.DrawScrollButton(graphics, top_button_rect, ScrollButton.Up, top_button_state);
111 ControlPaint.DrawScrollButton(graphics, bottom_button_rect, ScrollButton.Down, bottom_button_state);
114 private void tmrRepeat_Tick(object sender, EventArgs e) {
115 if (repeat_delay > 1) {
118 if (repeat_counter < repeat_delay) {
123 repeat_delay = (repeat_delay * 3 / 4);
126 if (mouse_pressed == 0) {
127 tmrRepeat.Enabled = false;
130 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y)) {
134 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y)) {
138 #endregion // Private & Internal Methods
140 #region Protected Instance Methods
141 protected override void OnMouseDown(MouseEventArgs e) {
142 if (e.Button != MouseButtons.Left) {
146 if (top_button_rect.Contains(e.X, e.Y)) {
149 } else if (bottom_button_rect.Contains(e.X, e.Y)) {
158 tmrRepeat.Enabled = true;
160 repeat_delay = InitialRepeatDelay;
165 protected override void OnMouseMove(MouseEventArgs e) {
166 ButtonState before, after;
168 before = ButtonState.Normal;
169 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y))
170 before = ButtonState.Pushed;
171 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y))
172 before = ButtonState.Pushed;
177 after = ButtonState.Normal;
178 if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y))
179 after = ButtonState.Pushed;
180 if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y))
181 after = ButtonState.Pushed;
183 if (before != after) {
184 if (after == ButtonState.Pushed) {
185 tmrRepeat.Enabled = true;
187 repeat_delay = InitialRepeatDelay;
189 // fire off one right now too for good luck
190 if (mouse_pressed == 1)
192 if (mouse_pressed == 2)
196 tmrRepeat.Enabled = false;
202 protected override void OnMouseUp(MouseEventArgs e) {
209 protected override void OnMouseWheel(MouseEventArgs e) {
212 else if (e.Delta < 0)
216 protected override void OnPaint(PaintEventArgs e) {
220 protected override void OnResize(EventArgs e) {
224 #endregion // Protected Instance Methods
227 internal void SetSelectable (bool selectable)
229 SetStyle (ControlStyles.Selectable, selectable);
232 #endregion // UpDownSpinner Sub-class
234 internal class UpDownTextBox : TextBox {
236 //private UpDownBase owner;
238 public UpDownTextBox (UpDownBase owner)
240 //this.owner = owner;
242 SetStyle (ControlStyles.FixedWidth, false);
245 internal void SetSelectable (bool selectable)
247 SetStyle (ControlStyles.Selectable, selectable);
250 internal void ActivateCaret (bool active)
253 document.CaretHasFocus ();
255 document.CaretLostFocus ();
258 protected override void OnGotFocus(EventArgs e)
260 this.Parent.OnGotFocusInternal(e);
263 protected override void OnLostFocus(EventArgs e)
265 this.Parent.OnLostFocusInternal(e);
269 #region Local Variables
270 internal UpDownTextBox txtView;
271 private UpDownSpinner spnSpinner;
272 private bool _InterceptArrowKeys = true;
273 private LeftRightAlignment _UpDownAlign;
274 private bool changing_text;
275 private bool user_edit;
276 #endregion // Local Variables
278 #region Public Constructors
279 public UpDownBase() {
280 _UpDownAlign = LeftRightAlignment.Right;
281 border_style = BorderStyle.Fixed3D;
283 spnSpinner = new UpDownSpinner(this);
285 txtView = new UpDownTextBox (this);
286 txtView.ModifiedChanged += new EventHandler(OnChanged);
287 txtView.AcceptsReturn = true;
288 txtView.AutoSize = false;
289 txtView.BorderStyle = BorderStyle.None;
290 txtView.Location = new System.Drawing.Point(17, 17);
291 txtView.TabIndex = TabIndex;
294 Controls.Add (spnSpinner);
295 Controls.Add (txtView);
298 this.ActiveControl = txtView;
300 Height = PreferredHeight;
301 base.BackColor = txtView.BackColor;
303 TabIndexChanged += new EventHandler (TabIndexChangedHandler);
305 txtView.KeyDown += new KeyEventHandler(OnTextBoxKeyDown);
306 txtView.KeyPress += new KeyPressEventHandler(OnTextBoxKeyPress);
307 // txtView.LostFocus += new EventHandler(OnTextBoxLostFocus);
308 txtView.Resize += new EventHandler(OnTextBoxResize);
309 txtView.TextChanged += new EventHandler(OnTextBoxTextChanged);
311 txtView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
313 // So the child controls don't get auto selected when the updown is selected
314 auto_select_child = false;
315 SetStyle(ControlStyles.FixedHeight, true);
317 SetStyle (ControlStyles.Opaque | ControlStyles.ResizeRedraw, true);
318 SetStyle (ControlStyles.StandardClick | ControlStyles.UseTextForAccessibility, false);
325 #region Private Methods
326 void reseat_controls() {
327 int text_displacement = 0;
329 int spinner_width = 16;
330 //int spinner_width = ClientSize.Height;
332 if (_UpDownAlign == LeftRightAlignment.Left) {
333 spnSpinner.Bounds = new Rectangle(0, 0, spinner_width, ClientSize.Height);
334 text_displacement = spnSpinner.Width;
336 spnSpinner.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
338 spnSpinner.Bounds = new Rectangle(ClientSize.Width - spinner_width, 0, spinner_width, ClientSize.Height);
340 spnSpinner.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;
343 txtView.Bounds = new Rectangle(text_displacement, 0, ClientSize.Width - spinner_width, Height);
346 private void TabIndexChangedHandler (object sender, EventArgs e)
348 txtView.TabIndex = TabIndex;
351 internal override void OnPaintInternal (PaintEventArgs e) {
352 e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), ClientRectangle);
355 internal override void OnGotFocusInternal (EventArgs e)
357 base.OnGotFocusInternal (e);
358 txtView.ActivateCaret (true);
359 txtView.SetSelectable (false);
360 spnSpinner.SetSelectable (false);
363 internal override void OnLostFocusInternal (EventArgs e)
365 base.OnLostFocusInternal (e);
366 txtView.ActivateCaret (false);
367 txtView.SetSelectable (true);
368 spnSpinner.SetSelectable (true);
371 #endregion // Private Methods
373 #region Public Instance Properties
375 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
376 [EditorBrowsable(EditorBrowsableState.Never)]
377 public override bool AutoScroll {
379 return base.AutoScroll;
383 base.AutoScroll = value;
388 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
389 [EditorBrowsable(EditorBrowsableState.Never)]
390 public new Size AutoScrollMargin {
391 get { return base.AutoScrollMargin; }
392 set { base.AutoScrollMargin = value; }
396 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
397 [EditorBrowsable(EditorBrowsableState.Never)]
398 public new Size AutoScrollMinSize {
399 get { return base.AutoScrollMinSize; }
400 set { base.AutoScrollMinSize = value; }
403 public override Color BackColor {
405 return base.BackColor;
409 base.BackColor = value;
410 txtView.BackColor = value;
415 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
416 [EditorBrowsable(EditorBrowsableState.Never)]
417 public override Image BackgroundImage {
419 return base.BackgroundImage;
422 base.BackgroundImage = value;
423 txtView.BackgroundImage = value;
428 [DefaultValue(BorderStyle.Fixed3D)]
430 public BorderStyle BorderStyle {
431 get { return InternalBorderStyle; }
432 set { InternalBorderStyle = value; }
435 public override ContextMenu ContextMenu {
437 return base.ContextMenu;
440 base.ContextMenu = value;
441 txtView.ContextMenu = value;
442 spnSpinner.ContextMenu = value;
447 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
448 [EditorBrowsable(EditorBrowsableState.Never)]
449 public new DockPaddingEdges DockPadding {
450 get { return base.DockPadding; }
454 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
455 public override bool Focused {
461 public override Color ForeColor {
463 return base.ForeColor;
466 base.ForeColor = value;
467 txtView.ForeColor = value;
472 public bool InterceptArrowKeys {
474 return _InterceptArrowKeys;
477 _InterceptArrowKeys = value;
482 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
483 [EditorBrowsable(EditorBrowsableState.Advanced)]
484 public int PreferredHeight {
486 // For some reason, the TextBox's PreferredHeight does not
487 // change when the Font property is assigned. Without a
488 // border, it will always be Font.Height anyway.
489 //int text_box_preferred_height = (txtView != null) ? txtView.PreferredHeight : Font.Height;
490 int text_box_preferred_height = Font.Height;
492 switch (border_style) {
493 case BorderStyle.FixedSingle:
494 case BorderStyle.Fixed3D:
495 text_box_preferred_height += 3; // magic number? :-)
497 return text_box_preferred_height + 4;
499 case BorderStyle.None:
501 return text_box_preferred_height;
506 [DefaultValue(false)]
507 public bool ReadOnly {
509 return txtView.ReadOnly;
512 txtView.ReadOnly = value;
517 public override string Text {
519 if (txtView != null) {
525 bool suppress_validation = changing_text;
527 txtView.Text = value;
529 if (!suppress_validation)
534 [DefaultValue(HorizontalAlignment.Left)]
536 public HorizontalAlignment TextAlign {
538 return txtView.TextAlign;
541 txtView.TextAlign = value;
545 [DefaultValue(LeftRightAlignment.Right)]
547 public LeftRightAlignment UpDownAlign {
552 _UpDownAlign = value;
557 #endregion // Public Instance Properties
559 #region Protected Instance Properties
560 protected bool ChangingText {
562 return changing_text;
565 changing_text = value;
569 protected override CreateParams CreateParams {
571 return base.CreateParams;
575 protected override Size DefaultSize {
577 return new Size(120, this.PreferredHeight);
581 protected bool UserEdit {
589 #endregion // Protected Instance Properties
591 #region Public Instance Methods
592 public abstract void DownButton();
593 public void Select(int start, int length) {
594 txtView.Select(start, length);
597 public abstract void UpButton();
598 #endregion // Public Instance Methods
600 #region Protected Instance Methods
601 protected override void Dispose(bool disposing) {
606 spnSpinner.Dispose();
609 base.Dispose (disposing);
612 protected virtual void OnChanged(object source, EventArgs e) {
615 protected override void OnFontChanged(EventArgs e) {
616 txtView.Font = this.Font;
617 Height = PreferredHeight;
620 protected override void OnHandleCreated(EventArgs e) {
621 base.OnHandleCreated (e);
624 protected override void OnLayout(LayoutEventArgs e) {
628 protected override void OnMouseWheel(MouseEventArgs e) {
633 else if (e.Delta < 0)
639 protected virtual void OnTextBoxKeyDown(object source, KeyEventArgs e) {
640 if (_InterceptArrowKeys) {
641 if ((e.KeyCode == Keys.Up) || (e.KeyCode == Keys.Down)) {
644 if (e.KeyCode == Keys.Up)
646 if (e.KeyCode == Keys.Down)
654 protected virtual void OnTextBoxKeyPress(object source, KeyPressEventArgs e) {
655 if (e.KeyChar == '\r') {
662 protected virtual void OnTextBoxLostFocus(object source, EventArgs e) {
668 protected virtual void OnTextBoxResize(object source, EventArgs e) {
669 // compute the new height, taking the border into account
670 Height = PreferredHeight;
672 // let anchoring reposition the controls
675 protected virtual void OnTextBoxTextChanged(object source, EventArgs e) {
677 ChangingText = false;
685 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
686 base.SetBoundsCore(x, y, width, height, specified);
688 if ((specified & BoundsSpecified.Size) != BoundsSpecified.None) {
693 protected abstract void UpdateEditText();
695 protected virtual void ValidateEditText() {
696 // to be overridden by subclassers
699 [EditorBrowsable(EditorBrowsableState.Advanced)]
700 protected override void WndProc(ref Message m) {
702 switch((Msg) m.Msg) {
706 XplatUI.SendMessage (txtView.Handle, (Msg) m.Msg, m.WParam, m.LParam);
709 base.WndProc (ref m);
713 #endregion // Protected Instance Methods
717 [EditorBrowsable(EditorBrowsableState.Never)]
718 public new event EventHandler BackgroundImageChanged {
719 add { base.BackgroundImageChanged += value; }
720 remove { base.BackgroundImageChanged -= value; }
724 [EditorBrowsable(EditorBrowsableState.Never)]
725 public new event EventHandler MouseEnter {
726 add { base.MouseEnter += value; }
727 remove { base.MouseEnter -= value; }
731 [EditorBrowsable(EditorBrowsableState.Never)]
732 public new event EventHandler MouseHover {
733 add { base.MouseHover += value; }
734 remove { base.MouseHover -= value; }
738 [EditorBrowsable(EditorBrowsableState.Never)]
739 public new event EventHandler MouseLeave {
740 add { base.MouseLeave += value; }
741 remove { base.MouseLeave -= value; }
745 [EditorBrowsable(EditorBrowsableState.Never)]
746 public new event MouseEventHandler MouseMove {
747 add { base.MouseMove += value; }
748 remove { base.MouseMove -= value; }