From f8af17618e9f24dd6833ecaab64bf968cca2ec15 Mon Sep 17 00:00:00 2001 From: hop311 Date: Wed, 20 Mar 2024 00:11:22 +0000 Subject: Label padding, progressbar range and piechart slice order tweaks --- extension/deps/openvic-simulation | 2 +- .../classes/GFXPieChartTexture.cpp | 40 +++++++++++++++++----- .../classes/GFXPieChartTexture.hpp | 10 +++--- .../src/openvic-extension/utility/UITools.cpp | 14 ++++++-- 4 files changed, 50 insertions(+), 16 deletions(-) (limited to 'extension') diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 2c892c9..c11d262 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 2c892c99a6647be15ef23cabf6cc40f08769283d +Subproject commit c11d262a4d2c987c8cf8e0d4b24929cbe56bb289 diff --git a/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp b/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp index f4c7851..10a2cb5 100644 --- a/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp @@ -23,7 +23,7 @@ StringName const& GFXPieChartTexture::_slice_weight_key() { return slice_weight_key; } -static constexpr float PI = std::numbers::pi_v; +static constexpr float TWO_PI = 2.0f * std::numbers::pi_v; Error GFXPieChartTexture::_generate_pie_chart_image() { ERR_FAIL_NULL_V(gfx_pie_chart, FAILED); @@ -31,40 +31,57 @@ Error GFXPieChartTexture::_generate_pie_chart_image() { gfx_pie_chart->get_size() <= 0, FAILED, vformat("Invalid GFX::PieChart size for GFXPieChartTexture - %d", gfx_pie_chart->get_size()) ); + const int32_t pie_chart_size = 2 * gfx_pie_chart->get_size(); + /* Whether we've already set the ImageTexture to an image of the right dimensions, * and so can update it without creating and setting a new image, or not. */ const bool can_update = pie_chart_image.is_valid() && pie_chart_image->get_width() == pie_chart_size && pie_chart_image->get_height() == pie_chart_size; + if (!can_update) { pie_chart_image = Image::create(pie_chart_size, pie_chart_size, false, Image::FORMAT_RGBA8); ERR_FAIL_NULL_V(pie_chart_image, FAILED); } static const Color background_colour { 0.0f, 0.0f, 0.0f, 0.0f }; + if (!slices.empty()) { const float pie_chart_radius = gfx_pie_chart->get_size(); + const Vector2 centre_translation = Vector2 { 0.5f, 0.5f } - static_cast(pie_chart_image->get_size()) * 0.5f; + for (Vector2i point { 0, 0 }; point.y < pie_chart_image->get_height(); ++point.y) { + for (point.x = 0; point.x < pie_chart_image->get_width(); ++point.x) { + const Vector2 offset = centre_translation + point; + if (offset.length() <= pie_chart_radius) { - float theta = 0.5f * PI + atan2(offset.y, offset.x); + + /* Calculate the anti-clockwise angle between the point and the centre of the image. + * The y coordinate is negated as the image coordinate system's y increases downwards. */ + float theta = atan2(-offset.y, offset.x); if (theta < 0.0f) { - theta += 2.0f * PI; + theta += TWO_PI; } + /* Rescale angle so that total_weight is a full rotation. */ - theta *= total_weight / (2.0f * PI); + theta *= total_weight / TWO_PI; + + /* Default to the first colour in case theta never reaches 0 due to floating point inaccuracy. */ Color colour = slices.front().first; + /* Find the slice theta lies in. */ for (slice_t const& slice : slices) { - if (theta <= slice.second) { + theta -= slice.second; + + if (theta <= 0.0f) { colour = slice.first; break; - } else { - theta -= slice.second; } } + pie_chart_image->set_pixelv(point, colour); } else { pie_chart_image->set_pixelv(point, background_colour); @@ -72,7 +89,9 @@ Error GFXPieChartTexture::_generate_pie_chart_image() { } } } else { + pie_chart_image->fill(background_colour); + } if (can_update) { @@ -80,10 +99,11 @@ Error GFXPieChartTexture::_generate_pie_chart_image() { } else { set_image(pie_chart_image); } + return OK; } -Error GFXPieChartTexture::set_slices_array(TypedArray const& new_slices) { +Error GFXPieChartTexture::set_slices_array(godot_pie_chart_data_t const& new_slices) { slices.clear(); total_weight = 0.0f; for (int32_t i = 0; i < new_slices.size(); ++i) { @@ -92,7 +112,9 @@ Error GFXPieChartTexture::set_slices_array(TypedArray const& new_sli !slice_dict.has(_slice_colour_key()) || !slice_dict.has(_slice_weight_key()), vformat("Invalid slice keys at index %d", i) ); slice_t slice = std::make_pair(slice_dict[_slice_colour_key()], slice_dict[_slice_weight_key()]); - ERR_CONTINUE_MSG(slice.second <= 0.0f, vformat("Invalid slice values at index %d", i)); + ERR_CONTINUE_MSG( + slice.second <= 0.0f, vformat("Invalid slice values at index %d \"%s\"", i, slice_dict[_slice_identifier_key()]) + ); total_weight += slice.second; slices.emplace_back(std::move(slice)); } diff --git a/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp b/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp index f8279e4..abeca1e 100644 --- a/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp @@ -29,15 +29,17 @@ namespace OpenVic { public: GFXPieChartTexture(); + using godot_pie_chart_data_t = godot::TypedArray; + /* Set slices given an Array of Dictionaries, each with the following key-value entries: * - colour: Color * - weight: float */ - godot::Error set_slices_array(godot::TypedArray const& new_slices); + godot::Error set_slices_array(godot_pie_chart_data_t const& new_slices); /* Generate slice data from a distribution of HasIdentifierAndColour derived objects, sorted by their weight. * The resulting Array of Dictionaries can be used as an argument for set_slices_array. */ template T> - static godot::TypedArray distribution_to_slices_array(fixed_point_map_t const& dist) { + static godot_pie_chart_data_t distribution_to_slices_array(fixed_point_map_t const& dist) { using namespace godot; using entry_t = std::pair; std::vector sorted_dist; @@ -49,9 +51,9 @@ namespace OpenVic { sorted_dist.push_back(entry); } std::sort(sorted_dist.begin(), sorted_dist.end(), [](entry_t const& lhs, entry_t const& rhs) -> bool { - return lhs.second < rhs.second; + return lhs.first < rhs.first; }); - TypedArray array; + godot_pie_chart_data_t array; for (auto const& [key, val] : sorted_dist) { Dictionary sub_dict; sub_dict[_slice_identifier_key()] = Utilities::std_view_to_godot_string(key->get_identifier()); diff --git a/extension/src/openvic-extension/utility/UITools.cpp b/extension/src/openvic-extension/utility/UITools.cpp index c00b64d..23dcced 100644 --- a/extension/src/openvic-extension/utility/UITools.cpp +++ b/extension/src/openvic-extension/utility/UITools.cpp @@ -177,8 +177,13 @@ static bool generate_icon(generate_gui_args_t&& args) { godot_progress_bar, false, vformat("Failed to create TextureProgressBar for GUI icon %s", icon_name) ); + static constexpr double MIN_VALUE = 0.0, MAX_VALUE = 1.0; + static constexpr uint32_t STEPS = 100; + godot_progress_bar->set_nine_patch_stretch(true); - godot_progress_bar->set_max(1.0); + godot_progress_bar->set_step((MAX_VALUE - MIN_VALUE) / STEPS); + godot_progress_bar->set_min(MIN_VALUE); + godot_progress_bar->set_max(MAX_VALUE); GFX::ProgressBar const* progress_bar = icon.get_sprite()->cast_to(); @@ -435,7 +440,12 @@ static bool generate_text(generate_gui_args_t&& args) { ERR_FAIL_NULL_V_MSG(godot_label, false, vformat("Failed to create Label for GUI text %s", text_name)); godot_label->set_text(std_view_to_godot_string(text.get_text())); - godot_label->set_custom_minimum_size(Utilities::to_godot_fvec2(text.get_max_size())); + + static const Vector2 default_padding { 1.0f, 0.0f }; + const Vector2 border_size = Utilities::to_godot_fvec2(text.get_border_size()) + default_padding; + const Vector2 max_size = Utilities::to_godot_fvec2(text.get_max_size()); + godot_label->set_position(godot_label->get_position() + border_size); + godot_label->set_custom_minimum_size(max_size - 2 * border_size); using enum GUI::AlignedElement::format_t; static const ordered_map format_map { -- cgit v1.2.3-56-ga3b1