It is currently Tue Dec 10, 2019 9:54 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: GadgetString's Autocomplete list
PostPosted: Tue Jan 15, 2019 10:03 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
I am currently working on a big project. I needed an autocompletion list for string gadget
My goal was also that it be the most possible crossplatform
And this morning I had an idea ....
What do you think? I am looking for new improvements

2019-16-01 11h05 : Update Code
2019-16-01 15h22 : Works Fine :mrgreen:
2019-16-01 15h52 Fix when move Window !
2019-16-01 16h28 Fix move Windows with no open autocomplete window
2019-16-01 16h43 hide autocomplete window if empty
2019-16-01 21h15 use Srod advice ! Better code
Code:
; ********************************************************************
; Program:           AutoComplete List
; Description:       Add an AutoComplete list to a String gadget

; Author:            Thyphoon
; Date:              January, 2019
; License:           Free, unrestricted, credit
;                    appreciated but not required.
; Note:              Please share improvement !
; Thanks to:         Srod
; ********************************************************************

EnableExplicit

DeclareModule AutoComplete
  Declare AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
  Declare CheckEvent(Event.i)
EndDeclareModule 

Module AutoComplete
  Declare MoveWindow()

  Prototype.s CallBack(String.s)
 
  Structure ac
    Window.i                  ;Original Window
    Gadget.i                  ;Original Gadget
    FirstEventKey.l           ;First Eventkey=Up +1=Down +2=Enter +3=Escape
    CallBack.CallBack         ;CallBack who return choice
  EndStructure
 
  Structure params
    acWindow.i                ;Autocomplete window
    acGadget.i                ;AutoComplete GadgetList
    CurrentName.s             ;CurrentName at last open autocomplete windows
    Map AutoCompleteGadget.ac()
    FirstEventKey.i
  EndStructure
 
  Global params.params
 
 
  Procedure AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
    Name.s=Str(Window)+"-"+Str(Gadget)
    params\AutoCompleteGadget(Name)\CallBack=*CallBack
    params\AutoCompleteGadget(Name)\Gadget=Gadget
    params\AutoCompleteGadget(Name)\Window=Window
    params\AutoCompleteGadget(Name)\FirstEventKey=FirstEventKey
    AddKeyboardShortcut(Window, #PB_Shortcut_Up, FirstEventKey)
    AddKeyboardShortcut(Window, #PB_Shortcut_Down, FirstEventKey+1)
    AddKeyboardShortcut(Window, #PB_Shortcut_Return, FirstEventKey+2)
    AddKeyboardShortcut(Window, #PB_Shortcut_Escape, FirstEventKey+3)
  EndProcedure
 
  Procedure RefreshAutocompleteWindow(Name.s)
    Gadget.i=params\AutoCompleteGadget(Name)\Gadget
    X.l=GadgetX(Gadget,#PB_Gadget_ScreenCoordinate)
    Y.l=GadgetY(Gadget,#PB_Gadget_ScreenCoordinate)+GadgetHeight(Gadget)
    W.l=GadgetWidth(Gadget)
    H.l=150
    ResizeWindow(params\acWindow,X,Y,W,H)
    ResizeGadget(params\acGadget,0,0,W,H)
    HideWindow(params\acWindow, #False,#PB_Window_NoActivate)
    StickyWindow(params\acWindow,#True)
  EndProcedure
 
  Procedure UpdateAutocompleteList(Name.s)
    ClearGadgetItems(params\acGadget)
    If params\AutoCompleteGadget(Name)\CallBack<>0
      BackString.s=params\AutoCompleteGadget(Name)\CallBack(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
      For n=1 To CountString(BackString,Chr(10))+1
        line.s=StringField(BackString,n,Chr(10))
        If LCase(Left(line,Len(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))))=LCase(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
          AddGadgetItem(params\acGadget,-1,line)
        EndIf
      Next
      ;Hide Autocomplete Window if no Choice
      If CountGadgetItems(params\acGadget)=0
        HideWindow(params\acWindow,#True)
      Else
        HideWindow(params\acWindow,#False,#PB_Window_NoActivate)
      EndIf
    Else
      Debug "Error with callback"
    EndIf
  EndProcedure
 
  Procedure OpenAutocompleteWindow(Name.s)
    If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
    If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acWindow):EndIf
    params\acWindow=OpenWindow(#PB_Any,0,0,50,50,"AutoComplete",#PB_Window_BorderLess|#PB_Window_NoActivate,WindowID(params\AutoCompleteGadget(Name)\Window));
    If params\acWindow
      params\CurrentName=Name
      SetWindowData(params\acWindow,params\AutoCompleteGadget(Name)\Gadget)
      params\acGadget=ListViewGadget(#PB_Any, 0, 0, 50,50)
    EndIf
    RefreshAutocompleteWindow(Name)
    UpdateAutocompleteList(Name)
    BindEvent(#PB_Event_MoveWindow, @MoveWindow(), params\AutoCompleteGadget(Name)\Window)
  EndProcedure
 
  Procedure CloseAutocompleteWindow(Name.s)
      If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
      If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acWindow):EndIf
      UnbindEvent(#PB_Event_MoveWindow, @MoveWindow(), Windows)
  EndProcedure
 
  Procedure MoveWindow()
    If EventWindow()=params\AutoCompleteGadget()\Window And params\acWindow>0 And IsWindow(params\acWindow)
      RefreshAutocompleteWindow(params\CurrentName)
    EndIf
  EndProcedure
 

  Procedure CheckEvent(Event.i)
    Static bbclick.b
    ;-Orignal Gadget Event
    Protected Name.s=Str(EventWindow())+"-"+Str(EventGadget())   
    If FindMapElement(params\AutoCompleteGadget(),Name)
      Select Event
        Case  #PB_Event_Gadget
          Select EventGadget()
              ; Main gadget Event 
            Case params\AutoCompleteGadget()\Gadget
              Select EventType()
                Case #PB_EventType_Focus
                  If params\acWindow=0 Or IsWindow(params\acWindow)=#False
                    If bbclick=#False
                      OpenAutocompleteWindow(Name)
                    Else
                      bbclick=#True
                    EndIf
                  EndIf
                Case #PB_EventType_LostFocus
                  If GetActiveGadget()<>params\acGadget
                    CloseAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf 
                Case #PB_EventType_Change
                  If bbclick=#False
                    If IsWindow(params\acWindow)
                      UpdateAutocompleteList(Name)
                    Else
                      Debug "pas de windows"
                    EndIf
                  Else
                    OpenAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf
              EndSelect

          EndSelect
     EndSelect
    EndIf
   
    Select Event
      ;if Keyword 
      Case #PB_Event_Menu
        Select EventMenu()
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey;UP
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)-1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+1;Down
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)+1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+2;Enter
            SetGadgetText(params\AutoCompleteGadget()\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+3;
            CloseAutocompleteWindow(params\CurrentName)
        EndSelect
      Case  #PB_Event_Gadget
        If EventGadget()=params\acGadget
          If EventType()=#PB_EventType_LeftDoubleClick
            SetGadgetText(params\AutoCompleteGadget(params\CurrentName)\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
            CloseAutocompleteWindow(params\CurrentName)
            bbclick=#True
          EndIf
        EndIf
    EndSelect 
   
   
   
  EndProcedure 
 
 
EndModule

;- MAIN TEST

CompilerIf #PB_Compiler_IsMainFile
 
  ; Callback to return keyword list. you must use a database en filter if you want ^_^
  Procedure.s ToDisplayInList(String.s)
    ProcedureReturn "Amiga"+Chr(10)+"Amstrad"+Chr(10)+"Atari"+Chr(10)+"Commodore"+Chr(10)+"BeBox"+Chr(10)+"Macintosh"+Chr(10)+"Spectrum"
  EndProcedure
 
  Procedure.s ToDisplayInListB(String.s)
    ProcedureReturn "Alain"+Chr(10)+"Bernard"+Chr(10)+"Charly"+Chr(10)+"David"+Chr(10)+"Eric"+Chr(10)+"Filipe"+Chr(10)+"Horace"+Chr(10)+"Jérome"+Chr(10)+"Kevin"+Chr(10)+"Laurent"+Chr(10)+"Marc"
  EndProcedure
 
  If OpenWindow(0, 200, 200, 800, 100, "AutoComplete Teste", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   
    StringGadget(1, 10, 10, 380, 26, "")
    StringGadget(2, 410, 10, 380, 26, "")
   
    AutoComplete::AddAutocompleteWindow(0,1,@ToDisplayInList()) ;Just init the gadget who must support AutoComplete list
    AutoComplete::AddAutocompleteWindow(0,2,@ToDisplayInListB())
    Repeat
      Define Event.i = WaitWindowEvent()
     
     
      AutoComplete::CheckEvent(Event)
     
      Select Event
        Case #PB_Event_Gadget
      EndSelect
    Until Event=#PB_Event_CloseWindow
  EndIf
  End
CompilerEndIf


Last edited by thyphoon on Wed Jan 16, 2019 9:16 pm, edited 6 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Tue Jan 15, 2019 1:28 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Jan 10, 2008 1:30 pm
Posts: 1244
Location: Germany, Glienicke
thyphoon wrote:
1) First problem is how to find the height of the window title bar ? and also thickness of the window to correctly position.

You have to use #PB_Window_InnerCoordinate:
Code:
    MainAC(Name)\X=WindowX(Windows, #PB_Window_InnerCoordinate)+GadgetX(Gadget)
    MainAC(Name)\Y=WindowY(Windows, #PB_Window_InnerCoordinate)+GadgetY(Gadget)+GadgetHeight(Gadget)

_________________
ImageImage


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Tue Jan 15, 2019 4:52 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jun 06, 2005 2:35 pm
Posts: 1220
Location: germany
Maybe also interesting: https://www.purebasic.fr/english/viewtopic.php?f=12&t=52079


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Tue Jan 15, 2019 4:56 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
STARGÅTE wrote:
thyphoon wrote:
1) First problem is how to find the height of the window title bar ? and also thickness of the window to correctly position.

You have to use #PB_Window_InnerCoordinate:
Code:
    MainAC(Name)\X=WindowX(Windows, #PB_Window_InnerCoordinate)+GadgetX(Gadget)
    MainAC(Name)\Y=WindowY(Windows, #PB_Window_InnerCoordinate)+GadgetY(Gadget)+GadgetHeight(Gadget)

YEEEEEEEEEEEEEEEEEEES :mrgreen: Thanks

Kukulkan wrote:

Very interesting. May be a mix of both is a goos idea :idea: :D


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 3:24 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
Big update 8)
Code:
code updated on the first post


Last edited by thyphoon on Wed Jan 16, 2019 4:30 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 3:28 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Wed Oct 29, 2003 4:35 pm
Posts: 10525
Location: Beyond the pale...
The auto complete seems to work well. However, if I drag the window then any visible autocomplete box is left behind and the program crashes when I release the mouse on line 56 (Gadget# is not initialised).

_________________
I may look like a mule, but I'm not a complete ass.


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 3:47 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
srod wrote:
The auto complete seems to work well. However, if I drag the window then any visible autocomplete box is left behind and the program crashes when I release the mouse on line 56 (Gadget# is not initialised).

thanks ! I will correct it !


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 3:54 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
I fix the problem when move the window :D Thanks Srod
Code:
Code updated on the first Post


Last edited by thyphoon on Wed Jan 16, 2019 4:30 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 3:56 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Wed Oct 29, 2003 4:35 pm
Posts: 10525
Location: Beyond the pale...
Nearly! :) Still crashes on the same line. Drag the window as soon as you run the program - before opening one of the autocomplete boxes.

_________________
I may look like a mule, but I'm not a complete ass.


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 4:27 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
srod wrote:
Nearly! :) Still crashes on the same line. Drag the window as soon as you run the program - before opening one of the autocomplete boxes.

:lol: Oups!!!!

Code:
; ********************************************************************
; Program:           AutoComplete List
; Description:       Add an AutoComplete list to a String gadget

; Author:            Thyphoon
; Date:              January, 2019
; License:           Free, unrestricted, credit
;                    appreciated but not required.
; Note:              Please share improvement !
; ********************************************************************

EnableExplicit

DeclareModule AutoComplete
  Declare AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
  Declare CheckEvent(Event.i)
EndDeclareModule 

Module AutoComplete
 
  Prototype.s CallBack(String.s)
 
  Structure ac
    Window.i                  ;Original Window
    Gadget.i                  ;Original Gadget
    FirstEventKey.l           ;First Eventkey=Up +1=Down +2=Enter +3=Escape
    CallBack.CallBack         ;CallBack who return choice
  EndStructure
 
  Structure params
    acWindow.i                ;Autocomplete window
    acGadget.i                ;AutoComplete GadgetList
    CurrentName.s             ;CurrentName at last open autocomplete windows
    Map AutoCompleteGadget.ac()
    FirstEventKey.i
  EndStructure
 
  Global params.params
 
 
  Procedure AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
    Name.s=Str(Window)+"-"+Str(Gadget)
    params\AutoCompleteGadget(Name)\CallBack=*CallBack
    params\AutoCompleteGadget(Name)\Gadget=Gadget
    params\AutoCompleteGadget(Name)\Window=Window
    params\AutoCompleteGadget(Name)\FirstEventKey=FirstEventKey
    AddKeyboardShortcut(Window, #PB_Shortcut_Up, FirstEventKey)
    AddKeyboardShortcut(Window, #PB_Shortcut_Down, FirstEventKey+1)
    AddKeyboardShortcut(Window, #PB_Shortcut_Return, FirstEventKey+2)
    AddKeyboardShortcut(Window, #PB_Shortcut_Escape, FirstEventKey+3)
  EndProcedure
 
  Procedure RefreshAutocompleteWindow(Name.s)
    Gadget.i=params\AutoCompleteGadget(Name)\Gadget
    Windows.i=params\AutoCompleteGadget(Name)\Window
    Debug Gadget
    X.l=WindowX(Windows,#PB_Window_InnerCoordinate)+GadgetX(Gadget)
    Y.l=WindowY(Windows,#PB_Window_InnerCoordinate)+GadgetY(Gadget)+GadgetHeight(Gadget)
    W.l=GadgetWidth(Gadget)
    H.l=150
    ResizeWindow(params\acWindow,X,Y,W,H)
    ResizeGadget(params\acGadget,0,0,W,H)
    HideWindow(params\acWindow, #False,#PB_Window_NoActivate)
    StickyWindow(params\acWindow,#True)
  EndProcedure
 
  Procedure UpdateAutocompleteList(Name.s)
    ClearGadgetItems(params\acGadget)
    If params\AutoCompleteGadget(Name)\CallBack<>0
      BackString.s=params\AutoCompleteGadget(Name)\CallBack(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))

      For n=1 To CountString(BackString,Chr(10))+1
        line.s=StringField(BackString,n,Chr(10))
        If LCase(Left(line,Len(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))))=LCase(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
          AddGadgetItem(params\acGadget,-1,line)
        EndIf
      Next
      ;Hide Autocomplete Window if no Choice
      If CountGadgetItems(params\acGadget)=0
        HideWindow(params\acWindow,#True)
      Else
        HideWindow(params\acWindow,#False,#PB_Window_NoActivate)
      EndIf
    Else
      Debug "Error with callback"
    EndIf
  EndProcedure
 
  Procedure OpenAutocompleteWindow(Name.s)
    If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
    If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acGadget):EndIf
    params\acWindow=OpenWindow(#PB_Any,0,0,50,50,"AutoComplete",#PB_Window_BorderLess|#PB_Window_NoActivate,WindowID(Window));
    If params\acWindow
      params\CurrentName=Name
      SetWindowData(params\acWindow,params\AutoCompleteGadget(Name)\Gadget)
      params\acGadget=ListViewGadget(#PB_Any, 0, 0, 50,50)
    EndIf
    RefreshAutocompleteWindow(Name)
    UpdateAutocompleteList(Name)
  EndProcedure
 
  Procedure CloseAutocompleteWindow(Name.s)
      Gadget.i=params\AutoCompleteGadget(Name)\Gadget
      Windows.i=params\AutoCompleteGadget(Name)\Window
      If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
      If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acWindow):EndIf
  EndProcedure
 
  Procedure CheckEvent(Event.i)
    Static bbclick.b
    ;-Orignal Gadget Event
    Protected Name.s=Str(EventWindow())+"-"+Str(EventGadget())   
    If FindMapElement(params\AutoCompleteGadget(),Name)
      Select Event
        Case  #PB_Event_Gadget
          Select EventGadget()
              ; Main gadget Event 
            Case params\AutoCompleteGadget()\Gadget
              Select EventType()
                Case #PB_EventType_Focus
                  If params\acWindow=0 Or IsWindow(params\acWindow)=#False
                    If bbclick=#False
                      OpenAutocompleteWindow(Name)
                    Else
                      bbclick=#True
                    EndIf
                  EndIf
                Case #PB_EventType_LostFocus
                  If GetActiveGadget()<>params\acGadget
                    CloseAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf 
                Case #PB_EventType_Change
                  If bbclick=#False
                    If IsWindow(params\acWindow)
                      UpdateAutocompleteList(Name)
                    Else
                      Debug "pas de windows"
                    EndIf
                  Else
                    OpenAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf
              EndSelect

          EndSelect
     EndSelect
    EndIf
   
    Select Event
      ;If Original Window Move 
      Case #PB_Event_MoveWindow,#PB_Event_SizeWindow
        If EventWindow()=params\AutoCompleteGadget()\Window And params\acWindow>0 And IsWindow(params\acWindow)
          RefreshAutocompleteWindow(params\CurrentName)
        EndIf
      ;if Keyword 
      Case #PB_Event_Menu
        Select EventMenu()
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey;UP
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)-1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+1;Down
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)+1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+2;Enter
            SetGadgetText(params\AutoCompleteGadget()\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+3;
            CloseAutocompleteWindow(params\CurrentName)
        EndSelect
      Case  #PB_Event_Gadget
        If EventGadget()=params\acGadget
          If EventType()=#PB_EventType_LeftDoubleClick
            SetGadgetText(params\AutoCompleteGadget(params\CurrentName)\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
            CloseAutocompleteWindow(params\CurrentName)
            bbclick=#True
          EndIf
        EndIf
    EndSelect 
   
   
   
  EndProcedure 
 
 
EndModule

;- MAIN TEST

CompilerIf #PB_Compiler_IsMainFile
 
  ; Callback to return keyword list. you must use a database en filter if you want ^_^
  Procedure.s ToDisplayInList(String.s)
    ProcedureReturn "Amiga"+Chr(10)+"Amstrad"+Chr(10)+"Atari"+Chr(10)+"Commodore"+Chr(10)+"BeBox"+Chr(10)+"Macintosh"+Chr(10)+"Spectrum"
  EndProcedure
 
  Procedure.s ToDisplayInListB(String.s)
    ProcedureReturn "Alain"+Chr(10)+"Bernard"+Chr(10)+"Charly"+Chr(10)+"David"+Chr(10)+"Eric"+Chr(10)+"Filipe"+Chr(10)+"Horace"+Chr(10)+"Jérome"+Chr(10)+"Kevin"+Chr(10)+"Laurent"+Chr(10)+"Marc"
  EndProcedure
 
  If OpenWindow(0, 200, 200, 800, 300, "AutoComplete Teste", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   
    StringGadget(1, 10, 10, 380, 26, "")
    StringGadget(2, 410, 10, 380, 26, "")
   
   
    AutoComplete::AddAutocompleteWindow(0,1,@ToDisplayInList()) ;Just init the gadget who must support AutoComplete list
    AutoComplete::AddAutocompleteWindow(0,2,@ToDisplayInListB())
    Repeat
      Define Event.i = WaitWindowEvent()
     
     
      AutoComplete::CheckEvent(Event)
     
      Select Event
        Case #PB_Event_Gadget
      EndSelect
     
    Until Event=#PB_Event_CloseWindow
  EndIf
  End
CompilerEndIf


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 5:01 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Wed Oct 29, 2003 4:35 pm
Posts: 10525
Location: Beyond the pale...
Yep - that's better.

I have made a simple modification so that when you drag the window, the auto complete box moves at the same time. Just a simple BindEvent(). You should use a suitable UnbindEvent() at some point.

At the moment this code is not easily used in a different program because of the way you have effectively hard coded parent window info into the module. You could easily change this, however, and create a library which had no dependency whatsoever on the parent window. GadgetX and GadgetY calculations would need to use the #PB_Gadget_ScreenCoordinate flag. Also, you would need to use a hidden window as the parent window of your 'pop up' to stop a taskbar entry appearing. Your host app would need to call a suitable library function everytime a #PB_Event_MoveWindow event was received. I've done this sort of thing a few times.

One thing I have spotted is that you are relying upon #PB_EventType_LostFocus events firing for ListView gadgets. This is undocumented for this gadget which is why you will need to test this on the other platforms.

Anyhow, I post your program with the move window alteration :
Code:
; ********************************************************************
; Program:           AutoComplete List
; Description:       Add an AutoComplete list to a String gadget

; Author:            Thyphoon
; Date:              January, 2019
; License:           Free, unrestricted, credit
;                    appreciated but not required.
; Note:              Please share improvement !
; ********************************************************************

EnableExplicit

DeclareModule AutoComplete
  Declare AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
  Declare CheckEvent(Event.i)
EndDeclareModule 

Module AutoComplete
  Declare MoveWindow()

  Prototype.s CallBack(String.s)
 
  Structure ac
    Window.i                  ;Original Window
    Gadget.i                  ;Original Gadget
    FirstEventKey.l           ;First Eventkey=Up +1=Down +2=Enter +3=Escape
    CallBack.CallBack         ;CallBack who return choice
  EndStructure
 
  Structure params
    acWindow.i                ;Autocomplete window
    acGadget.i                ;AutoComplete GadgetList
    CurrentName.s             ;CurrentName at last open autocomplete windows
    Map AutoCompleteGadget.ac()
    FirstEventKey.i
  EndStructure
 
  Global params.params
 
 
  Procedure AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
    Name.s=Str(Window)+"-"+Str(Gadget)
    params\AutoCompleteGadget(Name)\CallBack=*CallBack
    params\AutoCompleteGadget(Name)\Gadget=Gadget
    params\AutoCompleteGadget(Name)\Window=Window
    params\AutoCompleteGadget(Name)\FirstEventKey=FirstEventKey
    AddKeyboardShortcut(Window, #PB_Shortcut_Up, FirstEventKey)
    AddKeyboardShortcut(Window, #PB_Shortcut_Down, FirstEventKey+1)
    AddKeyboardShortcut(Window, #PB_Shortcut_Return, FirstEventKey+2)
    AddKeyboardShortcut(Window, #PB_Shortcut_Escape, FirstEventKey+3)
    BindEvent(#PB_Event_MoveWindow, @MoveWindow(), Window)

  EndProcedure
 
  Procedure RefreshAutocompleteWindow(Name.s)
    Gadget.i=params\AutoCompleteGadget(Name)\Gadget
    Windows.i=params\AutoCompleteGadget(Name)\Window
    X.l=WindowX(Windows,#PB_Window_InnerCoordinate)+GadgetX(Gadget)
    Y.l=WindowY(Windows,#PB_Window_InnerCoordinate)+GadgetY(Gadget)+GadgetHeight(Gadget)
    W.l=GadgetWidth(Gadget)
    H.l=150
    ResizeWindow(params\acWindow,X,Y,W,H)
    ResizeGadget(params\acGadget,0,0,W,H)
    HideWindow(params\acWindow, #False,#PB_Window_NoActivate)
    StickyWindow(params\acWindow,#True)
  EndProcedure
 
  Procedure UpdateAutocompleteList(Name.s)
    ClearGadgetItems(params\acGadget)
    If params\AutoCompleteGadget(Name)\CallBack<>0
      BackString.s=params\AutoCompleteGadget(Name)\CallBack(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
      For n=1 To CountString(BackString,Chr(10))+1
        line.s=StringField(BackString,n,Chr(10))
        If LCase(Left(line,Len(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))))=LCase(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
          AddGadgetItem(params\acGadget,-1,line)
        EndIf
      Next
    Else
      Debug "Error with callback"
    EndIf
  EndProcedure
 
  Procedure OpenAutocompleteWindow(Name.s)
    If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
    If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acGadget):EndIf
    params\acWindow=OpenWindow(#PB_Any,0,0,50,50,"AutoComplete",#PB_Window_BorderLess|#PB_Window_NoActivate,WindowID(Window));
    If params\acWindow
      params\CurrentName=Name
      SetWindowData(params\acWindow,params\AutoCompleteGadget(Name)\Gadget)
      params\acGadget=ListViewGadget(#PB_Any, 0, 0, 50,50)
    EndIf
    RefreshAutocompleteWindow(Name)
    UpdateAutocompleteList(Name)
  EndProcedure
 
  Procedure CloseAutocompleteWindow(Name.s)
      Gadget.i=params\AutoCompleteGadget(Name)\Gadget
      Windows.i=params\AutoCompleteGadget(Name)\Window
      If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
      If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acWindow):EndIf
  EndProcedure
 
  Procedure MoveWindow()
    If EventWindow()=params\AutoCompleteGadget()\Window And params\acWindow>0 And IsWindow(params\acWindow)
      RefreshAutocompleteWindow(params\CurrentName)
    EndIf
  EndProcedure
 

  Procedure CheckEvent(Event.i)
    Static bbclick.b
    ;-Orignal Gadget Event
    Protected Name.s=Str(EventWindow())+"-"+Str(EventGadget())   
    If FindMapElement(params\AutoCompleteGadget(),Name)
      Select Event
        Case  #PB_Event_Gadget
          Select EventGadget()
              ; Main gadget Event 
            Case params\AutoCompleteGadget()\Gadget
              Select EventType()
                Case #PB_EventType_Focus
                  If params\acWindow=0 Or IsWindow(params\acWindow)=#False
                    If bbclick=#False
                      OpenAutocompleteWindow(Name)
                    Else
                      bbclick=#True
                    EndIf
                  EndIf
                Case #PB_EventType_LostFocus
                  If GetActiveGadget()<>params\acGadget
                    CloseAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf 
                Case #PB_EventType_Change
                  If bbclick=#False
                    If IsWindow(params\acWindow)
                      UpdateAutocompleteList(Name)
                    Else
                      Debug "pas de windows"
                    EndIf
                  Else
                    OpenAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf
              EndSelect

          EndSelect
     EndSelect
    EndIf
   
    Select Event
      ;If Original Window Move 
      Case #PB_Event_MoveWindow,#PB_Event_SizeWindow
;        If EventWindow()=params\AutoCompleteGadget()\Window And params\acWindow>0 And IsWindow(params\acWindow)
;          RefreshAutocompleteWindow(params\CurrentName)
;        EndIf
      ;if Keyword 
      Case #PB_Event_Menu
        Select EventMenu()
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey;UP
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)-1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+1;Down
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)+1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+2;Enter
            SetGadgetText(params\AutoCompleteGadget()\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+3;
            CloseAutocompleteWindow(params\CurrentName)
        EndSelect
      Case  #PB_Event_Gadget
        If EventGadget()=params\acGadget
          If EventType()=#PB_EventType_LeftDoubleClick
            SetGadgetText(params\AutoCompleteGadget(params\CurrentName)\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
            CloseAutocompleteWindow(params\CurrentName)
            bbclick=#True
          EndIf
        EndIf
    EndSelect 
   
   
   
  EndProcedure 
 
 
EndModule

;- MAIN TEST

CompilerIf #PB_Compiler_IsMainFile
 
  ; Callback to return keyword list. you must use a database en filter if you want ^_^
  Procedure.s ToDisplayInList(String.s)
    ProcedureReturn "Amiga"+Chr(10)+"Amstrad"+Chr(10)+"Atari"+Chr(10)+"Commodore"+Chr(10)+"BeBox"+Chr(10)+"Macintosh"+Chr(10)+"Spectrum"
  EndProcedure
 
  Procedure.s ToDisplayInListB(String.s)
    ProcedureReturn "Alain"+Chr(10)+"Bernard"+Chr(10)+"Charly"+Chr(10)+"David"+Chr(10)+"Eric"+Chr(10)+"Filipe"+Chr(10)+"Horace"+Chr(10)+"Jérome"+Chr(10)+"Kevin"+Chr(10)+"Laurent"+Chr(10)+"Marc"
  EndProcedure
 
  If OpenWindow(0, 200, 200, 800, 100, "AutoComplete Teste", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   
    StringGadget(1, 10, 10, 380, 26, "")
    StringGadget(2, 410, 10, 380, 26, "")
   
    AutoComplete::AddAutocompleteWindow(0,1,@ToDisplayInList()) ;Just init the gadget who must support AutoComplete list
    AutoComplete::AddAutocompleteWindow(0,2,@ToDisplayInListB())
    Repeat
      Define Event.i = WaitWindowEvent()
     
     
      AutoComplete::CheckEvent(Event)
     
      Select Event
        Case #PB_Event_Gadget
      EndSelect
    Until Event=#PB_Event_CloseWindow
  EndIf
  End
CompilerEndIf

_________________
I may look like a mule, but I'm not a complete ass.


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 5:12 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
srod wrote:
Yep - that's better.

I have made a simple modification so that when you drag the window, the auto complete box moves at the same time. Just a simple BindEvent(). You should use a suitable UnbindEvent() at some point.

At the moment this code is not easily used in a different program because of the way you have effectively hard coded parent window info into the module. You could easily change this, however, and create a library which had no dependency whatsoever on the parent window. GadgetX and GadgetY calculations would need to use the #PB_Gadget_ScreenCoordinate flag. Also, you would need to use a hidden window as the parent window of your 'pop up' to stop a taskbar entry appearing. Your host app would need to call a suitable library function everytime a #PB_Event_MoveWindow event was received. I've done this sort of thing a few times.

One thing I have spotted is that you are relying upon #PB_EventType_LostFocus events firing for ListView gadgets. This is undocumented for this gadget which is why you will need to test this on the other platforms.

Anyhow, I post your program with the move window alteration :

Big Thanks :D I will analyse all your tips and try to update my code.


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 5:17 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Wed Oct 29, 2003 4:35 pm
Posts: 10525
Location: Beyond the pale...
Don't get me wrong, that's a nice utility which could be very handy indeed. Very useful. Thanks. :)

_________________
I may look like a mule, but I'm not a complete ass.


Top
 Profile  
Reply with quote  
 Post subject: Re: GadgetString's Autocomplete list
PostPosted: Wed Jan 16, 2019 9:13 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Dec 25, 2004 2:37 pm
Posts: 233
srod wrote:
Don't get me wrong, that's a nice utility which could be very handy indeed. Very useful. Thanks. :)

Big Thanks to you for your Help :D I love Purebasic and I love to share my work if can help somebody

srod wrote:
At the moment this code is not easily used in a different program because of the way you have effectively hard coded parent window info into the module. You could easily change this, however, and create a library which had no dependency whatsoever on the parent window.

I can't remove all parent window dependency. I must use AddKeyboardShortcut() who ask the parend window. And i don't found how to found Window with only Gadget Id.

srod wrote:
One thing I have spotted is that you are relying upon #PB_EventType_LostFocus events firing for ListView gadgets. This is undocumented for this gadget which is why you will need to test this on the other platforms.

I don't understant , In documentation EventType() speak about #PB_EventType_LostFocus and is compatible with StringGadget()

Last Version
Code:
; ********************************************************************
; Program:           AutoComplete List
; Description:       Add an AutoComplete list to a String gadget

; Author:            Thyphoon
; Date:              January, 2019
; License:           Free, unrestricted, credit
;                    appreciated but not required.
; Note:              Please share improvement !
; Thanks to:         Srod
; ********************************************************************

EnableExplicit

DeclareModule AutoComplete
  Declare AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
  Declare CheckEvent(Event.i)
EndDeclareModule 

Module AutoComplete
  Declare MoveWindow()

  Prototype.s CallBack(String.s)
 
  Structure ac
    Window.i                  ;Original Window
    Gadget.i                  ;Original Gadget
    FirstEventKey.l           ;First Eventkey=Up +1=Down +2=Enter +3=Escape
    CallBack.CallBack         ;CallBack who return choice
  EndStructure
 
  Structure params
    acWindow.i                ;Autocomplete window
    acGadget.i                ;AutoComplete GadgetList
    CurrentName.s             ;CurrentName at last open autocomplete windows
    Map AutoCompleteGadget.ac()
    FirstEventKey.i
  EndStructure
 
  Global params.params
 
 
  Procedure AddAutocompleteWindow(Window.i,Gadget.i,*CallBack,FirstEventKey.l=5000)
    Name.s=Str(Window)+"-"+Str(Gadget)
    params\AutoCompleteGadget(Name)\CallBack=*CallBack
    params\AutoCompleteGadget(Name)\Gadget=Gadget
    params\AutoCompleteGadget(Name)\Window=Window
    params\AutoCompleteGadget(Name)\FirstEventKey=FirstEventKey
    AddKeyboardShortcut(Window, #PB_Shortcut_Up, FirstEventKey)
    AddKeyboardShortcut(Window, #PB_Shortcut_Down, FirstEventKey+1)
    AddKeyboardShortcut(Window, #PB_Shortcut_Return, FirstEventKey+2)
    AddKeyboardShortcut(Window, #PB_Shortcut_Escape, FirstEventKey+3)
  EndProcedure
 
  Procedure RefreshAutocompleteWindow(Name.s)
    Gadget.i=params\AutoCompleteGadget(Name)\Gadget
    X.l=GadgetX(Gadget,#PB_Gadget_ScreenCoordinate)
    Y.l=GadgetY(Gadget,#PB_Gadget_ScreenCoordinate)+GadgetHeight(Gadget)
    W.l=GadgetWidth(Gadget)
    H.l=150
    ResizeWindow(params\acWindow,X,Y,W,H)
    ResizeGadget(params\acGadget,0,0,W,H)
    HideWindow(params\acWindow, #False,#PB_Window_NoActivate)
    StickyWindow(params\acWindow,#True)
  EndProcedure
 
  Procedure UpdateAutocompleteList(Name.s)
    ClearGadgetItems(params\acGadget)
    If params\AutoCompleteGadget(Name)\CallBack<>0
      BackString.s=params\AutoCompleteGadget(Name)\CallBack(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
      For n=1 To CountString(BackString,Chr(10))+1
        line.s=StringField(BackString,n,Chr(10))
        If LCase(Left(line,Len(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))))=LCase(GetGadgetText(params\AutoCompleteGadget(Name)\Gadget))
          AddGadgetItem(params\acGadget,-1,line)
        EndIf
      Next
      ;Hide Autocomplete Window if no Choice
      If CountGadgetItems(params\acGadget)=0
        HideWindow(params\acWindow,#True)
      Else
        HideWindow(params\acWindow,#False,#PB_Window_NoActivate)
      EndIf
    Else
      Debug "Error with callback"
    EndIf
  EndProcedure
 
  Procedure OpenAutocompleteWindow(Name.s)
    If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
    If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acWindow):EndIf
    params\acWindow=OpenWindow(#PB_Any,0,0,50,50,"AutoComplete",#PB_Window_BorderLess|#PB_Window_NoActivate,WindowID(params\AutoCompleteGadget(Name)\Window));
    If params\acWindow
      params\CurrentName=Name
      SetWindowData(params\acWindow,params\AutoCompleteGadget(Name)\Gadget)
      params\acGadget=ListViewGadget(#PB_Any, 0, 0, 50,50)
    EndIf
    RefreshAutocompleteWindow(Name)
    UpdateAutocompleteList(Name)
    BindEvent(#PB_Event_MoveWindow, @MoveWindow(), params\AutoCompleteGadget(Name)\Window)
  EndProcedure
 
  Procedure CloseAutocompleteWindow(Name.s)
      If params\acGadget>0 And IsGadget(params\acGadget):FreeGadget(params\acGadget):EndIf
      If params\acWindow>0 And IsWindow(params\acWindow):CloseWindow(params\acWindow):EndIf
      UnbindEvent(#PB_Event_MoveWindow, @MoveWindow(), Windows)
  EndProcedure
 
  Procedure MoveWindow()
    If EventWindow()=params\AutoCompleteGadget()\Window And params\acWindow>0 And IsWindow(params\acWindow)
      RefreshAutocompleteWindow(params\CurrentName)
    EndIf
  EndProcedure
 

  Procedure CheckEvent(Event.i)
    Static bbclick.b
    ;-Orignal Gadget Event
    Protected Name.s=Str(EventWindow())+"-"+Str(EventGadget())   
    If FindMapElement(params\AutoCompleteGadget(),Name)
      Select Event
        Case  #PB_Event_Gadget
          Select EventGadget()
              ; Main gadget Event 
            Case params\AutoCompleteGadget()\Gadget
              Select EventType()
                Case #PB_EventType_Focus
                  If params\acWindow=0 Or IsWindow(params\acWindow)=#False
                    If bbclick=#False
                      OpenAutocompleteWindow(Name)
                    Else
                      bbclick=#True
                    EndIf
                  EndIf
                Case #PB_EventType_LostFocus
                  If GetActiveGadget()<>params\acGadget
                    CloseAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf 
                Case #PB_EventType_Change
                  If bbclick=#False
                    If IsWindow(params\acWindow)
                      UpdateAutocompleteList(Name)
                    Else
                      Debug "pas de windows"
                    EndIf
                  Else
                    OpenAutocompleteWindow(Name)
                    bbclick=#False
                  EndIf
              EndSelect

          EndSelect
     EndSelect
    EndIf
   
    Select Event
      ;if Keyword 
      Case #PB_Event_Menu
        Select EventMenu()
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey;UP
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)-1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+1;Down
            SetGadgetState(params\acGadget,GetGadgetState(params\acGadget)+1)
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+2;Enter
            SetGadgetText(params\AutoCompleteGadget()\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
          Case params\AutoCompleteGadget(params\CurrentName)\FirstEventKey+3;
            CloseAutocompleteWindow(params\CurrentName)
        EndSelect
      Case  #PB_Event_Gadget
        If EventGadget()=params\acGadget
          If EventType()=#PB_EventType_LeftDoubleClick
            SetGadgetText(params\AutoCompleteGadget(params\CurrentName)\Gadget,GetGadgetItemText(params\acGadget,GetGadgetState(params\acGadget)))
            CloseAutocompleteWindow(params\CurrentName)
            bbclick=#True
          EndIf
        EndIf
    EndSelect 
   
   
   
  EndProcedure 
 
 
EndModule

;- MAIN TEST

CompilerIf #PB_Compiler_IsMainFile
 
  ; Callback to return keyword list. you must use a database en filter if you want ^_^
  Procedure.s ToDisplayInList(String.s)
    ProcedureReturn "Amiga"+Chr(10)+"Amstrad"+Chr(10)+"Atari"+Chr(10)+"Commodore"+Chr(10)+"BeBox"+Chr(10)+"Macintosh"+Chr(10)+"Spectrum"
  EndProcedure
 
  Procedure.s ToDisplayInListB(String.s)
    ProcedureReturn "Alain"+Chr(10)+"Bernard"+Chr(10)+"Charly"+Chr(10)+"David"+Chr(10)+"Eric"+Chr(10)+"Filipe"+Chr(10)+"Horace"+Chr(10)+"Jérome"+Chr(10)+"Kevin"+Chr(10)+"Laurent"+Chr(10)+"Marc"
  EndProcedure
 
  If OpenWindow(0, 200, 200, 800, 100, "AutoComplete Teste", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   
    StringGadget(1, 10, 10, 380, 26, "")
    StringGadget(2, 410, 10, 380, 26, "")
   
    AutoComplete::AddAutocompleteWindow(0,1,@ToDisplayInList()) ;Just init the gadget who must support AutoComplete list
    AutoComplete::AddAutocompleteWindow(0,2,@ToDisplayInListB())
    Repeat
      Define Event.i = WaitWindowEvent()
     
     
      AutoComplete::CheckEvent(Event)
     
      Select Event
        Case #PB_Event_Gadget
      EndSelect
    Until Event=#PB_Event_CloseWindow
  EndIf
  End
CompilerEndIf

And excuse me for my bad english :P


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye