GUI2: made widget initialization process more secure against memory leaks

This commit is the followup to a similar one I did regarding window initialization. Instead
of widgets being created on the heap and not being managed by a smart pointer until they're
added to a grid, they are now always managed by a shared_ptr. To that end, this commit covers
bunch of things:

* builder_widget::build (both overloads) and all its overrides (which have now been marked
  as such) now return shared_ptr<widget>.
* The builder_grid::build() override now returns the same instead of grid* since you can't
  use covariant return types with smart pointers.
* The two implementation build helpers in builder_grid have been combined with an optional
  replacement map as the second parameter. Uses of the version that took a grid pointer could
  be easily converted to pass a reference instead.
* The pane, matrix, and viewport build() functions were removed in favor of making the ctor
  public. In case there was a deprecated ctor, that was removed.
* The viewport now keeps a widget shared_ptr instead of a reference that was then deleted
  by address-of. This was both better design and necessary to fix a crash.
* build_single_widget_instance_helper and build_single_widget_instance were renamed to
  build_single_widget and build_single_widget_and_cast_to to better represent their roles
  and to indicate the latter was more a convenience extension for the latter than the other
  way around.
This commit is contained in:
Charles Dang 2018-06-06 18:11:49 +11:00
parent b70463b6ad
commit 3d894faf11
86 changed files with 267 additions and 313 deletions

View file

@ -50,7 +50,7 @@ window_ptr_t build_window_impl(const builder_window::window_resolution* definiti
{ {
// We set the values from the definition since we can only determine the // We set the values from the definition since we can only determine the
// best size (if needed) after all widgets have been placed. // best size (if needed) after all widgets have been placed.
window_ptr_t win = std::make_unique<window>(definition); auto win = std::make_unique<window>(definition);
assert(win); assert(win);
for(const auto& lg : definition->linked_groups) { for(const auto& lg : definition->linked_groups) {
@ -134,7 +134,7 @@ builder_widget_ptr create_widget_builder(const config& cfg)
FAIL("Unknown widget type " + cfg.ordered_begin()->key); FAIL("Unknown widget type " + cfg.ordered_begin()->key);
} }
widget* build_single_widget_instance_helper(const std::string& type, const config& cfg) widget_ptr build_single_widget(const std::string& type, const config& cfg)
{ {
const auto& iter = widget_builder_lookup().find(type); const auto& iter = widget_builder_lookup().find(type);
VALIDATE(iter != widget_builder_lookup().end(), "Invalid widget type '" + type + "'"); VALIDATE(iter != widget_builder_lookup().end(), "Invalid widget type '" + type + "'");
@ -438,49 +438,21 @@ builder_grid::builder_grid(const config& cfg)
DBG_GUI_P << "Window builder: grid has " << rows << " rows and " << cols << " columns.\n"; DBG_GUI_P << "Window builder: grid has " << rows << " rows and " << cols << " columns.\n";
} }
grid* builder_grid::build() const widget_ptr builder_grid::build() const
{ {
return build(new grid()); auto result = std::make_shared<grid>();
build(*result);
return result;
} }
widget* builder_grid::build(const replacements_map& replacements) const widget_ptr builder_grid::build(const replacements_map& replacements) const
{ {
grid* result = new grid(); auto result = std::make_shared<grid>();
build(*result, replacements); build(*result, replacements);
return result; return result;
} }
grid* builder_grid::build(grid* grid) const void builder_grid::build(grid& grid, optional_replacements_t replacements) const
{
grid->set_id(id);
grid->set_linked_group(linked_group);
grid->set_rows_cols(rows, cols);
log_scope2(log_gui_general, "Window builder: building grid");
DBG_GUI_G << "Window builder: grid '" << id << "' has " << rows << " rows and " << cols << " columns.\n";
for(unsigned x = 0; x < rows; ++x) {
grid->set_row_grow_factor(x, row_grow_factor[x]);
for(unsigned y = 0; y < cols; ++y) {
if(x == 0) {
grid->set_column_grow_factor(y, col_grow_factor[y]);
}
DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".\n";
const unsigned int i = x * cols + y;
widget* widget = widgets[i]->build();
grid->set_child(widget, x, y, flags[i], border_size[i]);
}
}
return grid;
}
void builder_grid::build(grid& grid, const replacements_map& replacements) const
{ {
grid.set_id(id); grid.set_id(id);
grid.set_linked_group(linked_group); grid.set_linked_group(linked_group);
@ -501,7 +473,14 @@ void builder_grid::build(grid& grid, const replacements_map& replacements) const
DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".\n"; DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".\n";
const unsigned int i = x * cols + y; const unsigned int i = x * cols + y;
grid.set_child(widgets[i]->build(replacements), x, y, flags[i], border_size[i]);
if(replacements != boost::none) {
auto widget = widgets[i]->build(replacements.get());
grid.set_child(widget, x, y, flags[i], border_size[i]);
} else {
auto widget = widgets[i]->build();
grid.set_child(widget, x, y, flags[i], border_size[i]);
}
} }
} }
} }

View file

