Skip to content

Commit

Permalink
Merge pull request #181 from OpenVicProject/ui-state-style
Browse files Browse the repository at this point in the history
UI polish
  • Loading branch information
Hop311 authored Jan 1, 2024
2 parents 8fc6204 + c0cc6e2 commit cf34ce1
Show file tree
Hide file tree
Showing 20 changed files with 439 additions and 85 deletions.
2 changes: 1 addition & 1 deletion extension/deps/openvic-simulation
106 changes: 106 additions & 0 deletions extension/src/openvic-extension/classes/GFXButtonStateTexture.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "GFXButtonStateTexture.hpp"

#include "openvic-extension/utility/ClassBindings.hpp"

using namespace OpenVic;
using namespace godot;

void GFXButtonStateTexture::_bind_methods() {
OV_BIND_METHOD(GFXButtonStateTexture::set_button_state, { "new_button_state" });
OV_BIND_METHOD(GFXButtonStateTexture::get_button_state);

OV_BIND_SMETHOD(get_generate_state_image_func_name);

OV_BIND_SMETHOD(button_state_to_theme_name, { "button_state" });
OV_BIND_METHOD(GFXButtonStateTexture::get_button_state_theme);

OV_BIND_METHOD(GFXButtonStateTexture::generate_state_image, { "source_image" });

BIND_ENUM_CONSTANT(HOVER);
BIND_ENUM_CONSTANT(PRESSED);
BIND_ENUM_CONSTANT(DISABLED);
}

GFXButtonStateTexture::GFXButtonStateTexture() : button_state { HOVER } {}

Ref<GFXButtonStateTexture> GFXButtonStateTexture::make_gfx_button_state_texture(
ButtonState button_state, Ref<Image> const& source_image
) {
Ref<GFXButtonStateTexture> button_state_texture;
button_state_texture.instantiate();
ERR_FAIL_NULL_V(button_state_texture, nullptr);
button_state_texture->set_button_state(button_state);
if (source_image.is_valid()) {
ERR_FAIL_COND_V(button_state_texture->generate_state_image(source_image) != OK, nullptr);
}
return button_state_texture;
}

void GFXButtonStateTexture::set_button_state(ButtonState new_button_state) {
ERR_FAIL_COND(new_button_state != HOVER && new_button_state != PRESSED && new_button_state != DISABLED);
button_state = new_button_state;
}

Error GFXButtonStateTexture::generate_state_image(Ref<Image> const& source_image) {
ERR_FAIL_COND_V(source_image.is_null() || source_image->is_empty(), FAILED);
/* Whether we've already set the ImageTexture to an image of the right dimensions and format,
* and so can update it without creating and setting a new image, or not. */
const bool can_update = state_image.is_valid() && state_image->get_size() == source_image->get_size()
&& state_image->get_format() == source_image->get_format();
if (!can_update) {
state_image = Image::create(source_image->get_width(), source_image->get_height(), false, source_image->get_format());
ERR_FAIL_NULL_V(state_image, FAILED);
}

static constexpr auto hover_colour = [](Color const& colour) -> Color {
return { std::min(colour.r + 0.1f, 1.0f), std::min(colour.g + 0.1f, 1.0f), std::min(colour.b + 0.1f, 1.0f), colour.a };
};
static constexpr auto pressed_colour = [](Color const& colour) -> Color {
return { std::max(colour.r - 0.1f, 0.0f), std::max(colour.g - 0.1f, 0.0f), std::max(colour.b - 0.1f, 0.0f), colour.a };
};
static constexpr auto disabled_colour = [](Color const& colour) -> Color {
const float luma = colour.get_luminance();
return { luma, luma, luma, colour.a };
};

const auto colour_func = button_state == HOVER ? hover_colour : button_state == PRESSED ? pressed_colour : disabled_colour;

for (Vector2i point { 0, 0 }; point.y < state_image->get_height(); ++point.y) {
for (point.x = 0; point.x < state_image->get_width(); ++point.x) {
state_image->set_pixelv(point, colour_func(source_image->get_pixelv(point)));
}
}

if (can_update) {
update(state_image);
} else {
set_image(state_image);
}
return OK;
}

StringName const& GFXButtonStateTexture::get_generate_state_image_func_name() {
static const StringName generate_state_image_func_name = "generate_state_image";
return generate_state_image_func_name;
}

StringName const& GFXButtonStateTexture::button_state_to_theme_name(ButtonState button_state) {
static const StringName theme_name_hover = "hover";
static const StringName theme_name_pressed = "pressed";
static const StringName theme_name_disabled = "disabled";
static const StringName theme_name_error = "";
switch (button_state) {
case HOVER:
return theme_name_hover;
case PRESSED:
return theme_name_pressed;
case DISABLED:
return theme_name_disabled;
default:
return theme_name_error;
}
}

StringName const& GFXButtonStateTexture::get_button_state_theme() const {
return button_state_to_theme_name(button_state);
}
46 changes: 46 additions & 0 deletions extension/src/openvic-extension/classes/GFXButtonStateTexture.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include <godot_cpp/classes/image_texture.hpp>

#include <openvic-simulation/utility/Getters.hpp>

namespace OpenVic {
class GFXButtonStateTexture : public godot::ImageTexture {
GDCLASS(GFXButtonStateTexture, godot::ImageTexture)

public:
enum ButtonState {
HOVER,
PRESSED,
DISABLED
};

private:
ButtonState PROPERTY(button_state);
godot::Ref<godot::Image> state_image;

protected:
static void _bind_methods();

public:
GFXButtonStateTexture();

/* Create a GFXButtonStateTexture using the specified godot::Image. Returns nullptr if generate_state_image fails. */
static godot::Ref<GFXButtonStateTexture> make_gfx_button_state_texture(
ButtonState button_state, godot::Ref<godot::Image> const& source_image = nullptr
);

/* Set the ButtonState to be generated by this class (calling this does not trigger state image generation). */
void set_button_state(ButtonState new_button_state);

/* Generate a modified version of source_image and update the underlying godot::ImageTexture to use it. */
godot::Error generate_state_image(godot::Ref<godot::Image> const& source_image);

static godot::StringName const& get_generate_state_image_func_name();

static godot::StringName const& button_state_to_theme_name(ButtonState button_state);
godot::StringName const& get_button_state_theme() const;
};
}

VARIANT_ENUM_CAST(OpenVic::GFXButtonStateTexture::ButtonState);
33 changes: 31 additions & 2 deletions extension/src/openvic-extension/classes/GFXIconTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ using OpenVic::Utilities::godot_to_std_string;
using OpenVic::Utilities::std_view_to_godot_string;
using OpenVic::Utilities::std_view_to_godot_string_name;

StringName const& GFXIconTexture::_signal_image_updated() {
static const StringName signal_image_updated = "image_updated";
return signal_image_updated;
}

