Browse Source

Update mouse tutorial (#932)

pull/942/head
Andrew Rudenko 3 years ago committed by GitHub
parent
commit
11464f199e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 96
      tutorials/Mouse_Events/README.md
  2. BIN
      tutorials/Mouse_Events/mouse_click.gif
  3. BIN
      tutorials/Mouse_Events/mouse_enter.gif
  4. BIN
      tutorials/Mouse_Events/mouse_event.gif
  5. BIN
      tutorials/Mouse_Events/mouse_move.gif

96
tutorials/Mouse_Events/README.md

@ -16,10 +16,11 @@ so code like this will work on both platforms:
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -29,9 +30,9 @@ import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) { fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) {
var count = remember { mutableStateOf(0) } var count by remember { mutableStateOf(0) }
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth()) { Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth()) {
var text = remember { mutableStateOf("Click magenta box!") } var text by remember { mutableStateOf("Click magenta box!") }
Column { Column {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
Box( Box(
@ -41,17 +42,17 @@ fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) {
.fillMaxHeight(0.2f) .fillMaxHeight(0.2f)
.combinedClickable( .combinedClickable(
onClick = { onClick = {
text.value = "Click! ${count.value++}" text = "Click! ${count++}"
}, },
onDoubleClick = { onDoubleClick = {
text.value = "Double click! ${count.value++}" text = "Double click! ${count++}"
}, },
onLongClick = { onLongClick = {
text.value = "Long click! ${count.value++}" text = "Long click! ${count++}"
} }
) )
) )
Text(text = text.value, fontSize = 40.sp) Text(text = text, fontSize = 40.sp)
} }
} }
} }
@ -69,6 +70,8 @@ color according to the mouse pointer position:
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -78,15 +81,15 @@ import androidx.compose.ui.input.pointer.pointerMoveFilter
import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.IntSize
fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) { fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) {
var color = remember { mutableStateOf(Color(0, 0, 0)) } var color by remember { mutableStateOf(Color(0, 0, 0)) }
Box( Box(
modifier = Modifier modifier = Modifier
.wrapContentSize(Alignment.Center) .wrapContentSize(Alignment.Center)
.fillMaxSize() .fillMaxSize()
.background(color = color.value) .background(color = color)
.pointerMoveFilter( .pointerMoveFilter(
onMove = { onMove = {
color.value = Color(it.x.toInt() % 256, it.y.toInt() % 256, 0) color = Color(it.x.toInt() % 256, it.y.toInt() % 256, 0)
false false
} }
) )
@ -104,6 +107,8 @@ import androidx.compose.desktop.Window
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -115,25 +120,28 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) { fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { Column(
Modifier.background(Color.White),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
repeat(10) { index -> repeat(10) { index ->
var active = remember { mutableStateOf(false) } var active by remember { mutableStateOf(false) }
Text( Text(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(color = if (active.value) Color.Green else Color.White) .background(color = if (active) Color.Green else Color.White)
.pointerMoveFilter( .pointerMoveFilter(
onEnter = { onEnter = {
active.value = true active = true
false false
}, },
onExit = { onExit = {
active.value = false active = false
false false
} }
), ),
fontSize = 30.sp, fontSize = 30.sp,
fontStyle = if (active.value) FontStyle.Italic else FontStyle.Normal, fontStyle = if (active) FontStyle.Italic else FontStyle.Normal,
text = "Item $index" text = "Item $index"
) )
} }
@ -144,54 +152,46 @@ fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) {
### Mouse right/middle clicks and keyboard modifiers ### Mouse right/middle clicks and keyboard modifiers
While first-class support for pointer type-specific data, like pressed mouse buttons, is still in development in Compose, there is an available raw AWT mouse event object in Compose for Desktop, that can be used as a workaround when you need advanced functionality. Compose for Desktop contains desktop-only `Modifier.mouseClickable`, where data about pressed mouse buttons and keyboard modifiers is available. This is an experimental API, which means that it's likely to be changed before release.
```kotlin ```kotlin
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.gestures.forEachGesture import androidx.compose.foundation.ExperimentalDesktopApi
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.mouseClickable
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.AwaitPointerEventScope
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.changedToDown
import androidx.compose.ui.input.pointer.consumeDownChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.IntSize
import java.awt.event.MouseEvent
@OptIn(ExperimentalDesktopApi::class)
fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) { fun main() = Window(title = "Compose for Desktop", size = IntSize(400, 400)) {
var lastEvent by remember { mutableStateOf<MouseEvent?>(null) } var clickableText by remember { mutableStateOf("Click me!") }
Column {
Text( Text(
text = "Custom button", modifier = Modifier.mouseClickable(
modifier = Modifier.pointerInput(Unit) { onClick = {
forEachGesture { clickableText = buildString {
awaitPointerEventScope { append("Buttons pressed:\n")
lastEvent = awaitEventFirstDown().also { append("primary: ${buttons.isPrimaryPressed}\t")
it.changes.forEach { it.consumeDownChange() } append("secondary: ${buttons.isSecondaryPressed}\t")
}.mouseEvent append("tertiary: ${buttons.isTertiaryPressed}\t")
}
} append("\n\nKeyboard modifiers pressed:\n")
append("alt: ${keyboardModifiers.isAltPressed}\t")
append("ctrl: ${keyboardModifiers.isCtrlPressed}\t")
append("meta: ${keyboardModifiers.isMetaPressed}\t")
append("shift: ${keyboardModifiers.isShiftPressed}\t")
} }
)
Text("Mouse event: ${lastEvent?.paramString()}")
} }
),
} text = clickableText
private suspend fun AwaitPointerEventScope.awaitEventFirstDown(): PointerEvent {
var event: PointerEvent
do {
event = awaitPointerEvent()
} while (
!event.changes.all { it.changedToDown() }
) )
return event
} }
``` ```
![Application running](mouse_event.gif) ![Application running](mouse_event.gif)
If you need more information about events there is an available raw AWT mouse event object in `mouseEvent` property of `PointerEvent`

BIN
tutorials/Mouse_Events/mouse_click.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 110 KiB

BIN
tutorials/Mouse_Events/mouse_enter.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 139 KiB

BIN
tutorials/Mouse_Events/mouse_event.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 889 KiB

After

Width:  |  Height:  |  Size: 61 KiB

BIN
tutorials/Mouse_Events/mouse_move.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 257 KiB

Loading…
Cancel
Save