Size of GUI component and viewport use with relative widths?

Well, I think I got somewhere… this would be the modified MainComponent.cpp (in respect to the gist code):

#include "MainComponent.h"

//==============================================================================
MainContentComponent::MainContentComponent()
{
    setSize (600, 400);
    addAndMakeVisible(myGSliders);
    addAndMakeVisible(myViewport);
    myViewport.setViewedComponent(&myGSliders, false);
    resized();
}

MainContentComponent::~MainContentComponent()
{
}

void MainContentComponent::paint (Graphics& g)
{
    //~ g.fillAll (Colour (0xff001F36));
    g.fillAll (Colour (0xff888888));

    g.setFont (Font (16.0f));
    g.setColour (Colours::white);
    g.drawText ("Hello World!", getLocalBounds(), Justification::centred, true);
}

void MainContentComponent::resized()
{
    // This is called when the MainContentComponent is resized.
    // If you add any child components, this is where you should
    // update their positions.
    myGSliders.setSize(getWidth()-0, myGSliders.getHeight()); // needs some space for v.scrollbar
    myViewport.setBounds(0, 0, proportionOfWidth(1.0f), 76); // but first size the view
    myGSliders.setSize(myViewport.getMaximumVisibleWidth(), myGSliders.getHeight()); // then resize component again, leaving space for scrollbar
}

The problem with the exception at exit is actually discussed in Access violation on closing Window when using Viewport - the problem is a double free; note that in MainComponent.h, the myViewport and myGSliders properties are declared as objects:

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

    void paint (Graphics&) override;
    void resized() override;

private:
    //==============================================================================
    MyGuiSliders myGSliders;
    Viewport myViewport;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

This crudely means that “C++” will take of their destruction, we do not have to manually delete them. However, the .setViewedComponent method has a deleteComponentWhenNoLongerNeeded argument which is by default true, and as such it will attempt to delete the viewed component at application exit, even if it has been already deleted. To prevent that, one must explicitly set false and then the unmap exception disappears.

As far as the sizing goes, first, I noticed that unless I call resized() in the constructor, something was weird with the scrollbars at very first display (i.e. I got horizontal instead of vertical scrollbar); then after a window resize, this is corrected. (something similar is mentioned in How to Use a Viewport)

Then, in the resized() menthod, I have to change the sizes of both myGSliders and myViewport, and myGSliders needs to be resized twice. First, I do:

myGSliders.setSize(getWidth(), myGSliders.getHeight());

In principle, I just need to set the width of myGSliders, not its height - however, there is no SetWidth method of JUCE Component, so I must do a .setSize using getWidth(), which would get the size of the parent (the window), and setting the height to the current height of myGSliders so it doesn’t change.

With the myGSliders sized, I can size the Viewport:

myViewport.setBounds(0, 0, proportionOfWidth(1.0f), 76);

… noting that instead of using .setBoundsRelative, which forces me to use relative percentages for all parameters, I use .setBounds which forces me to use pixels - however, there is a proportionOfWidth function which accepts a float/percent, and returns pixels (In respect to parent width, I guess).

Since now the total size of the viewport is set, we can now use the .getMaximumVisibleWidth method to find out (implicitly) what is the width of the vertical scrollbar that needs to be taken into account - or rather, what is the remaining width of the viewport - and set the myGSliders width to it:

myGSliders.setSize(myViewport.getMaximumVisibleWidth(), myGSliders.getHeight());

Without this, myGSliders is set at the width of the window, and since the vertical scrollbar is also shown (taking up a bit of the window), the engine thinks that a portion is missing, and insists on showing a horizontal scrollbar (while the vertical does not have its thumb element rendered).

And finally, the layout is as intended:

… and it scales with window resize (inner sliders too).