I’m working on creating a dynamic layout for my plugin with flexboxes, but it’s not behaving the way I would expect based on HTML flexboxes.
I don’t want any of my components to grow or shrink. I am only interested in juce::FlexBox figuring out the layout for me. The components I’m adding to flexboxes are already sized. However, unless I provide explicit measurements for each flex item, they will be 0 x 0. Using the juce::FlexItem::autoValue like so seems to have no effect:
box.items.add(juce::FlexItem(component).withFlex(0, 0, juce::FlexItem::autoValue));
Instead, I have to do the following:
box.items.add(juce::FlexItem(component).withHeight(component.getHeight()).withWidth(component.getWidth()).withFlex(0, 0, juce::FlexItem::autoValue));
This is just a simple example I’ve been working on to understand juce::FlexBox (code below):
- Main box (column)
- Slider box (row, wraps)
- Attack slider
- Decay slider
- Sustain slider
- Release slider
- Match input amplitude checkbox
- Slider box (row, wraps)
I’ve tested the Slider box on its own, and it works exactly as expected since each of its items are manually sized like the second code snippet. Once I nest the Slider box into another flexbox, then things start behaving in ways I don’t understand. I can’t provide an exact width or height of the Slider box because I don’t know how many rows or columns the items will take up. I could calculate that, but the whole point of using a flexbox in my case is to have it figure that out for me. This is what the below code ends up looking like:
I believe that since I haven’t provided explicit measurements the Slider box is assigned a size of 0 x 0 and that is why the mock checkbox is positioned at 0, 0. The mock checkbox also seems to be growing and shrinking, even though I have specified otherwise.
Is it possible to use juce::FlexItem::autoValue to just have automatically laid out flexboxes?
This is a minimal example of the expected/desired behavior in HTML:
<!DOCTYPE html>
<html>
<head>
<style>
html,
body {
padding: 0;
margin: 0;
height: 100%;
}
.divider {
width: 100%;
height: 2px;
background-color: black;
}
.sliders {
display: flex;
flex-wrap: wrap;
}
.plugin {
display: flex;
flex-direction: column;
}
.slider {
display: flex;
align-items: center;
justify-content: center;
color: white;
height: 150px;
width: 150px;
margin: 12px;
border-radius: 50%;
background-color: gray;
}
</style>
</head>
<body>
<div class="plugin">
<div class="sliders">
<div class="slider">Attack</div>
<div class="slider">Decay</div>
<div class="slider">Sustain</div>
<div class="slider">Release</div>
</div>
<div class="divider"></div>
<div class="slider">Match input amplitude</div>
</div>
</body>
</html>
To temporarily replace the sliders/checkboxes while I figure this out, I’ve created this square component:
#pragma once
#include "JuceHeader.hpp"
class Square : public juce::Component {
public:
Square(juce::Colour const &color) : m_color(color) { setSize(150, 150); }
void paint(juce::Graphics &g) override {
g.setColour(m_color);
g.drawRoundedRectangle(getLocalBounds().reduced(10).toFloat(), 6, 2);
}
private:
juce::Colour m_color;
};
And in my plugin editor, I use it as such:
#pragma once
#include "PluginProcessor.hpp"
#include "components/Square.hpp"
class PseudominEditor : public juce::AudioProcessorEditor {
public:
PseudominEditor(juce::AudioProcessor &processor);
~PseudominEditor() override;
void paint(juce::Graphics &) override;
void resized() override;
private:
Square m_attack = {juce::Colours::red};
Square m_decay = {juce::Colours::blue};
Square m_sustain = {juce::Colours::aqua};
Square m_release = {juce::Colours::orange};
Square m_matchInputAmplitude = {juce::Colours::purple};
juce::FlexBox m_mainBox;
juce::FlexBox m_slidersBox;
};
#include "PluginEditor.hpp"
#include "components/styles/Colors.hpp"
void addFlexItem(juce::FlexBox &box, juce::Component &component) {
box.items.add(juce::FlexItem(component)
.withMinWidth(component.getWidth())
.withMinHeight(component.getHeight()));
}
PseudominEditor::PseudominEditor(juce::AudioProcessor &processor,
pseudomin::PluginState &state)
: AudioProcessorEditor(processor), m_state(state) {
setSize(700, 250);
setResizable(true, true);
addAndMakeVisible(m_attack);
addAndMakeVisible(m_decay);
addAndMakeVisible(m_sustain);
addAndMakeVisible(m_release);
addAndMakeVisible(m_matchInputAmplitude);
m_slidersBox.flexDirection = juce::FlexBox::Direction::row;
m_slidersBox.flexWrap = juce::FlexBox::Wrap::wrap;
m_slidersBox.alignContent = juce::FlexBox::AlignContent::flexStart;
addFlexItem(m_slidersBox, m_attack);
addFlexItem(m_slidersBox, m_decay);
addFlexItem(m_slidersBox, m_sustain);
addFlexItem(m_slidersBox, m_release);
auto sliderHeight = m_attack.getHeight();
auto sliderWidth = m_attack.getWidth();
m_mainBox.flexDirection = juce::FlexBox::Direction::column;
m_mainBox.items.add(
juce::FlexItem(m_slidersBox).withFlex(0, 0, juce::FlexItem::autoValue));
addFlexItem(m_mainBox, m_matchInputAmplitude);
m_mainBox.performLayout(getLocalBounds());
}
PseudominEditor::~PseudominEditor() {}
void PseudominEditor::paint(juce::Graphics &g) {
g.fillAll(pseudomin::colors::backgroundMain);
}
void PseudominEditor::resized() { m_mainBox.performLayout(getLocalBounds()); }