@ -20,6 +20,8 @@
#include "gui/widgets/grid.hpp" #include "gui/widgets/grid.hpp"
#include "utils/functional.hpp" #include "utils/functional.hpp"
#include <boost/optional.hpp>
#include <memory> #include <memory>
class config; class config;
@ -31,7 +33,6 @@ class window;
/** Contains the info needed to instantiate a widget. */ /** Contains the info needed to instantiate a widget. */
struct builder_widget struct builder_widget
{ {
public:
/** /**
* The replacements type is used to define replacement types. * The replacements type is used to define replacement types.
* *
@ -40,7 +41,13 @@ public:
* using and `[instance]' widget this decision can be postponed until * using and `[instance]' widget this decision can be postponed until
* instantiation. * instantiation.
*/ */
typedef std::map<std::string, std::shared_ptr<builder_widget>> replacements_map; using replacements_map = std::map<std::string, std::shared_ptr<builder_widget>>;
/**
* @todo: evaluate whether to combine the two @ref build() functions with this
* as the sole parameter.
*/
using optional_replacements_t = boost::optional<const replacements_map&>;
explicit builder_widget(const config& cfg); explicit builder_widget(const config& cfg);
@ -48,9 +55,9 @@ public:
{ {
} }
virtual widget* build() const = 0; virtual widget_ptr build() const = 0;
virtual widget* build(const replacements_map& replacements) const = 0; virtual widget_ptr build(const replacements_map& replacements) const = 0;
/** Parameters for the widget. */ /** Parameters for the widget. */
std::string id; std::string id;
@ -60,8 +67,8 @@ public:
color_t debug_border_color; color_t debug_border_color;
}; };
typedef std::shared_ptr<builder_widget> builder_widget_ptr; using builder_widget_ptr = std::shared_ptr<builder_widget>;
typedef std::shared_ptr<const builder_widget> builder_widget_const_ptr; using builder_widget_const_ptr = std::shared_ptr<const builder_widget>;
/** /**
* Create a widget builder. * Create a widget builder.
@ -75,34 +82,43 @@ typedef std::shared_ptr<const builder_widget> builder_widget_const_ptr;
*/ */
builder_widget_ptr create_widget_builder(const config& cfg); builder_widget_ptr create_widget_builder(const config& cfg);
/**
* Helper function to implement @ref build_single_widget_instance. This keeps the main
* logic in the implementation despite said function being a template and therefor
* needing to be fully implemented in the declaration.
*/
widget* build_single_widget_instance_helper(const std::string& type, const config& cfg);
/** /**
* Builds a single widget instance of the given type with the specified attributes. * Builds a single widget instance of the given type with the specified attributes.
* *
* This should be used in place of creating a widget object directly, as it * This should be used in place of creating a widget object directly, as it
* allows the widget-specific builder code to be executed. * allows the widget-specific builder code to be executed.
* *
* This is equivalent to calling @c build() on the result of @ref create_widget_builder.
*
* @param type String ID of the widget type.
* @param cfg Data config to pass to the widget's builder.
*
* @returns A shared_ptr of the base widget type containing
* the newly built widget.
*/
widget_ptr build_single_widget(const std::string& type, const config& cfg);
/**
* Convenience wrapper around @ref build_single_widget that casts the resulting
* widget pointer to the given type.
*
* @tparam T The final widget type. The widget pointer will be * @tparam T The final widget type. The widget pointer will be
* cast to this. * cast to this.
* *
* @param type String ID of the widget type. * @param type String ID of the widget type.
* @param cfg Data config to pass to the widget's builder. * @param cfg Data config to pass to the widget's builder.
*
* @returns A shared_ptr of the given type containing the
* newly build widget.
*/ */
template<typename T> template<typename T>
T* build_single_widget_instance(const std::string& type, const config& cfg = config()) std::shared_ptr<T> build_single_widget_and_cast_to(const std::string& type, const config& cfg = {})
{ {
return dynamic_cast<T*>(build_single_widget_instance_helper(type, cfg)); return std::dynamic_pointer_cast<T>(build_single_widget(type, cfg));
} }
struct builder_grid : public builder_widget struct builder_grid : public builder_widget
{ {
public:
explicit builder_grid(const config& cfg); explicit builder_grid(const config& cfg);
unsigned rows; unsigned rows;
@ -121,15 +137,18 @@ public:
/** The widgets per grid cell. */ /** The widgets per grid cell. */
std::vector<builder_widget_ptr> widgets; std::vector<builder_widget_ptr> widgets;
grid* build() const; /** Inherited from @ref builder_widget. */
widget* build(const replacements_map& replacements) const; virtual widget_ptr build() const override;
grid* build(grid* grid) const; /** Inherited from @ref builder_widget. */
void build(grid& grid, const replacements_map& replacements) const; virtual widget_ptr build(const replacements_map& replacements) const override;
void build(grid& grid, optional_replacements_t replacements = boost::none) const;
}; };
typedef std::shared_ptr<builder_grid> builder_grid_ptr; using builder_grid_ptr = std::shared_ptr<builder_grid>;
typedef std::shared_ptr<const builder_grid> builder_grid_const_ptr; using builder_grid_const_ptr = std::shared_ptr<const builder_grid>;
using builder_grid_map = std::map<std::string, builder_grid_const_ptr>;
class builder_window class builder_window
{ {
@ -144,7 +163,6 @@ public:
struct window_resolution struct window_resolution
{ {
public:
explicit window_resolution(const config& cfg); explicit window_resolution(const config& cfg);
unsigned window_width; unsigned window_width;

View file

@ -29,12 +29,12 @@ builder_instance::builder_instance(const config& cfg)
{ {
} }
widget* builder_instance::build() const widget_ptr builder_instance::build() const
{ {
return build(replacements_map()); return build(replacements_map());
} }
widget* builder_instance::build(const replacements_map& replacements) const widget_ptr builder_instance::build(const replacements_map& replacements) const
{ {
const replacements_map::const_iterator itor = replacements.find(id); const replacements_map::const_iterator itor = replacements.find(id);
if(itor != replacements.end()) { if(itor != replacements.end()) {

View file

@ -28,9 +28,9 @@ struct builder_instance : public builder_widget
{ {
explicit builder_instance(const config& cfg); explicit builder_instance(const config& cfg);
widget* build() const; virtual widget_ptr build() const override;
widget* build(const replacements_map& replacements) const; virtual widget_ptr build(const replacements_map& replacements) const override;
/** /**
* Holds a copy of the cfg parameter in the constructor. * Holds a copy of the cfg parameter in the constructor.

View file

@ -137,17 +137,17 @@ void drop_down_menu::pre_show(window& window)
find_widget<toggle_panel>(&new_row, "panel", false).set_tooltip(entry["tooltip"]); find_widget<toggle_panel>(&new_row, "panel", false).set_tooltip(entry["tooltip"]);
if(entry.has_attribute("image")) { if(entry.has_attribute("image")) {
image* img = build_single_widget_instance<image>("image"); auto img = build_single_widget_and_cast_to<image>("image");
img->set_label(entry["image"]); img->set_label(entry["image"]);
grid* mi_grid = dynamic_cast<grid*>(new_row.find("menu_item", false)); grid* mi_grid = dynamic_cast<grid*>(new_row.find("menu_item", false));
if(mi_grid) { if(mi_grid) {
mi_grid->swap_child("label", img, false); mi_grid->swap_child("label", std::static_pointer_cast<widget>(img), false);
} }
} }
if(entry.has_attribute("checkbox")) { if(entry.has_attribute("checkbox")) {
toggle_button* checkbox = build_single_widget_instance<toggle_button>("toggle_button"); auto checkbox = build_single_widget_and_cast_to<toggle_button>("toggle_button");
checkbox->set_id("checkbox"); checkbox->set_id("checkbox");
checkbox->set_value_bool(entry["checkbox"].to_bool(false)); checkbox->set_value_bool(entry["checkbox"].to_bool(false));
@ -157,7 +157,7 @@ void drop_down_menu::pre_show(window& window)
grid* mi_grid = dynamic_cast<grid*>(new_row.find("menu_item", false)); grid* mi_grid = dynamic_cast<grid*>(new_row.find("menu_item", false));
if(mi_grid) { if(mi_grid) {
mi_grid->swap_child("icon", checkbox, false); mi_grid->swap_child("icon", std::static_pointer_cast<widget>(checkbox), false);
} }
} }
} }

View file

@ -646,7 +646,7 @@ void preferences_dialog::post_build(window& window)
} }
case ADVANCED_PREF_TYPE::SLIDER: { case ADVANCED_PREF_TYPE::SLIDER: {
slider* setter_widget = build_single_widget_instance<slider>("slider", config {"definition", "minimal"}); auto setter_widget = build_single_widget_and_cast_to<slider>("slider", config {"definition", "minimal"});
setter_widget->set_id("setter"); setter_widget->set_id("setter");
// Maximum must be set first or this will assert // Maximum must be set first or this will assert
setter_widget->set_value_range(option["min"].to_int(), option["max"].to_int()); setter_widget->set_value_range(option["min"].to_int(), option["max"].to_int());
@ -693,7 +693,7 @@ void preferences_dialog::post_build(window& window)
selected = 0; selected = 0;
} }
menu_button* setter_widget = build_single_widget_instance<menu_button>("menu_button"); auto setter_widget = build_single_widget_and_cast_to<menu_button>("menu_button");
setter_widget->set_id("setter"); setter_widget->set_id("setter");
details_grid.swap_child("setter", setter_widget, true); details_grid.swap_child("setter", setter_widget, true);
@ -718,7 +718,7 @@ void preferences_dialog::post_build(window& window)
case ADVANCED_PREF_TYPE::SPECIAL: { case ADVANCED_PREF_TYPE::SPECIAL: {
//main_grid->remove_child("setter"); //main_grid->remove_child("setter");
image* value_widget = build_single_widget_instance<image>("image"); auto value_widget = build_single_widget_and_cast_to<image>("image");
value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)"); value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)");
main_grid->swap_child("value", value_widget, true); main_grid->swap_child("value", value_widget, true);

View file

@ -461,9 +461,9 @@ builder_addon_list::builder_addon_list(const config& cfg)
} }
} }
widget* builder_addon_list::build() const widget_ptr builder_addon_list::build() const
{ {
addon_list* widget = new addon_list(*this); auto widget = std::make_shared<addon_list>(*this);
DBG_GUI_G << "Window builder: placed add-on list '" << id << DBG_GUI_G << "Window builder: placed add-on list '" << id <<
"' with definition '" << definition << "'.\n"; "' with definition '" << definition << "'.\n";

View file

@ -209,7 +209,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
widget::visibility install_status_visibility_; widget::visibility install_status_visibility_;

View file

@ -241,9 +241,9 @@ builder_button::builder_button(const config& cfg)
{ {
} }
widget* builder_button::build() const widget_ptr builder_button::build() const
{ {
button* widget = new button(*this); auto widget = std::make_shared<button>(*this);
widget->set_retval(get_retval(retval_id_, retval_, id)); widget->set_retval(get_retval(retval_id_, retval_, id));

View file

@ -142,7 +142,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
std::string retval_id_; std::string retval_id_;

View file

@ -810,9 +810,9 @@ builder_chatbox::builder_chatbox(const config& cfg)
{ {
} }
widget* builder_chatbox::build() const widget_ptr builder_chatbox::build() const
{ {
chatbox* widget = new chatbox(*this); auto widget = std::make_shared<chatbox>(*this);
DBG_GUI_G << "Window builder: placed unit preview pane '" << id DBG_GUI_G << "Window builder: placed unit preview pane '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -283,7 +283,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
}; };

View file

@ -257,7 +257,7 @@ container_base::init_grid(const std::shared_ptr<builder_grid>& grid_builder)
assert(grid_.get_rows() == 0 && grid_.get_cols() == 0); assert(grid_.get_rows() == 0 && grid_.get_cols() == 0);
grid_builder->build(&grid_); grid_builder->build(grid_);
} }
point container_base::border_space() const point container_base::border_space() const

View file

@ -193,7 +193,7 @@ public:
grid_.set_rows_cols(rows, cols); grid_.set_rows_cols(rows, cols);
} }
void set_child(widget* widget, void set_child(widget_ptr widget,
const unsigned row, const unsigned row,
const unsigned col, const unsigned col,
const unsigned flags, const unsigned flags,

View file

@ -175,9 +175,9 @@ builder_drawing::builder_drawing(const config& cfg)
assert(!draw.empty()); assert(!draw.empty());
} }
widget* builder_drawing::build() const widget_ptr builder_drawing::build() const
{ {
drawing* widget = new drawing(*this); auto widget = std::make_shared<drawing>(*this);
const wfl::map_formula_callable& size = get_screen_size_variables(); const wfl::map_formula_callable& size = get_screen_size_variables();

View file

@ -130,7 +130,7 @@ struct builder_drawing : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
/** The width of the widget. */ /** The width of the widget. */
typed_formula<unsigned> width; typed_formula<unsigned> width;

View file

@ -1108,16 +1108,16 @@ static_assert(false, "GUI2/Generator: GENERATE_PLACEMENT already defined!");
#define GENERATE_PLACEMENT \ #define GENERATE_PLACEMENT \
switch(placement) { \ switch(placement) { \
case generator_base::horizontal_list: \ case generator_base::horizontal_list: \
result = new generator<minimum, maximum, policy::placement::horizontal_list, select_action>; \ result = std::make_shared<generator<minimum, maximum, policy::placement::horizontal_list, select_action>>(); \
break; \ break; \
case generator_base::vertical_list: \ case generator_base::vertical_list: \
result = new generator<minimum, maximum, policy::placement::vertical_list, select_action>; \ result = std::make_shared<generator<minimum, maximum, policy::placement::vertical_list, select_action>>(); \
break; \ break; \
case generator_base::table: \ case generator_base::table: \
result = new generator<minimum, maximum, policy::placement::table, select_action>; \ result = std::make_shared<generator<minimum, maximum, policy::placement::table, select_action>>(); \
break; \ break; \
case generator_base::independent: \ case generator_base::independent: \
result = new generator<minimum, maximum, policy::placement::independent, select_action>; \ result = std::make_shared<generator<minimum, maximum, policy::placement::independent, select_action>>(); \
break; \ break; \
default: \ default: \
assert(false); \ assert(false); \
@ -1163,10 +1163,10 @@ static_assert(false, "GUI2/Generator: GENERATE_BODY already defined!");
} }
#endif #endif
generator_base* generator_base::build( generator_ptr generator_base::build(
const bool has_minimum, const bool has_maximum, const placement placement, const bool select) const bool has_minimum, const bool has_maximum, const placement placement, const bool select)
{ {
generator_base* result = nullptr; generator_ptr result = nullptr;
GENERATE_BODY; GENERATE_BODY;
return result; return result;
} }

View file

@ -26,8 +26,11 @@ namespace gui2
struct builder_grid; struct builder_grid;
typedef std::shared_ptr<const builder_grid> builder_grid_const_ptr; typedef std::shared_ptr<const builder_grid> builder_grid_const_ptr;
class generator_base;
class grid; class grid;
using generator_ptr = std::shared_ptr<generator_base>;
/** /**
* Abstract base class for the generator. * Abstract base class for the generator.
* *
@ -59,7 +62,7 @@ public:
* @param has_minimum Does one item need to be selected. * @param has_minimum Does one item need to be selected.
* @param has_maximum Is one the maximum number of items that can * @param has_maximum Is one the maximum number of items that can
* be selected? * be selected?
* @param placement The placement of the grids, see tplacement * @param placement The placement of the grids, see placement
* for more info. * for more info.
* @param select If a grid is selected, what should happen? * @param select If a grid is selected, what should happen?
* If true the grid is selected, if false the * If true the grid is selected, if false the
@ -68,7 +71,7 @@ public:
* @returns A pointer to a new object. The caller gets * @returns A pointer to a new object. The caller gets
* ownership of the new object. * ownership of the new object.
*/ */
static generator_base* build(const bool has_minimum, static generator_ptr build(const bool has_minimum,
const bool has_maximum, const bool has_maximum,
const placement placement, const placement placement,
const bool select); const bool select);

View file

@ -734,7 +734,7 @@ public:
assert(index == -1 || static_cast<unsigned>(index) <= items_.size()); assert(index == -1 || static_cast<unsigned>(index) <= items_.size());
child* item = new child; child* item = new child;
list_builder->build(&item->child_grid); list_builder->build(item->child_grid);
init(&item->child_grid, item_data, callback); init(&item->child_grid, item_data, callback);

View file

@ -66,7 +66,7 @@ unsigned grid::add_row(const unsigned count)
return result; return result;
} }
void grid::set_child(widget* widget, void grid::set_child(widget_ptr widget,
const unsigned row, const unsigned row,
const unsigned col, const unsigned col,
const unsigned flags, const unsigned flags,
@ -89,16 +89,17 @@ void grid::set_child(widget* widget,
cell.set_flags(flags); cell.set_flags(flags);
cell.set_border_size(border_size); cell.set_border_size(border_size);
cell.set_widget(widget); cell.set_widget(widget);
if(cell.get_widget()) {
// make sure the new child is valid before deferring // make sure the new child is valid before deferring
cell.get_widget()->set_parent(this); if(gui2::widget* w = cell.get_widget()) {
w->set_parent(this);
} }
} }
std::unique_ptr<widget> grid::swap_child(const std::string& id, widget_ptr grid::swap_child(const std::string& id,
widget* w, widget_ptr w,
const bool recurse, const bool recurse,
widget* new_parent) widget* new_parent)
{ {
assert(w); assert(w);
@ -111,7 +112,7 @@ std::unique_ptr<widget> grid::swap_child(const std::string& id,
grid* g = dynamic_cast<grid*>(child.get_widget()); grid* g = dynamic_cast<grid*>(child.get_widget());
if(g) { if(g) {
std::unique_ptr<widget> old = g->swap_child(id, w, true); widget_ptr old = g->swap_child(id, w, true);
if(old) { if(old) {
return old; return old;
} }
@ -122,7 +123,7 @@ std::unique_ptr<widget> grid::swap_child(const std::string& id,
} }
// Free widget from cell and validate. // Free widget from cell and validate.
std::unique_ptr<widget> old = child.free_widget(); widget_ptr old = child.free_widget();
assert(old); assert(old);
old->set_parent(new_parent); old->set_parent(new_parent);
@ -1086,7 +1087,7 @@ grid_implementation::cell_request_reduce_width(grid::child& child,
child.widget_->request_reduce_width(maximum_width - child.border_space().x); child.widget_->request_reduce_width(maximum_width - child.border_space().x);
} }
void set_single_child(grid& grid, widget* widget) void set_single_child(grid& grid, widget_ptr widget)
{ {
grid.set_rows_cols(1, 1); grid.set_rows_cols(1, 1);
grid.set_child(widget, grid.set_child(widget,

View file

@ -120,7 +120,7 @@ public:
* @param border_size The size of the border for the cell, how the * @param border_size The size of the border for the cell, how the
* border is applied depends on the flags. * border is applied depends on the flags.
*/ */
void set_child(widget* widget, void set_child(widget_ptr widget,
const unsigned row, const unsigned row,
const unsigned col, const unsigned col,
const unsigned flags, const unsigned flags,
@ -141,8 +141,8 @@ public:
* the widget is cleared). If no widget found * the widget is cleared). If no widget found
* and thus not replace nullptr will returned. * and thus not replace nullptr will returned.
*/ */
std::unique_ptr<widget> swap_child(const std::string& id, widget_ptr swap_child(const std::string& id,
widget* w, widget_ptr w,
const bool recurse, const bool recurse,
widget* new_parent = nullptr); widget* new_parent = nullptr);
@ -391,16 +391,17 @@ private:
return widget_.get(); return widget_.get();
} }
void set_widget(widget* widget) /** Acquires an owning reference to the given widget. */
void set_widget(widget_ptr widget)
{ {
widget_.reset(widget); widget_ = std::move(widget);
} }
/** /**
* Releases widget from ownership by this child and returns it in the * Releases widget from ownership by this child and returns it in the
* form of a new unique_ptr. widget_ will be null after this is called. * form of a new shared_ptr. widget_ will be null after this is called.
*/ */
std::unique_ptr<widget> free_widget() widget_ptr free_widget()
{ {
return std::exchange(widget_, nullptr); return std::exchange(widget_, nullptr);
} }
@ -421,7 +422,7 @@ private:
* Once the widget is assigned to the grid we own the widget and it * Once the widget is assigned to the grid we own the widget and it
* will be destroyed with the grid or @ref free_widget is called. * will be destroyed with the grid or @ref free_widget is called.
*/ */
std::unique_ptr<widget> widget_; widget_ptr widget_;
/** Returns the space needed for the border. */ /** Returns the space needed for the border. */
point border_space() const; point border_space() const;
@ -442,14 +443,17 @@ public:
{ {
return iterator(++itor_); return iterator(++itor_);
} }
iterator operator--() iterator operator--()
{ {
return iterator(--itor_); return iterator(--itor_);
} }
widget* operator->() widget* operator->()
{ {
return itor_->get_widget(); return itor_->get_widget();
} }
widget* operator*() widget* operator*()
{ {
return itor_->get_widget(); return itor_->get_widget();
@ -550,6 +554,8 @@ private:
virtual void impl_draw_children() override; virtual void impl_draw_children() override;
}; };
using grid_ptr = std::shared_ptr<grid>;
/** /**
* Sets the single child in a grid. * Sets the single child in a grid.
* *
@ -559,6 +565,6 @@ private:
* @param grid The grid to add the child to. * @param grid The grid to add the child to.
* @param widget The widget to add as child to the grid. * @param widget The widget to add as child to the grid.
*/ */
void set_single_child(grid& grid, widget* widget); void set_single_child(grid& grid, widget_ptr widget);
} // namespace gui2 } // namespace gui2

View file

@ -214,9 +214,9 @@ builder_horizontal_scrollbar::builder_horizontal_scrollbar(const config& cfg)
{ {
} }
widget* builder_horizontal_scrollbar::build() const widget_ptr builder_horizontal_scrollbar::build() const
{ {
horizontal_scrollbar* widget = new horizontal_scrollbar(*this); auto widget = std::make_shared<horizontal_scrollbar>(*this);
widget->finalize_setup(); widget->finalize_setup();

View file

@ -103,7 +103,7 @@ struct builder_horizontal_scrollbar : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
}; };
} // namespace implementation } // namespace implementation

View file

@ -165,9 +165,9 @@ builder_image::builder_image(const config& cfg) : builder_styled_widget(cfg)
{ {
} }
widget* builder_image::build() const widget_ptr builder_image::build() const
{ {
image* widget = new image(*this); auto widget = std::make_shared<image>(*this);
DBG_GUI_G << "Window builder: placed image '" << id << "' with definition '" DBG_GUI_G << "Window builder: placed image '" << id << "' with definition '"
<< definition << "'.\n"; << definition << "'.\n";

View file

@ -120,7 +120,7 @@ struct builder_image : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
}; };
} // namespace implementation } // namespace implementation

View file

@ -309,9 +309,9 @@ builder_label::builder_label(const config& cfg)
{ {
} }
widget* builder_label::build() const widget_ptr builder_label::build() const
{ {
label* lbl = new label(*this); auto lbl = std::make_shared<label>(*this);
const auto conf = lbl->cast_config_to<label_definition>(); const auto conf = lbl->cast_config_to<label_definition>();
assert(conf); assert(conf);

View file

@ -177,7 +177,7 @@ struct builder_label : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
bool wrap; bool wrap;

View file

@ -952,7 +952,7 @@ builder_listbox::builder_listbox(const config& cfg)
} }
} }
widget* builder_listbox::build() const widget_ptr builder_listbox::build() const
{ {
#ifdef GUI2_EXPERIMENTAL_LISTBOX #ifdef GUI2_EXPERIMENTAL_LISTBOX
list_view* widget = new list_view(true, true, generator_base::vertical_list, true, list_builder); list_view* widget = new list_view(true, true, generator_base::vertical_list, true, list_builder);
@ -965,7 +965,7 @@ widget* builder_listbox::build() const
return widget; return widget;
#else #else
listbox* widget = new listbox(*this, generator_base::vertical_list, list_builder, has_minimum_, has_maximum_); auto widget = std::make_shared<listbox>(*this, generator_base::vertical_list, list_builder, has_minimum_, has_maximum_);
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode); widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode); widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);
@ -1069,7 +1069,7 @@ builder_horizontal_listbox::builder_horizontal_listbox(const config& cfg)
} }
} }
widget* builder_horizontal_listbox::build() const widget_ptr builder_horizontal_listbox::build() const
{ {
#ifdef GUI2_EXPERIMENTAL_LISTBOX #ifdef GUI2_EXPERIMENTAL_LISTBOX
list_view* widget = new list_view(true, true, generator_base::horizontal_list, true, list_builder); list_view* widget = new list_view(true, true, generator_base::horizontal_list, true, list_builder);
@ -1082,7 +1082,7 @@ widget* builder_horizontal_listbox::build() const
return widget; return widget;
#else #else
listbox* widget = new listbox(*this, generator_base::horizontal_list, list_builder, has_minimum_, has_maximum_); auto widget = std::make_shared<listbox>(*this, generator_base::horizontal_list, list_builder, has_minimum_, has_maximum_);
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode); widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode); widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);
@ -1186,7 +1186,7 @@ builder_grid_listbox::builder_grid_listbox(const config& cfg)
} }
} }
widget* builder_grid_listbox::build() const widget_ptr builder_grid_listbox::build() const
{ {
#ifdef GUI2_EXPERIMENTAL_LISTBOX #ifdef GUI2_EXPERIMENTAL_LISTBOX
list_view* widget = new list_view(true, true, generator_base::grid, true, list_builder); list_view* widget = new list_view(true, true, generator_base::grid, true, list_builder);
@ -1199,7 +1199,7 @@ widget* builder_grid_listbox::build() const
return widget; return widget;
#else #else
listbox* widget = new listbox(*this, generator_base::table, list_builder, has_minimum_, has_maximum_); auto widget = std::make_shared<listbox>(*this, generator_base::table, list_builder, has_minimum_, has_maximum_);
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode); widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode); widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);

