xMask - A Masked Edit Gadget

Developed or developing a new product in PureBasic? Tell the world about it.
thanos
Enthusiast
Enthusiast
Posts: 423
Joined: Sat Jan 12, 2008 3:25 pm
Location: Greece
Contact:

Post by thanos »

When compiling the code with PureBasic 4.30 i received an error in line 132 'Syntax error'

Code: Select all

Procedure.s _xm_StripCharacters(xMask.__s_xMask_Main(), Text.s, IndexBegin.l)
What is wrong?
Regards

Thanos
» myPersonal Banker :: Because you do not need to have a master degree in economics in order to organize your finances!
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Code: Select all

Procedure.s _xm_StripCharacters(List xMask.__s_xMask_Main(), Text.s, IndexBegin.l) 
You need to declare linked lists and arrays when used as parameters now.
I may look like a mule, but I'm not a complete ass.
thanos
Enthusiast
Enthusiast
Posts: 423
Joined: Sat Jan 12, 2008 3:25 pm
Location: Greece
Contact:

Post by thanos »

srod wrote:

Code: Select all

Procedure.s _xm_StripCharacters(List xMask.__s_xMask_Main(), Text.s, IndexBegin.l) 
You need to declare linked lists and arrays when used as parameters now.
Thanks srod!
It is working now.
Btw, congratulations about the ADOmate and COMate libraries.
Excellent work.
Regards.

Thanos
» myPersonal Banker :: Because you do not need to have a master degree in economics in order to organize your finances!
kinglestat
Enthusiast
Enthusiast
Posts: 746
Joined: Fri Jul 14, 2006 8:53 pm
Location: Malta
Contact:

Post by kinglestat »

nice control Zombie
I might have a use for this you know
I may not help with your coding
Just ask about mental issues!

http://www.lulu.com/spotlight/kingwolf
http://www.sen3.net
mx101
User
User
Posts: 73
Joined: Thu Sep 18, 2008 3:21 pm

Re: xMask - A Masked Edit Gadget

Post by mx101 »

hi... Xombie

can you update the code to use in PB 4.51??


not work in PB 5.1 can you update the code?


thanks
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: xMask - A Masked Edit Gadget

Post by netmaestro »

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.
BERESHEIT
mx101
User
User
Posts: 73
Joined: Thu Sep 18, 2008 3:21 pm

Re: xMask - A Masked Edit Gadget

Post by mx101 »

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.

oki netmaestro thank you very much :)
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: xMask - A Masked Edit Gadget

Post by Peyman »

its updated and fixed some thing like work on x64 compiler and remove beep sound.
Update 1 Aprill 2011 :

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
Last edited by Peyman on Fri Apr 01, 2011 4:03 pm, edited 2 times in total.
Sorry for my bad english.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: xMask - A Masked Edit Gadget

Post by netmaestro »

Thanks peyman! Please restore xombie's original header for the code and add a couple of lines identifying who updated the code, when and why.
BERESHEIT
mx101
User
User
Posts: 73
Joined: Thu Sep 18, 2008 3:21 pm

Re: xMask - A Masked Edit Gadget

Post by mx101 »

Peyman and netmaestro thank you very much to both :D


How can i remove the beep sound ??
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: xMask - A Masked Edit Gadget

Post by Peyman »

@netmaestro:
thanks netmaestro, i cant find xombie's original header for the code so i write one.

@mx101 :
see my last post, its updated.
Sorry for my bad english.
mx101
User
User
Posts: 73
Joined: Thu Sep 18, 2008 3:21 pm

Re: xMask - A Masked Edit Gadget

Post by mx101 »

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.

thank you Peyman you save my day :D

thank you very much
ebs
Enthusiast
Enthusiast
Posts: 557
Joined: Fri Apr 25, 2003 11:08 pm

Re: xMask - A Masked Edit Gadget

Post by ebs »

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:

Code: Select all

123|-**-****
where "|" represents the caret.

I would like it to move past the "-" and look like this:

Code: Select all

123-|**-****
Thanks for your help!

Regards,
Eric
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: xMask - A Masked Edit Gadget

Post by Peyman »

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:

Code: Select all

123|-**-****
where "|" represents the caret.

I would like it to move past the "-" and look like this:

Code: Select all

123-|**-****
Thanks for your help!

Regards,
Eric
i add _xm_CheckStatic procedure for do this, check my post i repost the updated code. 8)
Sorry for my bad english.
ebs
Enthusiast
Enthusiast
Posts: 557
Joined: Fri Apr 25, 2003 11:08 pm

Re: xMask - A Masked Edit Gadget

Post by ebs »

Peyman wrote:i add _xm_CheckStatic procedure for do this, check my post i repost the updated code. 8)
Thank you - it works great! :P
Post Reply