Working on UI improvement

This commit is contained in:
Vladislav Khorev committed 2026-05-27 17:30:41 +03:00
1 parent 0da1ae124c
commit 80af0e61ae
43 files changed
+889 -64

No files matched your search

+68 -6
View File
@@ -373,9 +373,17 @@ namespace ZL {
void UiStaticImage::draw(Renderer& renderer) const {
if (!texture) return;
const float alpha = (fadeInEnabled && fadeInDurationMs > 0.0f)
? std::clamp(fadeInElapsedMs / fadeInDurationMs, 0.0f, 1.0f)
: 1.0f;
renderer.RenderUniform1i(textureUniformName, 0);
renderer.RenderUniform1f("uAlpha", alpha);
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
renderer.DrawVertexRenderStruct(mesh);
if (alpha < 1.0f) {
renderer.RenderUniform1f("uAlpha", 1.0f); // restore for subsequent draws
}
}
void UiTextField::draw(Renderer& renderer) const {
@@ -504,6 +512,8 @@ namespace ZL {
btn->texDisabled = loadTex("disabled");
btn->border = j.value("border", 0.0f);
if (j.contains("clickZoneWidth")) btn->clickZoneWidth = j["clickZoneWidth"].get<float>();
if (j.contains("clickZoneHeight")) btn->clickZoneHeight = j["clickZoneHeight"].get<float>();
node->button = btn;
}
@@ -616,6 +626,8 @@ namespace ZL {
if (j.contains("color") && j["color"].is_array() && j["color"].size() == 4) {
for (int i = 0; i < 4; ++i) tb->color[i] = j["color"][i].get<float>();
}
if (j.contains("clickZoneWidth")) tb->clickZoneWidth = j["clickZoneWidth"].get<float>();
if (j.contains("clickZoneHeight")) tb->clickZoneHeight = j["clickZoneHeight"].get<float>();
tb->textRenderer = std::make_unique<TextRenderer>();
if (!tb->textRenderer->init(renderer, tb->fontPath, tb->fontSize, zipFile)) {
@@ -679,6 +691,23 @@ namespace ZL {
}
node->staticImage = img;
// Optional fade-in on display
if (j.contains("fadeIn") && j["fadeIn"].is_object()) {
const auto& fi = j["fadeIn"];
img->fadeInEnabled = true;
img->fadeInDurationMs = fi.value("durationMs", 1000.0f);
img->fadeInElapsedMs = 0.0f;
}
// Optional pulse-scale animation
if (j.contains("pulse") && j["pulse"].is_object()) {
const auto& p = j["pulse"];
node->pulseEnabled = true;
node->pulseMinScale = p.value("minScale", 0.9f);
node->pulseMaxScale = p.value("maxScale", 1.1f);
node->pulsePeriodMs = p.value("periodMs", 1000.0f);
}
}
if (typeStr == "TextView") {
@@ -777,6 +806,7 @@ namespace ZL {
textViews.clear();
textFields.clear();
staticImages.clear();
pulsingNodes.clear();
collectButtonsAndSliders(root);
nodeActiveAnims.clear();
@@ -1020,6 +1050,12 @@ namespace ZL {
}
if (node->staticImage) {
staticImages.push_back(node->staticImage);
if (node->staticImage->fadeInEnabled) {
node->staticImage->fadeInElapsedMs = 0.0f; // restart fade every time UI is shown
}
}
if (node->pulseEnabled && node->staticImage) {
pulsingNodes.push_back(node);
}
for (auto& c : node->children) collectButtonsAndSliders(c);
}
@@ -1128,6 +1164,7 @@ namespace ZL {
prev.textViews = textViews;
prev.textFields = textFields;
prev.staticImages = staticImages;
prev.pulsingNodes = pulsingNodes;
prev.pressedButtons = pressedButtons;
prev.pressedTextButtons = pressedTextButtons;
prev.pressedSliders = pressedSliders;
@@ -1190,6 +1227,7 @@ namespace ZL {
textViews = s.textViews;
textFields = s.textFields;
staticImages = s.staticImages;
pulsingNodes = s.pulsingNodes;
pressedButtons = s.pressedButtons;
pressedTextButtons = s.pressedTextButtons;
pressedSliders = s.pressedSliders;
@@ -1233,6 +1271,7 @@ namespace ZL {
renderer.PushProjectionMatrix(Environment::projectionWidth, Environment::projectionHeight, -1, 1);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.RenderUniform1f("uAlpha", 1.0f); // ensure alpha is fully opaque unless a widget overrides it
std::function<void(const std::shared_ptr<UiNode>&)> drawNode =
[&](const std::shared_ptr<UiNode>& node) {
@@ -1301,6 +1340,29 @@ namespace ZL {
void UiManager::update(float deltaMs) {
if (!root) return;
// Fade-in animations (StaticImage elements with fadeInEnabled == true)
for (auto& img : staticImages) {
if (!img || !img->fadeInEnabled) continue;
if (img->fadeInElapsedMs < img->fadeInDurationMs) {
img->fadeInElapsedMs += deltaMs;
if (img->fadeInElapsedMs > img->fadeInDurationMs)
img->fadeInElapsedMs = img->fadeInDurationMs;
}
}
// Pulse-scale animations (StaticImage nodes with pulseEnabled == true)
for (auto& node : pulsingNodes) {
if (!node) continue;
node->pulseElapsedMs += deltaMs;
if (node->pulseElapsedMs >= node->pulsePeriodMs)
node->pulseElapsedMs = std::fmod(node->pulseElapsedMs, node->pulsePeriodMs);
const float phase = node->pulseElapsedMs / node->pulsePeriodMs;
const float t = (std::sin(phase * 2.0f * static_cast<float>(M_PI)) + 1.0f) * 0.5f;
const float s = node->pulseMinScale + (node->pulseMaxScale - node->pulseMinScale) * t;
node->scaleX = s;
node->scaleY = s;
}
std::vector<std::pair<std::shared_ptr<UiNode>, size_t>> animationsToRemove;
std::vector<std::function<void()>> pendingCallbacks;
@@ -1490,7 +1552,7 @@ namespace ZL {
for (auto& b : buttons) {
if (b->state != ButtonState::Disabled)
{
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
if (b->getClickZoneRect().containsConsideringBorder((float)x, (float)y, b->border)) {
if (b->state != ButtonState::Pressed) b->state = ButtonState::Hover;
}
else {
@@ -1501,7 +1563,7 @@ namespace ZL {
for (auto& tb : textButtons) {
if (tb->state != ButtonState::Disabled)
{
if (tb->rect.containsConsideringBorder((float)x, (float)y, tb->border)) {
if (tb->getClickZoneRect().containsConsideringBorder((float)x, (float)y, tb->border)) {
if (tb->state != ButtonState::Pressed) tb->state = ButtonState::Hover;
}
else {
@@ -1534,7 +1596,7 @@ namespace ZL {
for (auto& b : buttons) {
if (b->state != ButtonState::Disabled)
{
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
if (b->getClickZoneRect().containsConsideringBorder((float)x, (float)y, b->border)) {
b->state = ButtonState::Pressed;
pressedButtons[fingerId] = b;
if (b->onPress) b->onPress(b->name);
@@ -1546,7 +1608,7 @@ namespace ZL {
for (auto& tb : textButtons) {
if (tb->state != ButtonState::Disabled)
{
if (tb->rect.containsConsideringBorder((float)x, (float)y, tb->border)) {
if (tb->getClickZoneRect().containsConsideringBorder((float)x, (float)y, tb->border)) {
tb->state = ButtonState::Pressed;
pressedTextButtons[fingerId] = tb;
if (tb->onPress) tb->onPress(tb->name);
@@ -1593,7 +1655,7 @@ namespace ZL {
if (btnIt != pressedButtons.end()) {
auto b = btnIt->second;
if (b) {
bool contains = b->rect.contains((float)x, (float)y);
bool contains = b->getClickZoneRect().contains((float)x, (float)y);
if (b->state == ButtonState::Pressed) {
if (contains) {
clicked.push_back(b);
@@ -1609,7 +1671,7 @@ namespace ZL {
if (tbIt != pressedTextButtons.end()) {
auto tb = tbIt->second;
if (tb) {
bool contains = tb->rect.contains((float)x, (float)y);
bool contains = tb->getClickZoneRect().contains((float)x, (float)y);
if (tb->state == ButtonState::Pressed) {
if (contains) {
clickedText.push_back(tb);