View file

@ -44,6 +44,7 @@ class listbox : public scrollbar_container
friend struct implementation::builder_listbox; friend struct implementation::builder_listbox;
friend struct implementation::builder_horizontal_listbox; friend struct implementation::builder_horizontal_listbox;
friend struct implementation::builder_grid_listbox; friend struct implementation::builder_grid_listbox;
friend class debug_layout_graph; friend class debug_layout_graph;
public: public:
@ -66,6 +67,7 @@ public:
const bool select = true); const bool select = true);
/***** ***** ***** ***** Row handling. ***** ***** ****** *****/ /***** ***** ***** ***** Row handling. ***** ***** ****** *****/
/** /**
* When an item in the list is selected by the user we need to * When an item in the list is selected by the user we need to
* update the state. We installed a callback handler which * update the state. We installed a callback handler which
@ -365,7 +367,7 @@ private:
* of the scrollbar_container super class and freed when it's grid is * of the scrollbar_container super class and freed when it's grid is
* freed. * freed.
*/ */
generator_base* generator_; generator_ptr generator_;
const bool is_horizontal_; const bool is_horizontal_;
@ -444,7 +446,7 @@ struct builder_listbox : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;
@ -471,7 +473,7 @@ struct builder_horizontal_listbox : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;
@ -495,7 +497,7 @@ struct builder_grid_listbox : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;

