Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-touch support for zoom and scroll #427

Open
nonameentername opened this issue Sep 15, 2015 · 13 comments · May be fixed by #1178
Open

Add multi-touch support for zoom and scroll #427

nonameentername opened this issue Sep 15, 2015 · 13 comments · May be fixed by #1178
Labels
cat.Canvas Issue relates to the canvas info.HasInfo Potentially a key to a puzzle type.Enhancement Issue requests feature.

Comments

@nonameentername
Copy link

I'm looking at adding multi-touch zoom and scroll to mypaint similar to the design seen here: https://www.youtube.com/watch?v=iicnVez5U7M

I was looking at the mypaint code and could not find the location of pen input and zoom. Could someone point out the classes that should be modified to add this functionality?

@achadwick
Copy link
Member

Hi werner - thanks for the interest!

Sure, multi-touch gesture support is something that I'd really like (and can test!) MyPaint is in a beta development stage right now, with strings frozen for translation, but a simple implementation of this would be brilliant. Now follows the headdump!

GTK itself is evolving support for gesture events, new since GTK 3.14 (GtkGesture and its friends). Our upcoming release is slated to support GTK 3.10 or later, but I am perfectly happy to accept tested, bug-free, and ultra-simple code that carefully supports both versions and which doesn't introduce new UI strings. Multi-version support is something that's easy with Python! (And to be honest, 3.12+ is just better for paint programs - so the requirement's semi-fluid already to my mind.)

Input events from tablets are captured in gui/document.py and delegated to the top mode on the mode stack. Modes correspond to toolbar tools, mostly, although an individual tool's main mode could in theory push another mode onto the stack while the user does something fiddly. In practice, even the inking and frame tools just have stateful main modes.

The base classes for a lot of modes can be found in gui/mode.py. I will admit that the class hierarchy is a bit horrible and convoluted in there: it's my doing, and I'm happy to help explain the thicket.

Beware the cooperative __init__s and event hander methods.
Other modules exist. Note the messy metaclass-based registration.

Scrolling at present is implemented as a mixin, gui.mode.ScrollableModeMixin, because scrollwheel events have their own GTK event type, and thus their own capture method. Touch events are similar - they have their own "

Question: does every tool need to be zoomable or rotatable with gestures? Perhaps they all do, in which case you could probably get away with not delegating the touch events from the controlling gui.document.Document (warning: badly named class! it's an MVC controller for the document, and I want to go MVP with it at some stage...).

Practically, for what you want, you'll probably need to add another capture method on the gui Document class, and add touch events to gui.tileddrawwidget.TiledDrawWidget (unwieldy name for a canvas widget generally shortened to "tdw"). Looks like events are connected to in Document's init. You may or may not need to delegate events to the top mode, I suspect you won't.

There are multiple documents and multiple canvas widgets: the scratchpad is distinct from the main document and its view, and there's another document+tdw pair for the brush preview editor. The main-doc preview dockable points its tdw and controller at the main document's model.

Note that we have support for single-finger panning already introduced in #246's work, but if something like single-figure panning (GTK calls its gesture GtkGestureDrag, GtkGesturePan is axis-locked) with kinetic scrolling could be implemented simply and as a layer that overrides the touch before it turns into a pointer event, that would be awesome. Note the special handling of gui.device.AllowedUsage.NAVONLY for pointer events in the Document class: any overriding touch handling should use the same logic for deciding whether a single-finger touch event should be handled processed immediately and eaten, or let fall through to code that allows painting.

(Apologies for the braindump!)

@achadwick achadwick added the type.Enhancement Issue requests feature. label Sep 15, 2015
@alexandre-mbm
Copy link

From programmer's point of view, how many dollars would be fair to ask to implement this issue?

I want to assess with a potential interested, the possibility to hiring the implementation of this issue and others like it. Would deal in micro-payments platforms such as the Flattr or BountySource...

Someone interested in win a beer? How many? With a estimated term?

@odysseywestra
Copy link
Member

This will be a better suited question on our community forums over at
http://community mypaint.org under the MyPaint Questions or General Talk
category. Please ask there.

@achadwick achadwick added this to the MyPaint v1.3.x milestone Feb 12, 2016
@DiThi
Copy link

DiThi commented Feb 22, 2017

Hello all! Any progress with this? Did detecting touch events got any easier? I'm also interested in supporting a bounty if one is created.

@danShumway
Copy link

danShumway commented May 9, 2018

I am also highly interested in this. I've had no luck getting Clip Studio to work with Wine, and MyPaint is the closest Linux-compatible alternative. But lack of proper gestures like pinch-to-zoom and rotation are kind of a deal breaker at the moment.

@achadwick, is the above comment about MyPaint internals still accurate? I don't have much python experience, so I'm wondering how crazy I would need to be to try and implement something like this.

I really hate booting into Windows whenever I have to draw something.

@danShumway
Copy link

danShumway commented Jun 18, 2018

Question: does every tool need to be zoomable or rotatable with gestures? Perhaps they all do, in which case you could probably get away with not delegating the touch events

I've been looking into this. I had originally thought it did make sense to just always have gestures enabled, but it feels weird for the pen/pencil/eraser tools, since single touch still gets interpreted as a stroke, even during multitouch.

My implementation is going to focus specifically on touchscreens marked as navigation only.

I'm not massively familiar with Python, so not sure how this is going to end up working, but I do have gestures detected, so I'll likely hack some kind of proof of concept... soon-ish?

@danShumway
Copy link

danShumway commented Jun 19, 2018

Gtk gestures work with MyPaint. The performance is really bad; I suspect that's the fault of my implementation because normal rotation/scaling within MyPaint is very smooth on my tablet. Hopefully it's not a Gtk problem and hopefully it's not something incredibly complicated that takes me forever to figure out.

Proof of Concept: https://www.youtube.com/watch?v=f3Cfu5q7WEQ

To expand on what I was talking about above, MyPaint has explicit tools for panning, zooming, and rotating. All of these take single touches and block multitouch events from being thrown. It's possible I could override that, but it feels inconsistent and weird.

I don't want to mess with that paradigm, and I don't want to mess too much with MyPaint's internals. So if you select the rotate tool, you should only rotate.

My plan then is to add another tool alongside pan/rotate/scale that is explicitly multitouch. That will allow you to pan/rotate/scale at the same time with gestures if you select it. If you're on a tablet and you want that on permanently, set your input device to be navigation only and then leave your gesture tool set to multitouch.

This seems to be the strategy that's most consistent with MyPaint's current interface, and that gives users the most flexibility around how they want to use the interface. You'll still be able to draw with your finger on a tablet, you'll still be able to lock a gesture to only rotating or only panning. And maybe that even paves the way to multitouch painting or something in the far future.

@briend
Copy link
Contributor

briend commented Jun 19, 2018

Very cool progress. Regarding performance, do you think the poor performance has anything to do with the number of events received per second? That is, during the gesture to rotate, is mypaint receiving a bazillion events to rotate the canvas 0.0000001 degrees? I had a problem with the color picker, for example-- when moving the mouse around the color picker was picking a color for every single movement event. So it was really spiking CPU for really no benefit. I tamed it a bit by keeping a timestamp of the previous event and ignoring closely spaced events. Probably a much better way to do this. . . :-)

@danShumway
Copy link

danShumway commented Jun 19, 2018

Regarding performance, do you think the poor performance has anything to do with the number of events received per second?

That's my first guess. I don't have a ton of experience with Python, but in my Javascript experience it's fairly common to have event performance go out of control for exactly this reason - I almost always get improvements by debouncing events. It wouldn't surprise me if that's the case here as well since I believe Gtk's event loop is also single threaded.

@briend
Copy link
Contributor

briend commented Jun 19, 2018

Ah "debounce", I didn't know there was a name for it (I don't have a ton of experience in anything ;-). We should maybe look at using a debounce decorator like this
https://gist.github.com/walkermatt/2871026
to wrap any high-cost functions that can be delayed a bit. Obviously switch that to milliseconds :-P

