The Battle for Wesnoth  1.17.10+dev
window_builder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
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 
20 #include "formula/string_utils.hpp"
21 #include "gettext.hpp"
22 #include "gui/core/log.hpp"
27 #include "gui/widgets/pane.hpp"
28 #include "gui/widgets/settings.hpp"
29 #include "gui/widgets/viewport.hpp"
30 #include "gui/widgets/window.hpp"
31 #include "wml_exception.hpp"
32 
33 #include <functional>
34 
35 namespace gui2
36 {
37 
38 std::unique_ptr<window> build(const builder_window::window_resolution& definition)
39 {
40  // We set the values from the definition since we can only determine the
41  // best size (if needed) after all widgets have been placed.
42  auto win = std::make_unique<window>(definition);
43  assert(win);
44  win->finish_build(definition);
45  return win;
46 }
47 
48 std::unique_ptr<window> build(const std::string& type)
49 {
50  const builder_window::window_resolution& definition = get_window_builder(type);
51  auto window = build(definition);
52  window->set_id(type);
53  return window;
54 }
55 
57  : id(cfg["id"])
58  , linked_group(cfg["linked_group"])
59  , debug_border_mode(widget::debug_border::none)
60  , debug_border_color(decode_color(cfg["debug_border_color"]))
61 {
62  // TODO: move to a `decode` function?
63  switch(const int dbm = cfg["debug_border_mode"].to_int(0); dbm) {
64  case 0:
66  break;
67  case 1:
69  break;
70  case 2:
72  break;
73  default:
74  WRN_GUI_P << "Widget builder: unknown debug border mode " << dbm << ".";
75  }
76 }
77 
79 {
81  VALIDATE(children.size() == 1, "Grid cell does not have exactly 1 child.");
82 
83  if(const auto grid = cfg.optional_child("grid")) {
84  return std::make_shared<builder_grid>(grid.value());
85  }
86 
87  if(const auto instance = cfg.optional_child("instance")) {
88  return std::make_shared<implementation::builder_instance>(instance.value());
89  }
90 
91  if(const auto pane = cfg.optional_child("pane")) {
92  return std::make_shared<implementation::builder_pane>(pane.value());
93  }
94 
95  if(const auto viewport = cfg.optional_child("viewport")) {
96  return std::make_shared<implementation::builder_viewport>(viewport.value());
97  }
98 
99  for(const auto& [type, builder] : widget_builder_lookup()) {
100  if(type == "window" || type == "tooltip") {
101  continue;
102  }
103 
104  if(const auto c = cfg.optional_child(type)) {
105  return builder(c.value());
106  }
107  }
108 
109  // FAIL() doesn't return
110  //
111  // To fix this: add your new widget to source-lists/libwesnoth_widgets and rebuild.
112 
113  FAIL("Unknown widget type " + cfg.ordered_begin()->key);
114 }
115 
116 std::unique_ptr<widget> build_single_widget_instance_helper(const std::string& type, const config& cfg)
117 {
118  const auto& iter = widget_builder_lookup().find(type);
119  VALIDATE(iter != widget_builder_lookup().end(), "Invalid widget type '" + type + "'");
120 
121  widget_builder_func_t& builder = iter->second;
122  return builder(cfg)->build();
123 }
124 
125 void builder_window::read(const config& cfg)
126 {
127  VALIDATE(!id_.empty(), missing_mandatory_wml_key("window", "id"));
128  VALIDATE(!description_.empty(), missing_mandatory_wml_key("window", "description"));
129 
130  DBG_GUI_P << "Window builder: reading data for window " << id_ << ".";
131 
132  config::const_child_itors cfgs = cfg.child_range("resolution");
133  VALIDATE(!cfgs.empty(), _("No resolution defined."));
134 
135  for(const auto& i : cfgs) {
136  resolutions.emplace_back(i);
137  }
138 }
139 
141  : window_width(cfg["window_width"])
142  , window_height(cfg["window_height"])
143  , automatic_placement(cfg["automatic_placement"].to_bool(true))
144  , x(cfg["x"])
145  , y(cfg["y"])
146  , width(cfg["width"])
147  , height(cfg["height"])
148  , reevaluate_best_size(cfg["reevaluate_best_size"])
149  , functions()
150  , vertical_placement(implementation::get_v_align(cfg["vertical_placement"]))
151  , horizontal_placement(implementation::get_h_align(cfg["horizontal_placement"]))
152  , maximum_width(cfg["maximum_width"], 0u)
153  , maximum_height(cfg["maximum_height"], 0u)
154  , click_dismiss(cfg["click_dismiss"].to_bool())
155  , definition(cfg["definition"])
156  , linked_groups()
157  , tooltip(cfg.child_or_empty("tooltip"), "tooltip")
158  , helptip(cfg.child_or_empty("helptip"), "helptip")
159  , grid(nullptr)
160 {
161  if(!cfg["functions"].empty()) {
162  wfl::formula(cfg["functions"], &functions).evaluate();
163  }
164 
165  const config& c = cfg.child("grid");
166 
167  VALIDATE(c, _("No grid defined."));
168 
169  grid = std::make_shared<builder_grid>(c);
170 
171  if(!automatic_placement) {
172  VALIDATE(width.has_formula() || width(), missing_mandatory_wml_key("resolution", "width"));
173  VALIDATE(height.has_formula() || height(), missing_mandatory_wml_key("resolution", "height"));
174  }
175 
176  DBG_GUI_P << "Window builder: parsing resolution " << window_width << ',' << window_height;
177 
178  if(definition.empty()) {
179  definition = "default";
180  }
181 
183 }
184 
186  : id(cfg["id"])
187 {
188  VALIDATE(!id.empty(), missing_mandatory_wml_key("[window][resolution][" + tagname + "]", "id"));
189 }
190 
192  : builder_widget(cfg)
193  , rows(0)
194  , cols(0)
195  , row_grow_factor()
196  , col_grow_factor()
197  , flags()
198  , border_size()
199  , widgets()
200 {
201  log_scope2(log_gui_parse, "Window builder: parsing a grid");
202 
203  for(const auto& row : cfg.child_range("row")) {
204  unsigned col = 0;
205 
206  row_grow_factor.push_back(row["grow_factor"]);
207 
208  for(const auto& c : row.child_range("column")) {
209  flags.push_back(implementation::read_flags(c));
210  border_size.push_back(c["border_size"]);
211  if(rows == 0) {
212  col_grow_factor.push_back(c["grow_factor"]);
213  }
214 
215  widgets.push_back(create_widget_builder(c));
216 
217  ++col;
218  }
219 
220  if(col == 0) {
221  const t_string msg = VGETTEXT("Grid '$grid' row $row must have at least one column.", {
222  {"grid", id}, {"row", std::to_string(rows)}
223  });
224 
225  FAIL(msg);
226  }
227 
228  ++rows;
229 
230  if(rows == 1) {
231  cols = col;
232  } else if(col != cols) {
233  const t_string msg = VGETTEXT("Grid '$grid' row $row has a differing number of columns ($found found, $expected expected)", {
234  {"grid", id}, {"row", std::to_string(rows)}, {"found", std::to_string(col)}, {"expected", std::to_string(cols)}
235  });
236 
237  FAIL(msg);
238  }
239  }
240 
241  DBG_GUI_P << "Window builder: grid has " << rows << " rows and " << cols << " columns.";
242 }
243 
244 std::unique_ptr<widget> builder_grid::build() const
245 {
246  auto result = std::make_unique<grid>();
247  build(*result);
248  return result;
249 }
250 
251 std::unique_ptr<widget> builder_grid::build(const replacements_map& replacements) const
252 {
253  auto result = std::make_unique<grid>();
254  build(*result, replacements);
255  return result;
256 }
257 
259 {
260  grid.set_id(id);
262  grid.set_rows_cols(rows, cols);
263 
264  log_scope2(log_gui_general, "Window builder: building grid");
265 
266  DBG_GUI_G << "Window builder: grid '" << id << "' has " << rows << " rows and " << cols << " columns.";
267 
268  for(unsigned x = 0; x < rows; ++x) {
270 
271  for(unsigned y = 0; y < cols; ++y) {
272  if(x == 0) {
274  }
275 
276  DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".";
277 
278  const unsigned int i = x * cols + y;
279 
280  if(replacements) {
281  auto widget = widgets[i]->build(replacements.value());
282  grid.set_child(std::move(widget), x, y, flags[i], border_size[i]);
283  } else {
284  auto widget = widgets[i]->build();
285  grid.set_child(std::move(widget), x, y, flags[i], border_size[i]);
286  }
287  }
288  }
289 }
290 
291 } // 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:66
widget::debug_border debug_border_mode
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:402
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:978
unsigned read_flags(const config &cfg)
Returns the placement/resize flags.
Definition: helper.cpp:88
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:40
void set_row_grow_factor(const unsigned row, const unsigned factor)
Sets the grow factor for a row.
Definition: grid.hpp:87
std::shared_ptr< builder_widget > builder_widget_ptr
boost::iterator_range< const_all_children_iterator > const_all_children_itors
Definition: config.hpp:745
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:344
Base class for all widgets.
Definition: widget.hpp:53
std::unique_ptr< widget > build_single_widget_instance_helper(const std::string &type, const config &cfg)
Implementation detail for build_single_widget_instance.
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:110
std::function< builder_widget_ptr(const config &)> widget_builder_func_t
Function type alias for register_widget_builder.
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
static std::string _(const char *str)
Definition: gettext.hpp:93
Flood-filled rectangle.
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.
std::vector< linked_group_definition > linked_groups
Base container class.
Definition: grid.hpp:31
lg::log_domain log_gui_parse("gui/parse")
Definition: log.hpp:65
#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
#define log_scope2(domain, description)
Definition: log.hpp:238
utils::optional_reference< config > optional_child(config_key_type key, int n=0)
Euivalent to child, but returns an empty optional if the nth child was not found. ...
Definition: config.cpp:445
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:43
virtual std::unique_ptr< widget > build() const override
Inherited from builder_widget.
builder_grid(const config &cfg)
boost::iterator_range< const_child_iterator > const_child_itors
Definition: config.hpp:205
A viewport is an special widget used to view only a part of the widget it &#39;holds&#39;.
Definition: viewport.hpp:45
std::map< std::string, widget_builder_func_t > & widget_builder_lookup()
Returns the list of registered widget builders.
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
std::vector< unsigned > flags
The flags per grid cell.
std::size_t i
Definition: function.cpp:967
void read(const config &cfg)
builder_widget(const config &cfg)
#define WRN_GUI_P
Definition: log.hpp:68
#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:38
lg::log_domain log_gui_general("gui/general")
Definition: log.hpp:40
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:712
const_all_children_iterator ordered_begin() const
Definition: config.cpp:958
void set_id(const std::string &id)
Definition: widget.cpp:99
wfl::function_symbol_table functions
Class to show the tips.
Definition: tooltip.cpp:57
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:102
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:60
mock_char c
unsigned get_h_align(const std::string &h_align)
Returns the horizontal alignment.
Definition: helper.cpp:53
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:66
#define DBG_GUI_G
Definition: log.hpp:41
std::vector< unsigned > border_size
The border size per grid cell.
A simple wrapper class for optional reference types.
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
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
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:346
color_t decode_color(const std::string &color)
Converts a color string to a color.
Definition: helper.cpp:55
builder_widget_ptr create_widget_builder(const config &cfg)
Create a widget builder.