For those who prefer PB's SpinGadget to the API GtkSpinButton I have found a workaround for Gtk2 and Gtk3 to detect mouse wheel events in a SpinGadget and react accordingly.
Unfortunately the Gtk3 code is more complicated because of design changes from Gtk2 to Gtk3:
In Gtk3 the widgets don't possess anymore an own GdkWindow. In Gtk2 it's easy to detect whether the mouse wheel scroll event was fired by the GtkEntry widget contained in the SpinGadget by simply comparing the GdkWindow of the event with that of the GtkEntry. In Gtk3 it's necessary to compare the coordinates of the event with those of the GtkEntry and taking also into account the padding inside the GtkEntry (to work equally well with different desktop managers and themes)...
I have tested the following code examples successfully with PB 5.41 x64 in ASCII and Unicode mode on Ubuntu 14.04 x64 with these different desktop managers:
- Enlightenment E17
- KDE
- Unity
Gtk2 (subsystem "gtk2"):
Code: Select all
EnableExplicit
#SpinGadget = 0
Define *Entry.GtkWidget
Procedure.I GetChildContainer(Widget.I, ContainerName.S)
Protected Child.I
Protected ChildrenList.I
Protected i.I
Protected *Name
ChildrenList = gtk_container_get_children_(Widget)
If ChildrenList
For i = 0 To g_list_length_(ChildrenList)
Child = g_list_nth_data_(ChildrenList, i)
If Child
*Name = gtk_widget_get_name_(Child)
If PeekS(*Name, -1, #PB_UTF8) = ContainerName
Widget = Child
Break
EndIf
EndIf
Next i
EndIf
ProcedureReturn Child
EndProcedure
ProcedureC MouseWheelCallback(*Event.GdkEventScroll, *UserData)
Shared *Entry.GtkWidget
If *Event\type = #GDK_SCROLL
If *Entry\window = gdk_window_get_parent_(*Event\window)
Select *Event\direction
Case #GDK_SCROLL_UP
SetGadgetState(#SpinGadget, GetGadgetState(#SpinGadget) + 1)
Case #GDK_SCROLL_DOWN
SetGadgetState(#SpinGadget, GetGadgetState(#SpinGadget) - 1)
EndSelect
EndIf
EndIf
gtk_main_do_event_(*Event)
EndProcedure
OpenWindow(0, 100, 100, 180, 70, "SpinGadget")
SpinGadget(#SpinGadget, 65, 20, 60, 25, 0, 100, #PB_Spin_Numeric)
SetGadgetState(#SpinGadget, 50)
SetActiveGadget(#SpinGadget)
; ----- Get GtkEntry contained in SpinGadget
*Entry = GetChildContainer(GadgetID(#SpinGadget), "GtkEntry")
; ----- Set event handler to intercept mouse wheel scroll events
gdk_event_handler_set_(@MouseWheelCallback(), 0, 0)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
gdk_event_handler_set_(0, 0, 0)
Gtk3:
Code: Select all
EnableExplicit
#SpinGadget = 0
#GTK_STATE_FLAG_SELECTED = 1 << 2
ImportC ""
gtk_style_context_get_padding(*Context, GtkStateFlags.I, *Border.GtkBorder)
gtk_widget_get_style_context(*Widget.GtkWidget)
gtk_widget_get_allocated_height(*Widget.GtkWidget)
gtk_widget_get_allocated_width(*Widget.GtkWidget)
EndImport
Structure _GtkBorder
left.w
right.w
top.w
bottom.w
EndStructure
Define *Entry.GtkWidget
Define Padding._GtkBorder
Procedure.I GetChildContainer(Widget.I, ContainerName.S)
Protected Child.I
Protected ChildrenList.I
Protected i.I
Protected *Name
ChildrenList = gtk_container_get_children_(Widget)
If ChildrenList
For i = 0 To g_list_length_(ChildrenList)
Child = g_list_nth_data_(ChildrenList, i)
If Child
*Name = gtk_widget_get_name_(Child)
If PeekS(*Name, -1, #PB_UTF8) = ContainerName
Widget = Child
Break
EndIf
EndIf
Next i
EndIf
ProcedureReturn Child
EndProcedure
Procedure GetPadding(*Widget.GtkWidget)
Shared Padding._GtkBorder
Protected StyleContext.I
StyleContext = gtk_widget_get_style_context(*Widget)
gtk_style_context_get_padding(StyleContext, #GTK_STATE_FLAG_SELECTED,
@Padding)
Padding\top + 1
EndProcedure
ProcedureC MouseWheelCallback(*Event.GdkEventScroll, *UserData)
Shared *Entry.GtkWidget
Shared Padding._GtkBorder
Protected EntryHeight.I
Protected EntryWidth.I
Protected Entry_x.I
Protected Entry_y.I
If *Event\type = #GDK_SCROLL
Entry_x = GadgetX(#SpinGadget) + Padding\left
Entry_y = GadgetY(#SpinGadget) + Padding\top
EntryWidth = gtk_widget_get_allocated_width(*Entry) - (Padding\left +
Padding\right)
EntryHeight = gtk_widget_get_allocated_height(*Entry) - (Padding\top +
Padding\bottom)
If *Event\x > Entry_x And *Event\x < Entry_x + EntryWidth And
*Event\y > Entry_y And *Event\y < Entry_y + EntryHeight
Select *Event\direction
Case #GDK_SCROLL_UP
SetGadgetState(#SpinGadget, GetGadgetState(#SpinGadget) + 1)
Case #GDK_SCROLL_DOWN
SetGadgetState(#SpinGadget, GetGadgetState(#SpinGadget) - 1)
EndSelect
EndIf
EndIf
gtk_main_do_event_(*Event)
EndProcedure
OpenWindow(0, 100, 100, 180, 70, "SpinGadget")
SpinGadget(#SpinGadget, 65, 20, 60, 25, 0, 100, #PB_Spin_Numeric)
SetActiveGadget(#SpinGadget)
SetGadgetState(#SpinGadget, 50)
; ----- Get GtkEntry contained in SpinGadget
*Entry = GetChildContainer(GadgetID(#SpinGadget), "GtkEntry")
; ----- Set event handler to intercept mouse wheel scroll events
gdk_event_handler_set_(@MouseWheelCallback(), 0, 0)
; ----- Calculate padding of GtkEntry inside of SpinGadget
GetPadding(*Entry)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
gdk_event_handler_set_(0, 0, 0)
This is a 3rd simplified example which isn't as pixel-perfect as the Gtk3 example above (because it doesn't take internal padding into account) but which runs without any change with both Gtk3 and Gtk2 (subsystem "gtk2") and is also triggered if the cursor is above the arrows (like in Windows):
Code: Select all
EnableExplicit
#SpinGadget = 0
Procedure.I GetChildContainer(Widget.I, ContainerName.S)
Protected Child.I
Protected ChildrenList.I
Protected i.I
Protected *Name
ChildrenList = gtk_container_get_children_(Widget)
If ChildrenList
For i = 0 To g_list_length_(ChildrenList)
Child = g_list_nth_data_(ChildrenList, i)
If Child
*Name = gtk_widget_get_name_(Child)
If PeekS(*Name, -1, #PB_UTF8) = ContainerName
Widget = Child
Break
EndIf
EndIf
Next i
EndIf
ProcedureReturn Child
EndProcedure
ProcedureC MouseWheelCallback(*Event.GdkEventScroll, *UserData)
If *Event\type = #GDK_SCROLL
If WindowMouseX(0) > GadgetX(#SpinGadget) And
WindowMouseX(0) < GadgetX(#SpinGadget) + GadgetWidth(#SpinGadget) And
WindowMouseY(0) > GadgetY(#SpinGadget) And
WindowMouseY(0) < GadgetY(#SpinGadget) + GadgetHeight(#SpinGadget)
Select *Event\direction
Case #GDK_SCROLL_UP
SetGadgetState(#SpinGadget, GetGadgetState(#SpinGadget) + 1)
Case #GDK_SCROLL_DOWN
SetGadgetState(#SpinGadget, GetGadgetState(#SpinGadget) - 1)
EndSelect
EndIf
EndIf
gtk_main_do_event_(*Event)
EndProcedure
OpenWindow(0, 100, 100, 180, 70, "SpinGadget")
SpinGadget(#SpinGadget, 65, 20, 60, 25, 0, 100, #PB_Spin_Numeric)
SetActiveGadget(#SpinGadget)
SetGadgetState(#SpinGadget, 50)
; ----- Set event handler to intercept mouse wheel scroll events
gdk_event_handler_set_(@MouseWheelCallback(), 0, 0)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
gdk_event_handler_set_(0, 0, 0)