Hello, I'm just trying 1.0.0 and I can't get objec...
# compose-desktop
k
Hello, I'm just trying 1.0.0 and I can't get objects to pick up the mouse wheel (
.isTertiaryPressed
) button anymore. I was using the
Modifier.pointerInput(Unit)
in 1.0.0-beta5 with Kotlin 1.5.31, and tried just dropping the Compose
-beta5
in my Gradle file to upgrade to the release version. I also tried
.onPointerEvent(PointerEventType.Press)
in 1.0.0, but still it doesn't work. The scroll wheel rotation still works, and the Primary button presses OK. When pressing the wheel button while holding the Primary button down first, my debugging will show that the middle button is being pressed OK, but my conditional code is not running.
i
There were some changes in pointer events behavior. Does this snippet work on your machine?
Copy code
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.singleWindowApplication

@OptIn(ExperimentalComposeUiApi::class)
fun main() = singleWindowApplication {
    var text by remember { mutableStateOf("Press me") }

    Box(
        Modifier
            .fillMaxSize()
            .onPointerEvent(PointerEventType.Press) {
                val position = it.changes.first().position
                text = when {
                    it.buttons.isPrimaryPressed && it.buttons.isTertiaryPressed -> "Left+Middle click $position"
                    it.buttons.isPrimaryPressed -> "Left click $position"
                    it.buttons.isTertiaryPressed -> "Middle click $position"
                    else -> text
                }
            },
        contentAlignment = Alignment.Center
    ) {
        Text(text, fontSize = 30.sp)
    }
}
k
I thought there might have been, so went and looked at that page. I didn't try that code verbatim, but used that structure, and guidance from the Plug-In prompts.
i
but my conditional code is not running
could your show the condition code?
k
Copy code
//                .onPointerEvent(PointerEventType.Press) {
//                    val clicks = it.buttons
//                    val keys = it.keyboardModifiers
//                    val wheelBtn = clicks.isTertiaryPressed
//                    val ctrlBtn = keys.isCtrlPressed
//
//                    val pan = it.calculatePan()
//
//                    val panning = wheelBtn && !ctrlBtn
//                    val rotating = wheelBtn && ctrlBtn
//
//                    if (panning) offset += pan
//
//                    if (rotating) {
//                        rotationZ -= pan.x
//                        rotationX += pan.y
//                        if (rotationX > maxTilt) rotationX = maxTilt
//                        if (rotationX < minTilt) rotationX = minTilt
//                        if (rotationZ > 180) rotationZ -= 360
//                        if (rotationZ < -179) rotationZ += 360
//                    }
//
//                    // This resets the view in case of mad pan-zoom-rotes!
//                    if (clicks.isPrimaryPressed) {
//                        scale = 1f
//                        rotationX = 0f
//                        rotationZ = 0f
//                        offset = Offset.Zero
//                    }
//
//                }
That is under a Surface( modifier = Modifier .......
The
.onPointerEvent()
code wouldn't work when I tried going back to -beta5.
i
if (clicks.isPrimaryPressed) {
It should be
Copy code
if (!panning && !rotating && clicks.isPrimaryPressed) {
When we click with the wheel button, and the left button is still pressed,
isPrimaryPressed
will return true We have fixed a bug, when onPointerEvent/pointerEvent wrongly reported pressed buttons, so it is probably because of that your code behaves differently in 1.0.0.
k
I expected changes, so not an issue. I'll cogitate what you've written and try that. Thanks Igor for your help again, and congrats on the release!
i
if (!panning && !rotating && clicks.isPrimaryPressed)
or not. one minute 🙂
k
😁
Copy code
.pointerInput(Unit) {
                    forEachGesture {
                        awaitPointerEventScope {
                            awaitFirstDown()
                            do {
                                val event = awaitPointerEvent()
                                val clicks = event.buttons
                                val keys = event.keyboardModifiers
                                val wheelBtn = clicks.isTertiaryPressed
                                val ctrlBtn = keys.isCtrlPressed

                                val pan = event.calculatePan()
                                val panning = wheelBtn && !ctrlBtn
                                val rotating = wheelBtn && ctrlBtn

                                if (panning) offset += pan

                                if (rotating) {
                                    rotationZ -= pan.x
                                    rotationX += pan.y
                                    if (rotationX > maxTilt) rotationX = maxTilt
                                    if (rotationX < minTilt) rotationX = minTilt
                                    if (rotationZ > 180) rotationZ -= 360
                                    if (rotationZ < -179) rotationZ += 360
                                }

                                // This resets the view in case of mad pan-zoom-rotes!
                                if (clicks.isPrimaryPressed) {
                                    scale = 1f
                                    rotationX = 0f
                                    rotationZ = 0f
                                    offset = Offset.Zero
                                }
                                println("$wheelBtn $ctrlBtn")
                                //println("Pan $panning Rot $rotating rotX $rotationX rotZ $rotationZ")
                                //println("Pan $pan Pan2 $pan2 Dist $panDist Dir ${panDir * 180 / PI} Scale $scale rotX $rotationX rotZ $rotationZ")
                            } while (event.changes.any { it.pressed })
                        }
                    }
                }
This was my original code that worked perfectly in beta5.
I've gone back to beta5 so I can continue working on some other conceptual stuff.
i
Resetting with the left button should happen, even if the middle button is pressed, right? In that case, the condition should be:
Copy code
if (clicks.isPrimaryPressed && !isPrimaryPressedPrevious) {
     println("reset")
}
isPrimaryPressedPrevious = clicks.isPrimaryPressed
Where
isPrimaryPressedPrevious
is:
Copy code
var isPrimaryPressedPrevious by remember { mutableStateOf(false) }
It is somewhat inconvenient, but probably this is the only way, when we need to work with multiple pressed buttons.
k
Hmm. OK, I'll look that up. My main issue was that even with no buttons pressed, the wheel button was causing no response. I better head to bed, so thanks for your help!
The resetting with the left button was just a tool I built in while debugging.
i
the wheel button was causing no response.
not sure, but that is probably because we reset after we try to rotate
k
I could've made it anything else, but it was just convenient.
Reset the Composable after rotating, you mean?
I wonder if it's something to do with the
.forEachGesture
code that I got from a sample online? Separating out each click as a separate event?
i
When the left button is pressed, and we try to rotate with the middle button, we change rotationZ/rotationX in
if (rotating)
condition, but after that we execute code in
if (clicks.isPrimaryPressed)
condition, which sets rotationZ/rotationX to 0.0
k
OK, but if I don't touch the left button, and try to rotate the view with only the middle button and Ctrl key, it still doesn't do anything? It should only reset the view if the mouse is moved with the left button down?
i
forEachGesture
probably, it checks the state of
it.changes.first().changedToDown()
. and we had a bug in it, when we press multiple buttons.
it still doesn't do anything
Oh, in that case, it is something else.
k
Ah, that might be part of it then, but still it should work with the new
.onPointerEvent
code I wrote. Which should I be using?
.onPointerEvent
or
.pointerInput
?
As a side note, how do you do that Quote Reply business you've done there?
With the grey bar, quoting my text?
Oh, in that case, it is something else.
Found it! 🤓 OK, well I'll have to leave it with you mate! Goodnight!
🎉 1
i
onPointerEvent
is basically a simplified
pointerInput
(you can look at the code inside). I would recommend to use
onPointerEvent
(
pointerInput
can be helpful for more complex event handling, that is based on couroutines) Also,
forEachGesture
doesn't work well with multiple pressed buttons, so I suggest to avoid it.
k
OK thanks very much. 😎👍🏻
i
As a side note, how do you do that Quote Reply business you've done there?
Just type ">", and Slack transforms it to quote 🙂
k
Oh! That's easy then! Thanks!
Cool!
🤩 1
🙂 1
Bold italic strike
code.segment
Quote!
😄
💤
Ha! I got things to move again Igor!! I needed to use
.onPointerEvent(PointerEventType.Move) {
instead of
.Press)
!! I discovered all the buttons and keyModifiers were working fine, but I was getting no
.calculatePan()
, so I looked into the PointerEventTypes available. Looks like I might be able to use the
.Scroll
to detect the mouse wheel, instead of
.mouseScrollFilter
? What would you recommend? Also on that thought, is there any issue with having multiple
.onPointerEvent
modifiers, or is that just the way to do it? I guess it is the only option, as you'd need different types of
PointerEventType
parameters for different input types....
In my old code from the online sample I used, it had a do {} while () loop to keep tracking the mouse while the wheel button was down. This one is much neater!
i
I needed to use 
.onPointerEvent(PointerEventType.Move) {
  instead of 
.Press)
Oh, right, the small detail that didn’t catch an eye 🙂
Looks like I might be able to use the 
.Scroll
 to detect the mouse wheel, instead of 
.mouseScrollFilter
 ? What would you recommend?
mouseScrollFilter
will be deprecated in 1.1 or in 1.2, better to use
.Scroll
.
or is that just the way to do it
Yes, that is the way in which
.onPointerEvent
should be used. Each
onPointerEvent
creates a separate coroutine, so if your application is big, it can create 500 coroutines instead of 200 (if we would use
pointerInput
). And it doesn’t sound scary, because coroutines are lightweight.
k
All good! Ah, OK, thanks for the heads up! I'm having trouble finding the delta extraction anyway!!
Awesome. A nicely scaling infrastructure then! Thanks mate! I'll try
.Scroll
now....
Actually, yes
PointerEventType.Scroll
is what I'm working on now. I thought you meant a .Scroll modifier! 🥴
I can't find how to extract the scroll delta.
Ah, I think I have it now. I found a section on Mouse scroll listeners in the GitHub 1.0.0 release docs. Thanks to whoever has been updating all those docs!!!!!!!!! That is a massive job, and one I'm supposed to be helping with on our hobby project, but I keep getting distracted lately with coding!! 🤓
🙂 1
Yep, all working. Got what I needed! Thanks!
Maaaate!! And I've got "Click & Drag to New Position" working! Sooo easy! Not like in T...oFX like I was trying to use earlier...... 🤭
If only we can sort out the touch targets at X / Y rotated angles........ Not that I would know enough to help, but where would I look to find the code that manages touch targets??
Sorry, I'll ask the others in the thread where we were talking about it!