The Battle for Wesnoth  1.15.2+dev
gui_definition.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 "config.hpp"
20 #include "formatter.hpp"
21 #include "gui/core/log.hpp"
23 #include "gui/widgets/settings.hpp"
24 #include "wml_exception.hpp"
25 
26 namespace gui2
27 {
31 
33  : widget_types()
34  , window_types()
35  , id_(cfg["id"])
36  , description_(cfg["description"].t_str())
37  , popup_show_delay_(0)
38  , popup_show_time_(0)
39  , help_show_time_(0)
40  , double_click_time_(0)
41  , repeat_button_repeat_time_(0)
42  , sound_button_click_()
43  , sound_toggle_button_click_()
44  , sound_toggle_panel_click_()
45  , sound_slider_adjust_()
46  , has_helptip_message_()
47  , tips_(tip_of_the_day::load(cfg))
48 {
49  VALIDATE(!id_.empty(), missing_mandatory_wml_key("gui", "id"));
50  VALIDATE(!description_.empty(), missing_mandatory_wml_key("gui", "description"));
51 
52  DBG_GUI_P << "Parsing gui " << id_ << std::endl;
53 
54  //
55  // Widget parsing
56  //
57 
58  /** Parse widget definitions of each registered type. */
59  for(auto& widget_type : registered_widget_types()) {
60  const std::string& type_id = widget_type.first;
61 
63 
64  const std::string key = widget_type.second.key
65  ? widget_type.second.key
66  : type_id + "_definition";
67 
68  bool found_default_def = false;
69 
70  for(const config& definition : cfg.child_range(key)) {
71  // Run the static parser to get a definition ptr.
72  styled_widget_definition_ptr def_ptr = widget_type.second.parser(definition);
73 
74  const std::string& def_id = def_ptr->id;
75 
76  if(def_map.find(def_id) != def_map.end()) {
77  ERR_GUI_P << "Skipping duplicate definition '" << def_id << "' for '" << type_id << "'\n";
78  continue;
79  }
80 
81  def_map.emplace(def_id, std::move(def_ptr));
82 
83  if(def_id == "default") {
84  found_default_def = true;
85  }
86  }
87 
88  // Only the default GUI needs to ensure each widget has a default definition.
89  // Non-default ones can just fall back to the default definition in the default GUI.
90  if(id_ == "default") {
91  VALIDATE(found_default_def, "No default definition found for widget '" + type_id + "'");
92  }
93  }
94 
95  //
96  // Window parsing
97  //
98 
99  /** Parse each window. */
100  for(auto& w : cfg.child_range("window")) {
101  window_types.emplace(w["id"], builder_window(w));
102  }
103 
104  if(id_ == "default") {
105  // The default gui needs to define all window types since we're the
106  // fallback in case another gui doesn't define the window type.
107  for(const auto& window_type : registered_window_types()) {
108  const std::string error_msg(
109  "Window not defined in WML: '" + window_type + "'."
110  "Perhaps a mismatch between data and source versions. Try --data-dir <trunk-dir>");
111 
112  VALIDATE(window_types.find(window_type) != window_types.end(), error_msg);
113  }
114  }
115 
116  /***** settings *****/
117 
118  /**
119  * @todo Regarding sounds:
120  * Need to evaluate but probably we want the widget definition be able to:
121  * - Override the default (and clear it). This will allow toggle buttons in a
122  * listbox to sound like a toggle panel.
123  * - Override the default and above per instance of the widget, some buttons
124  * can give a different sound.
125  */
126  const config& settings = cfg.child("settings");
127 
128  popup_show_delay_ = settings["popup_show_delay"];
129  popup_show_time_ = settings["popup_show_time"];
130  help_show_time_ = settings["help_show_time"];
131  double_click_time_ = settings["double_click_time"];
132 
133  repeat_button_repeat_time_ = settings["repeat_button_repeat_time"];
134 
135  VALIDATE(double_click_time_, missing_mandatory_wml_key("settings", "double_click_time"));
136 
137  sound_button_click_ = settings["sound_button_click"].str();
138  sound_toggle_button_click_ = settings["sound_toggle_button_click"].str();
139  sound_toggle_panel_click_ = settings["sound_toggle_panel_click"].str();
140  sound_slider_adjust_ = settings["sound_slider_adjust"].str();
141 
142  has_helptip_message_ = settings["has_helptip_message"];
143 
144  VALIDATE(!has_helptip_message_.empty(), missing_mandatory_wml_key("[settings]", "has_helptip_message"));
145 }
146 
148 {
160 }
161 
162 namespace
163 {
164 template<typename TList, typename TConv>
165 const typename TList::value_type& get_best_resolution(const TList& list, const TConv& get_size)
166 {
167  using resolution_t = const typename TList::value_type;
168 
169  resolution_t* best_resolution = nullptr;
170  int best_resolution_score = std::numeric_limits<int>::min();
171 
172  const int screen_w = settings::screen_width;
173  const int screen_h = settings::screen_height;
174 
175  for(const auto& res : list) {
176  point size = get_size(res);
177 
178  int w = size.x ? size.x : 1;
179  int h = size.y ? size.y : 1;
180  int score = 0;
181 
182  if(w <= screen_w && h <= screen_h) {
183  score = w * h;
184  } else {
185  // Negative score, only used in case none of the given resolution fits on the screen
186  // (workaround for a bug where the windows size can become < 800x600).
187  score = std::min(screen_w - w, 0) + std::min(screen_h - h, 0);
188  }
189 
190  if(score >= best_resolution_score) {
191  best_resolution = &res;
192  best_resolution_score = score;
193  }
194  }
195 
196  assert(best_resolution != nullptr);
197  return *best_resolution;
198 }
199 
200 } // namespace
201 
202 resolution_definition_ptr get_control(const std::string& control_type, const std::string& definition)
203 {
204  const auto& current_types = current_gui->second.widget_types;
205  const auto& default_types = default_gui->second.widget_types;
206 
207  const auto widget_definitions = current_types.find(control_type);
208 
209  gui_definition::widget_definition_map_t::const_iterator control;
210 
211  if(widget_definitions == current_types.end()) {
212  goto fallback;
213  }
214 
215  control = widget_definitions->second.find(definition);
216 
217  if(control == widget_definitions->second.end()) {
218  fallback:
219  bool found_fallback = false;
220 
221  if(current_gui != default_gui) {
222  auto default_widget_definitions = default_types.find(control_type);
223 
224  VALIDATE(widget_definitions != current_types.end(),
225  formatter() << "Type '" << control_type << "' is unknown.");
226 
227  control = default_widget_definitions->second.find(definition);
228  found_fallback = control != default_widget_definitions->second.end();
229  }
230 
231  if(!found_fallback) {
232  if(definition != "default") {
233  LOG_GUI_G << "Control: type '" << control_type << "' definition '" << definition
234  << "' not found, falling back to 'default'.\n";
235  return get_control(control_type, "default");
236  }
237 
238  FAIL(formatter() << "default definition not found for styled_widget " << control_type);
239  }
240  }
241 
242  const auto& resolutions = (*control->second).resolutions;
243 
244  VALIDATE(!resolutions.empty(),
245  formatter() << "Control: type '" << control_type << "' definition '" << definition << "' has no resolutions.\n");
246 
247  return get_best_resolution(resolutions, [&](const resolution_definition_ptr& ptr) {
248  return point(
249  static_cast<int>(ptr->window_width),
250  static_cast<int>(ptr->window_height)
251  );
252  });
253 }
254 
256 {
258 
259  const auto& current_windows = current_gui->second.window_types;
260  const auto& default_windows = default_gui->second.window_types;
261 
262  auto iter = current_windows.find(type);
263 
264  if(iter == current_windows.end()) {
265  // Current GUI is the default one and no window type was found. Throw.
266  if(current_gui == default_gui) {
268  }
269 
270  // Else, try again to find the window, this time in the default GUI.
271  iter = default_windows.find(type);
272 
273  if(iter == default_windows.end()) {
275  }
276  }
277 
278  const auto& resolutions = iter->second.resolutions;
279 
280  VALIDATE(!resolutions.empty(), formatter() << "Window '" << type << "' has no resolutions.\n");
281 
282  return get_best_resolution(resolutions, [&](const builder_window::window_resolution& res) {
283  return point(
284  static_cast<int>(res.window_width),
285  static_cast<int>(res.window_height)
286  );
287  });
288 }
289 
290 bool add_single_widget_definition(const std::string& widget_type, const std::string& definition_id, const config& cfg)
291 {
292  auto& def_map = current_gui->second.widget_types[widget_type];
293  auto parser = registered_widget_types().find(widget_type);
294 
295  if(parser == registered_widget_types().end()) {
296  throw std::invalid_argument("widget '" + widget_type + "' doesn't exist");
297  }
298 
299  if(def_map.find(definition_id) != def_map.end()) {
300  return false;
301  }
302 
303  def_map.emplace(definition_id, parser->second.parser(cfg));
304  return true;
305 }
306 
307 void remove_single_widget_definition(const std::string& widget_type, const std::string& definition_id)
308 {
309  auto& definition_map = current_gui->second.widget_types[widget_type];
310 
311  auto it = definition_map.find(definition_id);
312  if(it != definition_map.end()) {
313  definition_map.erase(it);
314  }
315 }
316 
317 } // namespace gui2
Define the common log macros for the gui toolkit.
#define DBG_GUI_P
Definition: log.hpp:68
std::map< std::string, builder_window > window_types
Map of all known windows (the builder class builds a window).
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:420
gui_definition(const config &cfg)
Private ctor.
const builder_window::window_resolution & get_window_builder(const std::string &type)
Returns an reference to the requested builder.
unsigned double_click_time
Definition: settings.cpp:36
std::vector< game_tip > tips
Definition: settings.cpp:46
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
Definition: tips.cpp:35
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
child_itors child_range(config_key_type key)
Definition: config.cpp:362
std::string sound_button_click
Definition: settings.cpp:39
gui_theme_map_t guis
Map of all known GUIs.
#define h
Definitions for the interface to Wesnoth Markup Language (WML).
std::string sound_slider_adjust
Definition: settings.cpp:42
gui_theme_map_t::iterator default_gui
Iterator pointing to the default GUI.
void remove_single_widget_definition(const std::string &widget_type, const std::string &definition_id)
Removes a widget definition from the default GUI.
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.
#define ERR_GUI_P
Definition: log.hpp:71
int x
x coordinate.
Definition: point.hpp:44
std::shared_ptr< styled_widget_definition > styled_widget_definition_ptr
Generic file dialog.
Definition: field-fwd.hpp:22
unsigned repeat_button_repeat_time
Definition: settings.cpp:37
gui_theme_map_t::iterator current_gui
Iterator pointing to the current GUI.
Helper struct to signal that get_window_builder failed.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
std::map< std::string, gui_definition > gui_theme_map_t
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
std::shared_ptr< resolution_definition > resolution_definition_ptr
std::ostringstream wrapper.
Definition: formatter.hpp:38
t_string has_helptip_message
Definition: settings.cpp:44
std::string sound_toggle_panel_click_
std::map< std::string, styled_widget_definition_ptr > widget_definition_map_t
std::string sound_slider_adjust_
registered_widget_map & registered_widget_types()
Returns the list of registered widgets and their parsers.
#define LOG_GUI_G
Definition: log.hpp:41
Contains the general settings which have a default.
unsigned popup_show_time
Definition: settings.cpp:34
std::string sound_button_click_
Holds a 2D point.
Definition: point.hpp:23
resolution_definition_ptr get_control(const std::string &control_type, const std::string &definition)
Returns the appropriate config data for a widget instance fom the active GUI definition.
unsigned screen_width
The screen resolution should be available for all widgets since their drawing method will depend on i...
Definition: settings.cpp:25
int w
std::string sound_toggle_panel_click
Definition: settings.cpp:41
unsigned repeat_button_repeat_time_
std::string sound_toggle_button_click_
bool empty() const
Definition: tstring.hpp:182
std::map< std::string, widget_definition_map_t > widget_types
Map of each widget type, by id, and a sub-map of each of the type&#39;s definitions, also by id...
unsigned popup_show_delay
These are copied from the active gui.
Definition: settings.cpp:33
unsigned screen_height
Definition: settings.cpp:26
std::vector< game_tip > tips_
bool add_single_widget_definition(const std::string &widget_type, const std::string &definition_id, const config &cfg)
Adds a widget definition to the default GUI.
#define FAIL(message)
std::set< std::string > & registered_window_types()
Returns the list of registered windows.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
void activate() const
Activates this GUI.
std::string sound_toggle_button_click
Definition: settings.cpp:40
int y
y coordinate.
Definition: point.hpp:47
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
void update_screen_size_variables()
Update the size of the screen variables in settings.
Definition: settings.cpp:48
unsigned help_show_time
Definition: settings.cpp:35