isButtonDown()


#1

Why does this not work? There is no mouse movement just holding down the button.

[code]void SomeComponent::mouseDown(const MouseEvent& e)
{
int64 t = Time::getCurrentTime().toMilliseconds() + 1000; //One second for test purposes
while ( Time::getCurrentTime().toMilliseconds() < t ) //Wait for one second
{
}

if ( isMouseButtonDown() )
{
    //Always gets here even if button is released within the above loop
}

}
[/code]
All I want to do is make sure the mouse is still down after a given amout of time before calling a function. I know it is better to check the button within the loop but this is for testing purposes.


#2

Probably because you are blocking the message thread so no new mouse events are passed to the application and thus the mouse state is not updated and still in the down state it has to be in to trigger that callback.

You could start a timer then check if the mouse is still down in the timer callback? Something like (untested):

[code]class SomeComponent : public Timer
{
public:
// all the usual

void timerCallback();

}

void SomeComponent::mouseDown(const MouseEvent& e)
{
startTimer (1000);
}

void SomeComponent::timerCallback()
{
if ( isMouseButtonDown() )
{
// do some stuff
}

stopTimer();

}
[/code]


#3

Thanks but that seems quite funky and there must be a better method. I understand the logic of what you said but Windows and Mac both make this fairly simple. So the basic question is how do I wait a bit to see if the button is still down. Until I get a better method I guess that is what I’ll have to do. Thanks again.


#4

No, I can assure you that they don’t!

dave96’s suggestion is the correct way to do it, you MUST NOT pause on the event thread, and that’s true of every event-based GUI system that I’ve ever seen.

Yes, there are ways in which you can hackily run the event dispatch loop synchronously, but it’s very dangerous, and I’m not going to tell you the methods to use, so you’re not tempted to try it.

Personally, I’d have done it like this, to avoid checking the mouse-button state:

class Foo : public Component, Timer, etc { void mouseDown (const MouseEvent&) { startTimer (1000); } void mouseUp (const MouseEvent&) { stopTimer(); } void timerCallback() { stopTimer(); doSomeStuff(); } };


#5

I understand what you mean not pausing the event thread and I know the dangers but sometimes it is just simpler to do it when it is not dangerous.

I did not try this but wondering if this work:

Use component beginDragAutoRepeat to have mouseDrag called continuously and would the mouse event time be updated? Guess I could try it.


#6

Maybe I didn’t make myself clear…

I’m NOT saying: “it’s generally best to not use a modal loop like that, but yeah, sometimes it’s ok”.

I’m saying: “It’d be an absolutely fucking horrendous bit of sloppy hackery to ever use a modal loop like that, under any circumstances!”

It’s very easy to write the code properly, like we’ve shown you, so if you ignore our advice and use a modal loop, well… good luck with that!


#7

Watch you language here, there are nice people trying to use your code. Take it from me who has written four major music apps still in existence. Sometimes you have to hack the code because the authors of the code you’re using didn’t think globally and did not provide what others needed. I wrote a little demo app based on the juce font demo that had three Components (panels). When I rearranged the panels by hiding them, repositioning them, and them making them visible, it took ten seconds to recalculate itself and redraw, all done the safe juce way and this was on a MAC book pro with Solid State Drives. Maybe I didn’t understand the best juce way, but 10 seconds on any machine is a very long time. So please don’t be so critical and assume this is the holy grail of code. Sometimes safe code is SLOW code and real apps need to be fast, especially music apps. BTW, I crash juce code plenty even though it’s “safe code”. My hacked up app with a hacked up hosting code doesn’t crash when loading plugins, etc.

What I am saying is sometimes extra methods need to be written to get around slow message loops. Ex. Providing screen buffer flushing instead of waiting on the message loop. I spent a half an hour the other night writing code to get a component to erase(flash) and then redraw. I needed the flash to show the component was refreshing with a slight delay, even though it’s contents might not have changed, so the user knows something is happening. I am getting familiar with the juce way and even though it is a great concept, sometimes it is very difficult to do simple tasks that are common with MAC and PC. I can’t comment on Linux and Android yet.

Component::paint documentation

