Detecting Mouse Click once only

Monkey Forums/Monkey Beginners/Detecting Mouse Click once only

Arabia(Posted 2014) [#1]
I've managed to sort this problem out, but I'm sure there is an easier way which someone can help me with. It's for things like clicking on a button or image to select it.

e.g.

Global ImageSelected:Bool = True

Method OnUpdate()
  If MouseDown()
     if ImageSelected Then ImageSelected = False Else ImageSelected = True
 Endif
End


If this code is run, the ImageSelected variable with alternate between True & False until the mouse is released. What I want is for it to change only once until the mouse button is released, and then change again if the use clicks again.

I thought it would be a simple matter of putting a Repeat...Until NOT MouseDown() but this doesn't work - I'm guessing with the way Monkey Apps update (30 or whatever times a second) it just jumps out of the Repeat...Until loop - is that correct?

I won't post the full code of how I got around this, basically it was making another variable like MouseStillDown:Bool and then setting it inside the MouseDown() code.

Global MouseStillDown:Bool = False

If MouseDown() and NOT MouseStillDown Then
  MouseStillDown = True
  If ImageSelected Then ImageSelected = False Else ImageSelected = True
Endif

If NOT MouseDown() Then MouseStillDown = False


Guess what I'm asking is this, is the 2nd way and the way I'm doing it the correct way, or is there something easier that I'm missing?


Cocopino(Posted 2014) [#2]
I don't think you're missing something, you probably need your own custom MouseUp state or event. Basically you don't want to register a click when the user is just starting to click the button, he could be dragging the mouse away while holding the mouse button down.
If the user releases the click (MouseUp) inside the same button area he started to click, only then register it as a button press. Then, immediately after you've handled the click, set the MouseUp state back to false.

Alternatively, you can use MouseHit() and see if that yields better results for you.


Arabia(Posted 2014) [#3]
Yeah the MouseUp() makes a lot of sense for the exact reason you specified, but that also means checking that the mouse was first clicked on the object and then release while also on the object.

As long as the way I'm doing this currently is Ok, that's fine, I just thought there may have been a simpler way of doing it.

I haven't looked at any of the GUI modules to see how they work, and I really don't know as much about Monkey as I ought to. I'm guessing you could define each button/screen area as an Object/Class and have a MouseDown() & MouseUp() method to trigger when they are clicked.

Must go back and watch some of the more advanced Tutorials by InvaderJim, I'm sure there is some stuff in there that will address the above Class creation.


Gerry Quinn(Posted 2014) [#4]
The easiest way to do this is to use the MouseHit() function. That will tell you if the mouse was clicked since the previous update,

If MouseHit( MOUSE_LEFT ) > 0 And MouseIsOverButton()
DoButtonAction()
End

MouseDown() would be used if you were dragging or drawing something.


ziggy(Posted 2014) [#5]
MouseHit detects clicks, MouseDown detects button status (pressed or not). To sumarize, MouseHit will be "true" when the mouse button was up on previous frame, and it's down on current frame. This, or when mouse button was down in previous frame and it is up on current frame. That makes it be true only once per click, so it's useful to program buttons and the like.


ElectricBoogaloo(Posted 2014) [#6]
I tend to use a global "mdwn" variable, and set it upon "click".
The problem with mousehit is that it only works on that exact frame, so if you miss it by a fraction of a second, you've lost the "tap"
Instead, I check with MouseDown, then, upon "first use", I flag mdwn=1. Upon mousedown=0, I reset mdwn=0.
Basically, a little DIY goes a long way.


Derron(Posted 2014) [#7]
Instead of handling "hit" you might be interested in "click". "click" means: it was once down, is now up AND the time since that "up" is at least X milliseconds.

Why? How will you know if it is a "click" or a "doubleclick" (or triple or ...). Means: only use "hit" if you do not care for doubleclicks or others. Keep this in mind if your code evolves into something like a gui system.

To handle such things you might create your own mousemanager storing state data.


bye
Ron


Gerry Quinn(Posted 2014) [#8]
MouseHit(), unless it's bugged, is per update, not per rendering frame. Check it every update and you will be fine.

Of course you can track things any way you want instead - I do myself. But MouseHit() is the built-in function to allow you to test button-clicks easily.


Derron(Posted 2014) [#9]
Like said this does not "test for button clicks" but for "button hits" - which is something different (according to Microsoft - they handle it similar to the thing I described -> hit + waitingTime = click). Please make sure that you store the "hit position" as it might differ to the current one (clicking while moving the mouse).

bye
Ron


Gerry Quinn(Posted 2014) [#10]
Yeah, but classic Windows buttons are different - they are 100% mouse oriented and they fire on release if the mouse is still over the button. If you put down the mouse on a button, you can change your mind by dragging it away before you release it,.

It seems to me that with modern touch interfaces, you may as well just respond immediately to a mouse-down in a button area. That is simple and works whether there is a mouse or touch interface.

Maybe that's because I am multi-targeting, like many Monkey users. If you're targeting one device only, I guess it makes sense to have a less generic interface.


Derron(Posted 2014) [#11]
Hmm regarding "touch" and "similar behaviour" you are absolutely right that it might better to rely on "hit".

I personally always liked that "arghh... i wanted to click that other button"-rescue-method. It is of course also available on touch devices - as long as you keep your finger in touch with the device.

For me it is just the question of whether I need to distinguish between single and double clicks/taps. Then of course it is also a matter if I want to support "drag and drop", if you "click" on hit already, you never know if the finger/mousebutton was down for a specific period. That is why for a more complicated "gui" you will still need multiple events: mousehit (was up, is now down), mouseClick (was "hit" and is now up + waited enough time), mouseDoubleClick(mouseClick + hitCount = 2), ... A TryDrag (or startDrag) needs to know then, if the gui element was "clicked" or not - so normally it should react on "mouseDown + waitedTime" or "mouseDown + mouseMovedDistance>value".

For a normal "menu button" this is pure overhead and you might just choose between: onHit or onClick.

BTW: good idea with "onRelease" ... this is missing in my blitzmax-gui-lib and might be of use.


bye
Ron