Seite 1 von 3

Modul MouseOver

Verfasst: 27.07.2015 14:50
von mk-soft
Fügt die Gadgetevents MouseEnter und MouseLeave für alle Gadgets hinzu.

Update v1.01
- MacOS getestet

Update v1.02
- Windows x86 und x64
- Linux x86 und x64
- MacOS x64

Update v1.03
- Linux optimiert

Update v1.04
- Bugfix Init: falsche WindowsID für Timer

Update v1.05
- Bugfix Linux GTK3

Wegen ein Bug in PB v5.31 für MacOS (x86) beim Import ist es als Modul nicht lauffähig

Code: Alles auswählen

;-Begin Module MouseOver
; Comment: Modul MouseOver
; Author : mk-soft
; Version: v1.05
; Created: 27.07.2015
; Updated: 03.02.2016
; Link   : http://www.purebasic.fr/german/viewtopic.php?f=8&t=29047   
;
; Thanks to:
;
; - Wilbert for mac functions get object under mouse 
;     http://www.purebasic.fr/english/viewtopic.php?f=19&t=62056
;
; - Shardik for linux functions get object under mouse
;

DeclareModule MouseOver
  Declare Init(timer=999)
  Declare Release(timer=999)
EndDeclareModule

Module MouseOver
  
  ; Import internal function ------------------------------------------------------------
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Import ""
  CompilerElse
    ImportC ""
  CompilerEndIf
      PB_Object_EnumerateStart( PB_Objects )
      PB_Object_EnumerateNext( PB_Objects, *ID.Integer )
      PB_Object_EnumerateAbort( PB_Objects )
      PB_Object_GetObject( PB_Object , DynamicOrArrayID)
      PB_Window_Objects.i
      PB_Gadget_Objects.i
    EndImport
    
  ; -------------------------------------------------------------------------------------
  
  Global window_for_timer = -1
  
  ; -------------------------------------------------------------------------------------
  
  Procedure EventHandler()
    
    Static lasthandle, lastgadget = -1, x, y, last_x, last_y
    
    Protected gadget, handle
    
    x = WindowMouseX(EventWindow())
    y = WindowMouseY(EventWindow())
    If x <> last_x Or y <> last_y
      last_x = x
      last_y = y
      
      CompilerSelect #PB_Compiler_OS
        CompilerCase #PB_OS_Windows
          Protected desktop_x, desktop_y
          desktop_x = DesktopMouseX()
          desktop_y = DesktopMouseY()
          handle = WindowFromPoint_(desktop_y << 32 | desktop_x)
        CompilerCase #PB_OS_MacOS
          Protected win_id, win_cv, pt.NSPoint
          win_id = WindowID(EventWindow())
          win_cv = CocoaMessage(0, win_id, "contentView")
          CocoaMessage(@pt, win_id, "mouseLocationOutsideOfEventStream")
          handle = CocoaMessage(0, win_cv, "hitTest:@", @pt)
        CompilerCase #PB_OS_Linux
          Protected desktop_x, desktop_y, *GdkWindow.GdkWindowObject
          *GdkWindow.GdkWindowObject = gdk_window_at_pointer_(@desktop_x,@desktop_y)
          If *GdkWindow
            gdk_window_get_user_data_(*GdkWindow, @handle)
          Else
            handle = 0
          EndIf
      CompilerEndSelect
      
      If handle <> lasthandle
        If lastgadget >= 0
          If GadgetType(lastgadget) <> #PB_GadgetType_Canvas
            PostEvent(#PB_Event_Gadget, #PB_Ignore, lastgadget, #PB_EventType_MouseLeave)
          EndIf
          lastgadget = -1
        EndIf
        ; Find gadgetid over handle
        PB_Object_EnumerateStart(PB_Gadget_Objects)
        While PB_Object_EnumerateNext(PB_Gadget_Objects, @gadget)
          If handle = GadgetID(gadget)
            lastgadget = gadget
            If GadgetType(lastgadget) <> #PB_GadgetType_Canvas
              PostEvent(#PB_Event_Gadget, #PB_Any, gadget, #PB_EventType_MouseEnter)
            EndIf
            PB_Object_EnumerateAbort(PB_Gadget_Objects)
            Break
          EndIf
        Wend
        lasthandle = handle
      EndIf
    EndIf
    
  EndProcedure
  
  ; -------------------------------------------------------------------------------------
  
  Procedure Init(timer=999)
    Protected window
    PB_Object_EnumerateStart(PB_Window_Objects)
    If PB_Object_EnumerateNext(PB_Window_Objects, @window)
      AddWindowTimer(window, timer, 100)
      BindEvent(#PB_Event_Timer , @EventHandler())
      PB_Object_EnumerateAbort(PB_Window_Objects)
      window_for_timer = window
    EndIf
  EndProcedure
  
  ; -------------------------------------------------------------------------------------
  
  Procedure Release(timer=999)
    If window_for_timer >= 0
      UnbindEvent(#PB_Event_Timer , @EventHandler())
      RemoveWindowTimer(window_for_timer, timer)
      window_for_timer = -1
    EndIf
  EndProcedure
  
  ; -------------------------------------------------------------------------------------
  
EndModule

;-End Module MouseOver

; ***************************************************************************************

;- Example 1

CompilerIf #PB_Compiler_IsMainFile
  
  Enumeration FormWindow
    #Window_0
  EndEnumeration
  
  Enumeration FormGadget
    #Editor_0
    #Canvas_0
    #ExplorerList_0
    #ExplorerTree_0
    #ListView_0
    #ListIcon_0
    #Combo_0
    #Date_0
    #Option_0
    #Option_1
    #Checkbox_0
    #Hyperlink_0
    #IP_0
    #Button_0
    #Button_1
    #Button_2
    #Button_3
  EndEnumeration
  
  
  Procedure OpenWindow_0(x = 0, y = 0, width = 610, height = 400)
    OpenWindow(#Window_0, x, y, width, height, "MouseOver Events", #PB_Window_SystemMenu)
    EditorGadget(#Editor_0, 10, 10, 290, 60)
    CanvasGadget(#Canvas_0, 310, 10, 290, 60)
    ExplorerListGadget(#ExplorerList_0, 310, 80, 290, 100, "")
    ExplorerTreeGadget(#ExplorerTree_0, 10, 80, 290, 100, "")
    ListViewGadget(#ListView_0, 10, 190, 290, 60)
    ListIconGadget(#ListIcon_0, 310, 190, 290, 60, "Column 1", 100)
    ComboBoxGadget(#Combo_0, 10, 260, 290, 30)
    DateGadget(#Date_0, 310, 260, 290, 30, "")
    OptionGadget(#Option_0, 10, 300, 80, 30, "Option 1")
    OptionGadget(#Option_1, 100, 300, 90, 30, "Option 2")
    CheckBoxGadget(#Checkbox_0, 200, 300, 100, 30, "Check")
    HyperLinkGadget(#Hyperlink_0, 310, 300, 140, 30, "www.purebasic.com", 0)
    IPAddressGadget(#IP_0, 460, 300, 140, 30)
    ButtonGadget(#Button_0, 10, 340, 140, 40, "Button 0")
    ButtonGadget(#Button_1, 160, 340, 140, 40, "Button 1")
    ButtonGadget(#Button_2, 310, 340, 140, 40, "Button 2")
    ButtonGadget(#Button_3, 460, 340, 140, 40, "Button 3")
  EndProcedure

  OpenWindow_0()
  
  MouseOver::Init()
  
  Repeat
    Event = WaitWindowEvent(10)
    If Event = #PB_Event_Gadget
      
       Select EventType()
          Case #PB_EventType_MouseEnter
            Debug "MouseEnter Gadget " + EventGadget()
          Case #PB_EventType_MouseLeave
            Debug "MouseLeave Gadget " + EventGadget()
            
        EndSelect
    EndIf
    
  Until Event = #PB_Event_CloseWindow
  
CompilerEndIf

Re: Modul MouseOver

Verfasst: 27.07.2015 23:35
von Shardik
Schönes Modul und sehr nützlich, vielen Dank dafür!

Ich habe es unter MacOS X 10.6.8 (Snow Leopard) getestet:
- Mit PB 5.31 x64 (64 Bit) funktioniert es einwandfrei
- Mit PB 5.31 x86 (32 Bit) läuft es leider nicht und es werden folgende Fehler angezeigt:

Bild

Wenn man allerdings die Modulhülle entfernt, läuft es auch unter PB 5.31 x86 (32 Bit) einwandfrei!

Re: Modul MouseOver

Verfasst: 28.07.2015 02:25
von mestnyi

Code: Alles auswählen

CompilerCase #PB_OS_Linux
          ; Code ?
          Protected desktop_x,desktop_y, *Widget.GtkWidget = gdk_window_at_pointer_(@desktop_x,@desktop_y)
          If (desktop_x <>-1 Or desktop_y <>-1)
            gdk_window_get_origin_(*Widget\object,@desktop_x,@desktop_y)
            
            handle = *Widget
          EndIf
        

Re: Modul MouseOver

Verfasst: 28.07.2015 11:10
von Shardik
Leider ist das Beispiel von mestnyi nicht korrekt. Wenn man es in das Modul einbaut, werden nur MouseEnter und MouseLeave für Gadget 1 angezeigt. Dies liegt daran, dass mestnyi die Rückgabestruktur für gdk_window_at_Pointer_() falsch definiert:

Code: Alles auswählen

*Widget.GtkWidget = gdk_window_at_pointer_(@desktop_x,@desktop_y)
Diese Funktion gibt das GdkWindow des Gadgets zurück, das aktuell unter dem Mauszeiger liegt, sowie die x- und y-Koordinaten für die obere linke Ecke des Gadgets. Korrekt ist also:

Code: Alles auswählen

*GdkWindow.GdkWindowObject = gdk_window_at_pointer_(@desktop_x,@desktop_y)
Außerdem ist seine Funktion

Code: Alles auswählen

gdk_window_get_origin_(*Widget\object,@desktop_x,@desktop_y)
falsch und überflüssig, da sie für ein gegebenes GdkWindow eines Gadgets die x- und y-Werte in Root Window Koordinaten zurückgibt.

Dies ist das korrigierte Beispiel, das in das Modul eingefügt werden kann:

Code: Alles auswählen

        CompilerCase #PB_OS_Linux
          Protected desktop_x,desktop_y,*GdkWindow.GdkWindowObject = gdk_window_at_pointer_(@desktop_x,@desktop_y)
          If *GdkWindow
            handle = *GdkWindow\user_data
          EndIf

Re: Modul MouseOver

Verfasst: 28.07.2015 11:49
von NicTheQuick
Cooles Snippet! :allright:
Ich wollte gestern schon die Linux-Version dazu posten, aber ich hab diese blöde 'gdk_window_at_pointer_'-Funktion nicht gefunden, warum auch immer.

Ich habe aber noch eine Frage. Die ganzen Funktionen wie 'PB_Object_EnumerateStart( PB_Objects )' und globale Werte wie 'PB_Gadget_Objects', sind die irgendwo dokumentiert. Ich kann zwar deren Namen aus allen PB-Libraries extrahieren, aber dann habe ich immer noch nicht die Parameter. ;)

Edit: Wäre übrigens auch hier ganz gut aufgehoben.

Re: Modul MouseOver

Verfasst: 28.07.2015 13:13
von edel
Informationen findest du im SDK Ordner (nur Windows). Erwarte davon aber nicht zuviel ;)
NicTheQuick hat geschrieben:Ich kann zwar deren Namen aus allen PB-Libraries extrahieren, aber dann habe ich immer noch nicht die Parameter. ;)
Wie machst du das unter Linux, mit dumpdings?

Re: Modul MouseOver

Verfasst: 28.07.2015 14:53
von Shardik
Die letzte PureBasic-Version für Linux, die im Order /sdk/c/include die Header-Dateien für alle möglichen PB-Module (u.a. Gadget und Object) enthielt, war 4.20... :roll:

Re: Modul MouseOver

Verfasst: 28.07.2015 19:38
von mk-soft
Danke an allen für die Hilfe,

habe den Code jetzt für alle OS aktualisiert.

Läuft leider unter MacOS (x86) nicht als Modul. Denke aber das es sich um ein Bug in der 32bit Version für Mac liegt.

Alles Gute
Michael :allright:

P.S.
Die letzte PureBasic-Version für Linux, die im Order /sdk/c/include die Header-Dateien für alle möglichen PB-Module (u.a. Gadget und Object) enthielt, war 4.20
Fred hat angekündigt die SDK in der nächsten Release auch for Mac und Linux zu aktualisieren

http://www.purebasic.fr/english/viewtop ... 12&t=55344

Re: Modul MouseOver

Verfasst: 28.07.2015 19:48
von ts-soft
:allright:
Sehr brauchbar!

Re: Modul MouseOver

Verfasst: 28.07.2015 19:53
von Nino
Vielen Dank für das Modul!