From 0c71255938cda814ef7dffdeaf994a5cf6583f94 Mon Sep 17 00:00:00 2001 From: Quentin Bazin Date: Sun, 1 Mar 2020 15:45:09 +0100 Subject: [PATCH] [MouseItemWidget] Now supports drag-click. --- client/source/gui/AbstractInventoryWidget.hpp | 3 +- client/source/gui/CraftingWidget.cpp | 16 ++-- client/source/gui/CraftingWidget.hpp | 7 +- client/source/gui/InventoryWidget.cpp | 39 ++++---- client/source/gui/InventoryWidget.hpp | 14 ++- client/source/gui/ItemWidget.hpp | 5 + client/source/gui/MouseItemWidget.cpp | 96 ++++++++++++++++++- client/source/gui/MouseItemWidget.hpp | 17 +++- client/source/states/LuaGUIState.cpp | 13 +-- client/source/states/LuaGUIState.hpp | 2 +- mods/default/init.lua | 4 +- 11 files changed, 163 insertions(+), 53 deletions(-) diff --git a/client/source/gui/AbstractInventoryWidget.hpp b/client/source/gui/AbstractInventoryWidget.hpp index 919af2ec7..c9db1774b 100644 --- a/client/source/gui/AbstractInventoryWidget.hpp +++ b/client/source/gui/AbstractInventoryWidget.hpp @@ -38,8 +38,9 @@ class AbstractInventoryWidget : public Widget { const std::vector &shiftDestination() const { return m_shiftDestination; } void setShiftDestination(const std::string &shiftDestination); + void setShiftDestination(const std::vector &shiftDestination) { m_shiftDestination = shiftDestination; } - private: + protected: std::vector m_shiftDestination; }; diff --git a/client/source/gui/CraftingWidget.cpp b/client/source/gui/CraftingWidget.cpp index ad0d08dc7..0513e49eb 100644 --- a/client/source/gui/CraftingWidget.cpp +++ b/client/source/gui/CraftingWidget.cpp @@ -38,11 +38,14 @@ void CraftingWidget::init(unsigned int offset, unsigned int size) { m_craftingInventoryWidget.setParent(this); m_craftingResultInventoryWidget.setParent(this); + + m_craftingInventoryWidget.setShiftDestination(m_shiftDestination); + m_craftingResultInventoryWidget.setShiftDestination(m_shiftDestination); } -void CraftingWidget::onMouseEvent(const SDL_Event &event, MouseItemWidget &mouseItemWidget) { - m_craftingInventoryWidget.onMouseEvent(event, mouseItemWidget); - m_craftingResultInventoryWidget.onMouseEvent(event, mouseItemWidget, true); +void CraftingWidget::onEvent(const SDL_Event &event) { + m_craftingInventoryWidget.onEvent(event); + m_craftingResultInventoryWidget.onEvent(event); m_currentInventoryWidget = m_craftingResultInventoryWidget.currentItemWidget() ? &m_craftingResultInventoryWidget : &m_craftingInventoryWidget; @@ -81,11 +84,8 @@ void CraftingWidget::update() { } bool CraftingWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) { - if (m_currentInventoryWidget && dest->receiveItemStack(itemStack)) { - m_currentInventoryWidget->inventory()->clearStack(itemStack->x(), itemStack->y()); - m_currentInventoryWidget->update(); - m_currentInventoryWidget->sendUpdatePacket(); - return true; + if (m_currentInventoryWidget) { + return m_currentInventoryWidget->sendItemStackToDest(itemStack, dest); } return false; diff --git a/client/source/gui/CraftingWidget.hpp b/client/source/gui/CraftingWidget.hpp index a6caab887..6f427bc76 100644 --- a/client/source/gui/CraftingWidget.hpp +++ b/client/source/gui/CraftingWidget.hpp @@ -37,14 +37,15 @@ class CraftingWidget : public AbstractInventoryWidget { void init(unsigned int offset = 0, unsigned int size = 3); - void onMouseEvent(const SDL_Event &event, MouseItemWidget &mouseItemWidget); + void onEvent(const SDL_Event &event) override; void update() override; bool sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) override; bool receiveItemStack(const ItemWidget *itemStack) override; - const ItemWidget *currentItemWidget() const { return m_craftingResultInventoryWidget.currentItemWidget() ? m_craftingResultInventoryWidget.currentItemWidget() : m_craftingInventoryWidget.currentItemWidget(); } + ItemWidget *currentItemWidget() const { return m_craftingResultInventoryWidget.currentItemWidget() ? m_craftingResultInventoryWidget.currentItemWidget() : m_craftingInventoryWidget.currentItemWidget(); } + InventoryWidget *currentInventoryWidget() const { return m_currentInventoryWidget; } InventoryWidget &craftingInventoryWidget() { return m_craftingInventoryWidget; } InventoryWidget &craftingResultInventoryWidget() { return m_craftingResultInventoryWidget; } @@ -60,7 +61,7 @@ class CraftingWidget : public AbstractInventoryWidget { InventoryWidget m_craftingInventoryWidget{m_client}; Inventory m_craftingResultInventory{1, 1}; - InventoryWidget m_craftingResultInventoryWidget{m_client}; + InventoryWidget m_craftingResultInventoryWidget{m_client, true}; const Recipe *m_recipe = nullptr; }; diff --git a/client/source/gui/InventoryWidget.cpp b/client/source/gui/InventoryWidget.cpp index 00d910569..24b88b197 100644 --- a/client/source/gui/InventoryWidget.cpp +++ b/client/source/gui/InventoryWidget.cpp @@ -50,7 +50,7 @@ void InventoryWidget::init(Inventory &inventory, u16 offset, u16 size) { m_inventoryHeight = inventory.height(); } -void InventoryWidget::onMouseEvent(const SDL_Event &event, MouseItemWidget &mouseItemWidget, bool isReadOnly) { +void InventoryWidget::onEvent(const SDL_Event &event) { if (event.type == SDL_MOUSEMOTION) { m_currentItemWidget = nullptr; for (std::size_t i = 0 ; i < m_itemWidgets.size() ; ++i) { @@ -61,34 +61,24 @@ void InventoryWidget::onMouseEvent(const SDL_Event &event, MouseItemWidget &mous } } } - else if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT && m_currentItemWidget) { - if (m_inventory && !m_inventory->isUnlimited()) - mouseItemWidget.swapItems(*m_currentItemWidget, isReadOnly); - else if (m_inventory && mouseItemWidget.getStack().amount() == 0 && m_currentItemWidget->stack().amount() != 0) - mouseItemWidget.setStack(m_currentItemWidget->stack().item().stringID(), 64); - - sendUpdatePacket(); - } - else if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT && m_currentItemWidget) { - if (!isReadOnly) { - if (m_inventory && !m_inventory->isUnlimited()) - mouseItemWidget.putItem(*m_currentItemWidget); - else if (m_inventory && mouseItemWidget.getStack().amount() == 0 && m_currentItemWidget->stack().amount() != 0) - mouseItemWidget.setStack(m_currentItemWidget->stack().item().stringID(), 1); - - sendUpdatePacket(); - } - } } void InventoryWidget::update() { - for (auto &it : m_itemWidgets) + bool hasChanged = false; + + for (auto &it : m_itemWidgets) { it.update(); + + hasChanged = hasChanged || it.hasChanged(); + it.setChanged(false); + } + + if (hasChanged) + sendUpdatePacket(); } bool InventoryWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) { if (dest->receiveItemStack(itemStack)) { - m_inventory->clearStack(itemStack->x(), itemStack->y()); update(); sendUpdatePacket(); return true; @@ -98,10 +88,15 @@ bool InventoryWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractI } bool InventoryWidget::receiveItemStack(const ItemWidget *itemStack) { - bool stackAdded = m_inventory->addStack(itemStack->stack().item().stringID(), itemStack->stack().amount(), m_offset, m_size); + ItemStack stack = itemStack->stack(); + m_inventory->clearStack(itemStack->x(), itemStack->y()); + + bool stackAdded = m_inventory->addStack(stack.item().stringID(), stack.amount(), m_offset, m_size); if (stackAdded) sendUpdatePacket(); + else + m_inventory->setStack(itemStack->x(), itemStack->y(), stack.item().stringID(), stack.amount()); return stackAdded; } diff --git a/client/source/gui/InventoryWidget.hpp b/client/source/gui/InventoryWidget.hpp index a33258c16..eedca586e 100644 --- a/client/source/gui/InventoryWidget.hpp +++ b/client/source/gui/InventoryWidget.hpp @@ -36,12 +36,12 @@ class ClientCommandHandler; class InventoryWidget : public AbstractInventoryWidget { public: - InventoryWidget(ClientCommandHandler &client, Widget *parent = nullptr) - : AbstractInventoryWidget(parent), m_client(client) {} + InventoryWidget(ClientCommandHandler &client, bool isReadOnly = false, Widget *parent = nullptr) + : AbstractInventoryWidget(parent), m_client(client), m_isReadOnly(isReadOnly) {} void init(Inventory &inventory, u16 offset = 0, u16 size = 0); - void onMouseEvent(const SDL_Event &event, MouseItemWidget &mouseItemWidget, bool isReadOnly = false); + void onEvent(const SDL_Event &event) override; void update() override; @@ -50,9 +50,11 @@ class InventoryWidget : public AbstractInventoryWidget { void sendUpdatePacket(); - Inventory *inventory() { return m_inventory; } + Inventory *inventory() const { return m_inventory; } - const ItemWidget *currentItemWidget() const { return m_currentItemWidget; } + bool isReadOnly() const { return m_isReadOnly; } + + ItemWidget *currentItemWidget() const { return m_currentItemWidget; } private: void draw(gk::RenderTarget &target, gk::RenderStates states) const override; @@ -67,6 +69,8 @@ class InventoryWidget : public AbstractInventoryWidget { u16 m_offset = 0; u16 m_size = 0; + bool m_isReadOnly = false; + std::vector m_itemWidgets; ItemWidget *m_currentItemWidget = nullptr; diff --git a/client/source/gui/ItemWidget.hpp b/client/source/gui/ItemWidget.hpp index 3407d52b6..1d6b1f41b 100644 --- a/client/source/gui/ItemWidget.hpp +++ b/client/source/gui/ItemWidget.hpp @@ -47,6 +47,9 @@ class ItemWidget : public Widget { unsigned int x() const { return m_x; } unsigned int y() const { return m_y; } + bool hasChanged() const { return m_hasChanged; } + void setChanged(bool hasChanged) { m_hasChanged = hasChanged; } + protected: void draw(gk::RenderTarget &target, gk::RenderStates states) const override; @@ -64,6 +67,8 @@ class ItemWidget : public Widget { InventoryCube m_cube{10}; bool m_isImage = false; + + bool m_hasChanged = false; }; #endif // ITEMWIDGET_HPP_ diff --git a/client/source/gui/MouseItemWidget.cpp b/client/source/gui/MouseItemWidget.cpp index f726c4b87..4ee62cf67 100644 --- a/client/source/gui/MouseItemWidget.cpp +++ b/client/source/gui/MouseItemWidget.cpp @@ -24,6 +24,7 @@ * * ===================================================================================== */ +#include "InventoryWidget.hpp" #include "MouseItemWidget.hpp" MouseItemWidget::MouseItemWidget(Widget *parent) : ItemWidget(m_inventory, 0, 0, parent) { @@ -39,15 +40,103 @@ MouseItemWidget::MouseItemWidget(Widget *parent) : ItemWidget(m_inventory, 0, 0, void MouseItemWidget::onEvent(const SDL_Event &event) { if (event.type == SDL_MOUSEMOTION) { updatePosition(event.motion.x, event.motion.y); - } + if (m_isDragging) { + for (auto &it : m_draggedSlots) { + u16 splitAmount; + if (m_isLeftClickDrag) + splitAmount = m_draggedStack.amount() / m_draggedSlots.size(); + else + splitAmount = 1; + + it.first->setStack(m_draggedStack.item().stringID(), it.second.amount() + splitAmount); + it.first->update(); + } + + if (m_isLeftClickDrag) + setStack(m_draggedStack.item().stringID(), m_draggedStack.amount() % m_draggedSlots.size()); + else + setStack(m_draggedStack.item().stringID(), m_draggedStack.amount() - m_draggedSlots.size()); + } + } else if (event.type == SDL_MOUSEBUTTONDOWN) { updatePosition(event.button.x, event.button.y); + + if (getStack().amount() == 0) { + if (event.button.button == SDL_BUTTON_LEFT) { + leftClickBehaviour(); + } + else if (event.button.button == SDL_BUTTON_RIGHT) { + rightClickBehaviour(); + } + + m_isDragging = false; + } + else { + m_isDragging = true; + m_isLeftClickDrag = event.button.button == SDL_BUTTON_LEFT; + m_draggedStack = getStack(); + + if (m_currentItemWidget && (m_currentItemWidget->stack().amount() == 0 || m_currentItemWidget->stack().item().stringID() == m_draggedStack.item().stringID())) + m_draggedSlots[m_currentItemWidget] = m_currentItemWidget->stack(); + } + } + else if (event.type == SDL_MOUSEBUTTONUP) { + updatePosition(event.button.x, event.button.y); + + if (m_isDragging && m_draggedSlots.size() == 1) { + if (event.button.button == SDL_BUTTON_LEFT) { + leftClickBehaviour(); + } + else if (event.button.button == SDL_BUTTON_RIGHT) { + rightClickBehaviour(); + } + } + + m_isDragging = false; + + for (auto &it : m_draggedSlots) + it.first->setChanged(true); + + m_draggedSlots.clear(); } } -void MouseItemWidget::updateCurrentItem(const ItemWidget *currentItemWidget) { +void MouseItemWidget::leftClickBehaviour() { + if (m_currentInventoryWidget && m_currentInventoryWidget->currentItemWidget() && m_currentInventoryWidget->inventory()) { + ItemWidget *currentItemWidget = m_currentInventoryWidget->currentItemWidget(); + if (!m_currentInventoryWidget->inventory()->isUnlimited()) + swapItems(*currentItemWidget, m_currentInventoryWidget->isReadOnly()); + else if (getStack().amount() == 0 && currentItemWidget->stack().amount() != 0) + setStack(currentItemWidget->stack().item().stringID(), 64); + + m_currentInventoryWidget->sendUpdatePacket(); + } +} + +void MouseItemWidget::rightClickBehaviour() { + if (m_currentInventoryWidget && m_currentInventoryWidget->currentItemWidget() && m_currentInventoryWidget->inventory()) { + if (!m_currentInventoryWidget->isReadOnly()) { + ItemWidget *currentItemWidget = m_currentInventoryWidget->currentItemWidget(); + if (!m_currentInventoryWidget->inventory()->isUnlimited()) + putItem(*currentItemWidget); + else if (getStack().amount() == 0 && currentItemWidget->stack().amount() != 0) + setStack(currentItemWidget->stack().item().stringID(), 1); + + m_currentInventoryWidget->sendUpdatePacket(); + } + } +} + +void MouseItemWidget::updateCurrentItem(ItemWidget *currentItemWidget) { if (currentItemWidget) { + if (m_isDragging && (currentItemWidget->stack().amount() == 0 || currentItemWidget->stack().item().stringID() == m_draggedStack.item().stringID())) { + auto it = m_draggedSlots.find(currentItemWidget); + if (it == m_draggedSlots.end()) { + m_draggedSlots.emplace(std::make_pair(currentItemWidget, currentItemWidget->stack())); + } + } + m_currentItemWidget = (currentItemWidget->stack().item().id()) ? currentItemWidget : nullptr; m_tooltipText.setText(currentItemWidget->stack().item().label() + " [" + std::to_string(currentItemWidget->stack().item().id()) + "]"); @@ -101,7 +190,8 @@ void MouseItemWidget::putItem(ItemWidget &widget) { } void MouseItemWidget::draw(gk::RenderTarget &target, gk::RenderStates states) const { - ItemWidget::draw(target, states); + if (getStack().amount() > 0) + ItemWidget::draw(target, states); states.transform *= getTransform(); diff --git a/client/source/gui/MouseItemWidget.hpp b/client/source/gui/MouseItemWidget.hpp index d118f59ca..cb4350f72 100644 --- a/client/source/gui/MouseItemWidget.hpp +++ b/client/source/gui/MouseItemWidget.hpp @@ -32,18 +32,25 @@ #include "ItemWidget.hpp" #include "Text.hpp" +class InventoryWidget; + class MouseItemWidget : public ItemWidget { public: MouseItemWidget(Widget *parent); void onEvent(const SDL_Event &event) override; + void leftClickBehaviour(); + void rightClickBehaviour(); + const ItemWidget *currentItemWidget() const { return m_currentItemWidget; } - void updateCurrentItem(const ItemWidget *currentItemWidget); + void updateCurrentItem(ItemWidget *currentItemWidget); void swapItems(ItemWidget &widget, bool isReadOnly = false); void putItem(ItemWidget &widget); + void setCurrentInventoryWidget(InventoryWidget *inventoryWidget) { m_currentInventoryWidget = inventoryWidget; } + const ItemStack &getStack() const { return m_inventory.getStack(0, 0); } private: @@ -53,11 +60,17 @@ class MouseItemWidget : public ItemWidget { Inventory m_inventory{1, 1}; - const ItemWidget *m_currentItemWidget = nullptr; + ItemWidget *m_currentItemWidget = nullptr; + InventoryWidget *m_currentInventoryWidget = nullptr; gk::Sprite m_tooltipBackground{"texture-toasts", 160, 32}; Text m_tooltipText; Text m_tooltipInfoText; + + bool m_isDragging = false; + bool m_isLeftClickDrag = false; + std::unordered_map m_draggedSlots; + ItemStack m_draggedStack; }; #endif // MOUSEITEMWIDGET_HPP_ diff --git a/client/source/states/LuaGUIState.cpp b/client/source/states/LuaGUIState.cpp index 79f9d02bf..047a1ad73 100644 --- a/client/source/states/LuaGUIState.cpp +++ b/client/source/states/LuaGUIState.cpp @@ -98,10 +98,10 @@ void LuaGUIState::onEvent(const SDL_Event &event) { } else { for (auto &it : m_inventoryWidgets) - it.second.onMouseEvent(event, m_mouseItemWidget, false); + it.second.onEvent(event); for (auto &it : m_craftingWidgets) - it.second.onMouseEvent(event, m_mouseItemWidget); + it.second.onEvent(event); m_mouseItemWidget.onEvent(event); } @@ -121,7 +121,7 @@ void LuaGUIState::update() { it.second.update(); } - const ItemWidget *currentItemWidget = nullptr; + ItemWidget *currentItemWidget = nullptr; m_currentInventoryWidget = nullptr; for (auto &it : m_inventoryWidgets) { if (!currentItemWidget && ((currentItemWidget = it.second.currentItemWidget()))) { @@ -130,11 +130,12 @@ void LuaGUIState::update() { } for (auto &it : m_craftingWidgets) { if (!currentItemWidget && ((currentItemWidget = it.second.currentItemWidget()))) { - m_currentInventoryWidget = &it.second; + m_currentInventoryWidget = it.second.currentInventoryWidget(); } } m_mouseItemWidget.updateCurrentItem(currentItemWidget); + m_mouseItemWidget.setCurrentInventoryWidget(m_currentInventoryWidget); } void LuaGUIState::draw(gk::RenderTarget &target, gk::RenderStates states) const { @@ -243,7 +244,7 @@ void LuaGUIState::loadInventoryWidget(const std::string &name, s32 x, s32 y, sf: } if (widgetInventory) { - m_inventoryWidgets.emplace(name, InventoryWidget{m_client, &m_mainWidget}); + m_inventoryWidgets.emplace(name, InventoryWidget{m_client, false, &m_mainWidget}); auto &inventoryWidget = m_inventoryWidgets.at(name); inventoryWidget.setPosition(x, y); @@ -282,10 +283,10 @@ void LuaGUIState::loadCraftingWidget(const std::string &name, s32 x, s32 y, sf:: m_craftingWidgets.emplace(name, CraftingWidget{m_client, *craftingInventory, &m_mainWidget}); auto &craftingWidget = m_craftingWidgets.at(name); + craftingWidget.setShiftDestination(shiftDestination); craftingWidget.init(offset, size); craftingWidget.craftingInventoryWidget().setPosition(x, y); craftingWidget.craftingResultInventoryWidget().setPosition(resultX, resultY); - craftingWidget.setShiftDestination(shiftDestination); } else { DEBUG("ERROR: Crafting inventory is invalid"); diff --git a/client/source/states/LuaGUIState.hpp b/client/source/states/LuaGUIState.hpp index ef22c8852..a27888b76 100644 --- a/client/source/states/LuaGUIState.hpp +++ b/client/source/states/LuaGUIState.hpp @@ -64,7 +64,7 @@ class LuaGUIState : public InterfaceState { Widget m_mainWidget; MouseItemWidget m_mouseItemWidget{&m_mainWidget}; - AbstractInventoryWidget *m_currentInventoryWidget = nullptr; + InventoryWidget *m_currentInventoryWidget = nullptr; std::unordered_map m_craftingWidgets; std::unordered_map m_inventoryWidgets; diff --git a/mods/default/init.lua b/mods/default/init.lua index 9c341f04f..4f5329a92 100644 --- a/mods/default/init.lua +++ b/mods/default/init.lua @@ -98,7 +98,7 @@ function show_inventory(client, screen_width, screen_height, gui_scale) offset = 9, count = 9 * 3, - shift_destination = "inv_hotbar", + shift_destination = "inv_hotbar,inv_main", } gui:inventory { @@ -112,7 +112,7 @@ function show_inventory(client, screen_width, screen_height, gui_scale) offset = 0, count = 9, - shift_destination = "inv_main", + shift_destination = "inv_main,inv_hotbar", } gui:crafting {