StretchableLayoutManager stretches last element beyond its max size


#1

If you add items to a StretchableLayoutManager, it will stretch the last element beyond its maximum size. I find that in most cases, if all components have reached their maximum size, I would prefer there to be empty space beyond the last element. This can be achieved by commenting out the following:

void StretchableLayoutManager::layOutComponents (Component** const components,
                                                 int numComponents,
                                                 int x, int y, int w, int h,
                                                 const bool vertically,
                                                 const bool resizeOtherDimension)
{
    setTotalSize (vertically ? h : w);
    int pos = vertically ? y : x;
    for (int i = 0; i < numComponents; ++i)
    {
        if (const ItemLayoutProperties* const layout = getInfoFor (i))
        {
            if (Component* const c = components[i])
            {
//                if (i == numComponents - 1)
//                {
//                    // if it's the last item, crop it to exactly fit the available space..
//                    if (resizeOtherDimension)
//                    {
//                        if (vertically)
//                            c->setBounds (x, pos, w, jmax (layout->currentSize, h - pos));
//                        else
//                            c->setBounds (pos, y, jmax (layout->currentSize, w - pos), h);
//                    }
//                    else
//                    {
//                        if (vertically)
//                            c->setBounds (c->getX(), pos, c->getWidth(), jmax (layout->currentSize, h - pos));
//                        else
//                            c->setBounds (pos, c->getY(), jmax (layout->currentSize, w - pos), c->getHeight());
//                    }
//                }
//                else
                {
                    if (resizeOtherDimension)
                    {
                        if (vertically)
                            c->setBounds (x, pos, w, layout->currentSize);
                        else
                            c->setBounds (pos, y, layout->currentSize, h);
                    }
                    else
                    {
                        if (vertically)
                            c->setBounds (c->getX(), pos, c->getWidth(), layout->currentSize);
                        else
                            c->setBounds (pos, c->getY(), layout->currentSize, c->getHeight());
                    }
                }
            }
            pos += layout->currentSize;
        }
    }
}

It would also be nice to have some control over the space inbetween the components, although I'm aware that this could be achieved with blank components.

Joe.


#2

Well that might work for you, but a change like that would of course break all the existing code that uses that class!

(TBH that's an old class that I rarely use nowadays, and I'm planning to replace it with something better, so I'm not planning to spend much time worrying about the details of its implementation at the moment)


#3

Fair enough, it's a preference thing really. I look forward to the 'something better'!


#4

Why not just pass just a empty component, as last object.


#5

Actually, the last element can get stretched past its maximum size even when other elements are not at their maximum. I made a GUI project using IntroJucer on v3.2.0. Here's my code:

main.cpp: I made the window resizable

        MainWindow (String name)  : DocumentWindow (name,
                                                    Colours::lightgrey,
                                                    DocumentWindow::allButtons)
        {
            setUsingNativeTitleBar (true);
            setResizable(true, false);     // Added this line, rest is Introjucer-generated
            setContentOwned (new MainContentComponent(), true);

            centreWithSize (getWidth(), getHeight());
            setVisible (true);
        }

MainComponent.h:

class MainContentComponent   : public Component
{
public:
    //==============================================================================
    MainContentComponent();
    ~MainContentComponent();

    void resized();

private:
    ScopedPointer<DocumentWindow>    m_window1;
    ScopedPointer<DocumentWindow>    m_window2;
    ScopedPointer<StretchableLayoutResizerBar>        m_bar;
    StretchableLayoutManager        m_manager;

    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

MainComponent.cpp

MainContentComponent::MainContentComponent()
{
    setSize (600, 400);
    
    m_window1 = new DocumentWindow("Doc 1", Colours::red, 0, false);
    m_window2 = new DocumentWindow("Doc 2", Colours::green, 0, false);
    
    m_window1->setBounds(0, 0, 290, getHeight());
    addAndMakeVisible(m_window1);

    m_window2->setBounds(310, 0, 290, getHeight());
    addAndMakeVisible(m_window2);
    
    m_bar = new StretchableLayoutResizerBar(&m_manager, 1, true);
    m_bar->setBounds(290, 0, 20, getHeight());
    addAndMakeVisible(m_bar);
    
    m_manager.setItemLayout(0, 100, 5000, 290);
    m_manager.setItemLayout(1, 20, 20, 20);
    m_manager.setItemLayout(2, 100, 300, 290);
}

MainContentComponent::~MainContentComponent()
{
}

void MainContentComponent::resized()
{
    Component* comps[] = {m_window1, m_bar, m_window2};
    m_manager.layOutComponents(comps, 3, 0, 0, getWidth(), getHeight(), false, true);
}

The first embedded window has essentially no limit on its size, while the second is limited to a max of 300. I run the app, widen the main window, and both embedded windows get wider when only the first should. Then I drag the divider bar and it snaps to the right, where it should have been.

-Marc