void GFXIconTexture::_bind_methods() {
OV_BIND_METHOD(GFXIconTexture::clear);

Expand All @@ -26,16 +31,32 @@ void GFXIconTexture::_bind_methods() {
OV_BIND_METHOD(GFXIconTexture::get_icon_count);

ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_index"), "set_icon_index", "get_icon_index");

ADD_SIGNAL(
MethodInfo(_signal_image_updated(), PropertyInfo(Variant::OBJECT, "source_image", PROPERTY_HINT_RESOURCE_TYPE, "Image"))
);
}

GFXIconTexture::GFXIconTexture()
: gfx_texture_sprite { nullptr }, icon_index { GFX::NO_FRAMES }, icon_count { GFX::NO_FRAMES } {}

Ref<GFXIconTexture> GFXIconTexture::make_gfx_icon_texture(GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon) {
Ref<GFXIconTexture> GFXIconTexture::make_gfx_icon_texture(
GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon,
std::vector<Ref<GFXButtonStateTexture>> const& button_state_textures
) {
Ref<GFXIconTexture> icon_texture;
icon_texture.instantiate();
ERR_FAIL_NULL_V(icon_texture, nullptr);
icon_texture->set_gfx_texture_sprite(gfx_texture_sprite, icon);

for (Ref<GFXButtonStateTexture> const& button_state_texture : button_state_textures) {
icon_texture->connect(
_signal_image_updated(),
Callable { *button_state_texture, GFXButtonStateTexture::get_generate_state_image_func_name() },
CONNECT_PERSIST
);
}

ERR_FAIL_COND_V(icon_texture->set_gfx_texture_sprite(gfx_texture_sprite, icon) != OK, nullptr);
return icon_texture;
}

Expand All @@ -57,9 +78,15 @@ Error GFXIconTexture::set_gfx_texture_sprite(GFX::TextureSprite const* new_gfx_t
ERR_FAIL_NULL_V(asset_manager, FAILED);

const StringName texture_file = std_view_to_godot_string_name(new_gfx_texture_sprite->get_texture_file());

/* Needed for GFXButtonStateTexture, AssetManager::get_texture will re-use this image from its internal cache. */
const Ref<Image> image = asset_manager->get_image(texture_file);
ERR_FAIL_NULL_V_MSG(image, FAILED, vformat("Failed to load image: %s", texture_file));

const Ref<ImageTexture> texture = asset_manager->get_texture(texture_file);
ERR_FAIL_NULL_V_MSG(texture, FAILED, vformat("Failed to load texture: %s", texture_file));

sprite_image = image;
gfx_texture_sprite = new_gfx_texture_sprite;
set_atlas(texture);
icon_index = GFX::NO_FRAMES;
Expand Down Expand Up @@ -98,6 +125,7 @@ Error GFXIconTexture::set_icon_index(int32_t new_icon_index) {
}
icon_index = GFX::NO_FRAMES;
set_region({ {}, size });
emit_signal(_signal_image_updated(), sprite_image);
return OK;
}
if (GFX::NO_FRAMES < new_icon_index && new_icon_index <= icon_count) {
Expand All @@ -111,5 +139,6 @@ Error GFXIconTexture::set_icon_index(int32_t new_icon_index) {
}
}
set_region({ (icon_index - 1) * size.x / icon_count, 0, size.x / icon_count, size.y });
emit_signal(_signal_image_updated(), sprite_image->get_region(get_region()));
return OK;
}
12 changes: 11 additions & 1 deletion extension/src/openvic-extension/classes/GFXIconTexture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <openvic-simulation/interface/GFX.hpp>

#include "openvic-extension/classes/GFXButtonStateTexture.hpp"

namespace OpenVic {
class GFXIconTexture : public godot::AtlasTexture {
GDCLASS(GFXIconTexture, godot::AtlasTexture)
Expand All @@ -16,14 +18,22 @@ namespace OpenVic {
GFX::frame_t PROPERTY(icon_index);
GFX::frame_t PROPERTY(icon_count);

godot::Ref<godot::Image> sprite_image;

static godot::StringName const& _signal_image_updated();

protected:
static void _bind_methods();

public:
GFXIconTexture();

/* Create a GFXIconTexture using the specified GFX::TextureSprite and icon index. Returns nullptr if
* set_gfx_texture_sprite fails. Connects the provided GFXButtonStateTextures (if any) to the
* GFXIconTexture's image_updated signal. */
static godot::Ref<GFXIconTexture> make_gfx_icon_texture(
GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon = GFX::NO_FRAMES
GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon = GFX::NO_FRAMES,
std::vector<godot::Ref<GFXButtonStateTexture>> const& button_state_textures = {}
);

/* Discard the GFX::TextureSprite, atlas texture and icon index. */
Expand Down
31 changes: 27 additions & 4 deletions extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ using OpenVic::Utilities::godot_to_std_string;
using OpenVic::Utilities::std_view_to_godot_string;
using OpenVic::Utilities::std_view_to_godot_string_name;

StringName const& GFXMaskedFlagTexture::_signal_image_updated() {
static const StringName signal_image_updated = "image_updated";
return signal_image_updated;
}

Error GFXMaskedFlagTexture::_generate_combined_image() {
ERR_FAIL_NULL_V(overlay_image, FAILED);
bool can_update = true;
if (combined_image.is_null() || combined_image->get_size() != overlay_image->get_size()) {
/* Whether we've already set the ImageTexture to an image of the right dimensions and format,
* and so can update it without creating and setting a new image, or not. */
const bool can_update = combined_image.is_valid() && combined_image->get_size() == overlay_image->get_size()
&& combined_image->get_format() == overlay_image->get_format();
if (!can_update) {
combined_image = Image::create(
overlay_image->get_width(), overlay_image->get_height(), false, overlay_image->get_format()
);
ERR_FAIL_NULL_V(combined_image, FAILED);
can_update = false;
}

if (mask_image.is_valid() && flag_image.is_valid()) {
Expand Down Expand Up @@ -55,6 +62,7 @@ Error GFXMaskedFlagTexture::_generate_combined_image() {
} else {
set_image(combined_image);
}
emit_signal(_signal_image_updated(), combined_image);
return OK;
}

Expand All @@ -68,14 +76,29 @@ void GFXMaskedFlagTexture::_bind_methods() {
OV_BIND_METHOD(GFXMaskedFlagTexture::set_flag_country_name, { "new_flag_country_name" });
OV_BIND_METHOD(GFXMaskedFlagTexture::get_flag_country_name);
OV_BIND_METHOD(GFXMaskedFlagTexture::get_flag_type);

ADD_SIGNAL(
MethodInfo(_signal_image_updated(), PropertyInfo(Variant::OBJECT, "source_image", PROPERTY_HINT_RESOURCE_TYPE, "Image"))
);
}

GFXMaskedFlagTexture::GFXMaskedFlagTexture() : gfx_masked_flag { nullptr }, flag_country { nullptr } {}

Ref<GFXMaskedFlagTexture> GFXMaskedFlagTexture::make_gfx_masked_flag_texture(GFX::MaskedFlag const* gfx_masked_flag) {
Ref<GFXMaskedFlagTexture> GFXMaskedFlagTexture::make_gfx_masked_flag_texture(
GFX::MaskedFlag const* gfx_masked_flag, std::vector<Ref<GFXButtonStateTexture>> const& button_state_textures
) {
Ref<GFXMaskedFlagTexture> masked_flag_texture;
masked_flag_texture.instantiate();
ERR_FAIL_NULL_V(masked_flag_texture, nullptr);

for (Ref<GFXButtonStateTexture> const& button_state_texture : button_state_textures) {
masked_flag_texture->connect(
_signal_image_updated(),
Callable { *button_state_texture, GFXButtonStateTexture::get_generate_state_image_func_name() },
CONNECT_PERSIST
);
}

ERR_FAIL_COND_V(masked_flag_texture->set_gfx_masked_flag(gfx_masked_flag) != OK, nullptr);
return masked_flag_texture;
}
Expand Down
13 changes: 10 additions & 3 deletions extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <openvic-simulation/country/Country.hpp>
#include <openvic-simulation/interface/GFX.hpp>

#include "openvic-extension/classes/GFXButtonStateTexture.hpp"

namespace OpenVic {
class GFXMaskedFlagTexture : public godot::ImageTexture {
GDCLASS(GFXMaskedFlagTexture, godot::ImageTexture)
Expand All @@ -15,6 +17,8 @@ namespace OpenVic {

godot::Ref<godot::Image> overlay_image, mask_image, flag_image, combined_image;

static godot::StringName const& _signal_image_updated();

godot::Error _generate_combined_image();

protected:
Expand All @@ -23,9 +27,12 @@ namespace OpenVic {
public:
GFXMaskedFlagTexture();

/* Create a GFXMaskedFlagTexture using the specific GFX::MaskedFlag.
* Returns nullptr if setting gfx_masked_flag fails. */
static godot::Ref<GFXMaskedFlagTexture> make_gfx_masked_flag_texture(GFX::MaskedFlag const* gfx_masked_flag);
/* Create a GFXMaskedFlagTexture using the specified GFX::MaskedFlag. Returns nullptr if gfx_masked_flag fails.
* Connects the provided GFXButtonStateTextures (if any) to the GFXMaskedFlagTexture's image_updated signal. */
static godot::Ref<GFXMaskedFlagTexture> make_gfx_masked_flag_texture(
GFX::MaskedFlag const* gfx_masked_flag,
std::vector<godot::Ref<GFXButtonStateTexture>> const& button_state_textures = {}
);

/* Reset gfx_masked_flag, flag_country and flag_type to nullptr/an empty string, and unreference all images.
* This does not affect the godot::ImageTexture, which cannot be reset to a null or empty image. */
Expand Down
Loading

0 comments on commit cf34ce1

Please sign in to comment.