View file

@ -87,11 +87,6 @@ matrix::matrix(const implementation::builder_matrix& builder)
pane_ = find_widget<pane>(&content_, "pane", false, true); pane_ = find_widget<pane>(&content_, "pane", false, true);
} }
matrix* matrix::build(const implementation::builder_matrix& builder)
{
return new matrix(builder);
}
unsigned unsigned
matrix::create_item(const std::map<std::string, string_map>& item_data, matrix::create_item(const std::map<std::string, string_map>& item_data,
const std::map<std::string, std::string>& tags) const std::map<std::string, std::string>& tags)
@ -286,9 +281,9 @@ builder_matrix::builder_matrix(const config& cfg)
} }
} }
widget* builder_matrix::build() const widget_ptr builder_matrix::build() const
{ {
return matrix::build(*this); return std::make_shared<matrix>(*this);
} }
} // namespace implementation } // namespace implementation

View file

@ -100,11 +100,8 @@ class matrix : public tbase
{ {
friend class debug_layout_graph; friend class debug_layout_graph;
private:
explicit matrix(const implementation::builder_matrix& builder);
public: public:
static matrix* build(const implementation::builder_matrix& builder); explicit matrix(const implementation::builder_matrix& builder);
/***** ***** ***** ***** Item handling. ***** ***** ****** *****/ /***** ***** ***** ***** Item handling. ***** ***** ****** *****/
@ -247,7 +244,7 @@ struct builder_matrix : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;

View file

@ -280,9 +280,9 @@ builder_menu_button::builder_menu_button(const config& cfg)
} }
} }
widget* builder_menu_button::build() const widget_ptr builder_menu_button::build() const
{ {
menu_button* widget = new menu_button(*this); auto widget = std::make_shared<menu_button>(*this);
widget->set_retval(get_retval(retval_id_, retval_, id)); widget->set_retval(get_retval(retval_id_, retval_, id));
if(!options_.empty()) { if(!options_.empty()) {

View file

@ -182,7 +182,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
std::string retval_id_; std::string retval_id_;

View file

@ -168,9 +168,9 @@ builder_minimap::builder_minimap(const config& cfg) : builder_styled_widget(cfg)
{ {
} }
widget* builder_minimap::build() const widget_ptr builder_minimap::build() const
{ {
minimap* widget = new minimap(*this); auto widget = std::make_shared<minimap>(*this);
DBG_GUI_G << "Window builder: placed minimap '" << id DBG_GUI_G << "Window builder: placed minimap '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -119,7 +119,7 @@ struct builder_minimap : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
}; };
} // namespace implementation } // namespace implementation

View file

@ -280,9 +280,9 @@ builder_multi_page::builder_multi_page(const config& cfg)
} }
} }
widget* builder_multi_page::build() const widget_ptr builder_multi_page::build() const
{ {
multi_page* widget = new multi_page(*this); auto widget = std::make_shared<multi_page>(*this);
widget->set_page_builders(builders); widget->set_page_builders(builders);

View file

@ -29,7 +29,7 @@ namespace implementation
struct builder_multi_page; struct builder_multi_page;
} }
class generator_base; using generator_ptr = std::shared_ptr<class generator_base>;
/** The multi page class. */ /** The multi page class. */
class multi_page : public container_base class multi_page : public container_base
@ -174,7 +174,7 @@ public:
/***** ***** ***** setters / getters for members ***** ****** *****/ /***** ***** ***** setters / getters for members ***** ****** *****/
void set_page_builders(const std::map<std::string, builder_grid_const_ptr>& page_builders) void set_page_builders(const builder_grid_map& page_builders)
{ {
assert(!page_builders.empty()); assert(!page_builders.empty());
page_builders_ = page_builders; page_builders_ = page_builders;
@ -195,10 +195,10 @@ private:
* of the scrollbar_container super class and freed when it's grid is * of the scrollbar_container super class and freed when it's grid is
* freed. * freed.
*/ */
generator_base* generator_; generator_ptr generator_;
/** Contains the builder for the new items. */ /** Contains the builder for the new items. */
std::map<std::string, builder_grid_const_ptr> page_builders_; builder_grid_map page_builders_;
/** See @ref widget::impl_draw_background. */ /** See @ref widget::impl_draw_background. */
virtual void impl_draw_background() override; virtual void impl_draw_background() override;
@ -235,9 +235,9 @@ struct builder_multi_page : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
std::map<std::string, builder_grid_const_ptr> builders; builder_grid_map builders;
/** /**
* Multi page data. * Multi page data.

View file

@ -339,9 +339,9 @@ builder_multimenu_button::builder_multimenu_button(const config& cfg)
} }
} }
widget* builder_multimenu_button::build() const widget_ptr builder_multimenu_button::build() const
{ {
multimenu_button* widget = new multimenu_button(*this); auto widget = std::make_shared<multimenu_button>(*this);
widget->set_retval(get_retval(retval_id_, retval_, id)); widget->set_retval(get_retval(retval_id_, retval_, id));
widget->set_max_shown(max_shown_); widget->set_max_shown(max_shown_);

View file

@ -230,7 +230,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
std::string retval_id_; std::string retval_id_;

View file

@ -96,7 +96,7 @@ struct pane_implementation
{ {
if(item.id == id) { if(item.id == id) {
return item.item_grid; return item.item_grid.get();
} }
} }
@ -104,19 +104,6 @@ struct pane_implementation
} }
}; };
pane::pane(const builder_grid_ptr item_builder)
: widget()
, items_()
, item_builder_(item_builder)
, item_id_generator_(0)
, placer_(placer_base::build(placer_base::tgrow_direction::vertical, 1))
{
connect_signal<event::REQUEST_PLACEMENT>(
std::bind(
&pane::signal_handler_request_placement, this, _1, _2, _3),
event::dispatcher::back_pre_child);
}
pane::pane(const implementation::builder_pane& builder) pane::pane(const implementation::builder_pane& builder)
: widget(builder) : widget(builder)
, items_() , items_()
@ -130,22 +117,17 @@ pane::pane(const implementation::builder_pane& builder)
event::dispatcher::back_pre_child); event::dispatcher::back_pre_child);
} }
pane* pane::build(const implementation::builder_pane& builder)
{
return new pane(builder);
}
unsigned pane::create_item(const std::map<std::string, string_map>& item_data, unsigned pane::create_item(const std::map<std::string, string_map>& item_data,
const std::map<std::string, std::string>& tags) const std::map<std::string, std::string>& tags)
{ {
item item = { item_id_generator_++, tags, item_builder_->build() }; item item { item_id_generator_++, tags, std::dynamic_pointer_cast<grid>(item_builder_->build()) };
item.item_grid->set_parent(this); item.item_grid->set_parent(this);
for(const auto & data : item_data) for(const auto & data : item_data)
{ {
styled_widget* control styled_widget* control
= find_widget<styled_widget>(item.item_grid, data.first, false, false); = find_widget<styled_widget>(item.item_grid.get(), data.first, false, false);
if(control) { if(control) {
control->set_members(data.second); control->set_members(data.second);
@ -419,14 +401,14 @@ builder_pane::builder_pane(const config& cfg)
VALIDATE(parallel_items > 0, _("Need at least 1 parallel item.")); VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
} }
widget* builder_pane::build() const widget_ptr builder_pane::build() const
{ {
return build(replacements_map()); return build(replacements_map());
} }
widget* builder_pane::build(const replacements_map& /*replacements*/) const widget_ptr builder_pane::build(const replacements_map& /*replacements*/) const
{ {
return pane::build(*this); return std::make_shared<pane>(*this);
} }
} // namespace implementation } // namespace implementation

