Form Builder: Child Windows & Panels

Started by CombatWombat, 14 August 2013, 00:16:37

CombatWombat

Can I use the form builder and gui.loadWidgetsFromFile() to create child windows or populate panels?
If so, what is the syntax?  Is there any documentation for formbuilder?

Currently everything created and loaded this way is enabled and drawn by default. 
I am not sure how to create sub menus, option screens, etc.

Is my only option to load the objects, and then retrieve each by name (gui.getWidgets, etc) remove them from the GUI container, and add them to the proper panel/child window container?

texus

Form Builder is unable to create panels and child windows (I am currently rewriting the form builder from scratch in a more extendible way).

So you will have to edit the object files yourself. (code below is quickly written, it might contain small mistakes)
You can use the form builder to generate this:
Button: ""
{
    // ...
}

which you should then change in
ChildWindow: ""
{
    ConfigFile = "Black.conf"
    Size = (800, 600)

    Button: ""
    {
        // ...
    }
}


Other than the ConfigFile and Size, you can change more properties of the ChildWindow. I found a list in an old tutorial.


I hope to have the new form builder working at the end of the month so that you no longer need any workarounds, but I can't make any guarantees.

CombatWombat

Thanks.  I realized I could just call "loadWidgetsFromFile" from the container I want to populate, instead of from the instance of GUI.  Then I can just make a panelName.txt file for each menu.

As an aside: is "ContainerWidget" gone?  Merged with "Container"?  It still appears in the 0.6 documentation.

texus

QuoteI realized I could just call "loadWidgetsFromFile" from the container I want to populate, instead of from the instance of GUI.
I already forgot that I once added this possibility.

QuoteIt still appears in the 0.6 documentation.
It seems like the online docs haven't been updated yet. Will be fixed in a few minutes. Thanks for letting me know.

CombatWombat

Me again...

Is there a way to bind callbacks in the object file?
like:
bindCallback(tgui::Button::LeftMouseClicked)

You can set a callback ID in the object file, but it doesn't do anything without loading each UI object with a trigger like above in the C++ code.

texus

No.
The problem is that object files are old, they were introduced in v0.4 and since then they were only patched to keep working with the latest tgui version. When introducing the new callback system in v0.6, I couldn't immediate find a way to get callback working and eventually nothing was changed and binding callbacks still doesn't work.

I'm still not sure how to handle it.
For just binding the callback so that it is send to the parent widget (and eventually to the gui), I would have to make a check for every widget if the string is one of the possible triggers. And binding a callback to a function seems completely impossible.
Currenly the only way to solve this seems to be to let the form builder generate c++ code instead of object files, but that has its downsides too.


You don't have to go over every widget seperately, depending on the situation code like below is enough.

auto widgets = gui.getWidgets(); // replace gui with the container that contains the loaded widgets
for (auto& widget : widgets) {
    if (widget->getWidgetType() == tgui::Type_Button)
        widget->bindCallback(tgui::Button::LeftMouseClicked);
//  else if (widget->getWidgetType() == tgui::Type_xxx)
//      widget->bindCallback(tgui::xxx::yyy);
}


But if you really need a lot more code than what I have above then I might be able to quickly arrange something.
I could add callback so that you have to manually add 'Callback = LeftMousePressed' to the buttons in the object file. But then you still won't be able to bind functions. This change could take a few hours though.

CombatWombat

Your coded solution should work well enough.  I was struggling with casting the returned Widget::Ptr into specific types.  Didn't know to use "auto" like that.

As you said, I don't think adding function binding to the object files is practical.  Binding of the built in "callback triggers" would be a welcome future addition, though.

texus

QuoteI was struggling with casting the returned Widget::Ptr into specific types.
Any function declared on tgui::Widget can be called no matter the real type of the widget. You only need to upcast when you need specific functions like setText.

QuoteBinding of the built in "callback triggers" would be a welcome future addition, though.
I will add it to the todo list. I'll see when I have enough time to add something like this.

CombatWombat

QuoteAny function declared on tgui::Widget can be called no matter the real type of the widget. You only need to upcast when you need specific functions like setText.

That's what I was trying to do.  To use .additem from comboBox.

This didn't compile:
tgui::Combobox::Ptr comboPtr = dynamic_cast<tgui::Combobox::Ptr>(gui.get("A Combo Box"));
Where are the "Ptr" types declared?  Are they just typedefs for pointers of each widget type?

I also see now that I should check the type of widget before casting. 

I am still learning this C++ stuff and your answers have been helpful thus far.  Thank you.


texus

The Ptr's are indeed just typedefs in every widget.

But the smart pointer was written so that you wouldn't need to manually cast, it will work automatically.
Internally there will still be a cast, but you don't have to worry about it.

This will work:
tgui::Combobox::Ptr comboPtr = gui.get("A Combo Box");
comboPtr->addItem("test");


This will NOT work (as the get function only returns a tgui::Widget and there is no cast involved):
gui.get("A Combo Box")->addItem("test");

But you can still make it work on one line like this:
tgui::ComboBox::Ptr(gui.get("A Combo Box"))->addItem("test");