Advanced UI show/hide

Hello,

I want my plugin to show hide some components in this way:

Let’s call a group of component that has to be shown/hidden by pressing a button “a window”.
I wanted to hide the window that was displayed previoulsy when pressing a button to display another window.
I also want the initial state to not display any of these windows.

Since I got to create my own custom_foleys_MagicPluginEditor because I wanted the resizing to act differently, I use also the custom_foleys_MagicPluginEditor.cpp I have created to manage this shown/hidden states.

void CustomMagicPluginEditor::setPresetVisible()
{
    processorState.getPropertyAsValue("Tenn:DisplaySettings").setValue(true);
}
void CustomMagicPluginEditor::setPresetUnvisible()
{
    processorState.getPropertyAsValue("Tenn:DisplaySettings").setValue(false);   
}
void CustomMagicPluginEditor::setInformationVisible()
{
    processorState.getPropertyAsValue("Tenn:Information").setValue(true);
}
void CustomMagicPluginEditor::setInformationUnvisible()
{
    processorState.getPropertyAsValue("Tenn:Information").setValue(false);  
}
void CustomMagicPluginEditor::setMidiLearnVisible()
{
    processorState.getPropertyAsValue("Tenn:MidiLearn").setValue(true);
}
void CustomMagicPluginEditor::setMidiLearnUnvisible()
{
    processorState.getPropertyAsValue("Tenn:MidiLearn").setValue(false);  
}
void CustomMagicPluginEditor::setMidiClearVisible()
{
    processorState.getPropertyAsValue("Tenn:MidiClear").setValue(true);
}
void CustomMagicPluginEditor::setMidiClearUnvisible()
{
    processorState.getPropertyAsValue("Tenn:MidiClear").setValue(false);   
}
void CustomMagicPluginEditor::setLfoMenuVisible()
{
    processorState.getPropertyAsValue("Tenn:LfoMenu").setValue(true);
}
void CustomMagicPluginEditor::setLfoMenuUnvisible()
{
    processorState.getPropertyAsValue("Tenn:LfoMenu").setValue(false);  
}

void CustomMagicPluginEditor::updateSize()
{
    const auto rootNode = builder->getGuiRootNode();

    int width = rootNode.getProperty(foleys::IDs::width, 600);
    int height = rootNode.getProperty(foleys::IDs::height, 400);

    bool resizable = builder->getStyleProperty(foleys::IDs::resizable, builder->getGuiRootNode());
    bool resizeCorner = builder->getStyleProperty(foleys::IDs::resizeCorner, builder->getGuiRootNode());

#if JUCE_IOS
        resizable = false;
        resizeCorner = false;
#endif

     if (resizable)
     {
         processorState.getLastEditorSize(width, height);

         auto maximalBounds = juce::Desktop::getInstance().getDisplays().getTotalBounds(true);
         int minWidth = rootNode.getProperty(foleys::IDs::minWidth, 10);
         int minHeight = rootNode.getProperty(foleys::IDs::minHeight, 10);
         int maxWidth = rootNode.getProperty(foleys::IDs::maxWidth, maximalBounds.getWidth());
         int maxHeight = rootNode.getProperty(foleys::IDs::maxHeight, maximalBounds.getHeight());
         setResizable(resizable, resizeCorner);
         setResizeLimits(minWidth, minHeight, maxWidth, maxHeight);
         getConstrainer()->setFixedAspectRatio(1.56880733945);
     }
     setSize(height * 1.56880733945, height);
 }

void CustomMagicPluginEditor::setConfigTree (const juce::ValueTree& gui)
{
    // Set default values
    auto rootNode = gui.getChildWithName (foleys::IDs::view);
    auto& undo = builder->getUndoManager();
    if (! rootNode.hasProperty (foleys::IDs::resizable)) rootNode.setProperty (foleys::IDs::resizable, true, &undo);
    if (! rootNode.hasProperty (foleys::IDs::resizeCorner)) rootNode.setProperty (foleys::IDs::resizeCorner, true, &undo);

    processorState.setGuiValueTree (gui);
    builder->createGUI (*this);
    updateSize();
   
}

