Page 1 of 1

CanvasGadget/OpenGLGadget - Mouse events

Posted: Fri Jun 28, 2019 8:32 am
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.

Re: CanvasGadget/OpenGLGadget - Mouse events

Posted: Fri Jun 28, 2019 9:24 am
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.

Re: CanvasGadget/OpenGLGadget - Mouse events

Posted: Fri Jun 28, 2019 11:32 am
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.

Re: CanvasGadget/OpenGLGadget - Mouse events

Posted: Fri Jun 28, 2019 2:17 pm
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

Re: CanvasGadget/OpenGLGadget - Mouse events

Posted: Fri Jun 28, 2019 4:07 pm
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

Re: CanvasGadget/OpenGLGadget - Mouse events

Posted: Sun Jun 30, 2019 2:48 pm
by wombats
Thank you all. I mainly use macOS, but I will try your code when I am on Windows.