Cross plattform StringGadget text selection

Just starting out? Need help? Post your questions and find answers here.
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Cross plattform StringGadget text selection

Post by Kukulkan »

Hi,

I need some cross plattform function that allows me to select text and place cursor in a StringGadget. It also should be able to return the selection.

Here is my version for Windows. If you already did something before or are familiar with CocoaMessage() on MacOS, can you please insert your code at the TODO comments or at least give me a link to further information about how to get?

Code: Select all

EnableExplicit

; 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
        ; TODO
    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
        ; TODO
    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
      ; TODO
  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
      ; TODO
  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
Thank you!

Kukulkan
Wood51
New User
New User
Posts: 7
Joined: Sat May 12, 2012 11:21 am

Cross plattform StringGadget text selection

Post by Wood51 »

Hi !
perhaps with gtk_editable_select_region .
@+ wood51
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Cross plattform StringGadget text selection

Post by wilbert »

Try if this works on OS X

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
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Cross plattform StringGadget text selection

Post by Shardik »

I have added support for Linux and MacOS X with Carbon framework (PB 4.61 and older or PB 5.00 with subsystem Carbon):

Code: Select all

EnableExplicit

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
    ImportC ""
      GetControlData(ControlRef.L, ControlPartCode.L, TagName.L, BufferSize.L, *Buffer, *ActualSize)
      SetControlData(ControlRef.L, ControlPartCode.L, TagName.L, BufferSize.L, *Buffer)
    EndImport
    
    #kControlEditTextPart = 5
    #kControlEditTextSelectionTag = $73656C65 ; 'sele'
    
    Structure ControlEditTextSelectionRec
      SelStart.W
      SelEnd.W
    EndStructure
  CompilerElse
    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
CompilerEndIf

; Sets the selection in a StringGadget() independent of Operating System
; If Start.i < 1, every selection is 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), #EM_SETSEL, Start.i - 1, Start.i + Length.i - 1)
      CompilerCase #PB_OS_Linux
        gtk_editable_select_region_(GadgetID(GadgetID), Start - 1, Start -1 + Length)
      CompilerCase #PB_OS_MacOS
        CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
          Protected TextSelection.ControlEditTextSelectionRec
          TextSelection\selStart = Start - 1
          TextSelection\selEnd = Start -1 + Length
          SetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection)
        CompilerElse
          Protected Range.NSRange\location = Start - 1 : Range\length = Length
          CocoaMessage(0, TextEditor(GadgetID), "setSelectedRange:@", @Range)
        CompilerEndIf
    CompilerEndSelect
  Else
    ; Deselect all
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        SendMessage_(GadgetID(GadgetID.i), #EM_SETSEL, -1, 0)
      CompilerCase #PB_OS_Linux
        gtk_editable_delete_selection_(GadgetID(GadgetID))
      CompilerCase #PB_OS_MacOS
        CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
          TextSelection\selStart = -1
          TextSelection\selEnd = -1
          SetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection)
        CompilerElse
          CocoaMessage(0, TextEditor(GadgetID), "setSelectedRange:@", @NSRangeZero)
        CompilerEndIf
    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
      gtk_editable_get_selection_bounds_(GadgetID(GadgetID), @Start, @Stop)
      ProcedureReturn Start + 1
    CompilerCase #PB_OS_MacOS
      CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
        Protected TextSelection.ControlEditTextSelectionRec
        GetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection.ControlEditTextSelectionRec, 0)
        ProcedureReturn TextSelection\SelStart + 1
      CompilerElse
        Protected Range.NSRange
        CocoaMessage(@Range, TextEditor(GadgetID), "selectedRange")
        ProcedureReturn Range\location + 1
      CompilerEndIf
  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), #EM_GETSEL, @Start.i, @Stop.i)
      ProcedureReturn Stop.i - Start.i
    CompilerCase #PB_OS_Linux
      gtk_editable_get_selection_bounds_(GadgetID(GadgetID), @Start, @Stop)
      ProcedureReturn Stop - Start
    CompilerCase #PB_OS_MacOS
      CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
        Protected TextSelection.ControlEditTextSelectionRec
        GetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection.ControlEditTextSelectionRec, 0)
        ProcedureReturn TextSelection\SelEnd - TextSelection\SelStart
      CompilerElse
        Protected Range.NSRange
        CocoaMessage(@Range, TextEditor(GadgetID), "selectedRange")
        ProcedureReturn Range\length
      CompilerEndIf
  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
Update: I had to change

Code: Select all

#kControlEditTextSelectionTag = 'sele'
to

Code: Select all

#kControlEditTextSelectionTag = $73656C65 ; 'sele'
for the Carbon code in order to work correctly with both ASCII and Unicode compilation.
Last edited by Shardik on Fri Nov 02, 2012 7:54 pm, edited 2 times in total.
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: Cross plattform StringGadget text selection

Post by Kukulkan »

Wow, just tested the last version of Shardik on Windows and Mac OS and it works great! Linux will get tested today, too.

Thank you! :D

I plan to do some autocomplete stringgadget for entering (multiple) email addresses. If ready, I will post the source here in the forum (based on this code).

Kukulkan
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Cross plattform StringGadget text selection

Post by Shardik »

Kukulkan wrote:Wow, just tested the last version of Shardik on Windows and Mac OS and it works great!
I forgot to say that I took wilbert's version with added MacOS X Cocoa support (default setting in PB 5.00) and added MacOS X Carbon support plus Linux. Did you test both Cocoa and Carbon versions on MacOS X? :wink:
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: Cross plattform StringGadget text selection

Post by Kukulkan »

No, I just tested Cocoa method as I only compile with this.

I just tested now and it does not work with Carbon subsystem. It marks the whole text and GetStringGadgetSelectionLength() result is also wrong :(

Kukulkan
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Cross plattform StringGadget text selection

Post by Shardik »

Kukulkan wrote:I just tested now and it does not work with Carbon subsystem. It marks the whole text and GetStringGadgetSelectionLength() result is also wrong :(
Sorry to hear that! With which MacOS X version did you test? I tested with Snow Leopard (10.6.8 ) and the results of Cocoa and Carbon (PB 4.61 and PB 5.00 x86 with subsystem Carbon) were both identical (and the same as in Windows and Linux)...
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Cross plattform StringGadget text selection

Post by wilbert »

@Kukulkan, a little remark about my SetStringGadgetSelection cocoa code with Start < 1.
My current solution clears the selection and sets the cursor to the beginning of the text.
I don't know exactly what your goal is but if you want the focus on the Gadget also gone, there's a better way to accomplish that with.
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: Cross plattform StringGadget text selection

Post by Kukulkan »

Hi,
With which MacOS X version did you test?
I'm using MacOS 10.7.4 (Lion).
My current solution clears the selection and sets the cursor to the beginning of the text. I don't know exactly what your goal is but if you want the focus on the Gadget also gone, there's a better way to accomplish that with.
No, keeping focus is good! If someone does not need, he can use SetActiveGadget() function.

Kukulkan
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Cross plattform StringGadget text selection

Post by Shardik »

Kukulkan wrote:I just tested now and it does not work with Carbon subsystem. It marks the whole text and GetStringGadgetSelectionLength() result is also wrong :(
Kukulkan wrote:I'm using MacOS 10.7.4 (Lion).
Sorry, but I can't reproduce your described Carbon error neither in MacOS X 10.6.8 (Snow Leopard) nor in MacOS X 10.7.5 (Lion) using PB 4.61 and PB 5.00 x86 Beta 6 and Beta 8 with subsystem Carbon! I always obtain this result (the same as with Cocoa, Linux and Windows):

Image
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: Cross plattform StringGadget text selection

Post by Kukulkan »

This is how it looks on my Lion with "Subsystem = Carbon" run from IDE:

Image

I'm using PB 5.00 Beta 7

Kukulkan
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Cross plattform StringGadget text selection

Post by Shardik »

I think I have solved our Carbon problem: I assume you have activated "Create unicode executable" in the Compiler Options. With unicode compilation I obtain the same result as you have documented... :wink:

I only had to change

Code: Select all

#kControlEditTextSelectionTag = 'sele'
in my above code to

Code: Select all

#kControlEditTextSelectionTag = $73656C65 ; 'sele'
and now the Carbon code works correctly in ASCII and Unicode mode. Sorry for my mistake... :wink:
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Cross plattform StringGadget text selection

Post by davido »

@Shardik,
Very useful.
Thank you for taking the trouble to make it cross-platform. :D
DE AA EB
Post Reply