Working on UI for web

This commit is contained in:
Vladislav Khorev 2026-02-28 23:01:26 +03:00
parent ffbecbbcde
commit 6b4b549b3c
5 changed files with 151 additions and 159 deletions

View File

@ -1,22 +1,14 @@
{ {
"root": { "root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"children": [
{
"type": "LinearLayout", "type": "LinearLayout",
"name": "settingsButtons",
"orientation": "vertical", "orientation": "vertical",
"vertical_align": "center", "vertical_align": "center",
"horizontal_align": "center", "horizontal_align": "center",
"spacing": 10, "spacing": 10,
"x": 0, "x": 0,
"y": 0, "y": 0,
"width": 1280, "width": "match_parent",
"height": 720, "height": "match_parent",
"children": [ "children": [
{ {
"type": "Button", "type": "Button",
@ -108,7 +100,4 @@
} }
] ]
} }
]
} }
}

View File

@ -342,6 +342,7 @@ namespace ZL
Environment::width = event.window.data1; Environment::width = event.window.data1;
Environment::height = event.window.data2; Environment::height = event.window.data2;
Environment::computeProjectionDimensions(); Environment::computeProjectionDimensions();
menuManager.uiManager.updateAllLayouts();
std::cout << "Window resized: " << Environment::width << "x" << Environment::height << std::endl; std::cout << "Window resized: " << Environment::width << "x" << Environment::height << std::endl;
space.clearTextRendererCache(); space.clearTextRendererCache();

View File

@ -362,7 +362,7 @@ namespace ZL
} }
crosshairCfgLoaded = loadCrosshairConfig("resources/config/crosshair_config.json"); crosshairCfgLoaded = loadCrosshairConfig("resources/config/crosshair_config.json");
std::cerr << "[Crosshair] loaded=" << crosshairCfgLoaded std::cout << "[Crosshair] loaded=" << crosshairCfgLoaded
<< " enabled=" << crosshairCfg.enabled << " enabled=" << crosshairCfg.enabled
<< " w=" << Environment::width << " h=" << Environment::height << " w=" << Environment::width << " h=" << Environment::height
<< " alpha=" << crosshairCfg.alpha << " alpha=" << crosshairCfg.alpha

View File

