aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2024-02-05 20:38:23 +0100
committer GitHub <noreply@github.com>2024-02-05 20:38:23 +0100
commit6489da997cddb20667db0455fa4f38319dc7c883 (patch)
tree4e343f81b13f166ad4a478962348d4734ea7e11b /src/openvic-simulation
parent068c13ede817d17df599ca3481261bf17ed95604 (diff)
parent87fa1c74281a651b23089079c4c1621d4fb66d73 (diff)
Merge pull request #145 from OpenVicProject/gui-loading
Added support for loading all gui files
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp19
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.cpp8
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp30
-rw-r--r--src/openvic-simulation/history/DiplomaticHistory.cpp46
-rw-r--r--src/openvic-simulation/history/Period.cpp2
-rw-r--r--src/openvic-simulation/interface/GFX.cpp35
-rw-r--r--src/openvic-simulation/interface/GFX.hpp28
-rw-r--r--src/openvic-simulation/interface/GUI.cpp208
-rw-r--r--src/openvic-simulation/interface/GUI.hpp114
-rw-r--r--src/openvic-simulation/interface/LoadBase.hpp12
-rw-r--r--src/openvic-simulation/interface/UI.cpp41
-rw-r--r--src/openvic-simulation/interface/UI.hpp6
-rw-r--r--src/openvic-simulation/map/Map.cpp2
-rw-r--r--src/openvic-simulation/military/Deployment.cpp2
-rw-r--r--src/openvic-simulation/misc/Define.cpp4
-rw-r--r--src/openvic-simulation/scripts/Condition.cpp2
-rw-r--r--src/openvic-simulation/types/Colour.hpp6
-rw-r--r--src/openvic-simulation/types/Date.hpp12
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.hpp40
-rw-r--r--src/openvic-simulation/types/Vector.hpp3
-rw-r--r--src/openvic-simulation/types/fixed_point/FixedPoint.hpp13
-rw-r--r--src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp7
-rw-r--r--src/openvic-simulation/types/fixed_point/FixedPointMath.hpp2
-rw-r--r--src/openvic-simulation/utility/Getters.hpp16
-rw-r--r--src/openvic-simulation/utility/Logger.hpp25
25 files changed, 515 insertions, 168 deletions
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index c6d6281..157ff04 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -283,21 +283,34 @@ bool Dataloader::_load_interface_files(UIManager& ui_manager) const {
ui_manager.lock_sprites();
ui_manager.lock_fonts();
- // Hard-coded example until the mechanism for requesting them from GDScript is fleshed out
+ /* Hard-coded GUI file names, might be replaced with a dynamic system but everything should still be loaded on startup. */
static const std::vector<std::string_view> gui_files {
- "province_interface.gui", "topbar.gui"
+ /* Contains generic listbox scrollbar */
+ "core",
+
+ /* Over-map menus */
+ "province_interface", "topbar", "menubar", "outliner",
+
+ /* Nation management screens */
+ "country_production", "country_budget", "country_technology", "country_politics", "country_pops", "country_trade",
+ "country_diplomacy", "country_military"
};
+ static constexpr std::string_view gui_file_extension = ".gui";
+
ui_manager.reserve_more_scenes(gui_files.size());
for (std::string_view const& gui_file : gui_files) {
if (!ui_manager.load_gui_file(
- gui_file, parse_defines(lookup_file(append_string_views(interface_directory, gui_file))).get_file_node()
+ gui_file, parse_defines(lookup_file(
+ append_string_views(interface_directory, gui_file, gui_file_extension)
+ )).get_file_node()
)) {
Logger::error("Failed to load interface gui file: ", gui_file);
ret = false;
}
}
+
ui_manager.lock_scenes();
return ret;
diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp
index 7ab0dbe..297937a 100644
--- a/src/openvic-simulation/dataloader/NodeTools.cpp
+++ b/src/openvic-simulation/dataloader/NodeTools.cpp
@@ -169,6 +169,14 @@ node_callback_t NodeTools::expect_date(callback_t<Date> callback) {
return expect_identifier(expect_date_str(callback));
}
+node_callback_t NodeTools::expect_date_string(callback_t<Date> callback) {
+ return expect_string(expect_date_str(callback));
+}
+
+node_callback_t NodeTools::expect_date_identifier_or_string(callback_t<Date> callback) {
+ return expect_identifier_or_string(expect_date_str(callback));
+}
+
node_callback_t NodeTools::expect_years(callback_t<Timespan> callback) {
return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool {
return callback(Timespan::from_years(val));
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index 54b61d0..c41c09e 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -119,6 +119,8 @@ namespace OpenVic {
callback_t<std::string_view> expect_date_str(callback_t<Date> callback);
node_callback_t expect_date(callback_t<Date> callback);
+ node_callback_t expect_date_string(callback_t<Date> callback);
+ node_callback_t expect_date_identifier_or_string(callback_t<Date> callback);
node_callback_t expect_years(callback_t<Timespan> callback);
node_callback_t expect_months(callback_t<Timespan> callback);
node_callback_t expect_days(callback_t<Timespan> callback);
@@ -371,15 +373,15 @@ namespace OpenVic {
template<typename T, StringMapCase Case>
Callback<std::string_view> auto expect_mapped_string(
- template_string_map_t<T, Case> const& map, Callback<T> auto callback
+ template_string_map_t<T, Case> const& map, Callback<T> auto callback, bool warn = false
) {
- return [&map, callback](std::string_view string) -> bool {
+ return [&map, callback, warn](std::string_view string) -> bool {
const typename template_string_map_t<T, Case>::const_iterator it = map.find(string);
if (it != map.end()) {
return callback(it->second);
}
- Logger::error("String not found in map: ", string);
- return false;
+ Logger::warn_or_error(warn, "String not found in map: ", string);
+ return warn;
};
}
@@ -470,24 +472,14 @@ namespace OpenVic {
};
}
- template<typename... Args>
- bool warn_or_error(bool warn, Args&&... args) {
- if (warn) {
- Logger::warning(std::forward<Args>(args)...);
- return true;
- } else {
- Logger::error(std::forward<Args>(args)...);
- return false;
- }
- }
-
template<typename T, typename U, typename... SetArgs>
Callback<T> auto set_callback(tsl::ordered_set<U, SetArgs...>& set, bool warn = false) {
return [&set, warn](T val) -> bool {
if (set.emplace(std::move(val)).second) {
return true;
}
- return warn_or_error(warn, "Duplicate set entry: \"", val, "\"");
+ Logger::warn_or_error(warn, "Duplicate set entry: \"", val, "\"");
+ return warn;
};
}
@@ -497,7 +489,8 @@ namespace OpenVic {
if (set.emplace(&val).second) {
return true;
}
- return warn_or_error(warn, "Duplicate set entry: \"", &val, "\"");
+ Logger::warn_or_error(warn, "Duplicate set entry: \"", &val, "\"");
+ return warn;
};
}
@@ -509,7 +502,8 @@ namespace OpenVic {
if (map.emplace(key, std::move(value)).second) {
return true;
}
- return warn_or_error(warn, "Duplicate map entry with key: \"", key, "\"");
+ Logger::warn_or_error(warn, "Duplicate map entry with key: \"", key, "\"");
+ return warn;
};
}
}
diff --git a/src/openvic-simulation/history/DiplomaticHistory.cpp b/src/openvic-simulation/history/DiplomaticHistory.cpp
index 55d6d6b..22ee765 100644
--- a/src/openvic-simulation/history/DiplomaticHistory.cpp
+++ b/src/openvic-simulation/history/DiplomaticHistory.cpp
@@ -32,20 +32,20 @@ AllianceHistory::AllianceHistory(
Country const* new_first,
Country const* new_second,
const Period new_period
-) : first { new_first }, second { new_second }, period {new_period} {}
+) : first { new_first }, second { new_second }, period { new_period } {}
ReparationsHistory::ReparationsHistory(
Country const* new_receiver,
Country const* new_sender,
const Period new_period
-) : receiver { new_receiver }, sender { new_sender }, period {new_period} {}
+) : receiver { new_receiver }, sender { new_sender }, period { new_period } {}
SubjectHistory::SubjectHistory(
Country const* new_overlord,
Country const* new_subject,
const type_t new_type,
const Period new_period
-) : overlord { new_overlord }, subject { new_subject }, type { new_type }, period {new_period} {}
+) : overlord { new_overlord }, subject { new_subject }, type { new_type }, period { new_period } {}
void DiplomaticHistoryManager::reserve_more_wars(size_t size) {
if (locked) {
@@ -115,10 +115,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const&
std::optional<Date> end {};
bool ret = expect_dictionary_keys(
- "first", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(first))),
- "second", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(second))),
- "start_date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(start))),
- "end_date", ZERO_OR_ONE, expect_identifier_or_string(expect_date_str(assign_variable_callback(end)))
+ "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(first)),
+ "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(second)),
+ "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)),
+ "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end))
)(node);
alliances.push_back({ first, second, { start, end } });
@@ -131,10 +131,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const&
std::optional<Date> end {};
bool ret = expect_dictionary_keys(
- "first", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(overlord))),
- "second", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(subject))),
- "start_date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(start))),
- "end_date", ZERO_OR_ONE, expect_identifier_or_string(expect_date_str(assign_variable_callback(end)))
+ "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)),
+ "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)),
+ "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)),
+ "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end))
)(node);
subjects.push_back({ overlord, subject, SubjectHistory::type_t::VASSAL, { start, end } });
@@ -147,10 +147,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const&
std::optional<Date> end {};
bool ret = expect_dictionary_keys(
- "first", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(overlord)),
- "second", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(subject)),
- "start_date", ONE_EXACTLY, expect_date(assign_variable_callback(start)),
- "end_date", ZERO_OR_ONE, expect_date(assign_variable_callback(end))
+ "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)),
+ "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)),
+ "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)),
+ "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end))
)(node);
subjects.push_back({ overlord, subject, SubjectHistory::type_t::UNION, { start, end } });
@@ -163,10 +163,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const&
std::optional<Date> end {};
bool ret = expect_dictionary_keys(
- "first", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(overlord)),
- "second", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(subject)),
- "start_date", ONE_EXACTLY, expect_date(assign_variable_callback(start)),
- "end_date", ZERO_OR_ONE, expect_date(assign_variable_callback(end))
+ "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)),
+ "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)),
+ "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)),
+ "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end))
)(node);
subjects.push_back({ overlord, subject, SubjectHistory::type_t::SUBSTATE, { start, end } });
@@ -179,10 +179,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const&
std::optional<Date> end {};
bool ret = expect_dictionary_keys(
- "first", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(receiver)),
- "second", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(sender)),
- "start_date", ONE_EXACTLY, expect_date(assign_variable_callback(start)),
- "end_date", ZERO_OR_ONE, expect_date(assign_variable_callback(end))
+ "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(receiver)),
+ "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(sender)),
+ "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)),
+ "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end))
)(node);
reparations.push_back({ receiver, sender, { start, end } });
diff --git a/src/openvic-simulation/history/Period.cpp b/src/openvic-simulation/history/Period.cpp
index cb133dd..37758a1 100644
--- a/src/openvic-simulation/history/Period.cpp
+++ b/src/openvic-simulation/history/Period.cpp
@@ -5,7 +5,7 @@ using namespace OpenVic;
Period::Period(
const Date new_start_date,
const std::optional<Date> new_end_date
-) : start_date {new_start_date}, end_date {new_end_date} {}
+) : start_date { new_start_date }, end_date { new_end_date } {}
bool Period::is_date_in_period(const Date date) const {
return start_date <= date && (!end_date.has_value() || end_date.value() >= date);
diff --git a/src/openvic-simulation/interface/GFX.cpp b/src/openvic-simulation/interface/GFX.cpp
index ca31419..ff2737c 100644
--- a/src/openvic-simulation/interface/GFX.cpp
+++ b/src/openvic-simulation/interface/GFX.cpp
@@ -4,8 +4,11 @@ using namespace OpenVic;
using namespace OpenVic::GFX;
using namespace OpenVic::NodeTools;
-Font::Font(std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname)
- : HasIdentifierAndAlphaColour { new_identifier, new_colour, false }, fontname { new_fontname } {}
+Font::Font(
+ std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname, std::string_view new_charset,
+ uint32_t new_height
+) : HasIdentifierAndAlphaColour { new_identifier, new_colour, false }, fontname { new_fontname }, charset { new_charset },
+ height { new_height } {}
node_callback_t Sprite::expect_sprites(length_callback_t length_callback, callback_t<std::unique_ptr<Sprite>&&> callback) {
return expect_dictionary_keys_and_length(
@@ -17,8 +20,9 @@ node_callback_t Sprite::expect_sprites(length_callback_t length_callback, callba
"textSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, TextureSprite>(callback),
"maskedShieldType", ZERO_OR_MORE, _expect_instance<Sprite, MaskedFlag>(callback),
"tileSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, TileTextureSprite>(callback),
- // TODO - add the rest of the sprite types
- "corneredTileSpriteType", ZERO_OR_MORE, success_callback,
+ "corneredTileSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, CorneredTileTextureSprite>(callback),
+
+ /* Each only has one vanilla instance which isn't used anywhere. */
"BarChartType", ZERO_OR_MORE, success_callback,
"scrollingSprite", ZERO_OR_MORE, success_callback
);
@@ -47,8 +51,8 @@ TileTextureSprite::TileTextureSprite() : texture_file {}, size {} {}
bool TileTextureSprite::_fill_key_map(case_insensitive_key_map_t& key_map) {
bool ret = Sprite::_fill_key_map(key_map);
ret &= add_key_map_entries(key_map,
- "texturefile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)),
- "size", ZERO_OR_ONE, expect_ivec2(assign_variable_callback(size)),
+ "texturefile", ONE_EXACTLY, expect_string(assign_variable_callback_string(texture_file)),
+ "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)),
"norefcount", ZERO_OR_ONE, success_callback,
"loadType", ZERO_OR_ONE, success_callback
@@ -56,7 +60,22 @@ bool TileTextureSprite::_fill_key_map(case_insensitive_key_map_t& key_map) {
return ret;
}
-ProgressBar::ProgressBar() : back_colour {}, progress_colour {} {}
+CorneredTileTextureSprite::CorneredTileTextureSprite() : texture_file {}, size {}, border_size {} {}
+
+bool CorneredTileTextureSprite::_fill_key_map(case_insensitive_key_map_t& key_map) {
+ bool ret = Sprite::_fill_key_map(key_map);
+ ret &= add_key_map_entries(key_map,
+ "texturefile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)),
+ "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)),
+ "borderSize", ONE_EXACTLY, expect_ivec2(assign_variable_callback(border_size)),
+
+ "allwaystransparent", ZERO_OR_ONE, success_callback,
+ "loadType", ZERO_OR_ONE, success_callback
+ );
+ return ret;
+}
+
+ProgressBar::ProgressBar() : back_colour {}, back_texture_file {}, progress_colour {}, progress_texture_file {}, size {} {}
bool ProgressBar::_fill_key_map(case_insensitive_key_map_t& key_map) {
bool ret = Sprite::_fill_key_map(key_map);
@@ -90,6 +109,7 @@ bool LineChart::_fill_key_map(case_insensitive_key_map_t& key_map) {
ret &= add_key_map_entries(key_map,
"size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)),
"linewidth", ONE_EXACTLY, expect_uint(assign_variable_callback(linewidth)),
+
"allwaystransparent", ZERO_OR_ONE, success_callback
);
return ret;
@@ -102,6 +122,7 @@ bool MaskedFlag::_fill_key_map(case_insensitive_key_map_t& key_map) {
ret &= add_key_map_entries(key_map,
"textureFile1", ONE_EXACTLY, expect_string(assign_variable_callback_string(overlay_file)),
"textureFile2", ONE_EXACTLY, expect_string(assign_variable_callback_string(mask_file)),
+
"effectFile", ONE_EXACTLY, success_callback,
"allwaystransparent", ZERO_OR_ONE, success_callback,
"flipv", ZERO_OR_ONE, success_callback
diff --git a/src/openvic-simulation/interface/GFX.hpp b/src/openvic-simulation/interface/GFX.hpp
index 21baa85..108ecb6 100644
--- a/src/openvic-simulation/interface/GFX.hpp
+++ b/src/openvic-simulation/interface/GFX.hpp
@@ -12,11 +12,16 @@ namespace OpenVic::GFX {
friend class OpenVic::UIManager;
private:
- const std::string PROPERTY(fontname);
+ std::string PROPERTY(fontname);
+ std::string PROPERTY(charset);
+ uint32_t PROPERTY(height);
// TODO - colorcodes, effect
- Font(std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname);
+ Font(
+ std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname,
+ std::string_view new_charset, uint32_t new_height
+ );
public:
Font(Font&&) = default;
@@ -79,6 +84,25 @@ namespace OpenVic::GFX {
OV_DETAIL_GET_TYPE
};
+ class CorneredTileTextureSprite final : public Sprite {
+ friend std::unique_ptr<CorneredTileTextureSprite> std::make_unique<CorneredTileTextureSprite>();
+
+ std::string PROPERTY(texture_file);
+ ivec2_t PROPERTY(size);
+ ivec2_t PROPERTY(border_size);
+
+ protected:
+ CorneredTileTextureSprite();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override;
+
+ public:
+ CorneredTileTextureSprite(CorneredTileTextureSprite&&) = default;
+ virtual ~CorneredTileTextureSprite() = default;
+
+ OV_DETAIL_GET_TYPE
+ };
+
class ProgressBar final : public Sprite {
friend std::unique_ptr<ProgressBar> std::make_unique<ProgressBar>();
diff --git a/src/openvic-simulation/interface/GUI.cpp b/src/openvic-simulation/interface/GUI.cpp
index 7aebfe8..94e1fe3 100644
--- a/src/openvic-simulation/interface/GUI.cpp
+++ b/src/openvic-simulation/interface/GUI.cpp
@@ -6,6 +6,16 @@ using namespace OpenVic;
using namespace OpenVic::GUI;
using namespace OpenVic::NodeTools;
+Position::Position() : position {} {}
+
+bool Position::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) {
+ bool ret = Named::_fill_key_map(key_map);
+ ret &= add_key_map_entry(key_map,
+ "position", ONE_EXACTLY, expect_fvec2(assign_variable_callback(position))
+ );
+ return ret;
+}
+
Element::Element() : position {}, orientation { orientation_t::UPPER_LEFT } {}
bool Element::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
@@ -14,11 +24,14 @@ bool Element::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIMa
static const string_map_t<orientation_t> orientation_map = {
{ "UPPER_LEFT", UPPER_LEFT }, { "LOWER_LEFT", LOWER_LEFT },
{ "LOWER_RIGHT", LOWER_RIGHT }, { "UPPER_RIGHT", UPPER_RIGHT },
- { "CENTER", CENTER }
+ { "CENTER", CENTER }, { "CENTER_UP", CENTER_UP }, { "CENTER_DOWN", CENTER_DOWN }
};
ret &= add_key_map_entries(key_map,
- "position", ONE_EXACTLY, expect_fvec2(assign_variable_callback(position)),
- "orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation)))
+ "position", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(position)),
+ "orientation", ZERO_OR_ONE, expect_identifier_or_string(expect_mapped_string(
+ orientation_map, assign_variable_callback(orientation),
+ true /* Warn if the key here is invalid, leaving the default orientation UPPER_LEFT unchanged. */
+ ))
);
return ret;
}
@@ -29,22 +42,31 @@ bool Element::_fill_elements_key_map(
bool ret = true;
ret &= add_key_map_entries(key_map,
"iconType", ZERO_OR_MORE, _expect_instance<Element, Icon>(callback, ui_manager),
+ "shieldtype", ZERO_OR_MORE, _expect_instance<Element, Icon>(callback, ui_manager),
"guiButtonType", ZERO_OR_MORE, _expect_instance<Element, Button>(callback, ui_manager),
"checkboxType", ZERO_OR_MORE, _expect_instance<Element, Checkbox>(callback, ui_manager),
"textBoxType", ZERO_OR_MORE, _expect_instance<Element, Text>(callback, ui_manager),
"instantTextBoxType", ZERO_OR_MORE, _expect_instance<Element, Text>(callback, ui_manager),
"OverlappingElementsBoxType", ZERO_OR_MORE, _expect_instance<Element, OverlappingElementsBox>(callback, ui_manager),
"listboxType", ZERO_OR_MORE, _expect_instance<Element, ListBox>(callback, ui_manager),
+ "editBoxType", ZERO_OR_MORE, _expect_instance<Element, TextEditBox>(callback, ui_manager),
+ "scrollbarType", ZERO_OR_MORE, _expect_instance<Element, Scrollbar>(callback, ui_manager),
"windowType", ZERO_OR_MORE, _expect_instance<Element, Window>(callback, ui_manager),
- "positionType", ZERO_OR_MORE, success_callback // TODO - load this as a marker for placing sub-scenes
+ "eu3dialogtype", ZERO_OR_MORE, _expect_instance<Element, Window>(callback, ui_manager)
);
return ret;
}
bool Scene::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
- return Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool {
+ bool ret = Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool {
return scene_elements.add_item(std::move(element));
}, ui_manager);
+ ret &= add_key_map_entry(key_map,
+ "positionType", ZERO_OR_MORE, Position::_expect_value<Position>([this](Position&& position) -> bool {
+ return scene_positions.add_item(std::move(position));
+ })
+ );
+ return ret;
}
node_callback_t Scene::expect_scene(
@@ -56,7 +78,7 @@ node_callback_t Scene::expect_scene(
}, ui_manager);
}
-Window::Window() : moveable { false }, fullscreen { false } {}
+Window::Window() : background {}, size {}, moveable { false }, fullscreen { false } {}
bool Window::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool {
@@ -64,55 +86,71 @@ bool Window::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIMan
}, ui_manager);
ret &= Element::_fill_key_map(key_map, ui_manager);
ret &= add_key_map_entries(key_map,
- "backGround", ZERO_OR_ONE, success_callback, // TODO - load as potential panel texture (almost always empty)
"size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
- "moveable", ONE_EXACTLY, expect_int_bool(assign_variable_callback(moveable)),
+ "moveable", ZERO_OR_ONE, expect_int_bool(assign_variable_callback(moveable)),
+ "fullScreen", ZERO_OR_ONE, expect_bool(assign_variable_callback(fullscreen)),
+ "backGround", ZERO_OR_ONE, expect_string(assign_variable_callback_string(background), true),
+
"dontRender", ZERO_OR_ONE, success_callback, // always empty string?
"horizontalBorder", ZERO_OR_ONE, success_callback,
"verticalBorder", ZERO_OR_ONE, success_callback,
- "fullScreen", ZERO_OR_ONE, expect_bool(assign_variable_callback(fullscreen))
+ "upsound", ZERO_OR_ONE, success_callback,
+ "downsound", ZERO_OR_ONE, success_callback
);
return ret;
}
-Icon::Icon() : sprite { nullptr }, frame { GFX::NO_FRAMES } {}
+Icon::Icon() : sprite { nullptr }, frame { GFX::NO_FRAMES }, scale { 1 }, rotation { 0 } {}
bool Icon::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = Element::_fill_key_map(key_map, ui_manager);
ret &= add_key_map_entries(key_map,
- "spriteType", ONE_EXACTLY, expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite))),
- "frame", ZERO_OR_ONE, expect_uint(assign_variable_callback(frame))
+ // TODO - make these share a ONE_EXACTLY count
+ "spriteType", ZERO_OR_ONE, ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite)),
+ "buttonMesh", ZERO_OR_ONE, ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite)),
+
+ "frame", ZERO_OR_ONE, expect_uint(assign_variable_callback(frame)),
+ "scale", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(scale)),
+ "rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(rotation))
);
return ret;
}
-BaseButton::BaseButton() : sprite { nullptr } {}
+BaseButton::BaseButton() : sprite { nullptr }, text {}, font { nullptr } {}
bool BaseButton::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = Element::_fill_key_map(key_map, ui_manager);
// look up sprite registry for texture sprite with name...
ret &= add_key_map_entries(key_map,
+ // TODO - make these share a ONE_EXACTLY count
"quadTextureSprite", ZERO_OR_ONE,
- expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite)), true),
+ ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite), true),
"spriteType", ZERO_OR_ONE,
- expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite)), true),
- "shortcut", ZERO_OR_ONE, success_callback // TODO - load and use shortcuts (how to integrate with custom keybinds?)
+ ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite)),
+
+ "buttonText", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true),
+ /* Some buttons have multiple fonts listed with the last one being used. */
+ "buttonFont", ZERO_OR_MORE, ui_manager.expect_font_string(assign_variable_callback_pointer(font), true),
+
+ "shortcut", ZERO_OR_ONE, success_callback, // TODO - load and use shortcuts (how to integrate with custom keybinds?)
+ "tooltip", ZERO_OR_ONE, success_callback,
+ "tooltipText", ZERO_OR_ONE, success_callback,
+ "delayedTooltipText", ZERO_OR_ONE, success_callback
);
return ret;
}
-Button::Button() : text {}, font { nullptr} {}
+Button::Button() : size {}, rotation { 0 } {}
bool Button::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = BaseButton::_fill_key_map(key_map, ui_manager);
ret &= add_key_map_entries(key_map,
- "buttonText", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true),
- "buttonFont", ZERO_OR_ONE, expect_string(ui_manager.expect_font_str(assign_variable_callback_pointer(font))),
- "clicksound", ZERO_OR_ONE, success_callback,
- /* These are always empty in the base defines */
- "tooltip", ZERO_OR_ONE, success_callback,
- "tooltipText", ZERO_OR_ONE, success_callback,
- "delayedTooltipText", ZERO_OR_ONE, success_callback
+ "size", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(size)),
+ "rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(rotation)),
+
+ "format", ZERO_OR_ONE, success_callback, /* Is always left from what I've seen. */
+ "clicksound", ZERO_OR_ONE, success_callback, // TODO - clicksound!!!
+ "parent", ZERO_OR_ONE, success_callback /* Links buttons to a scrollbar, not needed thanks to contextual info. */
);
return ret;
}
@@ -128,7 +166,7 @@ bool AlignedElement::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_ma
bool ret = Element::_fill_key_map(key_map, ui_manager);
using enum format_t;
static const string_map_t<format_t> format_map = {
- { "left", left }, { "right", right }, { "centre", centre }, { "center", centre }
+ { "left", left }, { "right", right }, { "centre", centre }, { "center", centre }, { "justified", justified }
};
ret &= add_key_map_entries(key_map,
"format", ZERO_OR_ONE, expect_identifier(expect_mapped_string(format_map, assign_variable_callback(format))
@@ -136,18 +174,19 @@ bool AlignedElement::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_ma
return ret;
}
-Text::Text() : text {}, font { nullptr } {}
+Text::Text() : text {}, font { nullptr }, max_size {} {}
bool Text::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = AlignedElement::_fill_key_map(key_map, ui_manager);
ret &= add_key_map_entries(key_map,
"text", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true),
- "font", ONE_EXACTLY, expect_string(ui_manager.expect_font_str(assign_variable_callback_pointer(font))),
- "maxWidth", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_size.x)),
- "maxHeight", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_size.y)),
+ "font", ONE_EXACTLY, ui_manager.expect_font_string(assign_variable_callback_pointer(font)),
+ "maxWidth", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(max_size.x)),
+ "maxHeight", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(max_size.y)),
"borderSize", ZERO_OR_ONE, success_callback,
"fixedsize", ZERO_OR_ONE, success_callback,
+ "allwaystransparent", ZERO_OR_ONE, success_callback,
// Add warning about redundant key?
"textureFile", ZERO_OR_ONE, success_callback
@@ -155,7 +194,7 @@ bool Text::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManag
return ret;
}
-OverlappingElementsBox::OverlappingElementsBox() : size {} {}
+OverlappingElementsBox::OverlappingElementsBox() : size {}, spacing {} {}
bool OverlappingElementsBox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = AlignedElement::_fill_key_map(key_map, ui_manager);
@@ -166,16 +205,117 @@ bool OverlappingElementsBox::_fill_key_map(NodeTools::case_insensitive_key_map_t
return ret;
}
-ListBox::ListBox() : size {} {}
+ListBox::ListBox() : size {}, offset {}, spacing {}, scrollbar_name {} {}
bool ListBox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = Element::_fill_key_map(key_map, ui_manager);
ret &= add_key_map_entries(key_map,
+ "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
+ "offset", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(offset)),
+ "spacing", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(spacing)),
+ "scrollbartype", ZERO_OR_ONE, expect_string(assign_variable_callback_string(scrollbar_name)),
+
"backGround", ZERO_OR_ONE, success_callback,
+ "borderSize", ZERO_OR_ONE, success_callback,
+ "horizontal", ZERO_OR_ONE, success_callback,
+ "priority", ZERO_OR_ONE, success_callback,
+ "allwaystransparent", ZERO_OR_ONE, success_callback
+ );
+ return ret;
+}
+
+TextEditBox::TextEditBox() : text {}, font { nullptr }, texture_file {}, size {}, border_size {} {}
+
+bool TextEditBox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
+ bool ret = Element::_fill_key_map(key_map, ui_manager);
+ ret &= add_key_map_entries(key_map,
+ "text", ONE_EXACTLY, expect_string(assign_variable_callback_string(text), true),
+ "font", ONE_EXACTLY, ui_manager.expect_font_string(assign_variable_callback_pointer(font)),
+ "textureFile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file), true),
+ "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
+ "borderSize", ONE_EXACTLY, expect_fvec2(assign_variable_callback(border_size))
+ );
+ return ret;
+}
+
+Scrollbar::Scrollbar()
+ : slider_button_name {}, track_button_name {}, less_button_name{}, more_button_name {}, size {}, border_size {},
+ min_value {}, max_value {}, step_size {}, start_value {}, horizontal { false }, use_range_limit { false },
+ range_limit_min {}, range_limit_max {}, range_limit_min_icon_name {}, range_limit_max_icon_name {} {
+ scrollbar_elements.reserve(4); /* Space for 4 buttons, might need 2 more for range limit icons. */
+}
+
+bool Scrollbar::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
+ bool ret = Element::_fill_key_map(key_map, ui_manager);
+ const auto add_element = [this](std::unique_ptr<Element>&& element) -> bool {
+ return scrollbar_elements.add_item(std::move(element));
+ };
+ ret &= add_key_map_entries(key_map,
+ "slider", ONE_EXACTLY, expect_string(assign_variable_callback_string(slider_button_name)),
+ "track", ONE_EXACTLY, expect_string(assign_variable_callback_string(track_button_name)),
+ "leftbutton", ONE_EXACTLY, expect_string(assign_variable_callback_string(less_button_name)),
+ "rightbutton", ONE_EXACTLY, expect_string(assign_variable_callback_string(more_button_name)),
"size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
- "spacing", ZERO_OR_ONE, success_callback,
- "scrollbartype", ZERO_OR_ONE, success_callback, // TODO - implement modable listbox scrollbars
- "borderSize", ZERO_OR_ONE, success_callback
+ "borderSize", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(border_size)),
+ "minValue", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(min_value)),
+ "maxValue", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_value)),
+ "stepSize", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(step_size)),
+ "startValue", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(start_value)),
+ "horizontal", ONE_EXACTLY, expect_int_bool(assign_variable_callback(horizontal)),
+ "useRangeLimit", ZERO_OR_ONE, expect_bool(assign_variable_callback(use_range_limit)),
+ "rangeLimitMin", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(range_limit_min)),
+ "rangeLimitMax", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(range_limit_max)),
+ "rangeLimitMinIcon", ZERO_OR_ONE, expect_string(assign_variable_callback_string(range_limit_min_icon_name)),
+ "rangeLimitMaxIcon", ZERO_OR_ONE, expect_string(assign_variable_callback_string(range_limit_max_icon_name)),
+
+ "guiButtonType", ONE_OR_MORE, _expect_instance<Element, Button>(add_element, ui_manager),
+ "iconType", ZERO_OR_MORE, _expect_instance<Element, Icon>(add_element, ui_manager),
+
+ "priority", ZERO_OR_ONE, success_callback
);
return ret;
}
+
+template<std::derived_from<Element> T>
+T const* Scrollbar::get_element(std::string_view name, std::string_view type) const {
+ Element const* element = scrollbar_elements.get_item_by_identifier(name);
+ if (element != nullptr) {
+ T const* cast_element = element->cast_to<T>();
+ if (cast_element != nullptr) {
+ return cast_element;
+ } else {
+ Logger::error(
+ "GUI Scrollbar ", get_name(), " ", type, " element ", name, " has wrong type: ", element->get_type(),
+ " (expected ", T::get_type_static(), ")"
+ );
+ return nullptr;
+ }
+ } else {
+ Logger::error("GUI Scrollbar ", get_name(), " has no ", type, " element named ", name, "!");
+ return nullptr;
+ }
+}
+
+Button const* Scrollbar::get_slider_button() const {
+ return get_element<Button>(slider_button_name, "slider button");
+}
+
+Button const* Scrollbar::get_track_button() const {
+ return get_element<Button>(track_button_name, "track button");
+}
+
+Button const* Scrollbar::get_less_button() const {
+ return get_element<Button>(less_button_name, "less button");
+}
+
+Button const* Scrollbar::get_more_button() const {
+ return get_element<Button>(more_button_name, "more button");
+}
+
+Icon const* Scrollbar::get_range_limit_min_icon() const {
+ return get_element<Icon>(range_limit_min_icon_name, "range limit min icon");
+}
+
+Icon const* Scrollbar::get_range_limit_max_icon() const {
+ return get_element<Icon>(range_limit_max_icon_name, "range limit max icon");
+}
diff --git a/src/openvic-simulation/interface/GUI.hpp b/src/openvic-simulation/interface/GUI.hpp
index 96bb2a2..f044f7d 100644
--- a/src/openvic-simulation/interface/GUI.hpp
+++ b/src/openvic-simulation/interface/GUI.hpp
@@ -8,12 +8,27 @@ namespace OpenVic {
namespace OpenVic::GUI {
class Scene;
+ class Position final : public Named<> {
+ friend class LoadBase;
+
+ fvec2_t PROPERTY(position);
+
+ protected:
+ Position();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override;
+
+ public:
+ Position(Position&&) = default;
+ virtual ~Position() = default;
+ };
+
class Element : public Named<UIManager const&> {
friend class Scene;
public:
enum class orientation_t {
- UPPER_LEFT, LOWER_LEFT, LOWER_RIGHT, UPPER_RIGHT, CENTER
+ UPPER_LEFT, LOWER_LEFT, LOWER_RIGHT, UPPER_RIGHT, CENTER, CENTER_UP, CENTER_DOWN
};
private:
@@ -37,10 +52,13 @@ namespace OpenVic::GUI {
OV_DETAIL_GET_TYPE
};
+ using element_instance_registry_t = NamedInstanceRegistry<Element, UIManager const&>;
+
class Scene : public Named<UIManager const&> {
friend std::unique_ptr<Scene> std::make_unique<Scene>();
- NamedInstanceRegistry<Element, UIManager const&> IDENTIFIER_REGISTRY(scene_element);
+ element_instance_registry_t IDENTIFIER_REGISTRY(scene_element);
+ NamedRegistry<Position> IDENTIFIER_REGISTRY(scene_position);
protected:
Scene() = default;
@@ -62,12 +80,14 @@ namespace OpenVic::GUI {
class Window final : public Element {
friend std::unique_ptr<Window> std::make_unique<Window>();
- NamedInstanceRegistry<Element, UIManager const&> IDENTIFIER_REGISTRY(window_element);
+ element_instance_registry_t IDENTIFIER_REGISTRY(window_element);
+ std::string PROPERTY(background); /* The name of a child button who's sprite is used as the background. */
fvec2_t PROPERTY(size);
bool PROPERTY(moveable);
bool PROPERTY(fullscreen);
- // TODO - background, dontRender, horizontalBorder, verticalBorder
+
+ // TODO - dontRender, horizontalBorder, verticalBorder
protected:
Window();
@@ -86,6 +106,8 @@ namespace OpenVic::GUI {
GFX::Sprite const* PROPERTY(sprite);
GFX::frame_t PROPERTY(frame);
+ fixed_point_t PROPERTY(scale);
+ fixed_point_t PROPERTY(rotation); /* In radians, usually one of 0, PI/2 or -PI/2. */
protected:
Icon();
@@ -101,6 +123,9 @@ namespace OpenVic::GUI {
class BaseButton : public Element {
GFX::Sprite const* PROPERTY(sprite);
+ std::string PROPERTY(text);
+ GFX::Font const* PROPERTY(font);
+
// TODO - shortcut
protected:
@@ -118,8 +143,8 @@ namespace OpenVic::GUI {
class Button final : public BaseButton {
friend std::unique_ptr<Button> std::make_unique<Button>();
- std::string PROPERTY(text);
- GFX::Font const* PROPERTY(font);
+ fvec2_t PROPERTY(size);
+ fixed_point_t PROPERTY(rotation); /* In radians, usually one of 0, PI/2 or -PI/2. */
// TODO - clicksound
@@ -153,7 +178,7 @@ namespace OpenVic::GUI {
class AlignedElement : public Element {
public:
enum class format_t {
- left, centre, right
+ left, centre, right, justified
};
private:
@@ -176,7 +201,7 @@ namespace OpenVic::GUI {
std::string PROPERTY(text);
GFX::Font const* PROPERTY(font);
- fvec2_t PROPERTY(max_size); // maxWidth, maxHeight
+ fvec2_t PROPERTY(max_size); /* Defines keys: maxWidth, maxHeight */
// TODO - borderSize, fixedsize, textureFile
@@ -214,8 +239,11 @@ namespace OpenVic::GUI {
friend std::unique_ptr<ListBox> std::make_unique<ListBox>();
fvec2_t PROPERTY(size);
+ fvec2_t PROPERTY(offset);
+ fixed_point_t PROPERTY(spacing);
+ std::string PROPERTY(scrollbar_name); /* In vanilla this is always core's standardlistbox_slider */
- // TODO - backGround, spacing, scrollbartype, borderSize
+ // TODO - backGround, borderSize
protected:
ListBox();
@@ -228,4 +256,72 @@ namespace OpenVic::GUI {
OV_DETAIL_GET_TYPE
};
+
+ class TextEditBox final : public Element {
+ friend std::unique_ptr<TextEditBox> std::make_unique<TextEditBox>();
+
+ std::string PROPERTY(text);
+ GFX::Font const* PROPERTY(font);
+ std::string PROPERTY(texture_file);
+ fvec2_t PROPERTY(size);
+ fvec2_t PROPERTY(border_size);
+
+ protected:
+ TextEditBox();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override;
+
+ public:
+ TextEditBox(TextEditBox&&) = default;
+ virtual ~TextEditBox() = default;
+
+ OV_DETAIL_GET_TYPE
+ };
+
+ class Scrollbar final : public Element {
+ friend std::unique_ptr<Scrollbar> std::make_unique<Scrollbar>();
+
+ element_instance_registry_t IDENTIFIER_REGISTRY(scrollbar_element);
+
+ std::string PROPERTY(slider_button_name);
+ std::string PROPERTY(track_button_name);
+ std::string PROPERTY(less_button_name);
+ std::string PROPERTY(more_button_name);
+
+ fvec2_t PROPERTY(size);
+ fvec2_t PROPERTY(border_size);
+ fixed_point_t PROPERTY(min_value);
+ fixed_point_t PROPERTY(max_value);
+ fixed_point_t PROPERTY(step_size);
+ fixed_point_t PROPERTY(start_value);
+ bool PROPERTY_CUSTOM_PREFIX(horizontal, is)
+
+ bool PROPERTY(use_range_limit);
+ fixed_point_t PROPERTY(range_limit_min);
+ fixed_point_t PROPERTY(range_limit_max);
+ std::string PROPERTY(range_limit_min_icon_name);
+ std::string PROPERTY(range_limit_max_icon_name);
+
+ template<std::derived_from<Element> T>
+ T const* get_element(std::string_view name, std::string_view type) const;
+
+ protected:
+ Scrollbar();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override;
+
+ public:
+ Scrollbar(Scrollbar&&) = default;
+ virtual ~Scrollbar() = default;
+
+ Button const* get_slider_button() const;
+ Button const* get_track_button() const;
+ Button const* get_less_button() const;
+ Button const* get_more_button() const;
+
+ Icon const* get_range_limit_min_icon() const;
+ Icon const* get_range_limit_max_icon() const;
+
+ OV_DETAIL_GET_TYPE
+ };
}
diff --git a/src/openvic-simulation/interface/LoadBase.hpp b/src/openvic-simulation/interface/LoadBase.hpp
index 10b0169..29de165 100644
--- a/src/openvic-simulation/interface/LoadBase.hpp
+++ b/src/openvic-simulation/interface/LoadBase.hpp
@@ -23,6 +23,18 @@ namespace OpenVic {
return ret;
}
+ template<std::derived_from<LoadBase<Context...>> T>
+ static NodeTools::node_callback_t _expect_value(
+ NodeTools::callback_t<T&&> callback, Context... context
+ ) {
+ return [callback, &context...](ast::NodeCPtr node) -> bool {
+ T value {};
+ bool ret = value.load(node, context...);
+ ret &= callback(std::move(value));
+ return ret;
+ };
+ }
+
template<std::derived_from<LoadBase<Context...>> T, std::derived_from<T> U>
static NodeTools::node_callback_t _expect_instance(
NodeTools::callback_t<std::unique_ptr<T>&&> callback, Context... context
diff --git a/src/openvic-simulation/interface/UI.cpp b/src/openvic-simulation/interface/UI.cpp
index b977406..2646bb7 100644
--- a/src/openvic-simulation/interface/UI.cpp
+++ b/src/openvic-simulation/interface/UI.cpp
@@ -7,7 +7,9 @@ using namespace OpenVic::NodeTools;
using namespace OpenVic::GFX;
using namespace OpenVic::GUI;
-bool UIManager::add_font(std::string_view identifier, colour_argb_t colour, std::string_view fontname) {
+bool UIManager::add_font(
+ std::string_view identifier, colour_argb_t colour, std::string_view fontname, std::string_view charset, uint32_t height
+) {
if (identifier.empty()) {
Logger::error("Invalid font identifier - empty!");
return false;
@@ -20,23 +22,39 @@ bool UIManager::add_font(std::string_view identifier, colour_argb_t colour, std:
Logger::error("Invalid fontname for font ", identifier, " - empty!");
return false;
}
- return fonts.add_item({ identifier, colour, fontname }, duplicate_warning_callback);
+ return fonts.add_item({ identifier, colour, fontname, charset, height }, duplicate_warning_callback);
}
bool UIManager::_load_font(ast::NodeCPtr node) {
- std::string_view identifier, fontname;
+ std::string_view identifier, fontname, charset;
colour_argb_t colour = colour_argb_t::null();
+ uint32_t height = 0;
bool ret = expect_dictionary_keys(
"name", ONE_EXACTLY, expect_string(assign_variable_callback(identifier)),
"fontname", ONE_EXACTLY, expect_string(assign_variable_callback(fontname)),
"color", ONE_EXACTLY, expect_colour_hex(assign_variable_callback(colour)),
+ "charset", ZERO_OR_ONE, expect_string(assign_variable_callback(charset)),
+ "height", ZERO_OR_ONE, expect_uint(assign_variable_callback(height)),
"colorcodes", ZERO_OR_ONE, success_callback,
"effect", ZERO_OR_ONE, success_callback
)(node);
- ret &= add_font(identifier, colour, fontname);
+ ret &= add_font(identifier, colour, fontname, charset, height);
return ret;
}
+NodeCallback auto UIManager::_load_fonts(std::string_view font_key) {
+ return expect_dictionary_reserve_length(
+ fonts,
+ [this, font_key](std::string_view key, ast::NodeCPtr node) -> bool {
+ if (key != font_key) {
+ Logger::error("Invalid key: \"", key, "\" (expected ", font_key, ")");
+ return false;
+ }
+ return _load_font(node);
+ }
+ );
+}
+
bool UIManager::load_gfx_file(ast::NodeCPtr root) {
return expect_dictionary_keys(
"spriteTypes", ZERO_OR_ONE, Sprite::expect_sprites(
@@ -65,19 +83,10 @@ bool UIManager::load_gfx_file(ast::NodeCPtr root) {
return sprites.add_item(std::move(sprite), duplicate_warning_callback);
}
),
- "bitmapfonts", ZERO_OR_ONE, expect_dictionary_reserve_length(
- fonts,
- [this](std::string_view key, ast::NodeCPtr node) -> bool {
- if (key != "bitmapfont") {
- Logger::error("Invalid bitmapfonts key: ", key);
- return false;
- }
- return _load_font(node);
- }
- ),
+ "bitmapfonts", ZERO_OR_ONE, _load_fonts("bitmapfont"),
+ "fonts", ZERO_OR_ONE, _load_fonts("font"),
"objectTypes", ZERO_OR_ONE, success_callback,
- "lightTypes", ZERO_OR_ONE, success_callback,
- "fonts", ZERO_OR_ONE, success_callback
+ "lightTypes", ZERO_OR_ONE, success_callback
)(root);
}
diff --git a/src/openvic-simulation/interface/UI.hpp b/src/openvic-simulation/interface/UI.hpp
index 286e4f7..c8ffa98 100644
--- a/src/openvic-simulation/interface/UI.hpp
+++ b/src/openvic-simulation/interface/UI.hpp
@@ -10,9 +10,13 @@ namespace OpenVic {
IdentifierRegistry<GFX::Font> IDENTIFIER_REGISTRY(font);
bool _load_font(ast::NodeCPtr node);
+ NodeTools::NodeCallback auto _load_fonts(std::string_view font_key);
public:
- bool add_font(std::string_view identifier, colour_argb_t colour, std::string_view fontname);
+ bool add_font(
+ std::string_view identifier, colour_argb_t colour, std::string_view fontname, std::string_view charset,
+ uint32_t height
+ );
bool load_gfx_file(ast::NodeCPtr root);
bool load_gui_file(std::string_view scene_name, ast::NodeCPtr root);
diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp
index 9a97143..a5cd6a6 100644
--- a/src/openvic-simulation/map/Map.cpp
+++ b/src/openvic-simulation/map/Map.cpp
@@ -80,7 +80,7 @@ Province::distance_t Map::calculate_distance_between(Province const& from, Provi
)
);
- return fvec2_t { min_x, to_pos.y - from_pos.y}.length_squared().sqrt();
+ return fvec2_t { min_x, to_pos.y - from_pos.y }.length_squared().sqrt();
}
using adjacency_t = Province::adjacency_t;
diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp
index 14640ec..4e2693d 100644
--- a/src/openvic-simulation/military/Deployment.cpp
+++ b/src/openvic-simulation/military/Deployment.cpp
@@ -80,7 +80,7 @@ bool DeploymentManager::load_oob_file(
bool ret = expect_dictionary_keys(
"name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(leader_name)),
- "date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(leader_date))),
+ "date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(leader_date)),
"type", ONE_EXACTLY, UnitManager::expect_branch_identifier(assign_variable_callback(leader_branch)),
"personality", ONE_EXACTLY,
game_manager.get_military_manager().get_leader_trait_manager().expect_leader_trait_identifier_or_string(
diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp
index e4e6b52..9ec5d49 100644
--- a/src/openvic-simulation/misc/Define.cpp
+++ b/src/openvic-simulation/misc/Define.cpp
@@ -95,9 +95,7 @@ bool DefineManager::load_defines_file(ast::NodeCPtr root) {
} else if (key == "start_date" || key == "end_date") {
- return expect_identifier_or_string(expect_date_str(
- std::bind_front(&DefineManager::add_date_define, this, key)
- ))(value);
+ return expect_date_identifier_or_string(std::bind_front(&DefineManager::add_date_define, this, key))(value);
} else {
return false;
diff --git a/src/openvic-simulation/scripts/Condition.cpp b/src/openvic-simulation/scripts/Condition.cpp
index 045649b..aab8d93 100644
--- a/src/openvic-simulation/scripts/Condition.cpp
+++ b/src/openvic-simulation/scripts/Condition.cpp
@@ -620,7 +620,7 @@ node_callback_t ConditionManager::expect_condition_node(
} else if (identifier == "relation") {
expect_pair("who", "value"); // { who = [tag/this/from] value = x }
} else if (identifier == "unemployment_by_type") {
- expect_pair("type", "value"); // {type = [poptype] value = x }
+ expect_pair("type", "value"); // { type = [poptype] value = x }
} else if (identifier == "upper_house") {
expect_pair("ideology", "value"); // { ideology = name value = 0.x }
} else if (identifier == "work_available") {
diff --git a/src/openvic-simulation/types/Colour.hpp b/src/openvic-simulation/types/Colour.hpp
index 06a6b36..304d9de 100644
--- a/src/openvic-simulation/types/Colour.hpp
+++ b/src/openvic-simulation/types/Colour.hpp
@@ -12,7 +12,6 @@
#include <type_traits>
#include <utility>
-#include "openvic-simulation/utility/Getters.hpp"
#include "openvic-simulation/utility/Utility.hpp"
namespace OpenVic {
@@ -105,7 +104,10 @@ namespace OpenVic {
/* Colour represented by an unsigned integer, either 24-bit RGB or 32-bit ARGB. */
template<typename ValueT, typename ColourIntT, typename ColourTraits = colour_traits<ValueT, ColourIntT>>
- struct basic_colour_t : ReturnByValueProperty {
+ struct basic_colour_t {
+ /* PROPERTY generated getter functions will return colours by value, rather than const reference. */
+ using ov_return_by_value = void;
+
using colour_traits = ColourTraits;
using value_type = typename colour_traits::value_type;
using integer_type = typename colour_traits::integer_type;
diff --git a/src/openvic-simulation/types/Date.hpp b/src/openvic-simulation/types/Date.hpp
index 9178e6e..9376293 100644
--- a/src/openvic-simulation/types/Date.hpp
+++ b/src/openvic-simulation/types/Date.hpp
@@ -1,16 +1,19 @@
#pragma once
#include <algorithm>
+#include <array>
#include <cstdint>
#include <ostream>
#include <string>
-#include "openvic-simulation/utility/Getters.hpp"
#include "openvic-simulation/utility/Utility.hpp"
namespace OpenVic {
// A relative period between points in time, measured in days
- struct Timespan : ReturnByValueProperty {
+ struct Timespan {
+ /* PROPERTY generated getter functions will return timespans by value, rather than const reference. */
+ using ov_return_by_value = void;
+
using day_t = int64_t;
private:
@@ -86,7 +89,10 @@ namespace OpenVic {
// Represents an in-game date
// Note: Current implementation does not account for leap-years, or dates before Year 0
- struct Date : ReturnByValueProperty {
+ struct Date {
+ /* PROPERTY generated getter functions will return dates by value, rather than const reference. */
+ using ov_return_by_value = void;
+
using year_t = uint16_t;
using month_t = uint8_t;
using day_t = uint8_t;
diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp
index 7e6fdb3..f1edc95 100644
--- a/src/openvic-simulation/types/IdentifierRegistry.hpp
+++ b/src/openvic-simulation/types/IdentifierRegistry.hpp
@@ -269,30 +269,39 @@ namespace OpenVic {
} \
} \
constexpr NodeTools::Callback<std::string_view> auto expect_item_str( \
- NodeTools::Callback<external_value_type CONST&> auto callback, bool warn \
+ NodeTools::Callback<external_value_type CONST&> auto callback, bool allow_empty, bool warn \
) CONST { \
- return [this, callback, warn](std::string_view identifier) -> bool { \
+ return [this, callback, allow_empty, warn](std::string_view identifier) -> bool { \
+ if (identifier.empty()) { \
+ if (allow_empty) { \
+ return true; \
+ } else { \
+ Logger::warn_or_error(warn, "Invalid ", name, " identifier: empty!"); \
+ return warn; \
+ } \
+ } \
external_value_type CONST* item = get_item_by_identifier(identifier); \
if (item != nullptr) { \
return callback(*item); \
} \
- return NodeTools::warn_or_error(warn, "Invalid ", name, " identifier: ", identifier); \
+ Logger::warn_or_error(warn, "Invalid ", name, " identifier: ", identifier); \
+ return warn; \
}; \
} \
constexpr NodeTools::NodeCallback auto expect_item_identifier( \
NodeTools::Callback<external_value_type CONST&> auto callback, bool warn \
) CONST { \
- return NodeTools::expect_identifier(expect_item_str(callback, warn)); \
+ return NodeTools::expect_identifier(expect_item_str(callback, false, warn)); \
} \
constexpr NodeTools::NodeCallback auto expect_item_string( \
- NodeTools::Callback<external_value_type CONST&> auto callback, bool warn \
+ NodeTools::Callback<external_value_type CONST&> auto callback, bool allow_empty, bool warn \
) CONST { \
- return NodeTools::expect_string(expect_item_str(callback, warn)); \
+ return NodeTools::expect_string(expect_item_str(callback, allow_empty, warn), allow_empty); \
} \
constexpr NodeTools::NodeCallback auto expect_item_identifier_or_string( \
- NodeTools::Callback<external_value_type CONST&> auto callback, bool warn \
+ NodeTools::Callback<external_value_type CONST&> auto callback, bool allow_empty, bool warn \
) CONST { \
- return NodeTools::expect_identifier_or_string(expect_item_str(callback, warn)); \
+ return NodeTools::expect_identifier_or_string(expect_item_str(callback, allow_empty, warn), allow_empty); \
} \
constexpr NodeTools::NodeCallback auto expect_item_assign_and_default( \
NodeTools::KeyValueCallback auto default_callback, \
@@ -541,9 +550,10 @@ private:
return registry.get_items(); \
} \
constexpr NodeTools::Callback<std::string_view> auto expect_##singular##_str( \
- NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback, bool warn = false \
+ NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback, bool allow_empty = false, \
+ bool warn = false \
) const_kw { \
- return registry.expect_item_str(callback, warn); \
+ return registry.expect_item_str(callback, allow_empty, warn); \
} \
constexpr NodeTools::NodeCallback auto expect_##singular##_identifier( \
NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback, bool warn = false \
@@ -551,14 +561,16 @@ private:
return registry.expect_item_identifier(callback, warn); \
} \
constexpr NodeTools::NodeCallback auto expect_##singular##_string( \
- NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback, bool warn = false \
+ NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback, bool allow_empty = false, \
+ bool warn = false \
) const_kw { \
- return registry.expect_item_string(callback, warn); \
+ return registry.expect_item_string(callback, allow_empty, warn); \
} \
constexpr NodeTools::NodeCallback auto expect_##singular##_identifier_or_string( \
- NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback, bool warn = false \
+ NodeTools::Callback<decltype(registry)::external_value_type const_kw&> auto callback,bool allow_empty = false, \
+ bool warn = false \
) const_kw { \
- return registry.expect_item_identifier_or_string(callback, warn); \
+ return registry.expect_item_identifier_or_string(callback, allow_empty, warn); \
} \
constexpr NodeTools::NodeCallback auto expect_##singular##_assign_and_default( \
NodeTools::KeyValueCallback auto default_callback, \
diff --git a/src/openvic-simulation/types/Vector.hpp b/src/openvic-simulation/types/Vector.hpp
index 5514cc3..6897835 100644
--- a/src/openvic-simulation/types/Vector.hpp
+++ b/src/openvic-simulation/types/Vector.hpp
@@ -6,6 +6,9 @@ namespace OpenVic {
template<typename T>
struct vec2_t {
+ /* PROPERTY generated getter functions will return 2D vectors by value, rather than const reference. */
+ using ov_return_by_value = void;
+
using type = T;
T x, y;
diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
index 8d3a74b..6a47194 100644
--- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
+++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
@@ -1,22 +1,21 @@
#pragma once
-#include <cerrno>
-#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <sstream>
#include <string_view>
-#include "openvic-simulation/utility/Getters.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPointLUT.hpp"
#include "openvic-simulation/utility/Logger.hpp"
#include "openvic-simulation/utility/NumberUtils.hpp"
#include "openvic-simulation/utility/StringUtils.hpp"
-#include "FixedPointLUT.hpp"
-
namespace OpenVic {
- struct fixed_point_t : ReturnByValueProperty {
+ struct fixed_point_t {
+ /* PROPERTY generated getter functions will return fixed points by value, rather than const reference. */
+ using ov_return_by_value = void;
+
static constexpr size_t SIZE = 8;
static constexpr int32_t PRECISION = FPLUT::SIN_LUT_PRECISION;
@@ -27,7 +26,7 @@ namespace OpenVic {
constexpr fixed_point_t(int32_t new_value) : value { static_cast<int64_t>(new_value) << PRECISION } {}
// Trivial destructor
- ~fixed_point_t() = default;
+ constexpr ~fixed_point_t() = default;
static constexpr fixed_point_t max() {
return std::numeric_limits<int64_t>::max();
diff --git a/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp b/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp
index 45cb639..a5d585f 100644
--- a/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp
+++ b/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp
@@ -1,15 +1,10 @@
#pragma once
-#include <array>
-#include <cmath>
-#include <cstddef>
#include <cstdint>
-#include <numbers>
-#include <utility>
namespace OpenVic::FPLUT {
-#include "FixedPointLUT_sin.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp"
constexpr int32_t SHIFT = SIN_LUT_PRECISION - SIN_LUT_COUNT_LOG2;
diff --git a/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp b/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp
index c0b5f42..6cdb926 100644
--- a/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp
+++ b/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include "FixedPoint.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
namespace OpenVic::FPMath {
constexpr fixed_point_t sin(fixed_point_t number) {
diff --git a/src/openvic-simulation/utility/Getters.hpp b/src/openvic-simulation/utility/Getters.hpp
index 33aa5a2..fa76e74 100644
--- a/src/openvic-simulation/utility/Getters.hpp
+++ b/src/openvic-simulation/utility/Getters.hpp
@@ -51,13 +51,15 @@ public: \
ACCESS:
namespace OpenVic {
- /* Any struct extending ReturnByValueProperty will be returned by value by PROPERTY-generated getter functions,
+ /* Any struct tagged with ov_return_by_value will be returned by value by PROPERTY-generated getter functions,
* instead of by const reference as structs are by default. Use this for small structs which don't contain any
- * dynamically allocated memory, e.g. Date and fixed_point_t. */
- struct ReturnByValueProperty {
- constexpr bool operator==(ReturnByValueProperty const&) const = default;
- constexpr std::strong_ordering operator<=>(ReturnByValueProperty const&) const = default;
- };
+ * dynamically allocated memory, e.g. dates and colours. The tag must be public, as in the example below:
+ *
+ * public:
+ * using ov_return_by_value = void;
+ */
+ template<typename T>
+ concept ReturnByValue = requires { typename T::ov_return_by_value; };
/*
* Template function used to choose the return type and provide the implementation
@@ -72,7 +74,7 @@ namespace OpenVic {
/* Return std::string_view looking at std::string */
return std::string_view { property };
} else if constexpr (
- std::integral<T> || std::floating_point<T> || std::is_enum_v<T> || std::derived_from<T, ReturnByValueProperty>
+ std::integral<T> || std::floating_point<T> || std::is_enum_v<T> || ReturnByValue<T>
) {
/* Return value */
return T { property };
diff --git a/src/openvic-simulation/utility/Logger.hpp b/src/openvic-simulation/utility/Logger.hpp
index 53decb3..7a2c3d0 100644
--- a/src/openvic-simulation/utility/Logger.hpp
+++ b/src/openvic-simulation/utility/Logger.hpp
@@ -75,16 +75,16 @@ namespace OpenVic {
size_t message_count;
};
- template<typename... Ts>
+ template<typename... Args>
struct log {
- log(log_channel_t& log_channel, Ts&&... ts, source_location const& location) {
+ log(log_channel_t& log_channel, Args&&... args, source_location const& location) {
std::stringstream stream;
stream << StringUtils::get_filename(location.file_name()) << "("
/* Function name removed to reduce clutter. It is already included
* in Godot's print functions, so this was repeating it. */
//<< location.line() << ") `" << location.function_name() << "`: ";
<< location.line() << "): ";
- ((stream << std::forward<Ts>(ts)), ...);
+ ((stream << std::forward<Args>(args)), ...);
stream << std::endl;
log_channel.queue.push(stream.str());
if (log_channel.func) {
@@ -109,19 +109,28 @@ public: \
static inline size_t get_##name##_count() { \
return name##_channel.message_count; \
} \
- template<typename... Ts> \
+ template<typename... Args> \
struct name { \
- name(Ts&&... ts, source_location const& location = source_location::current()) { \
- log<Ts...> { name##_channel, std::forward<Ts>(ts)..., location }; \
+ name(Args&&... args, source_location const& location = source_location::current()) { \
+ log<Args...> { name##_channel, std::forward<Args>(args)..., location }; \
} \
}; \
- template<typename... Ts> \
- name(Ts&&...) -> name<Ts...>;
+ template<typename... Args> \
+ name(Args&&...) -> name<Args...>;
LOG_FUNC(info)
LOG_FUNC(warning)
LOG_FUNC(error)
#undef LOG_FUNC
+
+ template<typename... Args>
+ static inline constexpr void warn_or_error(bool warn, Args&&... args) {
+ if (warn) {
+ warning(std::forward<Args>(args)...);
+ } else {
+ error(std::forward<Args>(args)...);
+ }
+ }
};
}