Merge branch 'updateinventory' into 'master'
Some checks are pending
Build and test / Windows (2019) (push) Blocked by required conditions
Build and test / Windows (2022) (push) Blocked by required conditions
Build and test / Ubuntu (push) Waiting to run
Build and test / MacOS (push) Waiting to run
Build and test / Read .env file and expose it as output (push) Waiting to run

Update inventory window when item is added or removed into container by script

Closes #8431

See merge request OpenMW/openmw!4609
This commit is contained in:
Kuyondo 2025-04-28 09:46:58 +00:00
commit 513954936e
12 changed files with 193 additions and 38 deletions

View file

@ -43,6 +43,7 @@ namespace MWGui
, mSortModel(nullptr) , mSortModel(nullptr)
, mModel(nullptr) , mModel(nullptr)
, mSelectedItem(-1) , mSelectedItem(-1)
, mUpdateNextFrame(false)
, mDragAndDrop(dragAndDrop) , mDragAndDrop(dragAndDrop)
, mMessageBoxManager(manager) , mMessageBoxManager(manager)
{ {
@ -134,12 +135,20 @@ namespace MWGui
mItemView->resetScrollBars(); mItemView->resetScrollBars();
setTitle(actor.getClass().getName(actor)); setTitle(actor.getClass().getName(actor));
mPtr.getClass().getContainerStore(mPtr).setContListener(this);
} }
void CompanionWindow::onFrame(float dt) void CompanionWindow::onFrame(float dt)
{ {
checkReferenceAvailable(); checkReferenceAvailable();
updateEncumbranceBar();
if (mUpdateNextFrame)
{
updateEncumbranceBar();
mItemView->update();
mUpdateNextFrame = false;
}
} }
void CompanionWindow::updateEncumbranceBar() void CompanionWindow::updateEncumbranceBar()
@ -202,4 +211,13 @@ namespace MWGui
mSortModel = nullptr; mSortModel = nullptr;
} }
void CompanionWindow::itemAdded(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
void CompanionWindow::itemRemoved(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
} }

View file

