Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions druid/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,11 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
}

// TODO: factor as much logic as possible into monomorphic functions.
if ctx.is_handled
&& !matches!(
event,
Event::MouseDown(_) | Event::MouseUp(_) | Event::MouseMove(_) | Event::Wheel(_)
)
{
// a follow_up event should reach the widget which handled the first event.
// in this case we dont discard events when ctx.is_handled is set but just dont set our hot
// state to true
let follow_up_event = event.is_pointer_event() && self.state.has_active;
if ctx.is_handled && !follow_up_event {
// This function is called by containers to propagate an event from
// containers to children. Non-recurse events will be invoked directly
// from other points in the library.
Expand Down
10 changes: 10 additions & 0 deletions druid/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,16 @@ impl Event {
| Event::Zoom(_) => false,
}
}

/// Returns true if the event involves a cursor.
///
/// These events interact with the hot state and
pub fn is_pointer_event(&self) -> bool {
matches!(
self,
Event::MouseDown(_) | Event::MouseUp(_) | Event::MouseMove(_) | Event::Wheel(_)
)
}
}

impl LifeCycle {
Expand Down
27 changes: 16 additions & 11 deletions druid/src/widget/z_stack.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
BoxConstraints, Data, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx,
Point, Rect, Size, UnitPoint, UpdateCtx, Vec2, Widget, WidgetExt, WidgetPod,
BoxConstraints, Data, Env, Event, EventCtx, InternalEvent, LayoutCtx, LifeCycle, LifeCycleCtx,
PaintCtx, Point, Rect, Size, UnitPoint, UpdateCtx, Vec2, Widget, WidgetExt, WidgetPod,
};

/// A container that stacks its children on top of each other.
Expand Down Expand Up @@ -94,17 +94,22 @@ impl<T: Data> ZStack<T> {

impl<T: Data> Widget<T> for ZStack<T> {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
let is_pointer_event = matches!(
event,
Event::MouseDown(_) | Event::MouseMove(_) | Event::MouseUp(_) | Event::Wheel(_)
);

let mut previous_hot = false;
for layer in self.layers.iter_mut() {
layer.child.event(ctx, event, data, env);

if is_pointer_event && layer.child.is_hot() {
ctx.set_handled();
if event.is_pointer_event() && previous_hot {
if layer.child.is_active() {
ctx.set_handled();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this set_handled? Given your point about set_handled affecting the rest of the widget tree, it seems maybe better to avoid it?

Copy link
Collaborator Author

@xarvic xarvic Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean replace it with the obstructed flag or just remove it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a good chance I'm missing something, but I was thinking just remove it. Does that work?

I'm expecting that this child is active but not hot, and it will know how to correctly handle mouse events based on that, even if they aren't marked as handled.

Copy link
Collaborator Author

@xarvic xarvic Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm expecting that this child is active but not hot, and it will know how to correctly handle mouse events based on that, even if they aren't marked as handled.

The child only knows that it is not hot because it received a follow up event (Mouse event while active is set) which was marked as ´handled´.

In any case we either need set_handled or obstructed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't the child do ctx.is_hot()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is about the Pod not the widget. The Pod sees a mouse event inside its bounds. Therefore it sets its hot state to true. The only exception is that active and hot are both set. In that case the Pod sets hot to false but still propagates the event.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean handled and not active, right? So in that case I understand why you need set_handled here, thanks for the explanation! I still think it isn't ideal because (as you explained in some other thread) it affects the global widget tree and not just the subtree under the zstack. But I don't think figuring it out needs to block this pr...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ups my mistake. I meant active and set_handled. In this case hot is set to false even if the curser is inside the widgets bounds

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think it isn't ideal because (as you explained in some other thread) it affects the global widget tree and not just the subtree under the zstack. But I don't think figuring it out needs to block this pr...

I aggree. The only thing which is still brocken is scrolling while pressing a mousebutton. That is not the most impprtant usecase. I think we can merge this PR as it is.

layer.child.event(ctx, event, data, env);
} else {
layer
.child
.event(ctx, &Event::Internal(InternalEvent::MouseLeave), data, env);
}
} else {
layer.child.event(ctx, event, data, env);
}

previous_hot |= layer.child.is_hot();
}
}

Expand Down