[Windows] Module : AddEvents
Verfasst: 02.02.2014 12:49
Hallo.
Als ich im engl. Forum dieses Posting las, dachte ich... das krieg ich hin...
Pustekuchen. Ich hab da das MAC OS überlesen. Mist...
Vom Canvas her kennt man ja die netten Eventtypes wie MouseEnter, MouseLeave usw...
Wie wäre es denn auch bei anderen Gadgets mit diesen Types ?
Besonders das ImageGadget ist interessant, weil ein Canvas keinen AlphaKanal hat.
Wenn ein Gadget mit AE_AddEvents() registriert wurde,
sendet der interne Callback per PostEvent die Eventtypes an die EventSchleife des Fensters, die das Gadget normalerweise nicht unterstützt.
Viel Rede, kurzer Code. Sollte jemand wissen wie man dieses für Linux und Mac umsetzt... Melden !
Edit :
Neue Version als SubClassing Variante (Ohne FreeGadget) :
Als ich im engl. Forum dieses Posting las, dachte ich... das krieg ich hin...
Pustekuchen. Ich hab da das MAC OS überlesen. Mist...

Vom Canvas her kennt man ja die netten Eventtypes wie MouseEnter, MouseLeave usw...
Wie wäre es denn auch bei anderen Gadgets mit diesen Types ?
Besonders das ImageGadget ist interessant, weil ein Canvas keinen AlphaKanal hat.
Wenn ein Gadget mit AE_AddEvents() registriert wurde,
sendet der interne Callback per PostEvent die Eventtypes an die EventSchleife des Fensters, die das Gadget normalerweise nicht unterstützt.
Viel Rede, kurzer Code. Sollte jemand wissen wie man dieses für Linux und Mac umsetzt... Melden !

