mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-23 20:32:34 +00:00
425 lines
11 KiB
C#
Executable file
425 lines
11 KiB
C#
Executable file
// ============================================================================ '
|
|
// NumericUpDownEx - v.1.3 '
|
|
// ============================================================================ '
|
|
// Author: Claudio Nicora '
|
|
// WebSite: http://coolsoft.altervista.org '
|
|
// CodeProject: http://www.codeproject.com/KB/edit/NumericUpDownEx.aspx '
|
|
// License: CodeProject Open License '
|
|
// http://www.codeproject.com/info/cpol10.aspx '
|
|
// Feel free to contribute here: http://coolsoft.altervista.org '
|
|
// ============================================================================ '
|
|
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Drawing;
|
|
using System.ComponentModel;
|
|
using System.Windows.Forms;
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderEffects
|
|
{
|
|
[DesignerCategory("code")]
|
|
public class NumericUpDownEx : NumericUpDown
|
|
{
|
|
// reference to the underlying TextBox control
|
|
private TextBox _textbox;
|
|
|
|
// reference to the underlying UpDownButtons control
|
|
private Control _upDownButtons;
|
|
|
|
/// <summary>
|
|
/// object creator
|
|
/// </summary>
|
|
public NumericUpDownEx()
|
|
{
|
|
// extract a reference to the underlying TextBox field
|
|
_textbox = GetPrivateField<TextBox>(this, "upDownEdit");
|
|
if(_textbox == null)
|
|
{
|
|
throw new ArgumentNullException(this.GetType().FullName + ": Can't find internal TextBox field.");
|
|
}
|
|
// extract a reference to the underlying UpDownButtons field
|
|
_upDownButtons = GetPrivateField<Control>(this, "upDownButtons");
|
|
if(_upDownButtons == null)
|
|
{
|
|
throw new ArgumentNullException(this.GetType().FullName + ": Can't find internal UpDown buttons field.");
|
|
}
|
|
// add handlers (MouseEnter and MouseLeave events of NumericUpDown
|
|
// are not working properly)
|
|
_textbox.MouseEnter += _mouseEnterLeave;
|
|
_textbox.MouseLeave += _mouseEnterLeave;
|
|
_upDownButtons.MouseEnter += _mouseEnterLeave;
|
|
_upDownButtons.MouseLeave += _mouseEnterLeave;
|
|
base.MouseEnter += _mouseEnterLeave;
|
|
base.MouseLeave += _mouseEnterLeave;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Extracts a reference to a private underlying field
|
|
/// </summary>
|
|
protected static internal T GetPrivateField<T>(NumericUpDownEx ctrl, string fieldName) where T : Control
|
|
{
|
|
// find internal TextBox
|
|
FieldInfo fi = typeof(NumericUpDown).GetField(fieldName, BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
// take some caution... they could change field name in the future!
|
|
if(fi == null)
|
|
{
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
return fi.GetValue(ctrl) as T;
|
|
}
|
|
}
|
|
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
if(_upDownButtons.Visible == false)
|
|
{
|
|
e.Graphics.Clear(this.BackColor);
|
|
}
|
|
base.OnPaint(e);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// WndProc override to kill WN_MOUSEWHEEL message
|
|
/// </summary>
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
const int WM_MOUSEWHEEL = 0x20a;
|
|
|
|
if(m.Msg == WM_MOUSEWHEEL)
|
|
{
|
|
switch(_interceptMouseWheel)
|
|
{
|
|
case InterceptMouseWheelMode.Always:
|
|
// standard message
|
|
base.WndProc(ref m);
|
|
break;
|
|
case InterceptMouseWheelMode.WhenMouseOver:
|
|
if(_mouseOver)
|
|
{
|
|
// standard message
|
|
base.WndProc(ref m);
|
|
}
|
|
break;
|
|
case InterceptMouseWheelMode.Never:
|
|
// kill the message
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#region New properties
|
|
|
|
[DefaultValue(false)]
|
|
[Category("Behavior")]
|
|
[Description("Automatically select control text when it receives focus.")]
|
|
public bool AutoSelect
|
|
{
|
|
get { return _autoSelect; }
|
|
set { _autoSelect = value; }
|
|
}
|
|
|
|
private bool _autoSelect;
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public int SelectionStart
|
|
{
|
|
get { return _textbox.SelectionStart; }
|
|
set { _textbox.SelectionStart = value; }
|
|
}
|
|
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public int SelectionLength
|
|
{
|
|
get { return _textbox.SelectionLength; }
|
|
set { _textbox.SelectionLength = value; }
|
|
}
|
|
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public string SelectedText
|
|
{
|
|
get { return _textbox.SelectedText; }
|
|
set { _textbox.SelectedText = value; }
|
|
}
|
|
|
|
|
|
[DefaultValue(typeof(InterceptMouseWheelMode), "Always")]
|
|
[Category("Behavior")]
|
|
[Description("Enables MouseWheel only under certain conditions.")]
|
|
public InterceptMouseWheelMode InterceptMouseWheel
|
|
{
|
|
get { return _interceptMouseWheel; }
|
|
set { _interceptMouseWheel = value; }
|
|
}
|
|
|
|
private InterceptMouseWheelMode _interceptMouseWheel = InterceptMouseWheelMode.Always;
|
|
|
|
public enum InterceptMouseWheelMode
|
|
{
|
|
/// <summary>MouseWheel always works (defauld behavior)</summary>
|
|
Always,
|
|
/// <summary>MouseWheel works only when mouse is over the (focused) control</summary>
|
|
WhenMouseOver,
|
|
/// <summary>MouseWheel never works</summary>
|
|
Never
|
|
}
|
|
|
|
|
|
[DefaultValue(typeof(ShowUpDownButtonsMode), "Always")]
|
|
[Category("Behavior")]
|
|
[Description("Set UpDownButtons visibility mode.")]
|
|
public ShowUpDownButtonsMode ShowUpDownButtons
|
|
{
|
|
get { return _showUpDownButtons; }
|
|
set
|
|
{
|
|
_showUpDownButtons = value;
|
|
// update UpDownButtons visibility
|
|
UpdateUpDownButtonsVisibility();
|
|
}
|
|
}
|
|
|
|
private ShowUpDownButtonsMode _showUpDownButtons = ShowUpDownButtonsMode.Always;
|
|
|
|
public enum ShowUpDownButtonsMode
|
|
{
|
|
/// <summary>UpDownButtons are always visible (defauld behavior)</summary>
|
|
Always,
|
|
/// <summary>UpDownButtons are visible only when mouse is over the control</summary>
|
|
WhenMouseOver
|
|
}
|
|
|
|
/// <summary>
|
|
/// If set, incrementing value will cause it to restart from Minimum
|
|
/// when Maximum is reached (and viceversa).
|
|
/// </summary>
|
|
[DefaultValue(false)]
|
|
[Category("Behavior")]
|
|
[Description("If set, incrementing value will cause it to restart from Minimum when Maximum is reached (and viceversa).")]
|
|
public bool WrapValue
|
|
{
|
|
get { return _wrapValue; }
|
|
set { _wrapValue = value; }
|
|
}
|
|
private bool _wrapValue;
|
|
|
|
#endregion
|
|
|
|
|
|
#region Text selection
|
|
|
|
// select all the text on focus enter
|
|
protected override void OnGotFocus(EventArgs e)
|
|
{
|
|
if(_autoSelect)
|
|
{
|
|
_textbox.SelectAll();
|
|
}
|
|
base.OnGotFocus(e);
|
|
}
|
|
|
|
|
|
// MouseUp will kill the SelectAll made on GotFocus.
|
|
// Will restore it, but only if user have not made a partial text selection.
|
|
protected override void OnMouseUp(MouseEventArgs mevent)
|
|
{
|
|
if(_autoSelect && _textbox.SelectionLength == 0)
|
|
{
|
|
_textbox.SelectAll();
|
|
}
|
|
base.OnMouseUp(mevent);
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Additional events
|
|
|
|
// these events will be raised correctly, when mouse enters on the textbox
|
|
public new event EventHandler<EventArgs> MouseEnter;
|
|
public new event EventHandler<EventArgs> MouseLeave;
|
|
|
|
// Events raised BEFORE value decrement(increment
|
|
public event CancelEventHandler BeforeValueDecrement;
|
|
public event CancelEventHandler BeforeValueIncrement;
|
|
|
|
// flag to track mouse position
|
|
private bool _mouseOver;
|
|
|
|
// this handler is called at each mouse Enter/Leave movement
|
|
private void _mouseEnterLeave(object sender, EventArgs e)
|
|
{
|
|
Rectangle cr = RectangleToScreen(ClientRectangle);
|
|
Point mp = MousePosition;
|
|
|
|
// actual state
|
|
bool isOver = cr.Contains(mp);
|
|
|
|
// test if status changed
|
|
if(_mouseOver ^ isOver)
|
|
{
|
|
// update state
|
|
_mouseOver = isOver;
|
|
if(_mouseOver)
|
|
{
|
|
if(MouseEnter != null)
|
|
{
|
|
MouseEnter(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(MouseLeave != null)
|
|
{
|
|
MouseLeave(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update UpDownButtons visibility
|
|
if(_showUpDownButtons != ShowUpDownButtonsMode.Always)
|
|
{
|
|
UpdateUpDownButtonsVisibility();
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Value increment/decrement management
|
|
|
|
// raises the two new events
|
|
public override void DownButton()
|
|
{
|
|
CancelEventArgs e = new CancelEventArgs();
|
|
if(BeforeValueDecrement != null)
|
|
{
|
|
BeforeValueDecrement(this, e);
|
|
}
|
|
if(e.Cancel) return;
|
|
|
|
if(_wrapValue && Value - Increment < Minimum)
|
|
{
|
|
Value = Maximum;
|
|
}
|
|
else
|
|
{
|
|
base.DownButton();
|
|
}
|
|
}
|
|
public override void UpButton()
|
|
{
|
|
CancelEventArgs e = new CancelEventArgs();
|
|
if(BeforeValueIncrement != null)
|
|
{
|
|
BeforeValueIncrement(this, e);
|
|
}
|
|
if(e.Cancel) return;
|
|
|
|
if(_wrapValue && Value + Increment > Maximum)
|
|
{
|
|
Value = Minimum;
|
|
}
|
|
else
|
|
{
|
|
base.UpButton();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region UpDownButtons visibility management
|
|
|
|
/// <summary>
|
|
/// Show or hide the UpDownButtons, according to ShowUpDownButtons property value
|
|
/// </summary>
|
|
public void UpdateUpDownButtonsVisibility()
|
|
{
|
|
// test new state
|
|
bool newVisible;
|
|
switch(_showUpDownButtons)
|
|
{
|
|
case ShowUpDownButtonsMode.WhenMouseOver:
|
|
newVisible = _mouseOver;
|
|
break;
|
|
default:
|
|
newVisible = true;
|
|
break;
|
|
}
|
|
|
|
// assign only if needed
|
|
if(_upDownButtons.Visible != newVisible)
|
|
{
|
|
if(newVisible)
|
|
{
|
|
_textbox.Width = this.ClientRectangle.Width - _upDownButtons.Width;
|
|
}
|
|
else
|
|
{
|
|
_textbox.Width = this.ClientRectangle.Width;
|
|
}
|
|
_upDownButtons.Visible = newVisible;
|
|
OnTextBoxResize(_textbox, EventArgs.Empty);
|
|
this.Invalidate();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Custom textbox size management
|
|
/// </summary>
|
|
protected override void OnTextBoxResize(object source, EventArgs e)
|
|
{
|
|
if(_textbox == null)
|
|
return;
|
|
if(_showUpDownButtons == ShowUpDownButtonsMode.Always)
|
|
{
|
|
// standard management
|
|
base.OnTextBoxResize(source, e);
|
|
}
|
|
else
|
|
{
|
|
// custom management
|
|
|
|
// change position if RTL
|
|
bool fixPos = this.RightToLeft == RightToLeft.Yes ^ this.UpDownAlign == LeftRightAlignment.Left;
|
|
|
|
if(_mouseOver)
|
|
{
|
|
_textbox.Width = this.ClientSize.Width - _textbox.Left - _upDownButtons.Width - 2;
|
|
if(fixPos)
|
|
_textbox.Location = new Point(16, _textbox.Location.Y);
|
|
}
|
|
else
|
|
{
|
|
if(fixPos)
|
|
_textbox.Location = new Point(2, _textbox.Location.Y);
|
|
_textbox.Width = this.ClientSize.Width - _textbox.Left - 2;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|