#pragma once #include #include #include #include #include #include "openvic-extension/classes/GFXSpriteTexture.hpp" namespace OpenVic { class GUILabel : public godot::Control { GDCLASS(GUILabel, godot::Control) using colour_instructions_t = std::vector>; GUI::Text const* PROPERTY(gui_text); godot::String PROPERTY(text); godot::Dictionary PROPERTY(substitution_dict); godot::HorizontalAlignment PROPERTY(horizontal_alignment); godot::Size2 PROPERTY(max_size); // Actual max size is max_size - 2 * border_size godot::Size2 PROPERTY(border_size); // The padding between the Nodes bounding box and the text within it godot::Rect2 PROPERTY(adjusted_rect); // Offset + size after adjustment to fit content size bool PROPERTY_CUSTOM_PREFIX(auto_adjust_to_content_size, will); godot::Ref font; int32_t PROPERTY(font_size); godot::Color PROPERTY(default_colour); GFX::Font::colour_codes_t const* colour_codes; godot::Ref currency_texture; godot::Ref background; struct string_segment_t { godot::String text; godot::Color colour; real_t width; }; using currency_segment_t = std::monostate; using segment_t = std::variant; struct line_t { std::vector segments; real_t width {}; }; std::vector lines; bool line_update_queued; protected: static void _bind_methods(); void _notification(int what); public: GUILabel(); /* Reset gui_text to nullptr and reset current text. */ void clear(); /* Return the name of the GUI::Text, or an empty String if it's null. */ godot::String get_gui_text_name() const; /* Set the GUI::Text. */ godot::Error set_gui_text( GUI::Text const* new_gui_text, GFX::Font::colour_codes_t const* override_colour_codes = nullptr ); void set_text(godot::String const& new_text); void add_substitution(godot::String const& key, godot::String const& value); void set_substitution_dict(godot::Dictionary const& new_substitution_dict); void clear_substitutions(); void set_horizontal_alignment(godot::HorizontalAlignment new_horizontal_alignment); void set_max_size(godot::Size2 new_max_size); void set_border_size(godot::Size2 new_border_size); void set_auto_adjust_to_content_size(bool new_auto_adjust_to_content_size); godot::Ref get_font() const; void set_font(godot::Ref const& new_font); godot::Error set_font_file(godot::Ref const& new_font_file); godot::Error set_font_size(int32_t new_font_size); void set_default_colour(godot::Color const& new_default_colour); godot::Ref get_currency_texture() const; godot::Ref get_background() const; void set_background_texture(godot::Ref const& new_texture); void set_background_stylebox(godot::Ref const& new_stylebox_texture); private: void update_stylebox_border_size(); real_t get_string_width(godot::String const& string) const; real_t get_segment_width(segment_t const& segment) const; void _queue_line_update(); void _update_lines(); godot::String generate_substituted_text(godot::String const& base_text) const; std::pair generate_display_text_and_colour_instructions( godot::String const& substituted_text ) const; std::vector generate_lines_and_segments( godot::String const& display_text, colour_instructions_t const& colour_instructions ) const; void separate_lines( godot::String const& string, godot::Color const& colour, std::vector& lines ) const; void separate_currency_segments( godot::String const& string, godot::Color const& colour, line_t& line ) const; std::vector wrap_lines(std::vector& unwrapped_lines) const; void adjust_to_content_size(); }; }