diff --git a/src/frontend/gui/UINode.cpp b/src/frontend/gui/UINode.cpp index d8a51f68..9d5d60dd 100644 --- a/src/frontend/gui/UINode.cpp +++ b/src/frontend/gui/UINode.cpp @@ -190,3 +190,50 @@ void UINode::reposition() { setPos(positionfunc()); } } + +void UINode::setGravity(Gravity gravity) { + if (gravity == Gravity::none) { + setPositionFunc(nullptr); + return; + } + setPositionFunc([this, gravity](){ + auto parent = getParent(); + if (parent == nullptr) { + return getPos(); + } + glm::vec4 margin = getMargin(); + glm::vec2 size = getSize(); + glm::vec2 parentSize = parent->getSize(); + + float x = 0.0f, y = 0.0f; + switch (gravity) { + case Gravity::top_left: + case Gravity::center_left: + case Gravity::bottom_left: x = parentSize.x+margin.x; break; + case Gravity::top_center: + case Gravity::center_center: + case Gravity::bottom_center: x = (parentSize.x-size.x)/2.0f; break; + case Gravity::top_right: + case Gravity::center_right: + case Gravity::bottom_right: x = parentSize.x-size.x-margin.z; break; + default: break; + } + switch (gravity) { + case Gravity::top_left: + case Gravity::top_center: + case Gravity::top_right: y = parentSize.y+margin.y; break; + case Gravity::center_left: + case Gravity::center_center: + case Gravity::center_right: y = (parentSize.y-size.y)/2.0f; break; + case Gravity::bottom_left: + case Gravity::bottom_center: + case Gravity::bottom_right: y = parentSize.y-size.y-margin.w; break; + default: break; + } + return glm::vec2(x, y); + }); + + if (parent) { + reposition(); + } +} diff --git a/src/frontend/gui/UINode.h b/src/frontend/gui/UINode.h index eadfa5ca..9389a667 100644 --- a/src/frontend/gui/UINode.h +++ b/src/frontend/gui/UINode.h @@ -24,6 +24,22 @@ namespace gui { top=left, bottom=right, }; + enum class Gravity { + none, + + top_left, + top_center, + top_right, + + center_left, + center_center, + center_right, + + bottom_left, + bottom_center, + bottom_right + }; + /// @brief Base abstract class for all UI elements class UINode { /// @brief element identifier used for direct access in UiDocument @@ -161,6 +177,8 @@ namespace gui { /* Fetch pos from positionfunc if assigned */ void reposition(); + + virtual void setGravity(Gravity gravity); }; } diff --git a/src/frontend/gui/gui_xml.cpp b/src/frontend/gui/gui_xml.cpp index 224133c3..b2c02e0c 100644 --- a/src/frontend/gui/gui_xml.cpp +++ b/src/frontend/gui/gui_xml.cpp @@ -22,6 +22,25 @@ static Align align_from_string(const std::string& str, Align def) { return def; } +static Gravity gravity_from_string(const std::string& str) { + static const std::unordered_map gravity_names { + {"top-left", Gravity::top_left}, + {"top-center", Gravity::top_center}, + {"top-right", Gravity::top_right}, + {"center-left", Gravity::center_left}, + {"center-center", Gravity::center_center}, + {"center-right", Gravity::center_right}, + {"bottom-left", Gravity::bottom_left}, + {"bottom-center", Gravity::bottom_center}, + {"bottom-right", Gravity::bottom_right}, + }; + auto found = gravity_names.find(str); + if (found == gravity_names.end()) { + return found->second; + } + return Gravity::none; +} + /* Read basic UINode properties */ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) { if (element->has("id")) { @@ -67,6 +86,12 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no } std::string alignName = element->attr("align", "").getText(); node.setAlign(align_from_string(alignName, node.getAlign())); + + if (element->has("gravity")) { + node.setGravity(gravity_from_string( + element->attr("gravity").getText() + )); + } } diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 29b8988e..dc00b27a 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -229,10 +229,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player) gui->add(grabbedItemView); auto dgrapher = std::make_shared(350, 250, 2000); - dgrapher->setPositionFunc([=]() { - glm::vec2 size = dgrapher->getSize(); - return glm::vec2(Window::width-size.x, Window::height-size.y); - }); + dgrapher->setGravity(gui::Gravity::bottom_right); add(HudElement(hud_element_mode::permanent, nullptr, dgrapher, true)); } @@ -254,7 +251,49 @@ void Hud::cleanup() { return e.isRemoved(); }); elements.erase(it, elements.end()); -} +} + +void Hud::processInput(bool visible) { + if (Events::jpressed(keycode::ESCAPE)) { + if (pause) { + setPause(false); + } else if (inventoryOpen) { + closeInventory(); + } else { + setPause(true); + } + } + + if (visible && Events::jactive(BIND_HUD_INVENTORY)) { + if (inventoryOpen) { + closeInventory(); + } else { + openInventory(); + } + } + if (!pause) { + if (!inventoryOpen && Events::scroll) { + int slot = player->getChosenSlot(); + slot = (slot - Events::scroll) % 10; + if (slot < 0) { + slot += 10; + } + player->setChosenSlot(slot); + } + for ( + int i = static_cast(keycode::NUM_1); + i <= static_cast(keycode::NUM_9); + i++ + ) { + if (Events::jpressed(i)) { + player->setChosenSlot(i - static_cast(keycode::NUM_1)); + } + } + if (Events::jpressed(keycode::NUM_0)) { + player->setChosenSlot(9); + } + } +} void Hud::update(bool visible) { auto level = frontend->getLevel(); @@ -268,31 +307,16 @@ void Hud::update(bool visible) { if (pause && menu->getCurrent().panel == nullptr) { setPause(false); } - if (Events::jpressed(keycode::ESCAPE) && !gui->isFocusCaught()) { - if (pause) { - setPause(false); - } else if (inventoryOpen) { - closeInventory(); - } else { - setPause(true); - } - } - if (visible && !gui->isFocusCaught() && !pause) { - if (Events::jactive(BIND_HUD_INVENTORY)) { - if (inventoryOpen) { - closeInventory(); - } else { - openInventory(); - } - } + if (!gui->isFocusCaught()) { + processInput(visible); } if ((pause || inventoryOpen) == Events::_cursor_locked) { Events::toggleCursor(); } if (blockUI) { - voxel* vox = level->chunks->get(currentblock.x, currentblock.y, currentblock.z); + voxel* vox = level->chunks->get(blockPos.x, blockPos.y, blockPos.z); if (vox == nullptr || vox->id != currentblockid) { closeInventory(); } @@ -308,25 +332,6 @@ void Hud::update(bool visible) { contentAccess->setMinSize(glm::vec2(1, Window::height)); hotbarView->setVisible(visible); - if (!gui->isFocusCaught() && !pause) { - for (int i = static_cast(keycode::NUM_1); i <= static_cast(keycode::NUM_9); i++) { - if (Events::jpressed(i)) { - player->setChosenSlot(i - static_cast(keycode::NUM_1)); - } - } - if (Events::jpressed(keycode::NUM_0)) { - player->setChosenSlot(9); - } - } - if (!pause && !inventoryOpen && Events::scroll) { - int slot = player->getChosenSlot(); - slot = (slot - Events::scroll) % 10; - if (slot < 0) { - slot += 10; - } - player->setChosenSlot(slot); - } - if (visible) { for (auto& element : elements) { element.update(pause, inventoryOpen, player->debug); @@ -348,11 +353,6 @@ void Hud::openInventory() { add(HudElement(hud_element_mode::inventory_bound, inventoryDocument, inventoryView, false)); } -/// @brief Show player inventory + block UI -/// @param block world position of the open block -/// @param doc block UI document (root element must be an InventoryView) -/// @param blockinv block inventory. -/// If blockinv is nullptr a new virtual inventory will be created void Hud::openInventory( glm::ivec3 block, UiDocument* doc, @@ -378,7 +378,7 @@ void Hud::openInventory( } level->chunks->getChunkByVoxel(block.x, block.y, block.z)->setUnsaved(true); blockUI->bind(blockinv, frontend, interaction.get()); - currentblock = block; + blockPos = block; currentblockid = level->chunks->get(block.x, block.y, block.z)->id; add(HudElement(hud_element_mode::inventory_bound, doc, blockUI, false)); } @@ -427,13 +427,13 @@ void Hud::add(HudElement element) { scripting::on_ui_open( element.getDocument(), inventory.get(), - currentblock + blockPos ); } else { scripting::on_ui_open( element.getDocument(), nullptr, - currentblock + blockPos ); } } diff --git a/src/frontend/hud.h b/src/frontend/hud.h index 3976890e..c2a3ee03 100644 --- a/src/frontend/hud.h +++ b/src/frontend/hud.h @@ -97,7 +97,7 @@ class Hud { /// @brief Block inventory view std::shared_ptr blockUI = nullptr; /// @brief Position of the block open - glm::ivec3 currentblock {}; + glm::ivec3 blockPos {}; /// @brief Id of the block open (used to detect block destruction or replacement) blockid_t currentblockid = 0; @@ -107,6 +107,7 @@ class Hud { std::shared_ptr createContentAccess(); std::shared_ptr createHotbar(); + void processInput(bool visible); void updateElementsPosition(const Viewport& viewport); void cleanup(); public: