Code: Select all
Procedure.s _xm_StripCharacters(xMask.__s_xMask_Main(), Text.s, IndexBegin.l)
Regards
Thanos
Code: Select all
Procedure.s _xm_StripCharacters(xMask.__s_xMask_Main(), Text.s, IndexBegin.l)
Code: Select all
Procedure.s _xm_StripCharacters(List xMask.__s_xMask_Main(), Text.s, IndexBegin.l) 
Thanks srod!srod wrote:You need to declare linked lists and arrays when used as parameters now.Code: Select all
Procedure.s _xm_StripCharacters(List xMask.__s_xMask_Main(), Text.s, IndexBegin.l)


netmaestro wrote:Xombie hasn't posted in over six months. Let's give him a few days to respond and if none comes I'll update the code to the current version for you. You can also try to PM him, that might work.
Code: Select all
;=====================================================================
;  Program:            Masked String Gadget
;  Author:             Xombie, Updated By Peyman
;  Date:               April 1, 2011
;  Target OS:          Microsoft Windows All
;  Target Compiler:    PureBasic 4.xx X86/X64
;  License:            Free
;  Fixes :             Updating source to work with pb > 4.50 x86/x64 and many others fixes.
;=====================================================================
;
EnableExplicit
Declare SetGadgetMask(Gadget.i, TextMask.s, Text.s, PlaceHolder.b, RightToLeft.b = #False, SelectAllOnFocus.b = #False)
Declare RemoveGadgetMasks(Gadget.i)
Structure __s_xMask_Main
   ;
   Gadget.i
   ;
   Handle.i
   ;
   TextMask.s
   ;
   Text.s
   ;
   PlaceHolder.c
   ;
   RightToLeft.b
   ;
   OldCallback.i
   ;
   MaxLength.i
   ;
   SelectAllOnFocus.b
   ; If True, when the the xMask gadget is selected it will select the whole line.
   AdjustingText.b
   ; True if the callback is temporarily setting text.
EndStructure
Global NewList __xm_Main.__s_xMask_Main()
;- Internal Procedures
Procedure InsertCharacter(*HoldText.i, Index.i, Character.c)
   ;
   CompilerIf #PB_Compiler_Unicode = #True
      ;
      PokeC(*HoldText + (Index << 1), Character)
      ;
   CompilerElse
      ;
      PokeC(*HoldText + Index, Character)
      ;
   CompilerEndIf
   ;
EndProcedure
Procedure.i _xm_GetMaxLength(TextMask.s)
   ;
   Protected.Character *HoldChar
   ;
   Protected.b AllowAsNonFormatting
   ;
   Protected.i lResult
   ;
   *HoldChar = @TextMask
   ;
   While *HoldChar\c <> 0
      ;
      If AllowAsNonFormatting
         ;
         lResult + 1
         ;
         AllowAsNonFormatting = #False
         ;
      Else
         ;
         If *HoldChar\c = '0'
            ; This is a required number field.
            lResult + 1
            ;
         ElseIf *HoldChar\c = '9'
            ; This is a non-required number field.  Either a digit or a space is allowed here.
            lResult + 1
            ;
         ElseIf *HoldChar\c = 'L'
            ; A - Z, entry required
            lResult + 1
            ;
         ElseIf *HoldChar\c = '?'
            ; A - Z, entry optional.
            lResult + 1
            ;
         ElseIf *HoldChar\c = 'A'
            ; A - Z or 0 - 9, entry required.
            lResult + 1
            ;
         ElseIf *HoldChar\c = 'a'
            ; A - Z or 0 - 9, entry optional.
            lResult + 1
            ;
         ElseIf *HoldChar\c = '&'
            ; Any character or space, entry required.
            lResult + 1
            ;
         ElseIf *HoldChar\c = 'C'
            ; Any character or space, entry optional.
            lResult + 1
            ;
         ElseIf *HoldChar\c = ''
            ;
            ;
         ElseIf *HoldChar\c = ' '
            ;
            lResult + 1
            ;
         ElseIf *HoldChar\c = '\'
            ; The 'force non-formatting character' character.  Ignore this character and do not increase the maximum length.
            AllowAsNonFormatting = #True
            ; The following character will be included in the display no matter what it is.
         Else
            ; The character was a non-formating character.  Add it as-is.
            lResult + 1
            ; A display character always increases the length.
         EndIf
         ;
      EndIf
      ;
      CompilerIf #PB_Compiler_Unicode = #True : *HoldChar + 2 : CompilerElse : *HoldChar + 1 : CompilerEndIf
      ;
   Wend
   ;
   ProcedureReturn lResult
   ;
EndProcedure
Procedure.s _xm_StripCharacters(List xMask.__s_xMask_Main(), Text.s, IndexBegin.i)
   ; This procedure is used to to strip out unneeded characters in text being inserted into a mask.
   Protected.Character *HoldMask
   ;
   Protected.Character *HoldChar
   ;
   Protected.Character *OutText
   ;
   Protected.s HoldString
   ;
   Protected.b IsFormatting
   ;
   Protected.b FailedMask
   ;
   Protected.b ForceAdd
   ;
   *HoldChar = @Text
   ;
   *HoldMask = @xMask()\TextMask + (IndexBegin - 1)
   ;
   HoldString = Space(Len(Text))
   ;
   *OutText = @HoldString
   ;
   While *HoldMask\c And *HoldChar\c
      ;
      FailedMask = #True
      ;
      If *HoldMask\c = '0'
         ; Required numeric field (0-9).
         If *HoldChar\c > 47 And *HoldChar\c < 58 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '9'
         ; Non-required numeric field.  A number (0-9) or a space is allowed.
         If (*HoldChar\c > 47 And *HoldChar\c < 58) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'L'
         ; A - Z, entry required.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '?'
         ; A - Z, entry not required and may include spaces.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'A'
         ; A - Z or 0 - 9, entry required.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) Or (*HoldChar\c > 47 And *HoldChar\c < 58) : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'a'
         ; A - Z or 0 - 9, entry not required and may include spaces.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) Or (*HoldChar\c > 47 And *HoldChar\c < 58) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '&'
         ; Any character or space, entry required.
         If *HoldChar\c > 32 And *HoldChar\c < 256 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'C'
         ; Any character or space, entry not required and may include spaces.
         If (*HoldChar\c > 32 And *HoldChar\c < 256) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '>'
         ; Capitalize the following character.
         IsFormatting = #True
         ;
      ElseIf *HoldMask\c = '<'
         ; Decapitalize the following character.
         IsFormatting = #True
         ;
      ElseIf *HoldMask\c = '\'
         ; Add the next character as-is.
         IsFormatting = #True
         ;
      Else
         ;
         ForceAdd = #True
         ;
         If *HoldMask\c = *HoldChar\c : FailedMask = #False : EndIf
         ;
      EndIf
      ;
      If IsFormatting = #False
         ;
         If FailedMask
            ;
            ProcedureReturn Text
            ;
         Else
            ;
            If ForceAdd = #False
               ;
               *OutText\c = *HoldChar\c
               ;
               CompilerIf #PB_Compiler_Unicode = #True : *OutText + 2 : CompilerElse : *OutText + 1 : CompilerEndIf
               ;
            EndIf
            ;
            CompilerIf #PB_Compiler_Unicode = #True : *HoldChar + 2 : CompilerElse : *HoldChar + 1 : CompilerEndIf
            ;
         EndIf
         ;
      EndIf
      ;
      ForceAdd = #False : IsFormatting = #False
      ;
      CompilerIf #PB_Compiler_Unicode = #True : *HoldMask + 2 : CompilerElse : *HoldMask + 1 : CompilerEndIf
      ;
   Wend
   ;
   ProcedureReturn Left(HoldString, *OutText - @HoldString)
   ;