Edit :
- 09.06.2024
Fast 10 Jahre später
Eine SubClass Variante ohne FreeGadget Event... weil ich es gerade brauchte. - 07.02.2014
EventType Variable einstellbar (Danke TS-Soft)
AE_SetEventType_FreeGadget(EventTypeValue) & AE_GetEventType_FreeGadget() hinzugefügt und Beispielcode angepasst. - 04.02.2014
#PB_EventType_FreeGadget hinzugefügt.
Code: Alles auswählen
DeclareModule AddEvents
Declare AE_AddEvents(Window, Gadget) ; Add #PB_EventTypes to a gadget
Declare AE_GadgetMouseX(Gadget) ; Get MouseX in a gadget (like WindowMouseX()) if AE_AddEvents() registered this gadget
Declare AE_GadgetMouseY(Gadget) ; Get MouseY in a gadget (like WindowMouseY()) if AE_AddEvents() registered this gadget
Declare AE_SetEventType_FreeGadget(EventTypeValue) ; Set the EventType Value to your Custom Value
Declare AE_GetEventType_FreeGadget() ; Get the actual EventType Value for #EventType_FreeGadget
EndDeclareModule
Module AddEvents
;:---
;:-
;:- Module : AddEvents
;:- OS : Windows Only (min. XP/2000)
;:- Author : George Bisonte
;:- Date : 01, Feb. 2014
;:-
;:- Add #PB_EventTypes to other gadgets as canvas.
;:-
;:---
EnableExplicit
Structure struct_addeventdata
Window.i
Gadget.i
mTrack.i
mx.i
my.i
OldProc.i
EndStructure
Global NewMap AE_Data.struct_addeventdata()
Global EventType_FreeGadget = #PB_EventType_FirstCustomValue
Procedure AE_SetEventType_FreeGadget(EventTypeValue)
EventType_FreeGadget = EventTypeValue
EndProcedure
Procedure AE_GetEventType_FreeGadget()
ProcedureReturn EventType_FreeGadget
EndProcedure
Procedure AE_SendEvent(hWnd, EType) ; All OS
Protected mPosX, mPosY, gPosLeft, gPosTop, gPosRight, gPosBottom
With AE_Data(Str(hWnd))
gPosLeft = GadgetX(\Gadget, #PB_Gadget_ScreenCoordinate)
gPosTop = GadgetY(\Gadget, #PB_Gadget_ScreenCoordinate)
gPosRight = gPosLeft + GadgetWidth(\Gadget)
gPosBottom = gPosTop + GadgetHeight(\Gadget)
mPosX = DesktopMouseX()
mPosY = DesktopMouseY()
\mx = mPosX - gPosLeft : \my = mPosY - gPosTop
PostEvent(#PB_Event_Gadget, \Window, \Gadget, EType)
EndWith
EndProcedure
Procedure AE_CallBack(hWnd, uMsg, wParam, lParam) ; TRACKMOUSEEVENT, #WM_ Messages, CallWindowProc_(OldProc, hWnd, uMsg, wParam, lParam)
Protected OldProc, tm.TRACKMOUSEEVENT
If Not FindMapElement(AE_Data(), Str(hWnd))
ProcedureReturn #Null
EndIf
With AE_Data(Str(hWnd))
OldProc = \OldProc
Select uMsg
Case #WM_DESTROY
AE_SendEvent(hWnd, EventType_FreeGadget)
DeleteMapElement(AE_Data(), Str(hWnd))
Case #WM_LBUTTONDOWN
AE_SendEvent(hWnd, #PB_EventType_LeftButtonDown)
Case #WM_RBUTTONDOWN
AE_SendEvent(hWnd, #PB_EventType_RightButtonDown)
Case #WM_MBUTTONDOWN
AE_SendEvent(hWnd, #PB_EventType_MiddleButtonDown)
Case #WM_LBUTTONUP
AE_SendEvent(hWnd, #PB_EventType_LeftButtonUp)
Case #WM_RBUTTONUP
AE_SendEvent(hWnd, #PB_EventType_RightButtonUp)
Case #WM_MBUTTONUP
AE_SendEvent(hWnd, #PB_EventType_MiddleButtonUp)
Case #WM_MOUSEMOVE
If Not \mTrack
\mTrack = #True
tm\cbSize = SizeOf(TRACKMOUSEEVENT)
tm\dwFlags = #TME_LEAVE
tm\hwndTrack = hWnd
TrackMouseEvent_(@tm)
AE_SendEvent(hWnd, #PB_EventType_MouseEnter)
If OldProc : CallWindowProc_(OldProc, hWnd, uMsg, wParam, lParam) : EndIf
ProcedureReturn #Null
Else ; MouseMove
AE_SendEvent(hWnd, #PB_EventType_MouseMove)
EndIf
Case #WM_MOUSELEAVE
AE_SendEvent(hWnd, #PB_EventType_MouseLeave)
\mTrack = #False : \mx = -1 : \my = -1
ProcedureReturn #Null
EndSelect
EndWith
If OldProc
ProcedureReturn CallWindowProc_(OldProc, hWnd, uMsg, wParam, lParam)
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure AE_AddEvents(Window, Gadget) ; SetWindowLongPtr_(GadgetID(Gadget), #GWLP_WNDPROC, @AE_CallBack())
If IsGadget(Gadget) And IsWindow(Window)
AE_Data(Str(GadgetID(Gadget)))\Gadget = Gadget
AE_Data(Str(GadgetID(Gadget)))\Window = Window
AE_Data(Str(GadgetID(Gadget)))\mTrack = #False
AE_Data(Str(GadgetID(Gadget)))\mx = -1
AE_Data(Str(GadgetID(Gadget)))\my = -1
AE_Data(Str(GadgetID(Gadget)))\OldProc = SetWindowLongPtr_(GadgetID(Gadget), #GWLP_WNDPROC, @AE_CallBack())
EndIf
EndProcedure
Procedure AE_GadgetMouseX(Gadget) ; All OS
Protected Result = -1
If IsGadget(Gadget)
If FindMapElement(AE_Data(), Str(GadgetID(Gadget)))
Result = AE_Data(Str(GadgetID(Gadget)))\mx
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure AE_GadgetMouseY(Gadget) ; All OS
Protected Result = -1
If IsGadget(Gadget)
If FindMapElement(AE_Data(), Str(GadgetID(Gadget)))
Result = AE_Data(Str(GadgetID(Gadget)))\my
EndIf
EndIf
ProcedureReturn Result
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile ; Test
EnableExplicit
UseModule AddEvents
Enumeration #PB_EventType_FirstCustomValue; customevents
#custom1
#custom2
EndEnumeration
AE_SetEventType_FreeGadget(#PB_Compiler_EnumerationValue) ; <- thx ts soft
Define Event, Quit
Procedure MouseEnterProc()
Debug "Enter"
EndProcedure
LoadImage(1, #PB_Compiler_Home + "Examples\Sources\Data\GeeBee2.bmp") ; Change to your Image
OpenWindow(0, 0, 0, 248, 148, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(1, 10, 10, 0, 0, ImageID(1))
; Add Extra Eventtypes
AE_AddEvents(0, 1)
; This works also now with BindGadgetEvent...
BindGadgetEvent(1, @MouseEnterProc(), #PB_EventType_MouseEnter)
Repeat
Event = WaitWindowEvent()
Select Event
Case #WM_LBUTTONDOWN
If AE_GadgetMouseX(1) = -1
Debug "Not in Gadget"
EndIf
Case #PB_Event_CloseWindow
Quit = 1
Case #PB_Event_Gadget
If EventGadget() = 1
Select EventType()
Case #PB_EventType_LeftButtonDown
Debug "LeftButtonDown on x : " + Str(AE_GadgetMouseX(EventGadget())) + " y : " + Str(AE_GadgetMouseY(EventGadget()))
Case #PB_EventType_RightButtonDown
Debug "RightButtonDown on x : " + Str(AE_GadgetMouseX(EventGadget())) + " y : " + Str(AE_GadgetMouseY(EventGadget()))
FreeGadget(1)
Case #PB_EventType_MiddleButtonDown
Debug "MiddleButtonDown on x : " + Str(AE_GadgetMouseX(EventGadget())) + " y : " + Str(AE_GadgetMouseY(EventGadget()))
Case #PB_EventType_MouseLeave
Debug "Leave"
Case AE_GetEventType_FreeGadget() ; <- thx ts soft
Debug "FreeGadget : " + Str(EventGadget())
EndSelect
EndIf
EndSelect
Until Quit > 0
CompilerEndIf
Code: Alles auswählen
;-@TOP=========================================================================
;
; Name ......... : AddEvents (SubClass Variant)
; File ......... : module_addevents.pbi
; Type ......... : Module
; Author ....... : George Bisonte
; CreateDate ... : 9, June 2024
; Compiler ..... : PureBasic V6.11 LTS x86/x64
; Flags ........ : Unicode/XP-Skin/UserMode/ThreadSafe
; Subsystem .... : none
; TargetOS ..... : Windows only
; License ...... : MIT License
; Link ......... : https://www.purebasic.fr/german/viewtopic.php?p=319963
; Description .. : Add extra Eventypes to an ImageGadget like the CanvasGadget
;
;==============================================================================
DeclareModule AddEvents
; Inspirated from forumposts by edel, TS-Soft, Axolotl, mk-soft in german/english forum
EnableExplicit
Declare.i AddImageGadgetEventTypes(Window, Gadget) ; Register the ImageGadget
Declare.i GetImageGadgetMouseX() ; Get the mouse coord from EventData()
Declare.i GetImageGadgetMouseY() ; Get the mouse coord from EventData()
EndDeclareModule
Module AddEvents
Import "Comctl32.lib"
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
SetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, dwRefData) As "SetWindowSubclass"
GetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, *dwRefData) As "GetWindowSubclass"
RemoveWindowSubclass_(hWnd, *fnSubclass, uIdSubclass) As "RemoveWindowSubclass"
DefSubclassProc_(hWnd, uMsg, wParam, lParam) As "DefSubclassProc"
CompilerElse
SetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, dwRefData) As "_SetWindowSubclass@16"
GetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, *dwRefData) As "_GetWindowSubclass@16"
RemoveWindowSubclass_(hWnd, *fnSubclass, uIdSubclass) As "_RemoveWindowSubclass@12"
DefSubclassProc_(hWnd, uMsg, wParam, lParam) As "_DefSubclassProc@16"
CompilerEndIf
EndImport
Enumeration 1
#SubClass_ImageGadget
EndEnumeration
Structure s_subclassdata
Window.i
Gadget.i
mTrack.i
mx.w
my.w
EndStructure
Procedure.w LOWORD(Value.l)
ProcedureReturn Value & $FFFF
EndProcedure
Procedure.w HIWORD(Value.l)
ProcedureReturn (Value >> 16) & $FFFF
EndProcedure
Procedure.l MAKELONG(low.w, high.w)
ProcedureReturn (high * $10000) | (low & $FFFF)
EndProcedure
Procedure.i GetImageGadgetMouseX()
Protected x.w = LOWORD(EventData())
ProcedureReturn x
EndProcedure
Procedure.i GetImageGadgetMouseY()
Protected y.w = HIWORD(EventData())
ProcedureReturn y
EndProcedure
Procedure.i SubclassGadgetProc(hWnd, uMsg, wParam, lParam, uIdSubclass, *dwRefData.s_subclassdata)
Protected tm.TRACKMOUSEEVENT, GadgetRect.RECT, eData.l
If *dwRefData
GetWindowRect_(hWnd, @GadgetRect)
*dwRefData\mx = DesktopMouseX() - GadgetRect\left
*dwRefData\my = DesktopMouseY() - GadgetRect\top
If *dwRefData\mx < 0
*dwRefData\mx = -1
*dwRefData\my = -1
EndIf
eData = MAKELONG(*dwRefData\mx, *dwRefData\my)
Select uMsg
Case #WM_NCDESTROY ; FreeGadget
Debug "If you want, you can add a FreeGadget Event at this point ;)"
RemoveWindowSubclass_(hWnd, @SubclassGadgetProc(), uIdSubclass)
FreeStructure(*dwRefData)
Case #WM_LBUTTONDOWN
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_LeftButtonDown, eData)
Case #WM_LBUTTONUP
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_LeftButtonUp, eData)
Case #WM_MBUTTONDOWN
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_MiddleButtonDown, eData)
Case #WM_MBUTTONUP
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_MiddleButtonUp, eData)
Case #WM_RBUTTONDOWN
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_RightButtonDown, eData)
Case #WM_RBUTTONUP
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_RightButtonUp, eData)
Case #WM_MOUSELEAVE
*dwRefData\mTrack = #False
eData = MAKELONG(-1, -1)
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_MouseLeave, eData)
Case #WM_MOUSEMOVE
If Not *dwRefData\mTrack
*dwRefData\mTrack = #True
tm\cbSize = SizeOf(TRACKMOUSEEVENT)
tm\dwFlags = #TME_LEAVE
tm\hwndTrack = hWnd
TrackMouseEvent_(@tm)
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_MouseEnter, eData)
Else
PostEvent(#PB_Event_Gadget, *dwRefData\Window, *dwRefData\Gadget, #PB_EventType_MouseMove, eData)
EndIf
EndSelect
EndIf
ProcedureReturn DefSubclassProc_(hWnd, uMsg, wParam, lParam)
EndProcedure
Procedure.i AddImageGadgetEventTypes(Window, Gadget)
Protected *SubClassData.s_subclassdata
Protected Result = #False
If IsWindow(Window) And IsGadget(Gadget)
If GadgetType(Gadget) = #PB_GadgetType_Image
*SubClassData.s_subclassdata = AllocateStructure(s_subclassdata)
If *SubClassData
With *SubClassData
\Gadget = Gadget
\Window = Window
\mTrack = #False
\mx = -1
\my = -1
EndWith
SetWindowSubclass_(GadgetID(Gadget), @SubclassGadgetProc(), #SubClass_ImageGadget, *SubClassData)
Result = #True
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
UseModule AddEvents
LoadImage(1, #PB_Compiler_Home + "Examples\Sources\Data\GeeBee2.bmp") ; Change to your Image
OpenWindow(10, 0, 0, 248, 148, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(7, 10, 10, 0, 0, ImageID(1))
AddImageGadgetEventTypes(10, 7)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
If EventGadget() = 7
Select EventType()
Case #PB_EventType_LeftButtonUp
Debug "LMB - Up x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_LeftButtonDown
Debug "LMB - Down x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_RightButtonUp
Debug "RMB - Up x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_RightButtonDown
Debug "RMB - Down x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_MouseEnter
Debug "Mouse Enter x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_MouseLeave
Debug "Mouse Leave x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_MouseMove
Debug "Mouse Move x = " + Str(GetImageGadgetMouseX()) + " - y = " + Str(GetImageGadgetMouseY())
Case #PB_EventType_LeftClick ; The original EventTypes are also here ;)
Debug "LeftClick"
EndSelect
EndIf
EndSelect
ForEver
CompilerEndIf