The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
window_builder.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-lib"
17
19
21#include "gettext.hpp"
22#include "gui/core/log.hpp"
27#include "gui/widgets/pane.hpp"
30#include "wml_exception.hpp"
31
32#include <functional>
33
34namespace gui2
35{
37 : id(cfg["id"])
38 , linked_group(cfg["linked_group"])
39 , debug_border_mode(widget::debug_border::none)
40 , debug_border_color(color_t::from_rgba_string(cfg["debug_border_color"].str()))
41{
42 // TODO: move to a `decode` function?
43 switch(const int dbm = cfg["debug_border_mode"].to_int(0); dbm) {
44 case 0:
46 break;
47 case 1:
49 break;
50 case 2:
52 break;
53 default:
54 WRN_GUI_P << "Widget builder: unknown debug border mode " << dbm << ".";
55 }
56}
57
59{
60 VALIDATE(cfg.all_children_count() == 1, "Grid cell does not have exactly 1 child.");
61 auto [widget_key, widget_cfg] = *cfg.ordered_begin();
62
63 if(widget_key == "grid") {
64 return std::make_shared<builder_grid>(widget_cfg);
65 }
66
67 if(widget_key == "instance") {
68 return std::make_shared<implementation::builder_instance>(widget_cfg);
69 }
70
71 if(widget_key == "pane") {
72 return std::make_shared<implementation::builder_pane>(widget_cfg);
73 }
74
75 if(widget_key == "viewport") {
76 return std::make_shared<implementation::builder_viewport>(widget_cfg);
77 }
78
79 for(const auto& [type, builder] : widget_builder_lookup()) {
80 if(type == "window" || type == "tooltip") {
81 continue;
82 }
83
84 if(widget_key == type) {
85 return builder(widget_cfg);
86 }
87 }
88
89 // FAIL() doesn't return
90 //
91 // To fix this: add your new widget to source-lists/libwesnoth_widgets and rebuild.
92
93 FAIL("Unknown widget type " + widget_key);
94}
95
96std::unique_ptr<widget> build_single_widget_instance_helper(const std::string& type, const config& cfg)
97{
98 const auto& iter = widget_builder_lookup().find(type);
99 VALIDATE(iter != widget_builder_lookup().end(), "Invalid widget type '" + type + "'");
100
101 widget_builder_func_t& builder = iter->second;
102 return builder(cfg)->build();
103}
104
106{
107 VALIDATE(!id_.empty(), missing_mandatory_wml_key("window", "id"));
108 VALIDATE(!description_.empty(), missing_mandatory_wml_key("window", "description"));
109
110 DBG_GUI_P << "Window builder: reading data for window " << id_ << ".";
111
112 config::const_child_itors cfgs = cfg.child_range("resolution");
113 VALIDATE(!cfgs.empty(), _("No resolution defined for ") + id_);
114
115 for(const auto& i : cfgs) {
116 resolutions.emplace_back(i);
117 }
118}
119
121 : window_width(cfg["window_width"].to_unsigned())
122 , window_height(cfg["window_height"].to_unsigned())
123 , automatic_placement(cfg["automatic_placement"].to_bool(true))
124 , x(cfg["x"])
125 , y(cfg["y"])
126 , width(cfg["width"])
127 , height(cfg["height"])
128 , reevaluate_best_size(cfg["reevaluate_best_size"])
129 , functions()
130 , vertical_placement(implementation::get_v_align(cfg["vertical_placement"]))
131 , horizontal_placement(implementation::get_h_align(cfg["horizontal_placement"]))
132 , maximum_width(cfg["maximum_width"], 0u)
133 , maximum_height(cfg["maximum_height"], 0u)
134 , click_dismiss(cfg["click_dismiss"].to_bool())
135 , definition(cfg["definition"])
136 , linked_groups()
137 , tooltip(cfg.child_or_empty("tooltip"), "tooltip")
138 , helptip(cfg.child_or_empty("helptip"), "helptip")
139 , grid(nullptr)
140{
141 if(!cfg["functions"].empty()) {
142 wfl::formula(cfg["functions"], &functions).evaluate();
143 }
144
145 auto c = cfg.optional_child("grid");
146
147 VALIDATE(c, _("No grid defined."));
148
149 grid = std::make_shared<builder_grid>(*c);
150
152 VALIDATE(width.has_formula() || width(), missing_mandatory_wml_key("resolution", "width"));
153 VALIDATE(height.has_formula() || height(), missing_mandatory_wml_key("resolution", "height"));
154 }
155
156 DBG_GUI_P << "Window builder: parsing resolution " << window_width << ',' << window_height;
157
158 if(definition.empty()) {
159 definition = "default";
160 }
161
163}
164
166 : id(cfg["id"])
167{
168 VALIDATE(!id.empty(), missing_mandatory_wml_key("[window][resolution][" + tagname + "]", "id"));
169}
170
173 , rows(0)
174 , cols(0)
175 , row_grow_factor()
176 , col_grow_factor()
177 , flags()
178 , border_size()
179 , widgets()
180{
181 log_scope2(log_gui_parse, "Window builder: parsing a grid");
182
183 for(const auto& row : cfg.child_range("row")) {
184 unsigned col = 0;
185
186 row_grow_factor.push_back(row["grow_factor"].to_unsigned());
187
188 for(const auto& c : row.child_range("column")) {
190 border_size.push_back(c["border_size"].to_unsigned());
191 if(rows == 0) {
192 col_grow_factor.push_back(c["grow_factor"].to_unsigned());
193 }
194
195 widgets.push_back(create_widget_builder(c));
196
197 ++col;
198 }
199
200 if(col == 0) {
201 const t_string msg = VGETTEXT("Grid ‘$grid’ row $row must have at least one column.", {
202 {"grid", id}, {"row", std::to_string(rows)}
203 });
204
205 FAIL(msg);
206 }
207
208 ++rows;
209
210 if(rows == 1) {
211 cols = col;
212 } else if(col != cols) {
213 const t_string msg = VGETTEXT("Grid ‘$grid’ row $row has a differing number of columns ($found found, $expected expected)", {
214 {"grid", id}, {"row", std::to_string(rows)}, {"found", std::to_string(col)}, {"expected", std::to_string(cols)}
215 });
216
217 FAIL(msg);
218 }
219 }
220
221 DBG_GUI_P << "Window builder: grid has " << rows << " rows and " << cols << " columns.";
222}
223
224std::unique_ptr<widget> builder_grid::build() const
225{
226 auto result = std::make_unique<grid>();
227 build(*result);
228 return result;
229}
230
231std::unique_ptr<widget> builder_grid::build(const replacements_map& replacements) const
232{
233 auto result = std::make_unique<grid>();
234 build(*result, replacements);
235 return result;
236}
237
239{
240 grid.set_id(id);
243
244 log_scope2(log_gui_general, "Window builder: building grid");
245
246 DBG_GUI_G << "Window builder: grid '" << id << "' has " << rows << " rows and " << cols << " columns.";
247
248 for(unsigned x = 0; x < rows; ++x) {
250
251 for(unsigned y = 0; y < cols; ++y) {
252 if(x == 0) {
254 }
255
256 DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".";
257
258 const unsigned int i = x * cols + y;
259
260 if(replacements) {
261 auto widget = widgets[i]->build(replacements.value());
262 grid.set_child(std::move(widget), x, y, flags[i], border_size[i]);
263 } else {
264 auto widget = widgets[i]->build();
265 grid.set_child(std::move(widget), x, y, flags[i], border_size[i]);
266 }
267 }
268 }
269}
270
271} // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
const_all_children_iterator ordered_begin() const
Definition config.cpp:838
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition config.cpp:380
child_itors child_range(std::string_view key)
Definition config.cpp:268
std::size_t all_children_count() const
Definition config.cpp:302
boost::iterator_range< const_child_iterator > const_child_itors
Definition config.hpp:281
std::vector< window_resolution > resolutions
Resolution options for this window instance.
void read(const config &cfg)
At the moment two kinds of tips are known:
Definition tooltip.cpp:41
Base container class.
Definition grid.hpp:32
void set_row_grow_factor(const unsigned row, const unsigned factor)
Sets the grow factor for a row.
Definition grid.hpp:87
void set_column_grow_factor(const unsigned column, const unsigned factor)
Sets the grow factor for a column.
Definition grid.hpp:102
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition grid.cpp:711
void set_child(std::unique_ptr< widget > widget, const unsigned row, const unsigned col, const unsigned flags, const unsigned border_size)
Sets a child in the grid.
Definition grid.cpp:71
bool has_formula() const
Determine whether the class contains a formula.
Base class for all widgets.
Definition widget.hpp:55
void set_id(const std::string &id)
Definition widget.cpp:98
void set_linked_group(const std::string &linked_group)
Definition widget.cpp:356
@ outline
Single-pixel outline.
@ fill
Flood-filled rectangle.
A simple wrapper class for optional reference types.
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition formula.hpp:48
const config * cfg
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
static std::string _(const char *str)
Definition gettext.hpp:100
Define the common log macros for the gui toolkit.
#define WRN_GUI_P
Definition log.hpp:68
#define DBG_GUI_G
Definition log.hpp:41
#define DBG_GUI_P
Definition log.hpp:66
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
This file contains the window object, this object is a top level container which has the event manage...
#define log_scope2(domain, description)
Definition log.hpp:276
unsigned read_flags(const config &cfg)
Returns the placement/resize flags.
Definition helper.cpp:88
Generic file dialog.
std::shared_ptr< builder_widget > builder_widget_ptr
std::unique_ptr< widget > build_single_widget_instance_helper(const std::string &type, const config &cfg)
Implementation detail for build_single_widget_instance.
builder_widget_ptr create_widget_builder(const config &cfg)
Create a widget builder.
std::vector< linked_group_definition > parse_linked_group_definitions(const config &cfg)
std::function< builder_widget_ptr(const config &)> widget_builder_func_t
Function type alias for register_widget_builder.
lg::log_domain log_gui_general("gui/general")
Definition log.hpp:40
lg::log_domain log_gui_parse("gui/parse")
Definition log.hpp:65
std::map< std::string, widget_builder_func_t > & widget_builder_lookup()
Returns the list of registered widget builders.
Contains the implementation details for lexical_cast and shouldn't be used directly.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition color.hpp:51
std::vector< unsigned > col_grow_factor
std::vector< unsigned > flags
The flags per grid cell.
std::vector< builder_widget_ptr > widgets
The widgets per grid cell.
builder_grid(const config &cfg)
std::vector< unsigned > row_grow_factor
The grow factor for the rows / columns.
virtual std::unique_ptr< widget > build() const override
Inherited from builder_widget.
std::vector< unsigned > border_size
The border size per grid cell.
Contains the info needed to instantiate a widget.
widget::debug_border debug_border_mode
builder_widget(const config &cfg)
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
tooltip_info(const config &cfg, const std::string &tagname)
std::vector< linked_group_definition > linked_groups
std::string missing_mandatory_wml_key(const std::string &section, const std::string &key, const std::string &primary_key, const std::string &primary_value)
Returns a standard message for a missing wml key (attribute).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define FAIL(message)
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
#define i
#define c