gui2/tstacked_widget: Add single layer mode and layer switching

This effectively allows us to use stacked_widget as part of the
implementation of tabbed dialogs like Preferences.

The most important thing here is making sure individual layers are
selected so that they can receive events. This works fine in testing,
and it's much easier for me to take an existing widget and adapt it for
my purposes rather than build a new one from scratch.

Another important thing is not selecting the same layer twice. This
apparently deselects it instead.

Finally, existing applications like the titlescreen are unaffected.
This commit is contained in:
Ignacio R. Morelle 2015-07-10 18:13:25 -03:00
parent a9d0146656
commit 4854413f75
3 changed files with 63 additions and 3 deletions

View file

@ -11,6 +11,10 @@ Version 1.13.1+dev:
* New standing animation for the Dwarvish Runesmith
* Music and sound effects:
* New dwarf hit and die sounds.
* User interface:
* GUI2:
* stacked_widget can optionally display a single layer at a time. This
may be used to implement dialogs with multiple pages or tabs.
* Miscellaneous and bug fixes:
* Fixed unbound memory read in internal time formatting code with
specially-crafted input.

View file

@ -35,6 +35,7 @@ tstacked_widget::tstacked_widget()
: tcontainer_(1)
, generator_(
tgenerator_::build(false, false, tgenerator_::independent, false))
, selected_layer_(-1)
{
}
@ -103,9 +104,7 @@ tstacked_widget::finalize(std::vector<tbuilder_grid_const_ptr> widget_builder)
}
swap_grid(NULL, &grid(), generator_, "_content_grid");
for(size_t i = 0; i < generator_->get_item_count(); ++i) {
generator_->select_item(i, true);
}
select_layer(-1);
}
const std::string& tstacked_widget::get_control_type() const
@ -119,4 +118,34 @@ void tstacked_widget::set_self_active(const bool /*active*/)
/* DO NOTHING */
}
void tstacked_widget::select_layer_internal(const unsigned int layer, const bool select) const
{
// Selecting a layer that's already selected appears to actually deselect
// it, so make sure to only perform changes we want.
if(generator_->is_selected(layer) != select) {
generator_->select_item(layer, select);
}
}
void tstacked_widget::select_layer(const int layer)
{
const unsigned int num_layers = generator_->get_item_count();
selected_layer_ = std::max(-1, std::min<int>(layer, num_layers - 1));
for(unsigned int i = 0; i < num_layers; ++i) {
if(selected_layer_ >= 0) {
const bool selected = i == static_cast<unsigned int>(selected_layer_);
// Select current layer, leave the rest unselected.
select_layer_internal(i, selected);
generator_->item(i).set_visible(selected
? twidget::tvisible::visible
: twidget::tvisible::hidden);
} else {
// Select everything.
select_layer_internal(i, true);
generator_->item(i).set_visible(twidget::tvisible::visible);
}
}
}
} // namespace gui2

View file

@ -46,6 +46,23 @@ public:
/** See @ref twidget::layout_children. */
virtual void layout_children() OVERRIDE;
/**
* Gets the current visible layer number.
*
* The current layer number will be -1 if all layers are currently visible.
* In this case, only the topmost (highest-numbered) layer will receive
* events.
*/
int current_layer() const { return selected_layer_; }
/**
* Selects and displays a particular layer.
*
* If layer -1 is selected, all layers will be displayed but only the
* topmost (highest-numbered) layer will receive events.
*/
void select_layer(const int layer);
private:
/**
* Finishes the building initialization of the widget.
@ -64,6 +81,16 @@ private:
*/
tgenerator_* generator_;
/**
* The number of the current selected layer.
*/
int selected_layer_;
/**
* Helper to ensure the correct state is set when selecting a layer.
*/
void select_layer_internal(const unsigned int layer, const bool select) const;
/** See @ref tcontrol::get_control_type. */
virtual const std::string& get_control_type() const OVERRIDE;