StringGadget for passwords - toggle '*'?

Just starting out? Need help? Post your questions and find answers here.
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

StringGadget for passwords - toggle '*'?

Post by jassing »

I need to be able to toggle a string gadget's "*" -- can this be done?
User avatar
Kiffi
Addict
Addict
Posts: 1485
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Re: StringGadget for passwords - toggle '*'?

Post by Kiffi »

jassing wrote:can this be done?
yes, of course:

Code: Select all

Enumeration
  #myWindow
EndEnumeration
Enumeration
  #myPasswortField
  #chkToggle
EndEnumeration

If OpenWindow(#myWindow, #PB_Ignore, #PB_Ignore, 300, 100, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
  
  TextGadget(#PB_Any, 5, 5, 70, 30, "Password:")  
  StringGadget(#myPasswortField, 80, 5, 200, 30, "mySecretPassword", #PB_String_Password)
  CheckBoxGadget(#chkToggle, 5, 40, 200, 30, "Show Password")
  
  Repeat
    
    Select WaitWindowEvent()
        
      Case #PB_Event_Gadget
        
        Select EventGadget()
            
          Case #chkToggle
            If GetGadgetState(#chkToggle)
              StringGadget(#myPasswortField, 80, 5, 200, 30, GetGadgetText(#myPasswortField))
            Else
              StringGadget(#myPasswortField, 80, 5, 200, 30, GetGadgetText(#myPasswortField), #PB_String_Password)
            EndIf
            
        EndSelect
        
      Case #PB_Event_CloseWindow
        Break
        
    EndSelect
    
  ForEver
  
EndIf
Greetings ... Kiffi
Hygge
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: StringGadget for passwords - toggle '*'?

Post by Shardik »

It is not necessary to always recreate the complete StringGadget as in Kiffi's example
although Kiffi's example doesn't use API calls and therefore is usable cross-platform.
My example uses Windows API calls and therefore is only usable in Windows:

Code: Select all

OpenWindow(0, 20, 20, 150, 70, "Toggle password")
StringGadget(0, 30, 10, 80, 20, "Test", #PB_String_Password)
ButtonGadget(1, 10, 40, 130, 20, "Toggle password mode")

PasswordChar = SendMessage_(GadgetID(0), #EM_GETPASSWORDCHAR, 0, 0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 1
        If GetWindowLong_(GadgetID(0), #GWL_STYLE) & #ES_PASSWORD
          SendMessage_(GadgetID(0), #EM_SETPASSWORDCHAR, 0, 0)
        Else
          SendMessage_(GadgetID(0), #EM_SETPASSWORDCHAR, PasswordChar, 0)
        EndIf

        InvalidateRect_(GadgetID(0), 0, 1)
      EndIf
  EndSelect
ForEver
If you have XP-Style activated you also have to activate "Create unicode executable"
in "Compiler Options" to get back your initial password character:
MSDN wrote:Windows XP: If an edit control is from user32.dll, an asterisk is the default character for the ES_PASSWORD style. However, if an edit control is from comctl32.dll version 6, a black circle is the default character for the ES_PASSWORD style. Note that comctl32.dll version 6 is not redistributable but is included with Windows XP or later. To use comctl32.dll version 6, specify it in a manifest.
User avatar
Kiffi
Addict
Addict
Posts: 1485
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Re: StringGadget for passwords - toggle '*'?

Post by Kiffi »

Shardik wrote:although Kiffi's example doesn't use API calls and therefore is usable cross-platform.
yes, that was my intention.

Greetings ... Kiffi (developing currently under Ubuntu)
Hygge
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: StringGadget for passwords - toggle '*'?

Post by Shardik »

Kiffi wrote:Greetings ... Kiffi (developing currently under Ubuntu)
In Linux using API is even shorter and easier than in Windows: :wink:

Code: Select all

OpenWindow(0, 20, 20, 200, 70, "Toggle password")
StringGadget(0, 50, 10, 100, 20, "Test", #PB_String_Password)
ButtonGadget(1, 10, 40, 180, 23, "Toggle password mode")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 1
        gtk_entry_set_visibility_(GadgetID(0), gtk_entry_get_visibility_(GadgetID(0)) ! 1)
      EndIf
  EndSelect
ForEver
With Kiffi's cross-platform example one should always keep in mind that the redefinition
of Gadgets is only possible with static Gadget-IDs. So reusing dynamic Gadget-IDs created
with #PB_Any is not possible (see explanation by Trond):
http://www.purebasic.fr/english/viewtop ... 03&start=3
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: StringGadget for passwords - toggle '*'?

Post by jassing »

Thank you -- Yes, I need to retain cross platform.. so I need to avoid api's.
thank you both for your examples.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: StringGadget for passwords - toggle '*'?

Post by Shardik »

jassing wrote:Yes, I need to retain cross platform.. so I need to avoid api's.
You only need to avoid API calls if you don't have API solutions for all platforms
at hand. :wink: If you only need to support Windows and Linux, you can combine my
two example codes into one:

Code: Select all

EnableExplicit

Procedure TogglePasswordVisibility()
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      gtk_entry_set_visibility_(GadgetID(0), gtk_entry_get_visibility_(GadgetID(0)) ! 1)
    CompilerCase #PB_OS_Windows
      Static PasswordChar
      Static PasswordCharIsKnown

      If PasswordCharIsKnown = #False
        PasswordChar = SendMessage_(GadgetID(0), #EM_GETPASSWORDCHAR, 0, 0)
        PasswordCharIsKnown = #True
      EndIf

      If GetWindowLong_(GadgetID(0), #GWL_STYLE) & #ES_PASSWORD
        SendMessage_(GadgetID(0), #EM_SETPASSWORDCHAR, 0, 0)
      Else
        SendMessage_(GadgetID(0), #EM_SETPASSWORDCHAR, PasswordChar, 0)
      EndIf

      InvalidateRect_(GadgetID(0), 0, 1)
  CompilerEndSelect
EndProcedure

OpenWindow(0, 20, 20, 200, 70, "Toggle password mode")
StringGadget(0, 50, 10, 100, 20, "Test", #PB_String_Password)
ButtonGadget(1, 10, 40, 180, 23, "Toggle password mode")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 1
        TogglePasswordVisibility()
      EndIf
  EndSelect
ForEver
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Re: StringGadget for passwords - toggle '*'?

Post by Baldrick »

Kiffi's original snippet shortened slightly with a bitshift eliminating the 'If' statement. ( no real reason why I did this. Just a little bored & playing silly buggers atm...) :)

Code: Select all

Enumeration
  #myWindow
EndEnumeration
Enumeration
  #myPasswortField
  #chkToggle
EndEnumeration

If OpenWindow(#myWindow, #PB_Ignore, #PB_Ignore, 300, 100, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
 
  TextGadget(#PB_Any, 5, 5, 70, 30, "Password:") 
  StringGadget(#myPasswortField, 80, 5, 200, 30, "mySecretPassword", #PB_String_Password)
  CheckBoxGadget(#chkToggle, 5, 40, 200, 30, "Show Password")
  Repeat
   
    Select WaitWindowEvent()
      Case #PB_Event_Gadget
        Select EventGadget() 
          Case #chkToggle
              StringGadget(#myPasswortField, 80, 5, 200, 30, GetGadgetText(#myPasswortField),#PB_String_Password-GetGadgetState(#chkToggle)<<5)
        EndSelect
      Case #PB_Event_CloseWindow
        Break
    EndSelect
   
  ForEver
 
EndIf
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: StringGadget for passwords - toggle '*'?

Post by Vera »

Thanks for this interesting thread :)

@ Baldrick
to maintain crossplatform capability << 5 needs to be exchanged with | #PB_String_BorderLess :wink:
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Re: StringGadget for passwords - toggle '*'?

Post by Baldrick »

Vera wrote:Thanks for this interesting thread :)

@ Baldrick
to maintain crossplatform capability << 5 needs to be exchanged with | #PB_String_BorderLess :wink:
Not sure what you mean here Vera. All I am doing really is using the '0' or '1' value from a checkbox gadget & bitshifting that value to be used in the stringgadget flags. It will work with multiple flags as per this snippet below which is doing the same thing using multiple flags on the stringgadget() or whatever other gadget that supports flags, which allow modification on the fly.
Am I missing something?

Code: Select all

Enumeration
  #myWindow
EndEnumeration
Enumeration
  #myPasswortField
  #chkToggle
  #chkReadOnly
  #chkBorder
EndEnumeration
PassShift=CountString(Bin(#PB_String_Password),"0") ; set variables for number of places to shift checkbox status values
ReadOnlyShift=CountString(Bin(#PB_String_ReadOnly),"0") ; called at start of app is sufficient
BorderShift=CountString(Bin(#PB_String_BorderLess),"0") ; no need to call continually
If OpenWindow(#myWindow, #PB_Ignore, #PB_Ignore, 300, 100, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
  TextGadget(#PB_Any, 5, 5, 70, 30, "Password:")
  StringGadget(#myPasswortField, 80, 5, 200, 30, "mySecretPassword", #PB_String_Password); #PB_String_Password see note below
  CheckBoxGadget(#chkToggle, 5, 40, 100, 30, "Show Password")
  CheckBoxGadget(#chkReadOnly, 110, 40, 100, 30, "Read Only")
  CheckBoxGadget(#chkBorder, 5, 70, 100, 30, "Hide Border")
  Repeat 
    Select WaitWindowEvent()
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #chkToggle,#chkReadOnly,#chkBorder ; the checkboxes we need to watch & recalculate when any of them change state
            Password=#PB_String_Password-GetGadgetState(#chkToggle)<<PassShift
            ;password is calculated differently because it is set to hide as default with this window.
            ;If it was worded as 'Hide Password'& password flag not set, then you would not do the subtraction calculation
            ;i.e. GetGadgetState(#chkToggle)<<PassShift
            ReadOnly=GetGadgetState(#chkReadOnly)<<ReadOnlyShift
            Border=GetGadgetState(#chkBorder)<<BorderShift
            FlagOptions=Password|ReadOnly|Border  ; Bitwise Or your new values together
            StringGadget(#myPasswortField, 80, 5, 200, 30, GetGadgetText(#myPasswortField),FlagOptions); set gadget with new flag options
              
        EndSelect
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
EndIf
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: StringGadget for passwords - toggle '*'?

Post by Vera »

Baldrick wrote:Not sure what you mean here Vera.
I meant, that the values of the #PB_constants vary on the platforms, so '5' doesn't work on Linux. (It toggles the border but not the password)
If you'd insert the following you can make out the differences:

Debug PassShift ; win=5 - linux=0
Debug ReadOnlyShift ; win=11 - linux=1
Debug BorderShift ; win=17 - linux=5

toggle checkbox on/off
Debug ReadOnly ; win=2048/0 - linux=2/0
Debug Border ; win=131072/0 - linux=32/0
Debug FlagOptions ; win=0/32 - linux=0/1 (only toggle password)


and thanks for your commented enhanced code. It works straight and again gives me some more insights :)

greeting ~ Vera
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Re: StringGadget for passwords - toggle '*'?

Post by Baldrick »

Vera wrote:
Baldrick wrote:Not sure what you mean here Vera.
I meant, that the values of the #PB_constants vary on the platforms, so '5' doesn't work on Linux. (It toggles the border but not the password)
If you'd insert the following you can make out the differences:
Another of those "Ahaaa" moments for me Vera.
Thanks for that information :)
Nb: I must fix my Linux machine 1 of these days so I can test these things...... :P ( Don't any1 try to tell me Linux can't cop a virus, I am sure my Ubuntu has been attacked!!!!! Actually couldn't really care less, I will just reformat when I get around to it :) )
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: StringGadget for passwords - toggle '*'?

Post by Little John »

Shardik wrote:You only need to avoid API calls if you don't have API solutions for all platforms
at hand. :wink: If you only need to support Windows and Linux, you can combine my
two example codes into one:
Shardik, many thanks for that code! That's what I need at the moment. :-)

I've got two suggestions for improvement.
Shardik wrote:

Code: Select all

    CompilerCase #PB_OS_Windows
      [...]
      If GetWindowLong_(GadgetID(0), #GWL_STYLE) & #ES_PASSWORD
      [...]
GetWindowLong_() should be replaced with GetWindowLongPtr_().
[u]PureBasic Team Blog[/u] wrote:Do NOT use Get/SetWindowLong_() for subclassing anymore. These remain 32bit even on x64. Use Get/SetWindowLongPtr_() instead, which works correctly everywhere. There is really no need to use SetWindowLong_() over SetWindowLongPtr_() actually, so best do a search and replace and replace all of them right away.
Another problem is, that your fine TogglePasswordVisibility() procedure currently only works in the special case for a string gadget with number 0. For general usage, the procedure should take a gadget number as parameter (say 'gad'), and then inside the procedure replace GadgetID(0) with GadgetID(gad).

Thanks again!
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: StringGadget for passwords - toggle '*'?

Post by RASHAD »

Cross Platform

Code: Select all


If OpenWindow(0, 0,0, 300, 100, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
 
  StringGadget(0, 10, 10, 200, 20, "mySecretPassword",#PB_String_Password)
  toggle = StringGadget(#PB_Any, 10, 10, 200, 20, "mySecretPassword")
  ButtonGadget(3,10,65,60,25,"Toggle")
  HideGadget(toggle,1) 
  
  Repeat
   
    Select WaitWindowEvent()
       
      Case #PB_Event_Gadget
       
        Select EventGadget()           
          Case 0
            SetGadgetText(toggle,GetGadgetText(0))
            
          Case toggle
            SetGadgetText(0,GetGadgetText(toggle))
          
          Case 3
            run ! 1
            If Run = 1
              HideGadget(0,1)
              HideGadget(toggle,0)
            Else
              HideGadget(toggle,1)
              HideGadget(0,0)
            EndIf
            
        EndSelect
       
      Case #PB_Event_CloseWindow
        Break
       
    EndSelect
   
  ForEver
 
EndIf
Egypt my love
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: StringGadget for passwords - toggle '*'?

Post by Shardik »

Little John wrote:Shardik, many thanks for that code! That's what I need at the moment. :-)
I am glad that my code example was usefull for you.
Little John wrote:
Shardik wrote:

Code: Select all

    CompilerCase #PB_OS_Windows
      [...]
      If GetWindowLong_(GadgetID(0), #GWL_STYLE) & #ES_PASSWORD
      [...]
GetWindowLong_() should be replaced with GetWindowLongPtr_().
[u]PureBasic Team Blog[/u] wrote:Do NOT use Get/SetWindowLong_() for subclassing anymore. These remain 32bit even on x64. Use Get/SetWindowLongPtr_() instead, which works correctly everywhere. There is really no need to use SetWindowLong_() over SetWindowLongPtr_() actually, so best do a search and replace and replace all of them right away.
Thank you for reminding me about still having used GetWindowLong() in my code example from December 2010. But in June 2011 I already proposed to use GetWindowLongPtr() by myself in this posting citing MSDN... :D
Little John wrote:Another problem is, that your fine TogglePasswordVisibility() procedure currently only works in the special case for a string gadget with number 0. For general usage, the procedure should take a gadget number as parameter (say 'gad'), and then inside the procedure replace GadgetID(0) with GadgetID(gad).
Again you're right. I therefore adapted my code example and even added the MacOS part (which was the most difficult one because I had to mess around with PureBasic and Cocoa framework internals). Below is my now true cross-platform example tested successfully on the following operating systems:
- Linux Mint 17.3 'Sylvia' x64 with Cinnamon using PB 5.46 x64 in ASCII- and Unicode mode with Gtk2 and Gtk3
- MacOS 10.6.8 'Snow Leopard' using PB 5.46 x86 in ASCII- and Unicode mode
- MacOS 10.13.6 'High Sierra' using PB 5.46 x64 in ASCII- and Unicode mode
- Windows 7 SP1 x64 using PB 5.46 x86 in Unicode mode (ASCII mode doesn't work!)
- Windows 10 x64 1809 using PB 5.46 x86 and x64 in Unicode mode (ASCII mode doesn't work!)
- Xubuntu 18.04 x86 using PB 5.70 x86 with Gtk2, Gtk3 and Qt

Warning: although you have to call TogglePasswordVisibility() now with the number of your StringGadget, the procedure currently doesn't allow to work with more than one encrypted StringGadget cross-platform. On MacOS it would be necessary to define an array holding the different cells for each StringGadget and on Windows the Static variables would have to be taken care of. For the sake of keeping the example as easy and short as possible, I have not implemented this feature.

Update: I have added wombat's code to also support the new Qt subsystem in Linux.

Code: Select all

EnableExplicit

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  Define SecuredPasswordCell.I
  Define VisiblePasswordCell.I
CompilerEndIf

Procedure TogglePasswordVisibility(StringGadgetID.I)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      CompilerIf Subsystem("qt")
        If Val(QtScript("gadget(" + Str(StringGadgetID) + ").echoMode")) = 2
          QtScript("gadget(" + Str(StringGadgetID) + ").echoMode = 0")
        ElseIf Val(QtScript("gadget(" + Str(StringGadgetID) + ").echoMode")) = 0
          QtScript("gadget(" + Str(StringGadgetID) + ").echoMode = 2")
        EndIf
      CompilerElse
        gtk_entry_set_visibility_(GadgetID(StringGadgetID),
          gtk_entry_get_visibility_(GadgetID(StringGadgetID)) ! 1)
      CompilerEndIf
    CompilerCase #PB_OS_MacOS
      Shared SecuredPasswordCell.I
      Shared VisiblePasswordCell.I
      
      Protected Cell.I
      Protected Password.S

      Password = GetGadgetText(StringGadgetID)
      
      If PeekS(CocoaMessage(0, CocoaMessage(0, CocoaMessage(0,
        GadgetID(StringGadgetID), "cell"), "className"), "UTF8String"),
        -1, #PB_UTF8) = "NSSecureTextFieldCell"
        If VisiblePasswordCell = 0
          SecuredPasswordCell = CocoaMessage(0, GadgetID(StringGadgetID),
            "cell")
          CocoaMessage(0, SecuredPasswordCell, "retain")
          VisiblePasswordCell = CocoaMessage(0, CocoaMessage(0,
            CocoaMessage(0, 0, "NSTextField alloc"), "initWithFrame:", 0),
            "cell")
          CocoaMessage(0, VisiblePasswordCell, "retain")
        EndIf
        
        CocoaMessage(0, GadgetID(StringGadgetID),
          "setCell:", VisiblePasswordCell)
        CocoaMessage(0, VisiblePasswordCell, "setStringValue:$", @Password)
        CocoaMessage(0, GadgetID(StringGadgetID), "setNeedsDisplay:", #YES)
      Else
        If SecuredPasswordCell
          CocoaMessage(0, GadgetID(StringGadgetID),
            "setCell:", SecuredPasswordCell)
          CocoaMessage(0, SecuredPasswordCell, "setStringValue:$", @Password)
          CocoaMessage(0, GadgetID(StringGadgetID), "setNeedsDisplay:", #YES)
        EndIf
      EndIf
    CompilerCase #PB_OS_Windows
      Static PasswordChar
      Static PasswordCharIsKnown

      If PasswordCharIsKnown = #False
        PasswordChar = SendMessage_(GadgetID(StringGadgetID),
          #EM_GETPASSWORDCHAR, 0, 0)
        PasswordCharIsKnown = #True
      EndIf

      If GetWindowLongPtr_(GadgetID(StringGadgetID),
        #GWL_STYLE) & #ES_PASSWORD
        SendMessage_(GadgetID(StringGadgetID), #EM_SETPASSWORDCHAR, 0, 0)
      Else
        SendMessage_(GadgetID(StringGadgetID), #EM_SETPASSWORDCHAR,
          PasswordChar, 0)
      EndIf

      InvalidateRect_(GadgetID(StringGadgetID), 0, 1)
  CompilerEndSelect
EndProcedure

OpenWindow(0, 270, 100, 250, 90, "Toggle password visibility")
StringGadget(0, 40, 20, 180, 20, "Test", #PB_String_Password)
ButtonGadget(1, 40, 55, 180, 25, "Toggle password visibility")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
        CocoaMessage(0, VisiblePasswordCell, "release")
      CompilerEndIf
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 1
        ; ----- Only necessary for MacOS to work correctly after adding or
        ;       deleting characters
        SetActiveGadget(-1)

        TogglePasswordVisibility(0)
      EndIf
  EndSelect
ForEver
Last edited by Shardik on Mon Mar 25, 2019 2:21 pm, edited 4 times in total.
Post Reply