Skip to content

Commit

Permalink
Desktop: Treat Swing drag and move mouse events as Compose move events
Browse files Browse the repository at this point in the history
Difference between Swing drag and move events:
- move events are fired only in the bounds of the window and when mouse isn't pressed
- drag events are fired when mouse is pressed and can be fired even if the mouse outside of the pressed window

Currently we treat drag events only as Modifier.pointerInput events.
And move events only as Modifier.onPointerMove events

This CL allows:
- handle any mouse move/drag events with Modifier.pointerInput
- use mouse hover (Modifier.onPointerMove) with the pressed mouse button

But after this some components should handle Modifier.onPointerMove(onExit={}) differently.
For example, we need to keep scrollbar highlighted when we move mouse outside of the scrollbar.

Before this CL this was handled automatically, because we didn't send move events when we drag the mouse.
But it shouldn't be handled automatically, developer should explicitly write this logic
(keep scrollbar highlighted when we drag it)

Fixes:
JetBrains/compose-multiplatform#134
JetBrains/compose-multiplatform#530

Change-Id: If510840c2c7e4bf2e192f9990e5a05cec592635a
Test: manual ./gradlew :compose:desktop:desktop:desktop-samples:run1 -Pandroidx.compose.multiplatformEnabled=true
Test: drag Scrollbar and move mouse outside
  • Loading branch information
igordmn committed May 6, 2021
1 parent 60beda7 commit 76a746c
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -194,7 +195,13 @@ private fun Scrollbar(
}

var containerSize by remember { mutableStateOf(0) }
var isHover by remember { mutableStateOf(false) }
var isHovered by remember { mutableStateOf(false) }

val isHighlighted by remember {
derivedStateOf {
isHovered || dragInteraction.value is DragInteraction.Start
}
}

val minimalHeight = style.minimalHeight.toPx()
val sliderAdapter = remember(adapter, containerSize, minimalHeight) {
Expand All @@ -213,7 +220,7 @@ private fun Scrollbar(
}

val color by animateColorAsState(
if (isHover) style.hoverColor else style.unhoverColor,
if (isHighlighted) style.hoverColor else style.unhoverColor,
animationSpec = TweenSpec(durationMillis = style.hoverDurationMillis)
)

Expand All @@ -231,8 +238,8 @@ private fun Scrollbar(
},
modifier
.pointerMoveFilter(
onExit = { isHover = false; true },
onEnter = { isHover = true; true }
onExit = { isHovered = false; false },
onEnter = { isHovered = true; false }
)
.scrollOnPressOutsideSlider(isVertical, sliderAdapter, adapter, containerSize),
measurePolicy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ internal class ComposeLayer {
})
wrapped.addMouseMotionListener(object : MouseMotionAdapter() {
override fun mouseDragged(event: MouseEvent) = events.post {
owners.onMouseDragged(
owners.onMouseMoved(
(event.x * density.density).toInt(),
(event.y * density.density).toInt(),
event
Expand All @@ -185,7 +185,8 @@ internal class ComposeLayer {
override fun mouseMoved(event: MouseEvent) = events.post {
owners.onMouseMoved(
(event.x * density.density).toInt(),
(event.y * density.density).toInt()
(event.y * density.density).toInt(),
event
)
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import androidx.compose.ui.input.pointer.PointerInputEventProcessor
import androidx.compose.ui.input.pointer.PointerInputFilter
import androidx.compose.ui.input.pointer.PointerMoveEventFilter
import androidx.compose.ui.input.pointer.PositionCalculator
import androidx.compose.ui.input.pointer.ProcessResult
import androidx.compose.ui.input.pointer.TestPointerInputEventData
import androidx.compose.ui.layout.RootMeasurePolicy
import androidx.compose.ui.layout.boundsInWindow
Expand Down Expand Up @@ -317,9 +318,9 @@ internal class DesktopOwner(
root.draw(DesktopCanvas(canvas))
}

internal fun processPointerInput(event: PointerInputEvent) {
internal fun processPointerInput(event: PointerInputEvent): ProcessResult {
measureAndLayout()
pointerInputEventProcessor.process(event, this)
return pointerInputEventProcessor.process(event, this)
}

override fun processPointerInput(nanoTime: Long, pointers: List<TestPointerInputEventData>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,20 @@ internal class DesktopOwners(
pointerId += 1
}

fun onMouseDragged(x: Int, y: Int, nativeEvent: MouseEvent? = null) {
lastOwner?.processPointerInput(pointerInputEvent(nativeEvent, x, y, isMousePressed))
fun onMouseMoved(x: Int, y: Int, nativeEvent: MouseEvent? = null) {
val event = pointerInputEvent(nativeEvent, x, y, isMousePressed)
val result = lastOwner?.processPointerInput(event)
if (result?.anyMovementConsumed != true) {
val position = Offset(x.toFloat(), y.toFloat())
lastOwner?.onPointerMove(position)
}
}

fun onMouseScroll(x: Int, y: Int, event: MouseScrollEvent) {
val position = Offset(x.toFloat(), y.toFloat())
lastOwner?.onMouseScroll(position, event)
}

fun onMouseMoved(x: Int, y: Int) {
val position = Offset(x.toFloat(), y.toFloat())
lastOwner?.onPointerMove(position)
}

fun onMouseEntered(x: Int, y: Int) {
val position = Offset(x.toFloat(), y.toFloat())
lastOwner?.onPointerEnter(position)
Expand Down

0 comments on commit 76a746c

Please sign in to comment.