The Battle for Wesnoth  1.19.18+dev
gui.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 
18 #include "gui/gui.hpp"
19 
20 #include "config_cache.hpp"
21 #include "filesystem.hpp"
22 #include "gettext.hpp"
23 #include "gui/core/log.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "serialization/parser.hpp"
29 #include "wml_exception.hpp"
30 
31 namespace gui2
32 {
33 namespace
34 {
35 config read_and_validate(const std::string& path)
36 try {
37  preproc_map defines;
38 #ifdef __ANDROID__
39  defines.try_emplace("ANDROID");
40 #endif
42  return io::read(*preprocess_file(path, defines), &validator);
43 
44 } catch(const utils::bad_optional_access&) {
45  FAIL("GUI2: schema/gui.cfg not found.");
46 
47 } catch(const abstract_validator::error& e) {
48  FAIL("GUI2: could not read schema file: " + e.message);
49 
50 } catch(const config::error& e) {
51  ERR_GUI_P << "Could not read gui file: " << path;
52  ERR_GUI_P << e.what();
53  return {};
54 }
55 
56 /**
57  * Adds a theme definition object to the global registry.
58  *
59  * @param def A valid gui_definition config.
60  *
61  * @returns An optional iterator to the newly-constructed definition.
62  * If gui_definition throws wml_exception or a theme with the
63  * given ID already exists, returns nullopt.
64  */
65 auto register_theme(const config& def) -> utils::optional<gui_theme_map_t::iterator>
66 try {
67  auto [iter, is_unique] = guis.try_emplace(def["id"], def);
68  if(is_unique) return iter;
69 
70  ERR_GUI_P << "UI Theme '" << def["id"] << "' already exists.";
71  return utils::nullopt;
72 
73 } catch(const wml_exception& e) {
74  ERR_GUI_P << "Invalid UI theme: " << def["id"];
75  ERR_GUI_P << e.user_message;
76  return utils::nullopt;
77 }
78 
79 /**
80  * Parses any GUI2 theme definitions at the file path specified.
81  *
82  * @param full_path Path to file containing one or more [gui] tags.
83  * @param is_core If true, look for the default theme here.
84  */
85 void parse(const std::string& full_path, bool is_core)
86 {
87  config cfg = read_and_validate(full_path);
88  for(const config& def : cfg.child_range("gui")) {
89  const bool is_default = def["id"] == "default";
90 
91  if(is_default && !is_core) {
92  ERR_GUI_P << "UI theme id 'default' is reserved for core themes.";
93  continue;
94  }
95 
96  const auto iter = register_theme(def);
97  if(!iter) continue;
98 
99  if(is_default && is_core) {
100  default_gui = *iter;
102  }
103  }
104 }
105 
106 } // namespace
107 
108 void init()
109 {
110  LOG_GUI_G << "Initializing UI subststem.";
111 
112  // Reset the registry in case we're re-initializing
113  guis.clear();
114 
115  // Save current screen size.
117 
118  //
119  // Parse GUI definitions from mainline
120  //
121 
122  try {
123  parse(filesystem::get_wml_location("gui/_main.cfg").value(), true);
124  } catch(const utils::bad_optional_access&) {
125  FAIL("GUI2: gui/_main.cfg not found.");
126  }
127 
128  // The default GUI must be in mainline
129  VALIDATE(default_gui != guis.end(), _("No default gui defined."));
130 
131  //
132  // Parse GUI definitions from addons
133  //
134 
135  std::vector<std::string> addon_dirs;
136  const std::string umc_dir = filesystem::get_addons_dir();
138 
139  // Search for all $user_campaign_dir/*/gui-theme.cfg files
140  for(const std::string& umc : addon_dirs) {
141  const std::string gui_file = umc + "/gui-theme.cfg";
142 
143  if(filesystem::file_exists(gui_file)) {
144  parse(gui_file, false);
145  }
146  }
147 }
148 
149 void switch_theme(const std::string& theme_id)
150 {
151  if(theme_id.empty() || theme_id == "default") {
153  } else {
155  [&](const auto& theme) { return theme.first; });
156 
157  if(current_gui == guis.end()) {
158  ERR_GUI_P << "Missing [gui] definition for '" << theme_id << "'";
160  }
161  }
162 
163  current_gui->second.activate();
164 }
165 
166 } // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
child_itors child_range(std::string_view key)
Definition: config.cpp:268
Realization of serialization/validator.hpp abstract validator.
Definition: theme.hpp:43
const config * cfg
Declarations for File-IO.
static std::string _(const char *str)
Definition: gettext.hpp:97
Define the common log macros for the gui toolkit.
#define LOG_GUI_G
Definition: log.hpp:42
#define ERR_GUI_P
Definition: log.hpp:69
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
Definition: filesystem.cpp:466
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:344
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir)
Returns a translated path to the actual file or directory, if it exists.
std::string get_addons_dir()
std::string path
Definition: filesystem.cpp:106
void update_screen_size_variables()
Update the size of the screen variables in settings.
Definition: settings.cpp:59
Generic file dialog.
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:108
gui_theme_map_t guis
Map of all known GUIs.
void switch_theme(const std::string &theme_id)
Set and activate the given gui2 theme.
Definition: gui.cpp:149
gui_theme_map_t::iterator current_gui
Iterator pointing to the current GUI.
gui_theme_map_t::iterator default_gui
Iterator pointing to the default GUI.
config read(std::istream &in, abstract_validator *validator)
Definition: parser.cpp:600
auto find(Container &container, const Value &value, const Projection &projection={})
Definition: general.hpp:189
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map &defines)
Function to use the WML preprocessor on a file.
std::map< std::string, struct preproc_define > preproc_map
One of the realizations of serialization/validator.hpp abstract validator.
This file contains the settings handling of the widget library.
Used to manage with not initialized validators Supposed to be thrown from the constructor.
Definition: validator.hpp:97
Helper class, don't construct this directly.
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 e