Using mousewheel in GUI (listicongadget)

Just starting out? Need help? Post your questions and find answers here.
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Using mousewheel in GUI (listicongadget)

Post by Shardik »

You may try the following cross-platform example which detects the movement of the mouse wheel in a ListIconGadget. In PB's ListIconGadget moving the mouse wheel scrolls the contents automatically on Linux, MacOS and Windows without the need to program any code. But when using a virtual scroll bar you need to be able to detect the mouse wheel movement in order to synchronize the contents of the ListIconGadget with your own custom scroll bar. I hope you are able to adapt the following code for your customized ListIconGadget with virtual scroll bar.

I have successfully tested the example with the following operating systems:
- MacOS X 10.6.8 (Snow Leopard) with PB 5.30 x86 and x64 in ASCII and Unicode mode
- Ubuntu 12.04 x64 with KDE and Unity with PB 5.30 x64 in ASCII and Unicode mode
- Windows 7 SP1 x64 with PB 5.30 x86 and x64 in ASCII and Unicode mode

You should be aware of a shortcoming of the current solution: each up and down doesn't necessarily mean an up or down of a complete row because this may be configurable by the user on some operating systems. These are my current settings of the tested operating systems for one up/down:
- MacOS X 10.6.8 (Snow Leopard): 1/10th of a row
- Ubuntu 12.04 x64 with KDE and Unity: 1 row
- Windows 7: 3 rows

Code: Select all

EnableExplicit