View file

@ -41,27 +41,20 @@ class pane : public widget
public: public:
struct item struct item
{ {
unsigned id; unsigned id;
std::map<std::string, std::string> tags; std::map<std::string, std::string> tags;
grid* item_grid; grid_ptr item_grid;
}; };
typedef std::function<bool(const item&, const item&)> compare_functor_t; typedef std::function<bool(const item&, const item&)> compare_functor_t;
typedef std::function<bool(const item&)> filter_functor_t; typedef std::function<bool(const item&)> filter_functor_t;
/** @deprecated Use the second overload. */ public:
explicit pane(const builder_grid_ptr item_builder);
private:
explicit pane(const implementation::builder_pane& builder); explicit pane(const implementation::builder_pane& builder);
public: /*
static pane* build(const implementation::builder_pane& builder);
/**
* Creates a new item. * Creates a new item.
*/ */
unsigned create_item(const std::map<std::string, string_map>& item_data, unsigned create_item(const std::map<std::string, string_map>& item_data,
@ -195,9 +188,9 @@ struct builder_pane : public builder_widget
{ {
explicit builder_pane(const config& cfg); explicit builder_pane(const config& cfg);
widget* build() const; virtual widget_ptr build() const override;
widget* build(const replacements_map& replacements) const; virtual widget_ptr build(const replacements_map& replacements) const override;
placer_base::tgrow_direction grow_direction; placer_base::tgrow_direction grow_direction;

View file

@ -194,9 +194,9 @@ builder_panel::builder_panel(const config& cfg)
grid = std::make_shared<builder_grid>(c); grid = std::make_shared<builder_grid>(c);
} }
widget* builder_panel::build() const widget_ptr builder_panel::build() const
{ {
panel* widget = new panel(*this); auto widget = std::make_shared<panel>(*this);
DBG_GUI_G << "Window builder: placed panel '" << id << "' with definition '" DBG_GUI_G << "Window builder: placed panel '" << id << "' with definition '"
<< definition << "'.\n"; << definition << "'.\n";

View file

@ -97,7 +97,7 @@ struct builder_panel : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
builder_grid_ptr grid; builder_grid_ptr grid;
}; };

View file

@ -132,9 +132,9 @@ builder_password_box::builder_password_box(const config& cfg)
{ {
} }
widget* builder_password_box::build() const widget_ptr builder_password_box::build() const
{ {
password_box* widget = new password_box(*this); auto widget = std::make_shared<password_box>(*this);
// A password box doesn't have a label but a text. // A password box doesn't have a label but a text.
// It also has no history. // It also has no history.

View file

@ -78,7 +78,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
std::string history_; std::string history_;

View file

@ -144,9 +144,9 @@ builder_progress_bar::builder_progress_bar(const config& cfg)
{ {
} }
widget* builder_progress_bar::build() const widget_ptr builder_progress_bar::build() const
{ {
progress_bar* widget = new progress_bar(*this); auto widget = std::make_shared<progress_bar>(*this);
DBG_GUI_G << "Window builder: placed progress bar '" << id DBG_GUI_G << "Window builder: placed progress bar '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -97,7 +97,7 @@ struct builder_progress_bar : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
}; };
} // namespace implementation } // namespace implementation

View file

@ -243,9 +243,9 @@ builder_repeating_button::builder_repeating_button(const config& cfg)
{ {
} }
widget* builder_repeating_button::build() const widget_ptr builder_repeating_button::build() const
{ {
repeating_button* widget = new repeating_button(*this); auto widget = std::make_shared<repeating_button>(*this);
DBG_GUI_G << "Window builder: placed repeating button '" << id DBG_GUI_G << "Window builder: placed repeating button '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -142,7 +142,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
}; };
} // namespace implementation } // namespace implementation

View file

@ -269,9 +269,9 @@ builder_scroll_label::builder_scroll_label(const config& cfg)
{ {
} }
widget* builder_scroll_label::build() const widget_ptr builder_scroll_label::build() const
{ {
scroll_label* widget = new scroll_label(*this); auto widget = std::make_shared<scroll_label>(*this);
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode); widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode); widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);

View file

@ -138,7 +138,7 @@ struct builder_scroll_label : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;

View file

@ -759,10 +759,9 @@ void scrollbar_container::finalize_setup()
} }
/***** Setup the content *****/ /***** Setup the content *****/
content_ = build_single_widget_instance<spacer>("spacer"); content_ = build_single_widget_and_cast_to<spacer>("spacer");
// TODO: possibly move this unique_ptr casting functionality to a helper function. content_grid_ = std::dynamic_pointer_cast<grid>(get_grid().swap_child("_content_grid", content_, true));
content_grid_.reset(dynamic_cast<grid*>(get_grid().swap_child("_content_grid", content_, true).release()));
assert(content_grid_); assert(content_grid_);
content_grid_->set_parent(this); content_grid_->set_parent(this);

