JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.02k stars 1.1k forks source link

PressInteraction.Cancel is sent on mouse press and drag outside surface #4801

Open adrientetar opened 3 weeks ago

adrientetar commented 3 weeks ago

I'm using a MutableInteractionSource.interactions for a Button control, to know when it's focused/pressed/hovered. I noticed that, when I press the button, a PressInteraction.Press is sent (as you would expect), but then if I drag outside of the button while keeping pressed, PressInteraction.Cancel is sent, and mouse press isn't being tracked further (no PressInteraction.Release is sent when releasing the mouse button). Is it on purpose?

On Mac at least, it looks like the usual behavior (system apps) is that if you press a button, and then move wherever, as long as you come back inside the button bounds when you release the mouse, it will be counted as a press. The way InteractionSource works right now though, it's not possible to have the desktop press behavior. It works however if I use .onPointerEvent(PointerEventType.Press) and .onPointerEvent(PointerEventType.Release).

I'm wondering if, InteractionSource and onPointerEvent are supposed to have the same behaviors?

Affected platforms

Versions

To Reproduce You can use this snippet on desktop

eymar commented 2 weeks ago

The observed behaviour is the same on Android, so it's inherited from Jetpack Compose.

From InteractionSource docs:

A common use case is androidx.compose.foundation.indication, where androidx.compose.foundation.Indication implementations can subscribe to an InteractionSource to draw indication for different Interactions, such as a ripple effect for PressInteraction.Press and a state overlay for DragInteraction.Start.

So using InteractionSource is not the best way to derive the actions on buttons (clicked, double-clicked, etc). Listening to Pointer Events is a better choice for this.

JFYI: When dragging after PointerEventType.Press there is also PointerEventType.Exit event before PointerEventType.Release.

Considering the visual effects manifested by a Button when I interact with it, I assume the behaviour of InteractionSource is correct. If your use case requires not visual effects, but some other logic probably PointerEvents is better option.

Could you please share more details about your use case?