Untitled
unknown
csharp
2 years ago
38 kB
12
Indexable
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using static Cleverence.CompactForms.MaskedEditText.Mask.Options;
using Characters = Cleverence.CompactForms.MaskedEditText.Mask.Options.Characters;
namespace Cleverence.CompactForms.MaskedEditText
{
#if __ANDROID__
[DebuggerDisplay("{" + nameof(MaskString) + "}")]
#endif
public sealed class Mask
{
#region Public Properties
/// <summary>
/// Characters for filling empty spaces in mask
/// </summary>
public char MaskEmptyChar
{
get
{
return _maskEmptyChar;
}
set
{
_maskEmptyChar = value;
}
}
private char _maskEmptyChar = '_';
/// <summary>
/// Keyboard type used for this mask
/// </summary>
public KeyboardType KeyboardType
{
get
{
return _keyboardType;
}
}
private KeyboardType _keyboardType = KeyboardType.None;
#endregion
#region Private Properties
private readonly MaskNode _head;
public string MaskString { get; private set; }
private readonly Options.MaskOptions _maskOptions;
#endregion
#region Miscelanious
/// <summary>
/// Class that contains enums for operations with mask
/// </summary>
public class Options
{
/// <summary>
/// Modes used for ValidateString function
/// </summary>
public enum Validation
{
/// <summary>
/// Must match mask's length
/// </summary>
MatchLength,
/// <summary>
/// Can't exceed length of a mask, but can be less
/// </summary>
SmallerOrEqualLength,
/// <summary>
/// Can exceed length of a mask, but can't be smaller
/// </summary>
BiggerOrEqualLength,
/// <summary>
/// Can be bigger or smaller than mask's length
/// </summary>
FreeLength
}
/// <summary>
/// Modes used for DecorateString function
/// </summary>
public enum DecorateOptions
{
/// <summary>
/// Decorates and filling missing places with empty spaces
/// </summary>
DecorateEmpty,
/// <summary>
/// Stops once reaches end of string
/// </summary>
KeepEmpty
}
/// <summary>
/// Modes used for special mask options
/// </summary>
[Flags]
public enum MaskOptions
{
/// <summary>
/// Default flag for initialization
/// </summary>
None = 0,
/// <summary>
/// Return empty string for ToString() in case if no data is entered
/// </summary>
HideMaskIfEmpty = 1 << 0,
/// <summary>
/// Replaces text on entering instead inserting
/// </summary>
ReplaceMode = 1 << 1,
/// <summary>
/// Removed characters are replaced with empty space instead of text being shifted left
/// </summary>
StaticMode = 1 << 2,
/// <summary>
/// Allows the mask to be expanded without limit
/// </summary>
Limitless = 1 << 3,
/// <summary>
/// Allows you to show an empty mask character for characters that do not have displayed characters
/// </summary>
DisplayMaskEmptyChar = 1 << 4,
/// <summary>
/// Allows you to ignore the position of the mask symbol when entering, which gives the effect of a "smart" mask that can determine whether the mask rules are satisfied with the current input
/// </summary>
IgnoreMaskCharPosition = 1 << 5,
}
/// <summary>
/// Modes used for Count method
/// </summary>
[Flags]
public enum Characters
{
None = 0,
/// <summary>
/// Decorators (hardcoded characters)
/// </summary>
Decorators = 1 << 0,
/// <summary>
/// Characters that users filled in
/// </summary>
Filled = 1 << 1,
/// <summary>
/// Characters that aren't filled by user
/// </summary>
Empty = 1 << 2,
/// <summary>
/// Overflowing characters (characters after the mask)
/// </summary>
Overflowing = 1 << 3,
/// <summary>
/// Overriden characters (returns overriden instead of empty)
/// </summary>
Overriden = 1 << 4,
/// <summary>
/// The characters that must be displayed
/// </summary>
ReqiredDisplayCharacter = 1 << 5,
/// <summary>
/// All characters
/// </summary>
All = Decorators | Filled | Empty | Overflowing | Overriden | ReqiredDisplayCharacter
}
}
/// <summary>
/// Convert mask into usable form from maskString
/// </summary>
/// <param name="maskString">String that contains mask</param>
/// <param name="options">Additional mask options</param>
public Mask(string maskString, INodeTypeProvider nodeTypeProvider, params Options.MaskOptions[] options)
{
MaskNode current = null;
bool screening = false;
List<char> debugString = new List<char>(maskString.Length);
foreach (char character in maskString)
{
debugString.Add(character);
if (character.Equals('\\'))
{
screening = true;
continue;
}
NodeType info = new NodeType(null, KeyboardType.None, true);
if (!screening)
info = nodeTypeProvider.GetCharInfo(character);
else
screening = false;
MaskNode node = new MaskNode()
{
Character = character,
PreviousNode = current,
Regex = info.RegEx,
IsHardcoded = string.IsNullOrEmpty(info.RegEx),
IsReqiredDisplayCharacter = info.IsReqiredDisplayCharacter,
};
if (info.Type > KeyboardType)
_keyboardType = info.Type;
_head = _head ?? node;
if (current != null) current.NextNode = node;
current = node;
}
_head = _head ?? new MaskNode();
if (options.Length > 0)
{
foreach (Options.MaskOptions option in options)
_maskOptions |= option;
}
else
{
_maskOptions = 0;
}
MaskString = new string(debugString.ToArray());
}
#endregion
#region Public methods
/// <summary>
/// Validate that testString matches this mask
/// </summary>
/// <param name="testString">String to test</param>
/// <param name="mode">Validation mode</param>
/// <param name="hasMask">If true - checks the message with the mask. Otherwise checks if the mask can be applied</param>
/// <param name="allowEmpty">Include empty spaces in validation</param>
/// <returns>True if string matches the mask</returns>
public bool ValidateString(string testString, Options.Validation mode, bool hasMask, bool allowEmpty)
{
if (_head == null)
{
switch (mode)
{
case Options.Validation.FreeLength:
case Options.Validation.SmallerOrEqualLength:
case Options.Validation.BiggerOrEqualLength:
return true;
case Options.Validation.MatchLength:
return false;
}
}
bool result = true;
if (testString.Length > 0)
ForEachNode((n, c) =>
{
Queue<char> characters = new Queue<char>(testString);
char testChar = characters.Dequeue();
if (n.IsHardcoded)
{
if (hasMask && testChar != n.Character)
{
c.Break();
result = false;
}
}
else
{
if (n.Regex != null && !Regex.Match(testChar.ToString(), n.Regex).Success)
{
if (!allowEmpty || !testChar.Equals(MaskEmptyChar))
{
c.Break();
result = false;
}
}
}
}, null);
if (!result) return false;
if (!mode.Equals(Options.Validation.FreeLength))
{
switch (mode)
{
case Options.Validation.SmallerOrEqualLength:
if (!(testString.Length <= Count(false)))
return false;
return true;
case Options.Validation.MatchLength:
if (testString.Length != Count(false))
return false;
return true;
case Options.Validation.BiggerOrEqualLength:
if (!(testString.Length >= Count(false))) return false;
return true;
default:
return false;
}
}
return true;
}
/// <summary>
/// Decorates string with the mask, putting the control characters at correct places
/// </summary>
/// <param name="input">Input string to be decorated</param>
/// <param name="mode">Decorating mode</param>
/// <returns>Decorated string with mask characters or same input in case of validation failure</returns>
public string DecorateString(string input, Options.DecorateOptions mode)
{
if (!ValidateString(input, Options.Validation.FreeLength, false, false)) return input;
string finalString = "";
bool fillEmptySpaces = mode.Equals(Options.DecorateOptions.DecorateEmpty);
MaskNode current = _head;
int inputStrIdx = 0;
if (current == null) return input;
do
{
char inputChar = MaskEmptyChar;
if (inputStrIdx < input.Length) inputChar = input[inputStrIdx];
else if (!fillEmptySpaces) break;
if (current.IsHardcoded)
{
finalString += current.Character;
continue;
}
finalString += inputChar;
inputStrIdx++;
} while ((current = current.NextNode) != null);
return finalString;
}
/// <summary>
/// Returns raw string without decorators
/// </summary>
/// <returns>String without decorations failure</returns>
public string GetRaw()
{
string @string = "";
ForEachNode((node, control) =>
{
if (!node.IsHardcoded && node.DisplayedCharacter != null)
@string += node.DisplayedCharacter;
}, null);
return @string;
}
/// <summary>
/// Gets the closest best position to put cursor at, based on the mask
/// </summary>
/// <param name="position">Current position to start searching from</param>
/// <param name="opposite">Go in backward direction</param>
/// <param name="minSteps">Minimum steps to take before stopping getting valid position</param>
/// <param name="allowAfterTail">Allow null character after tail to be included in GetValidSelection</param>
/// <returns>Best closest position for editing</returns>
public int GetValidSelection(int position, bool opposite, int minSteps, bool allowAfterTail)
{
MaskNode current = _head;
int validPos = position;
for (int i = 0; i < position; i++)
{
if (current.NextNode == null)
{
position = allowAfterTail ? i + 1 : i;
break;
}
current = current.NextNode;
}
if (!current.IsHardcoded)
{
if (minSteps == 0)
return position;
minSteps--;
}
if (opposite && current.PreviousNode != null)
{
while ((current = current.PreviousNode) != null)
{
if (position > 0) position--;
if (!current.IsHardcoded && (minSteps == 0 || current.PreviousNode == null))
{
validPos = position;
break;
}
if (minSteps > 0) minSteps--;
}
}
else if (opposite == false && current.NextNode != null)
{
while ((current = current.NextNode) != null)
{
position++;
if (!current.IsHardcoded && (minSteps == 0 || current.NextNode == null))
{
validPos = position;
break;
}
if (minSteps > 0) minSteps--;
}
if (minSteps > 0 && allowAfterTail && current == null) validPos = position + 1;
}
else
{
if (current != null && current.NextNode == null && allowAfterTail)
validPos = position + 1;
}
return Math.Max(0, Math.Min(Count(true), validPos));
}
/// <summary>
/// Fixes selection to return the position between hardcoded characters
/// </summary>
/// <param name="pos">Position of cursor</param>
/// <returns>Valid position of cursor</returns>
public int FixSelection(int pos)
{
MaskNode targetNode = GetNode(pos,false);
if (targetNode == null) return GetValidSelection(pos,false,0,true);
if (targetNode.IsHardcoded) {
if(targetNode.PreviousNode != null && !targetNode.PreviousNode.IsHardcoded) return pos;
}
return GetValidSelection(pos,false,0,true);
}
/// <summary>
/// Converts mask with data into string form
/// </summary>
/// <param name="showEmptyMask">Show empty mask</param>
/// <param name="characters">Characters which to display</param>
/// <returns>Filled string with data</returns>
public string ToString(bool? showEmptyMask, params Characters[] characters)
{
showEmptyMask = showEmptyMask ?? (_maskOptions & Options.MaskOptions.HideMaskIfEmpty) == 0;
Characters options = Characters.None;
foreach (var character in characters) options |= character;
string @string = "";
if (!showEmptyMask.Value && Count(Characters.Filled) == 0)
return string.Empty;
ForEachNode(n => ProcessNode(n, options, ref @string), null);
return @string;
}
char? GetCharacter(char? @char) {
return @char == '\0' ? null : @char;
}
void ProcessNode(MaskNode current, Characters options, ref string @string)
{
char? @char = null;
if (current.DisplayedCharacter == null && options.HasFlag(Characters.Empty))
{
if (current.OverrideCharacter != null && options.HasFlag(Characters.Overriden))
@char = current.OverrideCharacter;
else if (current.IsHardcoded && options.HasFlag(Characters.Decorators))
@char = current.Character;
else if (_maskOptions.HasFlag(Options.MaskOptions.DisplayMaskEmptyChar))
@char = MaskEmptyChar;
else
@char = ' ';
}
else if (current.DisplayedCharacter != null)
{
if ((options.HasFlag(Characters.Filled) && !current.IsTemporary)
|| (options.HasFlag(Characters.Overflowing) && current.IsTemporary))
@char = current.DisplayedCharacter;
}
@string += GetCharacter(@char);
}
public string ToString(params Characters[] characters)
{
return ToString(null, characters);
}
/// <summary>
/// Converts mask with data into string form
/// </summary>
/// <returns>Filled string with data</returns>
public override string ToString()
{
return ToString(Characters.All);
}
/// <summary>
/// Inserts string starting at start position
/// </summary>
/// <param name="string">String to insert</param>
/// <param name="start">Starting position</param>
/// <param name="shift">New cursor position</param>
/// <param name="createNewNodes">Create new nodes if needed</param>
public void Insert(string @string, int start, out int shift, bool? createNewNodes)
{
createNewNodes = createNewNodes ?? _maskOptions.HasFlag(Options.MaskOptions.Limitless);
if (_maskOptions.HasFlag(Options.MaskOptions.ReplaceMode))
{
InternalInsert(@string, start, out shift, createNewNodes.Value);
}
else if (_maskOptions.HasFlag(Options.MaskOptions.IgnoreMaskCharPosition))
{
InternalInsert2(@string, start, out shift, createNewNodes.Value);
}
else
{
string firstHalf = "";
string secondHalf = "";
int idx = 0;
shift = 0;
ForEachNode(n =>
{
if (idx < start && !n.IsHardcoded && n.DisplayedCharacter != null)
firstHalf += n.DisplayedCharacter;
else if (idx >= start && !n.IsHardcoded && n.DisplayedCharacter != null)
secondHalf += n.DisplayedCharacter;
idx++;
}, null);
int _;
InternalRemove(0, Count(true), out _);
InternalInsert(firstHalf + @string, 0, out shift, createNewNodes.Value);
InternalInsert(secondHalf, shift, out _, createNewNodes.Value);
}
}
/// <summary>
/// Inserts string starting at start position
/// </summary>
/// <param name="string">String to insert</param>
/// <param name="start">Starting position</param>
/// <param name="createNewNodes">Create new nodes if needed</param>
public void Insert(string @string, int start, bool? createNewNodes)
{
int _;
Insert(@string, start, out _, createNewNodes);
}
/// <summary>
/// Removes certain amount of characters from mask filled data
/// </summary>
/// <param name="start">Starting index</param>
/// <param name="count">Amount of characters to remove</param>
/// <param name="shift">New cursor position</param>
public void Remove(int start, int count, out int shift)
{
InternalRemove(start, count, out shift);
if (_maskOptions.HasFlag(Options.MaskOptions.StaticMode)) return;
string data = GetRaw();
int _;
InternalRemove(0, Count(true), out _);
InternalInsert(data, 0, out _, true);
}
/// <summary>
/// Removes certain amount of characters from mask filled data
/// </summary>
/// <param name="start">Starting index</param>
/// <param name="count">Amount of characters to remove</param>
public void Remove(int start, int count)
{
int _;
Remove(start, count, out _);
}
/// <summary>
/// Get size of the mask
/// </summary>
/// <param name="countTemporary">Include temporary (overflowing) symbols</param>
/// <returns>Size of the mask</returns>
public int Count(bool countTemporary)
{
Characters options = Characters.Filled | Characters.Decorators | Characters.Empty;
options |= countTemporary ? Characters.Overflowing : 0;
return Count(options);
}
/// <summary>
/// Get size of the data in mask by parameters
/// </summary>
/// <param name="options">Types of characters to count</param>
/// <returns></returns>
public int Count(Characters options)
{
int count = 0;
ForEachNode((n, c) => {
if ((options.HasFlag(Characters.Empty) && n.DisplayedCharacter == null && !n.IsHardcoded)
|| (options.HasFlag(Characters.Decorators) && n.IsHardcoded)
|| (options.HasFlag(Characters.Overflowing) && n.IsTemporary)
|| (options.HasFlag(Characters.Filled) && n.DisplayedCharacter != null)
|| (options.HasFlag(Characters.ReqiredDisplayCharacter) && !n.IsHardcoded && n.IsReqiredDisplayCharacter))
count++;
}, null);
return count;
}
/// <summary>
/// Makes mask display specific characters that are passed in newMask
/// </summary>
/// <param name="newMask">New mask to display. Empty will clear overrides</param>
public void OverrideMask(string newMask)
{
if (newMask.Length != Count(false)) return;
Queue<char> characters = new Queue<char>(newMask);
bool clearMask = characters.Count == 0;
ForEachNode(n => {
if (clearMask) n.OverrideCharacter = null;
else n.OverrideCharacter = characters.Dequeue();
}, null);
}
/// <summary>
/// Function to get the latest filled position. If it's decorator - then gives you position at the end of the decorators
/// </summary>
/// <returns>Latest filled position</returns>
public int GetMaxFilledLength()
{
int count = 0;
int lastDisplayedSymbolIdx = 0;
MaskNode node = null;
ForEachNode(n => {
if (n.DisplayedCharacter != null)
{
lastDisplayedSymbolIdx = count;
node = n;
}
count++;
}, null);
if ((node != null && node.NextNode != null && node.NextNode.IsHardcoded) || (node != null && node.IsHardcoded) || (_head != null && _head.IsHardcoded))
{
int idx = GetValidSelection(lastDisplayedSymbolIdx + 1, false, 0, true);
MaskNode potentialNode = GetNode(idx, false);
if (potentialNode != null && potentialNode.IsHardcoded && potentialNode.NextNode == null)
return lastDisplayedSymbolIdx + 1;
return idx;
}
if (Count(Characters.Filled) == 0)
return lastDisplayedSymbolIdx;
else
return lastDisplayedSymbolIdx + 1;
}
//public Android.Text.InputTypes GetKeyboardInputType(Android.Text.InputTypes inputType) => KeyboardType switch
//{
// KeyboardType.Numeric when inputType == Android.Text.InputTypes.ClassText => Android.Text.InputTypes.ClassNumber,
// KeyboardType.Alphanumeric when inputType == Android.Text.InputTypes.ClassText => Android.Text.InputTypes.TextVariationFilter,
// _ => inputType
//};
public void ForEachNode(Action<MaskNode> action, MaskNode startingNode)
{
ForEachNode((n, _) => action.Invoke(n), startingNode);
}
public void ForEachNode(Action<MaskNode, LoopControl> action, MaskNode startingNode)
{
MaskNode current = startingNode ?? _head;
LoopControl control = new LoopControl();
if (current == null) return;
do
{
action.Invoke(current, control);
if (control.ProcessBreak()) break;
} while ((current = current.NextNode) != null);
}
#endregion
#region Private Methods
private void InternalRemove(int start, int count, out int shift)
{
MaskNode startingNode = GetNode(start,false);
shift = 0;
if (startingNode == null) return;
ForEachNode((node, control) => {
if (count == 0)
{
control.Break();
return;
}
if (!node.IsHardcoded)
{
if (node.IsTemporary)
{
node.PreviousNode.NextNode = node.NextNode;
if (node.NextNode != null)
node.NextNode.PreviousNode = node.PreviousNode;
}
else
{
node.DisplayedCharacter = null;
}
}
count--;
}, startingNode);
if (startingNode.IsHardcoded)
shift = GetValidSelection(start, true,0,true) + 1;
else if (startingNode.PreviousNode != null && startingNode.PreviousNode.IsHardcoded)
shift = GetValidSelection(start - 1, true,0,true) + 1;
else
shift = GetValidSelection(start, true,0,true);
}
private void InternalInsert(string @string, int start, out int shift, bool createNewNodes)
{
MaskNode startingNode = GetNode(start, createNewNodes);
Queue<char> characters = new Queue<char>(@string);
bool validForm = ValidateString(@string, Options.Validation.BiggerOrEqualLength, true, false);
shift = 0;
if (startingNode == null)
{
shift = start;
return;
}
int nodeIdx = 0;
int newCursorPos = start;
ForEachNode((node, control) => {
if (characters.Count == 0)
{
control.Break();
return;
}
if (!node.IsHardcoded)
{
char @char = characters.Dequeue();
if (node.Regex != null && Regex.Match(new string(@char, 1), node.Regex).Success || node.IsTemporary)
{
node.DisplayedCharacter = @char;
newCursorPos = nodeIdx + 1;
}
else if (!_maskOptions.HasFlag(Options.MaskOptions.StaticMode))
{
do
{
if ((node.Regex == null || !Regex.Match(new string(@char, 1), node.Regex).Success) &&
!node.IsTemporary) continue;
node.DisplayedCharacter = @char;
newCursorPos = nodeIdx + 1;
break;
} while (characters.TryDequeue(out @char));
}
}
else if (validForm)
{
characters.Dequeue();
}
if (characters.Count > 0 && createNewNodes && node.NextNode == null)
node.NextNode = new MaskNode
{
IsTemporary = true,
PreviousNode = node
};
// ReSharper disable once AccessToModifiedClosure
nodeIdx++;
}, startingNode);
//if (newCursorPos != start) newCursorPos++;
shift = GetValidSelection(newCursorPos,false,0,true);
}
private void InternalInsert2(string @string, int start, out int shift, bool createNewNodes)
{
MaskNode startingNode = GetNode(start, createNewNodes);
Queue<char> characters = new Queue<char>(@string);
bool validForm = ValidateString(@string, Options.Validation.BiggerOrEqualLength, true, false);
shift = 0;
if (startingNode == null)
{
shift = start;
return;
}
int nodeIdx = 0;
int newCursorPos = start;
var insertedString = new StringBuilder();
ForEachNode((node, control) => {
if (characters.Count == 0)
{
control.Break();
return;
}
if (!node.IsHardcoded)
{
char @char = characters.Dequeue();
if (node.IsReqiredDisplayCharacter && node.Regex != null && Regex.Match(new string(@char, 1), node.Regex).Success || node.IsTemporary)
{
node.DisplayedCharacter = @char;
}
else
{
ForEachNode((internalNode, internalLoop) =>
{
if (internalNode.IsReqiredDisplayCharacter && internalNode.DisplayedCharacter == null && node.Regex != null && Regex.Match(new string(@char, 1), node.Regex).Success || node.IsTemporary)
{
internalNode.DisplayedCharacter = @char;
internalLoop.Break();
}
else if (internalNode.IsReqiredDisplayCharacter && internalNode.DisplayedCharacter == null)
{
internalLoop.Break();
}
}, node.NextNode);
}
//if (node.Regex != null && Regex.Match(new string(@char, 1), node.Regex).Success || node.IsTemporary)
//{
// node.DisplayedCharacter = @char;
// newCursorPos = nodeIdx + 1;
//}
//ForEachNode((internalNode, internalLoop) =>
//{
// if(internalNode.IsReqiredDisplayCharacter)
// {
// internalNode.DisplayedCharacter = @char;
// }
//}, node);
}
else if (validForm)
{
characters.Dequeue();
}
if (characters.Count > 0 && createNewNodes && node.NextNode == null)
node.NextNode = new MaskNode
{
IsTemporary = true,
PreviousNode = node
};
// ReSharper disable once AccessToModifiedClosure
nodeIdx++;
}, startingNode);
//if (newCursorPos != start) newCursorPos++;
shift = GetValidSelection(newCursorPos, false, 0, true);
}
private MaskNode GetNode(int index, bool createIfNotFound)
{
MaskNode current = _head;
for (int i = 0; i < index; i++)
{
if (current.NextNode == null)
{
if (createIfNotFound)
{
MaskNode node = new MaskNode()
{
IsTemporary = true,
PreviousNode = current
};
current.NextNode = node;
return node;
}
return null;
}
current = current.NextNode;
}
return current;
}
#endregion
}
#region Classes/Enums/Extensions
public sealed class MaskNode
{
private MaskNode _previousNode;
private MaskNode _nextNode;
private string _regex = ".";
private char _character;
private char? _displayedCharacter;
private char? _overrideCharacter;
private bool _isHardcoded;
private bool _isTemporary;
private bool _isReqiredDisplayCharacter;
internal MaskNode PreviousNode
{
get { return _previousNode; }
set { _previousNode = value; }
}
internal MaskNode NextNode
{
get { return _nextNode; }
set { _nextNode = value; }
}
internal string Regex
{
get { return _regex; }
set { _regex = value; }
}
internal char Character
{
get { return _character; }
set { _character = value; }
}
internal char? DisplayedCharacter
{
get { return _displayedCharacter; }
set { _displayedCharacter = value; }
}
internal char? OverrideCharacter
{
get { return _overrideCharacter; }
set { _overrideCharacter = value; }
}
internal bool IsHardcoded
{
get { return _isHardcoded; }
set { _isHardcoded = value; }
}
internal bool IsTemporary
{
get { return _isTemporary; }
set { _isTemporary = value; }
}
/// <summary>
/// Требуется отображать символ?
/// </summary>
internal bool IsReqiredDisplayCharacter
{
get { return _isReqiredDisplayCharacter; }
set { _isReqiredDisplayCharacter = value; }
}
}
public sealed class LoopControl
{
private bool _willBreak;
internal void Break()
{
_willBreak = true;
}
internal bool ProcessBreak()
{
bool result = _willBreak;
_willBreak = false;
return result;
}
}
public sealed class NodeType
{
internal string RegEx { get; private set; }
internal KeyboardType Type { get; private set; }
/// <summary>
/// Требуется ли отображать значение
/// </summary>
public bool IsReqiredDisplayCharacter { get; private set; }
public NodeType(string regEx, KeyboardType type, bool isReqiredDisplayCharacter)
{
RegEx = regEx;
Type = type;
IsReqiredDisplayCharacter = isReqiredDisplayCharacter;
}
}
public enum KeyboardType
{
None,
Numeric,
Alphanumeric
}
internal static class Extensions
{
internal static bool TryDequeue<T>(this Queue<T> obj, out T item)
{
item = default(T);
if (obj.Count == 0) return false;
item = obj.Dequeue();
return true;
}
internal static bool HasFlag(this Enum item1, Enum item2) {
return (Convert.ToInt32(item1) & Convert.ToInt32(item2)) != 0;
}
}
#endregion
}Editor is loading...
Leave a Comment