@ -4,6 +4,8 @@
#include "referenceinterface.hpp" #include "referenceinterface.hpp"
#include "windowbase.hpp" #include "windowbase.hpp"
#include "../mwworld/containerstore.hpp"
namespace MWGui namespace MWGui
{ {
namespace Widgets namespace Widgets
@ -17,7 +19,7 @@ namespace MWGui
class SortFilterItemModel; class SortFilterItemModel;
class CompanionItemModel; class CompanionItemModel;
class CompanionWindow : public WindowBase, public ReferenceInterface class CompanionWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener
{ {
public: public:
CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager);
@ -30,6 +32,9 @@ namespace MWGui
void onFrame(float dt) override; void onFrame(float dt) override;
void clear() override { resetReference(); } void clear() override { resetReference(); }
void itemAdded(const MWWorld::ConstPtr& item, int count) override;
void itemRemoved(const MWWorld::ConstPtr& item, int count) override;
std::string_view getWindowIdForLua() const override { return "Companion"; } std::string_view getWindowIdForLua() const override { return "Companion"; }
private: private:
@ -37,6 +42,7 @@ namespace MWGui
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
CompanionItemModel* mModel; CompanionItemModel* mModel;
int mSelectedItem; int mSelectedItem;
bool mUpdateNextFrame;
DragAndDrop* mDragAndDrop; DragAndDrop* mDragAndDrop;

View file

@ -38,6 +38,7 @@ namespace MWGui
, mSortModel(nullptr) , mSortModel(nullptr)
, mModel(nullptr) , mModel(nullptr)
, mSelectedItem(-1) , mSelectedItem(-1)
, mUpdateNextFrame(false)
, mTreatNextOpenAsLoot(false) , mTreatNextOpenAsLoot(false)
{ {
getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
@ -160,6 +161,8 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
setTitle(container.getClass().getName(container)); setTitle(container.getClass().getName(container));
mPtr.getClass().getContainerStore(mPtr).setContListener(this);
} }
void ContainerWindow::resetReference() void ContainerWindow::resetReference()
@ -320,4 +323,25 @@ namespace MWGui
if (mModel && mModel->usesContainer(ptr)) if (mModel && mModel->usesContainer(ptr))
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
} }
void ContainerWindow::onFrame(float dt)
{
checkReferenceAvailable();
if (mUpdateNextFrame)
{
mItemView->update();
mUpdateNextFrame = false;
}
}
void ContainerWindow::itemAdded(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
void ContainerWindow::itemRemoved(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
} }

View file

@ -6,6 +6,8 @@
#include "itemmodel.hpp" #include "itemmodel.hpp"
#include "../mwworld/containerstore.hpp"
namespace MyGUI namespace MyGUI
{ {
class Gui; class Gui;
@ -21,7 +23,7 @@ namespace MWGui
namespace MWGui namespace MWGui
{ {
class ContainerWindow : public WindowBase, public ReferenceInterface class ContainerWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener
{ {
public: public:
ContainerWindow(DragAndDrop* dragAndDrop); ContainerWindow(DragAndDrop* dragAndDrop);
@ -30,7 +32,7 @@ namespace MWGui
void onClose() override; void onClose() override;
void clear() override { resetReference(); } void clear() override { resetReference(); }
void onFrame(float dt) override { checkReferenceAvailable(); } void onFrame(float dt) override;
void resetReference() override; void resetReference() override;
@ -38,6 +40,9 @@ namespace MWGui
void treatNextOpenAsLoot() { mTreatNextOpenAsLoot = true; } void treatNextOpenAsLoot() { mTreatNextOpenAsLoot = true; }
void itemAdded(const MWWorld::ConstPtr& item, int count) override;
void itemRemoved(const MWWorld::ConstPtr& item, int count) override;
std::string_view getWindowIdForLua() const override { return "Container"; } std::string_view getWindowIdForLua() const override { return "Container"; }
private: private:
@ -47,6 +52,7 @@ namespace MWGui
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
ItemModel* mModel; ItemModel* mModel;
int mSelectedItem; int mSelectedItem;
bool mUpdateNextFrame;
bool mTreatNextOpenAsLoot; bool mTreatNextOpenAsLoot;
MyGUI::Button* mDisposeCorpseButton; MyGUI::Button* mDisposeCorpseButton;
MyGUI::Button* mTakeButton; MyGUI::Button* mTakeButton;

View file

@ -11,7 +11,6 @@
#include "controllers.hpp" #include "controllers.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
#include "itemview.hpp" #include "itemview.hpp"
#include "itemwidget.hpp"
#include "sortfilteritemmodel.hpp" #include "sortfilteritemmodel.hpp"
namespace MWGui namespace MWGui
@ -72,25 +71,25 @@ namespace MWGui
mSourceSortModel->addDragItem(mItem.mBase, count); mSourceSortModel->addDragItem(mItem.mBase, count);
} }
ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget<ItemWidget>( mDraggedWidget = MyGUI::Gui::getInstance().createWidget<ItemWidget>(
"MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); "MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop");
Controllers::ControllerFollowMouse* controller Controllers::ControllerFollowMouse* controller
= MyGUI::ControllerManager::getInstance() = MyGUI::ControllerManager::getInstance()
.createItem(Controllers::ControllerFollowMouse::getClassTypeName()) .createItem(Controllers::ControllerFollowMouse::getClassTypeName())
->castType<Controllers::ControllerFollowMouse>(); ->castType<Controllers::ControllerFollowMouse>();
MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); MyGUI::ControllerManager::getInstance().addItem(mDraggedWidget, controller);
mDraggedWidget = baseWidget; mDraggedWidget->setItem(mItem.mBase);
baseWidget->setItem(mItem.mBase); mDraggedWidget->setNeedMouseFocus(false);
baseWidget->setNeedMouseFocus(false); mDraggedWidget->setCount(count);
baseWidget->setCount(count);
sourceView->update();
MWBase::Environment::get().getWindowManager()->setDragDrop(true); MWBase::Environment::get().getWindowManager()->setDragDrop(true);
mIsOnDragAndDrop = true; mIsOnDragAndDrop = true;
// Update item view after completing drag-and-drop setup
mSourceView->update();
} }
void DragAndDrop::drop(ItemModel* targetModel, ItemView* targetView) void DragAndDrop::drop(ItemModel* targetModel, ItemView* targetView)
@ -124,6 +123,22 @@ namespace MWGui
mSourceView->update(); mSourceView->update();
} }
void DragAndDrop::update()
{
if (mIsOnDragAndDrop)
{
int count = mItem.mBase.getCellRef().getCount();
if (count < mDraggedCount)
{
mItem.mCount = count;
mDraggedCount = count;
mDraggedWidget->setCount(mDraggedCount);
mSourceSortModel->clearDragItems();
mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount);
}
}
}
void DragAndDrop::onFrame() void DragAndDrop::onFrame()
{ {
if (mIsOnDragAndDrop && mItem.mBase.getCellRef().getCount() == 0) if (mIsOnDragAndDrop && mItem.mBase.getCellRef().getCount() == 0)
@ -137,8 +152,12 @@ namespace MWGui
// since mSourceView doesn't get updated in drag() // since mSourceView doesn't get updated in drag()
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); if (mDraggedWidget)
mDraggedWidget = nullptr; {
MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget);
mDraggedWidget = nullptr;
}
MWBase::Environment::get().getWindowManager()->setDragDrop(false); MWBase::Environment::get().getWindowManager()->setDragDrop(false);
} }

