GlowButton


#1

I'm trying to design a button component that glows when you hit it, then gradually fades back to its inert colour.

The computer can also trigger this glow.

I'm going to have a lot of these objects on-screen, maybe 100, so I'm trying to figure out an efficient method of implementing it.

One possible use case scenario:  I give each of the 12 pitch classes its own colour, and arrange the 88 piano notes in a spiral that wraps around at the octave.

How could I go about doing this?

I'm thinking that it could be accomplished GL, passing in a texture for the inert button, and for the glowing button, and feeding in a colour and glow (float) uniform for each frame.

But I sense I may only be able to batch these into the same draw call if they all are children at the same component.

Which wouldn't be the end of the world, but it would be much nicer architecture if I can have different components containing these buttons. Maybe one draw-call per component would be fine.

Might there be some way of doing this without getting into GL? It would be nice to get a passable implementation for my prototype, and rewrite something optimal further down the line. Also as I'm new to Juce, I could easily get bogged down for several weeks with this, so I would much rather get something simple running to start with.


#2

So you just want an animated button? Take a look at the JUCE demo "Timers and Events" page. You would probably do somthing similar but have FlashingComponent inherit from some subclass of button. Either that or create a wrapper Component that holds the button and flashes when the button is clicked.


#3

Sorry, I should've mentioned that I want to be able to set the intensity per frame. An analogy would be a light bulb, where you can adjust the voltage.

It is because I'm going to use them as musical notes. If music plays from the MIDI file it will activate them depending on the volume of each note. If the user hits the note on the screen, it will play at full volume.

I'm planning to give the button a 'float glow;' property, and each frame do:

glow = max(glow*.99f, inputVoltage)

that would create a fading effect, and also give me the option of holding it at a particular brightness level.


#4

Do you want a button with an outer glow?  I did too.

 

The first thing to overcome is that you can't draw outside the bounds of the button.  Placing a small button graphic in the middle of a large region isn't ideal since it'll trigger mouse over events and respond to clicks while the user is in the "glow zone" before they reach the actual button.

My solution is to use a custom component that contains a button inside a border region.  You can paint the glow in the border and listen to the button with your main button listener.

This code is a quick test.  You'll probably want to refine the painting of the actual glow effect and as for performance... well, I guess it's time to suck it and see.  You could always group many buttons onto one custom component -- eg 10 buttons per component instead of the single button in the code below.  That way you can draw all the glows in one paint call per group and only paint the group if and when a value changes.

 

HTH.  Disclaimer -- I'm also a JUCE noob :)

 


class GlowButton : public Component
{
public:
    //-----------------------------------------------------------------------
    GlowButton( const String& buttonName, const String& toolTip = String::empty) :
      button( buttonName, toolTip ), borderSize(4), baseColour( Colours::white ), glow(0.0f)
    {
        addAndMakeVisible( &button );
    };
    //-----------------------------------------------------------------------
    virtual ~GlowButton(){};
    //-----------------------------------------------------------------------
    void addListener( Button::Listener * listener ) {
        button.addListener( listener );
    };
    //-----------------------------------------------------------------------
    TextButton * getButton() {
        return &button;
    };
    //-----------------------------------------------------------------------
    void setSize( int w, int h ) {
        button.setTopLeftPosition( borderSize, borderSize );
        button.setSize( w - borderSize * 2, h - borderSize * 2 );
        Component::setSize( w, h );
    };
    //-----------------------------------------------------------------------
    void setBorderSize( int pixels ) {
        borderSize = pixels;
        setSize( getWidth(), getHeight() );
    };
    //-----------------------------------------------------------------------
    void setBaseColour ( Colour & c ) {
        baseColour = c;
    };
    //-----------------------------------------------------------------------
    void setGlow( float g ) {
        glow = g;
        repaint();
    };
    //-----------------------------------------------------------------------
    float getGlow(){ return glow; };
    //-----------------------------------------------------------------------
    void paint( Graphics &g ) {
        baseColour = baseColour.withAlpha( glow );
        g.setColour( baseColour );
        g.fillRoundedRectangle(0,0,getWidth()-1,getHeight()-1,5);
    };
    //-----------------------------------------------------------------------
private:
    int borderSize;
    Colour baseColour;
    float glow;
    TextButton button;
};

#5

You can override Component::hitTest to define a custom hit region i.e. the interactive bit of the button.