“If you want to cause a component to redraw itself, this is done asynchronously - calling the repaint() method marks a region of the component as “dirty”, and the paint() method will automatically be called sometime later, by the message thread, to paint any bits that need refreshing. In Juce (and almost all modern UI frameworks), you never redraw something synchronously.” “Sometime later” is not a good design for some apps. Think about gaming programs. They would never do it this way.

You didn’t answer this question:
Would using component beginDragAutoRepeat to have mouseDrag called continuously provide correct event times and would this be a cleaner method? Guess I could try it.


#8

[quote]You didn’t answer this question:
Would using component beginDragAutoRepeat to have mouseDrag called continuously provide correct event times and would this be a cleaner method? Guess I could try it.[/quote]

okay, here’s an answer to that question: No, that’s a stupid idea.

A timer will give you a callback after a specified time, for you to respond. That’s what you’ve said that want to do. Yet you express that such a solution somehow does not help you, and you would prefer to generate drag messages? Your attitude strikes me as very odd indeed.


#9

Wasn’t trying to be rude, but you seemed not understand just how strongly I’m recommending that you do NOT write code like that!

I obviously do a lot of benchmarking of rendering performance, and a screenful of controls, SVG images, gradients, etc should happily draw in < 10ms. If you have a program that takes 1000x longer than that, then I can only assume you’re mistakenly doing 1000x the work that’s actually needed. But to just quote a time like that as if it’s a fault in my code, without even having profiled it to see where the bottleneck is occurring, isn’t very helpful!

No. That’s not what that method does.

Back in the 1990s, that “flush to the screen” way of thinking might have still been common, but honestly, somewhere in the mid-90s people realised it was crap, and every GUI system since then has used asynchonous dirty-region repainting, because it works really well, and makes far, far more sense.

And saying “methods are needed to get around slow message loops” is like saying “bandages are needed for when I shoot myself in the foot”. No. Methods are NOT needed to get around slow message loops. A slow message loop is a BUG and needs to be fixed, not worked-around.

Erm… I think you’ll find that games either:

  • Do it this way, because a properly-written app that doesn’t block the message queue can expect the redraw to happen within a few milliseconds, which is more than fast enough.
  • Or, they have a dedicated rendering thread using openGL, which is entirely separate from the message thread. But even here, the golden rule of never blocking the message thread still applies.

#10

FirePlayer - I don’t want to be dis-respectful, but this is the umpteenth time you have mentioned this, and it’s getting old. This isn’t the place for a “pissing” match. We’re a small community here, and relying on anyone’s framework, means you aren’t going to get everything you need in the way you see fit. Meaning, its always going to be a compromise, unless of course you write your own framework. You seem to have a very strong opinion on how things should work, which is great, but if it goes against JUCE’s modus operandi, then subclass, fork, rewrite away! If JUCE is crashing on you(which I have to say it hardly ever does for me, only through my own stupidity), then post some crash-logs, steps to reproduce. I think you’ll find we’re all here to help each other, a quick browse through of the topics and the replies(even this one!) shows that!

Justin


#11

This is where I checked out. Not only are you resisting people’s help, you are making bold statements of fact that are complete BS.

Pretty much every game - judging by pretty much every game development book - gathers user input in/on the main thread, then uses that to affect actions in the main ‘game loop’. At most they may poll for the current state of controls in the game loop, but that’s not workable in most environments.

To suggest that they all block (at all) waiting for users to do things, and arbitrarily redraw entire scenes from random pieces of code throughout the app is just silly.

Please dial down the arrogance if you want to work with the users of this forum.

Bruce


#12

/me rolls his eyes. I’ve been doing this sort of programming for decades, in too many different GUI and real-time systems.

Never, ever block on the GUI update thread. Don’t spin, don’t wait, and if anything takes any serious amount of computation, you should defer that computation to a worker thread if at all possible. Even locks should be avoided!

This is true of every sort of real-time thread, and it’s even more true for threads that directly feed your audio output or do animation.

As for the jerkiness and slowness of your updating - I think all of us here suspect strongly that it’s an issue in your code because you haven’t shown any benchmarks and the rest of us have had excellent experiences with Juce’s smoothness and performance. And it’s open-source - if have a way to speed up the code, you could just show us.