View file

@ -478,10 +478,10 @@ private:
scrollbar_base *vertical_scrollbar_, *horizontal_scrollbar_; scrollbar_base *vertical_scrollbar_, *horizontal_scrollbar_;
/** The grid that holds the content. */ /** The grid that holds the content. */
std::unique_ptr<grid> content_grid_; grid_ptr content_grid_;
/** Dummy spacer to hold the contents location. */ /** Dummy spacer to hold the contents location. */
spacer* content_; std::shared_ptr<spacer> content_;
/** /**
* Cache for the visible area for the content. * Cache for the visible area for the content.

View file

@ -65,7 +65,7 @@ struct scrollbar_container_implementation
W* result = scrollbar_container.container_base::find_at(coordinate, W* result = scrollbar_container.container_base::find_at(coordinate,
must_be_active); must_be_active);
if(result == scrollbar_container.content_) { if(result == scrollbar_container.content_.get()) {
return scrollbar_container.content_grid_->find_at(coordinate, return scrollbar_container.content_grid_->find_at(coordinate,
must_be_active); must_be_active);
} }

View file

@ -149,9 +149,9 @@ builder_scrollbar_panel::builder_scrollbar_panel(const config& cfg)
assert(grid_); assert(grid_);
} }
widget* builder_scrollbar_panel::build() const widget_ptr builder_scrollbar_panel::build() const
{ {
scrollbar_panel* panel = new scrollbar_panel(*this); auto panel = std::make_shared<scrollbar_panel>(*this);
panel->set_vertical_scrollbar_mode(vertical_scrollbar_mode); panel->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
panel->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode); panel->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);
@ -183,7 +183,7 @@ widget* builder_scrollbar_panel::build() const
grid_->col_grow_factor[y]); grid_->col_grow_factor[y]);
} }
widget* widget = grid_->widgets[x * cols + y]->build(); auto widget = grid_->widgets[x * cols + y]->build();
content_grid->set_child(widget, content_grid->set_child(widget,
x, x,
y, y,

View file

@ -85,7 +85,7 @@ struct builder_scrollbar_panel : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;

View file

@ -163,9 +163,9 @@ builder_size_lock::builder_size_lock(const config& cfg)
content_ = create_widget_builder(cfg.child("widget")); content_ = create_widget_builder(cfg.child("widget"));
} }
widget* builder_size_lock::build() const widget_ptr builder_size_lock::build() const
{ {
size_lock* widget = new size_lock(*this); auto widget = std::make_shared<size_lock>(*this);
DBG_GUI_G << "Window builder: placed fixed size widget '" << id << "' with definition '" << definition << "'.\n"; DBG_GUI_G << "Window builder: placed fixed size widget '" << id << "' with definition '" << definition << "'.\n";

View file

@ -68,7 +68,7 @@ private:
* *
* The widget is owned by container_base (the base class). * The widget is owned by container_base (the base class).
*/ */
widget* widget_; widget_ptr widget_;
/** /**
* Finishes the building initialization of the widget. * Finishes the building initialization of the widget.
@ -109,7 +109,7 @@ struct builder_size_lock : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
typed_formula<unsigned> width_; typed_formula<unsigned> width_;
typed_formula<unsigned> height_; typed_formula<unsigned> height_;

View file

@ -450,9 +450,9 @@ builder_slider::builder_slider(const config& cfg)
} }
} }
widget* builder_slider::build() const widget_ptr builder_slider::build() const
{ {
slider* widget = new slider(*this); auto widget = std::make_shared<slider>(*this);
widget->set_best_slider_length(best_slider_length_); widget->set_best_slider_length(best_slider_length_);
widget->set_value_range(minimum_value_, maximum_value_); widget->set_value_range(minimum_value_, maximum_value_);

View file

@ -243,7 +243,7 @@ struct builder_slider : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
unsigned best_slider_length_; unsigned best_slider_length_;

View file

@ -173,9 +173,9 @@ builder_spacer::builder_spacer(const config& cfg)
{ {
} }
widget* builder_spacer::build() const widget_ptr builder_spacer::build() const
{ {
spacer* widget = new spacer(*this, width_, height_); auto widget = std::make_shared<spacer>(*this, width_, height_);
DBG_GUI_G << "Window builder: placed spacer '" << id DBG_GUI_G << "Window builder: placed spacer '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -108,7 +108,7 @@ struct builder_spacer : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
// We store these as strings since they could contain formulas. // We store these as strings since they could contain formulas.

View file

@ -282,9 +282,9 @@ builder_stacked_widget::builder_stacked_widget(const config& real_cfg)
} }
} }
widget* builder_stacked_widget::build() const widget_ptr builder_stacked_widget::build() const
{ {
stacked_widget* widget = new stacked_widget(*this); auto widget = std::make_shared<stacked_widget>(*this);
DBG_GUI_G << "Window builder: placed stacked widget '" << id DBG_GUI_G << "Window builder: placed stacked widget '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -31,7 +31,7 @@ namespace implementation
struct builder_stacked_widget; struct builder_stacked_widget;
} }
class generator_base; using generator_ptr = std::shared_ptr<class generator_base>;
class stacked_widget : public container_base class stacked_widget : public container_base
{ {
@ -143,7 +143,7 @@ private:
* In that case, the generator would not allow the interim state where no layer * In that case, the generator would not allow the interim state where no layer
* before the new chosen layer is reached in the loop. * before the new chosen layer is reached in the loop.
*/ */
generator_base* generator_; generator_ptr generator_;
/** /**
* The number of the current selected layer. * The number of the current selected layer.
@ -200,7 +200,7 @@ struct builder_stacked_widget : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
/** The builders for all layers of the stack .*/ /** The builders for all layers of the stack .*/
std::vector<builder_grid_const_ptr> stack; std::vector<builder_grid_const_ptr> stack;

