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
EndProcedure
Re: 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: