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) 2007 Novell, Inc. (http://www.novell.com)
23 // Rolf Bjarne Kvinge <RKvinge@novell.com>
31 0 Digit, required. This element will accept any single digit between 0 and 9.
32 9 Digit or space, optional.
33 # Digit or space, optional. If this position is blank in the mask, it will be rendered as a space in the Text property. Plus (+) and minus (-) signs are allowed.
34 L Letter, required. Restricts input to the ASCII letters a-z and A-Z. This mask element is equivalent to [a-zA-Z] in regular expressions.
35 ? Letter, optional. Restricts input to the ASCII letters a-z and A-Z. This mask element is equivalent to [a-zA-Z]? in regular expressions.
36 & Character, required. If the AsciiOnly property is set to true, this element behaves like the "L" element.
37 C Character, optional. Any non-control character. If the AsciiOnly property is set to true, this element behaves like the "?" element.
38 * LAMESPEC: A is REQUIRED, not optional.
39 A Alphanumeric, optional. If the AsciiOnly property is set to true, the only characters it will accept are the ASCII letters a-z and A-Z.
40 a Alphanumeric, optional. If the AsciiOnly property is set to true, the only characters it will accept are the ASCII letters a-z and A-Z.
41 . Decimal placeholder. The actual display character used will be the decimal symbol appropriate to the format provider, as determined by the control's FormatProvider property.
42 , Thousands placeholder. The actual display character used will be the thousands placeholder appropriate to the format provider, as determined by the control's FormatProvider property.
43 : Time separator. The actual display character used will be the time symbol appropriate to the format provider, as determined by the control's FormatProvider property.
44 / Date separator. The actual display character used will be the date symbol appropriate to the format provider, as determined by the control's FormatProvider property.
45 $ Currency symbol. The actual character displayed will be the currency symbol appropriate to the format provider, as determined by the control's FormatProvider property.
46 < Shift down. Converts all characters that follow to lowercase.
47 > Shift up. Converts all characters that follow to uppercase.
48 | Disable a previous shift up or shift down.
49 \ Escape. Escapes a mask character, turning it into a literal. "\\" is the escape sequence for a backslash.
53 using System.Globalization;
54 using System.Collections;
55 using System.Diagnostics;
58 namespace System.ComponentModel {
59 public class MaskedTextProvider : ICloneable
61 #region Private fields
62 private bool allow_prompt_as_input;
63 private bool ascii_only;
64 private CultureInfo culture;
65 private bool include_literals;
66 private bool include_prompt;
67 private bool is_password;
69 private char password_char;
70 private char prompt_char;
71 private bool reset_on_prompt;
72 private bool reset_on_space;
73 private bool skip_literals;
75 private EditPosition [] edit_positions;
77 private static char default_prompt_char = '_';
78 private static char default_password_char = char.MinValue;
82 #region Private classes
83 private enum EditState {
88 private enum EditType {
90 DigitOrSpaceOptional, // 9
91 DigitOrSpaceOptional_Blank, // #
94 CharacterRequired, // &
95 CharacterOptional, // C
96 AlphanumericRequired, // A
97 AlphanumericOptional, // a
98 DecimalPlaceholder, // .
99 ThousandsPlaceholder, // ,
106 private class EditPosition {
107 public MaskedTextProvider Parent;
108 public EditType Type;
109 public EditState State;
110 public char MaskCharacter;
115 input = char.MinValue;
118 internal EditPosition Clone () {
119 EditPosition result = new EditPosition ();
120 result.Parent = Parent;
122 result.State = State;
123 result.MaskCharacter = MaskCharacter;
124 result.input = input;
134 case EditState.LowerCase:
135 input = char.ToLower (value, Parent.Culture);
137 case EditState.UpperCase:
138 input = char.ToUpper (value, Parent.Culture);
140 default:// case EditState.None:
147 public bool IsAscii (char c)
149 return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
152 public bool Match (char c, out MaskedTextResultHint resultHint, bool only_test)
154 if (!MaskedTextProvider.IsValidInputChar (c)) {
155 resultHint = MaskedTextResultHint.InvalidInput;
159 if (Parent.ResetOnSpace && c == ' ' && Editable) {
160 resultHint = MaskedTextResultHint.CharacterEscaped;
162 resultHint = MaskedTextResultHint.Success;
163 if (!only_test && input != ' ') {
165 case EditType.AlphanumericOptional:
166 case EditType.AlphanumericRequired:
167 case EditType.CharacterOptional:
168 case EditType.CharacterRequired:
172 Input = char.MinValue;
180 if (Type == EditType.Literal && MaskCharacter == c && Parent.SkipLiterals) {
181 resultHint = MaskedTextResultHint.Success;
186 resultHint = MaskedTextResultHint.NonEditPosition;
191 case EditType.AlphanumericOptional:
192 case EditType.AlphanumericRequired:
193 if (char.IsLetterOrDigit (c)) {
194 if (Parent.AsciiOnly && !IsAscii (c)) {
195 resultHint = MaskedTextResultHint.AsciiCharacterExpected;
201 resultHint = MaskedTextResultHint.Success;
205 resultHint = MaskedTextResultHint.AlphanumericCharacterExpected;
208 case EditType.CharacterOptional:
209 case EditType.CharacterRequired:
210 if (Parent.AsciiOnly && !IsAscii (c)) {
211 resultHint = MaskedTextResultHint.LetterExpected;
213 } else if (!char.IsControl (c)) {
217 resultHint = MaskedTextResultHint.Success;
220 resultHint = MaskedTextResultHint.LetterExpected;
223 case EditType.DigitOrSpaceOptional:
224 case EditType.DigitOrSpaceOptional_Blank:
225 if (char.IsDigit (c) || c == ' ') {
229 resultHint = MaskedTextResultHint.Success;
232 resultHint = MaskedTextResultHint.DigitExpected;
235 case EditType.DigitRequired:
236 if (char.IsDigit (c)) {
240 resultHint = MaskedTextResultHint.Success;
243 resultHint = MaskedTextResultHint.DigitExpected;
246 case EditType.LetterOptional:
247 case EditType.LetterRequired:
248 if (!char.IsLetter (c)) {
249 resultHint = MaskedTextResultHint.LetterExpected;
251 } else if (Parent.AsciiOnly && !IsAscii (c)) {
252 resultHint = MaskedTextResultHint.LetterExpected;
258 resultHint = MaskedTextResultHint.Success;
262 resultHint = MaskedTextResultHint.Unknown;
267 public bool FilledIn {
269 return Input != char.MinValue;
273 public bool Required {
275 switch (MaskCharacter) {
287 public bool Editable {
289 switch (MaskCharacter) {
306 public bool Visible {
308 switch (MaskCharacter) {
320 if (Type == EditType.Literal) {
321 return MaskCharacter.ToString ();
323 switch (MaskCharacter) {
324 case '.': return Parent.Culture.NumberFormat.NumberDecimalSeparator;
325 case ',': return Parent.Culture.NumberFormat.NumberGroupSeparator;
326 case ':': return Parent.Culture.DateTimeFormat.TimeSeparator;
327 case '/': return Parent.Culture.DateTimeFormat.DateSeparator;
328 case '$': return Parent.Culture.NumberFormat.CurrencySymbol;
330 return FilledIn ? Input.ToString () : Parent.PromptChar.ToString ();
335 private EditPosition ()
339 public EditPosition (MaskedTextProvider Parent, EditType Type, EditState State, char MaskCharacter)
342 this.Parent = Parent;
344 this.MaskCharacter = MaskCharacter;
350 #region Private methods & properties
351 private void SetMask (string mask)
353 if (mask == null || mask == string.Empty)
354 throw new ArgumentException ("The Mask value cannot be null or empty.\r\nParameter name: mask");
358 System.Collections.Generic.List <EditPosition> list = new System.Collections.Generic.List<EditPosition> (mask.Length);
360 EditState State = EditState.None;
361 bool escaped = false;
362 for (int i = 0; i < mask.Length; i++) {
364 list.Add (new EditPosition (this, EditType.Literal, State, mask [i]));
374 list.Add (new EditPosition (this, EditType.DigitRequired, State, mask [i]));
377 list.Add (new EditPosition (this, EditType.DigitOrSpaceOptional, State, mask [i]));
380 list.Add (new EditPosition (this, EditType.DigitOrSpaceOptional_Blank, State, mask [i]));
383 list.Add (new EditPosition (this, EditType.LetterRequired, State, mask [i]));
386 list.Add (new EditPosition (this, EditType.LetterOptional, State, mask [i]));
389 list.Add (new EditPosition (this, EditType.CharacterRequired, State, mask [i]));
392 list.Add (new EditPosition (this, EditType.CharacterOptional, State, mask [i]));
395 list.Add (new EditPosition (this, EditType.AlphanumericRequired, State, mask [i]));
398 list.Add (new EditPosition (this, EditType.AlphanumericOptional, State, mask [i]));
401 list.Add (new EditPosition (this, EditType.DecimalPlaceholder, State, mask [i]));
404 list.Add (new EditPosition (this, EditType.ThousandsPlaceholder, State, mask [i]));
407 list.Add (new EditPosition (this, EditType.TimeSeparator, State, mask [i]));
410 list.Add (new EditPosition (this, EditType.DateSeparator, State, mask [i]));
413 list.Add (new EditPosition (this, EditType.CurrencySymbol, State, mask [i]));
416 State = EditState.LowerCase;
419 State = EditState.UpperCase;
422 State = EditState.None;
425 list.Add (new EditPosition (this, EditType.Literal, State, mask [i]));
429 edit_positions = list.ToArray ();
432 private EditPosition [] ClonePositions ()
434 EditPosition [] result = new EditPosition [edit_positions.Length];
435 for (int i = 0; i < result.Length; i++) {
436 result [i] = edit_positions [i].Clone ();
441 private bool AddInternal (string str_input, out int testPosition, out MaskedTextResultHint resultHint, bool only_test)
443 EditPosition [] edit_positions;
446 edit_positions = ClonePositions ();
448 edit_positions = this.edit_positions;
451 if (str_input == null)
452 throw new ArgumentNullException ("input");
454 if (str_input.Length == 0) {
455 resultHint = MaskedTextResultHint.NoEffect;
456 testPosition = LastAssignedPosition + 1;
460 resultHint = MaskedTextResultHint.Unknown;
463 int next_position = LastAssignedPosition;
464 MaskedTextResultHint tmpResult = MaskedTextResultHint.Unknown;
466 if (next_position >= edit_positions.Length) {
467 testPosition = next_position;
468 resultHint = MaskedTextResultHint.UnavailableEditPosition;
472 for (int i = 0; i < str_input.Length; i++) {
473 char input = str_input [i];
475 testPosition = next_position;
477 if (tmpResult > resultHint) {
478 resultHint = tmpResult;
481 if (VerifyEscapeChar (input, next_position)) {
482 tmpResult = MaskedTextResultHint.CharacterEscaped;
486 next_position = FindEditPositionFrom (next_position, true);
487 testPosition = next_position;
489 if (next_position == InvalidIndex) {
490 testPosition = edit_positions.Length;
491 resultHint = MaskedTextResultHint.UnavailableEditPosition;
495 if (!IsValidInputChar (input)) {
496 testPosition = next_position;
497 resultHint = MaskedTextResultHint.InvalidInput;
501 if (!edit_positions [next_position].Match (input, out tmpResult, false)) {
502 testPosition = next_position;
503 resultHint = tmpResult;
508 if (tmpResult > resultHint) {
509 resultHint = tmpResult;
515 private bool AddInternal (char input, out int testPosition, out MaskedTextResultHint resultHint, bool check_available_positions_first, bool check_escape_char_first)
518 * check_available_positions_first: when adding a char, MS first seems to check if there are any available edit positions, then if there are any
519 * they will try to add the char (meaning that if you add a char matching a literal char in the mask with SkipLiterals and there are no
520 * more available edit positions, it will fail).
522 * check_escape_char_first: When adding a char, MS doesn't check for escape char, they directly search for the first edit position.
523 * When adding a string, they check first for escape char, then if not successful they find the first edit position.
529 new_position = LastAssignedPosition + 1;
531 if (check_available_positions_first) {
532 int tmp = new_position;
533 bool any_available = false;
534 while (tmp < edit_positions.Length) {
535 if (edit_positions [tmp].Editable) {
536 any_available = true;
541 if (!any_available) {
543 resultHint = MaskedTextResultHint.UnavailableEditPosition;
544 return GetOperationResultFromHint (resultHint);
548 if (check_escape_char_first) {
549 if (VerifyEscapeChar (input, new_position)) {
550 testPosition = new_position;
551 resultHint = MaskedTextResultHint.CharacterEscaped;
556 new_position = FindEditPositionFrom (new_position, true);
558 if (new_position > edit_positions.Length - 1 ||new_position == InvalidIndex) {
559 testPosition = new_position;
560 resultHint = MaskedTextResultHint.UnavailableEditPosition;
561 return GetOperationResultFromHint (resultHint);
564 if (!IsValidInputChar (input)) {
565 testPosition = new_position;
566 resultHint = MaskedTextResultHint.InvalidInput;
567 return GetOperationResultFromHint (resultHint);
570 if (!edit_positions [new_position].Match (input, out resultHint, false)) {
571 testPosition = new_position;
572 return GetOperationResultFromHint (resultHint);
575 testPosition = new_position;
577 return GetOperationResultFromHint (resultHint);
580 private bool VerifyStringInternal (string input, out int testPosition, out MaskedTextResultHint resultHint, int startIndex, bool only_test)
582 int previous_position = startIndex;
583 int current_position;
584 resultHint = MaskedTextResultHint.Unknown;
586 // Replace existing characters
587 for (int i = 0; i < input.Length; i++) {
588 MaskedTextResultHint tmpResult;
589 current_position = FindEditPositionFrom (previous_position, true);
590 if (current_position == InvalidIndex) {
591 testPosition = edit_positions.Length;
592 resultHint = MaskedTextResultHint.UnavailableEditPosition;
596 if (!VerifyCharInternal (input [i], current_position, out tmpResult, only_test)) {
597 testPosition = current_position;
598 resultHint = tmpResult;
601 if (tmpResult > resultHint) {
602 resultHint = tmpResult;
604 previous_position = current_position + 1;
607 // Remove characters not in the input.
609 previous_position = FindEditPositionFrom (previous_position, true);
610 while (previous_position != InvalidIndex) {
611 if (edit_positions [previous_position].FilledIn) {
612 edit_positions [previous_position].Reset ();
613 if (resultHint != MaskedTextResultHint.NoEffect) {
614 resultHint = MaskedTextResultHint.Success;
617 previous_position = FindEditPositionFrom (previous_position + 1, true);
620 if (input.Length > 0) {
621 testPosition = startIndex + input.Length - 1;
623 testPosition = startIndex;
624 if (resultHint < MaskedTextResultHint.NoEffect) {
625 resultHint = MaskedTextResultHint.NoEffect;
632 private bool VerifyCharInternal (char input, int position, out MaskedTextResultHint hint, bool only_test)
634 hint = MaskedTextResultHint.Unknown;
636 if (position < 0 || position >= edit_positions.Length) {
637 hint = MaskedTextResultHint.PositionOutOfRange;
641 if (!IsValidInputChar (input)) {
642 hint = MaskedTextResultHint.InvalidInput;
646 if (input == ' ' && ResetOnSpace && edit_positions [position].Editable && edit_positions [position].FilledIn) {
648 edit_positions [position].Reset ();
650 hint = MaskedTextResultHint.SideEffect;
654 if (edit_positions [position].Editable && edit_positions [position].FilledIn && edit_positions [position].input == input) {
655 hint = MaskedTextResultHint.NoEffect;
659 if (SkipLiterals && !edit_positions [position].Editable && edit_positions [position].Text == input.ToString ()) {
660 hint = MaskedTextResultHint.CharacterEscaped;
664 return edit_positions [position].Match (input, out hint, only_test);
667 // Test to see if the input string can be inserted at the specified position.
668 // Does not try to move characters.
669 private bool IsInsertableString (string str_input, int position, out int testPosition, out MaskedTextResultHint resultHint)
671 int current_position = position;
674 resultHint = MaskedTextResultHint.UnavailableEditPosition;
675 testPosition = InvalidIndex;
677 for (int i = 0; i < str_input.Length; i++) {
678 char ch = str_input [i];
680 test_position = FindEditPositionFrom (current_position, true);
682 if (test_position != InvalidIndex && VerifyEscapeChar (ch, test_position)) {
683 current_position = test_position + 1;
687 if (VerifyEscapeChar (ch, current_position)) {
688 current_position = current_position + 1;
693 if (test_position == InvalidIndex) {
694 resultHint = MaskedTextResultHint.UnavailableEditPosition;
695 testPosition = edit_positions.Length;
699 testPosition = test_position;
701 if (!edit_positions [test_position].Match (ch, out resultHint, true)) {
705 current_position = test_position + 1;
707 resultHint = MaskedTextResultHint.Success;
712 private bool ShiftPositionsRight (EditPosition [] edit_positions, int start, out int testPosition, out MaskedTextResultHint resultHint)
715 int last_assigned_index = FindAssignedEditPositionFrom (edit_positions.Length, false);
716 int endindex = FindUnassignedEditPositionFrom (last_assigned_index, true); // Find the first non-assigned edit position
718 testPosition = start;
719 resultHint = MaskedTextResultHint.Unknown;
721 if (endindex == InvalidIndex) {
722 // No more free edit positions.
723 testPosition = edit_positions.Length;
724 resultHint = MaskedTextResultHint.UnavailableEditPosition;
728 while (endindex > index) {
732 index_to_move = FindEditPositionFrom (endindex - 1, false);
733 char_to_assign = edit_positions [index_to_move].input;
735 if (char_to_assign == char.MinValue) {
736 edit_positions [endindex].input = char_to_assign;
738 if (!edit_positions [endindex].Match (char_to_assign, out resultHint, false)) {
739 testPosition = endindex;
743 endindex = index_to_move;
746 if (endindex != InvalidIndex) {
747 edit_positions [endindex].Reset ();
753 private bool ReplaceInternal (string input, int startPosition, int endPosition, out int testPosition, out MaskedTextResultHint resultHint, bool only_test, bool dont_remove_at_end)
755 EditPosition [] edit_positions;
756 resultHint = MaskedTextResultHint.Unknown;
759 edit_positions = ClonePositions ();
761 edit_positions = this.edit_positions;
765 throw new ArgumentNullException ("input");
767 if (endPosition >= edit_positions.Length) {
768 testPosition = endPosition;
769 resultHint = MaskedTextResultHint.PositionOutOfRange;
773 if (startPosition < 0) {
774 testPosition = startPosition;
775 resultHint = MaskedTextResultHint.PositionOutOfRange;
779 if (startPosition >= edit_positions.Length) {
780 testPosition = startPosition;
781 resultHint = MaskedTextResultHint.PositionOutOfRange;
785 if (startPosition > endPosition) {
786 testPosition = startPosition;
787 resultHint = MaskedTextResultHint.PositionOutOfRange;
792 if (input.Length == 0) {
793 return RemoveAtInternal (startPosition, endPosition, out testPosition, out resultHint, only_test);
796 int previous_position = startPosition;
797 int current_position = previous_position;
798 MaskedTextResultHint tmpResult = MaskedTextResultHint.Unknown;
799 testPosition = InvalidIndex;
801 for (int i = 0; i < input.Length; i++) {
802 char current_input = input [i];
804 current_position = previous_position;
806 if (VerifyEscapeChar (current_input, current_position)) {
807 if (edit_positions [current_position].FilledIn &&
808 edit_positions [current_position].Editable &&
809 (current_input == ' ' && ResetOnSpace) || (current_input == PromptChar && ResetOnPrompt)) {
810 edit_positions [current_position].Reset ();
811 tmpResult = MaskedTextResultHint.SideEffect;
813 tmpResult = MaskedTextResultHint.CharacterEscaped;
815 } else if (current_position < edit_positions.Length && !edit_positions [current_position].Editable && FindAssignedEditPositionInRange (current_position, endPosition, true) == InvalidIndex) {
816 // If replacing over a literal, the replacement character is INSERTED at the next
817 // available edit position. Weird, huh?
818 current_position = FindEditPositionFrom (current_position, true);
819 if (current_position == InvalidIndex) {
820 resultHint = MaskedTextResultHint.UnavailableEditPosition;
821 testPosition = edit_positions.Length;
824 if (!InsertAtInternal (current_input.ToString (), current_position, out testPosition, out tmpResult, only_test)) {
825 resultHint = tmpResult;
830 current_position = FindEditPositionFrom (current_position, true);
832 if (current_position == InvalidIndex) {
833 testPosition = edit_positions.Length;
834 resultHint = MaskedTextResultHint.UnavailableEditPosition;
838 if (!IsValidInputChar (current_input)) {
839 testPosition = current_position;
840 resultHint = MaskedTextResultHint.InvalidInput;
844 if (!ReplaceInternal (edit_positions, current_input, current_position, out testPosition, out tmpResult, false)) {
845 resultHint = tmpResult;
850 if (tmpResult > resultHint) {
851 resultHint = tmpResult;
854 previous_position = current_position + 1;
857 testPosition = current_position;
860 if (!dont_remove_at_end && previous_position <= endPosition) {
861 if (!RemoveAtInternal (previous_position, endPosition, out tmpPosition, out tmpResult, only_test)) {
862 testPosition = tmpPosition;
863 resultHint = tmpResult;
867 if (tmpResult == MaskedTextResultHint.Success && resultHint < MaskedTextResultHint.SideEffect) {
868 resultHint = MaskedTextResultHint.SideEffect;
874 private bool ReplaceInternal (EditPosition [] edit_positions, char input, int position, out int testPosition, out MaskedTextResultHint resultHint, bool only_test)
876 testPosition = position;
878 if (!IsValidInputChar (input)) {
879 resultHint = MaskedTextResultHint.InvalidInput;
883 if (VerifyEscapeChar (input, position)) {
884 if (edit_positions [position].FilledIn && edit_positions [position].Editable && (input == ' ' && ResetOnSpace) || (input == PromptChar && ResetOnPrompt)) {
885 edit_positions [position].Reset ();
886 resultHint = MaskedTextResultHint.SideEffect;
888 resultHint = MaskedTextResultHint.CharacterEscaped;
890 testPosition = position;
894 if (!edit_positions [position].Editable) {
895 resultHint = MaskedTextResultHint.NonEditPosition;
899 bool is_filled = edit_positions [position].FilledIn;
900 if (is_filled && edit_positions [position].input == input) {
901 if (VerifyEscapeChar (input, position)) {
902 resultHint = MaskedTextResultHint.CharacterEscaped;
904 resultHint = MaskedTextResultHint.NoEffect;
906 } else if (input == ' ' && this.ResetOnSpace) {
908 resultHint = MaskedTextResultHint.SideEffect;
909 edit_positions [position].Reset ();
911 resultHint = MaskedTextResultHint.CharacterEscaped;
914 } else if (VerifyEscapeChar (input, position)) {
915 resultHint = MaskedTextResultHint.SideEffect;
917 resultHint = MaskedTextResultHint.Success;
919 MaskedTextResultHint tmpResult;
920 if (!edit_positions [position].Match (input, out tmpResult, false)) {
921 resultHint = tmpResult;
928 private bool RemoveAtInternal (int startPosition, int endPosition, out int testPosition, out MaskedTextResultHint resultHint, bool only_testing)
930 EditPosition [] edit_positions;
932 resultHint = MaskedTextResultHint.Unknown;
935 edit_positions = ClonePositions ();
937 edit_positions = this.edit_positions;
940 if (endPosition < 0 || endPosition >= edit_positions.Length) {
941 testPosition = endPosition;
942 resultHint = MaskedTextResultHint.PositionOutOfRange;
946 if (startPosition < 0 || startPosition >= edit_positions.Length) {
947 testPosition = startPosition;
948 resultHint = MaskedTextResultHint.PositionOutOfRange;
953 if (startPosition > endPosition) {
954 testPosition = startPosition;
955 resultHint = MaskedTextResultHint.PositionOutOfRange;
958 int edit_positions_in_range = 0;
959 for (int i = startPosition; i <= endPosition; i++) {
960 if (edit_positions [i].Editable) {
961 edit_positions_in_range++;
965 if (edit_positions_in_range == 0) {
966 testPosition = startPosition;
967 resultHint = MaskedTextResultHint.NoEffect;
971 int current_edit_position = FindEditPositionFrom (startPosition, true);
972 while (current_edit_position != InvalidIndex) {
973 // Find the edit position that will reach the current position.
974 int next_index = FindEditPositionFrom (current_edit_position + 1, true);
975 for (int j = 1; j < edit_positions_in_range && next_index != InvalidIndex; j++) {
976 next_index = FindEditPositionFrom (next_index + 1, true);
979 if (next_index == InvalidIndex) {
980 if (edit_positions [current_edit_position].FilledIn) {
981 edit_positions [current_edit_position].Reset ();
982 resultHint = MaskedTextResultHint.Success;
984 if (resultHint < MaskedTextResultHint.NoEffect) {
985 resultHint = MaskedTextResultHint.NoEffect;
989 if (!edit_positions [next_index].FilledIn) {
990 if (edit_positions [current_edit_position].FilledIn) {
991 edit_positions [current_edit_position].Reset ();
992 resultHint = MaskedTextResultHint.Success;
994 if (resultHint < MaskedTextResultHint.NoEffect) {
995 resultHint = MaskedTextResultHint.NoEffect;
999 MaskedTextResultHint tmpResult = MaskedTextResultHint.Unknown;
1000 if (edit_positions [current_edit_position].FilledIn) {
1001 resultHint = MaskedTextResultHint.Success;
1002 } else if (resultHint < MaskedTextResultHint.SideEffect) {
1003 resultHint = MaskedTextResultHint.SideEffect;
1005 if (!edit_positions [current_edit_position].Match (edit_positions [next_index].input, out tmpResult, false)) {
1006 resultHint = tmpResult;
1007 testPosition = current_edit_position;
1011 edit_positions [next_index].Reset ();
1013 current_edit_position = FindEditPositionFrom (current_edit_position + 1, true);
1016 if (resultHint == MaskedTextResultHint.Unknown) {
1017 resultHint = MaskedTextResultHint.NoEffect;
1020 testPosition = startPosition;
1025 private bool InsertAtInternal (string str_input, int position, out int testPosition, out MaskedTextResultHint resultHint, bool only_testing)
1027 EditPosition [] edit_positions;
1029 resultHint = MaskedTextResultHint.Unknown;
1032 edit_positions = ClonePositions ();
1034 edit_positions = this.edit_positions;
1037 if (position < 0 || position >= edit_positions.Length) {
1039 resultHint = MaskedTextResultHint.PositionOutOfRange;
1043 if (!IsInsertableString (str_input, position, out testPosition, out resultHint)) {
1047 resultHint = MaskedTextResultHint.Unknown;
1049 int next_position = position;
1050 for (int i = 0; i < str_input.Length; i++) {
1051 char input = str_input [i];
1052 int index = FindEditPositionFrom (next_position, true); // Find the first edit position (here the input will go)
1053 int endindex = FindUnassignedEditPositionFrom (next_position, true); // Find the first non-assigned edit position
1054 bool escaped = false;
1056 if (VerifyEscapeChar (input, next_position)) {
1059 if (input.ToString () == edit_positions [next_position].Text) {
1060 if (FindAssignedEditPositionInRange (0, next_position - 1, true) != InvalidIndex && endindex == InvalidIndex) {
1061 resultHint = MaskedTextResultHint.UnavailableEditPosition;
1062 testPosition = edit_positions.Length;
1065 resultHint = MaskedTextResultHint.CharacterEscaped;
1066 testPosition = next_position;
1072 if (!escaped && index == InvalidIndex) {
1073 // No edit positions left at all in the string
1074 testPosition = edit_positions.Length;
1075 resultHint = MaskedTextResultHint.UnavailableEditPosition;
1079 if (index == InvalidIndex) {
1080 index = next_position;
1083 bool was_filled = edit_positions [index].FilledIn;
1084 bool shift = was_filled;
1086 if (!ShiftPositionsRight (edit_positions, index, out testPosition, out resultHint)) {
1091 testPosition = index;
1094 resultHint = MaskedTextResultHint.Success;
1095 } else if (!edit_positions [index].Editable && input.ToString () == edit_positions [index].Text) {
1096 resultHint = MaskedTextResultHint.CharacterEscaped;
1097 testPosition = next_position;
1099 int first_edit_position = FindEditPositionFrom (index, true);
1100 if (first_edit_position == InvalidIndex) {
1101 resultHint = MaskedTextResultHint.UnavailableEditPosition;
1102 testPosition = edit_positions.Length;
1106 resultHint = MaskedTextResultHint.CharacterEscaped;
1107 if (input.ToString () == edit_positions [next_position].Text) {
1108 testPosition = next_position;
1112 MaskedTextResultHint tmpResult;
1113 if (!edit_positions [index].Match (input, out tmpResult, false)) {
1114 resultHint = tmpResult;
1117 if (resultHint < tmpResult) {
1118 resultHint = tmpResult;
1121 next_position = index + 1;
1128 #region Public constructors
1129 static MaskedTextProvider()
1133 public MaskedTextProvider(string mask)
1134 : this (mask, null, true, default_prompt_char, default_password_char, false)
1138 public MaskedTextProvider (string mask, bool restrictToAscii)
1139 : this (mask, null, true, default_prompt_char, default_password_char, restrictToAscii)
1143 public MaskedTextProvider (string mask, CultureInfo culture)
1144 : this (mask, culture, true, default_prompt_char, default_password_char, false)
1148 public MaskedTextProvider (string mask, char passwordChar, bool allowPromptAsInput)
1149 : this (mask, null, allowPromptAsInput, default_prompt_char, passwordChar, false)
1153 public MaskedTextProvider (string mask, CultureInfo culture, bool restrictToAscii)
1154 : this (mask, culture, true, default_prompt_char, default_password_char, restrictToAscii)
1158 public MaskedTextProvider(string mask, CultureInfo culture, char passwordChar, bool allowPromptAsInput)
1159 : this (mask, culture, allowPromptAsInput, default_prompt_char, passwordChar, false)
1163 public MaskedTextProvider(string mask, CultureInfo culture, bool allowPromptAsInput, char promptChar, char passwordChar, bool restrictToAscii)
1167 if (culture == null)
1168 this.culture = Threading.Thread.CurrentThread.CurrentCulture;
1170 this.culture = culture;
1172 this.allow_prompt_as_input = allowPromptAsInput;
1174 this.PromptChar = promptChar;
1175 this.PasswordChar = passwordChar;
1176 this.ascii_only = restrictToAscii;
1178 include_literals = true;
1179 reset_on_prompt = true;
1180 reset_on_space = true;
1181 skip_literals = true;
1185 #region Public methods
1186 public bool Add(char input)
1189 MaskedTextResultHint resultHint;
1190 return Add (input, out testPosition, out resultHint);
1193 public bool Add (string input)
1196 MaskedTextResultHint resultHint;
1197 return Add (input, out testPosition, out resultHint);
1200 public bool Add (char input, out int testPosition, out MaskedTextResultHint resultHint)
1202 return AddInternal (input, out testPosition, out resultHint, true, false);
1205 public bool Add (string input, out int testPosition, out MaskedTextResultHint resultHint)
1209 result = AddInternal (input, out testPosition, out resultHint, true);
1212 result = AddInternal (input, out testPosition, out resultHint, false);
1218 public void Clear ()
1220 MaskedTextResultHint resultHint;
1221 Clear (out resultHint);
1224 public void Clear (out MaskedTextResultHint resultHint)
1226 resultHint = MaskedTextResultHint.NoEffect;
1227 for (int i = 0; i < edit_positions.Length; i++) {
1228 if (edit_positions [i].Editable && edit_positions [i].FilledIn) {
1229 edit_positions [i].Reset ();
1230 resultHint = MaskedTextResultHint.Success;
1235 public object Clone ()
1237 MaskedTextProvider result = new MaskedTextProvider (mask);
1239 result.allow_prompt_as_input = allow_prompt_as_input;
1240 result.ascii_only = ascii_only;
1241 result.culture = culture;
1242 result.edit_positions = ClonePositions ();
1243 result.include_literals = include_literals;
1244 result.include_prompt = include_prompt;
1245 result.is_password = is_password;
1247 result.password_char = password_char;
1248 result.prompt_char = prompt_char;
1249 result.reset_on_prompt = reset_on_prompt;
1250 result.reset_on_space = reset_on_space;
1251 result.skip_literals = skip_literals;
1256 public int FindAssignedEditPositionFrom (int position, bool direction)
1259 return FindAssignedEditPositionInRange (position, edit_positions.Length - 1, direction);
1261 return FindAssignedEditPositionInRange (0, position, direction);
1265 public int FindAssignedEditPositionInRange (int startPosition, int endPosition, bool direction)
1270 if (startPosition < 0)
1272 if (endPosition >= edit_positions.Length)
1273 endPosition = edit_positions.Length - 1;
1275 if (startPosition > endPosition)
1276 return InvalidIndex;
1278 step = direction ? 1 : -1;
1279 start = direction ? startPosition : endPosition;
1280 end = (direction ? endPosition: startPosition) + step;
1282 for (int i = start; i != end; i+=step) {
1283 if (edit_positions [i].Editable && edit_positions [i].FilledIn)
1286 return InvalidIndex;
1289 public int FindEditPositionFrom (int position, bool direction)
1292 return FindEditPositionInRange (position, edit_positions.Length - 1, direction);
1294 return FindEditPositionInRange (0, position, direction);
1298 public int FindEditPositionInRange (int startPosition, int endPosition, bool direction)
1303 if (startPosition < 0)
1305 if (endPosition >= edit_positions.Length)
1306 endPosition = edit_positions.Length - 1;
1308 if (startPosition > endPosition)
1309 return InvalidIndex;
1311 step = direction ? 1 : -1;
1312 start = direction ? startPosition : endPosition;
1313 end = (direction ? endPosition : startPosition) + step;
1315 for (int i = start; i != end; i += step) {
1316 if (edit_positions [i].Editable)
1319 return InvalidIndex;
1322 public int FindNonEditPositionFrom (int position, bool direction)
1325 return FindNonEditPositionInRange (position, edit_positions.Length - 1, direction);
1327 return FindNonEditPositionInRange (0, position, direction);
1331 public int FindNonEditPositionInRange (int startPosition, int endPosition, bool direction)
1336 if (startPosition < 0)
1338 if (endPosition >= edit_positions.Length)
1339 endPosition = edit_positions.Length - 1;
1341 if (startPosition > endPosition)
1342 return InvalidIndex;
1344 step = direction ? 1 : -1;
1345 start = direction ? startPosition : endPosition;
1346 end = (direction ? endPosition : startPosition) + step;
1348 for (int i = start; i != end; i += step) {
1349 if (!edit_positions [i].Editable)
1352 return InvalidIndex;
1355 public int FindUnassignedEditPositionFrom (int position, bool direction)
1358 return FindUnassignedEditPositionInRange (position, edit_positions.Length - 1, direction);
1360 return FindUnassignedEditPositionInRange (0, position, direction);
1364 public int FindUnassignedEditPositionInRange (int startPosition, int endPosition, bool direction)
1369 if (startPosition < 0)
1371 if (endPosition >= edit_positions.Length)
1372 endPosition = edit_positions.Length - 1;
1374 if (startPosition > endPosition)
1375 return InvalidIndex;
1377 step = direction ? 1 : -1;
1378 start = direction ? startPosition : endPosition;
1379 end = (direction ? endPosition : startPosition) + step;
1381 for (int i = start; i != end; i += step) {
1382 if (edit_positions [i].Editable && !edit_positions [i].FilledIn)
1385 return InvalidIndex;
1388 public static bool GetOperationResultFromHint (MaskedTextResultHint hint)
1390 return (hint == MaskedTextResultHint.CharacterEscaped ||
1391 hint == MaskedTextResultHint.NoEffect ||
1392 hint == MaskedTextResultHint.SideEffect ||
1393 hint == MaskedTextResultHint.Success);
1396 public bool InsertAt (char input, int position)
1399 MaskedTextResultHint resultHint;
1400 return InsertAt (input, position, out testPosition, out resultHint);
1403 public bool InsertAt (string input, int position)
1406 MaskedTextResultHint resultHint;
1407 return InsertAt (input, position, out testPosition, out resultHint);
1410 public bool InsertAt (char input, int position, out int testPosition, out MaskedTextResultHint resultHint)
1412 return InsertAt (input.ToString (), position, out testPosition, out resultHint);
1415 public bool InsertAt (string input, int position, out int testPosition, out MaskedTextResultHint resultHint)
1418 throw new ArgumentNullException ("input");
1420 if (position >= edit_positions.Length) {
1421 testPosition = position;
1422 resultHint = MaskedTextResultHint.PositionOutOfRange;
1426 if (input == string.Empty) {
1427 testPosition = position;
1428 resultHint = MaskedTextResultHint.NoEffect;
1434 result = InsertAtInternal (input, position, out testPosition, out resultHint, true);
1437 result = InsertAtInternal (input, position, out testPosition, out resultHint, false);
1443 public bool IsAvailablePosition (int position)
1445 if (position < 0 || position >= edit_positions.Length)
1448 return edit_positions [position].Editable && !edit_positions [position].FilledIn;
1451 public bool IsEditPosition (int position)
1453 if (position < 0 || position >= edit_positions.Length)
1456 return edit_positions [position].Editable;
1459 public static bool IsValidInputChar (char c)
1461 return char.IsLetterOrDigit (c) || char.IsPunctuation (c) || char.IsSymbol (c) || c == ' ';
1464 public static bool IsValidMaskChar (char c)
1466 return char.IsLetterOrDigit (c) || char.IsPunctuation (c) || char.IsSymbol (c) || c == ' ';
1469 public static bool IsValidPasswordChar (char c)
1471 return char.IsLetterOrDigit (c) || char.IsPunctuation (c) || char.IsSymbol (c) || c == ' ' || c == char.MinValue;
1474 public bool Remove ()
1477 MaskedTextResultHint resultHint;
1478 return Remove (out testPosition, out resultHint);
1481 public bool Remove (out int testPosition, out MaskedTextResultHint resultHint)
1483 if (LastAssignedPosition == InvalidIndex) {
1484 resultHint = MaskedTextResultHint.NoEffect;
1489 testPosition = LastAssignedPosition;
1490 resultHint = MaskedTextResultHint.Success;
1491 edit_positions [LastAssignedPosition].input = char.MinValue;
1496 public bool RemoveAt (int position)
1498 return RemoveAt (position, position);
1501 public bool RemoveAt (int startPosition, int endPosition)
1504 MaskedTextResultHint resultHint;
1505 return RemoveAt (startPosition, endPosition, out testPosition, out resultHint);
1508 public bool RemoveAt (int startPosition, int endPosition, out int testPosition, out MaskedTextResultHint resultHint)
1512 result = RemoveAtInternal (startPosition, endPosition, out testPosition, out resultHint, true);
1515 result = RemoveAtInternal (startPosition, endPosition, out testPosition, out resultHint, false);
1521 public bool Replace (char input, int position)
1524 MaskedTextResultHint resultHint;
1525 return Replace (input, position, out testPosition, out resultHint);
1528 public bool Replace (string input, int position)
1531 MaskedTextResultHint resultHint;
1532 return Replace (input, position, out testPosition, out resultHint);
1535 public bool Replace (char input, int position, out int testPosition, out MaskedTextResultHint resultHint)
1537 if (position < 0 || position >= edit_positions.Length) {
1538 testPosition = position;
1539 resultHint = MaskedTextResultHint.PositionOutOfRange;
1543 if (VerifyEscapeChar (input, position)) {
1544 if (edit_positions [position].FilledIn && edit_positions [position].Editable && (input == ' ' && ResetOnSpace) || (input == PromptChar && ResetOnPrompt)) {
1545 edit_positions [position].Reset ();
1546 resultHint = MaskedTextResultHint.SideEffect;
1548 resultHint = MaskedTextResultHint.CharacterEscaped;
1550 testPosition = position;
1554 int current_edit_position;
1555 current_edit_position = FindEditPositionFrom (position, true);
1557 if (current_edit_position == InvalidIndex) {
1558 testPosition = position;
1559 resultHint = MaskedTextResultHint.UnavailableEditPosition;
1563 if (!IsValidInputChar (input)) {
1564 testPosition = current_edit_position;
1565 resultHint = MaskedTextResultHint.InvalidInput;
1569 return ReplaceInternal (edit_positions, input, current_edit_position, out testPosition, out resultHint, false);
1572 public bool Replace (string input, int position, out int testPosition, out MaskedTextResultHint resultHint)
1575 throw new ArgumentNullException ("input");
1577 if (position < 0 || position >= edit_positions.Length) {
1578 testPosition = position;
1579 resultHint = MaskedTextResultHint.PositionOutOfRange;
1583 if (input.Length == 0) {
1584 return RemoveAt (position, position, out testPosition, out resultHint);
1589 result = ReplaceInternal (input, position, edit_positions.Length - 1, out testPosition, out resultHint, true, true);
1592 result = ReplaceInternal (input, position, edit_positions.Length - 1, out testPosition, out resultHint, false, true);
1598 public bool Replace (char input, int startPosition, int endPosition, out int testPosition, out MaskedTextResultHint resultHint)
1601 if (endPosition >= edit_positions.Length) {
1602 testPosition = endPosition;
1603 resultHint = MaskedTextResultHint.PositionOutOfRange;
1607 if (startPosition < 0) {
1608 testPosition = startPosition;
1609 resultHint = MaskedTextResultHint.PositionOutOfRange;
1613 if (startPosition > endPosition) {
1614 testPosition = startPosition;
1615 resultHint = MaskedTextResultHint.PositionOutOfRange;
1619 if (startPosition == endPosition) {
1620 return ReplaceInternal (edit_positions, input, startPosition, out testPosition, out resultHint, false);
1623 return Replace (input.ToString (), startPosition, endPosition, out testPosition, out resultHint);
1626 public bool Replace (string input, int startPosition, int endPosition, out int testPosition, out MaskedTextResultHint resultHint)
1630 result = ReplaceInternal (input, startPosition, endPosition, out testPosition, out resultHint, true, false);
1633 result = ReplaceInternal (input, startPosition, endPosition, out testPosition, out resultHint, false, false);
1638 public bool Set (string input)
1641 MaskedTextResultHint resultHint;
1642 return Set (input, out testPosition, out resultHint);
1645 public bool Set (string input, out int testPosition, out MaskedTextResultHint resultHint)
1649 if (input == null) {
1650 throw new ArgumentNullException ("input");
1653 result = VerifyStringInternal (input, out testPosition, out resultHint, 0, true);
1656 result = VerifyStringInternal (input, out testPosition, out resultHint, 0, false);
1662 public string ToDisplayString ()
1664 return ToString (false, true, true, 0, Length);
1667 public override string ToString ()
1669 return ToString (true, IncludePrompt, IncludeLiterals, 0, Length);
1672 public string ToString (bool ignorePasswordChar)
1674 return ToString (ignorePasswordChar, IncludePrompt, IncludeLiterals, 0, Length);
1677 public string ToString (bool includePrompt, bool includeLiterals)
1679 return ToString (true, includePrompt, includeLiterals, 0, Length);
1682 public string ToString (int startPosition, int length)
1684 return ToString (true, IncludePrompt, IncludeLiterals, startPosition, length);
1687 public string ToString (bool ignorePasswordChar, int startPosition, int length)
1689 return ToString (ignorePasswordChar, IncludePrompt, IncludeLiterals, startPosition, length);
1692 public string ToString (bool includePrompt, bool includeLiterals, int startPosition, int length)
1694 return ToString (true, includePrompt, includeLiterals, startPosition, length);
1697 public string ToString (bool ignorePasswordChar, bool includePrompt, bool includeLiterals, int startPosition, int length)
1699 if (startPosition < 0)
1703 return string.Empty;
1705 StringBuilder result = new StringBuilder ();
1706 int start = startPosition;
1707 int end = startPosition + length - 1;
1709 if (end >= edit_positions.Length) {
1710 end = edit_positions.Length - 1;
1712 int last_assigned_position = FindAssignedEditPositionInRange (start, end, false);
1714 // Find the last position in the mask to check for
1715 if (!includePrompt) {
1716 int last_non_edit_position;
1718 last_non_edit_position = FindNonEditPositionInRange (start, end, false);
1720 if (includeLiterals) {
1721 end = last_assigned_position > last_non_edit_position ? last_assigned_position : last_non_edit_position;
1723 end = last_assigned_position;
1727 for (int i = start; i <= end; i++) {
1728 EditPosition ed = edit_positions [i];
1730 if (ed.Type == EditType.Literal) {
1731 if (includeLiterals) {
1732 result.Append (ed.Text);
1734 } else if (ed.Editable) {
1736 if (!ed.FilledIn) { // Nothing to hide or show.
1738 result.Append (PromptChar);
1740 result.Append (" ");
1741 } else if (ignorePasswordChar)
1742 result.Append (ed.Input);
1744 result.Append (PasswordChar);
1745 } else if (!ed.FilledIn) {
1746 if (includePrompt) {
1747 result.Append (PromptChar);
1748 } else if (includeLiterals) {
1749 result.Append (" ");
1750 } else if (last_assigned_position != InvalidIndex && last_assigned_position > i) {
1751 result.Append (" ");
1754 result.Append (ed.Text);
1757 if (includeLiterals)
1758 result.Append (ed.Text);
1762 return result.ToString ();
1765 public bool VerifyChar (char input, int position, out MaskedTextResultHint hint)
1767 return VerifyCharInternal (input, position, out hint, true);
1770 public bool VerifyEscapeChar (char input, int position)
1772 if (position >= edit_positions.Length || position < 0) {
1776 if (!edit_positions [position].Editable) {
1778 return input.ToString () == edit_positions [position].Text;
1784 if (ResetOnSpace && input == ' ') {
1786 } else if (ResetOnPrompt && input == PromptChar) {
1793 public bool VerifyString (string input)
1796 MaskedTextResultHint resultHint;
1797 return VerifyString (input, out testPosition, out resultHint);
1800 public bool VerifyString (string input, out int testPosition, out MaskedTextResultHint resultHint)
1802 if (input == null || input.Length == 0) {
1804 resultHint = MaskedTextResultHint.NoEffect;
1808 return VerifyStringInternal (input, out testPosition, out resultHint, 0, true);
1812 #region Public properties
1813 public bool AllowPromptAsInput {
1815 return allow_prompt_as_input;
1819 public bool AsciiOnly {
1825 public int AssignedEditPositionCount {
1828 for (int i = 0; i < edit_positions.Length; i++) {
1829 if (edit_positions [i].FilledIn) {
1837 public int AvailableEditPositionCount {
1840 foreach (EditPosition edit in edit_positions) {
1841 if (!edit.FilledIn && edit.Editable) {
1849 public CultureInfo Culture {
1855 public static char DefaultPasswordChar {
1861 public int EditPositionCount {
1864 foreach (EditPosition edit in edit_positions) {
1865 if (edit.Editable) {
1874 public IEnumerator EditPositions {
1876 System.Collections.Generic.List <int> result = new System.Collections.Generic.List<int> ();
1877 for (int i = 0; i < edit_positions.Length; i++) {
1878 if (edit_positions [i].Editable) {
1882 return result.GetEnumerator ();
1886 public bool IncludeLiterals {
1888 return include_literals;
1891 include_literals = value;
1895 public bool IncludePrompt {
1897 return include_prompt;
1900 include_prompt = value;
1904 public static int InvalidIndex {
1910 public bool IsPassword {
1912 return password_char != char.MinValue;
1915 password_char = value ? DefaultPasswordChar : char.MinValue;
1919 public char this [int index] {
1921 if (index < 0 || index >= Length) {
1922 throw new IndexOutOfRangeException (index.ToString ());
1925 return ToString (true, true, true, 0, edit_positions.Length) [index];
1929 public int LastAssignedPosition {
1931 return FindAssignedEditPositionFrom (edit_positions.Length - 1, false);
1938 for (int i = 0; i < edit_positions.Length; i++) {
1939 if (edit_positions [i].Visible)
1946 public string Mask {
1952 public bool MaskCompleted {
1954 for (int i = 0; i < edit_positions.Length; i++)
1955 if (edit_positions [i].Required && !edit_positions [i].FilledIn)
1961 public bool MaskFull {
1963 for (int i = 0; i < edit_positions.Length; i++)
1964 if (edit_positions [i].Editable && !edit_positions [i].FilledIn)
1970 public char PasswordChar {
1972 return password_char;
1975 password_char = value;
1979 public char PromptChar {
1984 prompt_char = value;
1988 public bool ResetOnPrompt {
1990 return reset_on_prompt;
1993 reset_on_prompt = value;
1997 public bool ResetOnSpace {
1999 return reset_on_space;
2002 reset_on_space = value;
2006 public bool SkipLiterals {
2008 return skip_literals;
2011 skip_literals = value;