View file

@ -661,7 +661,7 @@ builder_styled_widget::builder_styled_widget(const config& cfg)
<< "' and definition '" << definition << "'.\n"; << "' and definition '" << definition << "'.\n";
} }
widget* builder_styled_widget::build(const replacements_map& /*replacements*/) const widget_ptr builder_styled_widget::build(const replacements_map& /*replacements*/) const
{ {
return build(); return build();
} }

View file

@ -498,7 +498,7 @@ public:
using builder_widget::build; using builder_widget::build;
virtual widget* build(const replacements_map& replacements) const override; virtual widget_ptr build(const replacements_map& replacements) const override;
/** Parameters for the styled_widget. */ /** Parameters for the styled_widget. */
std::string definition; std::string definition;

View file

@ -485,9 +485,9 @@ builder_text_box::builder_text_box(const config& cfg)
{ {
} }
widget* builder_text_box::build() const widget_ptr builder_text_box::build() const
{ {
text_box* widget = new text_box(*this); auto widget = std::make_shared<text_box>(*this);
// A textbox doesn't have a label but a text // A textbox doesn't have a label but a text
widget->set_value(label_string); widget->set_value(label_string);

View file

@ -318,7 +318,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
std::string history; std::string history;

View file

@ -278,9 +278,9 @@ builder_toggle_button::builder_toggle_button(const config& cfg)
{ {
} }
widget* builder_toggle_button::build() const widget_ptr builder_toggle_button::build() const
{ {
toggle_button* widget = new toggle_button(*this); auto widget = std::make_shared<toggle_button>(*this);
widget->set_icon_name(icon_name_); widget->set_icon_name(icon_name_);
widget->set_retval(get_retval(retval_id_, retval_, id)); widget->set_retval(get_retval(retval_id_, retval_, id));

View file

@ -161,7 +161,7 @@ struct builder_toggle_button : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
std::string icon_name_; std::string icon_name_;

View file

@ -398,9 +398,9 @@ builder_toggle_panel::builder_toggle_panel(const config& cfg)
grid = std::make_shared<builder_grid>(c); grid = std::make_shared<builder_grid>(c);
} }
widget* builder_toggle_panel::build() const widget_ptr builder_toggle_panel::build() const
{ {
toggle_panel* widget = new toggle_panel(*this); auto widget = std::make_shared<toggle_panel>(*this);
widget->set_retval(get_retval(retval_id_, retval_, id)); widget->set_retval(get_retval(retval_id_, retval_, id));

View file

@ -200,7 +200,7 @@ struct builder_toggle_panel : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
builder_grid_ptr grid; builder_grid_ptr grid;

View file

@ -69,13 +69,13 @@ tree_view_node& tree_view::add_node(
int tree_view::remove_node(tree_view_node* node) int tree_view::remove_node(tree_view_node* node)
{ {
assert(node && node != root_node_ && node->parent_node_); assert(node && node != root_node_.get() && node->parent_node_);
const point node_size = node->get_size(); const point node_size = node->get_size();
tree_view_node::node_children_vector& siblings = node->parent_node_->children_; tree_view_node::node_children_vector& siblings = node->parent_node_->children_;
auto node_itor = std::find_if(siblings.begin(), siblings.end(), auto node_itor = std::find_if(siblings.begin(), siblings.end(),
[node](const std::unique_ptr<tree_view_node>& c) { return c.get() == node; } [node](const auto& c) { return c.get() == node; }
); );
assert(node_itor != siblings.end()); assert(node_itor != siblings.end());
@ -375,13 +375,13 @@ builder_tree_view::builder_tree_view(const config& cfg)
VALIDATE(!nodes.empty(), _("No nodes defined for a tree view.")); VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
} }
widget* builder_tree_view::build() const widget_ptr builder_tree_view::build() const
{ {
/* /*
* TODO see how much we can move in the constructor instead of * TODO see how much we can move in the constructor instead of
* building in several steps. * building in several steps.
*/ */
tree_view* widget = new tree_view(*this); auto widget = std::make_shared<tree_view>(*this);
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode); widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode); widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);

View file

@ -125,7 +125,7 @@ private:
bool need_layout_; bool need_layout_;
tree_view_node* root_node_; std::shared_ptr<tree_view_node> root_node_;
tree_view_node* selected_item_; tree_view_node* selected_item_;
@ -197,7 +197,7 @@ struct builder_tree_view : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
scrollbar_container::scrollbar_mode vertical_scrollbar_mode; scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode; scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;

View file

@ -60,7 +60,7 @@ tree_view_node::tree_view_node(
continue; continue;
} }
node_definition.builder->build(&grid_); node_definition.builder->build(grid_);
init_grid(&grid_, data); init_grid(&grid_, data);
if(parent_node_ && parent_node_->toggle_) { if(parent_node_ && parent_node_->toggle_) {

View file

@ -16,6 +16,7 @@
#include "gui/widgets/widget.hpp" #include "gui/widgets/widget.hpp"
#include "gui/widgets/grid.hpp" #include "gui/widgets/grid.hpp"
#include <memory> #include <memory>
namespace gui2 namespace gui2
@ -34,7 +35,8 @@ class tree_view_node : public widget
friend class tree_view; friend class tree_view;
public: public:
using node_children_vector = std::vector<std::unique_ptr<tree_view_node>>; using ptr_t = std::shared_ptr<tree_view_node>;
using node_children_vector = std::vector<ptr_t>;
bool operator==(const tree_view_node& node) bool operator==(const tree_view_node& node)
{ {

View file

@ -587,9 +587,9 @@ builder_unit_preview_pane::builder_unit_preview_pane(const config& cfg)
{ {
} }
widget* builder_unit_preview_pane::build() const widget_ptr builder_unit_preview_pane::build() const
{ {
unit_preview_pane* widget = new unit_preview_pane(*this); auto widget = std::make_shared<unit_preview_pane>(*this);
DBG_GUI_G << "Window builder: placed unit preview pane '" << id DBG_GUI_G << "Window builder: placed unit preview pane '" << id
<< "' with definition '" << definition << "'.\n"; << "' with definition '" << definition << "'.\n";

View file

@ -132,7 +132,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
private: private:
const std::string image_mods_; const std::string image_mods_;

View file

@ -194,9 +194,9 @@ builder_vertical_scrollbar::builder_vertical_scrollbar(const config& cfg)
{ {
} }
widget* builder_vertical_scrollbar::build() const widget_ptr builder_vertical_scrollbar::build() const
{ {
vertical_scrollbar* widget = new vertical_scrollbar(*this); auto widget = std::make_shared<vertical_scrollbar>(*this);
widget->finalize_setup(); widget->finalize_setup();

View file

@ -100,7 +100,7 @@ struct builder_vertical_scrollbar : public builder_styled_widget
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const; virtual widget_ptr build() const override;
}; };
} // namespace implementation } // namespace implementation

View file

@ -62,7 +62,7 @@ struct viewport_implementation
coordinate.x -= viewport->get_x(); coordinate.x -= viewport->get_x();
coordinate.y -= viewport->get_y(); coordinate.y -= viewport->get_y();
return viewport->widget_.find_at(coordinate, must_be_active); return viewport->widget_->find_at(coordinate, must_be_active);
} }
template <class W> template <class W>
@ -72,60 +72,45 @@ struct viewport_implementation
if(viewport->widget::find(id, must_be_active)) { if(viewport->widget::find(id, must_be_active)) {
return viewport; return viewport;
} else { } else {
return viewport->widget_.find(id, must_be_active); return viewport->widget_->find(id, must_be_active);
} }
} }
}; };
viewport::viewport(widget& widget) : widget_(widget), owns_widget_(false)
{
widget_.set_parent(this);
}
viewport::viewport(const implementation::builder_viewport& builder, viewport::viewport(const implementation::builder_viewport& builder,
const builder_widget::replacements_map& replacements) const builder_widget::replacements_map& replacements)
: widget(builder) : widget(builder)
, widget_(*builder.widget_->build(replacements)) , widget_(builder.widget_->build(replacements))
, owns_widget_(true)
{ {
widget_.set_parent(this); widget_->set_parent(this);
} }
viewport::~viewport() viewport::~viewport()
{ {
if(owns_widget_) {
delete &widget_;
}
}
viewport* viewport::build(const implementation::builder_viewport& builder,
const builder_widget::replacements_map& replacements)
{
return new viewport(builder, replacements);
} }
void viewport::place(const point& origin, const point& size) void viewport::place(const point& origin, const point& size)
{ {
widget::place(origin, size); widget::place(origin, size);
widget_.place(point(), widget_.get_best_size()); widget_->place(point(), widget_->get_best_size());
} }
void viewport::layout_initialize(const bool full_initialization) void viewport::layout_initialize(const bool full_initialization)
{ {
widget::layout_initialize(full_initialization); widget::layout_initialize(full_initialization);
if(widget_.get_visible() != widget::visibility::invisible) { if(widget_->get_visible() != widget::visibility::invisible) {
widget_.layout_initialize(full_initialization); widget_->layout_initialize(full_initialization);
} }
} }
void viewport::impl_draw_children() void viewport::impl_draw_children()
{ {
if(widget_.get_visible() != widget::visibility::invisible) { if(widget_->get_visible() != widget::visibility::invisible) {
widget_.draw_background(); widget_->draw_background();
widget_.draw_children(); widget_->draw_children();
widget_.draw_foreground(); widget_->draw_foreground();
} }
} }
@ -157,7 +142,7 @@ const widget* viewport::find(const std::string& id, const bool must_be_active)
point viewport::calculate_best_size() const point viewport::calculate_best_size() const
{ {
return widget_.get_best_size(); return widget_->get_best_size();
} }
bool viewport::disable_click_dismiss() const bool viewport::disable_click_dismiss() const
@ -211,14 +196,14 @@ builder_viewport::builder_viewport(const config& cfg)
{ {
} }
widget* builder_viewport::build() const widget_ptr builder_viewport::build() const
{ {
return build(replacements_map()); return build(replacements_map());
} }
widget* builder_viewport::build(const replacements_map& replacements) const widget_ptr builder_viewport::build(const replacements_map& replacements) const
{ {
return viewport::build(*this, replacements); return std::make_shared<viewport>(*this, replacements);
} }
} // namespace implementation } // namespace implementation

View file

@ -34,17 +34,9 @@ class viewport : public widget
friend struct viewport_implementation; friend struct viewport_implementation;
public: public:
/** @deprecated use the second overload. */
explicit viewport(widget& widget);
private:
viewport(const implementation::builder_viewport& builder, viewport(const implementation::builder_viewport& builder,
const builder_widget::replacements_map& replacements); const builder_widget::replacements_map& replacements);
public:
static viewport* build(const implementation::builder_viewport& builder,
const builder_widget::replacements_map& replacements);
~viewport(); ~viewport();
/** See @ref widget::place. */ /** See @ref widget::place. */
@ -86,9 +78,7 @@ public:
virtual iteration::walker_base* create_walker() override; virtual iteration::walker_base* create_walker() override;
private: private:
widget& widget_; widget_ptr widget_;
bool owns_widget_;
}; };
// }---------- BUILDER -----------{ // }---------- BUILDER -----------{
@ -100,9 +90,9 @@ struct builder_viewport : public builder_widget
{ {
explicit builder_viewport(const config& cfg); explicit builder_viewport(const config& cfg);
widget* build() const; virtual widget_ptr build() const override;
widget* build(const replacements_map& replacements) const; virtual widget_ptr build(const replacements_map& replacements) const override;
builder_widget_ptr widget_; builder_widget_ptr widget_;
}; };

