FieldControl.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // Copyright (c) 2007-2012 Michael Chapman
  2. // http://ipaddresscontrollib.googlecode.com
  3. // Permission is hereby granted, free of charge, to any person obtaining
  4. // a copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to
  8. // permit persons to whom the Software is furnished to do so, subject to
  9. // the following conditions:
  10. // The above copyright notice and this permission notice shall be
  11. // 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 NONINFRINGEMENT.
  15. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  16. // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  17. // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  18. // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. using System;
  20. using System.Drawing;
  21. using System.Globalization;
  22. using System.Windows.Forms;
  23. namespace IPAddressControlLib
  24. {
  25. internal class FieldControl : TextBox
  26. {
  27. #region Public Constants
  28. public const byte MinimumValue = 0;
  29. public const byte MaximumValue = 255;
  30. #endregion // Public Constants
  31. #region Public Events
  32. public event EventHandler<CedeFocusEventArgs> CedeFocusEvent;
  33. public event EventHandler<TextChangedEventArgs> TextChangedEvent;
  34. #endregion // Public Events
  35. #region Public Properties
  36. public bool Blank
  37. {
  38. get { return ( TextLength == 0 ); }
  39. }
  40. public int FieldIndex
  41. {
  42. get { return _fieldIndex; }
  43. set { _fieldIndex = value; }
  44. }
  45. public override Size MinimumSize
  46. {
  47. get
  48. {
  49. Graphics g = Graphics.FromHwnd( Handle );
  50. Size minimumSize = TextRenderer.MeasureText( g,
  51. Properties.Resources.FieldMeasureText, Font, Size,
  52. _textFormatFlags );
  53. g.Dispose();
  54. return minimumSize;
  55. }
  56. }
  57. public byte RangeLower
  58. {
  59. get { return _rangeLower; }
  60. set
  61. {
  62. if ( value < MinimumValue )
  63. {
  64. _rangeLower = MinimumValue;
  65. }
  66. else if ( value > _rangeUpper )
  67. {
  68. _rangeLower = _rangeUpper;
  69. }
  70. else
  71. {
  72. _rangeLower = value;
  73. }
  74. if ( Value < _rangeLower )
  75. {
  76. Text = _rangeLower.ToString( CultureInfo.InvariantCulture );
  77. }
  78. }
  79. }
  80. public byte RangeUpper
  81. {
  82. get { return _rangeUpper; }
  83. set
  84. {
  85. if ( value < _rangeLower )
  86. {
  87. _rangeUpper = _rangeLower;
  88. }
  89. else if ( value > MaximumValue )
  90. {
  91. _rangeUpper = MaximumValue;
  92. }
  93. else
  94. {
  95. _rangeUpper = value;
  96. }
  97. if ( Value > _rangeUpper )
  98. {
  99. Text = _rangeUpper.ToString( CultureInfo.InvariantCulture );
  100. }
  101. }
  102. }
  103. public byte Value
  104. {
  105. get
  106. {
  107. byte result;
  108. if ( !Byte.TryParse( Text, out result ) )
  109. {
  110. result = RangeLower;
  111. }
  112. return result;
  113. }
  114. }
  115. #endregion // Public Properties
  116. #region Public Methods
  117. public void TakeFocus( Action action )
  118. {
  119. Focus();
  120. switch ( action )
  121. {
  122. case Action.Trim:
  123. if ( TextLength > 0 )
  124. {
  125. int newLength = TextLength - 1;
  126. base.Text = Text.Substring( 0, newLength );
  127. }
  128. SelectionStart = TextLength;
  129. return;
  130. case Action.Home:
  131. SelectionStart = 0;
  132. SelectionLength = 0;
  133. return;
  134. case Action.End:
  135. SelectionStart = TextLength;
  136. return;
  137. }
  138. }
  139. public void TakeFocus( Direction direction, Selection selection )
  140. {
  141. Focus();
  142. if ( selection == Selection.All )
  143. {
  144. SelectionStart = 0;
  145. SelectionLength = TextLength;
  146. }
  147. else
  148. {
  149. SelectionStart = ( direction == Direction.Forward ) ? 0 : TextLength;
  150. }
  151. }
  152. public override string ToString()
  153. {
  154. return Value.ToString( CultureInfo.InvariantCulture );
  155. }
  156. #endregion // Public Methods
  157. #region Constructors
  158. public FieldControl()
  159. {
  160. BorderStyle = BorderStyle.None;
  161. MaxLength = 3;
  162. Size = MinimumSize;
  163. TabStop = false;
  164. TextAlign = HorizontalAlignment.Center;
  165. }
  166. #endregion //Constructors
  167. #region Protected Methods
  168. protected override void OnKeyDown( KeyEventArgs e )
  169. {
  170. if ( null == e ) { throw new ArgumentNullException( "e" ); }
  171. base.OnKeyDown( e );
  172. switch ( e.KeyCode )
  173. {
  174. case Keys.Home:
  175. SendCedeFocusEvent( Action.Home );
  176. return;
  177. case Keys.End:
  178. SendCedeFocusEvent( Action.End );
  179. return;
  180. }
  181. if ( IsCedeFocusKey( e ) )
  182. {
  183. SendCedeFocusEvent( Direction.Forward, Selection.All );
  184. e.SuppressKeyPress = true;
  185. return;
  186. }
  187. else if ( IsForwardKey( e ) )
  188. {
  189. if ( e.Control )
  190. {
  191. SendCedeFocusEvent( Direction.Forward, Selection.All );
  192. return;
  193. }
  194. else if ( SelectionLength == 0 && SelectionStart == TextLength )
  195. {
  196. SendCedeFocusEvent( Direction.Forward, Selection.None );
  197. return;
  198. }
  199. }
  200. else if ( IsReverseKey( e ) )
  201. {
  202. if ( e.Control )
  203. {
  204. SendCedeFocusEvent( Direction.Reverse, Selection.All );
  205. return;
  206. }
  207. else if ( SelectionLength == 0 && SelectionStart == 0 )
  208. {
  209. SendCedeFocusEvent( Direction.Reverse, Selection.None );
  210. return;
  211. }
  212. }
  213. else if ( IsBackspaceKey( e ) )
  214. {
  215. HandleBackspaceKey( e );
  216. }
  217. else if ( !IsNumericKey( e ) &&
  218. !IsEditKey( e ) &&
  219. !IsEnterKey( e ) )
  220. {
  221. e.SuppressKeyPress = true;
  222. }
  223. }
  224. protected override void OnParentBackColorChanged( EventArgs e )
  225. {
  226. base.OnParentBackColorChanged( e );
  227. BackColor = Parent.BackColor;
  228. }
  229. protected override void OnParentForeColorChanged( EventArgs e )
  230. {
  231. base.OnParentForeColorChanged( e );
  232. ForeColor = Parent.ForeColor;
  233. }
  234. protected override void OnSizeChanged( EventArgs e )
  235. {
  236. base.OnSizeChanged( e );
  237. Size = MinimumSize;
  238. }
  239. protected override void OnTextChanged( EventArgs e )
  240. {
  241. base.OnTextChanged( e );
  242. if ( !Blank )
  243. {
  244. int value;
  245. if ( !Int32.TryParse( Text, out value ) )
  246. {
  247. base.Text = String.Empty;
  248. }
  249. else
  250. {
  251. if ( value > RangeUpper )
  252. {
  253. base.Text = RangeUpper.ToString( CultureInfo.InvariantCulture );
  254. SelectionStart = 0;
  255. }
  256. else if ( ( TextLength == MaxLength ) && ( value < RangeLower ) )
  257. {
  258. base.Text = RangeLower.ToString( CultureInfo.InvariantCulture );
  259. SelectionStart = 0;
  260. }
  261. else
  262. {
  263. int originalLength = TextLength;
  264. int newSelectionStart = SelectionStart;
  265. base.Text = value.ToString( CultureInfo.InvariantCulture );
  266. if ( TextLength < originalLength )
  267. {
  268. newSelectionStart -= ( originalLength - TextLength );
  269. SelectionStart = Math.Max( 0, newSelectionStart );
  270. }
  271. }
  272. }
  273. }
  274. if ( null != TextChangedEvent )
  275. {
  276. TextChangedEventArgs args = new TextChangedEventArgs();
  277. args.FieldIndex = FieldIndex;
  278. args.Text = Text;
  279. TextChangedEvent( this, args );
  280. }
  281. if ( TextLength == MaxLength && Focused && SelectionStart == TextLength )
  282. {
  283. SendCedeFocusEvent( Direction.Forward, Selection.All );
  284. }
  285. }
  286. protected override void OnValidating( System.ComponentModel.CancelEventArgs e )
  287. {
  288. base.OnValidating( e );
  289. if ( !Blank )
  290. {
  291. if ( Value < RangeLower )
  292. {
  293. Text = RangeLower.ToString( CultureInfo.InvariantCulture );
  294. }
  295. }
  296. }
  297. protected override void WndProc( ref Message m )
  298. {
  299. switch ( m.Msg )
  300. {
  301. case 0x007b: // WM_CONTEXTMENU
  302. return;
  303. }
  304. base.WndProc( ref m );
  305. }
  306. #endregion // Protected Methods
  307. #region Private Methods
  308. private void HandleBackspaceKey( KeyEventArgs e )
  309. {
  310. if ( !ReadOnly && ( TextLength == 0 || ( SelectionStart == 0 && SelectionLength == 0 ) ) )
  311. {
  312. SendCedeFocusEvent( Action.Trim );
  313. e.SuppressKeyPress = true;
  314. }
  315. }
  316. private static bool IsBackspaceKey( KeyEventArgs e )
  317. {
  318. if ( e.KeyCode == Keys.Back )
  319. {
  320. return true;
  321. }
  322. return false;
  323. }
  324. private bool IsCedeFocusKey( KeyEventArgs e )
  325. {
  326. if ( e.KeyCode == Keys.OemPeriod ||
  327. e.KeyCode == Keys.Decimal ||
  328. e.KeyCode == Keys.Space )
  329. {
  330. if ( TextLength != 0 && SelectionLength == 0 && SelectionStart != 0 )
  331. {
  332. return true;
  333. }
  334. }
  335. return false;
  336. }
  337. private static bool IsEditKey( KeyEventArgs e )
  338. {
  339. if ( e.KeyCode == Keys.Back ||
  340. e.KeyCode == Keys.Delete )
  341. {
  342. return true;
  343. }
  344. else if ( e.Modifiers == Keys.Control &&
  345. ( e.KeyCode == Keys.C ||
  346. e.KeyCode == Keys.V ||
  347. e.KeyCode == Keys.X ) )
  348. {
  349. return true;
  350. }
  351. return false;
  352. }
  353. private static bool IsEnterKey( KeyEventArgs e )
  354. {
  355. if ( e.KeyCode == Keys.Enter ||
  356. e.KeyCode == Keys.Return )
  357. {
  358. return true;
  359. }
  360. return false;
  361. }
  362. private static bool IsForwardKey( KeyEventArgs e )
  363. {
  364. if ( e.KeyCode == Keys.Right ||
  365. e.KeyCode == Keys.Down )
  366. {
  367. return true;
  368. }
  369. return false;
  370. }
  371. private static bool IsNumericKey( KeyEventArgs e )
  372. {
  373. if ( e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9 )
  374. {
  375. if ( e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9 )
  376. {
  377. return false;
  378. }
  379. }
  380. return true;
  381. }
  382. private static bool IsReverseKey( KeyEventArgs e )
  383. {
  384. if ( e.KeyCode == Keys.Left ||
  385. e.KeyCode == Keys.Up )
  386. {
  387. return true;
  388. }
  389. return false;
  390. }
  391. private void SendCedeFocusEvent( Action action )
  392. {
  393. if ( null != CedeFocusEvent )
  394. {
  395. CedeFocusEventArgs args = new CedeFocusEventArgs();
  396. args.FieldIndex = FieldIndex;
  397. args.Action = action;
  398. CedeFocusEvent( this, args );
  399. }
  400. }
  401. private void SendCedeFocusEvent( Direction direction, Selection selection )
  402. {
  403. if ( null != CedeFocusEvent )
  404. {
  405. CedeFocusEventArgs args = new CedeFocusEventArgs();
  406. args.FieldIndex = FieldIndex;
  407. args.Action = Action.None;
  408. args.Direction = direction;
  409. args.Selection = selection;
  410. CedeFocusEvent( this, args );
  411. }
  412. }
  413. #endregion // Private Methods
  414. #region Private Data
  415. private int _fieldIndex = -1;
  416. private byte _rangeLower; // = MinimumValue; // this is removed for FxCop approval
  417. private byte _rangeUpper = MaximumValue;
  418. private TextFormatFlags _textFormatFlags = TextFormatFlags.HorizontalCenter |
  419. TextFormatFlags.SingleLine | TextFormatFlags.NoPadding;
  420. #endregion // Private Data
  421. }
  422. internal enum Direction
  423. {
  424. Forward,
  425. Reverse
  426. }
  427. internal enum Selection
  428. {
  429. None,
  430. All
  431. }
  432. internal enum Action
  433. {
  434. None,
  435. Trim,
  436. Home,
  437. End
  438. }
  439. internal class CedeFocusEventArgs : EventArgs
  440. {
  441. private int _fieldIndex;
  442. private Action _action;
  443. private Direction _direction;
  444. private Selection _selection;
  445. public int FieldIndex
  446. {
  447. get { return _fieldIndex; }
  448. set { _fieldIndex = value; }
  449. }
  450. public Action Action
  451. {
  452. get { return _action; }
  453. set { _action = value; }
  454. }
  455. public Direction Direction
  456. {
  457. get { return _direction; }
  458. set { _direction = value; }
  459. }
  460. public Selection Selection
  461. {
  462. get { return _selection; }
  463. set { _selection = value; }
  464. }
  465. }
  466. internal class TextChangedEventArgs : EventArgs
  467. {
  468. private int _fieldIndex;
  469. private String _text;
  470. public int FieldIndex
  471. {
  472. get { return _fieldIndex; }
  473. set { _fieldIndex = value; }
  474. }
  475. public String Text
  476. {
  477. get { return _text; }
  478. set { _text = value; }
  479. }
  480. }
  481. }