A little MouseHover Library (last update: August 10, 2016)

Developed or developing a new product in PureBasic? Tell the world about it.
mestnyi
Addict
Addict
Posts: 995
Joined: Mon Nov 25, 2013 6:41 am

Re: A little MouseHover Library (last update: August 10, 201

Post by mestnyi »

If you do not mind I would do so :)

Code: Select all

;===================================================== 

;EnableExplicit

Import ""
  PB_Gadget_SendGadgetCommand(hwnd, EventType)
EndImport

#HoverEvent_EnterGadget = #WM_USER + 100 
#HoverEvent_LeaveGadget = #WM_USER + 101

Global hook

Procedure EnterGadgetID( ) 
  Protected EnterGadgetID, GadgetID
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      
      Protected WindowID
      Protected Cursorpos.q
      
      GetCursorPos_( @Cursorpos )
      WindowID = WindowFromPoint_( Cursorpos )
      ScreenToClient_(WindowID, @Cursorpos) 
      GadgetID = ChildWindowFromPoint_( WindowID, Cursorpos )
      
      GetCursorPos_( @Cursorpos )
      WindowID = GetAncestor_( WindowID, #GA_ROOT )
      ScreenToClient_(WindowID, @Cursorpos) 
      WindowID = ChildWindowFromPoint_( WindowID, Cursorpos )
      
      If IsGadget( GetDlgCtrlID_( GadgetID )) 
        If GadgetID = GadgetID( GetDlgCtrlID_( GadgetID ))
          WindowID = GadgetID
        Else
          ; SpinGadget
          If GetWindow_( GadgetID, #GW_HWNDPREV ) = GadgetID( GetDlgCtrlID_( GadgetID ))
            If GetWindowLongPtr_( GadgetID, #GWL_STYLE ) & #WS_CLIPSIBLINGS = #False 
              SetWindowLongPtr_( GadgetID, #GWL_STYLE, GetWindowLongPtr_( GadgetID, #GWL_STYLE ) | #WS_CLIPSIBLINGS )
            EndIf
            WindowID = GetWindow_( GadgetID, #GW_HWNDPREV)
            
          ElseIf GetWindow_( GadgetID, #GW_HWNDNEXT ) = GadgetID( GetDlgCtrlID_( GadgetID ))
            If GetWindowLongPtr_( GadgetID, #GWL_STYLE ) & #WS_CLIPSIBLINGS = #False 
              SetWindowLongPtr_( GadgetID, #GWL_STYLE, GetWindowLongPtr_( GadgetID, #GWL_STYLE ) | #WS_CLIPSIBLINGS )
            EndIf
            WindowID = GetWindow_( GadgetID, #GW_HWNDNEXT)
          EndIf
        EndIf
      Else
        If GetParent_( GadgetID )
          WindowID = GetParent_( GadgetID ) ; С веб гаджетом проблемы
                                            ;Debug WindowID ; 
        EndIf
      EndIf
      
      ; SplitterGadget() 
      Protected RealClass.S = Space(13) 
      GetClassName_( GetParent_( WindowID ), @RealClass, Len( RealClass ))
      If RealClass.S = "PureSplitter" : WindowID = GetParent_( WindowID ) : EndIf
      
      ;Debug WindowID
      ProcedureReturn WindowID
      
 CompilerEndSelect
EndProcedure    

Procedure CallWndProc(nCode, wParam, lParam)
  Static LeaveID 
  Protected EnterID = EnterGadgetID( )
  
  
  If LeaveID <> EnterID 
    If LeaveID > 0 And LeaveID <> GetAncestor_( LeaveID, #GA_ROOT )
      PB_Gadget_SendGadgetCommand(LeaveID, #HoverEvent_LeaveGadget)
    EndIf
    If EnterID > 0 And EnterID <> GetAncestor_( EnterID, #GA_ROOT )
      PB_Gadget_SendGadgetCommand( EnterID, #HoverEvent_EnterGadget)
    EndIf
    LeaveID = EnterID 
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
EndProcedure

ProcedureDLL InitHoverEvents(hwnd)
  Shared hook
  hook = SetWindowsHookEx_(#WH_MOUSE, @CallWndProc(), #Null, GetCurrentThreadId_())
  If hook
    ProcedureReturn 1
  EndIf
EndProcedure

ProcedureDLL EndHoverEvents(hwnd)
  Shared hook
  If UnhookWindowsHookEx_(hook)
    ProcedureReturn 1
  EndIf
EndProcedure

;========================================================
;                  End of Library Code
;========================================================

CompilerIf #PB_Compiler_IsMainFile
  OpenWindow(10, 0, 0, 640, 480, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  
  PanelGadget(0, 8, 8, 300, 300)
  AddGadgetItem(0,0,"Tab 1")
  ContainerGadget(30, 5,5,260,220,#PB_Container_Flat)
  ContainerGadget(20, 15,15,220,180,#PB_Container_Flat)
  ButtonGadget(10, 25, 25, 100, 30, "")
  CloseGadgetList()
  CloseGadgetList()
  AddGadgetItem(0,1,"Tab 2")
  ButtonGadget(11, 10, 40, 200, 30, "")
  
  CloseGadgetList()
  
  InitHoverEvents(WindowID(10))
  
  Repeat 
    EventID = WaitWindowEvent()
    Select EventID
        
      Case #PB_Event_Gadget
        If EventType() = #HoverEvent_EnterGadget
          Debug "Entered Gadget " + EventGadget()
          
        ElseIf EventType() = #HoverEvent_LeaveGadget
          Debug "Left Gadget " + EventGadget()
        EndIf
    EndSelect
  Until EventID = #PB_Event_CloseWindow
  
  EndHoverEvents(WindowID(0))
CompilerEndIf
Last edited by mestnyi on Thu Aug 11, 2016 7:19 pm, edited 1 time in total.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: A little MouseHover Library (last update: August 10, 201

Post by netmaestro »

It doesn't work correctly - it shows leave events when surfing deeper into the stacked gadgets

If you're going to post alternative code that you wrote, could you please remove the header with my name on it first? Thanks.
BERESHEIT
mestnyi
Addict
Addict
Posts: 995
Joined: Mon Nov 25, 2013 6:41 am

Re: A little MouseHover Library (last update: August 10, 201

Post by mestnyi »

It doesn't work correctly - it shows leave events when surfing deeper into the stacked gadgets
It's just right.
Or do you mean it does not have to work inside the container?
For example, the canvas was observed in a similar way.
please remove the header with my name
If you want to let it be. :)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: A little MouseHover Library (last update: August 10, 201

Post by netmaestro »

The desired behavior is:

If a larger gadget contains a smaller gadget, such as say, a button inside a larger container, and both gadgets are initialized to receive hover events, then:

- When the cursor passes over the larger container, it should fire an entry event and be considered "hot"
- When the cursor keeps going and passes over the button, it should fire an entry event and be considered "hot" - But the container should still be considered hot too (because the button is inside it)
- If, when the cursor enters the button, the container fires an exit and becomes cold, that's not the desired behavior.

I know, it's not that easy to put into words, especially if your first language isn't the same as mine. But hats off to you for communicating in English, I couldn't do the same in Russian!
BERESHEIT
mestnyi
Addict
Addict
Posts: 995
Joined: Mon Nov 25, 2013 6:41 am

Re: A little MouseHover Library (last update: August 10, 201

Post by mestnyi »

The desired behavior is:
And why is the desired behavior? I mean where it may need? I just came out of it.

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Procedure GadgetsClipCallBack( GadgetID, lParam )
      If GadgetID
        Protected Gadget = GetProp_( GadgetID, "PB_ID" )
        
        If GetWindowLongPtr_( GadgetID, #GWL_STYLE ) & #WS_CLIPSIBLINGS = #False 
          If IsGadget( Gadget ) 
            Select GadgetType( Gadget )
              Case #PB_GadgetType_ComboBox
                Protected Height = GadgetHeight( Gadget )
                
            EndSelect
          EndIf
          
          SetWindowLongPtr_( GadgetID, #GWL_STYLE, GetWindowLongPtr_( GadgetID, #GWL_STYLE ) | #WS_CLIPSIBLINGS | #WS_CLIPCHILDREN )
          
          If Height
            ResizeGadget( Gadget, #PB_Ignore, #PB_Ignore, #PB_Ignore, Height )
          EndIf
          
          SetWindowPos_( GadgetID, #GW_HWNDFIRST, 0,0,0,0, #SWP_NOMOVE|#SWP_NOSIZE )
        EndIf
        
      EndIf
      
      ProcedureReturn GadgetID
    EndProcedure
  CompilerEndIf
  Procedure ClipGadgets( WindowID )
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      EnumChildWindows_( WindowID, @GadgetsClipCallBack(), 0 )
    CompilerEndIf
  EndProcedure
  
  
CompilerIf #PB_Compiler_IsMainFile
  OpenWindow(10, 0, 0, 640, 480, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  
  CanvasGadget(0, 8, 8, 300, 300,#PB_Canvas_Border)
  ;AddGadgetItem(0,0,"Tab 1")
  CanvasGadget(30, 5,5,260,220,#PB_Canvas_Border)
  CanvasGadget(20, 15,15,220,180,#PB_Canvas_Border)
  ButtonGadget(10, 25, 25, 100, 30, "")
;   CloseGadgetList()
;   CloseGadgetList()
;   AddGadgetItem(0,1,"Tab 2")
;   ButtonGadget(11, 10, 40, 200, 30, "")
;   
;   CloseGadgetList()
;   
  
  
   ClipGadgets( UseGadgetList(0) )
  Repeat 
    EventID = WaitWindowEvent()
    Select EventID
        
      Case #PB_Event_Gadget
        If EventType() = #PB_EventType_MouseEnter
          Debug "Entered Gadget " + EventGadget()
          
        ElseIf EventType() = #PB_EventType_MouseLeave
          Debug "Left Gadget " + EventGadget()
        EndIf
    EndSelect
  Until EventID = #PB_Event_CloseWindow
  
  
CompilerEndIf
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: A little MouseHover Library (last update: August 10, 201

Post by Joris »

Thanks Netmaestro.

Related to MouseHover would be this request too :
http://www.purebasic.fr/english/viewtop ... =3&t=65271
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
tj1010
Enthusiast
Enthusiast
Posts: 621
Joined: Mon Feb 25, 2013 5:51 pm
Location: US or Estonia
Contact:

Re: A little MouseHover Library (last update: August 10, 201

Post by tj1010 »

You can also just store callback function pointers and x-y-w-h in something global with a delayed thread and maybe some queue. All platforms no API. I did this with a canvas based game once and it saved massive amounts of code and time.
The truth hurts.
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: A little MouseHover Library (last update: August 10, 201

Post by Michael Vogel »

How to handle editable combobox gadgets?

You may see the problem when adding ComboBoxGadget(666, 25, 66, 100, 30,#PB_ComboBox_Editable) to the source in the first posting.

Here's a soultion to handle these gadgets, but who knows what the value 1001 stays for?

Code: Select all


; Define

	#Undefined=-#True

	#GridX=40
	#GridY=40

	#SizeX1=75
	#SizeX2=200
	#SizeY0=30

	#TabX1=10
	#TabX2=#TabX1+#SizeX1
	#TabY1=10
	#TabY2=#TabY1+#GridY
	#TabY3=#TabY2+#GridY
	#TabY4=#TabY3+#GridY
	#TabY5=#TabY4+#GridY


	Enumeration
		; Windows
		#WinMain
	EndEnumeration

	Enumeration
		; Gadgets in Main
		#MainTitle
		#MainIdX
		#MainId
		#MainInformationX
		#MainInformation
		#MainUsernameX
		#MainUsername
		#MainPasswordX
		#MainPassword
		#MainInfo
		#MainStatus

	EndEnumeration


; EndDefine
Procedure GetHoverGadget()

	Protected cursor.POINT
	Protected handle,id

	If GetCursorPos_(cursor.POINT)
		handle=WindowFromPoint_(PeekQ(@cursor))
		SetGadgetText(#MainInfo,Str(GetParent_(handle)))
		If handle
			id=GetDlgCtrlID_(handle)
			If id=1001
				id=GetDlgCtrlID_(GetParent_(handle))
			EndIf
		EndIf
	EndIf

	ProcedureReturn id

EndProcedure
Procedure Init()

	OpenWindow(#WinMain,0,0,#GridX*10,#GridY*5,"",#PB_Window_BorderLess|#PB_Window_ScreenCentered)

	a=ComboBoxGadget(#MainId,#TabX2,#TabY1,#SizeX2,#SizeY0)
	TextGadget(#MainIdX,#TabX1,#TabY1,#SizeX1,#SizeY0,"ID: "+Str(a),#SS_CENTERIMAGE)
	a=ComboBoxGadget(#MainInformation,#TabX2,#TabY2,#SizeX2,#SizeY0,#PB_ComboBox_Editable)
	TextGadget(#MainInformationX,#TabX1,#TabY2,#SizeX1,#SizeY0,"ID: "+Str(a),#SS_CENTERIMAGE)
	a=StringGadget(#MainUsername,#TabX2,#TabY3,#SizeX2,#SizeY0,"String",#ES_MULTILINE)
	TextGadget(#MainUsernameX,#TabX1,#TabY3,#SizeX1,#SizeY0,"ID: "+Str(a),#SS_CENTERIMAGE)
	a=ButtonGadget(#MainPassword,#TabX2,#TabY4,#SizeX2,#SizeY0,"Button")
	TextGadget(#MainPasswordX,#TabX1,#TabY4,#SizeX1,#SizeY0,"ID: "+Str(a),#SS_CENTERIMAGE)

	TextGadget(#MainInfo,#TabX1,#TabY5,300,20,"!")
	TextGadget(#MainStatus,#TabX2,#TabY5,300,20,"!")
	SetGadgetColor(#MainStatus,#PB_Gadget_BackColor,#Yellow)

EndProcedure

Init()

Repeat

	Select WaitWindowEvent()
	Case #PB_Event_Gadget
		Select EventGadget()
		Case #MainTitle
			SendMessage_(WindowID(#WinMain),#WM_NCLBUTTONDOWN,#HTCAPTION,0)
		Default
			Debug "G: "+Str(EventGadget())+" ("+EventType()+")"
		EndSelect

	Case #PB_Event_Menu
		Debug "M: "+Str(EventMenu())+" ("+EventType()+")"

	Case #PB_Event_CloseWindow
		DestroyCursor_(DragCursor)

		End

	EndSelect

	SetGadgetText(#MainStatus,Str(GetHoverGadget()))

ForEver
Post Reply