Drawablebutton renders weird

I am making a grid of buttons using svg images
The grids needs to be resizable

Buttons are rendering slightly trapezoidal.

    MyRelativeRectangle presetButtonSize = { juce::Rectangle<int>(700, 18 , 110, 34), 1200, 700 };
    
    MyRelativeRectangle presetButtonPadding = { juce::Rectangle<int>(700, 18 , 7, 8), 1200, 700 };
    
    MyRelativeRectangle presetSelectorBox = { juce::Rectangle<int>(701, 71 , 482, 178), 1200, 700 };
    
    MyRelativeRectangle presetSelectorFirst = { juce::Rectangle<int>(711, 82 , 482, 178), 1200, 700 };

in construtor:

    // Create the three SVG drawable instances
    normalImage = juce::Drawable::createFromImageData(BinaryData::btn_preset_normal_svg, BinaryData::btn_preset_normal_svgSize);
    hoverImage = juce::Drawable::createFromImageData(BinaryData::btn_preset_hover_svg, BinaryData::btn_preset_hover_svgSize);
    clickImage = juce::Drawable::createFromImageData(BinaryData::btn_preset_active_svg, BinaryData::btn_preset_active_svgSize);

         // Create the buttons and add them to the array
    for (int i = 0; i < 16; ++i)
    {
        std::unique_ptr<juce::DrawableButton> button = std::make_unique<juce::DrawableButton>("Button " + juce::String(i + 1), DrawableButton::ButtonStyle::ImageStretched);
        button->setImages(normalImage.get(), hoverImage.get(), clickImage.get(), nullptr, nullptr, nullptr);
        presetSelectionButtons.push_back(std::move(button));
        addAndMakeVisible(presetSelectionButtons.back().get());
        presetSelectionButtons.back()->addListener(this);
    }

in resized()

DBG("Get Width : " << getWidth());
    
    float actualButtonWidth = presetButtonSize.relativeRectangle.getWidth() * getWidth();
    float actualButtonHeight = actualButtonWidth * ((presetButtonSize.relativeRectangle.getHeight() * getHeight())/(presetButtonSize.relativeRectangle.getWidth() * getWidth()));
    DBG("Actual Button Width : " << actualButtonWidth);
    float actualButtonPaddingX = presetButtonPadding.relativeRectangle.getWidth() * getWidth();
    float actualButtonPaddingY = presetButtonPadding.relativeRectangle.getHeight() * getHeight();


    float actualBoxWidth = presetSelectorBox.relativeRectangle.getWidth() * getWidth();
    
    float actualx = presetSelectorFirst.relativeRectangle.getX() * getWidth();
    float actualy = presetSelectorFirst.relativeRectangle.getY() * getHeight();

    // Position the buttons within the component
    int buttonWidth = round(actualButtonWidth);
    int buttonHeight = round(actualButtonHeight);
    
    int spacingX = round(actualButtonPaddingX);
    int spacingY = round(actualButtonPaddingY);
    
    int boxWidth = round(actualBoxWidth);
    
    int x = actualx;
    int y = actualy;
    int count = 0;
    int columns = 4;
    
    DBG("buttonWidth  :" << buttonWidth);
    DBG("buttonHeight :" << buttonHeight);
    for (const auto& buttonPtr : presetSelectionButtons)
    {
        juce::DrawableButton* button = buttonPtr.get();

        button->setBounds(x + ((spacingX+buttonWidth) * (count%columns)),
                          y+ (buttonHeight+spacingY)*(count/columns), buttonWidth, buttonHeight);


        ++count;
    }

All 3 svg's have the same dimenions

I captured the image you posted, and drew some rectangles around the buttons and the grid, and I do not see the trapezoidal distortion you describe. Although it does look like there is a drop shadow at the bottom…

optical illusion…
Likely caused by the gradients.

1 Like

Wild.
I don’t see the same illusion on the figma layout.

Can I make the gradients render some other way?

try the SVG in a web browser, if they looks good then the issue in the SVG handling of JUCE which do not support all opcodes among other things

I think one of the offenders is the hard black line that appears at the bottom, as if it is a drop shadow. I wonder where it is coming from?

Using an svg may not be the best way to go here. You could do all of what’s shown on the figma image with standard Graphics drawing calls.

I’m doing gradients in all my buttons and GUI widgets using ColourGradient.

This is pulled from my TextButton drawing code, so it might not make total sense:

            ColourGradient cg;
            auto topColour = button.findColour(TextButton::buttonOnColourId);
            auto botColour = topColour.darker(0.7f);
            
            // shouldDrawButtonAsHighlighted = mouse over
            // shouldDrawButtonAsDown = mouse is holding it down
            // when mouse is down, both will be true
            // so, mouse over contrasts it a little, while mouse down contrasts it more
            if (shouldDrawButtonAsDown || shouldDrawButtonAsHighlighted)
            {
                // if we get here as a result of a momentary being held down
                // do NOT contrast the on Colour
                if (button.getClickingTogglesState())
                {
                    topColour = topColour.contrasting (shouldDrawButtonAsDown ? ad->buttonContrastDown : ad->buttonContrastOver);
                    botColour = botColour.contrasting (shouldDrawButtonAsDown ? ad->buttonContrastDown : ad->buttonContrastOver);
                }
            }
            auto cgBounds = boundsFull;           // start with the full bounds
            cgBounds.reduce(0.0f, 1.25f);         // squish by 1.25f on top/bot
            cg = ColourGradient::vertical (topColour, botColour, cgBounds);
            
            cg.addColour(0.25, topColour);  // add another point of topColour to make it brighter on top

            g.setGradientFill(cg);
            g.fillRoundedRectangle (boundsInset, cornerSize); // this purposely uses the inset bounds

outlines and hilighting is added on top of this later…

Classic case of Metamorphopsia, and I might add, delightfully discovered. 1: I applaud your SVG grid, and 2: all you have to do is add funk…

Thank our billion-year old scallop ancestors, lol, for their desire to not be eaten by cuttlefish, hehe …

1 Like

is it plausible to swap in a 3rd party rendering library?

Is there documentation on which SVG opcodes are not supported in JUCE?

a jassert when hitting unsupported SVG code would be nice…

Is there a reason why you prefer svg over juce::ColourGradient?

Designer delivered svgs and went on vacation!

Also I’m not sure I would recreate using juce::ColourGradient

Some people use inkscape to resave to simplify the SVG FWIW

1 Like

If I open in InkScape and then save, it will already be simplified?

I’m not sure if this svg is rescaled in that way you implemented this. Also you need to prove this on all supported systems and for hiDPI the implementation could be different on Mac or Windows. If you recreate this with juce gradient you can be sure everything is pixel perfect. Svg is not good enough implemented in juce. My opinion.