@ -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")
}
}
}
)
Text("Mouse event: ${lastEvent?.paramString()}")
}
}
append("\n\nKeyboard modifiers pressed:\n")
private suspend fun AwaitPointerEventScope.awaitEventFirstDown(): PointerEvent {
append("alt: ${keyboardModifiers.isAltPressed}\t")
var event: PointerEvent
append("ctrl: ${keyboardModifiers.isCtrlPressed}\t")
do {
append("meta: ${keyboardModifiers.isMetaPressed}\t")
event = awaitPointerEvent()
append("shift: ${keyboardModifiers.isShiftPressed}\t")
} while (
}
!event.changes.all { it.changedToDown() }
}
),
text = clickableText
)
)
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`