StringGadget: Toggle Insert/Overwrite Mode

Just starting out? Need help? Post your questions and find answers here.
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

StringGadget: Toggle Insert/Overwrite Mode

Post by charvista »

Hi Rashad and all other PB friends :)
I am trying to complete a template program that consists of all the necessary elements to enhance the StringGadget with support for Insert/Overwrite toggling on more than one StringGadget.
I am still missing some elements...
1) How can I get the current position of the caret in the input field? This is necessary (a) to edit the line manually at the correct position and (2) to put the caret back at the same position after a character has been added or replaced (or deleted with Backspace).
2) After hitting the Ins-key several times, the blinking "image" of the underline caret does not blink, despite the API statement SetCaretBlinkTime_(200)... it blinks only again when a character is entered.
3) There is a line that reads Case _SGad(0),_SGad(1),_SGad(2)... As long there are few elements, no problems, but how can I simplify that line if there were 100 elements?
Thanks!

Code: Select all

Global _TGad
Global Dim _SGad(2)

Procedure.b zInsState()
    InsState.b=GetKeyState_(#PB_Shortcut_Insert)
    If InsState & 1
        Mode.s="OVR ("+Str(InsState)+")"
    Else
        Mode.s="INS ("+Str(InsState)+")"
    EndIf
    SetGadgetText(_TGad,Mode)
    ProcedureReturn InsState
EndProcedure

Font2=LoadFont(#PB_Any,"Courier",14)

CreateImage(0,18,20)
StartDrawing(ImageOutput(0))
    Box(0,17,10,3,$FFFFFF)
StopDrawing()

OpenWindow(0,0,0,300,200,"Toggle Insert/Overwrite",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    AddKeyboardShortcut(0, #PB_Shortcut_Insert,1045)
    _TGad=TextGadget(#PB_Any,200,150,100,20,"")

    InsState.b=zInsState()
    
    _SGad(0)=StringGadget(#PB_Any,10,10,280,26,"")
    SetGadgetFont(_SGad(0),FontID(Font2))
    
    _SGad(1)=StringGadget(#PB_Any,10,40,280,26,"")
    SetGadgetFont(_SGad(1),FontID(Font2))
    
    _SGad(2)=StringGadget(#PB_Any,10,70,280,26,"")
    SetGadgetFont(_SGad(2),FontID(Font2))
    
    SetActiveGadget(_SGad(0))
    
    Repeat
        Event=WaitWindowEvent()
        CurrentGadget=GetActiveGadget()
        If Event=#PB_Event_Gadget
            Select EventGadget()
                Case _SGad(0),_SGad(1),_SGad(2)
                    If EventType()=#PB_EventType_Change
                        ;get caret position <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        Select InsState
                            Case 0,-128
                                ;insert chr
                            Case -127
                                ;replace chr
                        EndSelect
                    EndIf
            EndSelect
        EndIf
        If Event=#PB_Event_Menu
            Select EventMenu()
                Case 1045
                    If zInsState() & 1
                        ;DestroyCaret_()
                        CreateCaret_(GadgetID(CurrentGadget),ImageID(0),0,0)
                        SetCaretBlinkTime_(200); immobile = -1, normal blinking = 500
                        ShowCaret_(GadgetID(CurrentGadget))
                    Else
                        ;DestroyCaret_()
                        CreateCaret_(GadgetID(CurrentGadget),0,10,20); second parameter: 0=solid block, 1=dotted block
                        SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
                        ShowCaret_(GadgetID(CurrentGadget))
                    EndIf
            EndSelect
        EndIf
    Until event = #PB_Event_CloseWindow
CloseWindow(0)
Edit: Line 47 was missing a 's' (I wrote InState instead of InsState). Makes a big difference! :oops:
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4954
Joined: Sun Apr 12, 2009 6:27 am

Re: StringGadget: Toggle Insert/Overwrite Mode

Post by RASHAD »

Hi

To get the position

Code: Select all

Debug  SendMessage_(GadgetID(CurrentGadget), #EM_GETSEL, 0, 0) >> 16
To Force Insert\Overwrite

Code: Select all


Global hook

Procedure EG_Column(Gadget)
  SendMessage_(GadgetID(gadget),#EM_EXGETSEL,0,Pos.CHARRANGE) 
  ProcedureReturn (Pos\cpMax-(SendMessage_(GadgetID(gadget),#EM_LINEINDEX,SendMessage_(GadgetID(gadget), #EM_EXLINEFROMCHAR,0,Pos\cpMin),0))+1) 
EndProcedure 

Procedure EG_Row(Gadget)
  SendMessage_(GadgetID(gadget),#EM_EXGETSEL,0,Pos.CHARRANGE) 
  ProcedureReturn SendMessage_(GadgetID(gadget),#EM_EXLINEFROMCHAR,0,Pos\cpMin)+1 
EndProcedure

Procedure.l KeyboardHook(nCode.i, wParam.i, lParam.i) 
  If nCode < 0 
    ProcedureReturn CallNextHookEx_(hook, nCode, wParam, lParam) 
  EndIf
    If wParam = #VK_INSERT Or wParam = #VK_NUMPAD0 
    ProcedureReturn 1
  EndIf 
ProcedureReturn CallNextHookEx_(hook, nCode, wParam, lParam) 
EndProcedure 

OpenWindow(0, 200, 200, 400, 240,"Editor Test", #PB_Window_SystemMenu| #PB_Window_MinimizeGadget| #PB_Window_MaximizeGadget| #PB_Window_ScreenCentered)

CreateStatusBar(0, WindowID(0))
      AddStatusBarField(60)
      AddStatusBarField(40)
      AddStatusBarField(60)
      AddStatusBarField(40)
      AddStatusBarField(50)
      AddStatusBarField(40)
      
      StatusBarText(0, 0, "Line : ")
      StatusBarText(0, 2, "Column: ")
      StatusBarText(0, 4, "Mode :")
      StatusBarText(0, 5, "Insert")

EditorGadget(1,0,0, 400, 180)
SendMessage_(GadgetID(1), #EM_SETTARGETDEVICE, 0, 0)

Text$="{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fswiss\fcharset0 Arial;}}{\colortbl ;\red255\green0\blue0;\red0\green0\blue0;}"
Text$ = Text$ + "{\*\generator Msftedit 5.41.15.1503;}\viewkind4\uc1\pard\f0\fs20 Hello, this is \cf1\b\fs32 RTF\cf2\b0\fs20 direct!\cf0\par}"

SetGadgetText(1, Text$)
ButtonGadget(2,5,185,80,24,"Toggle",#PB_Button_Toggle)

Repeat
    StatusBarText(0, 1,Str(EG_Row(1)))
    StatusBarText(0, 3,Str(EG_Column(1)))
  
  Select WaitWindowEvent()
       
      Case #PB_Event_CloseWindow
          Q =1 
      
      Case #PB_Event_Gadget 
          Select EventGadget()
            Case 2
                If GetGadgetState(2) = 0
                  StatusBarText(0, 5, "Insert")
                Else
                  StatusBarText(0, 5, "Over")
                EndIf
                UnhookWindowsHookEx_(hook)
                SendMessage_(GadgetID(1), #WM_KEYDOWN, #VK_INSERT, 0)
                SendMessage_(GadgetID(1), #WM_KEYUP, #VK_INSERT, 0)
                SetActiveGadget(1)
                hook = SetWindowsHookEx_(#WH_KEYBOARD, @KeyboardHook(),GetModuleHandle_(0), GetWindowThreadProcessId_(WindowID(0), 0))

           
          EndSelect
  EndSelect
Until Q = 1
UnhookWindowsHookEx_(hook)

Egypt my love
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: StringGadget: Toggle Insert/Overwrite Mode

Post by Danilo »

Another thing you may like is a textual cue (tip that is displayed by the edit control to prompt the user for information).
It is displayed in background while there is no text in the StringGadget.

Requires WindowsXP or later and XP skin enabled in compiler options.

Code: Select all

Procedure SetStringGadgetTip(gadget,text$)
    Protected temp$
    CompilerIf #PB_Compiler_Unicode
        tmp$ = text$
    CompilerElse
        Protected len  = Len(text$)
        tmp$ = Space(len*2+2)
        PokeS(@tmp$,text$,len,#PB_Unicode)
    CompilerEndIf
    SendMessage_(GadgetID(gadget),#EM_SETCUEBANNER,#True,@tmp$)
EndProcedure

If OpenWindow(0, 0, 0, 322, 205, "StringGadget Flags", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

    StringGadget(0, 8,  10, 306, 20, "")
    SetStringGadgetTip(0,"Enter your name")

    StringGadget(1, 8,  35, 306, 20, "", #PB_String_Numeric)
    SetStringGadgetTip(1,"Enter your phone number")

    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

Re: StringGadget: Toggle Insert/Overwrite Mode

Post by charvista »

@Rashad Hi
As usually my thanks for your help. To get the position worked fine. However, I had trouble to force Insert/Overwrite on my String Gadgets. But never mind, I used a simple Toggle variable and it works fine now.

Code: Select all

Global Dim _SGad(2)

Procedure.i zInsState(TGad,InsState)
    If InsState=1
        Mode.s="OVR ("+Str(InsState)+")"
    Else
        Mode.s="INS ("+Str(InsState)+")"
    EndIf
    SetGadgetText(TGad,Mode)
EndProcedure

Procedure zGetGadgetArrayPos(CurrentGadget,Array SGad.i(1))
    Ubound=ArraySize(SGad())
    GadgetArrayPos=-1
    For i=0 To Ubound
        If SGad(i)=CurrentGadget
            GadgetArrayPos=i
            Break
        EndIf
    Next i
    ProcedureReturn GadgetArrayPos
EndProcedure

Procedure SetStringGadgetTip(Gadget,Text$)
    Protected temp$
    CompilerIf #PB_Compiler_Unicode
        tmp$=Text$
    CompilerElse
        Protected length=Len(Text$)
        tmp$=Space(length*2+2)
        PokeS(@tmp$,Text$,length,#PB_Unicode)
    CompilerEndIf
    SendMessage_(GadgetID(Gadget),#EM_SETCUEBANNER,#True,@tmp$)
EndProcedure

Font2=LoadFont(#PB_Any,"Courier",14)

CreateImage(0,18,20)
StartDrawing(ImageOutput(0))
    Box(0,17,10,3,$FFFFFF)
StopDrawing()

Win=OpenWindow(#PB_Any,0,0,300,200,"Toggle Insert/Overwrite",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    AddKeyboardShortcut(Win, #PB_Shortcut_Insert,1045)
    TGad=TextGadget(#PB_Any,200,150,100,20,"")

    InsState.b=0; initialize with 0 (insert)
    
    _SGad(0)=StringGadget(#PB_Any,10,10,280,26,"")
    SetStringGadgetTip(_SGad(0),"Enter your name")
    SetGadgetFont(_SGad(0),FontID(Font2))
    
    _SGad(1)=StringGadget(#PB_Any,10,40,280,26,"",#PB_String_Password)
    SetStringGadgetTip(_SGad(1),"Password")
    SetGadgetFont(_SGad(1),FontID(Font2))
    
    _SGad(2)=StringGadget(#PB_Any,10,70,280,26,"",#PB_String_Numeric)
    SetStringGadgetTip(_SGad(2),"Enter your phone number")
    SetGadgetFont(_SGad(2),FontID(Font2))
    
    SetActiveGadget(_SGad(0))
    zInsState(TGad,InsState)
    
    Repeat
        Event=WaitWindowEvent()
        If CurrentGadget<>GetActiveGadget()
            Agad=zGetGadgetArrayPos(GetActiveGadget(),_SGad())
            DestroyCaret_()
            CreateCaret_(GadgetID(_SGad(Agad)),0,10,20); insert caret; second parameter: 0=solid block, 1=dotted block
            SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
            ShowCaret_(GadgetID(_SGad(Agad)))
            InsState=0
            zInsState(TGad,InsState)
        EndIf
        CurrentGadget=GetActiveGadget(); get gadget number
        GadgetArrayPos=zGetGadgetArrayPos(CurrentGadget,_SGad()); get array pos based on gadget number
        If Event=#PB_Event_Gadget
            Select EventGadget()
                Case _SGad(0),_SGad(1),_SGad(2)
                    If EventType()=#PB_EventType_Change
                        CurrentCaretPos=SendMessage_(GadgetID(CurrentGadget),#EM_GETSEL,0,0)>>16
                        Select InsState
                            Case 1; overwrite
                                V.s=GetGadgetText(_SGad(GadgetArrayPos))
                                V.s=Left(V.s,CurrentCaretPos)+Mid(V.s,CurrentCaretPos+2)
                                SetGadgetText(_SGad(GadgetArrayPos),V.s)
                                SendMessage_(GadgetID(CurrentGadget),#EM_SETSEL,CurrentCaretPos,CurrentCaretPos); set caret back where he was
                        EndSelect
                    EndIf
            EndSelect
        EndIf
        If Event=#PB_Event_Menu
            Select EventMenu()
                Case 1045
                    If InsState=0
                        InsState=1
                        ;DestroyCaret_()
                        CreateCaret_(GadgetID(CurrentGadget),ImageID(0),0,0); overwrite caret
                        SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
                        ShowCaret_(GadgetID(CurrentGadget))
                    Else
                        InsState=0
                        ;DestroyCaret_()
                        CreateCaret_(GadgetID(CurrentGadget),0,10,20); insert caret; second parameter: 0=solid block, 1=dotted block
                        SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
                        ShowCaret_(GadgetID(CurrentGadget))
                    EndIf
                    zInsState(TGad,InsState)
            EndSelect
        EndIf
    Until Event=#PB_Event_CloseWindow
CloseWindow(Win))
@Danilo
Much appreciated your code! This is how the word "Password" is showed in the input field when we start Windows Vista or 7.
I included it in my example - as an example! :mrgreen:
I wonder if we can use another font for the tip, or another color?

Cheers!
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
User avatar
Lord
Addict
Addict
Posts: 907
Joined: Tue May 26, 2009 2:11 pm

Re: StringGadget: Toggle Insert/Overwrite Mode

Post by Lord »

Hi charvista!

There is a little problem in your code.

If you leave your window, the variable Agad gets negative.
So an Array-Index out of bounds Error occurs if you use
_SGad(Agad) on line 70.
Just use

Code: Select all

        If CurrentGadget<>GetActiveGadget()
          Agad=GetGadgetArrayPos(GetActiveGadget(),_SGad())
          If Agad>-1
            DestroyCaret_()
            CreateCaret_(GadgetID(_SGad(Agad)),0,10,20); insert caret; second parameter: 0=solid block, 1=dotted block
            SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
            ShowCaret_(GadgetID(_SGad(Agad)))
            InsState=0
            zInsState(TGad,InsState)
          EndIf
        EndIf
Image
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

Re: StringGadget: Toggle Insert/Overwrite Mode

Post by charvista »

Hi Lord!
You are right! It was indeed a little problem! :mrgreen:
Thank you for taking your time and for the correction.
I have corrected and added an old feature that also originates from Danilo: the ability to change the background color whenever the user changed the input contents.
Here I have added a gradual background color for the password. The longer the password, the better, thus the greener. The formule I used is not ideal for all color combinations (red to green gives black background - if someone has a better formula, please tell us!)
Enjoy!

Code: Select all

Global Dim _SGad(2)

Procedure.i zInsState(TGad,InsState)
    If InsState=1
        Mode.s="OVR ("+Str(InsState)+")"
    Else
        Mode.s="INS ("+Str(InsState)+")"
    EndIf
    SetGadgetText(TGad,Mode)
EndProcedure

Procedure zGetGadgetArrayPos(CurrentGadget,Array SGad.i(1))
    Ubound=ArraySize(SGad())
    GadgetArrayPos=-1
    For i=0 To Ubound
        If SGad(i)=CurrentGadget
            GadgetArrayPos=i
            Break
        EndIf
    Next i
    ProcedureReturn GadgetArrayPos
EndProcedure

Procedure SetStringGadgetTip(Gadget,Text$)
    Protected temp$
    CompilerIf #PB_Compiler_Unicode
        tmp$=Text$
    CompilerElse
        Protected length=Len(Text$)
        tmp$=Space(length*2+2)
        PokeS(@tmp$,Text$,length,#PB_Unicode)
    CompilerEndIf
    SendMessage_(GadgetID(Gadget),#EM_SETCUEBANNER,#True,@tmp$)
EndProcedure

Procedure.d zStrength(StartColor,StopColor,MaxStrength,CurrentStrength)
    ProcedureReturn StartColor+(StopColor-StartColor)/(MaxStrength-1)*(CurrentStrength-1)
EndProcedure



Font2=LoadFont(#PB_Any,"Courier",14)

CreateImage(0,18,20)
StartDrawing(ImageOutput(0))
    Box(0,17,10,3,$FFFFFF)
StopDrawing()

Win=OpenWindow(#PB_Any,0,0,300,200,"Toggle Insert/Overwrite",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    AddKeyboardShortcut(Win, #PB_Shortcut_Insert,1045)
    TGad=TextGadget(#PB_Any,200,150,100,20,"")

    InsState.b=0; initialize with 0 (insert)
    
    _SGad(0)=StringGadget(#PB_Any,10,10,280,26,"")
    SetStringGadgetTip(_SGad(0),"Enter your name")
    SetGadgetFont(_SGad(0),FontID(Font2))
    
    _SGad(1)=StringGadget(#PB_Any,10,40,280,26,"",#PB_String_Password)
    SetStringGadgetTip(_SGad(1),"Password")
    SetGadgetFont(_SGad(1),FontID(Font2))
    SendMessage_(GadgetID(_SGad(1)),#EM_SETLIMITTEXT,12,0); limit the input length to 12
    ; Check length of the password (initial)
    If Len(GetGadgetText(_SGad(1)))=0; no password (yet)
        SetGadgetColor(_SGad(1),#PB_Gadget_BackColor,$FFFFFF); background white
    ElseIf Len(GetGadgetText(_SGad(1)))>0 And Len(GetGadgetText(_SGad(1)))<=4
        SetGadgetColor(_SGad(1),#PB_Gadget_BackColor,$0000FF); background red
    ElseIf Len(GetGadgetText(_SGad(1)))>4 And Len(GetGadgetText(_SGad(1)))<9
        SetGadgetColor(_SGad(1),#PB_Gadget_BackColor,$00FFFF); background yellow
    Else
        SetGadgetColor(_SGad(1),#PB_Gadget_BackColor,$00FF00); background green
    EndIf
    
    
    _SGad(2)=StringGadget(#PB_Any,10,70,280,26,"",#PB_String_Numeric)
    SetStringGadgetTip(_SGad(2),"Enter your phone number")
    SetGadgetFont(_SGad(2),FontID(Font2))
    
    SetActiveGadget(_SGad(0))
    zInsState(TGad,InsState)
    
    
    Repeat
        Event=WaitWindowEvent()
        If CurrentGadget<>GetActiveGadget()
            Agad=zGetGadgetArrayPos(GetActiveGadget(),_SGad())
            If Agad>-1
                DestroyCaret_()
                CreateCaret_(GadgetID(_SGad(Agad)),0,10,20); insert caret; second parameter: 0=solid block, 1=dotted block
                SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
                ShowCaret_(GadgetID(_SGad(Agad)))
                InsState=0
                zInsState(TGad,InsState)
            EndIf
        EndIf
        CurrentGadget=GetActiveGadget(); get gadget number
        GadgetArrayPos=zGetGadgetArrayPos(CurrentGadget,_SGad()); get array pos based on gadget number
        If Event=#PB_Event_Gadget
            Select EventGadget()
                Case _SGad(0),_SGad(1),_SGad(2)
                    If EventType()=#PB_EventType_Change
                        ; Check length of the password
                        If Len(GetGadgetText(_SGad(1)))=0; no password (yet)
                            SetGadgetColor(_SGad(1),#PB_Gadget_BackColor,$FFFFFF); background white
                        Else
                            SetGadgetColor(_SGad(1),#PB_Gadget_BackColor,Int(zStrength($00FFFF,$00FF00,12,Len(GetGadgetText(_SGad(1)))))); gradual background
                        EndIf
                        ; Check caret
                        CurrentCaretPos=SendMessage_(GadgetID(CurrentGadget),#EM_GETSEL,0,0)>>16; get the current caret position
                        Select InsState
                            Case 1; overwrite
                                V.s=GetGadgetText(_SGad(GadgetArrayPos))
                                V.s=Left(V.s,CurrentCaretPos)+Mid(V.s,CurrentCaretPos+2)
                                SetGadgetText(_SGad(GadgetArrayPos),V.s)
                                SendMessage_(GadgetID(CurrentGadget),#EM_SETSEL,CurrentCaretPos,CurrentCaretPos); put caret back where he was
                        EndSelect
                    EndIf
            EndSelect
        EndIf
        If Event=#PB_Event_Menu
            Select EventMenu()
                Case 1045
                    If InsState=0
                        InsState=1
                        ;DestroyCaret_()
                        CreateCaret_(GadgetID(CurrentGadget),ImageID(0),0,0); overwrite caret
                        SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
                        ShowCaret_(GadgetID(CurrentGadget))
                    Else
                        InsState=0
                        ;DestroyCaret_()
                        CreateCaret_(GadgetID(CurrentGadget),0,10,20); insert caret; second parameter: 0=solid block, 1=dotted block
                        SetCaretBlinkTime_(-1); immobile = -1, normal blinking = 500
                        ShowCaret_(GadgetID(CurrentGadget))
                    EndIf
                    zInsState(TGad,InsState)
            EndSelect
        EndIf
    Until Event=#PB_Event_CloseWindow
CloseWindow(Win)
Cheers
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
Post Reply