As tediously usual, I go to an example from my current codebase. My time counter (which displays milliseconds) was originally a jerky thing that consumed very roughly a couple % of my CPU all on its ownsome - but when I looked at my code I realized that there was a lock contention with a worker thread. Once I rejiggered the code to get rid of that, the CPU usage fell to “unmeasurable” and it appears to be smooth down to the millisecond - of course, that’s impossible with my monitor, but it’s interesting to me that there’s a visible difference between a 10ms and a 1ms recalculation rate.

Once I got that smooth, I’d sometimes find that I’d add a new feature which “worked” but the counter would become jerky again. This always turned out to be some thread difficulty in my own code that I was able to fix.

And it is NOT Juce’s fault that threads are tricky! Juce has a perfectly regular thread model that’s as powerful as you need and seems to work really well. Concurrent programming is intrinsically hard…

tl; dr: don’t block real-time threads under any circumstances.


#13

+1 to that, imagine a listbox with 100,000+ songs and clicking to sort by the Title column on the message thread, on a handheld, while new items are being added to the list (in sorted order of course).


#14

[quote=“TomSwirly”]Concurrent programming is intrinsically hard…[/quote]

I think you meant

[size=200]Concurrent programming is intrinsically hard![/size]

This is worth repeating several times. When building a concurrent system, there is really no margin for error. Crap that you can get away with in a normal program, like being a bit sloppy with idioms, using the wrong data structure, etc… will bite you in your virtual ass in a concurrent program. Every line of code, every action, every thought, in a threaded app must be carefully scrutinized, over-analyzed, and documented.

The penalty for being lax, is to end up with a threaded program that is difficult or impossible to debug, contains numerous errors, and lays in wait like a ticking time bomb to go off in a user’s face with non-functionality.


#15

OK I am curious here. How many of you on this thread have produced a retail program that is in existence and making money, let’s say over a 100k a year. How many of these were written in Juce? Just curious. It’s easy to be caught up in academics. Hey would you rather have the profits from Linux or Windows?

I didn’t want to get is a pissing war but apparently you do. I simply asked the question on how to do a little routine I’ve done in every platform so far.

[color=#008000]A simple answer like this is not possible in Juce, but here is how it should be done in Juce. That is the response, I was hoping for.[/color]

There are those of us who do this for a living and believe it or not, I will be pleased if there many of you are doing the same writing retail apps. Also, what is the largest, popular, etc. app today that has been written entirely in Juce. I really need to know.

BTW, I know that Jules and many of you know way more about C++, multi-threaded code, etc. than I ever would want to. So I am not trying to say I do.

Here is an example of what I continually run into:
Imagine a juce program that requires every member function to be accessed through functions like the Point class does. Now Jules acknowledged this should probably be changed, so don’t flip out. I have two very large apps that probably have over 1000 places where a point is acccessed by it’s member variable directly. All platforms and frameworks do this except Juce. So I have to rewrite all these places to accommodate a “safe” Point class. Of, course I’ll just change the Juce code to be the way all other frameworks do it, to save me the time. There is no way a member function is needed, because a Point has no range/limits, that direct access could break. Do you get my point, no pun intended.

Now that the “experts” have ganged up let me tell you how I came to Juce. I have written my own cross-platform framework that I have used for the past 20 years. I got tired of rewriting the darn thing every time Apple released a new version of it’s OS. So I first looked at wxWidgets. It’s much easier to program with, especially the GUI, and is FREE. But it does not have Audio and I wanted Audio, hosting, etc and didn’t want to write another audio engine. I then took a quick look at Qt, liked it, many large corporations use it, but someone suggested I look at Juce because it was a one man operation and it might help him to grow with having more programs written in juce and the spreading the word and about the framework. Also I was told the support was very good, and I agree. I took a small synth that I had 90% done with the VST sdk and tried to convert it to juce. It has taken me two months to get the thing to work in Juce. Yes a lot of this was the learning curve, but the VST sdk worked like a charm and took me two weeks on both MAC and PC. I chose to start with a small synth to see if Juce could handle a large app, and I am still not convinced. [color=#FF0000]Please convince me and let’s make this small group a bigger group.[/color]

AND Please enough of this, OK?


#16

Those are example of music software made with Juce still in existence and which have made over 100k a year

http://www.motu.com/products/software/BPM
http://www.motu.com/products/software/machfive

Happy now ?


#17

So your logic is:

  1. You once wrote an app that used this awful mouse-button polling technique
  2. That app made you plenty of money
  3. Therefore: the mouse-button-polling trick = making a lot of money.

I think we’re all well-informed about your ability to sell software and make money (god knows you’ve mentioned it most of your posts!) But this thread is about whether you should run a modal loop, polling for the mouse-button state. The answer is “No you shouldn’t, for fuck’s sake”.

But despite all our strident efforts, you still seem to think we’re all amateurs who haven’t a clue what we’re talking about. Fine. I’m going to give up trying, and give you what you asked for:

[code]void mouseDown (const MouseEvent& e)
{
// do some mouse-down stuff

while (ModifierKeys::getCurrentModifiersRealtime().isLeftButtonDown())
{
    MessageManager::getInstance()->runDispatchLoopUntil (20);

    const Point<int> mousePos (getMouseXYRelative());

    // Put your hacky mouse-drag code here, bearing in mind that any of the objects on your call stack
    // may have been deleted, and that you have no idea whether this function is now being called
    // recursively inside multiple mouseDown() callbacks. Oh, and the app may have quit at this point. Good luck.
}        

}[/code]

Yes, you can do that in juce, so go ahead. You’ll probably never see any bugs in code written like this - it’s your users who will trigger all the nasty edge-cases, and will report bugs that are un-reproduceable because they’ll depend on some event or timer that happens to be triggered while the mouse is held down, in some incredibly rare way. Enjoy.

(And BTW I did change the Point class to expose the x and y members. A few weeks ago).


#18

Sorry that you are getting my point. I appreciate you providing the code (I could have made the direct Windows call to get the button state) but that was not my goal.

[color=#00BF00]1. You once wrote an app that used this awful mouse-button polling technique
2. That app made you plenty of money
3. Therefore: the mouse-button-polling trick = making a lot of money.[/color]

This is not what I am saying and I’ll try one more time. Large apps require different capabilities than plugins, home stuff, etc… Apps with 100,000 lines or more have different requirements than 20k plugins. To put it simple, time = money and the easier it is to get your code working safely within reason, the sooner it ships, the sooner you make money. time = money.This is my point! In the academic world this does not apply but In the real world it does.

Here is a better example: (why we’re filling the same area is not the point here)

[code]void Component::mouseDown( MouseEvent &e )
{
// Fill a large complex area with the color red and this may take sometime.


if ( isMouseIsDown() ) //What is wrong with this type of coding? Being able to call isMouseDown makes very readable and debuggable code
// Fill the same area with green


}[/code]

Can we avoid cursing when answering. It does nothing to help the situation.


#19

Yes, lets all write dodgy code in the pursuit of financial gain.

Disregard coding standards, acquire currency.


#20

It doesn’t make debuggable code. It makes code that doesn’t appear to have bugs, but will cause problems.

The problem is, every desktop type OS moved to an event based architecture. Juce didn’t invent this - it’s just a good citizen in this environment, as you have to be.

These OS’s expect you to service the event loop regularly, so it becomes the most effective thing to start all your main thread tasks with that mechanism, using timers, or callbacks, or idle time, or events etc.If you have tasks to do that don’t fit with that scheme, and you insist on blocking, you need to use threads. That’s just the way it is.

In your test case, you should change the background color and mark the component as needing a redraw. That component, and anything, say, in front of it, will be redrawn together, efficiently. You will then need to re-test your control

But - to directly answer your question. That code, on iOS, can cause your app to be quit. Failing to service the event loop makes the OS think your app is dead, as opposed to just brain dead, and it will be shut down. So if you take too long to draw, or it takes too long on one users iPad, because of something else, it will shut down. You will not be able to debug that, no.

Happy?

Bruce