#ListIcon = 0

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux ; --------------------------------------------------
    ProcedureC MouseWheelEventHandler(*Event.GdkEventScroll, *UserData)
      Protected *ListView.GtkWidget = GadgetID(#ListIcon)
      
      If *ListView\window = gdk_window_get_parent_(*Event\window)
        If *Event\type = #GDK_SCROLL
          Select *Event\direction
            Case #GDK_SCROLL_UP
              Debug "Up"
            Case #GDK_SCROLL_DOWN
              Debug "Down"
          EndSelect
        EndIf
      EndIf
      
      gtk_main_do_event_(*Event)
    EndProcedure 
  CompilerCase #PB_OS_MacOS ; --------------------------------------------------
    #NSScrollWheel = 22

    Procedure ScanVerticalMouseWheel()
      Protected CurrentEvent.I
      Protected DeltaY.F
      Protected EventType.I
      Protected SharedApplication.I = CocoaMessage(0, 0,
        "NSApplication sharedApplication")
      
      CurrentEvent = CocoaMessage(0, SharedApplication, "currentEvent")
      
      If CurrentEvent
        EventType = CocoaMessage(0, CurrentEvent, "type")
        
        If EventType = #NSScrollWheel
          If WindowMouseX(0) >= GadgetX(0) And
            WindowMouseX(0) <= GadgetX(0) + GadgetWidth(0)
            If WindowMouseY(0) >= GadgetY(0) And
              WindowMouseY(0) <= GadgetY(0) + GadgetHeight(0)
              CocoaMessage(@DeltaY, currentEvent, "deltaY")

              If DeltaY < 0.0
                Debug "Up"
              Else
                Debug "Down"
              EndIf
            EndIf
          EndIf
        EndIf
      EndIf
    EndProcedure
  CompilerCase #PB_OS_Windows ; ------------------------------------------------
    Define DefaultListIconCallback.I

    Procedure CustomListIconCallback(WindowHandle.I, Msg.I, WParam.I, LParam.I)
      Shared DefaultListIconCallback.I

      If Msg = #WM_MOUSEWHEEL
        If (WParam >> 16) & $8000 
          Debug "Down"
        Else          
          Debug "Up"
        EndIf
      EndIf

      ProcedureReturn CallWindowProc_(DefaultListIconCallback, WindowHandle,
        Msg, WParam, LParam)
   EndProcedure
CompilerEndSelect

Define i.I

OpenWindow(0, 200, 100, 300, 140, "Detect mouse wheel scrolling")
ListIconGadget(#ListIcon, 10, 10, 280, 120, "Column 1", 100)

For i = 1 To 20
  AddGadgetItem(0, -1, "Line " + Str(i))
Next i

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    gdk_event_handler_set_(@MouseWheelEventHandler(), 0, 0)
  CompilerCase #PB_OS_Windows
    DefaultListIconCallback = GetWindowLongPtr_(GadgetID(#ListIcon), #GWL_WNDPROC) 
    SetWindowLongPtr_(GadgetID(0), #GWL_WNDPROC, @CustomListIconCallback()) 
CompilerEndSelect

SetActiveGadget(#ListIcon)

Repeat
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    ScanVerticalMouseWheel()
  CompilerEndIf
Until WaitWindowEvent() = #PB_Event_CloseWindow

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  gdk_event_handler_set_(0, 0, 0)
CompilerEndIf
User avatar
marcoagpinto
Addict
Addict
Posts: 947
Joined: Sun Mar 10, 2013 3:01 pm
Location: Portugal
Contact:

Re: Using mousewheel in GUI (listicongadget)

Post by marcoagpinto »

Thanks!

The code is very complex for me to understand, but I will give a deeper look at it soon.

:D :) :o 8) :lol: :P :evil: :twisted: :wink: :!: :idea: :mrgreen:

Kind regards,
>Marco A.G.Pinto
---------------
User avatar
marcoagpinto
Addict
Addict
Posts: 947
Joined: Sun Mar 10, 2013 3:01 pm
Location: Portugal
Contact:

Re: Using mousewheel in GUI (listicongadget)

Post by marcoagpinto »

@Shardik

Not wanting to sound annoying, but is there a simple way of just detecting the the mouse wheel was scrolled, without binding it to gadgets?

Maybe the cross-platform code would become simpler and then I could associate it to the listicongadget the same way I am doing with other keys (CURS UP/DOWN and PG UP/DOWN).

Thanks, and sorry for bothering you.

Kind regards,
>Marco A.G.Pinto
----------------
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Using mousewheel in GUI (listicongadget)

Post by Shardik »

The simplest possibility already built-in in PureBasic is the EventType #PB_EventType_MouseWheel. But this EventType is only supported by the CanvasGadget and OpenGLGadget. And this EventType only detects that the mouse wheel has been moved but neither whether the wheel moved up or down nor the delta:

Code: Select all

OpenWindow(0, 200, 100, 300, 270, "Detect mouse wheel movement")
CanvasGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, #PB_Canvas_Border)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0
        If EventType() = #PB_EventType_MouseWheel
          Debug "Mouse wheel was moved"
        EndIf
      EndIf
  EndSelect
ForEver
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Using mousewheel in GUI (listicongadget)

Post by Shardik »

marcoagpinto wrote:Not wanting to sound annoying, but is there a simple way of just detecting the the mouse wheel was scrolled, without binding it to gadgets?
I don't think that there is a simpler way. I would strongly advise to bind the mouse wheel event to the ListIconGadget because otherwise you would also react to wheel scrolling when the cursor is outside of your ListIconGadget. But please take a look into the modified example below: it should be at least simpler for you to implement because I have declared the two additional event types

#PB_EventType_MouseWheel_Down
#PB_EventType_MouseWheel_Up

and all 3 callbacks now use PostEvent() to place these new event types in your standard event loop so that you may evaluate the mouse wheel events there:

Code: Select all

    Case #PB_Event_Gadget
      If EventGadget() = #ListIcon
        Select EventType()
          Case #PB_EventType_MouseWheel_Down
            Debug "Mouse wheel moved down"
          Case #PB_EventType_MouseWheel_Up
            Debug "Mouse wheel moved up"
        EndSelect
      EndIf
By the way I also optimized the MacOS part by defining an EventTapCallback (thank you for one of your invaluable examples demonstrating that callback, Wilbert!) instead of calling the procedure ScanVerticalMouseWheel() inside the event loop:

Code: Select all

EnableExplicit

#ListIcon = 0
#Window = 0

Enumeration 
  #PB_EventType_MouseWheel_Down = #PB_EventType_FirstCustomValue
  #PB_EventType_MouseWheel_Up
EndEnumeration

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux ; --------------------------------------------------
    ProcedureC MouseWheelCallback(*Event.GdkEventScroll, *UserData)
      Protected *ListView.GtkWidget = GadgetID(#ListIcon)
     
      If *ListView\window = gdk_window_get_parent_(*Event\window)
        If *Event\type = #GDK_SCROLL
          Select *Event\direction
            Case #GDK_SCROLL_UP
              PostEvent(#PB_Event_Gadget, #Window, #ListIcon,
                #PB_EventType_MouseWheel_Up)
            Case #GDK_SCROLL_DOWN
              PostEvent(#PB_Event_Gadget, #Window, #ListIcon,
                #PB_EventType_MouseWheel_Down)
          EndSelect
        EndIf
      EndIf
     
      gtk_main_do_event_(*Event)
    EndProcedure
  CompilerCase #PB_OS_MacOS ; --------------------------------------------------
    #kCGEventTapOptionListenOnly = 1
    #kCGHeadInsertEventTap = 0
    #NX_SCROLLWHEELMOVED = 22
    #NX_SCROLLWHEELMOVEDMASK = 1 << #NX_SCROLLWHEELMOVED

    ImportC ""
      CGEventTapCreateForPSN(*ProcessSerialNumber, CGEventTapPlacement.I,
        CGEventTapOptions.I, CGEventMask.Q, CGEventTapCallback.I, *UserData)
      GetCurrentProcess(*ProcessSerialNumber)
    EndImport

    ProcedureC MouseWheelCallback(CGEventTapProxy.I, CGEventType.I, CGEvent.I,
      *UserData)
      Protected DeltaY.CGFloat
      Protected NSEvent.I
      Protected Point.NSPoint
      
      NSEvent = CocoaMessage(0, 0, "NSEvent eventWithCGEvent:", CGEvent)
      CocoaMessage(@Point, NSEvent, "locationInWindow")
      
      If CocoaMessage(0, CocoaMessage(0, WindowID(#Window), "contentView"),
        "hitTest:@", @Point) = GadgetID(#ListIcon)
        CocoaMessage(@DeltaY, NSEvent, "deltaY")
        
        If DeltaY < 0.0
          PostEvent(#PB_Event_Gadget, #Window, #ListIcon,
            #PB_EventType_MouseWheel_Down)
        Else
          PostEvent(#PB_Event_Gadget, #Window, #ListIcon,
            #PB_EventType_MouseWheel_Up)
        EndIf
      EndIf
    EndProcedure
  CompilerCase #PB_OS_Windows ; ------------------------------------------------
    Define DefaultListIconCallback.I

    Procedure CustomListIconCallback(WindowHandle.I, Msg.I, WParam.I, LParam.I)
      Shared DefaultListIconCallback.I

      If Msg = #WM_MOUSEWHEEL
        If (WParam >> 16) & $8000
          PostEvent(#PB_Event_Gadget, #Window, #ListIcon,
            #PB_EventType_MouseWheel_Down)
        Else         
          PostEvent(#PB_Event_Gadget, #Window, #ListIcon,
            #PB_EventType_MouseWheel_Up)
        EndIf
      EndIf

      ProcedureReturn CallWindowProc_(DefaultListIconCallback, WindowHandle,
        Msg, WParam, LParam)
   EndProcedure
CompilerEndSelect

Define i.I

OpenWindow(0, 200, 100, 300, 140, "Detect mouse wheel scrolling")
ListIconGadget(#ListIcon, 10, 10, 280, 120, "Column 1", 100)

For i = 1 To 20
  AddGadgetItem(0, -1, "Line " + Str(i))
Next i

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    gdk_event_handler_set_(@MouseWheelCallback(), 0, 0)
  CompilerCase #PB_OS_MacOS
    Define MachPort.I
    Define ProcessSerialNumber.Q

    GetCurrentProcess(@ProcessSerialNumber)
    MachPort = CGEventTapCreateForPSN(@ProcessSerialNumber,
      #kCGHeadInsertEventTap, #kCGEventTapOptionListenOnly,
      #NX_SCROLLWHEELMOVEDMASK, @MouseWheelCallback(), 0)

    If MachPort
      CocoaMessage(0, CocoaMessage(0, 0, "NSRunLoop currentRunLoop"),
      "addPort:", MachPort,
      "forMode:$", @"kCFRunLoopCommonModes")
    EndIf
  CompilerCase #PB_OS_Windows
    DefaultListIconCallback = GetWindowLongPtr_(GadgetID(#ListIcon),
      #GWL_WNDPROC)
    SetWindowLongPtr_(GadgetID(#ListIcon), #GWL_WNDPROC,
      @CustomListIconCallback())
CompilerEndSelect

SetActiveGadget(#ListIcon)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      CompilerSelect #PB_Compiler_OS
        CompilerCase #PB_OS_Linux
          gdk_event_handler_set_(0, 0, 0)
        CompilerCase #PB_OS_MacOS
          CFRelease_(MachPort)
      CompilerEndSelect
      Break
    Case #PB_Event_Gadget
      If EventGadget() = #ListIcon
        Select EventType()
          Case #PB_EventType_MouseWheel_Down
            Debug "Mouse wheel moved down"
          Case #PB_EventType_MouseWheel_Up
            Debug "Mouse wheel moved up"
        EndSelect
      EndIf
  EndSelect
ForEver
User avatar
marcoagpinto
Addict
Addict
Posts: 947
Joined: Sun Mar 10, 2013 3:01 pm
Location: Portugal
Contact:

Re: Using mousewheel in GUI (listicongadget)

Post by marcoagpinto »

Thanks for all the help!!!!!

:twisted:
Post Reply