diff --git a/doc/en/scripting/builtins/libgui.md b/doc/en/scripting/builtins/libgui.md
index 53d6e4ad2..a7ddbeaec 100644
--- a/doc/en/scripting/builtins/libgui.md
+++ b/doc/en/scripting/builtins/libgui.md
@@ -139,7 +139,7 @@ gui.confirm(
## Documents and templates
```lua
--- Loads a UI document with its script, returns the name of the document if successfully loaded.
+-- Loads a UI document with its script. Returns document environment table
gui.load_document(
-- Path to the xml file of the page. Example: `core:layouts/pages/main.xml`
path: str,
@@ -147,7 +147,7 @@ gui.load_document(
name: str
-- Table of parameters passed to the on_open event
args: table
-) -> str
+) -> table
-- Loads and processes layout template from file
gui.template(
diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md
index 643f2adcb..704a0b786 100644
--- a/doc/en/xml-ui-layouts.md
+++ b/doc/en/xml-ui-layouts.md
@@ -39,6 +39,8 @@ Examples:
- `position-func` - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open*
- `size-func` - element size provider (two numbers), called when the size of the container in which the element is located changes, or when an element is added to the container. Can be called before on_hud_open is called.
- `onclick` - lua function called when an element is clicked.
+- `onrightclick` - lua function called when the right mouse button is pressed on an element.
+- `onmiddleclick` - lua function called when the middle mouse button is pressed on an element.
- `ondoubleclick` - lua function called when you double click on an element.
- `onfocus` - lua function called when focusing on an element.
- `ondefocus` - lua function called when the element loses focus.
diff --git a/doc/ru/scripting/builtins/libgui.md b/doc/ru/scripting/builtins/libgui.md
index 9c2eb7418..ea1221415 100644
--- a/doc/ru/scripting/builtins/libgui.md
+++ b/doc/ru/scripting/builtins/libgui.md
@@ -140,12 +140,12 @@ gui.confirm(
## Документы и шаблоны
```lua
--- Загружает UI документ и его скрипт. Возвращает имя документа.
+-- Загружает UI документ и его скрипт. Возвращает пространство имён документа
gui.load_document(
path: string, -- путь к xml файлу, например: core:layouts/pages/main.xml
name: string, -- id документа, например: core:pages/main
args: table -- параметры для события on_open
-) -> string
+) -> table
-- Обрабатывает xml шаблон макета из файла
gui.template(
diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md
index 3b40f6c9c..9be788e7f 100644
--- a/doc/ru/xml-ui-layouts.md
+++ b/doc/ru/xml-ui-layouts.md
@@ -43,6 +43,8 @@
- `position-func` - поставщик позиции элемента (два числа), вызываемый при изменении размера контейнера, в котором находится элемент, либо при добавлении элемента в контейнер. Может быть вызван до вызова on_hud_open.
- `size-func` - поставщик размера элемента (два числа), вызываемый при изменении размера контейнера, в котором находится элемент, либо при добавлении элемента в контейнер. Может быть вызван до вызова on_hud_open.
- `onclick` - lua функция вызываемая при нажатии на элемент.
+- `onrightclick` - lua функция вызываемая при нажатии правой кнопки мыши на элемент.
+- `onmiddleclick` - lua функция вызываемая при нажатии средней кнопки мыши на элемент.
- `ondoubleclick` - lua функция вызываемая при двойном нажатии на элемент.
- `onfocus` - lua функция вызываемая при фокусировке на элемент.
- `ondefocus` - lua функция вызываемая при потере фокуса элеметом.
diff --git a/res/content/base/modules/util.lua b/res/content/base/modules/util.lua
index 874e6d3d6..dbad0c2a1 100644
--- a/res/content/base/modules/util.lua
+++ b/res/content/base/modules/util.lua
@@ -1,5 +1,44 @@
local util = {}
+local DROP_FORCE = 8
+local DROP_INIT_VEL = {0, 3, 0}
+
+---@param mode integer 0 - whole stack, 1 - single item, 2 - dupe whole stack
+function util.drop_from_slot(invid, slot, mode)
+ if invid == 0 then
+ return
+ end
+ local pid = hud.get_player()
+ if mode == 2 and !player.is_infinite_items(pid) then
+ return
+ end
+ local itemid, itemcount = inventory.get(invid, slot)
+ if itemid == 0 then
+ return
+ end
+
+ local drop_itemcount = 1
+ if mode == 0 then
+ drop_itemcount = itemcount
+ end
+ if mode == 2 then
+ drop_itemcount = item.stack_size(itemid)
+ else
+ inventory.set(invid, slot, itemid, itemcount - drop_itemcount)
+ end
+
+ local data = inventory.get_all_data(invid, slot)
+ local pvel = { player.get_vel(pid) }
+ local ppos = vec3.add({ player.get_pos(pid) }, { 0, 0.7, 0 })
+ local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
+ local drop = util.drop(ppos, itemid, drop_itemcount, data, 1.5)
+ if not drop then
+ return
+ end
+ local velocity = vec3.add(throw_force, vec3.add(pvel, DROP_INIT_VEL))
+ drop.rigidbody:set_vel(velocity)
+end
+
function util.drop(ppos, itemid, count, data, pickup_delay)
if itemid == 0 or not itemid then
return nil
diff --git a/res/content/base/scripts/hud.lua b/res/content/base/scripts/hud.lua
index 3620566e5..d0e3d1532 100644
--- a/res/content/base/scripts/hud.lua
+++ b/res/content/base/scripts/hud.lua
@@ -1,46 +1,10 @@
local base_util = require "util"
-local DROP_FORCE = 8
-local DROP_INIT_VEL = {0, 3, 0}
-
----@param mode integer 0 - whole stack, 1 - single item, 2 - dupe whole stack
-function drop_from_slot(invid, slot, mode)
- local pid = hud.get_player()
- if mode == 2 and !player.is_infinite_items(pid) then
- return
- end
- local itemid, itemcount = inventory.get(invid, slot)
- if itemid == 0 then
- return
- end
-
- local drop_itemcount = 1
- if mode == 0 then
- drop_itemcount = itemcount
- end
- if mode == 2 then
- drop_itemcount = item.stack_size(itemid)
- else
- inventory.set(invid, slot, itemid, itemcount - drop_itemcount)
- end
-
- local data = inventory.get_all_data(invid, slot)
- local pvel = { player.get_vel(pid) }
- local ppos = vec3.add({ player.get_pos(pid) }, { 0, 0.7, 0 })
- local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
- local drop = base_util.drop(ppos, itemid, drop_itemcount, data, 1.5)
- if not drop then
- return
- end
- local velocity = vec3.add(throw_force, vec3.add(pvel, DROP_INIT_VEL))
- drop.rigidbody:set_vel(velocity)
-end
-
-function on_inventory_clicked_outside(exc_invid, exc_slot, mode)
- drop_from_slot(exc_invid, exc_slot, mode)
-end
-
function on_hud_open()
+ events.on("core:drop_outside_inventory", function(mode)
+ local invid = hud.get_exchange_inventory()
+ base_util.drop_from_slot(invid, 0, mode)
+ end)
input.add_callback("player.drop", function()
if hud.is_paused() or hud.is_inventory_open() then
return
@@ -51,7 +15,7 @@ function on_hud_open()
if input.is_pressed("key:left-ctrl") or input.is_pressed("key:right-ctrl") then
mode = 0
end
- drop_from_slot(invid, slot, mode)
+ base_util.drop_from_slot(invid, slot, mode)
end)
rules.create("do-loot-non-player", true)
end
diff --git a/res/modules/internal/gui_util.lua b/res/modules/internal/gui_util.lua
index 656a0dfc8..971bad39f 100644
--- a/res/modules/internal/gui_util.lua
+++ b/res/modules/internal/gui_util.lua
@@ -192,13 +192,15 @@ function gui.ask(text, on_yes, on_no, yes_text, no_text)
-
+
- ]], id, string.escape_xml(text)), {on_yes=yes_callback, on_no=no_callback},
- string.escape_xml(yes_text), string.escape_xml(no_text))
+ ]], id,
+ string.escape_xml(text),
+ string.escape_xml(yes_text),
+ string.escape_xml(no_text)), {on_yes=yes_callback, on_no=no_callback})
input.add_callback("key:escape", no_callback, gui.root[id])
end
diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp
index 1aa03436b..08a4b8455 100644
--- a/src/frontend/hud.cpp
+++ b/src/frontend/hud.cpp
@@ -174,6 +174,15 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
gui,
""
);
+
+ inventoryDropArea = guiutil::create(
+ gui,
+ R"()"
+ );
uicamera = std::make_unique(glm::vec3(), 1);
uicamera->perspective = false;
@@ -188,6 +197,7 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
gui.add(debugPanel);
gui.add(darkOverlay);
+ gui.add(inventoryDropArea);
gui.add(hotbarView);
gui.add(contentAccessPanel);
@@ -213,6 +223,7 @@ Hud::~Hud() {
}
gui.remove(hotbarView);
gui.remove(darkOverlay);
+ gui.remove(inventoryDropArea);
gui.remove(contentAccessPanel);
gui.remove(debugPanel);
}
@@ -358,6 +369,7 @@ void Hud::update(bool visible) {
contentAccess->setMinSize(glm::vec2(1, windowSize.y));
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
darkOverlay->setVisible(isMenuOpen);
+ inventoryDropArea->setVisible(inventoryOpen);
menu.setVisible(isMenuOpen);
if (visible) {
@@ -739,6 +751,10 @@ std::shared_ptr Hud::getSecondInventory() {
return nullptr;
}
+std::shared_ptr Hud::getExchangeInventory() {
+ return exchangeSlotInv;
+}
+
bool Hud::isContentAccess() const {
return showContentPanel;
}
diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp
index f80c36369..f40a53581 100644
--- a/src/frontend/hud.hpp
+++ b/src/frontend/hud.hpp
@@ -93,6 +93,8 @@ class Hud : public util::ObjectsKeeper {
std::shared_ptr debugPanel;
/// @brief Overlay used in pause mode
std::shared_ptr darkOverlay;
+ /// @brief Overlay used in inventory
+ std::shared_ptr inventoryDropArea;
/// @brief Inventories interaction agent (grabbed item)
std::shared_ptr exchangeSlot;
/// @brief Exchange slot inventory (1 slot only)
@@ -207,6 +209,8 @@ public:
std::shared_ptr getSecondInventory();
+ std::shared_ptr getExchangeInventory();
+
bool isContentAccess() const;
void setContentAccess(bool flag);
diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp
index fb4320113..944c32fb5 100644
--- a/src/graphics/ui/GUI.cpp
+++ b/src/graphics/ui/GUI.cpp
@@ -178,8 +178,6 @@ void GUI::actMouse(Frame& frame, float delta, const CursorState& cursor) {
}
it = mouseOver.erase(it);
}
-
- bool focusHappened = false;
if (input.jclicked(Mousecode::BUTTON_1)) {
if (pressed == nullptr && this->hover) {
@@ -197,10 +195,10 @@ void GUI::actMouse(Frame& frame, float delta, const CursorState& cursor) {
if (focus != pressed) {
focus = pressed;
focus->onFocus();
- focusHappened = true;
+ return;
}
}
- if (this->hover == nullptr && focus && !focusHappened) {
+ if (this->hover == nullptr && focus) {
focus->defocus();
focus = nullptr;
}
@@ -209,44 +207,13 @@ void GUI::actMouse(Frame& frame, float delta, const CursorState& cursor) {
pressed = nullptr;
}
- if (hover && !focusHappened) {
+ if (hover) {
for (Mousecode code : MOUSECODES_ALL) {
if (input.jclicked(code)) {
hover->clicked(code);
}
}
}
- performClickOutside(frame, delta, cursorPos);
-}
-
-void GUI::performClickOutside(Frame& frame, float delta, glm::vec2 cursorPos) {
- auto nodes = frame.getNodes();
- std::vector> activeNodes;
-
- for (const auto& node : nodes) {
- if (node && node->isVisible() && node->isInteractive()) {
- activeNodes.push_back(node);
- }
- }
-
- for (Mousecode code : {Mousecode::BUTTON_1, Mousecode::BUTTON_2, Mousecode::BUTTON_3}) {
- if (input.jclicked(code)) {
- bool isOverAnyNode = false;
- for (const auto& node : activeNodes) {
- if (node && node->isInside(cursorPos)) {
- isOverAnyNode = true;
- break;
- }
- }
- if (!isOverAnyNode) {
- for (const auto& node : activeNodes) {
- if (node) {
- node->clickedOutside(code);
- }
- }
- }
- }
- }
}
void GUI::actFocused() {
diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp
index 9b65089c1..97fc0ed37 100644
--- a/src/graphics/ui/GUI.hpp
+++ b/src/graphics/ui/GUI.hpp
@@ -2,6 +2,7 @@
#include "delegates.hpp"
+#include
#include
#include
#include
@@ -92,7 +93,6 @@ namespace gui {
bool debug = false;
void actMouse(Frame& frame, float delta, const CursorState& cursor);
- void performClickOutside(Frame& frame, float delta, glm::vec2 cursorPos);
void actFocused();
void updateTooltip(float delta);
void resetTooltip();
diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp
index 29111a4ad..c8cca1f5b 100644
--- a/src/graphics/ui/elements/InventoryView.cpp
+++ b/src/graphics/ui/elements/InventoryView.cpp
@@ -18,7 +18,6 @@
#include "graphics/ui/GUI.hpp"
#include "items/Inventory.hpp"
#include "items/ItemDef.hpp"
-#include "items/ItemStack.hpp"
#include "logic/scripting/scripting.hpp"
#include "maths/voxmaths.hpp"
#include "objects/Player.hpp"
@@ -615,33 +614,6 @@ void InventoryView::setPos(const glm::vec2& pos) {
Container::setPos(pos - origin);
}
-void InventoryView::clickedOutside(Mousecode button) {
- // root is the id of the main inventory
- if (getId() != "root") {
- return;
- }
- int mode;
- if (button == Mousecode::BUTTON_1) {
- mode = 0;
- } else if (button == Mousecode::BUTTON_2) {
- mode = 1;
- } else if (button == Mousecode::BUTTON_3) {
- mode = 2;
- } else {
- return;
- };
- auto exchangeSlot = std::dynamic_pointer_cast(
- gui.get(SlotView::EXCHANGE_SLOT_NAME));
- if (exchangeSlot == nullptr) {
- return;
- }
- ItemStack& grabbed = exchangeSlot->getStack();
- if (grabbed.isEmpty()) {
- return;
- }
- scripting::on_inventory_clicked_outside(exchangeSlot->getInventoryId(), 0, mode);
-}
-
void InventoryView::setOrigin(const glm::vec2& origin) {
this->origin = origin;
}
diff --git a/src/graphics/ui/elements/InventoryView.hpp b/src/graphics/ui/elements/InventoryView.hpp
index a0d3c76e9..243d8b6b5 100644
--- a/src/graphics/ui/elements/InventoryView.hpp
+++ b/src/graphics/ui/elements/InventoryView.hpp
@@ -143,8 +143,6 @@ namespace gui {
void setSelected(int index);
- void clickedOutside(Mousecode button) override;
-
void bind(
const std::shared_ptr& inventory,
const Content* content
diff --git a/src/graphics/ui/elements/ModelViewer.cpp b/src/graphics/ui/elements/ModelViewer.cpp
index 727110f8b..748eabae5 100644
--- a/src/graphics/ui/elements/ModelViewer.cpp
+++ b/src/graphics/ui/elements/ModelViewer.cpp
@@ -13,6 +13,7 @@
#include "window/Window.hpp"
#include "../GUI.hpp"
+// TODO: remove
// TODO: remove
#include
@@ -24,8 +25,7 @@ ModelViewer::ModelViewer(
: Container(gui, size),
modelName(modelName),
camera(),
- batch(std::make_unique(1024)),
- fbo(std::make_unique(size.x, size.y)) {
+ batch(std::make_unique(1024)) {
camera.perspective = true;
camera.position = glm::vec3(2, 2, 2);
}
@@ -115,7 +115,13 @@ void ModelViewer::draw(const DrawContext& pctx, const Assets& assets) {
return;
}
auto& prevShader = Shader::getUsed();
-
+
+ if (!fbo) {
+ if (size.x <= 0 || size.y <= 0) {
+ return;
+ }
+ fbo = std::make_unique(size.x, size.y);
+ }
fbo->resize(size.x, size.y);
{
glDisable(GL_SCISSOR_TEST);
@@ -154,6 +160,13 @@ void ModelViewer::draw(const DrawContext& pctx, const Assets& assets) {
Container::draw(pctx, assets);
}
+void ModelViewer::setVisible(bool flag) {
+ if (!flag && fbo) {
+ fbo.reset();
+ }
+ Container::setVisible(flag);
+}
+
void ModelViewer::setCenter(const glm::vec3& center) {
this->center = center;
}
diff --git a/src/graphics/ui/elements/ModelViewer.hpp b/src/graphics/ui/elements/ModelViewer.hpp
index 4e841faae..8cf999bb9 100644
--- a/src/graphics/ui/elements/ModelViewer.hpp
+++ b/src/graphics/ui/elements/ModelViewer.hpp
@@ -23,7 +23,6 @@ namespace gui {
bool grabbing = false;
public:
ModelViewer(GUI& gui, const glm::vec2& size, const std::string& modelName);
-
~ModelViewer();
void setModel(const std::string& modelName);
@@ -34,6 +33,7 @@ namespace gui {
void act(float delta) override;
void draw(const DrawContext& pctx, const Assets& assets) override;
+ void setVisible(bool flag) override;
void setRotation(const glm::vec3& euler);
void setCenter(const glm::vec3& center);
diff --git a/src/graphics/ui/elements/UINode.cpp b/src/graphics/ui/elements/UINode.cpp
index 465ff26e4..85347b9a8 100644
--- a/src/graphics/ui/elements/UINode.cpp
+++ b/src/graphics/ui/elements/UINode.cpp
@@ -79,6 +79,8 @@ void UINode::click(int, int) {
void UINode::clicked(Mousecode button) {
if (button == Mousecode::BUTTON_2) {
actions.notify(UIAction::RIGHT_CLICK, gui);
+ } else if (button == Mousecode::BUTTON_3) {
+ actions.notify(UIAction::MIDDLE_CLICK, gui);
}
}
diff --git a/src/graphics/ui/elements/UINode.hpp b/src/graphics/ui/elements/UINode.hpp
index bd2254567..a7b18390c 100644
--- a/src/graphics/ui/elements/UINode.hpp
+++ b/src/graphics/ui/elements/UINode.hpp
@@ -58,6 +58,7 @@ namespace gui {
FOCUS,
DEFOCUS,
RIGHT_CLICK,
+ MIDDLE_CLICK,
MOUSE_OVER,
MOUSE_OUT,
MOUSE_ENTER,
@@ -207,9 +208,6 @@ namespace gui {
virtual void onFocus();
virtual void doubleClick(int x, int y);
virtual void click(int x, int y);
- virtual void clickedOutside(Mousecode button) {
- // Empty for all UINodes, except InventoryView
- }
virtual void clicked(Mousecode button);
virtual void mouseMove(int x, int y) {};
virtual void mouseRelease(int x, int y);
diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp
index 3026f8215..41a603cea 100644
--- a/src/graphics/ui/gui_xml.cpp
+++ b/src/graphics/ui/gui_xml.cpp
@@ -181,6 +181,7 @@ static void read_uinode(
register_action(node, reader, element, "onclick", UIAction::CLICK);
register_action(node, reader, element, "onrightclick", UIAction::RIGHT_CLICK);
+ register_action(node, reader, element, "onmiddleclick", UIAction::MIDDLE_CLICK);
register_action(node, reader, element, "onfocus", UIAction::FOCUS);
register_action(node, reader, element, "ondefocus", UIAction::DEFOCUS);
register_action(node, reader, element, "ondoubleclick", UIAction::DOUBLE_CLICK);
diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp
index 057dc205e..81e5fc4f7 100644
--- a/src/logic/scripting/lua/libs/libgui.cpp
+++ b/src/logic/scripting/lua/libs/libgui.cpp
@@ -1127,6 +1127,7 @@ static int l_gui_load_document(lua::State* L) {
}
auto env = scripting::create_doc_environment(parentEnv, alias);
+ auto envId = *env;
// namespace extension
if (lua::istable(L, 4)) {
if (lua::get_from(L, "table", "extend")) {
@@ -1148,7 +1149,7 @@ static int l_gui_load_document(lua::State* L) {
engine->requireAssets().store(std::move(documentPtr), alias);
scripting::on_ui_open(*document, {args});
- return 0;
+ return lua::pushenv(L, envId);
}
static int l_set_syntax_styles(lua::State* L) {
diff --git a/src/logic/scripting/lua/libs/libhud.cpp b/src/logic/scripting/lua/libs/libhud.cpp
index 7f5c893c5..a457ca6ee 100644
--- a/src/logic/scripting/lua/libs/libhud.cpp
+++ b/src/logic/scripting/lua/libs/libhud.cpp
@@ -149,6 +149,15 @@ static int l_get_second_inventory(lua::State* L) {
}
}
+static int l_get_exchange_inventory(lua::State* L) {
+ auto inventory = hud->getExchangeInventory();
+ if (inventory == nullptr) {
+ return lua::pushinteger(L, 0);
+ } else {
+ return lua::pushinteger(L, inventory->getId());
+ }
+}
+
static int l_get_player(lua::State* L) {
auto player = hud->getPlayer();
return lua::pushinteger(L, player->getId());
@@ -216,6 +225,7 @@ const luaL_Reg hudlib[] = {
{"show_overlay", wrap_hud},
{"get_block_inventory", wrap_hud},
{"get_second_inventory", wrap_hud},
+ {"get_exchange_inventory", wrap_hud},
{"close", wrap_hud},
{"pause", wrap_hud},
{"resume", wrap_hud},