How to make a Drawable shrink a bit when it's toggle state is "Down" in a drawable button?

Hi I am currently trying to create a Drawable Button with 4 times the same image (for the states Up, Over, Down and Disabled). But I would like to resize the image corresponding to the Down toggle state so that It gives the illusion of being pressed.

I tried to do it directly by applying an AffineTransform::scale() to the Drawable. But it doesn’t change anything. Probably because of the the buttons are set to be ButtonStyle::ImageFitted. Just to be sure I am not doing something stupid, here is the code I used. In the private section I initialize a unique pointer :

  1. std::unique_ptr < Drawable > instDown = Drawable::createFromImageData (BinaryData::instrumentDown_svg, BinaryData::instrumentDown_svgSize);

Then in the constructor I resize the image and initialize the drawable buttons doing :

  1. instDown.get()->setTransform( juce::AffineTransform::scale(10.f, 10.f, instDown.get()->getDrawableBounds().getCentreX(), instDown.get()->getDrawableBounds().getCentreX()));
  2. instDrawableButton.setImages(instUp.get(), instOver.get(), instDown.get(), instUp.get());

I thought of something else that would do the trick, which is to create a DrawableComposite and to resize my drawable inside the composite. But then I struggle to create a DrawableComposite. I don’t understand how to add a Drawable to a composite because in the documentation there is no such function as “AddDrawable” in DrawableComposite.

Also, could someone tell me how to add code in a forum topic ? Here I use blockquotes but I would like to know for the next time.

I’ll appreciate any help.
Romain.

Apologies for not being able to answer your main question.

But to add code to the forum, you put three backticks ``` before the code and three after the code.

For example, myFunction(new Value) appears as just text without the backticks. If we put backticks before and after, it appears as code; i.e. - myFunction(newValue).

1 Like

I haven’t actually tried this so not sure if it does what you’re looking for, but DrawableButton::setEdgeIndent() could be promising.

The issue with setEdgeIndent is that it shrinks every image of the DrawableButton, It’s not possible to only affect the “down” image.

I found a solution to the problem though. It’s probably not the cleanest way of doing this, but I made a ShrinkableDrawableButton that extends DrawableButton so that I could reduce the size of the rectangle in which the image is drawn only when the button is Down. The amount by which the drawable button shrinks is GS::Button_Pixel_Shrink_When_Down, which is an int variable. Here is the code :

 class ShrinkDrawableButton : public DrawableButton
{
public:
    ShrinkDrawableButton(const String& name, const DrawableButton::ButtonStyle buttonStyle) : DrawableButton(name, buttonStyle)
    {
        
    }
    
    Drawable* my_getCurrentImage() const noexcept
    {
        if (isDown())  return getDownImage();
        if (isOver())  return getOverImage();

        return getNormalImage();
    }
    
    void resized() override
    {
        Button::resized();
        auto my_currentImage = my_getCurrentImage();
        auto my_style = getStyle();
        if (my_currentImage != nullptr)
        {
            if (my_style != ImageRaw)
            {
                int transformFlags = 0;

                if (my_style == ImageStretched)
                {
                    transformFlags |= RectanglePlacement::stretchToFit;
                }
                else
                {
                    transformFlags |= RectanglePlacement::centred;

                    if (my_style == ImageOnButtonBackgroundOriginalSize)
                        transformFlags |= RectanglePlacement::doNotResize;
                }
                if (isDown())  // Here is the only modification from the original code.
                    my_currentImage->setTransformToFit (getImageBounds().reduced(GS::Button_Pixel_Shrink_When_Down), transformFlags);
                else
                    my_currentImage->setTransformToFit (getImageBounds(), transformFlags);

            }
        }
    }
};

If anyone knows how to do this using a LookAndFeel class, please share it here because I think it could be much cleaner code.

Would it work to just call setEdgeIndent() whenever the button state changes?

drawableButton.onClick = [this] { setEdgeIndent (drawableButton.isDown() ? 6 : 3); };

If so, you could add this functionality to your DrawableButton subclass using Button::Listener, so that you can still use onClick to perform whatever action the button triggers.

This would be a nice solution, but unfortunately it doesn’t work and I don’t understand why. When I print a message each time the button is clicked, it doesn’t print anything when I press the button down, but it prints the message 2 times when the button is released.

c_DB.onClick = [this] {
       DBG("Clicked");
       c_DB.setEdgeIndent (c_DB.getToggleState() ? 6 : 3);
};

That’s strange, I’m not sure why that would be happening, either. Does the button creation code still look like what you included in your first post?

Btw, regarding the code examples in your first post, when using a unique_ptr you don’t have to call .get() each time you want to access a member, you can just use the arrow operator ->. So in your first post, instead of doing things like instDown.get()->setTransform() you can just do instDown->setTransform()