mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-18 07:43:59 +00:00
GUI2: rework init codepath for a second time
Resolves #9973. Reworks #9974, since I misunderstood how schema validators worked. They are indeed stateful and you need one instance per read call. I also decided to do away with the global macro context because I do *not* want to have to deal with people claiming the core GUI2 macros constitute a public API (nor do we want macros from one addon affecting the themes in another in the unlikely event that multiple people make gui2 themes.)
This commit is contained in:
parent
ea52702bd0
commit
968e9b95e1
150
src/gui/gui.cpp
150
src/gui/gui.cpp
|
@ -32,93 +32,78 @@ namespace gui2
|
|||
{
|
||||
namespace
|
||||
{
|
||||
class theme_parser
|
||||
config read_and_validate(const std::string& path)
|
||||
try {
|
||||
preproc_map defines;
|
||||
schema_validation::schema_validator validator{filesystem::get_wml_location("schema/gui.cfg").value()};
|
||||
filesystem::scoped_istream stream = preprocess_file(path, &defines);
|
||||
return ::read(*stream, &validator);
|
||||
|
||||
} catch(const utils::bad_optional_access&) {
|
||||
FAIL("GUI2: schema/gui.cfg not found.");
|
||||
|
||||
} catch(const abstract_validator::error& e) {
|
||||
FAIL("GUI2: could not read schema file: " + e.message);
|
||||
|
||||
} catch(const config::error& e) {
|
||||
ERR_GUI_P << "Could not read gui file: " << path;
|
||||
ERR_GUI_P << e.what();
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a theme definition object to the global registry.
|
||||
*
|
||||
* @param def A valid gui_definition config.
|
||||
*
|
||||
* @returns An optional iterator to the newly-constructed definition.
|
||||
* If gui_definition throws wml_exception or a theme with the
|
||||
* given ID already exists, returns nullopt.
|
||||
*/
|
||||
auto register_theme(const config& def) -> utils::optional<gui_theme_map_t::iterator>
|
||||
try {
|
||||
auto [iter, is_unique] = guis.try_emplace(def["id"], def);
|
||||
if(is_unique) return iter;
|
||||
|
||||
ERR_GUI_P << "UI Theme '" << def["id"] << "' already exists.";
|
||||
return utils::nullopt;
|
||||
|
||||
} catch(const wml_exception& e) {
|
||||
ERR_GUI_P << "Invalid UI theme: " << def["id"];
|
||||
ERR_GUI_P << e.user_message;
|
||||
return utils::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses any GUI2 theme definitions at the file path specified.
|
||||
*
|
||||
* @param full_path Path to file containing one or more [gui] tags.
|
||||
* @param is_core If true, look for the default theme here.
|
||||
*/
|
||||
void parse(const std::string& full_path, bool is_core)
|
||||
{
|
||||
public:
|
||||
theme_parser()
|
||||
try
|
||||
: validator_(filesystem::get_wml_location("schema/gui.cfg").value())
|
||||
, defines_(game_config::config_cache::instance().get_preproc_map())
|
||||
{
|
||||
guis.clear(); // Reset in case we're re-initializing the UI subsystem
|
||||
} catch(const utils::bad_optional_access&) {
|
||||
FAIL("GUI2: schema/gui.cfg not found.");
|
||||
} catch(const abstract_validator::error& e) {
|
||||
FAIL("GUI2: could not read schema file: " + e.message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses any GUI2 theme definitions at the file path specified.
|
||||
*
|
||||
* @param full_path Path to file containing one or more [gui] tags.
|
||||
* @param is_core If true, look for the default theme here.
|
||||
*/
|
||||
void parse(const std::string& full_path, bool is_core)
|
||||
{
|
||||
#if __cpp_range_based_for >= 202211L // lifetime extension of temporaries
|
||||
for(const config& def : read_and_validate(full_path).child_range("gui")) {
|
||||
for(const config& def : read_and_validate(full_path).child_range("gui")) {
|
||||
#else
|
||||
config cfg = read_and_validate(full_path);
|
||||
for(const config& def : cfg.child_range("gui")) {
|
||||
config cfg = read_and_validate(full_path);
|
||||
for(const config& def : cfg.child_range("gui")) {
|
||||
#endif
|
||||
const bool is_default = def["id"] == "default";
|
||||
const bool is_default = def["id"] == "default";
|
||||
|
||||
if(is_default && !is_core) {
|
||||
ERR_GUI_P << "UI theme id 'default' is reserved for core themes.";
|
||||
continue;
|
||||
}
|
||||
if(is_default && !is_core) {
|
||||
ERR_GUI_P << "UI theme id 'default' is reserved for core themes.";
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto iter = register_theme(def);
|
||||
if(!iter) continue;
|
||||
const auto iter = register_theme(def);
|
||||
if(!iter) continue;
|
||||
|
||||
if(is_default && is_core) {
|
||||
default_gui = *iter;
|
||||
current_gui = default_gui;
|
||||
}
|
||||
if(is_default && is_core) {
|
||||
default_gui = *iter;
|
||||
current_gui = default_gui;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
auto read_and_validate(const std::string& path) -> config
|
||||
try {
|
||||
filesystem::scoped_istream stream = preprocess_file(path, &defines_);
|
||||
return ::read(*stream, &validator_);
|
||||
|
||||
} catch(const config::error& e) {
|
||||
ERR_GUI_P << "Could not read gui file: " << path;
|
||||
ERR_GUI_P << e.what();
|
||||
return {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a theme definition object to the global registry.
|
||||
*
|
||||
* @param def A valid gui_definition config.
|
||||
*
|
||||
* @returns An optional iterator to the newly-constructed definition.
|
||||
* If errors occurred while parsing the config or a theme with
|
||||
* the given ID already exists, returns nullopt.
|
||||
*/
|
||||
auto register_theme(const config& def) const -> utils::optional<gui_theme_map_t::iterator>
|
||||
try {
|
||||
auto [iter, is_unique] = guis.try_emplace(def["id"], def);
|
||||
if(is_unique) return iter;
|
||||
|
||||
ERR_GUI_P << "UI Theme '" << def["id"] << "' already exists.";
|
||||
return utils::nullopt;
|
||||
|
||||
} catch(const wml_exception& e) {
|
||||
ERR_GUI_P << "Invalid UI theme: " << def["id"];
|
||||
ERR_GUI_P << e.user_message;
|
||||
return utils::nullopt;
|
||||
}
|
||||
|
||||
/** GUI2 schema validator. */
|
||||
schema_validation::schema_validator validator_;
|
||||
|
||||
/** Common macro context shared by all themes (@todo: document this fact). */
|
||||
preproc_map defines_;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -126,6 +111,9 @@ void init()
|
|||
{
|
||||
LOG_GUI_G << "Initializing UI subststem.";
|
||||
|
||||
// Reset the registry in case we're re-initializing
|
||||
guis.clear();
|
||||
|
||||
// Save current screen size.
|
||||
settings::update_screen_size_variables();
|
||||
|
||||
|
@ -133,10 +121,8 @@ void init()
|
|||
// Parse GUI definitions from mainline
|
||||
//
|
||||
|
||||
theme_parser parser;
|
||||
|
||||
try {
|
||||
parser.parse(filesystem::get_wml_location("gui/_main.cfg").value(), true);
|
||||
parse(filesystem::get_wml_location("gui/_main.cfg").value(), true);
|
||||
} catch(const utils::bad_optional_access&) {
|
||||
FAIL("GUI2: gui/_main.cfg not found.");
|
||||
}
|
||||
|
@ -157,7 +143,7 @@ void init()
|
|||
const std::string gui_file = umc + "/gui-theme.cfg";
|
||||
|
||||
if(filesystem::file_exists(gui_file)) {
|
||||
parser.parse(gui_file, false);
|
||||
parse(gui_file, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user