From f1d3978897b0e89f6f8f70128494c847d434d09c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 May 2012 01:14:33 +0200 Subject: [PATCH] Issue #290: Auto-Close MW-reference related GUI windows --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 4 +-- apps/openmw/mwgui/alchemywindow.hpp | 2 ++ apps/openmw/mwgui/container.cpp | 27 ++++++++++-------- apps/openmw/mwgui/container.hpp | 16 +++++------ apps/openmw/mwgui/dialogue.cpp | 9 ++++-- apps/openmw/mwgui/dialogue.hpp | 7 +++-- apps/openmw/mwgui/inventorywindow.cpp | 8 +++--- apps/openmw/mwgui/inventorywindow.hpp | 2 ++ apps/openmw/mwgui/referenceinterface.cpp | 28 +++++++++++++++++++ apps/openmw/mwgui/referenceinterface.hpp | 29 ++++++++++++++++++++ apps/openmw/mwgui/tradewindow.cpp | 35 ++++++++++++++---------- apps/openmw/mwgui/tradewindow.hpp | 2 ++ apps/openmw/mwgui/window_manager.cpp | 18 ++++++++++++ apps/openmw/mwgui/window_manager.hpp | 1 + 15 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 apps/openmw/mwgui/referenceinterface.cpp create mode 100644 apps/openmw/mwgui/referenceinterface.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ac3882714..edbeab0a1 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -28,7 +28,7 @@ add_openmw_dir (mwgui dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow - confirmationdialog alchemywindow + confirmationdialog alchemywindow referenceinterface ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 4fdd6588f..50d209524 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -171,7 +171,7 @@ namespace MWGui // create a reference and add it to player inventory MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), result.first); - MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); ref.getPtr().getRefData().setCount(1); store.add(ref.getPtr()); @@ -223,7 +223,7 @@ namespace MWGui setFilter(ContainerBase::Filter_Ingredients); // pick the best available apparatus - MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::Ptr bestAlbemic; MWWorld::Ptr bestMortarPestle; diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index e75597bcd..c01a18e41 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -42,6 +42,8 @@ namespace MWGui void removeIngredient(MyGUI::Widget* ingredient); + virtual void onReferenceUnavailable() { ; } + void update(); }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6aabeb2c6..1cfbc1b2b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -264,16 +264,16 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); if (mDragAndDrop->mDraggedFrom != this) { assert(object.getContainerStore() && "Item is not in a container!"); // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside - if (mContainer.getTypeName() == typeid(ESM::Container).name()) + if (mPtr.getTypeName() == typeid(ESM::Container).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->flags & ESM::Container::Organic) { // user notification @@ -288,13 +288,13 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) // check that we don't exceed the allowed weight (only for containers, not for inventory) if (!isInventory()) { - float capacity = MWWorld::Class::get(mContainer).getCapacity(mContainer); + float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); // try adding the item, and if weight is exceeded, just remove it again. object.getRefData().setCount(mDragAndDrop->mDraggedCount); MWWorld::ContainerStoreIterator it = containerStore.add(object); - float curWeight = MWWorld::Class::get(mContainer).getEncumbrance(mContainer); + float curWeight = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); if (curWeight > capacity) { it->getRefData().setCount(0); @@ -346,7 +346,7 @@ void ContainerBase::setFilter(ContainerBase::Filter filter) void ContainerBase::openContainer(MWWorld::Ptr container) { - mContainer = container; + mPtr = container; drawItems(); } @@ -356,7 +356,7 @@ void ContainerBase::drawItems() { MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); int x = 0; int y = 0; @@ -557,7 +557,7 @@ void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) void ContainerBase::addItem(MWWorld::Ptr item, int count) { - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); int origCount = item.getRefData().getCount(); @@ -569,7 +569,7 @@ void ContainerBase::addItem(MWWorld::Ptr item, int count) void ContainerBase::transferBoughtItems() { - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) { @@ -587,7 +587,7 @@ void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) MWWorld::ContainerStore& ContainerBase::getContainerStore() { - MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); return store; } @@ -651,7 +651,7 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { // transfer everything into the player's inventory - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); @@ -676,3 +676,8 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getWindowManager()->popGuiMode(); } } + +void ContainerWindow::onReferenceUnavailable() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); +} diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 26e78149a..5cd8167c2 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -2,15 +2,14 @@ #define MGUI_CONTAINER_H #include -#include "../mwclass/container.hpp" -#include -#include -#include -#include + #include "window_base.hpp" +#include "referenceinterface.hpp" + +#include "../mwclass/container.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" -#include + namespace MWWorld { @@ -43,7 +42,7 @@ namespace MWGui int mDraggedCount; }; - class ContainerBase + class ContainerBase : public ReferenceInterface { public: ContainerBase(DragAndDrop* dragAndDrop); @@ -89,7 +88,6 @@ namespace MWGui MyGUI::Widget* mSelectedItem; DragAndDrop* mDragAndDrop; - MWWorld::Ptr mContainer; Filter mFilter; @@ -140,6 +138,8 @@ namespace MWGui void onWindowResize(MyGUI::Window* window); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); + + virtual void onReferenceUnavailable(); }; } #endif // CONTAINER_H diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a68ff666..ce687424c 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -125,7 +125,7 @@ void DialogueWindow::onSelectTopic(std::string topic) { /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mActor); + mWindowManager.getTradeWindow()->startTrade(mPtr); } else @@ -135,7 +135,7 @@ void DialogueWindow::onSelectTopic(std::string topic) void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { mEnabled = true; - mActor = actor; + mPtr = actor; topicsList->setEnabled(true); setTitle(npcName); @@ -260,3 +260,8 @@ void DialogueWindow::goodbye() topicsList->setEnabled(false); mEnabled = false; } + +void DialogueWindow::onReferenceUnavailable() +{ + mWindowManager.removeGuiMode(GM_Dialogue); +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index d3106ad38..8e9aba003 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -2,6 +2,7 @@ #define MWGUI_DIALOGE_H #include "window_base.hpp" +#include "referenceinterface.hpp" #include #include "../mwworld/ptr.hpp" @@ -25,7 +26,7 @@ namespace MWGui { class DialogueHistory; - class DialogueWindow: public WindowBase + class DialogueWindow: public WindowBase, public ReferenceInterface { public: DialogueWindow(WindowManager& parWindowManager); @@ -58,6 +59,8 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onWindowResize(MyGUI::Window* _sender); + virtual void onReferenceUnavailable(); + private: void updateOptions(); /** @@ -70,8 +73,6 @@ namespace MWGui bool mEnabled; - MWWorld::Ptr mActor; // actor being talked to - DialogueHistory* history; Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 04a30b69b..2b224ab2c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -155,7 +155,7 @@ namespace MWGui if (mDragAndDrop->mDraggedFrom != this) { // add item to the player's inventory - MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::ContainerStoreIterator it = invStore.begin(); int origCount = ptr.getRefData().getCount(); @@ -192,7 +192,7 @@ namespace MWGui std::vector InventoryWindow::getEquippedItems() { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); std::vector items; @@ -210,7 +210,7 @@ namespace MWGui void InventoryWindow::_unequipItem(MWWorld::Ptr item) { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { @@ -244,7 +244,7 @@ namespace MWGui int InventoryWindow::getPlayerGold() { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 86f7ee3c7..ecff75f10 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -48,6 +48,8 @@ namespace MWGui virtual bool isInventory() { return true; } virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item); + + virtual void onReferenceUnavailable() { ; } }; } diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp new file mode 100644 index 000000000..c6e710952 --- /dev/null +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -0,0 +1,28 @@ +#include "referenceinterface.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" + +namespace MWGui +{ + ReferenceInterface::ReferenceInterface() + : mCurrentPlayerCell(NULL) + { + } + + void ReferenceInterface::checkReferenceAvailable() + { + if (mPtr.isEmpty()) + return; + + MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + + // check if player has changed cell, or count of the reference has become 0 + if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) + || mPtr.getRefData().getCount() == 0) + onReferenceUnavailable(); + + mCurrentPlayerCell = playerCell; + } +} diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp new file mode 100644 index 000000000..40844b238 --- /dev/null +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -0,0 +1,29 @@ +#ifndef MWGUI_REFERENCEINTERFACE_H +#define MWGUI_REFERENCEINTERFACE_H + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + /// \brief this class is intended for GUI interfaces that access an MW-Reference + /// for example dialogue window accesses an NPC, or Container window accesses a Container + /// these classes have to be automatically closed if the reference becomes unavailable + /// make sure that checkReferenceAvailable() is called every frame and that onReferenceUnavailable() has been overridden + class ReferenceInterface + { + public: + ReferenceInterface(); + + void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable + + protected: + virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable + + MWWorld::Ptr mPtr; + + private: + MWWorld::Ptr::CellStore* mCurrentPlayerCell; + }; +} + +#endif diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 311ea6c95..0a12a82a0 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -157,9 +157,9 @@ namespace MWGui // check if the merchant can afford this int merchantgold; - if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->npdt52.gold == -10) merchantgold = ref->base->npdt12.gold; else @@ -167,7 +167,7 @@ namespace MWGui } else // ESM::Creature { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); merchantgold = ref->base->data.gold; } if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) @@ -218,7 +218,7 @@ namespace MWGui // i give you back your stuff! returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); // now gimme back my stuff! - mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); mWindowManager.popGuiMode(); } @@ -240,9 +240,9 @@ namespace MWGui } int merchantgold; - if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->npdt52.gold == -10) merchantgold = ref->base->npdt12.gold; else @@ -250,7 +250,7 @@ namespace MWGui } else // ESM::Creature { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); merchantgold = ref->base->data.gold; } @@ -262,13 +262,13 @@ namespace MWGui { std::vector items; - if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + if (mPtr.getTypeName() == typeid(ESM::Creature).name()) { // creatures don't have equipment slots. return items; } - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { @@ -285,15 +285,15 @@ namespace MWGui bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) { int services = 0; - if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->hasAI) services = ref->base->AI.services; } - else if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->hasAI) services = ref->base->AI.services; } @@ -327,7 +327,7 @@ namespace MWGui std::vector TradeWindow::itemsToIgnore() { std::vector items; - MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) @@ -356,4 +356,11 @@ namespace MWGui updateLabels(); } + + void TradeWindow::onReferenceUnavailable() + { + // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) + mWindowManager.removeGuiMode(GM_Barter); + mWindowManager.removeGuiMode(GM_Dialogue); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 8da96d37e..b391fd8fa 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -69,6 +69,8 @@ namespace MWGui virtual std::vector itemsToIgnore(); void updateLabels(); + + virtual void onReferenceUnavailable(); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index acd0b089f..a6d236136 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -472,6 +472,10 @@ void WindowManager::onFrame (float frameDuration) mStatsWindow->onFrame(); hud->onFrame(frameDuration); + + mDialogueWindow->checkReferenceAvailable(); + mTradeWindow->checkReferenceAvailable(); + mContainerWindow->checkReferenceAvailable(); } const ESMS::ESMStore& WindowManager::getStore() const @@ -626,3 +630,17 @@ void WindowManager::popGuiMode() updateVisible(); } + +void WindowManager::removeGuiMode(GuiMode mode) +{ + std::vector::iterator it = mGuiModes.begin(); + while (it != mGuiModes.end()) + { + if (*it == mode) + it = mGuiModes.erase(it); + else + ++it; + } + + updateVisible(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index df32547fc..7082cc0bc 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -109,6 +109,7 @@ namespace MWGui void pushGuiMode(GuiMode mode); void popGuiMode(); + void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack GuiMode getMode() const {