foleys::MagicGUIBuilder& CustomMagicPluginEditor::getGUIBuilder()
{
    // This shouldn't be possible, since the builder instance is created if none was supplied...
    jassert (builder);

    return *builder;
}
void CustomMagicPluginEditor::paint (juce::Graphics& g)
{
    bool infoDisplayState = processorState.getPropertyAsValue("Tenn:Information").getValue();
    bool settingsDisplayState = processorState.getPropertyAsValue("Tenn:DisplaySettings").getValue();
    bool lfoMenuState = processorState.getPropertyAsValue("Tenn:LfoMenu").getValue();
    if (ff == true)
    {
        setPresetVisible();
        setPresetUnvisible();
        setInformationVisible();
        setInformationUnvisible();
        setLfoMenuVisible();
        setLfoMenuUnvisible();
        setMidiClearVisible();
        setMidiClearUnvisible();
        setMidiLearnUnvisible();
        setMidiLearnVisible();
        ff = false;
    }
    if (infoDisplayState == true && prevInfoDisplayState == false)
    {
        setPresetUnvisible();
        setMidiLearnUnvisible();
        setLfoMenuUnvisible();
    }
    if (settingsDisplayState == true && prevSettingsDisplayState == false)
    {
        setInformationUnvisible();
        setMidiLearnUnvisible();
        setLfoMenuUnvisible();
        if (juce::JUCEApplicationBase::isStandaloneApp() == true)
        {
            setMidiClearVisible();
        }
    }
    if (lfoMenuState == true && prevLfoMenuState == false)
    {
        setLfoMenuVisible();
        setInformationUnvisible();
        setMidiLearnUnvisible();
        setMidiLearnVisible();
        setPresetUnvisible();
    }
    if (infoDisplayState == false && prevInfoDisplayState == true && juce::JUCEApplicationBase::isStandaloneApp() == true)
    {
        setMidiLearnVisible();

    }
    if (settingsDisplayState == false && prevSettingsDisplayState == true && juce::JUCEApplicationBase::isStandaloneApp() == true)
    {
        setMidiLearnVisible();
        setMidiClearUnvisible();
    }
    if (lfoMenuState == false &&  prevLfoMenuState == true && juce::JUCEApplicationBase::isStandaloneApp() == true)
    {
        setMidiLearnVisible();
    }
    prevInfoDisplayState = infoDisplayState;
    prevSettingsDisplayState = settingsDisplayState;
    prevLfoMenuState = lfoMenuState;
    g.fillAll (juce::Colours::black);
}

It works but I wondered if it is safe or not and if it exists a much simpler way to acheivce it.

Thanks for your answers :slight_smile:

This is unfortunately not a good way to do it. The paint() method should not alter the state at all.
A problem is, that the changes of visibility will trigger a repaint, which might be a reason for the slow loading times you are observing in the other thread.

It is much easier to connect the ToggleButton to a property and select this property in the View’s visibility property.
It might be necessary to recreate the GUI manually (Menu File->Refresh) while setting this up. But when it is loaded it should work out of the box.

I experimented with fixed aspect ratio but I didn’t really have success. Does this work for you? I can see you force the initial size, but does it really prevent the user from resizing to a different aspect ratio? If so, I can happily add this property.

The toggle button->property approach is working too but what I don’t understand is how to not display the view having a visibility property on plugin init and how to hide a view as soon as I use a toggle button to display another.

So basically the behavior should be: I open the plugin, it displays only the basic controls, by clicking on a toggle button I can open another view on top of it showing other controllers, then I can use the same toggle button to hide this view or another toggle button to hide the view and display another one. Does it seem doable by just using the toggle button properties link to view visibility property?

And yes the constrained ratio on resizing works :slight_smile: the components move a bit like in a jelly cake when resizing but not too bad.