Anything beyond the basics in using the LiveCode language. Share your handlers, functions and magic here.
Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Thu Jun 09, 2016 9:00 am
Here I am again,
I am building a button click or move routine (for a mobile app).
I have one problem and that is when I move the button by keeping mousedown for 2 seconds, after I release the button (mouse up) it keeps sticking to my mouse.
So if I click the message after the move, before 2 seconds are past, the button keeps sticking to my mouse until I click the button again.
What I really want is, to have the button immediately un-stick after the move is done (after mouseup).
Tried many things but cannot get it to work properly (used 'grab me' but that was even worse).
The script is below. Just place it in a button on a card and test.
Any suggestions ?
Code: Select all
local MovingYN
on mousedown
put "No"into MovingYN
end mousedown
---------------------------------------------------------------------------------
on mouseStillDown // mousedown
--wait 100 millisec with messages
if the mouse is down then
send "StartMove" to me in 2 seconds
end if
end mouseStillDown //mousedown
---------------------------------------------------------------------------------
on mouseMove
if MovingYN is "Yes" then
set the loc of me to the mouseLoc
end if
end mouseMove
---------------------------------------------------------------------------------
on mouseup
if MovingYN is "Yes" then
put the loc of me into TheNewLocation
Answer information "Button has moved to: " & the topleft of me
put "No"into MovingYN
// Now do any routine related to moving this button
// End any routine
else
answer "Button was only clicked!"
// Now do any routine related to clicking this button
// end any routine
end if
end mouseup
---------------------------------------------------------------------------------
On StartMove
put "Yes"into MovingYN
end StartMove
---------------------------------------------------------------------------------
-
dunbarx
- VIP Livecode Opensource Backer
- Posts: 9647
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Post
by dunbarx » Thu Jun 09, 2016 2:11 pm
Hi.
Try this:
Code: Select all
on mouseDown
send "grabMe" to me in 120
end mouseDown
on grabme
if the mouseLoc is within the rect of me and the mouse is down then
set the loc of me to the mouseLoc
send "grabMe" to me in 1
else
exit to top
end if
end grabme
Now this handler is a bit ugly. Do you see why?
Craig Newman
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Thu Jun 09, 2016 6:39 pm
exit to top
Bit of a nasty way to leave but I use it sometime as well
..
I will try your suggestions and give my remarks later today.
Thanks Craig
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Thu Jun 09, 2016 6:54 pm
Cudo's to you Craig,
Your routine works perfect and has very few lines of code
.
I only made very small changes to enable me to incorporate the difference between move and click scripts.
Thanks again !!!
Code: Select all
local MovedYN
on mouseDown
put "No" into MovedYN
send "grabMe" to me in 60
end mouseDown
on grabme
if the mouseLoc is within the rect of me and the mouse is down then
set the loc of me to the mouseLoc
put "Yes" into MovedYN
send "grabMe" to me in 1
else
exit to top
end if
end grabme
on Mouseup
if MovedYN is "Yes" then
answer "Button has been moved !"
else
answer "Button has been clicked!"
end if
end Mouseup
-
dunbarx
- VIP Livecode Opensource Backer
- Posts: 9647
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Post
by dunbarx » Thu Jun 09, 2016 9:30 pm
Hi.
"Exit to top" is an essential snippet. Can't be beat. It derives from "Exit to HyperCard". Use it wisely, and whenever you need to. You will need to, trust me.
The ugly part was the way I threw this together. The "grabMe" handler needs to be slowed down, or it will throw a recursion error. Try it. Waiting 1 tick is adequate to allow the user to:
- move the button smoothly
- keep the recursion error at bay unless the user holds the mouse down for a VERY long time
But it is still ugly. It should be rethought so that the tick is not required at all. Game for that?
Craig
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Fri Jun 10, 2016 1:40 pm
Hi Craig,
Tried it and sure enough after a few moves I got the error so I took up the gauntlet and came up with the following changes.
With the following changed 'grabme' routine the problem seems solved...
No exit or delay needed and fewer lines of code
Thanks for the help Craig
Code: Select all
on grabme
put "Yes" into MovedYN
repeat while the mouseLoc is within the rect of me and the mouse is down
set the loc of me to the mouseLoc
end repeat
end grabme
-
sturgis
- Livecode Opensource Backer
- Posts: 1685
- Joined: Sat Feb 28, 2009 11:49 pm
Post
by sturgis » Sun Jun 12, 2016 2:23 pm
Just for completeness, if you ever have need to use your initial method to move things around, you were close. Here's a version (super simple) that works.
Code: Select all
-- there is still a problem with this method, but it should be easy enough to fix..
-- if you click the button and drag the mouse away before 2 seconds without releasing it,
-- the button will 'jump' to the mouse location after 2 seconds
-- one could add a mouseleave handler that resets the moveDelay if needed.
local MovingDelay
on mousedown
put the millisec into MovingDelay
end mousedown
---------------------------------------------------------------------------------
on mouseMove
if MovingDelay is not empty and the millisec - MovingDelay > 2000 then
set the loc of me to the mouseLoc
end if
end mouseMove
---------------------------------------------------------------------------------
on mouseup
answer information "The mouse was down for" && the millisec - movingDelay && "milliseconds"
put empty into movingDelay
end mouseup
---------------------------------------------------------------------------------
on mouseRelease
-- this is needed on the off chance you move the mouse fast enough to
-- be outside the rect of the button on mouseup. In which case, mouseup is not sent
-- to the button, but mouserelease still is.
answer information "The mouse was down for" && the millisec - movingDelay && "milliseconds"
put empty into movingDelay
end mouseRelease
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Mon Jun 13, 2016 4:03 pm
Thanks Sturgis...
Tried your code and it also works really nice however there is a difference and depending on what you want as a developer both codes have their purpose.
The difference is (as I see it) that your code needs the mouse to move and the other code only needs the mouse to be pressed ....
I like your code best if you want to move things around and tweak the reaction time on when to start moving. I like the other code better when I want the user to keep pressing a button until it 'unlocks' and only then have the user move the button. In your case if the user keeps his cursor or finger still nothing 'unlocks'.
So again, depending on what you want as a developer both codes have their purpose ... really thanks for the support and I am sure I will find a need for both ways.
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Tue Jun 14, 2016 6:26 pm
Small addition to the sturgis code
I changed 'if MovingDelay is not empty and the millisec - MovingDelay > 2000 then'
into 'if MovingDelay is not empty and the millisec - MovingDelay > 2000
and the mouseLoc is within the rect of me then'.
This solves the issue mentioned by Sturgis in the remarks section of his code.
Code: Select all
-- there is still a problem with this method, but it should be easy enough to fix..
-- if you click the button and drag the mouse away before 2 seconds without releasing it,
-- the button will 'jump' to the mouse location after 2 seconds
-- one could add a mouseleave handler that resets the moveDelay if needed.
-- >> Solved with the addition of 'and the mouseLoc is within the rect of me'
local MovingDelay
on mousedown
put the millisec into MovingDelay
end mousedown
---------------------------------------------------------------------------------
on mouseMove
if MovingDelay is not empty and the millisec - MovingDelay > 2000 and the mouseLoc is within the rect of me then
set the loc of me to the mouseLoc
end if
end mouseMove
---------------------------------------------------------------------------------
on mouseup
answer information "From mouseup: The mouse was down for" && the millisec - movingDelay && "milliseconds"
put empty into movingDelay
end mouseup
---------------------------------------------------------------------------------
on mouseRelease
-- this is needed on the off chance you move the mouse fast enough to
-- be outside the rect of the button on mouseup. In which case, mouseup is not sent
-- to the button, but mouserelease still is.
answer information "From mouseRelease: The mouse was down for" && the millisec - movingDelay && "milliseconds"
put empty into movingDelay
end mouseRelease
-
sturgis
- Livecode Opensource Backer
- Posts: 1685
- Joined: Sat Feb 28, 2009 11:49 pm
Post
by sturgis » Tue Jun 14, 2016 6:35 pm
I tweaked the code similar to what mrcoollion did, plus added a timer that changes the cursor to the hand after the delay so that there is a visual cue that the button is now held by the cursor. If interested I'll post the changes. Slightly more complicated but the visual feedback seems to work well.
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Tue Jun 14, 2016 6:40 pm
Please do post!
Regards CL
-
sturgis
- Livecode Opensource Backer
- Posts: 1685
- Joined: Sat Feb 28, 2009 11:49 pm
Post
by sturgis » Tue Jun 14, 2016 6:50 pm
Ok, here it is. Added a constant for the delay, added sMoving as the actual "are we going to move this" flag. added sMessage so that the switch to hand cursor can be cancelled if the mouse leaves the rect of the button before time.
Code: Select all
-- there is still a problem with this method, but it should be easy enough to fix..
-- if you click the button and drag the mouse away before 2 seconds without releasing it,
-- the button will 'jump' to the mouse location after 2 seconds
-- one could add a mouseleave handler that resets the moveDelay if needed.
local MovingDelay,sMoving,sMessage
constant kDelay=500
on mousedown
put the millisec into MovingDelay
put true into sMoving
send "talkToTheHand" to me in kDelay millisec -- sets the cursor to hand, doesn't rely on mousemove
put the result into sMessage -- the message id so we can cancel it if the mouse leaves the button before time
end mousedown
command talkToTheHand
set the cursor to hand
lock cursor
end talkToTheHand
---------------------------------------------------------------------------------
on mouseMove
if sMoving is not empty and the millisec - MovingDelay > kDelay then
set the loc of me to the mouseLoc
else
if the mouseloc is not within the rect of me then
cancel sMessage
put empty into sMoving
unlock cursor
end if
end if
end mouseMove
---------------------------------------------------------------------------------
on mouseup
unlock cursor
answer information "The mouse was down for" && the millisec - movingDelay && "milliseconds"
put empty into sMoving
end mouseup
---------------------------------------------------------------------------------
on mouseRelease
-- this is needed on the off chance you move the mouse fast enough to
-- be outside the rect of the button on mouseup. In which case, mouseup is not sent
-- to the button, but mouserelease still is.
unlock cursor
answer information "The mouse was down for" && the millisec - movingDelay && "milliseconds"
put empty into sMoving
end mouseRelease
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Tue Jun 14, 2016 8:00 pm
Great and thanks Sturgis
,
In addition to all the code above i have made a version based on mouseStillDown .
With this version I do not need to move the mouse (or finger) but i can still tweak the reaction time as i can with the sturgis code.
I should be able to also filter the action on mouseButtonNumber so 'mouseStillDown' only reacts on the left mouse button but i cannot seem to get this working.
Code: Select all
local MovedYN, MovingDelay
on mouseDown
put "No" into MovedYN
put the millisec into MovingDelay
end mouseDown
on mouseStillDown
repeat while MovingDelay is not empty and the millisec - MovingDelay > 1000 and the mouseLoc is within the rect of me and the mouse is down
set the loc of me to the mouseLoc
put "Yes" into MovedYN
set the cursor to hand
lock cursor
end repeat
end mouseStillDown
on Mouseup
if MovedYN is "Yes" then
unlock cursor
answer "From Mouseup : Button has been moved !"
else
answer "From Mouseup : Button has been clicked!"
end if
put empty into movingDelay
end Mouseup
on mouseRelease
answer "From Mouserelease: I have been triggered!"
put empty into movingDelay
unlock cursor // probably not necessary but just in case :-0
end mouseRelease
-
sturgis
- Livecode Opensource Backer
- Posts: 1685
- Joined: Sat Feb 28, 2009 11:49 pm
Post
by sturgis » Tue Jun 14, 2016 8:42 pm
Gotta go to town, but off the top of my head you probably need to do something simple like...
Code: Select all
on mouseDown pBtn
if pBtn is 3 then
put "No" into MovedYN
put the millisec into MovingDelay
end if
end mouseDown
And in your mousestilldown.. Since the dictionary says its sent "periodically" you probably don't want a tight repeat loop in it. Treat it like mousemove and change your repeat to an if.
Code: Select all
if movingDelay is not empty and the millisec - movingDelay > 1000 and the mouseloc is within the rect of me then
set the loc of me to the mouseloc
set the cursor to hand
lock cursor
end if
The tight repeat loop won't leave room for other messages to process, so setting movingdelay probably won't happen, plus it may build up a queue of "mousestilldown" messages for no purpose, and probably negative (slow down or crash) effects.
-
mrcoollion
- Posts: 720
- Joined: Thu Sep 11, 2014 1:49 pm
- Location: The Netherlands
Post
by mrcoollion » Tue Jun 14, 2016 9:25 pm
Just tried your If/Then in place of the repeat suggestion.
Even though it does work the movement of the button is not smooth
and if i move to fast the button is 'lost' .
With the repeat statement every thing works fine and the movement is very smooth.
Try it out yourself and past the code below in a button.
Put 1 or 2 into the whichroutine variable in line 12 to switch between If/Then or Repeat ...
Code: Select all
local MovedYN, MovingDelay,reactiontime
on mouseDown pressedButton
put 500 into reactiontime
if pressedButton is 1 then
put "No" into MovedYN
put the millisec into MovingDelay
end if
end mouseDown
on mouseStillDown
put 2 into whichroutine
if whichroutine is 1 then
If movingDelay is not empty and the millisec - movingDelay > reactiontime and the mouseloc is within the rect of me and the mouse is down then
set the loc of me to the mouseloc
set the cursor to hand
lock cursor
end if
else
repeat while MovingDelay is not empty and the millisec - MovingDelay > reactiontime and the mouseLoc is within the rect of me and the mouse is down
set the loc of me to the mouseLoc
put "Yes" into MovedYN
set the cursor to hand
lock cursor
end repeat
end if
end mouseStillDown
on Mouseup
if MovedYN is "Yes" then
unlock cursor
answer "From Mouseup : Button has been moved !"
else
answer "From Mouseup : Button has been clicked!"
end if
put empty into movingDelay
end Mouseup
on mouseRelease
answer "From Mouserelease: I have been triggered!"
put empty into movingDelay
unlock cursor // probably not necessary but just in case :-0
end mouseRelease