wjakob / nanogui

Minimalistic GUI library for OpenGL
Other
4.66k stars 608 forks source link

Modifying layouts dynamically #163

Closed totalgee closed 8 years ago

totalgee commented 8 years ago

Hi there, I'm using the Cinder Block version of NanoGUI, but my question is one about your underlying library. Is there any trick to modifying the GUI dynamically, for example, adding/removing things from a layout?

I have a Button that, when pressed, is supposed to toggle on and off certain items in the layout. Hiding them (using setVisible()) works fine, but they still appear in the layout where they were, like a "blank space". I'd like the layout to readjust to their removal and reappearance.

I tried something like this:

        // In my GUI creation method:
        // ...
        auto b = new Button(popup, "Toggle options");
        b->setCallback([this] () {
            bool wasVisible = this->optionsWidget->visible();
            this->optionsWidget->setVisible(!wasVisible);
            if (wasVisible) {
                this->window->removeChild(this->optionsWidget);
            }
            else {
                this->window->addChild(this->optionsWidget);
            }
            performLayout(getContext());
        });
totalgee commented 8 years ago

Just answering myself... I see you added a check for visibility in the layout code (in b290cad). So, is that the "correct way" to add/remove things dynamically -- just use visibility? So I shouldn't try adding/removing children dynamically -- because it tends to crash in weird places, like memory corruption...

If that's indeed the right way, then I'll have to update/sync the Cinder Block to a more recent version of your library. Thanks.

totalgee commented 8 years ago

Fixed this in the Cinder Block with Hurleyworks/NanoguiBlock#6.

wjakob commented 8 years ago

Hi, you should be able to simply remove widgets. Changing visibility of course works but is a bit hacky since the widgets are still listed as children. Removing a widget changes the reference count, which can cause a widget to be deallocated. If you want to reuse a widget, you have to guard it with a ref<..> reference. See the nanogui code for details.

Wenzel

totalgee commented 7 years ago

Okay, that makes total sense. It was crashing a bit randomly, just like a memory corruption bug (presumably because the widget had been deleted). I hadn't seen any NanoGUI example using ref<> (other than for the main window). I'll give it another go, holding my detached widget pointers as refs, and I'm sure it'll work fine now. Thanks, Glen.

totalgee commented 7 years ago

Just to follow up...I tried it, and indeed it works fine (no crashes) when using ref<> to hold any pointers that are removed from the hierarchy. Thanks again.

(On a related note: it would be nice to have a Widget::insertChild() method, that specifies where to insert a child (before a given index, or before an existing sibling pointer), not just addChild() that always does push_back().)

totalgee commented 7 years ago

Ah, once again I see this is because the Cinder Block I'm using is synchronized with a year-old version of NanoGUI...sigh. I see you've since added Widget::addChild(int index, Widget *widget). So, never mind... (-;

wjakob commented 7 years ago

:)