#pragma once #include "color.hpp" #include "dinkyecs.hpp" #include "lel.hpp" #include #include #include #include "textures.hpp" #include #include "events.hpp" #include "constants.hpp" #include "components.hpp" #include namespace guecs { using std::shared_ptr, std::make_shared; struct Label { std::string label; unsigned int size = GUECS_FONT_SIZE; shared_ptr font = nullptr; shared_ptr text = nullptr; void init(lel::Cell &cell, shared_ptr font_ptr) { if(font == nullptr) font = font_ptr; if(text == nullptr) text = make_shared(*font, label, size); auto bounds = text->getLocalBounds(); auto text_cell = lel::center(bounds.size.x, bounds.size.y, cell); // this stupid / 2 is because SFML renders from baseline rather than from the claimed bounding box text->setPosition({float(text_cell.x), float(text_cell.y) - text_cell.h / 2}); } }; struct Textual { std::string content; unsigned int size = GUECS_FONT_SIZE; shared_ptr font = nullptr; shared_ptr text = nullptr; void init(lel::Cell &cell, shared_ptr font_ptr) { if(font == nullptr) font = font_ptr; if(text == nullptr) text = make_shared(*font, content, size); text->setPosition({float(cell.x + GUECS_PADDING * 2), float(cell.y + GUECS_PADDING * 2)}); text->setCharacterSize(size); } void update(std::string& new_content) { content = new_content; text->setString(content); } }; struct Clickable { /* This is actually called by UI::mouse and passed the entity ID of the * button pressed so you can interact with it in the event handler. */ std::function action; }; struct Sprite { std::string name; std::shared_ptr sprite = nullptr; std::shared_ptr texture = nullptr; void init(lel::Cell &cell) { auto sprite_texture = textures::get(name); texture = sprite_texture.texture; sprite = make_shared(*texture); sprite->setPosition({ float(cell.x + GUECS_PADDING), float(cell.y + GUECS_PADDING)}); auto size = texture->getSize(); sprite->setScale({ float(cell.w - GUECS_PADDING * 2) / size.x, float(cell.h - GUECS_PADDING * 2) / size.y}); } }; struct Rectangle { shared_ptr shape = nullptr; void init(lel::Cell& cell) { sf::Vector2f size{float(cell.w) - GUECS_PADDING * 2, float(cell.h) - GUECS_PADDING * 2}; if(shape == nullptr) shape = make_shared(size); shape->setPosition({float(cell.x + GUECS_PADDING), float(cell.y + GUECS_PADDING)}); shape->setFillColor(GUECS_FILL_COLOR); shape->setOutlineColor(GUECS_BORDER_COLOR); shape->setOutlineThickness(GUECS_BORDER_PX); } }; struct Meter { float percent = 1.0f; Rectangle bar; void init(lel::Cell& cell) { bar.init(cell); } }; struct ActionData { std::any data; }; struct CellName { std::string name; }; struct Background { float x = 0.0f; float y = 0.0f; float w = 0.0f; float h = 0.0f; shared_ptr shape = nullptr; Background(lel::Parser& parser) : x(parser.grid_x), y(parser.grid_y), w(parser.grid_w), h(parser.grid_h) {} Background() {} void init() { sf::Vector2f size{float(w), float(h)}; if(shape == nullptr) shape = make_shared(size); shape->setPosition({float(x), float(y)}); shape->setFillColor(GUECS_BG_COLOR); } }; class UI { public: DinkyECS::World $world; std::unordered_map $name_ents; shared_ptr $font = nullptr; lel::Parser $parser; std::string $grid = ""; UI(); void position(int x, int y, int width, int height); void layout(std::string grid); DinkyECS::Entity entity(std::string name); inline lel::CellMap& cells() { return $parser.cells; } inline DinkyECS::World& world() { return $world; } void init(); void render(sf::RenderWindow& window); bool mouse(float x, float y); template void set(DinkyECS::Entity ent, Comp val) { $world.set(ent, val); } template void set_init(DinkyECS::Entity ent, Comp val) { dbc::check(has(ent),"WRONG! slot is missing its cell?!"); auto& cell = get(ent); val.init(cell); $world.set(ent, val); } lel::Cell& cell_for(DinkyECS::Entity entity) { return $world.get(entity); } template Comp& get(DinkyECS::Entity entity) { return $world.get(entity); } template std::optional get_if(DinkyECS::Entity entity) { return $world.get_if(entity); } template bool has(DinkyECS::Entity entity) { return $world.has(entity); } template void remove(DinkyECS::Entity ent) { $world.remove(ent); } template void close(string region) { auto ent = entity(region); remove(ent); } void show_sprite(string region, string sprite_name); void show_text(string region, string content); void update_text(string region, string content); void update_label(string region, string content); void show_label(string region, string content); }; Clickable make_action(DinkyECS::World& target, Events::GUI event); }