Page 1 of 1

ListIconGadget GetSelectedItems (All OS)

Posted: Tue Aug 29, 2023 4:19 pm
by mk-soft
After a query ...
Get selected items into an array.

Update v1.01.5
- Bugfix window check count
- Update example

Code: Select all

;-TOP

; Comment : GetSelectedItems (All OS)
; Author  : mk-soft
; Version : v1.01.5
; Date    : 29.08.2023
; Update  : 30.08.2023

; Link    : https://www.purebasic.fr/english/viewtopic.php?t=82334

EnableExplicit

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  
  ImportC ""
    gtk_tree_path_get_indices_with_depth(*path, depth)
  EndImport
  
  Structure udtItemsArray
    *pData.Integer
  EndStructure
  
  ProcedureC GFuncSelectedItemsCB(*data, *userdata.udtItemsArray)
    Protected *array.long, depth = 1
    *array = gtk_tree_path_get_indices_with_depth(*data, @depth)
    *userdata\pData\i = *array\l
    *userdata\pData + SizeOf(Integer)
  EndProcedure
  
CompilerEndIf

Procedure GetSelectedItems(Gadget, Array Items(1)) ; Result count of items
  
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_MacOS
      Protected IndexSet, cnt
      IndexSet = CocoaMessage(0, GadgetID(Gadget), "selectedRowIndexes")
      cnt = CocoaMessage(0, IndexSet, "count")
      If cnt > 0
        Dim Items(cnt - 1)
        CocoaMessage(0, IndexSet, "getIndexes:", @Items(), "maxCount:", cnt, "inIndexRange:", #nil)
      EndIf
      
    CompilerCase #PB_OS_Windows
      Protected hWnd, pos, cnt
      hWnd = GadgetID(Gadget)
      cnt = SendMessage_(hWnd, #LVM_GETSELECTEDCOUNT, 0, 0)
      If cnt > 0
        Dim Items(cnt - 1)
        cnt = 0
        pos = -1
        pos = SendMessage_(hWnd, #LVM_GETNEXTITEM, pos, #LVNI_SELECTED)
        While pos <> -1
          Items(cnt) = pos
          cnt + 1
          pos = SendMessage_(hWnd, #LVM_GETNEXTITEM, pos, #LVNI_SELECTED)
        Wend
      EndIf
      
    CompilerCase #PB_OS_Linux
      Protected *selection, *list, cnt, Items.udtItemsArray
      *selection = gtk_tree_view_get_selection_(GadgetID(Gadget))
      *list = gtk_tree_selection_get_selected_rows_(*selection, 0)
      cnt = g_list_length_(*list)
      If cnt > 0
        Dim Items(cnt - 1)
        Items\pData = @Items()
        g_list_foreach_(*list, @GFuncSelectedItemsCB(), @Items)
      EndIf
      g_list_free_(*list)
      
  CompilerEndSelect
  
  ProcedureReturn cnt
EndProcedure

; ****

CompilerIf #PB_Compiler_IsMainFile
  
  ;- Example
  
  #ProgramTitle = "Example - ListIconGadget GetSelectedItems"
  #ProgramVersion = "v1.01.5"
  
  Enumeration Windows
    #Main
  EndEnumeration
  
  Enumeration MenuBar
    #MainMenu
  EndEnumeration
  
  Enumeration MenuItems
    #MainMenuAbout
    #MainMenuExit
  EndEnumeration
  
  Enumeration Gadgets
    #MainList
    #MainButtonOk
    #MainButtonCancel
  EndEnumeration
  
  Enumeration StatusBar
    #MainStatusBar
  EndEnumeration
  
  ; ----
  
  Procedure FillList(Gadget)
    Protected txt.s, i, c
    RemoveGadgetColumn(Gadget, #PB_All)
    ; Add columns
    AddGadgetColumn(Gadget, 0, "Column 1", 200)
    AddGadgetColumn(Gadget, 1, "Column 2", 200)
    AddGadgetColumn(Gadget, 2, "Column 3", 200)
    AddGadgetColumn(Gadget, 3, "Column 4", 200)
    AddGadgetColumn(Gadget, 4, "Column 5", 200)
    AddGadgetColumn(Gadget, 5, "Column 6", 200)
    AddGadgetColumn(Gadget, 6, "Column 7", 200)
    AddGadgetColumn(Gadget, 7, "Column 8", 200)
    ; Add Items
    For i = 1 To 1000
      txt = ""
      For c = 1 To 8
        txt + "Item " + Str(i) + "." + Str(c) + #LF$
      Next
      AddGadgetItem(Gadget, -1, txt)
    Next  
  EndProcedure
  
  ; ----
  
  Procedure UpdateWindow()
    Protected dx, dy
    dx = WindowWidth(#Main)
    dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
    ; Resize gadgets
    ResizeGadget(#MainList, 5, 5, dx - 10, dy - 45)
    ResizeGadget(#MainButtonok, 10, dy - 35, 120, 30)
    ResizeGadget(#MainButtonCancel, dx - 130, dy - 35, 120, 30)
  EndProcedure
  
  ; ----
  
  Procedure Main()
    Protected dx, dy
    
    Protected cnt, idx
    Dim Items(0)
    
    #MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
    
    If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
      ; Menu
      CreateMenu(#MainMenu, WindowID(#Main))
      MenuTitle("&File")
      CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
        MenuItem(#PB_Menu_About, "")
      CompilerElse
        MenuItem(#MainMenuAbout, "About")
      CompilerEndIf
      ; Menu File Items
      
      CompilerIf Not #PB_Compiler_OS = #PB_OS_MacOS
        MenuBar()
        MenuItem(#MainMenuExit, "E&xit")
      CompilerEndIf
      
      ; StatusBar
      CreateStatusBar(#MainStatusBar, WindowID(#Main))
      AddStatusBarField(#PB_Ignore)
      
      ; Gadgets
      dx = WindowWidth(#Main)
      dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
      ListIconGadget(#MainList, 5, 5, dx -10, dy - 45, "", 0, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_FullRowSelect | #PB_ListIcon_MultiSelect)
      ButtonGadget(#MainButtonok, 10, dy - 35, 120, 30, "Ok")
      ButtonGadget(#MainButtonCancel, dx - 130, dy - 35, 120, 30, "Cancel")
      
      FillList(#MainList)
      
      ; Bind Events
      BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
      
      ; Event Loop
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Select EventWindow()
              Case #Main
                Break
                
            EndSelect
            
          Case #PB_Event_Menu
            Select EventMenu()
                CompilerIf #PB_Compiler_OS = #PB_OS_MacOS   
                Case #PB_Menu_About
                  PostEvent(#PB_Event_Menu, #Main, #MainMenuAbout)
                  
                Case #PB_Menu_Preferences
                  
                Case #PB_Menu_Quit
                  PostEvent(#PB_Event_CloseWindow, #Main, #Null)
                  
                CompilerEndIf
                
              Case #MainMenuAbout
                MessageRequester("About", #ProgramTitle + #LF$ + #ProgramVersion, #PB_MessageRequester_Info)
                
              Case #MainMenuExit
                PostEvent(#PB_Event_CloseWindow, #Main, #Null)
                
            EndSelect
            
          Case #PB_Event_Gadget
            Select EventGadget()
              Case #MainList
                Select EventType()
                  Case #PB_EventType_Change
                    ;
                    
                EndSelect
                
              Case #MainButtonOk
                cnt = GetSelectedItems(#MainList, Items())
                For idx = 0 To cnt - 1
                  Debug Items(idx)
                Next
                
              Case #MainButtonCancel
                ;
                
            EndSelect
            
        EndSelect
      ForEver
      
    EndIf
    
  EndProcedure : Main()
  
CompilerEndIf

Re: ListIconGadget GetSelectedItems (All OS)

Posted: Tue Aug 29, 2023 5:43 pm
by pamen
Excellent!
Thank you.

Re: ListIconGadget GetSelectedItems (All OS)

Posted: Tue Aug 29, 2023 7:11 pm
by jacdelad
There's a SendMessage command in Windows, #LVM_GETSELECTEDCOUNT, which let's you dim the array to the correct size right from the beginning.
https://learn.microsoft.com/en-us/windo ... ectedcount

Re: ListIconGadget GetSelectedItems (All OS)

Posted: Tue Aug 29, 2023 7:59 pm
by mk-soft
Update v1.01.3

Re: ListIconGadget GetSelectedItems (All OS)

Posted: Wed Aug 30, 2023 7:32 am
by Shardik
mk-soft's code doesn't check if no item is selected at all and crashes with no item selected on Windows in

Code: Select all

Dim Items(cnt - 1)

Re: ListIconGadget GetSelectedItems (All OS)

Posted: Wed Aug 30, 2023 8:14 am
by BarryG
Why are we not just For/Nexting the list and just checking the #PB_ListIcon_Selected flag for each item?

Re: ListIconGadget GetSelectedItems (All OS)

Posted: Wed Aug 30, 2023 1:26 pm
by mk-soft
Shardik wrote: Wed Aug 30, 2023 7:32 am mk-soft's code doesn't check if no item is selected at all and crashes with no item selected on Windows in

Code: Select all

Dim Items(cnt - 1)
Ups ...
Had only inserted #LVM_GETSELECTEDCOUNT later and was not paying attention.

Update v1.01.5
- Bugfix window check count
- Update example

@BarryG
I haven't checked, but this should be faster for large amounts of data.