// Copyright (c) 2007 Michael Chapman
// 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.
using System;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;
namespace IPAddressControlLib
{
internal enum Direction
{
Forward,
Reverse
}
internal enum Selection
{
None,
All
}
internal enum Action
{
None,
Trim,
Home,
End
}
internal class CedeFocusEventArgs : EventArgs
{
private int _fieldIndex;
private Action _action;
private Direction _direction;
private Selection _selection;
public int FieldIndex
{
get { return _fieldIndex; }
set { _fieldIndex = value; }
}
public Action Action
{
get { return _action; }
set { _action = value; }
}
public Direction Direction
{
get { return _direction; }
set { _direction = value; }
}
public Selection Selection
{
get { return _selection; }
set { _selection = value; }
}
}
internal class TextChangedEventArgs : EventArgs
{
private int _fieldIndex;
private String _text;
public int FieldIndex
{
get { return _fieldIndex; }
set { _fieldIndex = value; }
}
public String Text
{
get { return _text; }
set { _text = value; }
}
}
internal class FieldControl : TextBox
{
#region Public Constants
public const byte MinimumValue = 0;
public const byte MaximumValue = 255;
#endregion // Public Constants
#region Public Events
public event EventHandler<CedeFocusEventArgs> CedeFocusEvent;
public event EventHandler<TextChangedEventArgs> TextChangedEvent;
#endregion // Public Events
#region Public Properties
public bool Blank
{
get { return ( TextLength == 0 ); }
}
public int FieldIndex
{
get { return _fieldIndex; }
set { _fieldIndex = value; }
}
public override Size MinimumSize
{
get
{
Graphics g = Graphics.FromHwnd( Handle );
Size minimumSize = TextRenderer.MeasureText( g,
Properties.Resources.FieldMeasureText, Font, Size,
_textFormatFlags );
g.Dispose();
return minimumSize;
}
}
public byte RangeLower
{
get { return _rangeLower; }
set
{
if ( value < MinimumValue )
{
_rangeLower = MinimumValue;
}
else if ( value > _rangeUpper )
{
_rangeLower = _rangeUpper;
}
else
{
_rangeLower = value;
}
if ( Value < _rangeLower )
{
Text = _rangeLower.ToString( CultureInfo.InvariantCulture );
}
}
}
public byte RangeUpper
{
get { return _rangeUpper; }
set
{
if ( value < _rangeLower )
{
_rangeUpper = _rangeLower;
}
else if ( value > MaximumValue )
{
_rangeUpper = MaximumValue;
}
else
{
_rangeUpper = value;
}
if ( Value > _rangeUpper )
{
Text = _rangeUpper.ToString( CultureInfo.InvariantCulture );
}
}
}
public byte Value
{
get
{
byte result;
if ( !Byte.TryParse( Text, out result ) )
{
result = RangeLower;
}
return result;
}
}
#endregion // Public Properties
#region Public Methods
public void TakeFocus( Action action )
{
Focus();
switch ( action )
{
case Action.Trim:
if ( TextLength > 0 )
{
int newLength = TextLength - 1;
base.Text = Text.Substring( 0, newLength );
}
SelectionStart = TextLength;
return;
case Action.Home:
SelectionStart = 0;
SelectionLength = 0;
return;
case Action.End:
SelectionStart = TextLength;
return;
}
}
public void TakeFocus( Direction direction, Selection selection )
{
Focus();
if ( selection == Selection.All )
{
SelectionStart = 0;
SelectionLength = TextLength;
}
else
{
SelectionStart = ( direction == Direction.Forward ) ? 0 : TextLength;
}
}
public override string ToString()
{
return Value.ToString( CultureInfo.InvariantCulture );
}
#endregion // Public Methods
#region Constructors
public FieldControl()
{
BorderStyle = BorderStyle.None;
MaxLength = 3;
Size = MinimumSize;
TabStop = false;
TextAlign = HorizontalAlignment.Center;
}
#endregion //Constructors
#region Protected Methods
protected override void OnKeyDown( KeyEventArgs e )
{
base.OnKeyDown( e );
switch ( e.KeyCode )
{
case Keys.Home:
SendCedeFocusEvent( Action.Home );
return;
case Keys.End:
SendCedeFocusEvent( Action.End );
return;
}
if ( IsCedeFocusKey( e ) )
{
SendCedeFocusEvent( Direction.Forward, Selection.All );
e.SuppressKeyPress = true;
return;
}
else if ( IsForwardKey( e ) )
{
if ( e.Control )
{
SendCedeFocusEvent( Direction.Forward, Selection.All );
return;
}
else if ( SelectionLength == 0 && SelectionStart == TextLength )
{
SendCedeFocusEvent( Direction.Forward, Selection.None );
return;
}
}
else if ( IsReverseKey( e ) )
{
if ( e.Control )
{
SendCedeFocusEvent( Direction.Reverse, Selection.All );
return;
}
else if ( SelectionLength == 0 && SelectionStart == 0 )
{
SendCedeFocusEvent( Direction.Reverse, Selection.None );
return;
}
}
else if ( IsBackspaceKey( e ) )
{
HandleBackspaceKey( e );
}
else if ( !IsNumericKey( e ) &&
!IsEditKey( e ) &&
!IsEnterKey( e ) )
{
e.SuppressKeyPress = true;
}
}
protected override void OnParentBackColorChanged( EventArgs e )
{
base.OnParentBackColorChanged( e );
BackColor = Parent.BackColor;
}
protected override void OnParentForeColorChanged( EventArgs e )
{
base.OnParentForeColorChanged( e );
ForeColor = Parent.ForeColor;
}
protected override void OnSizeChanged( EventArgs e )
{
base.OnSizeChanged( e );
Size = MinimumSize;
}
protected override void OnTextChanged( EventArgs e )
{
base.OnTextChanged( e );
if ( !Blank )
{
int value;
if ( !Int32.TryParse( Text, out value ) )
{
base.Text = String.Empty;
}
else
{
if ( value > RangeUpper )
{
base.Text = RangeUpper.ToString( CultureInfo.InvariantCulture );
SelectionStart = 0;
}
else if ( ( TextLength == MaxLength ) && ( value < RangeLower ) )
{
base.Text = RangeLower.ToString( CultureInfo.InvariantCulture );
SelectionStart = 0;
}
else
{
int originalLength = TextLength;
int newSelectionStart = SelectionStart;
base.Text = value.ToString( CultureInfo.InvariantCulture );
if ( TextLength < originalLength )
{
newSelectionStart -= ( originalLength - TextLength );
SelectionStart = Math.Max( 0, newSelectionStart );
}
}
}
}
if ( null != TextChangedEvent )
{
TextChangedEventArgs args = new TextChangedEventArgs();
args.FieldIndex = FieldIndex;
args.Text = Text;
TextChangedEvent( this, args );
}
if ( TextLength == MaxLength && Focused && SelectionStart == TextLength )
{
SendCedeFocusEvent( Direction.Forward, Selection.All );
}
}
protected override void OnValidating( System.ComponentModel.CancelEventArgs e )
{
base.OnValidating( e );
if ( !Blank )
{
if ( Value < RangeLower )
{
Text = RangeLower.ToString( CultureInfo.InvariantCulture );
}
}
}
protected override void WndProc( ref Message m )
{
switch ( m.Msg )
{
case 0x007b: // WM_CONTEXTMENU
return;
}
base.WndProc( ref m );
}
#endregion // Protected Methods
#region Private Methods
private void HandleBackspaceKey( KeyEventArgs e )
{
if ( !ReadOnly && ( TextLength == 0 || ( SelectionStart == 0 && SelectionLength == 0 ) ) )
{
SendCedeFocusEvent( Action.Trim );
e.SuppressKeyPress = true;
}
}
private static bool IsBackspaceKey( KeyEventArgs e )
{
if ( e.KeyCode == Keys.Back )
{
return true;
}
return false;
}
private bool IsCedeFocusKey( KeyEventArgs e )
{
if ( e.KeyCode == Keys.OemPeriod ||
e.KeyCode == Keys.Decimal ||
e.KeyCode == Keys.Space )
{
if ( TextLength != 0 && SelectionLength == 0 && SelectionStart != 0 )
{
return true;
}
}
return false;
}
private static bool IsEditKey( KeyEventArgs e )
{
if ( e.KeyCode == Keys.Back ||
e.KeyCode == Keys.Delete )
{
return true;
}
else if ( e.Modifiers == Keys.Control &&
( e.KeyCode == Keys.C ||
e.KeyCode == Keys.V ||
e.KeyCode == Keys.X ) )
{
return true;
}
return false;
}
private static bool IsEnterKey( KeyEventArgs e )
{
if ( e.KeyCode == Keys.Enter ||
e.KeyCode == Keys.Return )
{
return true;
}
return false;
}
private static bool IsForwardKey( KeyEventArgs e )
{
if ( e.KeyCode == Keys.Right ||
e.KeyCode == Keys.Down )
{
return true;
}
return false;
}
private static bool IsNumericKey( KeyEventArgs e )
{
if ( e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9 )
{
if ( e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9 )
{
return false;
}
}
return true;
}
private static bool IsReverseKey( KeyEventArgs e )
{
if ( e.KeyCode == Keys.Left ||
e.KeyCode == Keys.Up )
{
return true;
}
return false;
}
private void SendCedeFocusEvent( Action action )
{
if ( null != CedeFocusEvent )
{
CedeFocusEventArgs args = new CedeFocusEventArgs();
args.FieldIndex = FieldIndex;
args.Action = action;
CedeFocusEvent( this, args );
}
}
private void SendCedeFocusEvent( Direction direction, Selection selection )
{
if ( null != CedeFocusEvent )
{
CedeFocusEventArgs args = new CedeFocusEventArgs();
args.FieldIndex = FieldIndex;
args.Action = Action.None;
args.Direction = direction;
args.Selection = selection;
CedeFocusEvent( this, args );
}
}
#endregion // Private Methods
#region Private Data
private int _fieldIndex = -1;
private byte _rangeLower; // = MinimumValue; // this is removed for FxCop approval
private byte _rangeUpper = MaximumValue;
private TextFormatFlags _textFormatFlags = TextFormatFlags.HorizontalCenter |
TextFormatFlags.SingleLine | TextFormatFlags.NoPadding;
#endregion // Private Data
}
}