Modul MouseOver

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Modul MouseOver

Beitrag 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
Zuletzt geändert von mk-soft am 03.02.2016 21:48, insgesamt 4-mal geändert.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: Modul MouseOver

Beitrag 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!
mestnyi
Beiträge: 15
Registriert: 25.02.2014 22:00

Re: Modul MouseOver

Beitrag 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
        
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: Modul MouseOver

Beitrag 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
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Modul MouseOver

Beitrag 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.
Bild
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Re: Modul MouseOver

Beitrag 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?
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: Modul MouseOver

Beitrag 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:
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Modul MouseOver

Beitrag 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
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Modul MouseOver

Beitrag von ts-soft »

:allright:
Sehr brauchbar!
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Modul MouseOver

Beitrag von Nino »

Vielen Dank für das Modul!
Antworten