Working on UI for web
This commit is contained in:
parent
ffbecbbcde
commit
6b4b549b3c
@ -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 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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();
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user