PureBasic Forum
http://forums.purebasic.com/english/

CanvasGadget/OpenGLGadget - Mouse events
http://forums.purebasic.com/english/viewtopic.php?f=13&t=73102
Page 1 of 1

Author:  wombats [ Fri Jun 28, 2019 8:32 am ]
Post subject:  CanvasGadget/OpenGLGadget - Mouse events

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:
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:
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.

Author:  #NULL [ Fri Jun 28, 2019 9:24 am ]
Post subject:  Re: CanvasGadget/OpenGLGadget - Mouse events

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.

Author:  srod [ Fri Jun 28, 2019 11:32 am ]
Post subject:  Re: CanvasGadget/OpenGLGadget - Mouse events

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.

Author:  RASHAD [ Fri Jun 28, 2019 2:17 pm ]
Post subject:  Re: CanvasGadget/OpenGLGadget - Mouse events

For Windows the rest for Shardik

Code:
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:
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

Author:  srod [ Fri Jun 28, 2019 4:07 pm ]
Post subject:  Re: CanvasGadget/OpenGLGadget - Mouse events

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:
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

Author:  wombats [ Sun Jun 30, 2019 2:48 pm ]
Post subject:  Re: CanvasGadget/OpenGLGadget - Mouse events

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

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/