Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

456 lines
11 KiB
C#

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright (c) 2005 Novell, Inc.
//
// Authors:
// Jonathan Gilbert <logic@deltaq.org>
//
// Integration into MWF:
// Peter Bartok <pbartok@novell.com>
//
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace System.Windows.Forms {
[DefaultEvent("ValueChanged")]
[DefaultProperty("Value")]
[DefaultBindingProperty ("Value")]
[ClassInterface (ClassInterfaceType.AutoDispatch)]
[ComVisible (true)]
public class NumericUpDown : UpDownBase, ISupportInitialize {
#region Local Variables
private bool suppress_validation;
private int decimal_places;
private bool hexadecimal;
private decimal increment;
private decimal maximum;
private decimal minimum;
private bool thousands_separator;
private decimal dvalue;
NumericUpDownAccelerationCollection accelerations;
// private long buttonPressedTicks;
//private bool isSpinning;
#endregion // Local Variables
#region UIA FrameWork Events
static object UIAMinimumChangedEvent = new object ();
internal event EventHandler UIAMinimumChanged {
add { Events.AddHandler (UIAMinimumChangedEvent, value); }
remove { Events.RemoveHandler (UIAMinimumChangedEvent, value); }
}
internal void OnUIAMinimumChanged (EventArgs e)
{
EventHandler eh = (EventHandler) Events [UIAMinimumChangedEvent];
if (eh != null)
eh (this, e);
}
static object UIAMaximumChangedEvent = new object ();
internal event EventHandler UIAMaximumChanged {
add { Events.AddHandler (UIAMaximumChangedEvent, value); }
remove { Events.RemoveHandler (UIAMaximumChangedEvent, value); }
}
internal void OnUIAMaximumChanged (EventArgs e)
{
EventHandler eh = (EventHandler) Events [UIAMaximumChangedEvent];
if (eh != null)
eh (this, e);
}
static object UIASmallChangeChangedEvent = new object ();
internal event EventHandler UIASmallChangeChanged {
add { Events.AddHandler (UIASmallChangeChangedEvent, value); }
remove { Events.RemoveHandler (UIASmallChangeChangedEvent, value); }
}
internal void OnUIASmallChangeChanged (EventArgs e)
{
EventHandler eh = (EventHandler) Events [UIASmallChangeChangedEvent];
if (eh != null)
eh (this, e);
}
#endregion
#region Public Constructors
public NumericUpDown() {
suppress_validation = false;
decimal_places = 0;
hexadecimal = false;
increment = 1M;
maximum = 100M;
minimum = 0.0M;
thousands_separator = false;
Text = "0";
}
#endregion // Public Constructors
#region Public Instance Properties
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public NumericUpDownAccelerationCollection Accelerations {
get {
if (accelerations == null)
accelerations = new NumericUpDownAccelerationCollection ();
return accelerations;
}
}
[DefaultValue(0)]
public int DecimalPlaces {
get {
return decimal_places;
}
set {
decimal_places = value;
UpdateEditText();
}
}
[DefaultValue(false)]
public bool Hexadecimal {
get {
return hexadecimal;
}
set {
hexadecimal = value;
UpdateEditText();
}
}
public decimal Increment {
get {
return increment;
}
set {
if (value < 0) {
throw new ArgumentOutOfRangeException("value", value, "NumericUpDown increment cannot be negative");
}
increment = value;
// UIA Framework Event: SmallChange Changed
OnUIASmallChangeChanged (EventArgs.Empty);
}
}
[RefreshProperties(RefreshProperties.All)]
public decimal Maximum {
get {
return maximum;
}
set {
maximum = value;
if (minimum > maximum)
minimum = maximum;
if (dvalue > maximum)
Value = maximum;
// UIA Framework Event: Maximum Changed
OnUIAMaximumChanged (EventArgs.Empty);
}
}
[RefreshProperties(RefreshProperties.All)]
public decimal Minimum {
get {
return minimum;
}
set {
minimum = value;
if (maximum < minimum)
maximum = minimum;
if (dvalue < minimum)
Value = minimum;
// UIA Framework Event: Minimum Changed
OnUIAMinimumChanged (EventArgs.Empty);
}
}
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public new Padding Padding {
get { return Padding.Empty; }
set { }
}
[Bindable(false)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
}
}
[DefaultValue(false)]
[Localizable(true)]
public bool ThousandsSeparator {
get {
return thousands_separator;
}
set {
thousands_separator = value;
UpdateEditText();
}
}
[Bindable(true)]
public decimal Value {
get {
if (UserEdit)
ValidateEditText ();
return dvalue;
}
set {
if (value != dvalue) {
if (!suppress_validation && ((value < minimum) || (value > maximum))) {
throw new ArgumentOutOfRangeException ("value", "NumericUpDown.Value must be within the specified Minimum and Maximum values");
}
dvalue = value;
OnValueChanged (EventArgs.Empty);
UpdateEditText ();
}
}
}
#endregion // Public Instance Properties
#region Public Instance Methods
public void BeginInit() {
suppress_validation = true;
}
public void EndInit() {
suppress_validation = false;
Value = Check (dvalue);
UpdateEditText ();
}
public override string ToString() {
return string.Format("{0}, Minimum = {1}, Maximum = {2}", base.ToString(), minimum, maximum);
}
public override void DownButton() {
if (UserEdit) {
ParseEditText ();
}
Value = Math.Max (minimum, unchecked (dvalue - increment));
// UIA Framework Event: DownButton Click
OnUIADownButtonClick (EventArgs.Empty);
}
public override void UpButton() {
if (UserEdit) {
ParseEditText ();
}
Value = Math.Min (maximum, unchecked (dvalue + increment));
// UIA Framework Event: UpButton Click
OnUIAUpButtonClick (EventArgs.Empty);
}
#endregion // Public Instance Methods
#region Protected Instance Methods
protected override AccessibleObject CreateAccessibilityInstance() {
AccessibleObject acc;
acc = new AccessibleObject(this);
acc.role = AccessibleRole.SpinButton;
return acc;
}
protected override void OnTextBoxKeyPress(object source, KeyPressEventArgs e) {
if ((ModifierKeys & ~Keys.Shift) != Keys.None) {
return;
}
NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
string pressedKey = e.KeyChar.ToString ();
if ((pressedKey != nfi.NegativeSign) && (pressedKey != nfi.NumberDecimalSeparator) &&
(pressedKey != nfi.NumberGroupSeparator)) {
string acceptable = hexadecimal ? "\b0123456789abcdefABCDEF" : "\b0123456789";
if (acceptable.IndexOf (e.KeyChar) == -1) {
// FIXME: produce beep to signal that "invalid" key was pressed
// prevent the key from reaching the text box
e.Handled = true;
}
}
base.OnTextBoxKeyPress(source, e);
}
protected virtual void OnValueChanged(EventArgs e) {
EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
if (eh != null)
eh (this, e);
}
protected void ParseEditText () {
try {
if (!hexadecimal) {
Value = Check (decimal.Parse (Text, CultureInfo.CurrentCulture));
} else {
Value = Check (Convert.ToDecimal (Convert.ToInt32 (Text, 16)));
}
}
catch { }
finally {
UserEdit = false;
}
}
private decimal Check (decimal val)
{
decimal ret = val;
if (ret < minimum) {
ret = minimum;
}
if (ret > maximum) {
ret = maximum;
}
return ret;
}
protected override void UpdateEditText () {
if (suppress_validation)
return;
if (UserEdit)
ParseEditText ();
ChangingText = true;
if (!hexadecimal) {
// "N" and "F" differ only in that "N" includes commas
// every 3 digits to the left of the decimal and "F"
// does not.
string format_string;
if (thousands_separator) {
format_string = "N";
} else {
format_string = "F";
}
format_string += decimal_places;
Text = dvalue.ToString (format_string, CultureInfo.CurrentCulture);
} else {
// Cast to Int64 to be able to use the "X" formatter.
// If the value is below Int64.MinValue or above Int64.MaxValue,
// then an OverflowException will be thrown, as with .NET.
Text = ((Int64)dvalue).ToString("X", CultureInfo.CurrentCulture);
}
}
protected override void ValidateEditText() {
ParseEditText ();
UpdateEditText ();
}
protected override void OnLostFocus(EventArgs e) {
base.OnLostFocus(e);
if (UserEdit)
UpdateEditText();
}
protected override void OnKeyUp (KeyEventArgs e)
{
// isSpinning = false;
base.OnKeyUp (e);
}
protected override void OnKeyDown (KeyEventArgs e)
{
// buttonPressedTicks = DateTime.Now.Ticks;
// isSpinning = true;
base.OnKeyDown (e);
}
#endregion // Protected Instance Methods
#region Events
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
public new event EventHandler PaddingChanged {
add { base.PaddingChanged += value; }
remove { base.PaddingChanged -= value; }
}
static object ValueChangedEvent = new object ();
public event EventHandler ValueChanged {
add { Events.AddHandler (ValueChangedEvent, value); }
remove { Events.RemoveHandler (ValueChangedEvent, value); }
}
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public new event EventHandler TextChanged {
add { base.TextChanged += value; }
remove { base.TextChanged -= value; }
}
#endregion // Events
}
}