Tool Tip Functionning - 1 Tooltip for X buttons

Started by r4gTime, 23 October 2020, 14:43:04

r4gTime

Hello, I'd like to ask you a few questions about tooltips, because my game can't stop crashing since I implemented these.

I have X buttons implemented automatically, and 1 childWindow that I want to appear as a tooltip. But of course for each button I want to update the informations in the childwindow.

So I created a childwindow named "child_game_city_construction_tooltip".

Then I put it as a tooltip in my buttons when I create them :
Code (cpp) Select
...
button->setToolTip(xgui.get<tgui::ChildWindow>("child_game_city_construction_tooltip"));
...


But first problem : If I put my childwindow on setVisible(false), the tooltip nevers shows up. If I put it on true, then the childwindow becomes visible outside its "tooltip mission", until I go on a button that uses it.

Then, I want to update its information :
Code (cpp) Select
if(signalName == "MouseEntered") {
...
            // MAJ ToolTip
            if(s.find("construct_bati") != std::string::npos) {
                xgui.get<tgui::ChildWindow>("child_game_city_construction_tooltip")->setTitle(game.GetBatiFromType(cb).nom);
            }
        }


This code works the first Time I enter a button. But then when I go on another button, it crashes.

It seems that a widget couldn't work as a tooltip for several buttons, or something like that ?

Thank you very much for your help !

texus

Some parts of the tool tip are automatically handled by TGUI and you shouldn't change them yourself:
- the position (what you pass to setPosition is added as an offset for the tool tip relative to your mouse, it isn't an absolute position like with normal widgets)
- the visibility (you should never have to call setVisible on a tooltip widget, TGUI will show and hide them automatically)
- the parent (i.e. don't call gui.add on the tooltip)

The crash originates from the fact that you have made the child window a part of xgui instead of letting the buttons handle the tool tip.
In order for widgets to show up on the screen, they need to be added to the gui (either directly or indirectly via some container widget). So when the button wants to show the tool tip, it adds it to the gui (which does practically nothing since you already did that). But when the tool tip gets hidden, the button removes the tool tip child window from the gui. So when you hover over the next button, `xgui.get<tgui::ChildWindow>("child_game_city_construction_tooltip")` will return a nullptr and the code crashes as you attempt to call setTitle on a nullptr.

The solution is to not add the child window to the gui (i.e. don't call xgui.add(childWindow) and instead store the child window pointer somewhere so that you can call `button->setToolTip(childWindow)` and `childWindow->setTitle(...)`. This solves both the crash and the wrong behavior where the child window is visible before you hover over a button.

Btw, when you get another crash, you should check the call stack in your IDE, it tells you where the crash happened. This information can save time in searching what went wrong.

r4gTime

Thank you very much for your reply.

I kinda feel this implementation is a bit tricky, since I'm using gui builder to design my gui, and then load it automatically with a xgui.loadfromfile, I would never guess I should store my tooltips outside xgui, even with debugging.
This would mean I shouldn't put it in the same file as my main gui ?
But maybe I didn't understand some concepts yet.

Thank you again texus :)



texus

The gui builder simply doesn't support tool tips yet.

QuoteThis would mean I shouldn't put it in the same file as my main gui ?
You could technically still store it in the main gui, but directly after calling xgui.loadWidgetsFromFile you would have to remove it again:
Code (cpp) Select
tgui::ChildWindow::Ptr toolTipChildWindow = xgui.get<tgui::ChildWindow>("child_game_city_construction_tooltip");
xgui.remove(toolTipChildWindow);
// Use the toolTipChildWindow variable directly when calling setToolTip and setTitle.


The loadWidgetsFromFile will always add all widgets to the parent (because otherwise there would be no way to access the widget after calling loadWidgetsFromFile), so if you use a second file then you can't put a ChildWindow widget in there either. The second file would have to contain the contents of the child window (e.g. just a label) and in your c++ code you would have to create the child window yourself, give it a title and size and call childWindow->loadWidgetsFromFile("tooltip_contents_form.txt").

If the contents of the child window doesn't change too much based on the the button you are on then you can use one of the above solutions, but otherwise you might want to create everything dynamically in c++. The gui builder was intended for static forms and even tool tips were designed to be static (one tool tip for each button instead of reusing the same child window). It is possible to reuse the same child window (with a hack such as changing the contents on the the MouseEntered signal), but what you are trying to do was never considered so there is no "correct" solution for it.