Working on UI improvement
This commit is contained in:
1 parent
0da1ae124c
commit
80af0e61ae
43 files changed
+889
-64
No files matched your search
+68
-6
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user