diff --git a/projectfiles/VC12/wesnoth.vcxproj b/projectfiles/VC12/wesnoth.vcxproj index 5305f1f00a863..7594c6acb3dd7 100644 --- a/projectfiles/VC12/wesnoth.vcxproj +++ b/projectfiles/VC12/wesnoth.vcxproj @@ -2581,6 +2581,14 @@ $(IntDir)Gui\Widgets\ $(IntDir)Gui\Widgets\ + + $(IntDir)Gui\Widgets + $(IntDir)Gui\Widgets + $(IntDir)Gui\Widgets + $(IntDir)Gui\Widgets + $(IntDir)Gui\Widgets + $(IntDir)Gui\Widgets + $(IntDir)Gui\Widgets\ $(IntDir)Gui\Widgets\ @@ -4344,6 +4352,7 @@ + diff --git a/projectfiles/VC12/wesnoth.vcxproj.filters b/projectfiles/VC12/wesnoth.vcxproj.filters index 194e8970eb663..335cb786e3597 100644 --- a/projectfiles/VC12/wesnoth.vcxproj.filters +++ b/projectfiles/VC12/wesnoth.vcxproj.filters @@ -1558,6 +1558,9 @@ Font + + Gui\Widgets + @@ -3017,6 +3020,9 @@ Font + + Gui\Widgets + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf31d70a5641b..6f29f6061d532 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -536,6 +536,7 @@ set(wesnoth-gui_widget_SRC gui/widgets/scrollbar_container.cpp gui/widgets/scrollbar_panel.cpp gui/widgets/settings.cpp + gui/widgets/size_fixater.cpp gui/widgets/slider.cpp gui/widgets/spacer.cpp gui/widgets/stacked_widget.cpp diff --git a/src/SConscript b/src/SConscript index 3bf33f508c436..7c0199bdbe8fe 100644 --- a/src/SConscript +++ b/src/SConscript @@ -466,6 +466,7 @@ wesnoth_sources = Split(""" gui/widgets/scrollbar_panel.cpp gui/widgets/scrollbar.cpp gui/widgets/settings.cpp + gui/widgets/size_fixater.cpp gui/widgets/slider.cpp gui/widgets/spacer.cpp gui/widgets/stacked_widget.cpp diff --git a/src/gui/widgets/container.hpp b/src/gui/widgets/container.hpp index 3871ce3949916..6259e1042870d 100644 --- a/src/gui/widgets/container.hpp +++ b/src/gui/widgets/container.hpp @@ -85,7 +85,7 @@ class tcontainer_ : public tcontrol /** See @ref twidget::demand_reduce_height. */ virtual void demand_reduce_height(const unsigned maximum_height) override; -private: +protected: /** See @ref twidget::calculate_best_size. */ virtual tpoint calculate_best_size() const override; diff --git a/src/gui/widgets/size_fixater.cpp b/src/gui/widgets/size_fixater.cpp new file mode 100644 index 0000000000000..a1b1081773d05 --- /dev/null +++ b/src/gui/widgets/size_fixater.cpp @@ -0,0 +1,148 @@ +/* + Copyright (C) 2016 Jyrki Vesterinen + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#define GETTEXT_DOMAIN "wesnoth-lib" + +#include "size_fixater.hpp" + +#include +#include +#include +#include +#include + +namespace gui2 +{ + +REGISTER_WIDGET(size_fixater) + +void tsize_fixater::layout_children() +{ + assert(generator_ != nullptr); + assert(generator_->get_item_count() == 1); + + generator_->item(0).layout_children(); +} + +void tsize_fixater::finalize(tbuilder_grid_const_ptr widget_builder) +{ + assert(generator_ != nullptr); + + generator_->create_item(-1, widget_builder, string_map(), nullptr); + + static const std::string id = "_content_grid"; + grid().set_id(id); + twidget* old_grid = grid().swap_child(id, generator_, true); + delete old_grid; +} + +tsize_fixater_definition::tsize_fixater_definition(const config& cfg) : + tcontrol_definition(cfg) +{ + DBG_GUI_P << "Parsing fixed size widget " << id << '\n'; + + load_resolutions(cfg); +} + +/*WIKI + * @page = GUIWidgetDefinitionWML + * @order = 1_size_fixater + * + * == Size fixater == + * + * A size fixater contains one child widget and forces it to have the specified size. + * This can be used, for example, when there are two list boxes in different rows of + * the same grid and it's desired that only one list box changes size when its + * contents change. + * + * A size fixater has no states. + * @begin{parent}{name="gui/"} + * @begin{tag}{name="size_fixater_definition"}{min=0}{max=-1}{super="generic/widget_definition"} + * @end{tag}{name="size_fixater_definition"} + * @end{tag}{name="gui/"} + */ +tsize_fixater_definition::tresolution::tresolution(const config& cfg) : + tresolution_definition_(cfg), grid(nullptr) +{ + const config& child = cfg.child("grid"); + VALIDATE(child, _("No grid defined.")); + + grid = std::make_shared(child); +} + +/*WIKI + * @page = GUIWidgetInstanceWML + * @order = 2_size_fixater + * @begin{parent}{name="gui/window/resolution/grid/row/column/"} + * @begin{tag}{name="size_fixater"}{min=0}{max=-1}{super="generic/widget_instance"} + * == Size fixater == + * + * A size fixater contains one child widget and forces it to have the specified size. + * This can be used, for example, when there are two list boxes in different rows of + * the same grid and it's desired that only one list box changes size when its + * contents change. + * + * @begin{table}{config} + * widget & section & mandatory & The widget. $ + * width & f_unsigned & mandatory & The width of the widget. $ + * height & f_unsigned & mandatory & The height of the widget. $ + * @end{table} + * + * The variables available are the same as for window resolution, see + * [[GuiToolkitWML#Resolution_2]] for the list of items. + * @end{tag}{name="size_fixater"} + * @end{parent}{name="gui/window/resolution/grid/row/column/"} + */ + +namespace implementation +{ + +tbuilder_size_fixater::tbuilder_size_fixater(const config& cfg) : + tbuilder_control(cfg), width_(cfg["width"]), height_(cfg["height"]), content_(nullptr) +{ + VALIDATE(cfg.has_child("widget"), _("No widget defined.")); + content_ = std::make_shared(cfg.child("widget")); +} + +twidget* tbuilder_size_fixater::build() const +{ + tsize_fixater* widget = new tsize_fixater(); + + init_control(widget); + + DBG_GUI_G << "Window builder: placed fixed size widget '" << id << + "' with definition '" << definition << "'.\n"; + + auto conf = std::static_pointer_cast(widget->config()); + assert(conf != nullptr); + + widget->init_grid(conf->grid); + + game_logic::map_formula_callable size = get_screen_size_variables(); + + const unsigned width = width_(size); + const unsigned height = height_(size); + + VALIDATE(width > 0 && height > 0, _("Invalid size.")); + + widget->set_size(tpoint(width, height)); + + widget->finalize(content_); + + return widget; +} + +} + +} \ No newline at end of file diff --git a/src/gui/widgets/size_fixater.hpp b/src/gui/widgets/size_fixater.hpp new file mode 100644 index 0000000000000..10f511d0e8ade --- /dev/null +++ b/src/gui/widgets/size_fixater.hpp @@ -0,0 +1,136 @@ +/* + Copyright (C) 2016 Jyrki Vesterinen + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#ifndef GUI_WIDGETS_SIZE_FIXATER_HPP_INCLUDED +#define GUI_WIDGETS_SIZE_FIXATER_HPP_INCLUDED + +#include + +#include +#include +#include +#include + +namespace gui2 +{ + + namespace implementation + { + struct tbuilder_size_fixater; + } + + /* A fixed-size widget that wraps an arbitrary widget and forces it to the given size. */ + + class tsize_fixater : public tcontainer_ + { + friend struct implementation::tbuilder_size_fixater; + + public: + tsize_fixater() : + tcontainer_(1), + generator_( + tgenerator_::build(false, false, tgenerator_::independent, false)) + {} + + /** See @ref tcontrol::get_active. */ + bool get_active() const override + { + return true; + } + + /** See @ref tcontrol::get_state. */ + unsigned get_state() const override + { + return 0; + } + + /** See @ref twidget::layout_children. */ + void layout_children() override; + + void set_size(const tpoint& size) + { + size_ = size; + } + + protected: + tpoint calculate_best_size() const override + { + return size_; + } + + private: + tpoint size_; + + /** + * Contains a pointer to the generator. + * + * The pointer is not owned by this class, it's stored in the content_grid_ + * of the tcontainer_ base class and freed when its grid is freed. + */ + tgenerator_* generator_; + + /** + * Finishes the building initialization of the widget. + * + * @param widget_builder The builder to build the contents of the + * widget. + */ + void finalize(tbuilder_grid_const_ptr widget_builder); + + /** See @ref tcontrol::get_control_type. */ + const std::string& get_control_type() const override + { + static const std::string control_type = "size_fixater"; + return control_type; + } + + /** See @ref tcontainer_::set_self_active. */ + void set_self_active(const bool) override + { + // DO NOTHING + } + }; + + struct tsize_fixater_definition : public tcontrol_definition + { + explicit tsize_fixater_definition(const config& cfg); + + struct tresolution : public tresolution_definition_ + { + explicit tresolution(const config& cfg); + + tbuilder_grid_ptr grid; + }; + }; + + namespace implementation + { + + struct tbuilder_size_fixater : public tbuilder_control + { + explicit tbuilder_size_fixater(const config& cfg); + + using tbuilder_control::build; + + twidget* build() const; + + private: + tbuilder_grid_const_ptr content_; + tformula width_; + tformula height_; + }; + } +} + +#endif \ No newline at end of file diff --git a/src/gui/widgets/stacked_widget.cpp b/src/gui/widgets/stacked_widget.cpp index 842f2197f8b91..efe1a91165476 100644 --- a/src/gui/widgets/stacked_widget.cpp +++ b/src/gui/widgets/stacked_widget.cpp @@ -16,11 +16,11 @@ #include "gui/widgets/stacked_widget.hpp" -#include "gui/auxiliary/find_widget.hpp" #include "gui/core/register_widget.hpp" #include "gui/widgets/settings.hpp" #include "gui/widgets/generator.hpp" #include "gettext.hpp" +#include "wml_exception.hpp" #include "utils/functional.hpp" @@ -57,42 +57,6 @@ void tstacked_widget::layout_children() } } -namespace -{ - -/** - * Swaps an item in a grid for another one.*/ -void swap_grid(tgrid* grid, - tgrid* content_grid, - twidget* widget, - const std::string& id) -{ - assert(content_grid); - assert(widget); - - // Make sure the new child has same id. - widget->set_id(id); - - // Get the container containing the wanted widget. - tgrid* parent_grid = nullptr; - if(grid) { - parent_grid = find_widget(grid, id, false, false); - } - if(!parent_grid) { - parent_grid = find_widget(content_grid, id, true, false); - } - parent_grid = dynamic_cast(parent_grid->parent()); - assert(parent_grid); - - // Replace the child. - widget = parent_grid->swap_child(id, widget, false); - assert(widget); - - delete widget; -} - -} // namespace - void tstacked_widget::finalize(std::vector widget_builder) { @@ -102,7 +66,11 @@ tstacked_widget::finalize(std::vector widget_builder) { generator_->create_item(-1, builder, empty_data, nullptr); } - swap_grid(nullptr, &grid(), generator_, "_content_grid"); + + static const std::string id = "_content_grid"; + grid().set_id(id); + twidget* old_grid = grid().swap_child(id, generator_, true); + delete old_grid; select_layer(-1); }