Converting some Windows code to Cocoa... Does anyone know how to achieve these two StringGadget functions?
1. "Select All" a StringGadget, equivalent to Windows #EM_SETSEL
2. Replace selection (could be empty) with a string, equivalent to #EM_REPLACESEL
Thanks for any help!
Cocoa StringGadget functions
Re: Cocoa StringGadget functions
I had this in my notes and I think it is from wilbert. (Maybe it should be added to the 'Cocoa - Methods, Tips & Tricks' thread?)
Code: Select all
EnableExplicit
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
Global NSRangeZero.NSRange
Procedure.i TextEditor(Gadget.i)
Protected TextField.i = GadgetID(Gadget)
Protected Window.i = CocoaMessage(0, TextField, "window")
ProcedureReturn CocoaMessage(0, Window, "fieldEditor:", #YES, "forObject:", TextField)
EndProcedure
CompilerEndIf
; Sets the selection in a StringGadget() independent of Operating System
; If Start.i < 1, every selectionis removed.
; If Length.i = 0, only the cursor is set.
Procedure SetStringGadgetSelection(GadgetID.i, Start.i, Length.i)
If Start.i > 0 And Length.i > -1
; Set selection
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
SendMessage_(GadgetID(GadgetID.i), #EM_SETSEL, Start.i - 1, Start.i + Length.i - 1)
CompilerCase #PB_OS_Linux
; TODO
CompilerCase #PB_OS_MacOS
Protected Range.NSRange\location = Start - 1 : Range\length = Length
CocoaMessage(0, TextEditor(GadgetID), "setSelectedRange:@", @Range)
CompilerEndSelect
Else
; Deselect all
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
SendMessage_(GadgetID(GadgetID.i), #EM_SETSEL, -1, 0)
CompilerCase #PB_OS_Linux
; TODO
CompilerCase #PB_OS_MacOS
CocoaMessage(0, TextEditor(GadgetID), "setSelectedRange:@", @NSRangeZero)
CompilerEndSelect
EndIf
EndProcedure
Procedure.i GetStringGadgetSelectionStart(GadgetID.i)
; Get selection
Protected Start.i = 0
Protected Stop.i = 0
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
SendMessage_(GadgetID(GadgetID.i), #EM_GETSEL, @Start.i, @Stop.i)
ProcedureReturn Start.i + 1
CompilerCase #PB_OS_Linux
; TODO
CompilerCase #PB_OS_MacOS
Protected Range.NSRange
CocoaMessage(@Range, TextEditor(GadgetID), "selectedRange")
ProcedureReturn Range\location + 1
CompilerEndSelect
EndProcedure
Procedure.i GetStringGadgetSelectionLength(GadgetID.i)
; Get selection
Protected Start.i = 0
Protected Stop.i = 0
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
SendMessage_(GadgetID(GadgetID.i), #EM_GETSEL, @Start.i, @Stop.i)
ProcedureReturn Stop.i - Start.i
CompilerCase #PB_OS_Linux
; TODO
CompilerCase #PB_OS_MacOS
Protected Range.NSRange
CocoaMessage(@Range, TextEditor(GadgetID), "selectedRange")
ProcedureReturn Range\length
CompilerEndSelect
EndProcedure
If OpenWindow(0, 200, 300, 195, 160, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
Define strGadgID.i = StringGadget(#PB_Any, 10, 10, 180, 20, "Testcontent")
SetActiveGadget(strGadgID.i)
SetStringGadgetSelection(strGadgID.i, 3, 4) ; mark 4 characters beginning with the 3rd character
Debug "Cursor before " + Str(GetStringGadgetSelectionStart(strGadgID.i))
Debug "Marked characters: " + Str(GetStringGadgetSelectionLength(strGadgID.i))
Repeat
Define Event.i = WaitWindowEvent()
If Event.i = #PB_Event_CloseWindow
Define Quit.i = 1
EndIf
Until Quit.i = 1
EndIf
End
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
Re: Cocoa StringGadget functions
Hi WilliamL, thank you, that example works well for setting the selection range.
Also, I discovered that SetActiveGadget() seems to automatically "select all" (at least on PB 5.42, OSX 10.11 ?) so that's easy enough.
Any idea about question # 2? Inserting a string at the cursor?
If the StringGadget has focus, I can get its "currentEditor" handle and then call its "insertText" method -- this works.
If the gadget does NOT have focus, its "currentEditor" is null. If I call SetActiveGadget() then "currentEditor" works, but this will select-all and replace the entire gadget contents...
Also, I discovered that SetActiveGadget() seems to automatically "select all" (at least on PB 5.42, OSX 10.11 ?) so that's easy enough.
Any idea about question # 2? Inserting a string at the cursor?
If the StringGadget has focus, I can get its "currentEditor" handle and then call its "insertText" method -- this works.
If the gadget does NOT have focus, its "currentEditor" is null. If I call SetActiveGadget() then "currentEditor" works, but this will select-all and replace the entire gadget contents...
Re: Cocoa StringGadget functions
Here's a code example of what I'm trying to do.
Press Enter when Gadget # 0 has focus, and when Gadget # 1 has focus...
Press Enter when Gadget # 0 has focus, and when Gadget # 1 has focus...
Code: Select all
OpenWindow(0, 0, 0, 320, 240, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
StringGadget(0, 10, 10, 300, 25, "Select part of this text, then press Enter")
StringGadget(1, 10, 50, 300, 25, "Focus here, then press Enter")
AddKeyboardShortcut(0, #PB_Shortcut_Return, 0)
Procedure InsertText()
*P = GadgetID(0)
;SetActiveGadget(0) ; this helps, but selects ALL of Gadget 0 text
*P = CocoaMessage(#Null, *P, "currentEditor")
If (*P)
CocoaMessage(#Null, *P, "insertText:$", @"TEST")
Else
Debug "No currentEditor for Gadget #0"
EndIf
EndProcedure
SetActiveGadget(0)
Repeat
E = WaitWindowEvent()
If (E = #PB_Event_CloseWindow)
Break
ElseIf (E = #PB_Event_Menu)
If (EventMenu() = #PB_Menu_Quit)
Break
Else
InsertText()
EndIf
EndIf
ForEver
Re: Cocoa StringGadget functions
I think I solved my own question.
Sounds like OS X does not keep the cursor/selection when a text field loses focus... so when a StringGadget does NOT have focus, the best I can do is insert text at the end.
This procedure is OK for me:
Sounds like OS X does not keep the cursor/selection when a text field loses focus... so when a StringGadget does NOT have focus, the best I can do is insert text at the end.
This procedure is OK for me:
Code: Select all
Procedure InsertGadgetText(Gadget.i, Text.s)
CompilerIf (#PB_Compiler_OS = #PB_OS_Windows)
SendMessage_(GadgetID(Gadget), #EM_REPLACESEL, #Null, @Text)
If (GetActiveGadget() <> Gadget)
SetActiveGadget(Gadget)
EndIf
CompilerElseIf (#PB_Compiler_OS = #PB_OS_MacOS)
Protected *GID = GadgetID(Gadget)
If (GetActiveGadget() <> Gadget)
SetActiveGadget(Gadget)
Protected *Win = CocoaMessage(#Null, *GID, "window")
Protected *FE = CocoaMessage(#Null, *Win, "fieldEditor:", #YES, "forObject:", *GID)
If (*FE)
Protected Range.NSRange
Range\location = Len(GetGadgetText(Gadget))
Range\length = 0
CocoaMessage(#Null, *FE, "setSelectedRange:@", @Range)
EndIf
EndIf
Protected *CE = CocoaMessage(#Null, *GID, "currentEditor")
If (*CE)
CocoaMessage(#Null, *CE, "insertText:$", @Text)
EndIf
CompilerEndIf
EndProcedure
OpenWindow(0, 10, 10, 320, 80, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
StringGadget(0, 10, 10, 300, 25, "Select some of this text and press Enter")
StringGadget(1, 10, 45, 300, 25, "Dummy")
AddKeyboardShortcut(0, #PB_Shortcut_Return, 0)
SetActiveGadget(0)
Repeat
Event = WaitWindowEvent()
If (Event = #PB_Event_CloseWindow)
Done = #True
ElseIf (Event = #PB_Event_Menu)
InsertGadgetText(0, "ABC")
EndIf
Until (Done)