Let widgets register themselves automatically.

This commit is contained in:
Mark de Wever 2010-03-30 21:56:16 +00:00
parent 8cb8138d40
commit 491b675ff7
25 changed files with 285 additions and 64 deletions

View file

@ -17,6 +17,7 @@
#include "gui/widgets/button.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/button.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "sound.hpp"
@ -28,6 +29,8 @@
namespace gui2 {
REGISTER_WIDGET(button)
tbutton::tbutton()
: tcontrol(COUNT)
, tclickable_()

View file

@ -16,10 +16,15 @@
#include "gui/widgets/horizontal_scrollbar.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/auxiliary/widget_definition/horizontal_scrollbar.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(horizontal_scrollbar)
unsigned thorizontal_scrollbar::minimum_positioner_length() const
{
boost::intrusive_ptr

View file

@ -17,13 +17,19 @@
#include "gui/widgets/image.hpp"
#include "../../image.hpp"
#include "gui/auxiliary/widget_definition/image.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
namespace gui2 {
REGISTER_WIDGET(image)
tpoint timage::calculate_best_size() const
{
surface image(image::get_image(image::locator(label())));

View file

@ -16,9 +16,15 @@
#include "gui/widgets/label.hpp"
#include "gui/auxiliary/widget_definition/label.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(label)
void tlabel::set_state(const tstate state)
{
if(state != state_) {

View file

@ -18,14 +18,22 @@
#include "gui/auxiliary/layout_exception.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/listbox.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include <boost/bind.hpp>
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
namespace gui2 {
REGISTER_WIDGET(listbox)
namespace {
// in seperate namespace to avoid name classes
REGISTER_WIDGET3(tlistbox_definition, "horizontal_listbox", _4)
void callback_list_item_clicked(twidget* caller)
{

View file

@ -17,10 +17,14 @@
#include "gui/widgets/minimap.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/minimap.hpp"
#include "gui/widgets/settings.hpp"
#include "map.hpp"
#include "map_exception.hpp"
#include "../../minimap.hpp"
#include <boost/bind.hpp>
#include <algorithm>
static lg::log_domain log_config("config");
@ -34,6 +38,8 @@ static lg::log_domain log_config("config");
namespace gui2 {
REGISTER_WIDGET(minimap)
/** Key type for the cache. */
struct tkey
{

View file

@ -16,10 +16,15 @@
#include "gui/widgets/multi_page.hpp"
#include "gui/auxiliary/widget_definition/multi_page.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/generator.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(multi_page)
tmulti_page::tmulti_page()
: tcontainer_(0)
, generator_(NULL)

View file

@ -18,12 +18,17 @@
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/panel.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
namespace gui2 {
REGISTER_WIDGET(panel)
SDL_Rect tpanel::get_client_rect() const
{
boost::intrusive_ptr<const tpanel_definition::tresolution> conf =

View file

@ -18,13 +18,19 @@
#include "gui/widgets/password_box.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/text_box.hpp"
#include "gui/widgets/settings.hpp"
#include "serialization/string_utils.hpp"
#include <boost/bind.hpp>
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
namespace gui2 {
REGISTER_WIDGET3(ttext_box_definition, "password_box", "text_box_definition")
namespace {
size_t get_text_length(const std::string& str)

View file

@ -18,6 +18,7 @@
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/timer.hpp"
#include "gui/auxiliary/widget_definition/repeating_button.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "sound.hpp"
@ -29,6 +30,8 @@
namespace gui2 {
REGISTER_WIDGET(repeating_button)
trepeating_button::trepeating_button()
: tcontrol(COUNT)
, tclickable_()

View file

@ -18,6 +18,8 @@
#include "gui/widgets/label.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/scroll_label.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/scrollbar.hpp"
#include "gui/widgets/spacer.hpp"
#include "gui/widgets/window.hpp"
@ -29,6 +31,8 @@
namespace gui2 {
REGISTER_WIDGET(scroll_label)
tscroll_label::tscroll_label()
: tscrollbar_container(COUNT)
, state_(ENABLED)

View file

@ -16,8 +16,15 @@
#include "gui/widgets/scrollbar_panel.hpp"
#include "gui/auxiliary/widget_definition/scrollbar_panel.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(scrollbar_panel)
const std::string& tscrollbar_panel::get_control_type() const
{
static const std::string type = "scrollbar_panel";

View file

@ -27,32 +27,11 @@
#include "foreach.hpp"
#include "gettext.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/button.hpp"
#include "gui/auxiliary/widget_definition/horizontal_scrollbar.hpp"
#include "gui/auxiliary/widget_definition/image.hpp"
#include "gui/auxiliary/widget_definition/label.hpp"
#include "gui/auxiliary/widget_definition/listbox.hpp"
#include "gui/auxiliary/widget_definition/minimap.hpp"
#include "gui/auxiliary/widget_definition/multi_page.hpp"
#include "gui/auxiliary/widget_definition/panel.hpp"
#include "gui/auxiliary/widget_definition/repeating_button.hpp"
#include "gui/auxiliary/widget_definition/scroll_label.hpp"
#include "gui/auxiliary/widget_definition/scrollbar_panel.hpp"
#include "gui/auxiliary/widget_definition/slider.hpp"
#include "gui/auxiliary/widget_definition/spacer.hpp"
#include "gui/auxiliary/widget_definition/stacked_widget.hpp"
#include "gui/auxiliary/widget_definition/text_box.hpp"
#include "gui/auxiliary/widget_definition/toggle_button.hpp"
#include "gui/auxiliary/widget_definition/toggle_panel.hpp"
#include "gui/auxiliary/widget_definition/tooltip.hpp"
#include "gui/auxiliary/widget_definition/tree_view.hpp"
#include "gui/auxiliary/widget_definition/vertical_scrollbar.hpp"
#include "gui/widgets/window.hpp"
#include "serialization/parser.hpp"
#include "serialization/preprocessor.hpp"
#include "formula_string_utils.hpp"
namespace gui2 {
bool new_widgets = false;
@ -77,8 +56,6 @@ namespace settings {
} // namespace settings
namespace {
/**
* Returns the list of registered windows.
*
@ -90,6 +67,20 @@ static std::vector<std::string>& registered_window_types()
return result;
}
typedef std::map<
std::string
, boost::function<void(
tgui_definition&
, const std::string&
, const config&
, const char *key)> > tregistered_widget_type;
static tregistered_widget_type& registred_widget_type()
{
static tregistered_widget_type result;
return result;
}
struct tgui_definition
{
tgui_definition()
@ -127,10 +118,11 @@ struct tgui_definition
std::map<std::string, twindow_definition> windows;
std::map<std::string, twindow_builder> window_types;
void load_widget_definitions(
const std::string& definition_type
, const std::vector<tcontrol_definition_ptr>& definitions);
private:
template<class T>
void load_definitions(const std::string& definition_type,
const config &cfg, const char *key = NULL);
unsigned popup_show_delay_;
unsigned popup_show_time_;
@ -260,31 +252,17 @@ const std::string& tgui_definition::read(const config& cfg)
DBG_GUI_P << "Parsing gui " << id << '\n';
/***** Control definitions *****/
load_definitions<tbutton_definition>("button", cfg);
// share the definition of the normal listbox.
load_definitions<tlistbox_definition>("horizontal_listbox", cfg);
load_definitions<thorizontal_scrollbar_definition>("horizontal_scrollbar", cfg);
load_definitions<timage_definition>("image", cfg);
load_definitions<tlabel_definition>("label", cfg);
load_definitions<tlistbox_definition>("listbox", cfg);
load_definitions<tminimap_definition>("minimap", cfg);
load_definitions<tmulti_page_definition>("multi_page", cfg);
load_definitions<tstacked_widget_definition>("stacked_widget", cfg);
load_definitions<tpanel_definition>("panel", cfg);
load_definitions<trepeating_button_definition>("repeating_button", cfg);
load_definitions<tscroll_label_definition>("scroll_label", cfg);
load_definitions<tscrollbar_panel_definition>("scrollbar_panel", cfg);
load_definitions<tslider_definition>("slider", cfg);
load_definitions<tspacer_definition>("spacer", cfg);
load_definitions<ttext_box_definition>("text_box", cfg);
// use the same definition for password boxes
load_definitions<ttext_box_definition>("password_box", cfg, "text_box_definition");
load_definitions<ttoggle_button_definition>("toggle_button", cfg);
load_definitions<ttoggle_panel_definition>("toggle_panel", cfg);
load_definitions<ttooltip_definition>("tooltip", cfg);
load_definitions<ttree_view_definition>("tree_view", cfg);
load_definitions<tvertical_scrollbar_definition>("vertical_scrollbar", cfg);
load_definitions<twindow_definition>("window", cfg);
typedef std::pair<
const std::string
, boost::function<void(
tgui_definition&
, const std::string&
, const config&
, const char *key)> > thack;
foreach(thack& widget_type, registred_widget_type()) {
widget_type.second(*this, widget_type.first, cfg, NULL);
}
/***** Window types *****/
foreach (const config &w, cfg.child_range("window")) {
@ -388,29 +366,31 @@ void tgui_definition::activate() const
settings::sound_slider_adjust = sound_slider_adjust_;
}
template<class T>
void tgui_definition::load_definitions(
const std::string &definition_type, const config &cfg, const char *key)
void tgui_definition::load_widget_definitions(
const std::string& definition_type
, const std::vector<tcontrol_definition_ptr>& definitions)
{
foreach (const config &d, cfg.child_range(key ? key : definition_type + "_definition"))
{
T* def = new T(d);
foreach(const tcontrol_definition_ptr& def, definitions) {
// We assume all definitions are unique if not we would leak memory.
assert(control_definition[definition_type].find(def->id)
== control_definition[definition_type].end());
== control_definition[definition_type].end());
control_definition[definition_type].insert(std::make_pair(def->id, def));
control_definition[definition_type]
.insert(std::make_pair(def->id, def));
}
utils::string_map symbols;
symbols["definition"] = definition_type;
symbols["id"] = "default";
t_string msg(vgettext(
"Widget definition '$definition' doesn't contain the definition for '$id'.",
symbols));
"Widget definition '$definition' "
"doesn't contain the definition for '$id'."
, symbols));
VALIDATE(control_definition[definition_type].find("default")
!= control_definition[definition_type].end(), msg);
!= control_definition[definition_type].end(), msg);
}
/** Map with all known windows, (the builder class builds a window). */
@ -422,8 +402,6 @@ void tgui_definition::load_definitions(
/** Points to the current gui. */
std::map<std::string, tgui_definition>::const_iterator current_gui = guis.end();
} // namespace
void register_window(const std::string& id)
{
const std::vector<std::string>::iterator itor = std::find(
@ -494,6 +472,25 @@ tstate_definition::tstate_definition(const config &cfg) :
canvas.set_cfg(draw);
}
void register_widget(const std::string& id
, boost::function<void(
tgui_definition& gui_definition
, const std::string& definition_type
, const config& cfg
, const char *key)> functor)
{
registred_widget_type().insert(std::make_pair(id, functor));
}
void load_widget_definitions(
tgui_definition& gui_definition
, const std::string& definition_type
, const std::vector<tcontrol_definition_ptr>& definitions)
{
DBG_GUI_P << "Load definition '" << definition_type << "'.\n";
gui_definition.load_widget_definitions(definition_type, definitions);
}
tresolution_definition_ptr get_control(
const std::string& control_type, const std::string& definition)
{

View file

@ -22,11 +22,15 @@
#include "gui/auxiliary/widget_definition/window.hpp"
#include <boost/function.hpp>
#include <string>
#include <vector>
namespace gui2 {
class tgui_definition;
/** Do we wish to use the new library or not. */
extern bool new_widgets;
@ -46,6 +50,73 @@ extern bool new_widgets;
*/
void register_window(const std::string& id);
/**
* Registers a widgets.
*
* This function registers the available widgets defined in WML. All widgets
* need to register themselves before @ref gui2::init) is called.
*
* @warning This function runs before @ref main() so needs to be careful
* regarding the static initialization problem.
*
* @param id The id of the widget to register.
* @param functor The function to load the definitions.
*/
void register_widget(const std::string& id
, boost::function<void(
tgui_definition& gui_definition
, const std::string& definition_type
, const config& cfg
, const char *key)> functor);
/**
* Loads the definitions of a widget.
*
* @param gui_definition The gui definition the widget definition
* belongs to.
* @param definition_type The type of the widget whose definitions are
* to be loaded.
* @param definitions The definitions serialized from a config
* object.
*/
void load_widget_definitions(
tgui_definition& gui_definition
, const std::string& definition_type
, const std::vector<tcontrol_definition_ptr>& definitions);
/**
* Loads the definitions of a widget.
*
* This function is templated and kept small so only loads the definitions from
* the config and then lets the real job be done by the @ref
* load_widget_definitions above.
*
* @param gui_definition The gui definition the widget definition
* belongs to.
* @param definition_type The type of the widget whose definitions are
* to be loaded.
* @param config The config to serialiaze the definitions
* from.
* @param key Optional id of the definition to load.
*/
template<class T>
void load_widget_definitions(
tgui_definition& gui_definition
, const std::string& definition_type
, const config& cfg
, const char *key)
{
std::vector<tcontrol_definition_ptr> definitions;
foreach(const config& definition
, cfg.child_range(key ? key : definition_type + "_definition")) {
definitions.push_back(new T(definition));
}
load_widget_definitions(gui_definition, definition_type, definitions);
}
tresolution_definition_ptr get_control(
const std::string& control_type, const std::string& definition);

View file

@ -23,11 +23,15 @@
#include "gui/widgets/settings.hpp"
#include "sound.hpp"
#include <boost/bind.hpp>
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
namespace gui2 {
REGISTER_WIDGET(slider)
static int distance(const int a, const int b)
{
/**

View file

@ -16,8 +16,15 @@
#include "gui/widgets/spacer.hpp"
#include "gui/auxiliary/widget_definition/spacer.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(spacer)
const std::string& tspacer::get_control_type() const
{
static const std::string type = "spacer";

View file

@ -17,10 +17,16 @@
#include "gui/widgets/stacked_widget.hpp"
#include "foreach.hpp"
#include "gui/auxiliary/widget_definition/stacked_widget.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/generator.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(stacked_widget)
tstacked_widget::tstacked_widget()
: tcontainer_(1)
, generator_(NULL)

View file

@ -20,6 +20,7 @@
#include "foreach.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/text_box.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "game_preferences.hpp"
@ -30,6 +31,8 @@
namespace gui2 {
REGISTER_WIDGET(text_box)
ttext_history ttext_history::get_history(const std::string& id, const bool enabled)
{
std::vector<std::string>* vec = preferences::get_history(id);

View file

@ -18,6 +18,7 @@
#include "foreach.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/toggle_button.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "sound.hpp"
@ -29,6 +30,8 @@
namespace gui2 {
REGISTER_WIDGET(toggle_button)
ttoggle_button::ttoggle_button()
: tcontrol(COUNT)
, state_(ENABLED)

View file

@ -30,6 +30,8 @@
namespace gui2 {
REGISTER_WIDGET(toggle_panel)
ttoggle_panel::ttoggle_panel()
: tpanel(COUNT)
, state_(ENABLED)

View file

@ -16,8 +16,15 @@
#include "gui/widgets/tooltip.hpp"
#include "gui/auxiliary/widget_definition/tooltip.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(tooltip)
const std::string& ttooltip::get_control_type() const
{
static const std::string type = "tooltip";

View file

@ -17,6 +17,8 @@
#include "gui/widgets/tree_view.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/tree_view.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/tree_view_node.hpp"
#include "gui/widgets/window.hpp"
@ -27,6 +29,8 @@
namespace gui2 {
REGISTER_WIDGET(tree_view)
ttree_view::ttree_view(const std::vector<tnode_definition>& node_definitions)
: tscrollbar_container(2)
, node_definitions_(node_definitions)

View file

@ -17,9 +17,14 @@
#include "gui/widgets/vertical_scrollbar.hpp"
#include "gui/auxiliary/widget_definition/vertical_scrollbar.hpp"
#include "gui/widgets/settings.hpp"
#include <boost/bind.hpp>
namespace gui2 {
REGISTER_WIDGET(vertical_scrollbar)
unsigned tvertical_scrollbar::minimum_positioner_length() const
{
boost::intrusive_ptr<const tvertical_scrollbar_definition::tresolution> conf =

View file

@ -748,5 +748,51 @@ T& find_widget(typename tconst_duplicator<T, twidget>::type* widget
} // namespace gui2
/**
* Registers a widget.
*
* Call this function to register a widget. Use this macro in the
* implementation, inside the gui2 namespace.
*
* @see @ref load_widget_definitions for more information.
*
* @note When the type is tfoo_definition, the id "foo" and no special key best
* use RESISTER_WIDGET(foo) instead.
*
* @param type Class type of the window to register.
* @param id Id of the widget
* @param key The id to load if differs from id.
*/
#define REGISTER_WIDGET3( \
type \
, id \
, key) \
namespace { \
\
namespace ns_##type { \
\
struct tregister_helper { \
tregister_helper() \
{ \
register_widget(id, boost::bind( \
load_widget_definitions<type> \
, _1 \
, _2 \
, _3 \
, key)); \
} \
}; \
\
static tregister_helper register_helper; \
} \
}
/**
* Wrapper for REGISTER_WIDGET3.
*
* "Calls" REGISTER_WINDOW3(tid_definition, "id", _4)
*/
#define REGISTER_WIDGET(id) REGISTER_WIDGET3(t##id##_definition, #id, _4)
#endif

View file

@ -50,6 +50,8 @@
namespace gui2{
REGISTER_WIDGET(window)
unsigned twindow::sunset_ = 0;
namespace {