1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 21:49:56 +00:00
openmw-tes3mp/apps/openmw/mwgui/inventorywindow.cpp
Emanuel Guevel b2e5e8dd0d Saner inventory window pinning/hiding
Hide inventory window pin button in container, companion and barter mode.
Restore the pinned inventory window position when exiting these modes.
Allow toggling windows visibility in inventory mode only.
2013-08-07 23:30:08 +02:00

509 lines
19 KiB
C++

#include "inventorywindow.hpp"
#include <stdexcept>
#include <boost/lexical_cast.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/action.hpp"
#include "bookwindow.hpp"
#include "scrollwindow.hpp"
#include "spellwindow.hpp"
#include "itemview.hpp"
#include "inventoryitemmodel.hpp"
#include "sortfilteritemmodel.hpp"
#include "tradeitemmodel.hpp"
#include "countdialog.hpp"
#include "tradewindow.hpp"
#include "container.hpp"
namespace MWGui
{
InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop)
: WindowPinnableBase("openmw_inventory_window.layout")
, mTrading(false)
, mLastXSize(0)
, mLastYSize(0)
, mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ())
, mPreviewDirty(true)
, mDragAndDrop(dragAndDrop)
, mSelectedItem(-1)
, mPositionInventory(0, 342, 498, 258)
, mPositionContainer(0, 342, 498, 258)
, mPositionCompanion(0, 342, 498, 258)
, mPositionBarter(0, 342, 498, 258)
, mGuiMode(GM_Inventory)
{
static_cast<MyGUI::Window*>(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize);
getWidget(mAvatar, "Avatar");
getWidget(mAvatarImage, "AvatarImage");
getWidget(mEncumbranceBar, "EncumbranceBar");
getWidget(mFilterAll, "AllButton");
getWidget(mFilterWeapon, "WeaponButton");
getWidget(mFilterApparel, "ApparelButton");
getWidget(mFilterMagic, "MagicButton");
getWidget(mFilterMisc, "MiscButton");
getWidget(mLeftPane, "LeftPane");
getWidget(mRightPane, "RightPane");
getWidget(mArmorRating, "ArmorRating");
mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked);
getWidget(mItemView, "ItemView");
mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected);
mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &InventoryWindow::onBackgroundSelected);
updatePlayer();
mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterAll->setStateSelected(true);
setCoord(mPositionInventory.left, mPositionInventory.top, mPositionInventory.width, mPositionInventory.height);
onWindowResize(static_cast<MyGUI::Window*>(mMainWidget));
mPreview.setup();
}
void InventoryWindow::updatePlayer()
{
mPtr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr());
mSortModel = new SortFilterItemModel(mTradeModel);
mItemView->setModel(mSortModel);
mPreview = MWRender::InventoryPreview(mPtr);
mPreview.setup();
}
void InventoryWindow::setGuiMode(GuiMode mode)
{
mGuiMode = mode;
switch(mode) {
case GM_Container:
setPinButtonVisible(false);
mMainWidget->setCoord(mPositionContainer);
break;
case GM_Companion:
setPinButtonVisible(false);
mMainWidget->setCoord(mPositionCompanion);
break;
case GM_Barter:
setPinButtonVisible(false);
mMainWidget->setCoord(mPositionBarter);
break;
case GM_Inventory:
default:
setPinButtonVisible(true);
mMainWidget->setCoord(mPositionInventory);
break;
}
onWindowResize(static_cast<MyGUI::Window*>(mMainWidget));
}
TradeItemModel* InventoryWindow::getTradeModel()
{
return mTradeModel;
}
ItemModel* InventoryWindow::getModel()
{
return mTradeModel;
}
void InventoryWindow::onBackgroundSelected()
{
if (mDragAndDrop->mIsOnDragAndDrop)
mDragAndDrop->drop(mTradeModel, mItemView);
}
void InventoryWindow::onItemSelected (int index)
{
onItemSelectedFromSourceModel (mSortModel->mapToSource(index));
}
void InventoryWindow::onItemSelectedFromSourceModel (int index)
{
if (mDragAndDrop->mIsOnDragAndDrop)
{
mDragAndDrop->drop(mTradeModel, mItemView);
return;
}
const ItemStack& item = mTradeModel->getItem(index);
unequipItem(item.mBase);
MWWorld::Ptr object = item.mBase;
int count = item.mCount;
bool shift = MyGUI::InputManager::getInstance().isShiftPressed();
if (MyGUI::InputManager::getInstance().isControlPressed())
count = 1;
if (mTrading)
{
// check if merchant accepts item
int services = MWBase::Environment::get().getWindowManager()->getTradeWindow()->getMerchantServices();
if (!MWWorld::Class::get(object).canSell(object, services))
{
MWBase::Environment::get().getWindowManager()->
messageBox("#{sBarterDialog4}");
return;
}
}
if (count > 1 && !shift)
{
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
std::string message = mTrading ? "#{sQuanityMenuMessage01}" : "#{sTake}";
dialog->open(MWWorld::Class::get(object).getName(object), message, count);
dialog->eventOkClicked.clear();
if (mTrading)
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem);
else
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dragItem);
mSelectedItem = index;
}
else
{
mSelectedItem = index;
if (mTrading)
sellItem (NULL, count);
else
dragItem (NULL, count);
}
// item might have been unequipped
notifyContentChanged();
}
void InventoryWindow::dragItem(MyGUI::Widget* sender, int count)
{
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mTradeModel, mItemView, count);
}
void InventoryWindow::sellItem(MyGUI::Widget* sender, int count)
{
const ItemStack& item = mTradeModel->getItem(mSelectedItem);
std::string sound = MWWorld::Class::get(item.mBase).getDownSoundId(item.mBase);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
if (item.mType == ItemStack::Type_Barter)
{
// this was an item borrowed to us by the merchant
MWBase::Environment::get().getWindowManager()->getTradeWindow()->returnItem(mSelectedItem, count);
mTradeModel->returnItemBorrowedToUs(mSelectedItem, count);
}
else
{
// borrow item to the merchant
MWBase::Environment::get().getWindowManager()->getTradeWindow()->borrowItem(mSelectedItem, count);
mTradeModel->borrowItemFromUs(mSelectedItem, count);
}
mItemView->update();
}
void InventoryWindow::updateItemView()
{
mItemView->update();
mPreviewDirty = true;
}
void InventoryWindow::open()
{
updateEncumbranceBar();
mItemView->update();
notifyContentChanged();
}
void InventoryWindow::onWindowResize(MyGUI::Window* _sender)
{
const float aspect = 0.5; // fixed aspect ratio for the left pane
mLeftPane->setSize( (_sender->getSize().height-44) * aspect, _sender->getSize().height-44 );
mRightPane->setCoord( mLeftPane->getPosition().left + (_sender->getSize().height-44) * aspect + 4,
mRightPane->getPosition().top,
_sender->getSize().width - 12 - (_sender->getSize().height-44) * aspect - 15,
_sender->getSize().height-44 );
switch(mGuiMode) {
case GM_Container:
mPositionContainer = _sender->getCoord();
break;
case GM_Companion:
mPositionCompanion = _sender->getCoord();
break;
case GM_Barter:
mPositionBarter = _sender->getCoord();
break;
case GM_Inventory:
default:
mPositionInventory = _sender->getCoord();
}
if (mMainWidget->getSize().width != mLastXSize || mMainWidget->getSize().height != mLastYSize)
{
mLastXSize = mMainWidget->getSize().width;
mLastYSize = mMainWidget->getSize().height;
mPreviewDirty = true;
}
}
void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender)
{
if (_sender == mFilterAll)
mSortModel->setCategory(SortFilterItemModel::Category_All);
else if (_sender == mFilterWeapon)
mSortModel->setCategory(SortFilterItemModel::Category_Weapon);
else if (_sender == mFilterApparel)
mSortModel->setCategory(SortFilterItemModel::Category_Apparel);
else if (_sender == mFilterMagic)
mSortModel->setCategory(SortFilterItemModel::Category_Magic);
else if (_sender == mFilterMisc)
mSortModel->setCategory(SortFilterItemModel::Category_Misc);
mFilterAll->setStateSelected(false);
mFilterWeapon->setStateSelected(false);
mFilterApparel->setStateSelected(false);
mFilterMagic->setStateSelected(false);
mFilterMisc->setStateSelected(false);
mItemView->update();
static_cast<MyGUI::Button*>(_sender)->setStateSelected(true);
}
void InventoryWindow::onPinToggled()
{
MWBase::Environment::get().getWindowManager()->setWeaponVisibility(!mPinned);
}
void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender)
{
if (mDragAndDrop->mIsOnDragAndDrop)
{
MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase;
mDragAndDrop->finish();
if (mDragAndDrop->mSourceModel != mTradeModel)
{
// add item to the player's inventory
MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
MWWorld::ContainerStoreIterator it = invStore.begin();
int origCount = ptr.getRefData().getCount();
ptr.getRefData().setCount(mDragAndDrop->mDraggedCount);
it = invStore.add(ptr);
ptr.getRefData().setCount(origCount);
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
ptr = *it;
}
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(ptr).use(ptr);
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
// this is necessary for books/scrolls: if they are already in the player's inventory,
// the "Take" button should not be visible.
// NOTE: the take button is "reset" when the window opens, so we can safely do the following
// without screwing up future book windows
MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false);
MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false);
mItemView->update();
notifyContentChanged();
}
else
{
MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance ().getLastPressedPosition (MyGUI::MouseButton::Left);
MyGUI::IntPoint relPos = mousePos - mAvatar->getAbsolutePosition ();
int realX = int(float(relPos.left) / float(mAvatar->getSize().width) * 512.f );
int realY = int(float(relPos.top) / float(mAvatar->getSize().height) * 1024.f );
MWWorld::Ptr itemSelected = getAvatarSelectedItem (realX, realY);
if (itemSelected.isEmpty ())
return;
for (size_t i=0; i < mTradeModel->getItemCount (); ++i)
{
if (mTradeModel->getItem(i).mBase == itemSelected)
{
onItemSelectedFromSourceModel(i);
return;
}
}
throw std::runtime_error("Can't find clicked item");
}
}
MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y)
{
int slot = mPreview.getSlotSelected (x, y);
if (slot == -1)
return MWWorld::Ptr();
MWWorld::Ptr player = mPtr;
MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player);
if (invStore.getSlot(slot) != invStore.end())
return *invStore.getSlot (slot);
else
return MWWorld::Ptr();
}
void InventoryWindow::unequipItem(const MWWorld::Ptr& item)
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
if (it != invStore.end() && *it == item)
{
invStore.equip(slot, invStore.end());
std::string script = MWWorld::Class::get(*it).getScript(*it);
// Unset OnPCEquip Variable on item's script, if it has a script with that variable declared
if(script != "")
(*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0);
return;
}
}
}
void InventoryWindow::updateEncumbranceBar()
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
float capacity = MWWorld::Class::get(player).getCapacity(player);
float encumbrance = MWWorld::Class::get(player).getEncumbrance(player);
mEncumbranceBar->setValue(encumbrance, capacity);
}
void InventoryWindow::onFrame()
{
if (!mMainWidget->getVisible())
return;
updateEncumbranceBar();
}
int InventoryWindow::getPlayerGold()
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
for (MWWorld::ContainerStoreIterator it = invStore.begin();
it != invStore.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001"))
return it->getRefData().getCount();
}
return 0;
}
void InventoryWindow::setTrading(bool trading)
{
mTrading = trading;
}
void InventoryWindow::doRenderUpdate ()
{
if (mPreviewDirty)
{
mPreviewDirty = false;
MyGUI::IntSize size = mAvatar->getSize();
mPreview.update (size.width, size.height);
mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024)));
mAvatarImage->setImageTexture("CharacterPreview");
}
}
void InventoryWindow::notifyContentChanged()
{
// update the spell window just in case new enchanted items were added to inventory
if (MWBase::Environment::get().getWindowManager()->getSpellWindow())
MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells();
// update selected weapon icon
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (weaponSlot == invStore.end())
MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon();
else
MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*weaponSlot);
mPreviewDirty = true;
mArmorRating->setCaptionWithReplacing ("#{sArmor}: "
+ boost::lexical_cast<std::string>(static_cast<int>(MWWorld::Class::get(mPtr).getArmorRating(mPtr))));
}
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
{
// make sure the object is of a type that can be picked up
std::string type = object.getTypeName();
if ( (type != typeid(ESM::Apparatus).name())
&& (type != typeid(ESM::Armor).name())
&& (type != typeid(ESM::Book).name())
&& (type != typeid(ESM::Clothing).name())
&& (type != typeid(ESM::Ingredient).name())
&& (type != typeid(ESM::Light).name())
&& (type != typeid(ESM::Miscellaneous).name())
&& (type != typeid(ESM::Lockpick).name())
&& (type != typeid(ESM::Probe).name())
&& (type != typeid(ESM::Repair).name())
&& (type != typeid(ESM::Weapon).name())
&& (type != typeid(ESM::Potion).name()))
return;
if (MWWorld::Class::get(object).getName(object) == "") // objects without name presented to user can never be picked up
return;
int count = object.getRefData().getCount();
if (object.getCellRef().mGoldValue > 1)
count = object.getCellRef().mGoldValue;
// add to player inventory
// can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWWorld::Ptr newObject = *MWWorld::Class::get (player).getContainerStore (player).add (object);
// remove from world
MWBase::Environment::get().getWorld()->deleteObject (object);
// get ModelIndex to the item
mTradeModel->update();
size_t i=0;
for (; i<mTradeModel->getItemCount(); ++i)
{
if (mTradeModel->getItem(i).mBase == newObject)
break;
}
if (i == mTradeModel->getItemCount())
throw std::runtime_error("Added item not found");
mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count);
}
MyGUI::IntCoord InventoryWindow::getAvatarScreenCoord ()
{
return mAvatar->getAbsoluteCoord ();
}
}