community
community copied to clipboard
Horizontal Scroll with Modifier Key for Mouse
Hi
I ran into the issue that I needed to scroll horizontally and I didn't feel like using the multi-touch emulation. Many applications have a modifier key designated to switch from a vertical scrolling direction to horizontal scrolling direction.
I added said capability into kivy. (I've two implementations, one is commented out. One is faster and relies on default behavior, the other is slower but more verbose.) Since this is my first time working with the project I'm not very familiar with both the way you do the docs and how you like to have the config (more verbose vs faster).
I'd appreciate it if a maintainer could glance at the code I wrote and help me figure out how it should be structured to integrate as good as possible with the existing project.
AliSot2000
PS: I've written an issue already concerning this but I've had no response since so I decided to open this pull request.
Maintainer merge checklist
- [ ] Title is descriptive/clear for inclusion in release notes.
- [ ] Applied a
Component: xxxlabel. - [ ] Applied the
api-deprecationorapi-breaklabel. - [ ] Applied the
release-highlightlabel to be highlighted in release notes. - [ ] Added to the milestone version it was merged into.
- [ ] Unittests are included in PR.
- [ ] Properly documented, including
versionadded,versionchangedas needed.
Thanks for opening your first pull request here! ๐ Please check out our contributing guidelines.
FYI https://github.com/Android-for-Python/gestures4kivy#pan
FYI https://github.com/Android-for-Python/gestures4kivy#pan
I tried that first.
I ran into issues with nested boxes which scroll. (I do not remember what they were since itโs been some time that I worked on the project)
@RobertFlatt
Hi, I've gotten around to testing again. I've tried a lot of things but I was unable to use gestures4kivy to implement nested ScrollViews. The outer ScrollView would always capture the event and not propagate it to the nested one, thereby making it useless. From my googling and understanding of events in kivy, this seems to be the default 'way' to handle it.
I don't see me rewriting the gestures4kivy too if I've already implemented a solution with this pull request.
For your convenience, I've an example of nested ScrollViews which you can use to verify the behaviour yourself. Example
From the gestures4kivy docs:
CommonGestures callback methods detect gestures; they do not implement behaviors.
I'm not really the right person to ask, I know only a little about the ScrollView widget, which is enough to know I don't understand. Since I'm not a kv jockey either, your example is a mystery to me. So I tried something more basic.
I tried a simpler Python example, based on https://kivy.org/doc/stable/api-kivy.uix.scrollview.html and a model of a slot machine, imagine each number is a different fruit๐๐๐
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.app import runTouchApp
def buttons():
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
# Make sure the height is such that there is something to scroll.
layout.bind(minimum_height=layout.setter('height'))
for i in range(20):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
return layout
def child_scroll():
child = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
child.add_widget(buttons())
return child
layout2 = GridLayout(cols=3, spacing=10, size_hint_y=None)
layout2.add_widget(child_scroll())
layout2.add_widget(child_scroll())
layout2.add_widget(child_scroll())
root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
root.add_widget(layout2)
runTouchApp(root)
Each of the three columns scrolls independently.
I can see that one might also want to have the three columns move together (though a slot machine presumably does not allow this)
But I don't understand how to disambiguate one control signal (button, gesture, big handle on the side of the slot machine) to do two different functions (independent scroll, and synchronized scroll) in the same screen area.
My lack of understanding is about UI design, not a about code, and unrelated to how the control signal is generated.
I did a little more experimenting. As far as I can tell, and I may be wrong:
- Touch events are not propagated to the parent ScrollView.
- Wheel Touch events are not propagated to the parent or to child ScrollView
Which I assume is what it says here https://kivy.org/doc/stable/api-kivy.uix.scrollview.html#scrolling-behavior
Without an event g4k is not going to respond.
But you can steal the touch events from ScrollView by messing with the method resolution order. But I don't know how portable or reliable this is. If HScrollView is the parent, and ScrollView is the child
class HScrollView(CommonGestures, ScrollView):
def cgb_pan(self, touch, focus_x, focus_y, delta_x, velocity):
print('pan')
# do your thing here
So my application has a ScrollView which scrolls horizontally. This Scroll View contains another GridLayout which has itself multiple children which scroll too.
Using the default ScrollView works. The problem is that I cannot scroll horizontally bc I don't have a horizontal mouse button and I don't like to use the touch emulation.
I want to emulate the behavior you get when you comment all on_scroll_start, on_scroll_stop, on_scroll_move, cgb_scroll, cgb_pan in the example.
Now I tried to implement that with the gestures4kivy like in said example. But you should discover that the scrolling is only sent to the parent and not the child ScrollViews. Compare that to the behavior I got before where on a horizontal scroll first the inner ScrollView scrolled until it reached its limit, then the outer ScrollView scrolls until your cursor is on top of another ScrollView. Then the inner one scrolls again, until the limit is reached...
It is this behavior I'm trying to replicated with gestures4kivy.
g4k gestures have the scope of the widget that inherits CommonGestures.
You can of course use the callbacks to call methods in child widgets if you want to.
There is no additional magic behavior for any co-inherited Widget.
I really don't understand enough about interacting ScrollViews to comprehend the mechanism behind the behavior you describe.
Have fun figuring it out.