View file

@ -728,4 +728,6 @@ public:
virtual iteration::walker_base* create_walker() = 0; virtual iteration::walker_base* create_walker() = 0;
}; };
using widget_ptr = std::shared_ptr<widget>;
} // namespace gui2 } // namespace gui2

View file

@ -16,13 +16,12 @@
#include "gui/auxiliary/find_widget.hpp" #include "gui/auxiliary/find_widget.hpp"
#include "gui/widgets/grid.hpp" #include "gui/widgets/grid.hpp"
#include "gui/widgets/widget.hpp"
#include <cassert> #include <cassert>
namespace gui2 namespace gui2
{ {
void swap_grid(grid* g, grid* content_grid, widget* widget, const std::string& id) void swap_grid(grid* g, grid* content_grid,widget_ptr widget, const std::string& id)
{ {
assert(content_grid); assert(content_grid);
assert(widget); assert(widget);

View file

@ -14,15 +14,16 @@
#pragma once #pragma once
#include "gui/widgets/widget.hpp"
#include <string> #include <string>
namespace gui2 namespace gui2
{ {
class grid; class grid;
class widget;
/** /**
* Swaps an item in a grid for another one. * Swaps an item in a grid for another one.
*/ */
void swap_grid(grid* g, grid* content_grid, widget* widget, const std::string& id); void swap_grid(grid* g, grid* content_grid, widget_ptr widget, const std::string& id);
} }

View file

@ -98,7 +98,7 @@ public:
using builder_styled_widget::build; using builder_styled_widget::build;
widget* build() const virtual widget_ptr build() const override
{ {
return nullptr; return nullptr;
} }
@ -948,7 +948,7 @@ namespace
*/ */
void window_swap_grid(grid* g, void window_swap_grid(grid* g,
grid* content_grid, grid* content_grid,
widget* widget, widget_ptr widget,
const std::string& id) const std::string& id)
{ {
assert(content_grid); assert(content_grid);