I just want to share my multiple email address autocomplete code. To enter, simply type the address. To finish some input (dividing addresses) type comma (,), semicolon (;) or a blank ( ).
It works by using a ordinary StringGadget and simply adding the following to your event loop (adapt to your needs):
Code: Select all
If EventGadget() = MyStringGadgetID.i And EventType() = #PB_EventType_Change
AutoCompleteStringGadget(MyStringGadgetID.i, MailAddressesLinkedList())
EndIf
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
Structure ControlEditTextSelectionRec
SelStart.W
SelEnd.W
EndStructure
CompilerElse
Global NSRangeZero.NSRange
Procedure.i acTextEditor(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, acTextEditor(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, acTextEditor(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, acTextEditor(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, acTextEditor(GadgetID), "selectedRange")
ProcedureReturn Range\length
CompilerEndIf
CompilerEndSelect
EndProcedure
Procedure.i AutoCompleteFindStringRev(String$, StringToFind$, StringToFind2$ = "", StringToFind3$ = "")
Protected x.i = 0
String$ = UCase(String$)
StringToFind$ = UCase(StringToFind$)
StringToFind2$ = UCase(StringToFind2$)
StringToFind3$ = UCase(StringToFind3$)
For x.i = Len(String$) To 1 Step -1
If Mid(String$, x.i, Len(StringToFind$)) = StringToFind$
ProcedureReturn x.i
EndIf
If Mid(String$, x.i, Len(StringToFind2$)) = StringToFind2$
ProcedureReturn x.i
EndIf
If Mid(String$, x.i, Len(StringToFind3$)) = StringToFind3$
ProcedureReturn x.i
EndIf
Next
ProcedureReturn 0
EndProcedure
Procedure AutoCompleteStringGadget(strGadgID.i, List Options.s())
Static NewMap LastLength.i()
Static NewMap LastAddress.s()
Protected StandardDivider.s = ","
Protected TempText.s = ""
Protected RightChar.s = ""
Protected Offset.i = 1
Protected Left.i = 0
Protected Part.s = ""
Protected Content.s = GetGadgetText(strGadgID.i)
Left.i = AutoCompleteFindStringRev(Content.s, ",", ";", " ")
If Left.i > 0: Offset.i = Left.i + 1: EndIf
Part.s = UCase(Trim(Mid(Content.s, Offset.i)))
If Len(Content.s) > LastLength(Str(strGadgID.i))
RightChar.s = Right(Content.s, 1)
If LastAddress(Str(strGadgID.i)) <> "" And (RightChar.s = "," Or RightChar.s = ";" Or RightChar.s = " ")
Left.i = AutoCompleteFindStringRev(Left(Content.s, Left.i - 1), ",", ";", " ")
Offset.i = 1
If Left.i > 0: Offset.i = Left.i + 1: EndIf
TempText.s = Left(Content.s, Offset.i - 1) + Options() + StandardDivider.s
SetGadgetText(strGadgID.i, TempText.s)
SetStringGadgetSelection(strGadgID.i, Len(TempText.s) + 1, 0)
LastAddress(Str(strGadgID.i)) = ""
EndIf
If Len(Part.s) > 0
LastAddress(Str(strGadgID.i)) = ""
ForEach Options()
If Left(UCase(Options()), Len(Part.s)) = Part.s
TempText.s = Left(Content.s, Offset.i - 1) + Options()
SetGadgetText(strGadgID.i, TempText.s)
SetStringGadgetSelection(strGadgID.i, Offset.i + Len(Part.s), 500)
LastAddress(Str(strGadgID.i)) = Options()
Break
EndIf
Next
EndIf
EndIf
LastLength(Str(strGadgID.i)) = Len(Content.s)
EndProcedure
; EXAMPLE USAGE:
; ================================================================================
NewList MailAddresses.s()
AddElement(MailAddresses())
MailAddresses() = "apple@company.com"
AddElement(MailAddresses())
MailAddresses() = "apple2@company.com"
AddElement(MailAddresses())
MailAddresses() = "berry@company.com"
AddElement(MailAddresses())
MailAddresses() = "peach@company.com"
AddElement(MailAddresses())
MailAddresses() = "banana@company.com"
If OpenWindow(0, 200, 300, 395, 160, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
Define strGadgID.i = StringGadget(#PB_Any, 10, 10, 380, 26, "")
Define btnGadgID.i = ButtonGadget(#PB_Any, 10, 40, 380, 26, "Button")
SetActiveGadget(strGadgID.i)
Repeat
Define Event.i = WaitWindowEvent()
If Event.i = #PB_Event_CloseWindow
Define Quit.i = 1
EndIf
If Event.i = #PB_Event_Gadget
Define et.i = EventType()
Define gd.i = EventGadget()
If gd.i = strGadgID.i And et.i = #PB_EventType_Change
AutoCompleteStringGadget(gd.i, MailAddresses())
EndIf
EndIf
Until Quit.i = 1
EndIf
End
Any enhancements welcome
Kukulkan