#pragma once #include #include #include #include #include #include #include enum class Alignment { START, END, CENTER, LEFT = START, TOP = START, RIGHT = END, BOTTOM = END }; std::ostream& operator<<(std::ostream& os, Alignment align); struct PositionInfo { PositionInfo(); int x; int y; Alignment align_h; Alignment align_v; }; class Widget { public: Widget(SDL_Renderer* renderer); virtual ~Widget(); virtual void set_width(int width, bool preserve_aspect_ratio = true); virtual void set_height(int height, bool preserve_aspect_ratio = true); virtual void set_position(int x, int y); virtual void set_alignment(Alignment align_h, Alignment align_v); int get_width(); int get_height(); const PositionInfo& get_position(); virtual void draw() = 0; protected: void recalculate_pos(); SDL_Renderer* renderer; SDL_Rect rect; PositionInfo pos; }; class TextureWidget : public Widget { public: TextureWidget(SDL_Renderer* renderer, std::optional texture); ~TextureWidget(); virtual void draw() override; void update_texture(SDL_Texture* new_texture); private: void update_dimensions_from_texture(SDL_Texture* texture); std::optional texture; }; class ImageWidget : public TextureWidget { public: ImageWidget(SDL_Renderer* renderer, const std::string& path); }; class TextWidget : public TextureWidget { public: TextWidget(SDL_Renderer* renderer, TTF_Font* font, const std::string& initial_text = ""); ~TextWidget(); void update_text(const std::string& new_text); void set_wrap_width(int width); protected: TTF_Font* font; std::string text; int wrap_width = -1; // -1 means no wrapping (default behavior) SDL_Texture* generate_text(const std::string& text); }; class ListWidget : public Widget { public: ListWidget(SDL_Renderer* renderer, int element_height, Alignment element_alignment); virtual ~ListWidget(); void add_element(Widget* element); virtual void draw() override; void select_next(); void select_prev(); void select(size_t n); size_t get_selection(); protected: int element_height; Alignment element_alignment; size_t selection; std::vector elements; void place_element(Widget* element, int index); };