@ -201,8 +201,30 @@ namespace ZL {
// так как LinearLayout их пересчитает. // так как LinearLayout их пересчитает.
node->localX = j.value("x", 0.0f); node->localX = j.value("x", 0.0f);
node->localY = j.value("y", 0.0f); node->localY = j.value("y", 0.0f);
node->width = j.value("width", 0.0f); if (j.contains("width")) {
node->height = j.value("height", 0.0f); if (j["width"].is_string() && j["width"] == "match_parent") {
node->width = -1.0f; // Наш маркер для match_parent
}
else {
node->width = j["width"].get<float>();
}
}
else
{
node->width = 0.0f;
}
if (j.contains("height")) {
if (j["height"].is_string() && j["height"] == "match_parent") {
node->height = -1.0f; // Наш маркер для match_parent
}
else {
node->height = j["height"].get<float>();
}
}
else
{
node->height = 0.0f;
}
// 3. Параметры компоновки // 3. Параметры компоновки
if (j.contains("orientation")) { if (j.contains("orientation")) {
@ -220,14 +242,13 @@ namespace ZL {
if (j.contains("vertical_align")) { if (j.contains("vertical_align")) {
std::string valign = j["vertical_align"]; std::string valign = j["vertical_align"];
if (valign == "center") node->layoutSettings.vAlign = VerticalAlign::Center; if (valign == "center") node->layoutSettings.vAlign = VerticalAlign::Center;
else if (valign == "top") node->layoutSettings.vAlign = VerticalAlign::Top; else if (valign == "bottom") node->layoutSettings.vAlign = VerticalAlign::Bottom;
} }
// Подготавливаем базовый rect для компонентов (кнопок и т.д.) // Подготавливаем базовый rect для компонентов (кнопок и т.д.)
// На этапе парсинга мы даем им "желаемый" размер // На этапе парсинга мы даем им "желаемый" размер
UiRect initialRect = { node->localX, node->localY, node->width, node->height }; UiRect initialRect = { node->localX, node->localY, node->width, node->height };
if (typeStr == "Button") { if (typeStr == "Button") {
auto btn = std::make_shared<UiButton>(); auto btn = std::make_shared<UiButton>();
btn->name = node->name; btn->name = node->name;
@ -441,7 +462,7 @@ namespace ZL {
void UiManager::replaceRoot(std::shared_ptr<UiNode> newRoot) { void UiManager::replaceRoot(std::shared_ptr<UiNode> newRoot) {
root = newRoot; root = newRoot;
layoutNode(root, 0, 0); layoutNode(root, 0, 0, Environment::projectionWidth, Environment::projectionHeight);
buttons.clear(); buttons.clear();
sliders.clear(); sliders.clear();
textViews.clear(); textViews.clear();
@ -466,54 +487,17 @@ namespace ZL {
} }
void UiManager::layoutNode(const std::shared_ptr<UiNode>& node, float parentX, float parentY, float parentW, float parentH) {
node->screenRect.w = (node->width < 0) ? parentW : node->width;
node->screenRect.h = (node->height < 0) ? parentH : node->height;
void UiManager::updateLayout(const std::shared_ptr<UiNode>& node, float parentX, float parentY) { // 2. Позиция относительно родителя
// 1. Сначала определяем позицию самого контейнера
// Если это корень, он обычно занимает весь экран или заданные координаты
node->screenRect.x = parentX + node->localX; node->screenRect.x = parentX + node->localX;
node->screenRect.y = parentY + node->localY; node->screenRect.y = parentY + node->localY;
node->screenRect.w = node->width;
node->screenRect.h = node->height;
float currentX = node->screenRect.x; // Используем удобные локальные переменные для расчетов детей
// В UI обычно Y растет сверху вниз, но в нашем OpenGL (Renderer.cpp) float currentW = node->screenRect.w;
// используется орто-матрица с Y-вверх. Учтем это. float currentH = node->screenRect.h;
float currentY = node->screenRect.y + node->screenRect.h;
for (auto& child : node->children) {
if (node->layoutType == LayoutType::Linear) {
if (node->orientation == Orientation::Vertical) {
// Игнорируем child->localX/Y для LinearVertical
currentY -= child->height; // Сдвигаемся вниз на высоту элемента
updateLayout(child, node->screenRect.x, currentY - node->screenRect.y);
currentY -= node->spacing; // Добавляем отступ
}
else {
// Логика для Horizontal...
updateLayout(child, currentX, 0); // упрощенно
currentX += child->width + node->spacing;
}
}
else {
// FrameLayout: используем честные localX и localY
updateLayout(child, node->screenRect.x, node->screenRect.y);
}
}
// После вычисления позиций, нужно обновить меши кнопок (buildMesh)
// на основе вычисленных screenRect.
if (node->button) {
node->button->rect = node->screenRect;
node->button->buildMesh();
}
}
void UiManager::layoutNode(const std::shared_ptr<UiNode>& node, float parentX, float parentY) {
// 1. Базовый расчет позиции текущего узла относительно родителя
node->screenRect.x = parentX + node->localX;
node->screenRect.y = parentY + node->localY;
node->screenRect.w = node->width;
node->screenRect.h = node->height;
if (node->layoutType == LayoutType::Linear) { if (node->layoutType == LayoutType::Linear) {
float totalContentWidth = 0; float totalContentWidth = 0;
@ -531,14 +515,12 @@ namespace ZL {
} }
} }
// Вычисляем начальные смещения (Offsets)
float startX = 0; float startX = 0;
float startY = node->height; // Начинаем сверху (Y растет вверх) float startY = currentH;
// Вертикальное выравнивание всего блока внутри контейнера
if (node->orientation == Orientation::Vertical) { if (node->orientation == Orientation::Vertical) {
if (node->layoutSettings.vAlign == VerticalAlign::Center) { if (node->layoutSettings.vAlign == VerticalAlign::Center) {
startY = (node->height + totalContentHeight) / 2.0f; startY = (currentH + totalContentHeight) / 2.0f;
} }
else if (node->layoutSettings.vAlign == VerticalAlign::Bottom) { else if (node->layoutSettings.vAlign == VerticalAlign::Bottom) {
startY = totalContentHeight; startY = totalContentHeight;
@ -548,10 +530,10 @@ namespace ZL {
// Горизонтальное выравнивание всего блока // Горизонтальное выравнивание всего блока
if (node->orientation == Orientation::Horizontal) { if (node->orientation == Orientation::Horizontal) {
if (node->layoutSettings.hAlign == HorizontalAlign::Center) { if (node->layoutSettings.hAlign == HorizontalAlign::Center) {
startX = (node->width - totalContentWidth) / 2.0f; startX = (currentW - totalContentWidth) / 2.0f;
} }
else if (node->layoutSettings.hAlign == HorizontalAlign::Right) { else if (node->layoutSettings.hAlign == HorizontalAlign::Right) {
startX = node->width - totalContentWidth; startX = currentW - totalContentWidth;
} }
} }
@ -559,12 +541,15 @@ namespace ZL {
float cursorY = startY; float cursorY = startY;
for (auto& child : node->children) { for (auto& child : node->children) {
if (node->orientation == Orientation::Vertical) {
cursorY -= child->height;
// Горизонтальное выравнивание внутри строки (Cross-axis alignment) float childW = (child->width < 0) ? currentW : child->width;
float childH = (child->height < 0) ? currentH : child->height;
if (node->orientation == Orientation::Vertical) {
cursorY -= childH; // используем вычисленный childH
float childX = 0; float childX = 0;
float freeSpaceX = node->width - child->width; float freeSpaceX = currentW - childW;
if (node->layoutSettings.hAlign == HorizontalAlign::Center) childX = freeSpaceX / 2.0f; if (node->layoutSettings.hAlign == HorizontalAlign::Center) childX = freeSpaceX / 2.0f;
else if (node->layoutSettings.hAlign == HorizontalAlign::Right) childX = freeSpaceX; else if (node->layoutSettings.hAlign == HorizontalAlign::Right) childX = freeSpaceX;
@ -573,24 +558,34 @@ namespace ZL {
cursorY -= node->spacing; cursorY -= node->spacing;
} }
else { else {
// Вертикальное выравнивание внутри колонки
float childY = 0;
float freeSpaceY = node->height - child->height;
if (node->layoutSettings.vAlign == VerticalAlign::Center) childY = freeSpaceY / 2.0f;
else if (node->layoutSettings.vAlign == VerticalAlign::Bottom) childY = 0; // Внизу
else childY = freeSpaceY; // Вверху
child->localX = cursorX; child->localX = cursorX;
child->localY = childY;
cursorX += child->width + node->spacing; // Вертикальное выравнивание внутри "строки" (Cross-axis alignment)
float childY = 0;
float freeSpaceY = currentH - childH;
if (node->layoutSettings.vAlign == VerticalAlign::Center) {
childY = freeSpaceY / 2.0f;
} }
layoutNode(child, node->screenRect.x, node->screenRect.y); else if (node->layoutSettings.vAlign == VerticalAlign::Top) {
childY = freeSpaceY; // Прижимаем к верхнему краю (т.к. Y растет вверх)
}
else if (node->layoutSettings.vAlign == VerticalAlign::Bottom) {
childY = 0; // Прижимаем к нижнему краю
}
child->localY = childY;
// Сдвигаем курсор вправо для следующего элемента
cursorX += childW + node->spacing;
}
layoutNode(child, node->screenRect.x, node->screenRect.y, currentW, currentH);
} }
} }
else { else {
// Если Frame, просто идем по детям с их фиксированными координатами // Если Frame, просто идем по детям с их фиксированными координатами
for (auto& child : node->children) { for (auto& child : node->children) {
layoutNode(child, node->screenRect.x, node->screenRect.y); layoutNode(child, node->screenRect.x, node->screenRect.y, node->width, node->height);
} }
} }
@ -630,6 +625,13 @@ namespace ZL {
} }
} }
void UiManager::updateAllLayouts() {
if (!root) return;
// Запускаем расчет от корня, передавая размеры экрана как "родительские"
layoutNode(root, 0, 0, Environment::projectionWidth, Environment::projectionHeight);
}
void UiManager::collectButtonsAndSliders(const std::shared_ptr<UiNode>& node) { void UiManager::collectButtonsAndSliders(const std::shared_ptr<UiNode>& node) {
if (node->button) { if (node->button) {
buttons.push_back(node->button); buttons.push_back(node->button);

View File

@ -245,10 +245,10 @@ namespace ZL {
bool startAnimationOnNode(const std::string& nodeName, const std::string& animName); bool startAnimationOnNode(const std::string& nodeName, const std::string& animName);
bool stopAnimationOnNode(const std::string& nodeName, const std::string& animName); bool stopAnimationOnNode(const std::string& nodeName, const std::string& animName);
bool setAnimationCallback(const std::string& nodeName, const std::string& animName, std::function<void()> cb); bool setAnimationCallback(const std::string& nodeName, const std::string& animName, std::function<void()> cb);
void updateAllLayouts();
private: private:
void updateLayout(const std::shared_ptr<UiNode>& node, float parentX, float parentY); void layoutNode(const std::shared_ptr<UiNode>& node, float parentX, float parentY, float parentW, float parentH);
void layoutNode(const std::shared_ptr<UiNode>& node, float parentX, float parentY);
void syncComponentRects(const std::shared_ptr<UiNode>& node); void syncComponentRects(const std::shared_ptr<UiNode>& node);
void collectButtonsAndSliders(const std::shared_ptr<UiNode>& node); void collectButtonsAndSliders(const std::shared_ptr<UiNode>& node);