View file

@ -2,6 +2,7 @@
#define OPENMW_MWGUI_DRAGANDDROP_H #define OPENMW_MWGUI_DRAGANDDROP_H
#include "itemmodel.hpp" #include "itemmodel.hpp"
#include "itemwidget.hpp"
namespace MyGUI namespace MyGUI
{ {
@ -18,7 +19,7 @@ namespace MWGui
{ {
public: public:
bool mIsOnDragAndDrop; bool mIsOnDragAndDrop;
MyGUI::Widget* mDraggedWidget; ItemWidget* mDraggedWidget;
ItemModel* mSourceModel; ItemModel* mSourceModel;
ItemView* mSourceView; ItemView* mSourceView;
SortFilterItemModel* mSourceSortModel; SortFilterItemModel* mSourceSortModel;
@ -30,6 +31,7 @@ namespace MWGui
void startDrag( void startDrag(
int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count);
void drop(ItemModel* targetModel, ItemView* targetView); void drop(ItemModel* targetModel, ItemView* targetView);
void update();
void onFrame(); void onFrame();
void finish(); void finish();

View file

@ -86,7 +86,7 @@ namespace MWGui
, mLastYSize(0) , mLastYSize(0)
, mPreview(std::make_unique<MWRender::InventoryPreview>(parent, resourceSystem, MWMechanics::getPlayer())) , mPreview(std::make_unique<MWRender::InventoryPreview>(parent, resourceSystem, MWMechanics::getPlayer()))
, mTrading(false) , mTrading(false)
, mUpdateTimer(0.f) , mUpdateNextFrame(false)
{ {
mPreviewTexture mPreviewTexture
= std::make_unique<osgMyGUI::OSGTexture>(mPreview->getTexture(), mPreview->getTextureStateSet()); = std::make_unique<osgMyGUI::OSGTexture>(mPreview->getTexture(), mPreview->getTextureStateSet());
@ -145,6 +145,8 @@ namespace MWGui
auto tradeModel = std::make_unique<TradeItemModel>(std::make_unique<InventoryItemModel>(mPtr), MWWorld::Ptr()); auto tradeModel = std::make_unique<TradeItemModel>(std::make_unique<InventoryItemModel>(mPtr), MWWorld::Ptr());
mTradeModel = tradeModel.get(); mTradeModel = tradeModel.get();
mPtr.getClass().getInventoryStore(mPtr).setContListener(this);
if (mSortModel) // reuse existing SortModel when possible to keep previous category/filter settings if (mSortModel) // reuse existing SortModel when possible to keep previous category/filter settings
mSortModel->setSourceModel(std::move(tradeModel)); mSortModel->setSourceModel(std::move(tradeModel));
else else
@ -681,22 +683,21 @@ namespace MWGui
void InventoryWindow::onFrame(float dt) void InventoryWindow::onFrame(float dt)
{ {
updateEncumbranceBar(); if (mUpdateNextFrame)
if (mPinned)
{ {
mUpdateTimer += dt; if (mTrading)
if (0.1f < mUpdateTimer)
{ {
mUpdateTimer = 0; mTradeModel->updateBorrowed();
MWBase::Environment::get().getWindowManager()->getTradeWindow()->mTradeModel->updateBorrowed();
// Update pinned inventory in-game MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateItemView();
if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateOffer();
{
mItemView->update();
notifyContentChanged();
}
} }
updateEncumbranceBar();
mDragAndDrop->update();
mItemView->update();
notifyContentChanged();
mUpdateNextFrame = false;
} }
} }
@ -848,6 +849,16 @@ namespace MWGui
mPreview->rebuild(); mPreview->rebuild();
} }
void InventoryWindow::itemAdded(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
void InventoryWindow::itemRemoved(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
MyGUI::IntSize InventoryWindow::getPreviewViewportSize() const MyGUI::IntSize InventoryWindow::getPreviewViewportSize() const
{ {
const MyGUI::IntSize previewWindowSize = mAvatarImage->getSize(); const MyGUI::IntSize previewWindowSize = mAvatarImage->getSize();

View file

@ -5,6 +5,7 @@
#include "windowpinnablebase.hpp" #include "windowpinnablebase.hpp"
#include "../mwrender/characterpreview.hpp" #include "../mwrender/characterpreview.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
namespace osg namespace osg
@ -30,7 +31,7 @@ namespace MWGui
class DragAndDrop; class DragAndDrop;
class ItemModel; class ItemModel;
class InventoryWindow : public WindowPinnableBase class InventoryWindow : public WindowPinnableBase, public MWWorld::ContainerStoreListener
{ {
public: public:
InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem);
@ -62,6 +63,9 @@ namespace MWGui
void setGuiMode(GuiMode mode); void setGuiMode(GuiMode mode);
void itemAdded(const MWWorld::ConstPtr& item, int count) override;
void itemRemoved(const MWWorld::ConstPtr& item, int count) override;
/// Cycle to previous/next weapon /// Cycle to previous/next weapon
void cycle(bool next); void cycle(bool next);
@ -107,7 +111,7 @@ namespace MWGui
std::unique_ptr<MWRender::InventoryPreview> mPreview; std::unique_ptr<MWRender::InventoryPreview> mPreview;
bool mTrading; bool mTrading;
float mUpdateTimer; bool mUpdateNextFrame;
void toggleMaximized(); void toggleMaximized();

View file

@ -113,6 +113,25 @@ namespace MWGui
encumbrance = std::max(0.f, encumbrance); encumbrance = std::max(0.f, encumbrance);
} }
void TradeItemModel::updateBorrowed()
{
auto update = [](std::vector<ItemStack>& list) {
for (auto it = list.begin(); it != list.end();)
{
size_t actualCount = it->mBase.getCellRef().getCount();
if (actualCount < it->mCount)
it->mCount = actualCount;
if (it->mCount == 0)
it = list.erase(it);
else
++it;
}
};
update(mBorrowedFromUs);
update(mBorrowedToUs);
}
void TradeItemModel::abort() void TradeItemModel::abort()
{ {
mBorrowedFromUs.clear(); mBorrowedFromUs.clear();

View file

@ -31,6 +31,9 @@ namespace MWGui
void returnItemBorrowedFromUs(ModelIndex itemIndex, ItemModel* source, size_t count); void returnItemBorrowedFromUs(ModelIndex itemIndex, ItemModel* source, size_t count);
/// Update borrowed items in this model
void updateBorrowed();
/// Permanently transfers items that were borrowed to us from another model to this model /// Permanently transfers items that were borrowed to us from another model to this model
void transferItems(); void transferItems();
/// Aborts trade /// Aborts trade

View file

@ -123,6 +123,7 @@ namespace MWGui
, mItemToSell(-1) , mItemToSell(-1)
, mCurrentBalance(0) , mCurrentBalance(0)
, mCurrentMerchantOffer(0) , mCurrentMerchantOffer(0)
, mUpdateNextFrame(false)
{ {
getWidget(mFilterAll, "AllButton"); getWidget(mFilterAll, "AllButton");
getWidget(mFilterWeapon, "WeaponButton"); getWidget(mFilterWeapon, "WeaponButton");
@ -201,11 +202,27 @@ namespace MWGui
onFilterChanged(mFilterAll); onFilterChanged(mFilterAll);
mFilterEdit->setCaption({}); mFilterEdit->setCaption({});
for (const auto& source : itemSources)
source.getClass().getContainerStore(source).setContListener(this);
} }
void TradeWindow::onFrame(float dt) void TradeWindow::onFrame(float dt)
{ {
checkReferenceAvailable(); checkReferenceAvailable();
if (mUpdateNextFrame)
{
if (isVisible())
{
mTradeModel->updateBorrowed();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->updateBorrowed();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
mItemView->update();
updateOffer();
}
mUpdateNextFrame = false;
}
} }
void TradeWindow::onNameFilterChanged(MyGUI::EditBox* _sender) void TradeWindow::onNameFilterChanged(MyGUI::EditBox* _sender)
@ -643,4 +660,19 @@ namespace MWGui
if (mTradeModel && mTradeModel->usesContainer(ptr)) if (mTradeModel && mTradeModel->usesContainer(ptr))
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter);
} }
void TradeWindow::updateItemView()
{
mItemView->update();
}
void TradeWindow::itemAdded(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
void TradeWindow::itemRemoved(const MWWorld::ConstPtr& item, int count)
{
mUpdateNextFrame = true;
}
} }

View file

@ -4,6 +4,8 @@
#include "referenceinterface.hpp" #include "referenceinterface.hpp"
#include "windowbase.hpp" #include "windowbase.hpp"
#include "../mwworld/containerstore.hpp"
namespace Gui namespace Gui
{ {
class NumericEditBox; class NumericEditBox;
@ -20,7 +22,7 @@ namespace MWGui
class SortFilterItemModel; class SortFilterItemModel;
class TradeItemModel; class TradeItemModel;
class TradeWindow : public WindowBase, public ReferenceInterface class TradeWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener
{ {
public: public:
TradeWindow(); TradeWindow();
@ -31,23 +33,25 @@ namespace MWGui
void onFrame(float dt) override; void onFrame(float dt) override;
void clear() override { resetReference(); } void clear() override { resetReference(); }
void borrowItem(int index, size_t count);
void returnItem(int index, size_t count);
int getMerchantServices();
bool exit() override; bool exit() override;
void resetReference() override; void resetReference() override;
void onDeleteCustomData(const MWWorld::Ptr& ptr) override; void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
void updateItemView();
void itemAdded(const MWWorld::ConstPtr& item, int count) override;
void itemRemoved(const MWWorld::ConstPtr& item, int count) override;
typedef MyGUI::delegates::MultiDelegate<> EventHandle_TradeDone; typedef MyGUI::delegates::MultiDelegate<> EventHandle_TradeDone;
EventHandle_TradeDone eventTradeDone; EventHandle_TradeDone eventTradeDone;
std::string_view getWindowIdForLua() const override { return "Trade"; } std::string_view getWindowIdForLua() const override { return "Trade"; }
private: private:
friend class InventoryWindow;
ItemView* mItemView; ItemView* mItemView;
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
TradeItemModel* mTradeModel; TradeItemModel* mTradeModel;
@ -81,6 +85,8 @@ namespace MWGui
int mCurrentBalance; int mCurrentBalance;
int mCurrentMerchantOffer; int mCurrentMerchantOffer;
bool mUpdateNextFrame;
void sellToNpc( void sellToNpc(
const MWWorld::Ptr& item, int count, bool boughtItem); ///< only used for adjusting the gold balance const MWWorld::Ptr& item, int count, bool boughtItem); ///< only used for adjusting the gold balance
void buyFromNpc( void buyFromNpc(
@ -91,6 +97,11 @@ namespace MWGui
void onItemSelected(int index); void onItemSelected(int index);
void sellItem(MyGUI::Widget* sender, int count); void sellItem(MyGUI::Widget* sender, int count);
void borrowItem(int index, size_t count);
void returnItem(int index, size_t count);
int getMerchantServices();
void onFilterChanged(MyGUI::Widget* _sender); void onFilterChanged(MyGUI::Widget* _sender);
void onNameFilterChanged(MyGUI::EditBox* _sender); void onNameFilterChanged(MyGUI::EditBox* _sender);
void onOfferButtonClicked(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender);