CanvasGadget/OpenGLGadget - Mouse events

Just starting out? Need help? Post your questions and find answers here.
wombats
Enthusiast
Enthusiast
Posts: 663
Joined: Thu Dec 29, 2011 5:03 pm

CanvasGadget/OpenGLGadget - Mouse events

Post by wombats »

Hi,

The CanvasGadget and OpenGLGadget don't fire the #PB_EventType_MouseEnter and #PB_EventType_MouseLeave events while a mouse button is pressed. Is this a bug? If not, is there a way to do this across all three platforms (Windows, macOS and Linux/Qt)?

I need this because I am changing the cursor depending on the user's action in the gadget. However, if they move the cursor outside of the gadget while holding down a mouse button, the cursor changes to the default (as expected), but my code doesn't have the opportunity to change it back when they reenter the gadget because #PB_EventType_MouseEnter isn't fired.

Code: Select all

Procedure CanvasEvents()
  Select EventType()
    Case #PB_EventType_MouseEnter : Debug "Mouse enter"
    Case #PB_EventType_MouseLeave : Debug "Mouse leave"
  EndSelect
EndProcedure

OpenWindow(0, 0, 0, 320, 240, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 320, 240)
BindGadgetEvent(0, @CanvasEvents())

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow

Code: Select all

Procedure CanvasEvents()
  Select EventType()
    Case #PB_EventType_MouseEnter : Debug "Mouse enter"
    Case #PB_EventType_MouseLeave : Debug "Mouse leave"
  EndSelect
EndProcedure

OpenWindow(0, 0, 0, 320, 240, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenGLGadget(0, 0, 0, 320, 240)
BindGadgetEvent(0, @CanvasEvents())

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
I know that I can clip the cursor to the gadget on Windows with #PB_Canvas_ClipMouse, but I don't like that behaviour.
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: CanvasGadget/OpenGLGadget - Mouse events

Post by #NULL »

On linux with gtk2 and gtk3 I get the enter and leave events while the button is pressed. The leave event is triggered twice, once when the mouse leaves and once when I release the button. With qt I don't get the events while the button is pressed, and I get the leave event only if I release the button.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: CanvasGadget/OpenGLGadget - Mouse events

Post by srod »

On Windows the canvas gadget is automatically capturing the mouse input after a left mouse button down event which is why you are not seeing the mouse-leave event until you release the mouse. This makes the canvas gadget easier to work with in many regards, but at the cost of a little flexibility since we may not always want to capture the mouse input after a left click etc.

While this is not a bug (as it is intentional) I would personally prefer for the canvas gadget not to automatically capture the mouse input and instead have the option to do it with a simple function call etc.

Your best option is to monitor the mouse move events and examine the mouse coordinates etc. Have to be careful with any embedded child gadgets mind and any overlapping windows could be problematic. On windows you also have the option of TrackMouseEvent_() which will send #WM_MOUSELEAVE messages if requested, though I am unsure how this rolls when the mouse has been captured - never tested that.
I may look like a mule, but I'm not a complete ass.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: CanvasGadget/OpenGLGadget - Mouse events

Post by RASHAD »

For Windows the rest for Shardik

Code: Select all

Procedure IsMouseOver(hWnd) 
    GetCursorPos_(p.POINT) 
    GetWindowRect_(hWnd,r.RECT) 
    If p\x >= r\left+4 And p\x < r\right-4 And p\y >= r\top+4 And p\y < r\bottom - 4
      ProcedureReturn 1 
    Else 
      ProcedureReturn 0
    EndIf 
EndProcedure

Procedure CanvasEvents()
 If IsMouseOver(GadgetID(0)) <> 1
    ReleaseCapture_()
 EndIf
  Select EventType()
    Case #PB_EventType_MouseEnter : Debug "Mouse enter"
    Case #PB_EventType_MouseLeave : Debug "Mouse leave"
  EndSelect
EndProcedure

OpenWindow(0, 0, 0, 320, 240, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 320, 240)
BindGadgetEvent(0, @CanvasEvents())

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Should be cross platform

Code: Select all

Procedure CanvasEvents()
  x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
  y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
  If x <= 0 Or x >= 320 Or y <= 0 Or y >= 240
    Debug "Mouse leave 2"
  Else
    Debug "Mouse enter 2"
  EndIf
  Select EventType()
    Case #PB_EventType_MouseEnter : Debug "Mouse enter"
    Case #PB_EventType_MouseLeave : Debug "Mouse leave"
  EndSelect
EndProcedure

OpenWindow(0, 0, 0, 320, 240, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 320, 240)
BindGadgetEvent(0, @CanvasEvents())
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Quit = 1     
    
  EndSelect
Until Quit = 1
Egypt my love
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: CanvasGadget/OpenGLGadget - Mouse events

Post by srod »

Windows only and without messing around with the mouse-capture. Move in and out of the canvas with the button down as many times as you see fit.

Code: Select all

Procedure IsMouseOver(hWnd) 
  GetCursorPos_(p.POINT) 
  If WindowFromPoint_(p\y<<32+p\x) = hWnd
    ProcedureReturn 1 
  Else 
    ProcedureReturn 0
  EndIf 
EndProcedure

Procedure ReportMouseEnter()
  Debug "Mouse enter"
EndProcedure

Procedure ReportMouseLeave()
  Debug "Mouse leave"
EndProcedure

Procedure CanvasEvents()
  Static st_MouseCaptured, st_blnCursorOverCanvas
  Protected blnCursorOverCanvas
  Select EventType()
    Case #PB_EventType_LeftButtonDown
      st_MouseCaptured = #True
      st_blnCursorOverCanvas = #True
    Case #PB_EventType_LeftButtonUp
      If st_blnCursorOverCanvas
        st_MouseCaptured = #False
      EndIf
    Case #PB_EventType_MouseMove 
      If st_MouseCaptured
        blnCursorOverCanvas = IsMouseOver(GadgetID(0))
        If st_blnCursorOverCanvas <> blnCursorOverCanvas
          Select blnCursorOverCanvas
            Case 0
              ReportMouseLeave()
            Case 1
              ReportMouseEnter()
          EndSelect
        EndIf
        st_blnCursorOverCanvas = blnCursorOverCanvas
      EndIf
    Case #PB_EventType_MouseLeave
      If st_MouseCaptured = #False
        ReportMouseLeave()
      EndIf
      st_MouseCaptured = #False
   Case #PB_EventType_MouseEnter
      If st_MouseCaptured = #False
        ReportMouseEnter()
      EndIf
      st_MouseCaptured = #False
  EndSelect

EndProcedure

OpenWindow(0, 0, 0, 320, 240, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 320, 240)
BindGadgetEvent(0, @CanvasEvents())

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
I may look like a mule, but I'm not a complete ass.
wombats
Enthusiast
Enthusiast
Posts: 663
Joined: Thu Dec 29, 2011 5:03 pm

Re: CanvasGadget/OpenGLGadget - Mouse events

Post by wombats »

Thank you all. I mainly use macOS, but I will try your code when I am on Windows.
Post Reply