From a1d54b01b0d4accdc0d86e1a116e55cc4f35464b Mon Sep 17 00:00:00 2001 From: vottozi Date: Fri, 6 Feb 2026 15:11:27 +0600 Subject: [PATCH] Add TextView UI component --- src/Game.cpp | 13 ++++++++++++ src/UiManager.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++- src/UiManager.h | 25 ++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/Game.cpp b/src/Game.cpp index 40e5793..6ba12ce 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -275,6 +275,15 @@ namespace ZL loadGameplayUI = [this]() { uiManager.loadFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE); + auto velocityTv = uiManager.findTextView("velocityText"); + if (velocityTv) { + velocityTv->rect.x = 10.0f; + velocityTv->rect.y = static_cast(Environment::height) - velocityTv->rect.h - 10.0f; + } + else { + std::cerr << "Failed to find velocityText in UI" << std::endl; + } + uiManager.startAnimationOnNode("backgroundNode", "bgScroll"); static bool isExitButtonAnimating = false; uiManager.setAnimationCallback("settingsButton", "buttonsExit", [this]() { @@ -1206,6 +1215,10 @@ namespace ZL } } + // update velocity text + std::string velocityStr = "Velocity: " + std::to_string(static_cast(Environment::shipState.velocity)); + uiManager.setText("velocityText", velocityStr); + uiManager.update(static_cast(delta)); lastTickCount = newTickCount; } diff --git a/src/UiManager.cpp b/src/UiManager.cpp index 5187433..9cf0d94 100644 --- a/src/UiManager.cpp +++ b/src/UiManager.cpp @@ -1,5 +1,6 @@ #include "UiManager.h" #include "utils/Utils.h" +#include "render/TextRenderer.h" #include #include #include @@ -205,6 +206,7 @@ namespace ZL { layoutNode(root); buttons.clear(); sliders.clear(); + textViews.clear(); collectButtonsAndSliders(root); nodeActiveAnims.clear(); @@ -327,6 +329,29 @@ namespace ZL { } } + if (node->type == "TextView") { + auto tv = std::make_shared(); + tv->name = node->name; + tv->rect = node->rect; + + if (j.contains("text")) tv->text = j["text"].get(); + if (j.contains("fontPath")) tv->fontPath = j["fontPath"].get(); + if (j.contains("fontSize")) tv->fontSize = j["fontSize"].get(); + if (j.contains("color") && j["color"].is_array() && j["color"].size() == 4) { + for (int i = 0; i < 4; ++i) { + tv->color[i] = j["color"][i].get(); + } + } + if (j.contains("centered")) tv->centered = j["centered"].get(); + + tv->textRenderer = std::make_unique(); + if (!tv->textRenderer->init(renderer, tv->fontPath, tv->fontSize)) { + std::cerr << "Failed to init TextRenderer for TextView: " << tv->name << std::endl; + } + + node->textView = tv; + } + if (j.contains("children") && j["children"].is_array()) { for (const auto& ch : j["children"]) { node->children.push_back(parseNode(ch, renderer, zipFile)); @@ -376,7 +401,10 @@ namespace ZL { if (node->slider) { sliders.push_back(node->slider); } - for (auto& c : node->children) collectButtonsAndSliders(c); + if (node->textView) { + textViews.push_back(node->textView); + } + for (auto& c : node->children) collectButtonsAndSliders(c); // можно переименовать в collectControls } bool UiManager::setButtonCallback(const std::string& name, std::function cb) { @@ -532,6 +560,9 @@ namespace ZL { for (const auto& s : sliders) { s->draw(renderer); } + for (const auto& tv : textViews) { + tv->draw(renderer); + } renderer.PopMatrix(); renderer.PopProjectionMatrix(); @@ -862,4 +893,21 @@ namespace ZL { return true; } + std::shared_ptr UiManager::findTextView(const std::string& name) { + for (auto& tv : textViews) { + if (tv->name == name) return tv; + } + return nullptr; + } + + bool UiManager::setText(const std::string& name, const std::string& newText) { + auto tv = findTextView(name); + if (!tv) { + std::cerr << "TextView not found: " << name << std::endl; + return false; + } + tv->text = newText; + return true; + } + } // namespace ZL \ No newline at end of file diff --git a/src/UiManager.h b/src/UiManager.h index 5891566..5cfe6c8 100644 --- a/src/UiManager.h +++ b/src/UiManager.h @@ -2,6 +2,7 @@ #include "render/Renderer.h" #include "render/TextureManager.h" +#include "render/TextRenderer.h" #include "Environment.h" #include "external/nlohmann/json.hpp" #include @@ -71,6 +72,24 @@ namespace ZL { void draw(Renderer& renderer) const; }; + struct UiTextView { + std::string name; + UiRect rect; + std::string text = ""; + std::string fontPath = "resources/fonts/DroidSans.ttf"; + int fontSize = 32; + std::array color = { 1.f, 1.f, 1.f, 1.f }; // rgba + bool centered = true; + + std::unique_ptr textRenderer; + + void draw(Renderer& renderer) const { + if (textRenderer) { + textRenderer->drawText(text, rect.x + rect.w / 2, rect.y + rect.h / 2, 1.0f, centered, color); + } + } + }; + struct UiNode { std::string type; UiRect rect; @@ -78,6 +97,7 @@ namespace ZL { std::vector> children; std::shared_ptr button; std::shared_ptr slider; + std::shared_ptr textView; std::string orientation = "vertical"; float spacing = 0.0f; @@ -135,6 +155,9 @@ namespace ZL { bool setSliderCallback(const std::string& name, std::function cb); bool setSliderValue(const std::string& name, float value); // programmatic set (clamped 0..1) + std::shared_ptr findTextView(const std::string& name); + bool setText(const std::string& name, const std::string& newText); + bool pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = ""); bool popMenu(); void clearMenuStack(); @@ -176,6 +199,7 @@ namespace ZL { std::shared_ptr root; std::vector> buttons; std::vector> sliders; + std::vector> textViews; std::map, std::vector> nodeActiveAnims; std::map, std::function> animCallbacks; // key: (nodeName, animName) @@ -194,6 +218,7 @@ namespace ZL { }; std::vector menuStack; + }; } // namespace ZL \ No newline at end of file