The Battle for Wesnoth  1.15.12+dev
window_builder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "formula/string_utils.hpp"
20 #include "gettext.hpp"
21 #include "gui/core/log.hpp"
26 #include "gui/widgets/pane.hpp"
27 #include "gui/widgets/settings.hpp"
28 #include "gui/widgets/viewport.hpp"
29 #include "gui/widgets/window.hpp"
30 #include "wml_exception.hpp"
31 
32 #include <functional>
33 
34 namespace gui2
35 {
36 
37 std::unique_ptr<window> build(const builder_window::window_resolution& definition)
38 {
39  // We set the values from the definition since we can only determine the
40  // best size (if needed) after all widgets have been placed.
41  auto win = std::make_unique<window>(definition);
42  assert(win);
43 
44  for(const auto& lg : definition.linked_groups) {
45  if(win->has_linked_size_group(lg.id)) {
46  t_string msg = VGETTEXT("Linked '$id' group has multiple definitions.", {{"id", lg.id}});
47 
48  FAIL(msg);
49  }
50 
51  win->init_linked_size_group(lg.id, lg.fixed_width, lg.fixed_height);
52  }
53 
54  win->set_click_dismiss(definition.click_dismiss);
55 
56  const auto conf = win->cast_config_to<window_definition>();
57  assert(conf);
58 
59  if(conf->grid) {
60  win->init_grid(*conf->grid);
61  win->finalize(*definition.grid);
62  } else {
63  win->init_grid(*definition.grid);
64  }
65 
66  win->add_to_keyboard_chain(win.get());
67 
68  return win;
69 }
70 
71 std::unique_ptr<window> build(const std::string& type)
72 {
73  const builder_window::window_resolution& definition = get_window_builder(type);
74  auto window = build(definition);
75  window->set_id(type);
76  return window;
77 }
78 
80  : id(cfg["id"])
81  , linked_group(cfg["linked_group"])
82  , debug_border_mode(cfg["debug_border_mode"])
83  , debug_border_color(decode_color(cfg["debug_border_color"]))
84 {
85 }
86 
88 {
90  VALIDATE(children.size() == 1, "Grid cell does not have exactly 1 child.");
91 
92  if(const config& grid = cfg.child("grid")) {
93  return std::make_shared<builder_grid>(grid);
94  }
95 
96  if(const config& instance = cfg.child("instance")) {
97  return std::make_shared<implementation::builder_instance>(instance);
98  }
99 
100  if(const config& pane = cfg.child("pane")) {
101  return std::make_shared<implementation::builder_pane>(pane);
102  }
103 
104  if(const config& viewport = cfg.child("viewport")) {
105  return std::make_shared<implementation::builder_viewport>(viewport);
106  }
107 
108  for(const auto& item : widget_builder_lookup()) {
109  if(item.first == "window" || item.first == "tooltip") {
110  continue;
111  }
112 
113  if(const config& c = cfg.child(item.first)) {
114  return item.second(c);
115  }
116  }
117 
118  // FAIL() doesn't return
119  //
120  // To fix this: add your new widget to source-lists/libwesnoth_widgets and rebuild.
121 
122  FAIL("Unknown widget type " + cfg.ordered_begin()->key);
123 }
124 
125 widget* build_single_widget_instance_helper(const std::string& type, const config& cfg)
126 {
127  const auto& iter = widget_builder_lookup().find(type);
128  VALIDATE(iter != widget_builder_lookup().end(), "Invalid widget type '" + type + "'");
129 
130  widget_builder_func_t& builder = iter->second;
131  return builder(cfg)->build();
132 }
133 
134 void builder_window::read(const config& cfg)
135 {
136  VALIDATE(!id_.empty(), missing_mandatory_wml_key("window", "id"));
137  VALIDATE(!description_.empty(), missing_mandatory_wml_key("window", "description"));
138 
139  DBG_GUI_P << "Window builder: reading data for window " << id_ << ".\n";
140 
141  config::const_child_itors cfgs = cfg.child_range("resolution");
142  VALIDATE(!cfgs.empty(), _("No resolution defined."));
143 
144  for(const auto& i : cfgs) {
145  resolutions.emplace_back(i);
146  }
147 }
148 
150  : window_width(cfg["window_width"])
151  , window_height(cfg["window_height"])
152  , automatic_placement(cfg["automatic_placement"].to_bool(true))
153  , x(cfg["x"])
154  , y(cfg["y"])
155  , width(cfg["width"])
156  , height(cfg["height"])
157  , reevaluate_best_size(cfg["reevaluate_best_size"])
158  , functions()
159  , vertical_placement(implementation::get_v_align(cfg["vertical_placement"]))
160  , horizontal_placement(implementation::get_h_align(cfg["horizontal_placement"]))
161  , maximum_width(cfg["maximum_width"], 0u)
162  , maximum_height(cfg["maximum_height"], 0u)
163  , click_dismiss(cfg["click_dismiss"].to_bool())
164  , definition(cfg["definition"])
165  , linked_groups()
166  , tooltip(cfg.child_or_empty("tooltip"), "tooltip")
167  , helptip(cfg.child_or_empty("helptip"), "helptip")
168  , grid(nullptr)
169 {
170  if(!cfg["functions"].empty()) {
171  wfl::formula(cfg["functions"], &functions).evaluate();
172  }
173 
174  const config& c = cfg.child("grid");
175 
176  VALIDATE(c, _("No grid defined."));
177 
178  grid = std::make_shared<builder_grid>(builder_grid(c));
179 
180  if(!automatic_placement) {
181  VALIDATE(width.has_formula() || width(), missing_mandatory_wml_key("resolution", "width"));
182  VALIDATE(height.has_formula() || height(), missing_mandatory_wml_key("resolution", "height"));
183  }
184 
185  DBG_GUI_P << "Window builder: parsing resolution " << window_width << ',' << window_height << '\n';
186 
187  if(definition.empty()) {
188  definition = "default";
189  }
190 
192 }
193 
195  : id(cfg["id"])
196 {
197  VALIDATE(!id.empty(), missing_mandatory_wml_key("[window][resolution][" + tagname + "]", "id"));
198 }
199 
201  : builder_widget(cfg)
202  , rows(0)
203  , cols(0)
204  , row_grow_factor()
205  , col_grow_factor()
206  , flags()
207  , border_size()
208  , widgets()
209 {
210  log_scope2(log_gui_parse, "Window builder: parsing a grid");
211 
212  for(const auto& row : cfg.child_range("row")) {
213  unsigned col = 0;
214 
215  row_grow_factor.push_back(row["grow_factor"]);
216 
217  for(const auto& c : row.child_range("column")) {
218  flags.push_back(implementation::read_flags(c));
219  border_size.push_back(c["border_size"]);
220  if(rows == 0) {
221  col_grow_factor.push_back(c["grow_factor"]);
222  }
223 
224  widgets.push_back(create_widget_builder(c));
225 
226  ++col;
227  }
228 
229  if(col == 0) {
230  const t_string msg = VGETTEXT("Grid '$grid' row $row must have at least one column.", {
231  {"grid", id}, {"row", std::to_string(rows)}
232  });
233 
234  FAIL(msg);
235  }
236 
237  ++rows;
238 
239  if(rows == 1) {
240  cols = col;
241  } else if(col != cols) {
242  const t_string msg = VGETTEXT("Grid '$grid' row $row has a differing number of columns ($found found, $expected expected)", {
243  {"grid", id}, {"row", std::to_string(rows)}, {"found", std::to_string(col)}, {"expected", std::to_string(cols)}
244  });
245 
246  FAIL(msg);
247  }
248  }
249 
250  DBG_GUI_P << "Window builder: grid has " << rows << " rows and " << cols << " columns.\n";
251 }
252 
254 {
255  return build(new grid());
256 }
257 
258 widget* builder_grid::build(const replacements_map& replacements) const
259 {
260  grid* result = new grid();
261  build(*result, replacements);
262  return result;
263 }
264 
266 {
267  grid->set_id(id);
269  grid->set_rows_cols(rows, cols);
270 
271  log_scope2(log_gui_general, "Window builder: building grid");
272 
273  DBG_GUI_G << "Window builder: grid '" << id << "' has " << rows << " rows and " << cols << " columns.\n";
274 
275  for(unsigned x = 0; x < rows; ++x) {
277 
278  for(unsigned y = 0; y < cols; ++y) {
279  if(x == 0) {
281  }
282 
283  DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".\n";
284 
285  const unsigned int i = x * cols + y;
286 
287  widget* widget = widgets[i]->build();
288  grid->set_child(widget, x, y, flags[i], border_size[i]);
289  }
290  }
291 
292  return grid;
293 }
294 
295 void builder_grid::build(grid& grid, const replacements_map& replacements) const
296 {
297  grid.set_id(id);
299  grid.set_rows_cols(rows, cols);
300 
301  log_scope2(log_gui_general, "Window builder: building grid");
302 
303  DBG_GUI_G << "Window builder: grid '" << id << "' has " << rows << " rows and " << cols << " columns.\n";
304 
305  for(unsigned x = 0; x < rows; ++x) {
307 
308  for(unsigned y = 0; y < cols; ++y) {
309  if(x == 0) {
311  }
312 
313  DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".\n";
314 
315  const unsigned int i = x * cols + y;
316  grid.set_child(widgets[i]->build(replacements), x, y, flags[i], border_size[i]);
317  }
318  }
319 }
320 
321 } // namespace gui2
Define the common log macros for the gui toolkit.
Contains the info needed to instantiate a widget.
#define DBG_GUI_P
Definition: log.hpp:65
virtual grid * build() const override
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:414
const builder_window::window_resolution & get_window_builder(const std::string &type)
Returns an reference to the requested builder.
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:953
unsigned read_flags(const config &cfg)
Returns the placement/resize flags.
Definition: helper.cpp:87
Key Type Default Description window_width unsigned 0 Width of the application window.
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:39
void set_row_grow_factor(const unsigned row, const unsigned factor)
Sets the grow factor for a row.
Definition: grid.hpp:86
boost::iterator_range< const_all_children_iterator > const_all_children_itors
Definition: config.hpp:688
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
This file contains the window object, this object is a top level container which has the event manage...
child_itors child_range(config_key_type key)
Definition: config.cpp:356
Base class for all widgets.
Definition: widget.hpp:49
std::vector< linked_group_definition > parse_linked_group_definitions(const config &cfg)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
std::function< builder_widget_ptr(const config &)> widget_builder_func_t
Function type alias for register_widget_builder.
static std::string _(const char *str)
Definition: gettext.hpp:92
std::shared_ptr< builder_widget > builder_widget_ptr
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.
Generic file dialog.
Definition: field-fwd.hpp:22
std::vector< linked_group_definition > linked_groups
Base container class.
Definition: grid.hpp:30
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
lg::log_domain log_gui_parse("gui/parse")
Definition: log.hpp:64
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
std::vector< unsigned > row_grow_factor
The grow factor for the rows / columns.
This file contains the settings handling of the widget library.
std::vector< unsigned > col_grow_factor
widget * build_single_widget_instance_helper(const std::string &type, const config &cfg)
Helper function to implement build_single_widget_instance.
#define log_scope2(domain, description)
Definition: log.hpp:207
tooltip_info(const config &cfg, const std::string &tagname)
A pane is a container where new members can be added and removed during run-time. ...
Definition: pane.hpp:42
builder_grid(const config &cfg)
void set_child(widget *widget, const unsigned row, const unsigned col, const unsigned flags, const unsigned border_size)
Sets a child in the grid.
Definition: grid.cpp:69
boost::iterator_range< const_child_iterator > const_child_itors
Definition: config.hpp:204
Definition: pump.hpp:39
A viewport is an special widget used to view only a part of the widget it &#39;holds&#39;.
Definition: viewport.hpp:44
std::vector< unsigned > flags
The flags per grid cell.
std::size_t i
Definition: function.cpp:940
void read(const config &cfg)
builder_widget(const config &cfg)
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
unsigned get_v_align(const std::string &v_align)
Returns the vertical alignment.
Definition: helper.cpp:37
lg::log_domain log_gui_general("gui/general")
Definition: log.hpp:39
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:722
bool grid()
Definition: general.cpp:519
const_all_children_iterator ordered_begin() const
Definition: config.cpp:933
widget_builder_map & widget_builder_lookup()
Returns the list of registered widget builders.
void set_id(const std::string &id)
Definition: widget.cpp:97
wfl::function_symbol_table functions
Class to show the tips.
Definition: tooltip.cpp:56
std::vector< builder_widget_ptr > widgets
The widgets per grid cell.
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
#define FAIL(message)
void set_column_grow_factor(const unsigned column, const unsigned factor)
Sets the grow factor for a column.
Definition: grid.hpp:101
bool has_formula() const
Determine whether the class contains a formula.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
mock_char c
unsigned get_h_align(const std::string &h_align)
Returns the horizontal alignment.
Definition: helper.cpp:52
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
#define DBG_GUI_G
Definition: log.hpp:40
std::vector< unsigned > border_size
The border size per grid cell.
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:344
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:409
color_t decode_color(const std::string &color)
Converts a color string to a color.
Definition: helper.cpp:58
builder_widget_ptr create_widget_builder(const config &cfg)
Create a widget builder.