@achadwick
Copy link
Member

A new tool seems like the wrong way to do this. Most multi-touch gestures should be handled independently of the mode stack, in my opinion. It's always useful to point the view somewhere else even if you're laying down some inker goodness and finesseing control points.

(We are doing grabs wrong anyway for Wayland, as my somewhat depressing adventure into it has revealed recently. Ugh, so much is broken on Wayland right now.)

Remember that gestures are implemented as GtkGestures added to widgets in GTK3. they should take care of any low-level handling by MT devices, and they will do it in C. You'd surely only need to throttle the start/update/end notifications you get.

There is no reason a regular input mode cannot add and remove gestures to the main canvas when they are enter()ed and leave()d, perhaps in place of their existing low-level event handling with all that grabby wrongness.

I think the base MT two-finger zoom/pan/rotate core should always be available. In my head-design, they'd have interlocks so that, say, if you two-finger pan over a certain threshold, any rotate or zoom behaviour which has crept in would cancel and reset to zero. This kind of interlocking has to be implemented at the base level, if it's absent in the behaviour of the core GTK objects.

@achadwick
Copy link
Member

If you're getting an unmanageable hosepipe of angle-changed or scale-changed signals, it might be a consequence of us needing to turn event compression off to receive 200Hz event streams and not ~60Hz ones (see gdk_window_set_event_compression()). Trust me, you need fine-grained events for freehand mode in a drawing app 😀

Another way of handling events coming in too fast is to record the angle update and queue up a single one-shot temporary idle handler (see g_idle_add()). The idle handler updates the canvas rotation when it eventually runs, and then de-schedules itself (and clears any record of its ID so a new handler can set up).

@odysseywestra odysseywestra changed the title Add multi-touch support for zoom and scroll [Feature Request] Add multi-touch support for zoom and scroll Dec 28, 2019
@alex-skxy
Copy link

Are there any updates on this?

@brentyi brentyi linked a pull request Mar 6, 2022 that will close this issue
@AesaraB AesaraB linked a pull request Jan 17, 2024 that will close this issue
@AesaraB AesaraB added info.Triage Need to triage this cat.Canvas Issue relates to the canvas and removed info.Triage Need to triage this labels Jan 17, 2024
@AesaraB AesaraB modified the milestones: v2.1.x, Graveyard: Overhauls Jan 17, 2024
@AesaraB AesaraB changed the title [Feature Request] Add multi-touch support for zoom and scroll Add multi-touch support for zoom and scroll Jan 17, 2024
@AesaraB AesaraB added the info.HasInfo Potentially a key to a puzzle label Jan 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cat.Canvas Issue relates to the canvas info.HasInfo Potentially a key to a puzzle type.Enhancement Issue requests feature.
Development

Successfully merging a pull request may close this issue.

9 participants