DirectGUI: Mouse-wheel scrolling

Has anyone here ever gotten mouse-wheel control of either a DirectSlider or a DirectScrolledFrame to work?

I’ve had some suggestions that wheel-scrolling move various UI elements in A Door to the Mists, and I agree that it would be a convenient feature to have. However, DirectGUI seems to be fighting me in my attempts to actually implement such a thing: there is no DGG-value to bind wheel-events; UI elements block wheel events set on a DirectObject; and my attempts to get a DirectSlider to “accept” a wheel-event have thus far been unsuccessful.

Does anyone have any thoughts regarding this?

I’m also keen to have the wheel working seamlessly for DirectGUI.

I had not much time to look at it, though I was able to bind the wheel button on a directframe and get notified in order to implement basic scrolling in CEFPanda :

WHEELUP = p3d.PGButton.getReleasePrefix() + p3d.MouseButton.wheelUp().getName() + '-'
WHEELDOWN = p3d.PGButton.getReleasePrefix() + p3d.MouseButton.wheelDown().getName() + '-'

self.frame.bind(WHEELDOWN, self._handle_mouse_wheel, [False])
self.frame.bind(WHEELUP, self._handle_mouse_wheel, [True])

It works, but you receive events related to the step of the wheel, but not the actual rotation of the wheel, meaning you have to apply your own “rotation speed”, i.e. one event mean, for example, 50 pixels up or down.

1 Like

Interesting, thank you! I’ll likely experiment with that, and see how things go! :slight_smile:

[edit] Update!

Okay, the above seems to work rather well for DirectSliders and DirectScrollBars, at the least! The only caveat is that it calls for binding both the slider-object and the “thumb”-object–if you don’t, the thumb seems to prevent the “wheel”-event from passing through to the slider.

This is more or less what I would expect, I think. In the case of a DirectSlider or DirectScrollBar, at least, I think that the “pageSize” value seems appropriate to apply for this purpose.

However, DirectScrolledFrames are proving trickier: While I have their scrollbars working, thus far I haven’t managed to get a wheel-event out of the scrolled-frame objects themselves. Thus one can at the least scroll such objects via their bars, but alas one can’t scroll them with the mouse simply hovering over the frame itself…

In case it helps anyone, and for any who might be interested, the following is my current approach. It’s pretty much what @eldee shows above, but with a few tweaks and a bit more detail:

In my “common-values” file:
(This is just as eldee gives, above.)

WHEEL_UP = PGButton.getReleasePrefix() + MouseButton.wheelUp().getName() + "-"
WHEEL_DOWN = PGButton.getReleasePrefix() + MouseButton.wheelDown().getName() + "-"

In the convenience function that I use to build DirectSliders:
(The code used for DirectScrolledFrame scroll-bars is pretty much the same.)

        # Setting-up of slider-options precedes here...

        result = DirectSlider(**kwargs)

        result.bind(WHEEL_UP, Common.handleMouseScroll, [result, 1])
        result.thumb.bind(WHEEL_UP, Common.handleMouseScroll, [result, 1])
        result.bind(WHEEL_DOWN, Common.handleMouseScroll, [result, -1])
        result.thumb.bind(WHEEL_DOWN, Common.handleMouseScroll, [result, -1])

        # A bit more logic unrelated to scrolling follows here...

And finally, the “handleMouseScroll” function, which is part of my “Common”-class:

@staticmethod
    def handleMouseScroll(obj, dir, data):
        if isinstance(obj, DirectSlider) or isinstance(obj, DirectScrollBar):
            obj.setValue(obj.getValue() + dir*obj["pageSize"])

(The “if”-statement is intended should I manage to get wheel-events from DirectScrolledFrames; in that case I would likely want slightly different logic, perhaps accessing the scroll-bars based on which of them, if either, is showing.)

If you bind the wheel up and down events to the DirectScrolledFrames directly, it should work. At least it did for my Designer app. The trickier part is that, if you put stuff into the frame, the wheel event may be caught by those other elements and may not be propagated down to the scrolled frame as desired. I’ve surpassed this a little hacky by simply binding the wheel events to all elements within the frame.
You can see in this file for example how I’ve done it:

The interesting lines are 59,59 (binding) and 91,92 (scroll function), 106, 107 (bind for inner elements) and finally line 154 which is necessary to catch and propagate down the event from some elements like DirectFrames.

Ah, you’re quite right–I wasn’t setting the state of my DirectScrolledFrames to be “normal”. Thank you for prompting me to look again! ^^;

As to propagating the wheel-events, indeed, what you describe should work. I’m loath to do that, however, especially as it could become fairly complicated and fairly messy fairly quickly, with nested objects and various menus (including some gameplay-mechanic “menus”) to deal with, I fear… :/

[edit]
(Hmm… I wonder whether it’s worth suggesting a change to how DirectGUI handles events: instead of simply blocking events from passing through, DirectGUI items might indicate whether they’ve handled an event, and if not, pass it on to their parent-object. I think that I recall hearing of at least one other GUI-framework doing something like this, and it seems like it should work. It would be easy enough to have a default setting that preserves the current behaviour by just always reporting events as having been handled.)

Sorry for the late reply. As for the propagating of wheel events, well, yes, it’s probably not the best to bind the event to all elements if you have a complex setup but it was the simplest for me at that time and did work.
Your change proposal for event handling in DirectGUI does sound rather good and yeah, it’s something I know from other GUI toolkits too. Though if you set it to default to the old behavior you’d still need to enable it for every element and I’m currently not even sure if there wasn’t already a feature similar to that implemented for DirectGUI. If not, then I’d like to see something like that implemented too.

Don’t worry about the late reply! :slight_smile:

For my next demo-release I think that I’m going to stick with scrolling being available only when the mouse is hovering over a scroll-bar; it may not be perfect, but it’s better than nothing at all.

I might give further thought to full-DirectScrolledFrame scrolling at a later stage…

As to the change proposal, I may post it to GitHub, then–it does seem like something that might be useful!

(With one potential change: I wonder whether it might not be preferable to have events pass on to widgets beneath the current one, rather than to parent-widgets. If I do post this suggestion to GitHub, I’ll likely mention both options for discussion.)

A minor update: I’ve posted the above-mentioned suggestion on GitHub: