On 2020 Oct 8, at 13:26, Shawn Rutledge 
<shawn.rutle...@qt.io<mailto:shawn.rutle...@qt.io>> wrote:

If you subclass QQuickItem and start handling events, it becomes clear that 
QEvent::accept() has always meant two things in legacy Qt Quick: 1) stop 
propagation and 2) grab the mouse.

…etc… and there weren’t a lot of replies to that thread.  At the time, bigger 
changes were possible; now, Qt 6.0 is released (and then some), and we always 
end up making only incremental changes anyway, with old behavior held in place 
by autotests and tradition and shortage of time.

The next increment seems to be this: I think all pointer handlers (TapHandler, 
DragHandler, HoverHandler, WheelHandler, PointHandler) should share a common 
boolean flag to tell whether they accept or reject events.  What we have so far 
is that TapHandler has gesturePolicy, which was meant to be intuitive for 
designers: describe how it behaves in an observable way, despite the fact that 
under the covers it affects the accept flag, which everyone with Qt experience 
knows about, but designers can’t be expected to know.  Based on bug reports 
we’ve received, programmers still want to control the state of the accept flag 
to control whether further propagation is allowed.  And I want that to be 
declarative, not requiring you to write a JS if statement to decide.

What should we call the flag then?  I think our best candidates so far are 
“blocking”, “transparent” and “propagates".  “Blocking” I think is pretty clear 
(as long as users don’t confuse it with the idea of blocking execution, as 
modal dialogs do); “transparent” maybe has a good meaning if you understand 
that it concerns only event delivery, not appearance, and it goes with things 
like Qt::WindowTransparentForInput; on the other hand, it does not mean that 
the handler fails to react at all, but that it lets the event keep propagating. 
 And speaking of propagating: I’ve never liked the meaning we give to that 
word, because it makes me think of propagating plants: i.e. copying.  In fact 
we try to avoid copying events where possible; and even if we do it, it’s not 
the handler’s job to copy the event and send it to another target; so maybe 
let’s not imply that… even though traditional Qt programmers already know what 
event propagation is.

So what do you think? do you have any preference there?

More background, how this came up again: Richard has been refactoring the 
delivery of hover events in Qt Quick.  It’s something I hadn’t gotten around to 
yet: I’ve been torn for a while on whether we should continue with 
frame-synchronous hover events or come up with something else.  From one 
perspective, the reason we have hover events is to inform all the items and 
handlers that care, that the mouse has moved; so the naive implementation in 
early versions of Qt 5 was just sending the actual mouse moves in the form of 
QHoverEvents, which made me wonder why do we have those: why isn’t a 
QMouseEvent good enough?  But then multiple users wrote bugs complaining about 
the case when the mouse does not move, but items are being animated, and they 
happen to go underneath the current cursor position.  (Why is it so hard for 
items to just observe the mouse?  The trouble is the sheer number of them that 
could want to do that, in general.  So we use events.  Could we possibly invent 
something better?)  Robin fixed this set of bugs by sending an artificial hover 
event once per frame, before the scene graph gets updated prior to rendering.  
It sounds expensive, but we also have a flag 
QQuickItemPrivate::subtreeHoverEnabled, which is false unless the item or one 
of its children actually needs hover events, which it expresses by setting 
hoverEnabled to true.  So if you are worried about the cost of these events, 
make sure your UI design allows us to rule out most or all of the item subtrees 
while we are delivering the hover events, so that it can stop short, and 
doesn’t need to visit every item and handler.  MouseArea has hoverEnabled: 
false by default.  I didn’t want pointer handlers to have restrictions by 
default; so the result of an empty HoverHandler { } declaration inside an item 
is that the item will have its private hoverEnabled flag true, and thus its 
parents all need subtreeHoverEnabled true too.  I wanted to solve the 
long-standing problem when an item and its parent (or grandparent) need to show 
visual hover feedback simultaneously.  MouseArea will only allow that in the 
case that one MouseArea is a direct child of another (not the usual way you 
design components!) and they both have hoverEnabled: true.  HoverHandler works 
regardless of the hierarchy.  So, that implies the hover event needs to be 
rejected by default, so that it can keep propagating to all other hover 
handlers; and that means more work for the delivery code.  Now, Richard wants 
to enable you to optimize it again by having some flag that you can set to tell 
that when one HoverHandler has reacted, it’s enough: nothing else in the scene 
needs to know.  A HoverHandler ought to reject events by default, because it 
cannot know in general whether other items and handlers are interested; but you 
should be able to tell it to leave them accepted so that propagation stops, if 
you know that no others will be interested.

I’m working on Qt Quick 3D lately: when you have an interactive 2D Qt Quick 
scene mapped onto a 3D object, the pointing devices and the keyboard have to 
keep working normally.  That’s the first step.  The next step might be to allow 
declaring pointer handlers directly inside 3D objects, without a 2D subscene: 
that’s just an experiment so far.  (See 
https://github.com/ec1oud/qtquick3d-input-demo for a demo, but it depends on 
features that aren’t yet integrated.)  Anyway… when you hover a 3D object, we 
need to do picking (create a mathematical abstraction of a ray pointing down 
into the scene, calculate which faces of which 3D objects it intersects and at 
what exact positions, then visit each 2D scene that is mapped onto them to see 
what items and handers are impacted), so the expense of doing that at 60FPS (or 
more) is higher than it was in Qt Quick itself.  (Granted, we can probably do 
it less often: every 1/10 of a second might be often enough.  So maybe we can 
just skip some frames until that much time has elapsed.)  I think application 
developers need ways to avoid that overhead in case hover is not needed in most 
of the scene.

WheelHandler behaves in a way that looks to be “blocking” by default, but I 
think we need the flag there too: you should be able to react to the mouse 
wheel in more than one place in the z stack, if you need to.  (Show feedback in 
one layer and actually move something in another layer, for example.). Last 
year I was going to call it acceptsEvents, just in WheelHandler, but that patch 
sat there in gerrit, unapproved for a year, and I already was thinking we need 
to solve this problem in general, not just for WheelHandler.  If we are to have 
one unified flag, the default setting will be different in different handlers, 
and I think that’s OK: we'll just document it.  The interaction between the new 
flag and TapHandler.gesturePolicy is tricky though.  One will have to override 
the other.  I suppose maybe blocking should override gesturePolicy because 
blocking is the geekier flag, you probably know what you’re doing if you use 
it?  But I didn’t try yet; maybe something would go wrong with that.

_______________________________________________
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development

Reply via email to