gadget and probably others(not tested) in Mac and Windows, even when mouse is down.
Code: Select all
;gadgetEx.pb
;Justin 07/24
EnableExplicit
;- DECLARES
#GADGETEX_PROP_CALLBACK = "_pb_cb_"
#GADGETEX_PROP_OLD_PROC = "_pb_oldProc_"
#GADGETEX_PROP_TAREA = "_pb_tarea_"
Enumeration
#GADGETEX_EVENT_MOUSEMOVE
EndEnumeration
Procedure.w HIWORD2(Value.i)
ProcedureReturn (((Value) >> 16) & $FFFF)
EndProcedure
Procedure.w LOWORD2(Value.i)
ProcedureReturn ((Value) & $FFFF)
EndProcedure
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
#GADGETEX_MODIFIER_CONTROL = #MK_CONTROL
#GADGETEX_MODIFIER_SHIFT = #MK_SHIFT
#GADGETEX_MODIFIER_ALT = $80
#GADGETEX_MODIFIER_LEFTMOUSEBUTTON = #MK_LBUTTON
#GADGETEX_MODIFIER_RIGHTMOUSEBUTTON = #MK_RBUTTON
#GADGETEX_MODIFIER_MIDDLEMOUSEBUTTON = #MK_MBUTTON
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
#OBJC_ASSOCIATION_ASSIGN = 0
;NSTrackingAreaOptions
#NSTrackingMouseEnteredAndExited = $01
#NSTrackingMouseMoved = $02
#NSTrackingCursorUpdate = $04
#NSTrackingActiveWhenFirstResponder = $10
#NSTrackingActiveInKeyWindow = $20
#NSTrackingActiveInActiveApp = $40
#NSTrackingActiveAlways = $80
#NSTrackingAssumeInside = $100
#NSTrackingInVisibleRect = $200
#NSTrackingEnabledDuringMouseDrag = $400
#NSEventModifierFlagShift = 1 << 17
#NSEventModifierFlagControl = 1 << 18
#NSEventModifierFlagOption = 1 << 19
#NSEventModifierFlagCommand = 1 << 20
#GADGETEX_MODIFIER_CONTROL = #NSEventModifierFlagControl
#GADGETEX_MODIFIER_SHIFT = #NSEventModifierFlagShift
#GADGETEX_MODIFIER_ALT = #NSEventModifierFlagOption
#GADGETEX_MODIFIER_COMMAND = #NSEventModifierFlagCommand
#GADGETEX_MODIFIER_LEFTMOUSEBUTTON = 1 << 24
#GADGETEX_MODIFIER_RIGHTMOUSEBUTTON = 1 << 25
#GADGETEX_MODIFIER_MIDDLEMOUSEBUTTON = 1 << 26
PrototypeC gadgetEx_onMouseMovedProto(obj.i, sel.i, nsEv.i)
PrototypeC gadgetEx_onMouseDraggedProto(obj.i, sel.i, nsEv.i)
PrototypeC gadgetEx_onUpdateTrackingAreasProto(obj.i, sel.i)
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
#GADGETEX_MODIFIER_CONTROL = #GDK_CONTROL_MASK
#GADGETEX_MODIFIER_SHIFT = #GDK_SHIFT_MASK
#GADGETEX_MODIFIER_ALT = #GDK_MOD1_MASK
#GADGETEX_MODIFIER_LEFTMOUSEBUTTON = #GDK_BUTTON1_MASK
#GADGETEX_MODIFIER_RIGHTMOUSEBUTTON = #GDK_BUTTON3_MASK
#GADGETEX_MODIFIER_MIDDLEMOUSEBUTTON = #GDK_BUTTON2_MASK
Structure GdkEvent Align #PB_Structure_AlignC
StructureUnion
type.l
motion.GdkEventMotion
EndStructureUnion
EndStructure
CompilerEndIf
;- GADGETEX_GLOBAL
Structure GADGETEX_GLOBAL
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
oldMouseMoved.gadgetEx_onMouseMovedProto
oldMouseDragged.gadgetEx_onMouseDraggedProto
oldRightMouseDragged.gadgetEx_onMouseDraggedProto
oldUpdateTrackingAreas.gadgetEx_onUpdateTrackingAreasProto
CompilerEndIf
EndStructure
;- GADGETEX_EVENT
Structure GADGETEX_EVENT
type.l
EndStructure
;- GADGETEX_EVENT_MOUSEMOVE
Structure GADGETEX_EVENT_MOUSEMOVE Extends GADGETEX_EVENT
x.l
y.l
modifiers.l ;biwise #GADGETEX_MODIFIER_
EndStructure
Prototype gadgetEx_callbackProto(gdt.i, *evt.GADGETEX_EVENT)
;-
;- PRIVATE
Procedure.i gadgetEx()
Static.GADGETEX_GLOBAL *gex
If *gex = 0
*gex = AllocateStructure(GADGETEX_GLOBAL)
EndIf
ProcedureReturn *gex
EndProcedure
;-
;- WINDOWS
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Procedure gadgetEx_onMouseMoveWin(hwnd.i, msg.l, wparam.i, lparam.i)
Protected.gadgetEx_callbackProto cb
Protected.GADGETEX_EVENT_MOUSEMOVE ev
cb = GetProp_(hwnd, #GADGETEX_PROP_CALLBACK)
If cb
ev\type = #GADGETEX_EVENT_MOUSEMOVE
ev\x = LOWORD2(lparam)
ev\y = HIWORD2(lparam)
ev\modifiers = wparam
If GetKeyState_(#VK_MENU) & $8000
ev\modifiers | #GADGETEX_MODIFIER_ALT
EndIf
cb(GetProp_(hwnd, "PB_ID"), @ev)
EndIf
EndProcedure
Procedure gadgetEx_onNcDestroyWin(hwnd.i, msg.l, wparam.i, lparam.i)
Protected.i oldProc
oldProc = GetProp_(hwnd, #GADGETEX_PROP_OLD_PROC)
RemoveProp_(hwnd, #GADGETEX_PROP_CALLBACK)
RemoveProp_(hwnd, #GADGETEX_PROP_OLD_PROC)
SetWindowLongPtr_(hwnd, #GWLP_WNDPROC, oldProc)
ProcedureReturn CallWindowProc_(oldProc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure gadgetEx_procWin(hwnd.i, msg.l, wparam.i, lparam.i)
Select msg
Case #WM_MOUSEMOVE
gadgetEx_onMouseMoveWin(hwnd, msg, wparam, lparam)
Case #WM_NCDESTROY : ProcedureReturn gadgetEx_onNcDestroyWin(hwnd, msg, wparam, lparam)
EndSelect
ProcedureReturn CallWindowProc_(GetProp_(hwnd, #GADGETEX_PROP_OLD_PROC), hwnd, msg, wparam, lparam)
EndProcedure
;-
;- MAC
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
Procedure gadgetEx_onMouseMoveHandler(obj.i, sel.i, nsEv.i)
Protected.NSPoint pt
Protected.GADGETEX_EVENT_MOUSEMOVE ev
Protected.gadgetEx_callbackProto cb
Protected.i gdt
Protected.l btnMask, modifiers
cb = objc_getAssociatedObject_(obj, #GADGETEX_PROP_CALLBACK)
If cb
gdt = CocoaMessage(0, obj, "tag")
CocoaMessage(@pt, nsEv, "locationInWindow")
CocoaMessage(@pt, obj, "convertPoint:@", @pt, "fromView:", #nil)
ev\type = #GADGETEX_EVENT_MOUSEMOVE
ev\x = pt\x
ev\y = GadgetHeight(gdt) - pt\y
ev\modifiers = CocoaMessage(0, nsEv, "modifierFlags")
btnMask = CocoaMessage(0, 0, "NSEvent pressedMouseButtons")
If btnMask & 1 << 0
ev\modifiers | #GADGETEX_MODIFIER_LEFTMOUSEBUTTON
EndIf
If btnMask & 1 << 1
ev\modifiers | #GADGETEX_MODIFIER_RIGHTMOUSEBUTTON
EndIf
If btnMask & 1 << 2
ev\modifiers | #GADGETEX_MODIFIER_MIDDLEMOUSEBUTTON
EndIf
cb(gdt, @ev)
EndIf
EndProcedure
Procedure gadgetEx_onMouseMovedMac(obj.i, sel.i, nsEv.i)
Protected.GADGETEX_GLOBAL *gex = gadgetEx()
gadgetEx_onMouseMoveHandler(obj, sel, nsEv)
If *gex\oldMouseMoved
*gex\oldMouseMoved(obj, sel, nsEv)
EndIf
EndProcedure
Procedure gadgetEx_onMouseDraggedMac(obj.i, sel.i, nsEv.i)
Protected.GADGETEX_GLOBAL *gex = gadgetEx()
gadgetEx_onMouseMoveHandler(obj, sel, nsEv)
If *gex\oldMouseDragged
*gex\oldMouseDragged(obj, sel, nsEv)
EndIf
EndProcedure
Procedure gadgetEx_onRightMouseDraggedMac(obj.i, sel.i, nsEv.i)
Protected.GADGETEX_GLOBAL *gex = gadgetEx()
gadgetEx_onMouseMoveHandler(obj, sel, nsEv)
If *gex\oldRightMouseDragged
*gex\oldRightMouseDragged(obj, sel, nsEv)
EndIf
EndProcedure
ProcedureC gadgetEx_onUpdateTrackingAreas(obj.i, sel.i)
Protected.NSRect rc
Protected.i trackingArea
Protected.GADGETEX_GLOBAL *gex = gadgetEx()
trackingArea = objc_getAssociatedObject_(obj, #GADGETEX_PROP_TAREA)
If trackingArea
CocoaMessage(0, obj, "removeTrackingArea:", trackingArea)
CocoaMessage(0, trackingArea, "release")
EndIf
trackingArea = CocoaMessage(0, 0, "NSTrackingArea alloc")
objc_setAssociatedObject_(obj, #GADGETEX_PROP_TAREA, trackingArea, #OBJC_ASSOCIATION_ASSIGN)
CocoaMessage(0, trackingArea, "initWithRect:@", @rc,
"options:", #NSTrackingMouseEnteredAndExited | #NSTrackingActiveInActiveApp | #NSTrackingInVisibleRect | #NSTrackingMouseMoved | #NSTrackingEnabledDuringMouseDrag,
"owner:", obj, "userInfo:", #nil)
CocoaMessage(0, obj, "addTrackingArea:", trackingArea)
If *gex\oldUpdateTrackingAreas
*gex\oldUpdateTrackingAreas(obj, sel)
EndIf
EndProcedure
;-
;- LINUX
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
Procedure gadgetEx_onEventMotionNotifyLin(widget.i, *evt.GdkEventMotion, gdt.i)
Protected.GADGETEX_EVENT_MOUSEMOVE ev
Protected.gadgetEx_callbackProto cb
cb = g_object_get_data_(widget, #GADGETEX_PROP_CALLBACK)
If cb
ev\type = #GADGETEX_EVENT_MOUSEMOVE
ev\x = *evt\x
ev\y = *evt\y
ev\modifiers = *evt\state
cb(gdt, @ev)
EndIf
EndProcedure
Procedure gadgetEx_onEventLin(widget.i, *evt.GdkEvent, gdt.i)
Select *evt\type
Case #GDK_MOTION_NOTIFY : ProcedureReturn gadgetEx_onEventMotionNotifyLin(widget, *evt, gdt)
EndSelect
EndProcedure
CompilerEndIf
;-
;- PUBLIC
Procedure gadgetEx_setup(gdt.i, callback.i)
Protected.i osHandle
Protected.GADGETEX_GLOBAL *gex = gadgetEx()
osHandle = GadgetID(gdt)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SetProp_(osHandle, #GADGETEX_PROP_CALLBACK, callback)
SetProp_(osHandle, #GADGETEX_PROP_OLD_PROC, SetWindowLongPtr_(osHandle, #GWLP_WNDPROC, @gadgetEx_procWin()))
ProcedureReturn #True
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
Protected.i viewClass
Protected.i selMouseMoved, selMouseDragged, selUpdateTrackingAreas, selRightMouseDragged
objc_setAssociatedObject_(osHandle, #GADGETEX_PROP_CALLBACK, callback, #OBJC_ASSOCIATION_ASSIGN)
viewClass = object_getClass_(osHandle)
selMouseMoved = sel_registerName_("mouseMoved:")
selMouseDragged = sel_registerName_("mouseDragged:")
selRightMouseDragged = sel_registerName_("rightMouseDragged:")
selUpdateTrackingAreas = sel_registerName_("updateTrackingAreas")
If class_getMethodImplementation_(viewClass, selMouseMoved) <> @gadgetEx_onMouseMovedMac()
*gex\oldMouseMoved = class_replaceMethod_(viewClass, selMouseMoved, @gadgetEx_onMouseMovedMac(), "v@:@")
EndIf
If class_getMethodImplementation_(viewClass, selMouseDragged) <> @gadgetEx_onMouseDraggedMac()
*gex\oldMouseDragged = class_replaceMethod_(viewClass, selMouseDragged, @gadgetEx_onMouseDraggedMac(), "v@:@")
EndIf
If class_getMethodImplementation_(viewClass, selUpdateTrackingAreas) <> @gadgetEx_onUpdateTrackingAreas()
*gex\oldUpdateTrackingAreas = class_replaceMethod_(viewClass, selUpdateTrackingAreas, @gadgetEx_onUpdateTrackingAreas(), "v@:@")
EndIf
If class_getMethodImplementation_(viewClass, selRightMouseDragged) <> @gadgetEx_onRightMouseDraggedMac()
*gex\oldRightMouseDragged = class_replaceMethod_(viewClass, selRightMouseDragged, @gadgetEx_onRightMouseDraggedMac(), "v@:@")
EndIf
ProcedureReturn #True
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
Select GadgetType(gdt)
Case #PB_GadgetType_Image
Protected.i evBox, wdName, parent
parent = gtk_widget_get_parent_(osHandle)
wdName = gtk_widget_get_name_(parent)
If wdName = 0 : ProcedureReturn #False: EndIf
If PeekS(wdName, -1, #PB_UTF8) = "GtkEventBox"
evBox = parent
ElseIf PeekS(wdName, -1, #PB_UTF8) = "GtkFrame"
parent = gtk_widget_get_parent_(parent)
wdName = gtk_widget_get_name_(parent)
If wdName = 0 : ProcedureReturn #False : EndIf
If PeekS(wdName, -1, #PB_UTF8) = "GtkEventBox"
evBox = parent
Else
ProcedureReturn #False
EndIf
Else
ProcedureReturn #False
EndIf
g_object_set_data_(evBox, #GADGETEX_PROP_CALLBACK, callback)
gtk_widget_add_events_(evBox, #GDK_POINTER_MOTION_MASK)
g_signal_connect_(evBox, "event", @gadgetEx_onEventLin(), gdt)
ProcedureReturn #True
;TODO Handle more gadget types
Default
ProcedureReturn #False
EndSelect
CompilerEndIf
EndProcedure
;-
;- --------------
;- TEST
;- --------------
Procedure.s getModifiersStr(mods.l)
Protected.s smods
If mods & #GADGETEX_MODIFIER_ALT = #GADGETEX_MODIFIER_ALT
smods + " " + "Alt"
EndIf
If mods & #GADGETEX_MODIFIER_CONTROL = #GADGETEX_MODIFIER_CONTROL
smods + " " + "Ctrl"
EndIf
If mods & #GADGETEX_MODIFIER_SHIFT = #GADGETEX_MODIFIER_SHIFT
smods + " " + "Shift"
EndIf
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
If mods & #GADGETEX_MODIFIER_COMMAND = #GADGETEX_MODIFIER_COMMAND
smods + " " + "Cmd"
EndIf
CompilerEndIf
If mods & #GADGETEX_MODIFIER_LEFTMOUSEBUTTON = #GADGETEX_MODIFIER_LEFTMOUSEBUTTON
smods + " " + "LButton"
EndIf
If mods & #GADGETEX_MODIFIER_RIGHTMOUSEBUTTON = #GADGETEX_MODIFIER_RIGHTMOUSEBUTTON
smods + " " + "RButton"
EndIf
If mods & #GADGETEX_MODIFIER_MIDDLEMOUSEBUTTON = #GADGETEX_MODIFIER_MIDDLEMOUSEBUTTON
smods + " " + "MButton"
EndIf
ProcedureReturn smods
EndProcedure
Procedure imgGdt1_Callback(gdt.i, *evt.GADGETEX_EVENT)
Select *evt\type
Case #GADGETEX_EVENT_MOUSEMOVE
Protected.GADGETEX_EVENT_MOUSEMOVE *evtMouseMove = *evt
Debug "img mouse move " + gdt + " " + *evtMouseMove\x + " " + *evtMouseMove\y
Debug "Modifiers " + getModifiersStr(*evtMouseMove\modifiers)
Debug ""
EndSelect
EndProcedure
Procedure main()
OpenWindow(0, 0, 0, 245, 105, "ImageGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
If LoadImage(0, #PB_Compiler_Home + "examples/sources/Data/Map.bmp")
ImageGadget(1, 10, 10, 100, 83, ImageID(0))
gadgetEx_setup(1, @imgGdt1_Callback())
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
EndProcedure
main()