EndProcedure
Procedure.c _xm_ReturnCharacter(List xMask.__s_xMask_Main(), Character.c, *Index.i, UsingPlaceholder.b = #False)
   ;
   Protected.Character *HoldMask
   ;
   Protected.b IsFormatting
   ;
   Protected.b FailedMask
   ;
   Protected.b ForceAdd
   ;
   Protected.i Position
   ;
   Protected.b DoUpper, DoLower, IsStatic
   ;
   Protected.i HoldIndex
   ;
   *HoldMask = @xMask()\TextMask
   ;
   While *HoldMask\c
      ;
      FailedMask = #True
      ;
      If ForceAdd
         ;
         IsStatic = #True
         ;
      Else
         ;
         If *HoldMask\c = '0'
            ; Required numeric field (0-9).
            If Character > 47 And Character < 58 : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = '9'
            ; Non-required numeric field.  A number (0-9) or a space is allowed.
            If (Character > 47 And Character < 58) Or Character = 32 : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = 'L'
            ; A - Z, entry required.
            If (Character > 64 And Character < 91) Or (Character > 96 And Character < 123) : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = '?'
            ; A - Z, entry not required and may include spaces.
            If (Character > 64 And Character < 91) Or (Character > 96 And Character < 123) Or Character = 32 : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = 'A'
            ; A - Z or 0 - 9, entry required.
            If (Character > 64 And Character < 91) Or (Character > 96 And Character < 123) Or (Character > 47 And Character < 58) : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = 'a'
            ; A - Z or 0 - 9, entry not required and may include spaces.
            If (Character > 64 And Character < 91) Or (Character > 96 And Character < 123) Or (Character > 47 And Character < 58) Or Character = 32 : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = '&'
            ; Any character or space, entry required.
            If Character > 32 And Character < 256 : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = 'C'
            ; Any character or space, entry not required and may include spaces.
            If (Character > 32 And Character < 256) Or Character = 32 : FailedMask = #False : EndIf
            ;
         ElseIf *HoldMask\c = '>'
            ; Capitalize the following character.
            IsFormatting = #True
            ;
            DoUpper = #True
            ;
         ElseIf *HoldMask\c = '<'
            ; Decapitalize the following character.
            IsFormatting = #True
            ;
            DoLower = #True
            ;
         ElseIf *HoldMask\c = '\'
            ; Add the next character as-is.
            IsFormatting = #True
            ;
            ForceAdd = #True
            ;
         Else
            ;
            IsStatic = #True
            ;
         EndIf
         ;
      EndIf
      ;
      ; If IsStatic And UsingPlaceholder : FailedMask = #True : Else : FailedMask = #False : EndIf
      If UsingPlaceholder : FailedMask = IsStatic : EndIf
      ;
      If IsFormatting = #False
         ;
         HoldIndex + 1
         ;
         If IsStatic = #False
            ;
            If Position = PeekL(*Index)
               ;
               PokeL(*Index, HoldIndex - 1)
               ;
               If FailedMask
                  ;
                  ProcedureReturn 0
                  ;
               Else
                  ;
                  If UsingPlaceholder
                     ;
                     ProcedureReturn xMask()\PlaceHolder
                     ;
                  ElseIf DoUpper
                     ;
                     If Character > 96 And Character < 123 : ProcedureReturn Character - 32 : Else : ProcedureReturn Character : EndIf
                     ;
                  ElseIf DoLower
                     ;
                     If Character > 64 And Character < 91 : ProcedureReturn Character + 32 : Else : ProcedureReturn Character : EndIf
                     ;
                  Else
                     ;
                     ProcedureReturn Character
                     ;
                  EndIf
                  ;
               EndIf
               ;
            EndIf
            ;
            Position + 1
            ;
         Else
            ;
            If UsingPlaceholder
               ;
               If Position = PeekL(*Index)
                  ;
                  PokeL(*Index, HoldIndex - 1)
                  ;
                  ProcedureReturn 0
                  ;
               EndIf
               ;
            EndIf
            ;
            If Position < PeekL(*Index) : Position + 1 : EndIf
            ;
         EndIf
         ;
         DoUpper = #False : DoLower = #False
         ;
      EndIf
      ;
      ForceAdd = #False : IsFormatting = #False : IsStatic = #False
      ;
      CompilerIf #PB_Compiler_Unicode = #True : *HoldMask + 2 : CompilerElse : *HoldMask + 1 : CompilerEndIf
      ;
   Wend
   ;
   ProcedureReturn 0
   ;
EndProcedure
Procedure.s _xm_MaskToText(List xMask.__s_xMask_Main(), Text.s, ForcePlaceHolder.b = #False)
   ; Inserts the mask into a string gadget with the placeholder character - replacing with Text as
   ; possible.  If ForcePlaceHolder is true, the returned string will just be the placeholder.
   Protected.Character *HoldChar
   ;
   Protected.Character *HoldMask
   ;
   Protected.Character *OutText
   ;
   Protected.s HoldString
   ;
   Protected.b IgnoreMask
   ; True if the last character was '\' - the next character is treated as an output character.
   Protected.b FailedMask
   ; True if the mask conditions are failed when inserting text.
   Protected.b IsFormatting
   ;
   Protected.b DoUpper, DoLower, ForceAdd
   ;
   *HoldMask = @xMask()\TextMask
   ;
   *HoldChar = @Text
   ;
   HoldString = Space(xMask()\MaxLength)
   ;
   *OutText = @HoldString
   ;
   While *HoldMask\c
      ; Loop until the end-of-line character is located.
      FailedMask = #True
      ; The mask fails by default.
      IsFormatting = #False
      ; A formatting character is the '>' or '<' or '\' character.
      If *HoldMask\c = '0'
         ; Required numeric field (0-9).
         If *HoldChar\c > 47 And *HoldChar\c < 58 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '9'
         ; Non-required numeric field.  A number (0-9) or a space is allowed.
         If (*HoldChar\c > 47 And *HoldChar\c < 58) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'L'
         ; A - Z, entry required.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '?'
         ; A - Z, entry not required and may include spaces.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'A'
         ; A - Z or 0 - 9, entry required.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) Or (*HoldChar\c > 47 And *HoldChar\c < 58) : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'a'
         ; A - Z or 0 - 9, entry not required and may include spaces.
         If (*HoldChar\c > 64 And *HoldChar\c < 91) Or (*HoldChar\c > 96 And *HoldChar\c < 123) Or (*HoldChar\c > 47 And *HoldChar\c < 58) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '&'
         ; Any character or space, entry required.
         If *HoldChar\c > 32 And *HoldChar\c < 256 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = 'C'
         ; Any character or space, entry not required and may include spaces.
         If (*HoldChar\c > 32 And *HoldChar\c < 256) Or *HoldChar\c = 32 : FailedMask = #False : EndIf
         ;
      ElseIf *HoldMask\c = '>'
         ; Capitalize the following character.
         IsFormatting = #True
         ;
         DoUpper = #True
         ;
      ElseIf *HoldMask\c = '<'
         ; Decapitalize the following character.
         IsFormatting = #True
         ;
         DoLower = #True
         ;
      ElseIf *HoldMask\c = '\'
         ; Add the next character as-is.
         IsFormatting = #True
         ;
         ForceAdd = #True
         ;
      Else
         ;
         ForceAdd = #True
         ;
         FailedMask = #False
         ;
      EndIf
      ;
      If IsFormatting = #False Or ForcePlaceHolder
         ;
         If ForcePlaceHolder Or *HoldChar\c = 0 : FailedMask = #False : EndIf
         ;
         If FailedMask
            ; The text does not match the mask.
            ProcedureReturn ""
            ; Return an empty string.
         Else
            ;
            If ForceAdd
               ;
               *OutText\c = *HoldMask\c
               ;
            ElseIf ForcePlaceHolder Or *HoldChar\c = 0
               ;
               *OutText\c = xMask()\PlaceHolder
               ;
            Else
               ;
               If DoUpper
                  ;
                  *OutText\c = Asc(UCase(Mid(Text, *HoldChar - @Text + 1, 1)))
                  ;
               ElseIf DoLower
                  ;
                  *OutText\c = Asc(LCase(Mid(Text, *HoldChar - @Text + 1, 1)))
                  ;
               Else
                  ;
                  *OutText\c = *HoldChar\c
                  ; Store the current character.
               EndIf
               ;
               CompilerIf #PB_Compiler_Unicode = #True : *HoldChar + 2 : CompilerElse : *HoldChar + 1 : CompilerEndIf
               ;
            EndIf
            ;
            CompilerIf #PB_Compiler_Unicode = #True : *OutText + 2 : CompilerElse : *OutText + 1 : CompilerEndIf
            ; Point to the next available space.
         EndIf
         ;
         DoUpper = #False : DoLower = #False : ForceAdd = #False
         ;
      EndIf
      ;
      CompilerIf #PB_Compiler_Unicode = #True : *HoldMask + 2 : CompilerElse : *HoldMask + 1 : CompilerEndIf
      ;
   Wend
   ;
   ProcedureReturn Left(HoldString, *OutText - @HoldString)
   ;
EndProcedure
Procedure _xm_ClearText(List xMask.__s_xMask_Main(), OnlyHighlighted = #False)
   ;
   Protected.c Character
   ;
   Protected.s HoldString
   ;
   Protected.i iLoop, HoldIndex
   ;
   Protected.POINT HoldSelect
   ;
   SendMessage_(xMask()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
   ; Retrieve the start and end selection values.  We'll use this when replacing characters.
   If OnlyHighlighted And HoldSelect\X = HoldSelect\Y : ProcedureReturn : EndIf
   ;
   If HoldSelect\X < xMask()\MaxLength
      ;
      If HoldSelect\X < HoldSelect\Y : HoldSelect\Y - 1 : EndIf
      ;
      HoldString = GetGadgetText(xMask()\Gadget)
      ;
      For iLoop = HoldSelect\X To HoldSelect\Y
         ;
         HoldIndex = iLoop
         ;
         Character = _xm_ReturnCharacter(xMask(), 0, @HoldIndex, #True)
         ;
         If Character : InsertCharacter(@HoldString, HoldIndex, Character) : EndIf
         ;
      Next iLoop
      ;
      xMask()\AdjustingText = #True
      ;
      SetGadgetText(xMask()\Gadget, HoldString)
      ;
      xMask()\AdjustingText = #False
      ;
      SendMessage_(xMask()\Handle, #EM_SETSEL, HoldSelect\X, HoldSelect\X)
      ;
   EndIf
   ;
EndProcedure
Procedure.b _xm_CheckStatic(List xMask.__s_xMask_Main(), Index.i, Text.s) ;By Peyman
  Protected.Character *HoldMask
  *HoldMask = @xMask()\TextMask
  *HoldMask + Index
   
  Select *HoldMask\c
    Case '0', '9', 'L', '?', 'A', 'a', '&', 'C', '>', '<', '\'
      ProcedureReturn #False
      
    Default
      If *HoldMask\c = Asc(Text)
        ProcedureReturn #True
      Else
        ProcedureReturn #False
      EndIf
      
  EndSelect
 
EndProcedure
Procedure _xm_EditCallback(HandleWindow.i, message.i, wParam.i, lParam.i)
   ; This is a custom callback function used by our xMask gadget.  We'll use this to check
   ; for various events and handle them in the appropriate manner.
   Protected.b CaughtMatch
   ;
   Protected.i iLoop
   ;
   Protected.i lResult
   ;
   Protected.i HoldStyle
   ;
   Protected.s HoldString, HoldText
   ;
   Protected.POINT HoldSelect
   ;
   Protected.c Character
   ;
   Protected.i HoldIndex
   ;
   ResetList(__xm_Main())
   While NextElement(__xm_Main())
      ;
      If __xm_Main()\Handle = HandleWindow : CaughtMatch = #True : Break : EndIf
      ;
   Wend
   ;
   If CaughtMatch = #False : ProcedureReturn : EndIf
   ; This should never happen but exit if the string gadget is not on the list.
   HoldStyle = GetWindowLongPtr_(__xm_Main()\Handle, #GWL_STYLE)
   ; Get the style of the string gadget.
   If HoldStyle & #ES_READONLY = 0
      ; Ensure the string gadget is not read only.
      If message = #WM_SETTEXT
         ;{ Text is changing via a 'SetGadgetText()' call.
         If __xm_Main()\AdjustingText = #False
            ;
            HoldString = _xm_MaskToText(__xm_Main(), _xm_StripCharacters(__xm_Main(), PeekS(lParam), 1), #False)
            ; Check the text against the mask and store the result.  lParam is the pointer to the updating text.
            If HoldString <> ""
               ;
               __xm_Main()\AdjustingText = #True
               ;
               SetGadgetText(__xm_Main()\Gadget, HoldString)
               ; Update the text in the control.
               __xm_Main()\AdjustingText = #False
               ;
            EndIf
            ;
            message = 0
            ; Clear the message - the text is handled internally.
         EndIf
         ;}
      ElseIf message = #WM_SETFOCUS
        ; The edit control received focus.
        If __xm_Main()\SelectAllOnFocus
          SendMessage_(__xm_Main()\Handle, #EM_SETSEL, #Null, -1)
        EndIf
         ; Select all text in the edit control.
      ElseIf message = #WM_CHAR
         ;{
         If wParam = #VK_BACK
           ;
            SendMessage_(__xm_Main()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
            ; Retrieve the start and end selection values.  We'll use this when replacing characters.
            If HoldSelect\X
               ;
               If HoldSelect\X = HoldSelect\Y : HoldSelect\X - 1 : HoldSelect\Y - 1 : EndIf
               ;
               HoldString = GetGadgetText(__xm_Main()\Gadget)
               ;
               For iLoop = HoldSelect\X To HoldSelect\Y
                  ;
                  HoldIndex = iLoop
                  ;
                  Character = _xm_ReturnCharacter(__xm_Main(), wParam, @HoldIndex, #True)
                  ;
                  If Character : InsertCharacter(@HoldString, HoldIndex, Character) : EndIf
                  ;
               Next iLoop
               ;
               __xm_Main()\AdjustingText = #True
               ;
               SetGadgetText(__xm_Main()\Gadget, HoldString)
               ;
               __xm_Main()\AdjustingText = #False
               ;
               SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\X, HoldSelect\X)
               
               ;By Peyman
               If _xm_CheckStatic(__xm_Main(), HoldSelect\X - 1, Mid(HoldString, HoldSelect\X, 1))
                 SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\X - 1, HoldSelect\X - 1)
               EndIf
               ;
               ;
               
            EndIf
            ;
         Else
           ;
           
            SendMessage_(__xm_Main()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
            ; Retrieve the start and end selection values.  We'll use this when replacing characters.
            If HoldSelect\X <= __xm_Main()\MaxLength
               ; Do not allow any text past the maximum length.
               HoldIndex = HoldSelect\X
               ;
               Character = _xm_ReturnCharacter(__xm_Main(), wParam, @HoldSelect\X)
               ;
               If Character
                  ;
                  HoldString = GetGadgetText(__xm_Main()\Gadget)
                  ;
                  InsertCharacter(@HoldString, HoldSelect\X, Character)
                  ;
                  __xm_Main()\AdjustingText = #True
                  ;
                  SetGadgetText(__xm_Main()\Gadget, HoldString)
                  ;
                  __xm_Main()\AdjustingText = #False
                  ;
                  HoldSelect\X + 1
                  SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\X, HoldSelect\X) ; HoldSelect\y + (HoldSelect\x - HoldIndex) + 1)
                  
                  ;By Peyman
                  If _xm_CheckStatic(__xm_Main(), HoldSelect\X, Mid(HoldString, HoldSelect\X + 1, 1))
                    SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\X + 1, HoldSelect\X + 1)
                  EndIf
                  
                  ;
               EndIf
               ;
            EndIf
            ;
         EndIf
         ;
         ; Flush the charcter And prevent program from say beep ;-)
         message = 0
         
         ;}
      ElseIf message = #WM_KEYDOWN
         ;{ A key is down.  This event will fire along with #WM_CHAR.  wParam returns the virtual key code.
         If wParam = #VK_DELETE
           ;
            _xm_ClearText(__xm_Main()) : wParam = 0
            ;
         EndIf
         
         ;By Peyman
         If wParam = #VK_RIGHT
           ;
           SendMessage_(__xm_Main()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
           HoldString = GetGadgetText(__xm_Main()\Gadget)
           
           HoldSelect\X + 1
           
           If _xm_CheckStatic(__xm_Main(), HoldSelect\X, Mid(HoldString, HoldSelect\X + 1, 1))
            SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\X, HoldSelect\X)
           EndIf
            ;
         EndIf
         
         ;By Peyman
         If wParam = #VK_LEFT
           ;
           SendMessage_(__xm_Main()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
           If HoldSelect\X = HoldSelect\Y : HoldSelect\X - 1 : HoldSelect\Y - 1 : EndIf
           HoldString = GetGadgetText(__xm_Main()\Gadget)
           
           If _xm_CheckStatic(__xm_Main(), HoldSelect\X - 1, Mid(HoldString, HoldSelect\X, 1))
            SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\X, HoldSelect\X)
           EndIf
            ;
         EndIf
          
         ;}
      ElseIf message = #WM_CLEAR
         ;{ The delete submenu from the right-click menu is called.
         _xm_ClearText(__xm_Main(), #True) : message = 0
         ;
         ;}
      ElseIf message = #WM_CUT
         ;{ The cut submenu from the right-click menu is called.
         SendMessage_(__xm_Main()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
         ; Retrieve the start and end selection values.  We'll use this when replacing characters.
         If HoldSelect\X = HoldSelect\Y : ProcedureReturn : EndIf
         ;
         HoldString = Mid(GetGadgetText(__xm_Main()\Gadget), HoldSelect\X + 1, HoldSelect\Y - HoldSelect\X)
         ;
         SetClipboardText(HoldString)
         ;
         _xm_ClearText(__xm_Main(), #True) : message = 0
         ;
         ;}
      ElseIf message = #WM_PASTE
         ;{ The paste submenu from the right-click menu is called.
         SendMessage_(__xm_Main()\Handle, #EM_GETSEL, @HoldSelect\X, @HoldSelect\Y)
         ; Retrieve the start and end selection values.  We'll use this when replacing characters.
         If HoldSelect\X = HoldSelect\Y : ProcedureReturn : EndIf
         ;
         HoldString = GetGadgetText(__xm_Main()\Gadget)
         ;
         HoldText = _xm_StripCharacters(__xm_Main(), GetClipboardText(), HoldSelect\X + 1)
         ;
         HoldIndex = 1
         ;
         For iLoop = HoldSelect\X To HoldSelect\Y
            ;
            Character = _xm_ReturnCharacter(__xm_Main(), Asc(Mid(HoldText, HoldIndex, 1)), @iLoop, #False)
            ;
            If Character : InsertCharacter(@HoldString, iLoop, Character) : EndIf
            ;
            HoldIndex + 1
            ;
         Next iLoop
         ;
         __xm_Main()\AdjustingText = #True
         ;
         SetGadgetText(__xm_Main()\Gadget, HoldString)
         ; Update the text in the control.
         __xm_Main()\AdjustingText = #False
         ;
         SendMessage_(__xm_Main()\Handle, #EM_SETSEL, HoldSelect\Y, HoldSelect\Y)
         ;
         message = 0
         ;
         ;}
      EndIf
      ;
   EndIf
   ;
   lResult = CallWindowProc_(__xm_Main()\OldCallback, HandleWindow, message, wParam, lParam)
   ; Call the original edit control's callback function for any messages not handled.
   ProcedureReturn lResult
   ;
EndProcedure
;- Main Procedures
Procedure.s xm_GetRawData(Gadget.i)
  ;
  ResetList(__xm_Main())
  While NextElement(__xm_Main())
    ;
    If __xm_Main()\Gadget = Gadget
      ;
      ProcedureReturn _xm_StripCharacters(__xm_Main(), GetGadgetText(__xm_Main()\Gadget), 1)
      ;
    EndIf
    ;
  Wend
  ;
  ProcedureReturn ""
  ;
EndProcedure
Procedure RemoveGadgetMasks(Gadget.i) ; Use 0 to remove all masks.
  ;
  ResetList(__xm_Main())
  While NextElement(__xm_Main())
    ;
    If Not Gadget Or Gadget = __xm_Main()\Gadget
      ;
      SetWindowLongPtr_(__xm_Main()\Handle, #GWLP_WNDPROC, __xm_Main()\OldCallback)
      ; Now set the custom callback to use for the new xMask gadget.
      DeleteElement(__xm_Main())
      ;
    EndIf
    ;
  Wend
  ;
EndProcedure
Procedure SetGadgetMask(Gadget.i, TextMask.s, Text.s, PlaceHolder.b, RightToLeft.b = #False, SelectAllOnFocus.b = #False)
  ; Modifies a string gadget to only accept certain characters based on a mask.
  Protected.s HoldString
  ; The handle of the gadget.
  Protected.i Handle
   
  Handle = GadgetID(Gadget)
  ; Truncate the string based on the number of characters copied.
  If GadgetType(Gadget) = #PB_GadgetType_String
    ; Only edit controls may be masked.
    ResetList(__xm_Main())
    While NextElement(__xm_Main())
      ;
      If __xm_Main()\Gadget = Gadget
        ProcedureReturn
      EndIf
      ; Do not allow duplicates.
    Wend
    ;
    AddElement(__xm_Main())
    ; Add a new xMask control.
    With __xm_Main()
      ;
      \Gadget = Gadget
      \Handle = Handle
      ;
      \TextMask = TextMask
      \Text = Text
      ;
      \PlaceHolder = PlaceHolder
      \RightToLeft = RightToLeft
      ;
      \MaxLength = _xm_GetMaxLength(TextMask)
      ; Get the maximum allowed length of the edit control.
      \SelectAllOnFocus = SelectAllOnFocus
      ;
    EndWith
    ;
    HoldString = _xm_MaskToText(__xm_Main(), Text, #False)
    ;
    If HoldString = ""
      HoldString = _xm_MaskToText(__xm_Main(), HoldString, #True)
    EndIf
    ;
    SetGadgetText(Gadget, HoldString)
    ;
    SendMessage_(Handle, #EM_LIMITTEXT, __xm_Main()\MaxLength, #Null)
    ; Set the maximum number of allowed characters.
    ; Store the original callback procedure address for the Edit control and set the custom callback to use for the new xMask gadget.
    __xm_Main()\OldCallback = SetWindowLongPtr_(__xm_Main()\Handle, #GWLP_WNDPROC, @_xm_EditCallback())
  EndIf
  ;
EndProcedure
;- Test Program
;{ Create Test Window
If OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_TitleBar | #PB_Window_SystemMenu)
  StringGadget(0, 10, 10, 120, 20, "")
  SetGadgetMask(0, "999-99-9999", "123456789", '*', #False, #True)
  ButtonGadget(1, 80, 150, 50, 50,  "")
EndIf
;
Define.b DoQuit
;
Define.i HoldID
;
While DoQuit = #False
   ;
   HoldID = WaitWindowEvent()
   ;
   If HoldID = #PB_Event_CloseWindow
      ; Close the program.
      DoQuit = #True
      ;
   EndIf
   ;
Wend
;}
RemoveGadgetMasks(0)
End

Peyman wrote:@netmaestro:
thanks netmaestro, i cant find xombie's original header for the code so i write one.
@mx101 :
see my last post, its updated.
Code: Select all
123|-**-****Code: Select all
123-|**-****i add _xm_CheckStatic procedure for do this, check my post i repost the updated code.ebs wrote:Peyman,
Can you suggest a code change that would move the caret (text cursor) past any literal characters in the mask?
I would like it to move to the next character input position, because I think that makes it clearer where the next
character entered will go.
For example, using the example in the code, the mask is "999-99-9999".
If I enter "123", the StringGadget looks like this:where "|" represents the caret.Code: Select all
123|-**-****
I would like it to move past the "-" and look like this:Thanks for your help!Code: Select all
123-|**-****
Regards,
Eric
Thank you - it works great!Peyman wrote:i add _xm_CheckStatic procedure for do this, check my post i repost the updated code.