ListIconGadget: No #PB_EventType_Change!
ListIconGadget: No #PB_EventType_Change!
If you change the selected row in a ListIconGadget with the arrow keys, no #PB_EventType_Change Event is triggered! No chance to find out if the selection inside the ListIconGadget was changed....
This is Mac OS only. With Windows it works.
			
			
									
									
						This is Mac OS only. With Windows it works.
Re: ListIconGadget: No #PB_EventType_Change!
It seems the bug is active only, if a GadgetCallback is activated:
http://www.purebasic.fr/english/viewtop ... 53#p490253
			
			
									
									
						http://www.purebasic.fr/english/viewtop ... 53#p490253
Re: ListIconGadget: No #PB_EventType_Change!
Could you post a full working snippet please ?
			
			
									
									
						Re: ListIconGadget: No #PB_EventType_Change!
Left gadget (with a callback) don't send a #PB_EventType_Change if you select a new row with up/down arrow keys:
			
			
									
									
						Code: Select all
EnableExplicit
Structure CallbackEntry
  WindowID.I
  ListIconID.I
  DefaultCallback.I
EndStructure
NewList CallbackEntry.CallbackEntry()
CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux ; ------------------------------------------------
    ProcedureC ColumnHeaderClickCallback(*Column, ListIconData.I)
      Shared CallbackEntry()
      ForEach CallbackEntry()
        If ListIconData >> 16 = CallbackEntry()\ListIconID
          Break
        EndIf
      Next
      PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID,
        CallbackEntry()\ListIconID, #PB_EventType_LeftClick,
        (ListIconData & $FFFF) + 1)
    EndProcedure
    Procedure SetGadgetCallback(WindowID.I, ListIconID.I)
      Shared CallbackEntry()
      Protected Column.I
      Protected ColumnCount.I
      Protected ColumnIndex.I
      Protected *ListStore.GtkListStore
      AddElement(CallbackEntry())
      CallbackEntry()\WindowID = WindowID
      CallbackEntry()\ListIconID = ListIconID
      gtk_tree_view_set_headers_clickable_(GadgetID(ListIconID), #True)
      *ListStore = gtk_tree_view_get_model_(GadgetID(ListIconID))
      ColumnCount = (*ListStore\n_columns - 3) / 3
      For ColumnIndex = 0 To ColumnCount - 1
        Column = gtk_tree_view_get_column_(GadgetID(CallbackEntry()\ListIconID),
          ColumnIndex)
        If Column
          g_signal_connect_data_(Column, "clicked",
            @ColumnHeaderClickCallback(), ListIconID << 16 | ColumnIndex, 0, 0)
        EndIf
      Next ColumnIndex
    EndProcedure
  CompilerCase #PB_OS_MacOS ; ------------------------------------------------
    ImportC ""
      sel_registerName(MethodName.S)
      class_addMethod(Class.I, Selector.I, Implementation.I, Types.S)
    EndImport
    Procedure.S ConvertToUTF8(String.S)
      Protected UTF8String.S = Space(StringByteLength(String))
      PokeS(@UTF8String, String, -1, #PB_UTF8)
      ProcedureReturn UTF8String
    EndProcedure
   
    ProcedureC ColumnHeaderClickCallback(Object.I, Selector.I, TableView.I,
      TableColumn.I)
      Shared CallbackEntry()
      Protected ClickedHeaderColumn.I
 
      ForEach CallbackEntry()
        If TableView = GadgetID(CallbackEntry()\ListIconID)
          Break
        EndIf
      Next
   
      ClickedHeaderColumn = Val(PeekS(CocoaMessage(0,
        CocoaMessage(0, TableColumn, "identifier"),
        "UTF8String"), -1, #PB_UTF8))
      PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID,
        CallbackEntry()\ListIconID, #PB_EventType_LeftClick,
        ClickedHeaderColumn + 1)
    EndProcedure
   
    Procedure SetGadgetCallback(WindowID.I, ListIconID.I)
      Shared CallbackEntry()
     
      Protected AppDelegate.I
      Protected DelegateClass.I
      Protected Selector.I = sel_registerName(ConvertToUTF8("tableView:didClickTableColumn:"))
      Protected Types.S = ConvertToUTF8("v@:@@")
      AddElement(CallbackEntry())
      CallbackEntry()\WindowID = WindowID
      CallbackEntry()\ListIconID = ListIconID
      AppDelegate = CocoaMessage(0,
        CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
      DelegateClass = CocoaMessage(0, AppDelegate, "class")
      class_addMethod(DelegateClass, Selector, @ColumnHeaderClickCallback(),
        Types)
      CocoaMessage(0, GadgetID(CallbackEntry()\ListIconID),
        "setDelegate:", AppDelegate)
    EndProcedure
  CompilerCase #PB_OS_Windows ; ----------------------------------------------
    Procedure ColumnHeaderClickCallback(WindowHandle.I, Msg.I, WParam.I,
      LParam.I)
      Shared CallbackEntry()
      Protected Result.I
      Protected *Header.HD_NOTIFY
      ForEach CallbackEntry()
        If WindowHandle = GadgetID(CallbackEntry()\ListIconID)
          Break
        EndIf
      Next
      Result = CallWindowProc_(CallbackEntry()\DefaultCallback, WindowHandle,
        Msg, WParam, LParam)
      If Msg = #WM_NOTIFY
        *Header = LParam
        If *Header\hdr\code = #HDN_ITEMCLICK
          PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID,
            CallbackEntry()\ListIconID, #PB_EventType_LeftClick,
            *Header\iItem + 1)
        EndIf
      EndIf
      ProcedureReturn Result
    EndProcedure
    Procedure SetGadgetCallback(WindowID.I, ListIconID.I)
      Shared CallbackEntry()
      AddElement(CallbackEntry())
      CallbackEntry()\WindowID = WindowID
      CallbackEntry()\ListIconID = ListIconID
      CallbackEntry()\DefaultCallback = SetWindowLongPtr_(GadgetID(CallbackEntry()\ListIconID),
        #GWL_WNDPROC, @ColumnHeaderClickCallback())
    EndProcedure ; -----------------------------------------------------------
CompilerEndSelect
; ========================================== SPECIFIC CODE FOR TESTING
Enumeration
  #zero
  #windows_nb
  #list1_nb
  #list2_nb
EndEnumeration
#Title_column1$ = "Name"
#Title_column2$ = "Address"
Define GadgetID.I
OpenWindow(#windows_nb, 0, 0, 950, 150, "Detect left click on header cell",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ListIconGadget(#list1_nb, 10, 10, 430, WindowHeight(#windows_nb) - 20, #Title_column1$,
  110, #PB_ListIcon_FullRowSelect)
AddGadgetColumn(#list1_nb, 1, #Title_column2$, 300)
AddGadgetItem(#list1_nb, -1, "Harry Rannit" + #LF$ +
  "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(#list1_nb, -1, "Ginger Brokeit"+ #LF$ +
  "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(#list1_nb, -1, "Didi Foundit"+ #LF$ +
  "321 Logo Drive, Mouse House, Downtown")
ListIconGadget(#list2_nb, 460, 10, 430, WindowHeight(#windows_nb) - 20, #Title_column1$,
  110, #PB_ListIcon_FullRowSelect)
AddGadgetColumn(#list2_nb, 1, #Title_column2$, 300)
AddGadgetItem(#list2_nb, -1, "Harry Rannit" + #LF$ +
  "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(#list2_nb, -1, "Ginger Brokeit"+ #LF$ +
  "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(#list2_nb, -1, "Didi Foundit"+ #LF$ +
  "321 Logo Drive, Mouse House, Downtown")
SetGadgetCallback(#windows_nb, #list1_nb)
;SetGadgetCallback(#windows_nb, #list2_nb) ; -> gadget 2 without that callback
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      CompilerIf #PB_Compiler_OS = #PB_OS_Windows
        ForEach CallbackEntry()
          SetWindowLongPtr_(GadgetID(CallbackEntry()\ListIconID),
            #GWL_WNDPROC, CallbackEntry()\DefaultCallback)
        Next
      CompilerEndIf
      Break
    Case #PB_Event_Gadget
      GadgetID = EventGadget()
      Select GadgetID
        Case #list1_nb, #list2_nb
          Select EventType()
          Case #PB_EventType_LeftClick
            If EventData()
              Debug "Left click on header of column " + Str(EventData() - 1) + " gadget=" + Str(GadgetID)
            Else
              Debug "Left click on row " + Str(GetGadgetState(GadgetID)) + " gadget=" + Str(GadgetID)
            EndIf
          Case #PB_EventType_Change
            Debug "changed"
          EndSelect
      EndSelect
  EndSelect
ForEver
Re: ListIconGadget: No #PB_EventType_Change!
You are replacing the delegate, so PB one isn't called anymore. It's not a PB bug.
			
			
									
									
						Re: ListIconGadget: No #PB_EventType_Change!
I don't know what you mean. I copied this code from the forum.Fred wrote:You are replacing the delegate, so PB one isn't called anymore. It's not a PB bug.
Is it possible to catch a click on the List Icon Gadget header without "replacing the delegate"?
Re: ListIconGadget: No #PB_EventType_Change!
Can you add this "header click" official to PureBasic? Then we don't need to "replace the delegate".
That would be great.
			
			
									
									
						That would be great.
Re: ListIconGadget: No #PB_EventType_Change!
I have taken Lebostein's example, stripped off all specific Linux and Windows code for a clearer outline (so now it's only runnable on MacOS) and implemented a second callback for the method tableViewSelectionDidChange: to catch and signal all selection changes in both of the two ListIconGadgets.
I have tested the example successfully on MacOS 10.6.8 (Snow Leopard) and MacOS 10.11.6 (El Capitan) with PB 5.43 x86 and x64 (ASCII and Unicode mode) and with PB 5.50 x86 and x64.
			
			
									
									
						I have tested the example successfully on MacOS 10.6.8 (Snow Leopard) and MacOS 10.11.6 (El Capitan) with PB 5.43 x86 and x64 (ASCII and Unicode mode) and with PB 5.50 x86 and x64.
Code: Select all
EnableExplicit
ImportC ""
  sel_registerName(MethodName.P-ASCII)
  class_addMethod(Class.I, Selector.I, Implementation.I, Types.P-ASCII)
EndImport
Structure CallbackEntry
  WindowID.I
  ListIconID.I
  DefaultCallback.I
EndStructure
Define AppDelegate.I = CocoaMessage(0,
  CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define NotificationCenter.I = CocoaMessage(0, 0,
  "NSNotificationCenter defaultCenter")
NewList CallbackEntry.CallbackEntry()
ProcedureC ColumnHeaderClickCallback(Object.I, Selector.I, TableView.I,
  TableColumn.I)
  Shared CallbackEntry()
  
  Protected ClickedHeaderColumn.I
  
  ForEach CallbackEntry()
    If TableView = GadgetID(CallbackEntry()\ListIconID)
      Break
    EndIf
  Next
  
  ClickedHeaderColumn = Val(PeekS(CocoaMessage(0,
    CocoaMessage(0, TableColumn, "identifier"),
    "UTF8String"), -1, #PB_UTF8))
  PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID,
    CallbackEntry()\ListIconID, #PB_EventType_LeftClick,
    ClickedHeaderColumn + 1)
EndProcedure
ProcedureC SelectionDidChangeCallback(Object.I, Selector.I, Notification.I)
  Shared CallbackEntry()
  Static ChangeSignalled.I
  If ChangeSignalled
    PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID,
      CallbackEntry()\ListIconID, #PB_EventType_Change)
    ChangeSignalled = #False
  Else
    ChangeSignalled = #True
  EndIf
EndProcedure
Procedure SetGadgetCallback(WindowID.I, ListIconID.I)
  Shared AppDelegate.I
  Shared CallbackEntry()
  Shared DelegateClass.I
  Shared NotificationCenter.I
  
  AddElement(CallbackEntry())
  CallbackEntry()\WindowID = WindowID
  CallbackEntry()\ListIconID = ListIconID
  ; ----- Initialize callback for changing selection
  class_addMethod(DelegateClass,
    sel_registerName("tableViewSelectionDidChange:"),
    @SelectionDidChangeCallback(), "v@:@")
  CocoaMessage(0, NotificationCenter,
    "addObserver:", AppDelegate,
    "selector:", sel_registerName("tableViewSelectionDidChange:"),
    "name:$", @"NSTableViewSelectionDidChangeNotification",
    "object:", GadgetID(CallbackEntry()\ListIconID))
  ; ----- Initialize callback for header click
  class_addMethod(DelegateClass,
    sel_registerName("tableView:didClickTableColumn:"),
    @ColumnHeaderClickCallback(), "v@:@@")
  CocoaMessage(0, GadgetID(CallbackEntry()\ListIconID),
    "setDelegate:", AppDelegate)
EndProcedure
; ========================================== SPECIFIC CODE FOR TESTING
Enumeration
  #zero
  #windows_nb
  #list1_nb
  #list2_nb
EndEnumeration
#Title_column1$ = "Name"
#Title_column2$ = "Address"
Define GadgetID.I
OpenWindow(#windows_nb, 0, 0, 870, 110, "Detect left click on header cell",
  #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ListIconGadget(#list1_nb, 10, 10, 420, WindowHeight(#windows_nb) - 20,
  #Title_column1$, 110, #PB_ListIcon_FullRowSelect)
AddGadgetColumn(#list1_nb, 1, #Title_column2$, 300)
AddGadgetItem(#list1_nb, -1, "Harry Rannit" + #LF$ +
  "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(#list1_nb, -1, "Ginger Brokeit"+ #LF$ +
  "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(#list1_nb, -1, "Didi Foundit"+ #LF$ +
  "321 Logo Drive, Mouse House, Downtown")
ListIconGadget(#list2_nb, 440, 10, 420, WindowHeight(#windows_nb) - 20,
  #Title_column1$, 110, #PB_ListIcon_FullRowSelect)
AddGadgetColumn(#list2_nb, 1, #Title_column2$, 300)
AddGadgetItem(#list2_nb, -1, "Harry Rannit" + #LF$ +
  "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(#list2_nb, -1, "Ginger Brokeit"+ #LF$ +
  "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(#list2_nb, -1, "Didi Foundit"+ #LF$ +
  "321 Logo Drive, Mouse House, Downtown")
SetGadgetCallback(#windows_nb, #list1_nb)
SetGadgetCallback(#windows_nb, #list2_nb)
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      GadgetID = EventGadget()
      Select GadgetID
        Case #list1_nb, #list2_nb
          Select EventType()
          Case #PB_EventType_LeftClick
            If EventData()
              Debug "Left click on header of column " + Str(EventData() - 1) +
                ", Gadget " + Str(GadgetID)
            Else
              Debug "-> Left click on row " + Str(GetGadgetState(GadgetID)) +
                ", Gadget " + Str(GadgetID)
            EndIf
          Case #PB_EventType_Change
            Debug "Selected row changed:"
          EndSelect
      EndSelect
  EndSelect
ForEver
CocoaMessage(0, NotificationCenter, "removeObserver:", AppDelegate)Re: ListIconGadget: No #PB_EventType_Change!
Thanks!!!! That's it!  
			
			
									
									
						Re: ListIconGadget: No #PB_EventType_Change!
I hope Fred will add the header click event to PB one day. In my eyes an essential thing for list table gadgets...
			
			
									
									
						Re: ListIconGadget: No #PB_EventType_Change!
But #PB_EventType_Change returns the wrong GadgetID !!!!
add the gadget ID to the output:
Start the code and click on the entries on left and right. The GadgetID is everytime = 3, whether you click left or right.
But if you click one time the header, then it suddenly works....
			
			
									
									
						add the gadget ID to the output:
Code: Select all
Debug "Selected row changed, Gadget " + Str(GadgetID)But if you click one time the header, then it suddenly works....
Re: ListIconGadget: No #PB_EventType_Change!
You are right, it's a bug. The callback SelectionDidChangeCallback() is a notification callback which doesn't receive in its parameters the currently selected ListIconGadget (TableView) and column object (Table Column) like the ColumnHeaderClickCallback(). So in SelectionDidChangeCallback() PostEvent() incorrectly sends the previously selected linked list elements WindowID and ListIconID.Lebostein wrote:But #PB_EventType_Change returns the wrong GadgetID !!!!
add the gadget ID to the output:Start the code and click on the entries on left and right. The GadgetID is everytime = 3, whether you click left or right.Code: Select all
Debug "Selected row changed, Gadget " + Str(GadgetID)
But if you click one time the header, then it suddenly works....
To eleminate this bug please change in SelectionDidChangeCallback() this code
Code: Select all
    PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID,
      CallbackEntry()\ListIconID, #PB_EventType_Change)Code: Select all
    PostEvent(#PB_Event_Gadget, GetActiveWindow(), GetActiveGadget(),
      #PB_EventType_Change)Re: ListIconGadget: No #PB_EventType_Change!
Thats it!!  
  Thanks a million!
			
			
									
									
						Re: ListIconGadget: No #PB_EventType_Change!
Edit: It seems the last change influences other gadgets with the #PB_EventType_Change event. What about that solution? It seems it works, but I don't know if it's right:
			
			
									
									
						Code: Select all
ProcedureC SelectionDidChangeCallback(Object.I, Selector.I, Notification.I)
  Shared CallbackEntry()
  Static ChangeSignalled.I
  ForEach CallbackEntry()
    If GetActiveWindow() = CallbackEntry()\WindowID And GetActiveGadget() = CallbackEntry()\ListIconID
      If ChangeSignalled
        PostEvent(#PB_Event_Gadget, CallbackEntry()\WindowID, CallbackEntry()\ListIconID, #PB_EventType_Change)
        ChangeSignalled = #False
      Else
        ChangeSignalled = #True
      EndIf
    EndIf
  Next
EndProcedureRe: ListIconGadget: No #PB_EventType_Change!
Your solution should be even better than my proposition. Your solution takes care that the correct entry in the shared LinkedList CallbackEntry() is selected. Due to the sharing of the LinkedList CallbackEntry() in the callbacks, the change of an entry in a callback is also in effect in the main program.Lebostein wrote:Edit: It seems the last change influences other gadgets with the #PB_EventType_Change event. What about that solution? It seems it works, but I don't know if it's right:

