Extended Button Behavior Question


#1

Hi all,

I am trying to implement a special kind of button that triggers two commands:

  • One that’s triggered as soon as the button is down.
  • Another one that’s triggered when the button is up again.

I searched the documentation and the forums but couldn’t find how to achieve this behavior.

What did I miss?

The context of all this is a cue/play button that should start playing when pressed, do nothing more while the mouse button / key is held down and stop playing when released.

Thanks.


#2

You could override the stateChanged callback to see when it goes up/down…


#3

I just tried that. It kinda works.

I used ButtonListener::buttonStateChanged(Button*) and setTriggeredOnMouseDown(true).

The trouble with this is that I cannot determine the previous state of the button, just the current one.

What I’m looking for is some test that could tell me that the button just went from down to normal/over. (some kind of “buttonReleased” event)

Anyway, I also noticed something very weird, that looks like a bug:

When setTriggeredOnMouseDown is enabled on a Button instance, it seems to never lose the focus after having been clicked once.
In my application, its buttonStateChanged callback is called at every single click on any other component, from the Button::focusLost function.

I tried to simplify the bug and managed to reproduce it on a very simple application.

Here’s the code for the test component I used:

struct ButtonTestComponent : public Component, public ButtonListener
{
    ButtonTestComponent ()
    {
        button1 = new TextButton("triggeredOnMouseDOWN");
        button1->setTriggeredOnMouseDown(true);
        button2 = new TextButton("triggeredOnMouseUP  ");

        addAndMakeVisible(button1);
        addAndMakeVisible(button2);

        button1->addButtonListener(this);
        button2->addButtonListener(this);
    }

    virtual void resized ()
    {
        const int y = getHeight() / 2;
        button1->setBounds(0, 0, getWidth(), y);
        button2->setBounds(0, y, getWidth(), getHeight() - y);
    }

    static const String describeState (Button* button)
    {
        if (button->isDown())
            return "down";
        else if (button->isOver())
            return "over";
        else
            return "normal";
    }

    virtual void buttonStateChanged (Button* button)
    {
        String s;
        s << button->getName() << " -> " << describeState(button);
        Logger::outputDebugString(s);
    }

    virtual void buttonClicked (Button* button)
    {
        String s;
        s << button->getName() << " -> clicked";
        Logger::outputDebugString(s);
    }

    TextButton* button1;
    TextButton* button2;
};

The following image shows the mouse events used to reproduce the bug:

And this is what my program log contains after the two clicks on the buttons:

triggeredOnMouseDOWN -> over
triggeredOnMouseDOWN -> down
triggeredOnMouseDOWN -> clicked
triggeredOnMouseDOWN -> over
triggeredOnMouseDOWN -> normal
triggeredOnMouseUP   -> over
triggeredOnMouseDOWN -> down
triggeredOnMouseUP   -> down
triggeredOnMouseUP   -> over
triggeredOnMouseUP   -> clicked
triggeredOnMouseUP   -> normal

This is the last “triggeredOnMouseDOWN -> down” that really bothers me.

Is there any way to get rid of it ?

I’m using Juce 1.43 on windows XP, with Visual C++ 8.0.

Thanks.


#4

Wow. Good bug!

Try this tweak in Button::updateState(), it’s about line 230ish:

[code] const bool over = reallyContains (mx, my, true);
const bool down = isMouseButtonDownAnywhere();

    if ((down && (over || (triggerOnMouseDown && state == buttonDown))) || isKeyDown)
        state = buttonDown;
    else if (over)
        state = buttonOver;

[/code]


#5

Does the trick.

Thanks a bunch! This was driving me nuts :slight_smile:


#6

It was certainly a subtle one!


#7

Hi Jules,

Just a quick update on this bug:

I think the fix you gave contains a typo:

It should be:

Otherwise, (state == buttonDown) will always be false, and any triggeredOnMouseDown’ed button won’t stay down while the mouse is kept down and moved outside of the button.

I also noticed a strange interaction between keyboard shortcuts and mouse clicks on triggeredOnMouseDown’ed buttons:

=> Press keyboard shortcut

[ Button is down ]

=> Press mouse button on anything but the button

[ Button still down ]

=> Release keyboard shortcut

[ Button still down ]

=> Release mouse button

[ Button will remain down until hovered or next keyboard shortcut  ]

Do you know how to avoid this?

Thanks :slight_smile:


#8

Hi Jules,

Just a quick update on this bug:

I think the fix you gave contains a typo:

It should be:

Otherwise, (state == buttonDown) will always be false, and any triggeredOnMouseDown’ed button won’t stay down while the mouse is kept down and moved outside of the button.

I also noticed a strange interaction between keyboard shortcuts and mouse clicks on triggeredOnMouseDown’ed buttons:

=> Press keyboard shortcut

[ Button is down ]

=> Press mouse button on anything but the button

[ Button still down ]

=> Release keyboard shortcut

[ Button still down ]

=> Release mouse button

[ Button will remain down until hovered or next keyboard shortcut  ]

Do you know how to avoid this?

Thanks :slight_smile:


#9

Sorry, yes, you’re right about that typo, of course.

Not sure about how to avoid the other situation you mention, but how often do people click a button and press its shortcut key at the same time!?


#10

Hi again,

Sorry for the delay, I’ve been internet-deprived for quite some time :frowning:

The trouble with the situation I mention is not that I press the button shortcut key and click on the same button with the mouse. I agree that this is very unlikely to happen.

My problem is that I press (and maintain down) the button shortcut key, then click anywhere in the application window and release the shortcut key before the mouse button.

In my application, this happens when cueing a track (cue shorcut key maintained down) and moving a slider somewhere else, for instance. If I ever do this and inadvertently release the slider after the shortcut, I’m screwed, the button stays down.

Any thoughts?

Thanks for your patience :slight_smile:


#11

Ok, I see. The problem is that the button is checking for isMouseButtonDownAnywhere, rather than isMouseButtonDown.

Looking at that now, I can’t figure out why it’s done that way, but I’m sure there was a good reason! I think I will change it, and that should solve your problem, but will have to keep an eye out for other things going wrong!


#12

Thanks. Problem solved :slight_smile:


#13