Thanks for your responses.
First question: yes, that sounds like a good idea. I got another idea too: split the value of attributes into subvalues: base, bought, bonus. Only "bought" is a spinbutton, the others are regular labels. If the user buys ST, it increases the "bought" subvalue of ST and the "bonus" subvalue of HP. In this system, the values of the interactive widgets don't have to be changed programmatically. And also, the accounting of CP becomes easier. Cost has to be computed only for "bought" attribute points. That makes it both easier for the program to recalculate all values, and for the user to keep track of where his CP budget goes to. It also makes it easier to keep track of free (temporary) bonuses caused by spells, magic items etc. They al go to "bonus" and that way they are not included in calculating the CP cost.
Second question: yes I keep member variables pointing to widgets, so they are easily accessible from the callback functions. Those references will prevent the widgets from being destroyed. That will probably be the reason why they stay visible. This is easily fixed by setting the member variables to nullptr when the widget is no longer needed.
Also for this I have thought up a slightly different approach. The different screen objects stay alive in the screen manager object. I guess it is more efficient to just keep the windows intact, but only make the active screen visible and sensitive. That way it's easy to make a back button that keeps the choices the user made beforehand: just switch the visibility and sensitivity.
So it will work like this:
- the screen manager keeps the SFGUI and desktop objects, they are passed by reference to each screen object in the run () function. Don't want the compiler to copy them. So the run function has three parameters, all references: the SFML rendertarget, sfg::SFGUI and sfg::Desktop.
- each screen has its own sfg::Window object. The GUI layout (the widget hierarchy) is build up in the constructor of the screen object.
- if run () is called by the manager, make the current sfg::Window active: guiwindow -> SetState (sfg::Widget::State::NORMAL); and guiwindow -> Show (true);
- if "next" or "back" button is clicked, just make the current window inactive and invisible: guiwindow -> SetState (sfg::Widget::State::INSENSITIVE); and guiwindow -> Show (false);. Now the manager will call the run () of the appropriate next window. Will making the window INSENSITIVE also make all underlying widgets INSENSITIVE? Otherwise there may remain invisible hot zones on the screen, which is not what I want.
- if the wizard is left altogether, reset all widgets to default value, so the next time the user has a clean start.
Does this approach make sense?