SFML community forums

Help => Graphics => Topic started by: starkhorn on June 14, 2016, 11:28:02 pm

Title: Doing a drag and drop method
Post by: starkhorn on June 14, 2016, 11:28:02 pm
Hi Folks,

I am trying to implement method that can detect whether a user is holding down the left mouse button, thus indicating that the user is dragging a sprite.

In my event loop, I have this - note some is pseudo code. Basically I am sleeping the program for 100 milliseconds after the a sf::Mouse::Left event is detected. If the mouse is still pressed then I say the user is attempt to drag an icon.

I cannot assume that just having a sf::Mouse::Left indicates that the user is dragging an icon as he could just be left clicking the sprite to select it. If I did then it starts dragging/dropping icons when the user is just trying to select them.

It just seems a bit of an inefficient way to detect whether a user is dragging by adding a sleep. Is there a more efficient method to implement drag/drop, whilst at the same time support left clicking


                        if (event.type == sf::Event::MouseButtonPressed)
                        {
                                //if left button pressed
                                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                                        cout << "left pressed \n";
                                        sf::sleep(sf::milliseconds(100));
                                        if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
                                        {
                                                isDragging = true;
                                                cout << "left pressed and isDragging \n";
                                               
                                                //Here I check if mouse was within the bounds of the sprite and do what I need to do
                                        }
                                }
                        }

 
Title: Re: Doing a drag and drop method
Post by: Hapax on June 15, 2016, 03:08:51 am
Is the sleep there to ensure that the button is held rather than just clicked?
You can do this with a clock by testing how long has passed since the left button was first clicked. It would probably be useful to keep track of this state (pre-drag hold) so that you know when the time has passed and the left button is still down (or just simply hasn't yet been released) you can set the "is dragging" flag only if the pre-drag hold state is present.
Title: AW: Doing a drag and drop method
Post by: eXpl0it3r on June 15, 2016, 01:34:44 pm
IMHO it's easier to track the MouseButtonPressed and MouseButtonReleased event.
Save the initial position when the mouse gets pressed and set a boolean to true. Then in the mouse move event you can check if the boolean is true and if the thing underneath the initial position is dragabble and move the object accordingly.
That way you don't need a timer and don't introduce potential interface lag.
Title: Re: Doing a drag and drop method
Post by: Hapax on June 15, 2016, 08:32:51 pm
I agree that that way is simpler, eXpl0it3r, but sometimes you want to enforce a delay. One reason is for "drag-clicking" (moving the mouse during a click) which might want to be counted as clicking instead of dragging. The problem with that is more evident with touches than clicks.
Title: Re: Doing a drag and drop method
Post by: Mario on June 15, 2016, 08:36:57 pm
Hapax: Just enforce a minimum drag distance. This should avoid all "accidential drags".
Title: Re: Doing a drag and drop method
Post by: Hapax on June 15, 2016, 08:44:09 pm
That too would work for most cases. However, consider accessibility and possible spasms during a click; the move could be quite drastic in a short time.
The timer would alleviate that problem but is probably very likely to be not required for most applications.
Title: Re: Doing a drag and drop method
Post by: starkhorn on June 15, 2016, 11:02:29 pm
Is the sleep there to ensure that the button is held rather than just clicked?

Yes that is exactly why the sleep is there. Basically if the left pressed event is triggered then I want to know if the user is still holding the left button. If I don't have that sleep in there then it takes left clicks as dragging attempts and moves the sprite when I just trying to left-click on the sprite.

I don't think I fully understand the timing method that you are describing. Are you able to clarify how the timer would work?

I did make an attempt as below, but it always seemed to be saying the user was dragging, even during a left-click.

So in my class I defined a gameClock

sf::Clock gameClock;
 

Then at the beginning of the event loop, I have this to check if the left button is pressed and if the gameclock elapsed time is > 100 milliseconds. If not then restart the game clock

                        if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && gameClock.getElapsedTime().asMilliseconds() >= 100)
                        {
                                cout << "gameClock.getElapsedTime().asMilliseconds() = " << gameClock.getElapsedTime().asMilliseconds() << "\n";
                                cout << "setting isdragging to true\n";
                                isDragging = true;
                        }
                        else
                        {
                                gameClock.restart();
                        }
 

Now I am not entirely sure if this what you meant as to having a timer?

Then in my events I have more or less the same thing, except no sleep or isButton pressed check anymore.

                        if (event.type == sf::Event::MouseButtonPressed)
                        {
                                //if left button pressed
                                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                                        cout << "left pressed \n";
                                        if (isDragging)
                                        {
                                                //Here I check if mouse was within the bounds of the sprite and if so then do the dragging updates.
                                        }
                                        else if (!isDragging)
                                        {
                                                //Do the stuff I want to do when user is not trying to do a drag and drop
                                        }
                                }
                        }
 
Title: Re: Doing a drag and drop method
Post by: Hapax on June 17, 2016, 06:05:08 pm
First thing I'd like to mention is that you shouldn't really be mixing real-time mouse states with mouse events for a number of reason not least the fact that they may not match chronologically.

Second is that it's likely that it's a better option to go with the simpler version mentioned above by Exploiter; it's probably a more common method.

Going with the idea of using that method, you can use events like this:

I'm suggesting to manually use a flag/boolean to keep track of the pressed/down state of the button since the events could technically be delayed so the real-time state is inaccurate for the actual time of the events.