Container UI rewrite

actorid
scrawl 12 years ago
parent 7e05b725d0
commit 0c4a963132

@ -32,7 +32,8 @@ add_openmw_dir (mwgui
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
keywordsearch
keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
tradeitemmodel companionitemmodel pickpocketitemmodel
)
add_openmw_dir (mwdialogue

@ -338,6 +338,9 @@ namespace MWBase
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
virtual float getWindSpeed() = 0;
virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
///< get all containers in active cells owned by this Npc
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
virtual int canRest() = 0;

@ -164,4 +164,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Apparatus;
}
float Apparatus::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Apparatus> *ref =
ptr.get<ESM::Apparatus>();
return ref->mBase->mData.mWeight;
}
}

@ -13,6 +13,8 @@ namespace MWClass
public:
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -387,4 +387,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Armor;
}
float Armor::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Armor> *ref =
ptr.get<ESM::Armor>();
return ref->mBase->mData.mWeight;
}
}

@ -12,6 +12,8 @@ namespace MWClass
public:
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -188,4 +188,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Books;
}
float Book::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Book> *ref =
ptr.get<ESM::Book>();
return ref->mBase->mData.mWeight;
}
}

@ -60,6 +60,8 @@ namespace MWClass
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -307,4 +307,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Clothing;
}
float Clothing::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Clothing> *ref =
ptr.get<ESM::Clothing>();
return ref->mBase->mData.mWeight;
}
}

@ -73,6 +73,8 @@ namespace MWClass
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -225,6 +225,16 @@ namespace MWClass
return weight;
}
int Creature::getServices(const MWWorld::Ptr &actor) const
{
MWWorld::LiveCellRef<ESM::Creature>* ref = actor.get<ESM::Creature>();
if (ref->mBase->mHasAI)
return ref->mBase->mAiData.mServices;
else
return 0;
}
MWWorld::Ptr
Creature::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
{

@ -62,6 +62,8 @@ namespace MWClass
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
virtual int getServices (const MWWorld::Ptr& actor) const;
static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const;

@ -202,4 +202,12 @@ namespace MWClass
{
return npcServices & ESM::NPC::Ingredients;
}
float Ingredient::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Ingredient> *ref =
ptr.get<ESM::Ingredient>();
return ref->mBase->mData.mWeight;
}
}

@ -57,6 +57,8 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -208,4 +208,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Lights;
}
float Light::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Light> *ref =
ptr.get<ESM::Light>();
return ref->mBase->mData.mWeight;
}
}

@ -58,6 +58,8 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -189,4 +189,11 @@ namespace MWClass
return ref->mBase->mData.mUses;
}
float Lockpick::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Lockpick> *ref =
ptr.get<ESM::Lockpick>();
return ref->mBase->mData.mWeight;
}
}

@ -60,6 +60,8 @@ namespace MWClass
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const;
///< Return item max health or throw an exception, if class does not have item health
};

@ -254,4 +254,11 @@ namespace MWClass
return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc);
}
float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mWeight;
}
}

@ -54,6 +54,8 @@ namespace MWClass
const;
///< Generate action for using via inventory menu
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -648,6 +648,15 @@ namespace MWClass
scale *= race->mData.mHeight.mFemale;
}
int Npc::getServices(const MWWorld::Ptr &actor) const
{
MWWorld::LiveCellRef<ESM::NPC>* ref = actor.get<ESM::NPC>();
if (ref->mBase->mHasAI)
return ref->mBase->mAiData.mServices;
else
return 0;
}
MWWorld::Ptr
Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
{

@ -128,6 +128,8 @@ namespace MWClass
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
virtual int getServices (const MWWorld::Ptr& actor) const;
static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const;

@ -199,4 +199,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Potions;
}
float Potion::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Potion> *ref =
ptr.get<ESM::Potion>();
return ref->mBase->mData.mWeight;
}
}

@ -53,6 +53,8 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -188,4 +188,11 @@ namespace MWClass
return ref->mBase->mData.mUses;
}
float Probe::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Probe> *ref =
ptr.get<ESM::Probe>();
return ref->mBase->mData.mWeight;
}
}

@ -60,6 +60,8 @@ namespace MWClass
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const;
///< Return item max health or throw an exception, if class does not have item health
};

@ -180,4 +180,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::RepairItem;
}
float Repair::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Repair> *ref =
ptr.get<ESM::Repair>();
return ref->mBase->mData.mWeight;
}
}

@ -62,6 +62,8 @@ namespace MWClass
///< Return item max health or throw an exception, if class does not have item health
/// (default implementation: throw an exceoption)
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
};
}

@ -440,4 +440,11 @@ namespace MWClass
{
return npcServices & ESM::NPC::Weapon;
}
float Weapon::getWeight(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Weapon> *ref =
ptr.get<ESM::Weapon>();
return ref->mBase->mData.mWeight;
}
}

@ -79,6 +79,8 @@ namespace MWClass
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
};
}

@ -1,6 +1,7 @@
#include "alchemywindow.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -8,6 +9,11 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "inventoryitemmodel.hpp"
#include "sortfilteritemmodel.hpp"
#include "itemview.hpp"
namespace
{
@ -20,13 +26,25 @@ namespace
path.append(".dds");
return path;
}
std::string getCountString(const int count)
{
if (count == 1)
return "";
if (count > 9999)
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
else
return boost::lexical_cast<std::string>(count);
}
}
namespace MWGui
{
AlchemyWindow::AlchemyWindow()
: WindowBase("openmw_alchemy_window.layout")
, ContainerBase(0), mApparatus (4), mIngredients (4)
, mApparatus (4)
, mIngredients (4)
{
getWidget(mCreateButton, "CreateButton");
getWidget(mCancelButton, "CancelButton");
@ -40,6 +58,13 @@ namespace MWGui
getWidget(mApparatus[3], "Apparatus4");
getWidget(mEffectsBox, "CreatedEffects");
getWidget(mNameEdit, "NameEdit");
getWidget(mItemView, "ItemView");
InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
mSortModel = new SortFilterItemModel(model);
mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients);
mItemView->setModel (mSortModel);
mItemView->eventItemClicked += MyGUI::newDelegate(this, &AlchemyWindow::onSelectedItem);
mIngredients[0]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
mIngredients[1]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
@ -49,12 +74,6 @@ namespace MWGui
mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked);
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
MyGUI::ScrollView* itemView;
MyGUI::Widget* containerWidget;
getWidget(containerWidget, "Items");
getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView);
center();
}
@ -126,12 +145,9 @@ namespace MWGui
void AlchemyWindow::open()
{
openContainer (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr
setFilter (ContainerBase::Filter_Ingredients);
mNameEdit->setCaption("");
mAlchemy.setAlchemist (mPtr);
mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
int index = 0;
@ -155,8 +171,9 @@ namespace MWGui
update();
}
void AlchemyWindow::onSelectedItemImpl(MWWorld::Ptr item)
void AlchemyWindow::onSelectedItem(int index)
{
MWWorld::Ptr item = mSortModel->getItem(index).mBase;
int res = mAlchemy.addIngredient(item);
if (res != -1)
@ -168,19 +185,10 @@ namespace MWGui
}
}
std::vector<MWWorld::Ptr> AlchemyWindow::itemsToIgnore()
{
std::vector<MWWorld::Ptr> ignore;
// don't show ingredients that are currently selected in the "available ingredients" box.
for (int i=0; i<4; ++i)
if (mIngredients[i]->isUserString("ToolTipType"))
ignore.push_back(*mIngredients[i]->getUserData<MWWorld::Ptr>());
return ignore;
}
void AlchemyWindow::update()
{
mSortModel->clearDragItems();
MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy.beginIngredients ();
for (int i=0; i<4; ++i)
{
@ -193,6 +201,9 @@ namespace MWGui
++it;
}
if (!item.isEmpty())
mSortModel->addDragItem(item, item.getRefData().getCount());
if (ingredient->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
@ -214,7 +225,7 @@ namespace MWGui
text->setCaption(getCountString(ingredient->getUserData<MWWorld::Ptr>()->getRefData().getCount()));
}
drawItems();
mItemView->update();
std::vector<ESM::ENAMstruct> effects;
ESM::EffectList list;

@ -5,19 +5,25 @@
#include "../mwmechanics/alchemy.hpp"
#include "container.hpp"
#include "widgets.hpp"
#include "windowbase.hpp"
namespace MWGui
{
class AlchemyWindow : public WindowBase, public ContainerBase
class ItemView;
class SortFilterItemModel;
class AlchemyWindow : public WindowBase
{
public:
AlchemyWindow();
virtual void open();
protected:
private:
ItemView* mItemView;
SortFilterItemModel* mSortModel;
MyGUI::Button* mCreateButton;
MyGUI::Button* mCancelButton;
@ -29,17 +35,12 @@ namespace MWGui
void onCreateButtonClicked(MyGUI::Widget* _sender);
void onIngredientSelected(MyGUI::Widget* _sender);
virtual void onSelectedItemImpl(MWWorld::Ptr item);
virtual std::vector<MWWorld::Ptr> itemsToIgnore();
void onSelectedItem(int index);
void removeIngredient(MyGUI::Widget* ingredient);
virtual void onReferenceUnavailable() { ; }
void update();
private:
MWMechanics::Alchemy mAlchemy;
std::vector<MyGUI::ImageBox *> mApparatus;

@ -0,0 +1,34 @@
#include "companionitemmodel.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwworld/class.hpp"
namespace MWGui
{
CompanionItemModel::CompanionItemModel(const MWWorld::Ptr &actor)
: InventoryItemModel(actor)
{
}
void CompanionItemModel::copyItem (const ItemStack& item, size_t count)
{
if (mActor.getTypeName() == typeid(ESM::NPC).name())
{
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
stats.modifyProfit(MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
}
InventoryItemModel::copyItem(item, count);
}
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)
{
if (mActor.getTypeName() == typeid(ESM::NPC).name())
{
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
stats.modifyProfit(-MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
}
InventoryItemModel::removeItem(item, count);
}
}

@ -0,0 +1,22 @@
#ifndef MWGUI_COMPANION_ITEM_MODEL_H
#define MWGUI_COMPANION_ITEM_MODEL_H
#include "inventoryitemmodel.hpp"
namespace MWGui
{
/// @brief The companion item model keeps track of the companion's profit by
/// monitoring which items are being added to and removed from the model.
class CompanionItemModel : public InventoryItemModel
{
public:
CompanionItemModel (const MWWorld::Ptr& actor);
virtual void copyItem (const ItemStack& item, size_t count);
virtual void removeItem (const ItemStack& item, size_t count);
};
}
#endif

@ -7,51 +7,102 @@
#include "../mwmechanics/npcstats.hpp"
#include "../mwworld/class.hpp"
#include "messagebox.hpp"
#include "itemview.hpp"
#include "sortfilteritemmodel.hpp"
#include "companionitemmodel.hpp"
#include "container.hpp"
#include "countdialog.hpp"
namespace MWGui
{
CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* manager)
: ContainerBase(dragAndDrop)
, WindowBase("openmw_companion_window.layout")
: WindowBase("openmw_companion_window.layout")
, mDragAndDrop(dragAndDrop)
, mMessageBoxManager(manager)
, mSelectedItem(-1)
, mModel(NULL)
, mSortModel(NULL)
{
MyGUI::ScrollView* itemView;
MyGUI::Widget* containerWidget;
getWidget(containerWidget, "Items");
getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView);
getWidget(mCloseButton, "CloseButton");
getWidget(mProfitLabel, "ProfitLabel");
getWidget(mEncumbranceBar, "EncumbranceBar");
getWidget(mItemView, "ItemView");
mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &CompanionWindow::onBackgroundSelected);
mItemView->eventItemClicked += MyGUI::newDelegate(this, &CompanionWindow::onItemSelected);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked);
setCoord(200,0,600,300);
}
void CompanionWindow::open(MWWorld::Ptr npc)
void CompanionWindow::onItemSelected(int index)
{
openContainer(npc);
setTitle(MWWorld::Class::get(npc).getName(npc));
drawItems();
if (mDragAndDrop->mIsOnDragAndDrop)
{
mDragAndDrop->drop(mModel, mItemView);
updateEncumbranceBar();
return;
}
const ItemStack& item = mSortModel->getItem(index);
MWWorld::Ptr object = item.mBase;
int count = item.mCount;
bool shift = MyGUI::InputManager::getInstance().isShiftPressed();
if (MyGUI::InputManager::getInstance().isControlPressed())
count = 1;
mSelectedItem = mSortModel->mapToSource(index);
if (count > 1 && !shift)
{
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
dialog->open(MWWorld::Class::get(object).getName(object), "#{sTake}", count);
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem);
}
else
dragItem (NULL, count);
}
void CompanionWindow::dragItem(MyGUI::Widget* sender, int count)
{
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count);
}
void CompanionWindow::notifyItemDragged(MWWorld::Ptr item, int count)
void CompanionWindow::onBackgroundSelected()
{
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
if (mDragAndDrop->mIsOnDragAndDrop)
{
MWMechanics::NpcStats& stats = MWWorld::Class::get(mPtr).getNpcStats(mPtr);
stats.modifyProfit(MWWorld::Class::get(item).getValue(item) * count);
mDragAndDrop->drop(mModel, mItemView);
updateEncumbranceBar();
}
}
void CompanionWindow::open(const MWWorld::Ptr& npc)
{
mPtr = npc;
setTitle(MWWorld::Class::get(npc).getName(npc));
updateEncumbranceBar();
mModel = new CompanionItemModel(npc);
mSortModel = new SortFilterItemModel(mModel);
mItemView->setModel(mSortModel);
}
void CompanionWindow::onFrame()
{
updateEncumbranceBar();
}
void CompanionWindow::updateEncumbranceBar()
{
if (mPtr.isEmpty())
return;
float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr);
float encumbrance = MWWorld::Class::get(mPtr).getEncumbrance(mPtr);
mEncumbranceBar->setValue(encumbrance, capacity);
@ -65,11 +116,6 @@ void CompanionWindow::updateEncumbranceBar()
}
}
void CompanionWindow::onWindowResize(MyGUI::Window* window)
{
drawItems();
}
void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
{
if (mPtr.getTypeName() == typeid(ESM::NPC).name() && MWWorld::Class::get(mPtr).getNpcStats(mPtr).getProfit() < 0)

@ -1,34 +1,47 @@
#ifndef OPENMW_MWGUI_COMPANIONWINDOW_H
#define OPENMW_MWGUI_COMPANIONWINDOW_H
#include "container.hpp"
#include "widgets.hpp"
#include "windowbase.hpp"
#include "referenceinterface.hpp"
namespace MWGui
{
class MessageBoxManager;
class ItemView;
class DragAndDrop;
class SortFilterItemModel;
class CompanionItemModel;
class CompanionWindow : public ContainerBase, public WindowBase
class CompanionWindow : public WindowBase, public ReferenceInterface
{
public:
CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager);
virtual ~CompanionWindow() {}
void open(MWWorld::Ptr npc);
void open(const MWWorld::Ptr& npc);
void onFrame ();
virtual void notifyItemDragged(MWWorld::Ptr item, int count);
private:
ItemView* mItemView;
SortFilterItemModel* mSortModel;
CompanionItemModel* mModel;
size_t mSelectedItem;
DragAndDrop* mDragAndDrop;
protected:
MyGUI::Button* mCloseButton;
MyGUI::TextBox* mProfitLabel;
Widgets::MWDynamicStat* mEncumbranceBar;
MessageBoxManager* mMessageBoxManager;
void onItemSelected(int index);
void onBackgroundSelected();
void dragItem(MyGUI::Widget* sender, int count);
void onMessageBoxButtonClicked(int button);
void updateEncumbranceBar();
void onWindowResize(MyGUI::Window* window);
void onCloseButtonClicked(MyGUI::Widget* _sender);
virtual void onReferenceUnavailable();

@ -7,681 +7,216 @@
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "countdialog.hpp"
#include "tradewindow.hpp"
#include "inventorywindow.hpp"
#include "itemview.hpp"
#include "inventoryitemmodel.hpp"
#include "sortfilteritemmodel.hpp"
#include "pickpocketitemmodel.hpp"
namespace
{
bool compareType(std::string type1, std::string type2)
{
// this defines the sorting order of types. types that are first in the vector, appear before other types.
std::vector<std::string> mapping;
mapping.push_back( typeid(ESM::Weapon).name() );
mapping.push_back( typeid(ESM::Armor).name() );
mapping.push_back( typeid(ESM::Clothing).name() );
mapping.push_back( typeid(ESM::Potion).name() );
mapping.push_back( typeid(ESM::Ingredient).name() );
mapping.push_back( typeid(ESM::Apparatus).name() );
mapping.push_back( typeid(ESM::Book).name() );
mapping.push_back( typeid(ESM::Light).name() );
mapping.push_back( typeid(ESM::Miscellaneous).name() );
mapping.push_back( typeid(ESM::Lockpick).name() );
mapping.push_back( typeid(ESM::Repair).name() );
mapping.push_back( typeid(ESM::Probe).name() );
assert( std::find(mapping.begin(), mapping.end(), type1) != mapping.end() );
assert( std::find(mapping.begin(), mapping.end(), type2) != mapping.end() );
return std::find(mapping.begin(), mapping.end(), type1) < std::find(mapping.begin(), mapping.end(), type2);
}
bool sortItems(MWWorld::Ptr left, MWWorld::Ptr right)
{
if (left.getTypeName() == right.getTypeName())
std::string getCountString(const int count)
{
int cmp = MWWorld::Class::get(left).getName(left).compare(
MWWorld::Class::get(right).getName(right));
return cmp < 0;
}
if (count == 1)
return "";
if (count > 9999)
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
else
{
return compareType(left.getTypeName(), right.getTypeName());
}
}
bool isChargedSoulstone (MWWorld::Ptr ptr)
{
if (ptr.getTypeName() != typeid(ESM::Miscellaneous).name())
return false;
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
return (ref->mRef.mSoul != "");
return boost::lexical_cast<std::string>(count);
}
}
namespace MWGui
{
ContainerBase::ContainerBase(DragAndDrop* dragAndDrop)
: mDragAndDrop(dragAndDrop)
, mFilter(ContainerBase::Filter_All)
, mDisplayEquippedItems(true)
, mHighlightEquippedItems(true)
{
}
void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView)
{
mContainerWidget = containerWidget;
mItemView = itemView;
mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked);
mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel);
}
ContainerBase::~ContainerBase()
{
}
void ContainerBase::onSelectedItem(MyGUI::Widget* _sender)
{
mSelectedItem = _sender;
if (mDragAndDrop && !isTrading())
{
if(!mDragAndDrop->mIsOnDragAndDrop)
{
MWWorld::Ptr object = (*_sender->getUserData<MWWorld::Ptr>());
int count = object.getRefData().getCount();
if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1)
{
startDragItem(_sender, count);
}
else if (MyGUI::InputManager::getInstance().isControlPressed())
{
startDragItem(_sender, 1);
}
else
{
std::string message = "#{sTake}";
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
dialog->open(MWWorld::Class::get(object).getName(object), message, count);
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem);
}
}
else
onContainerClicked(mContainerWidget);
}
else if (isTrading())
{
MWWorld::Ptr object = (*_sender->getUserData<MWWorld::Ptr>());
int count = object.getRefData().getCount();
if (isInventory())
{
// the player is trying to sell an item, check if the merchant accepts it
if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object))
{
// user notification "i don't buy this item"
MWBase::Environment::get().getWindowManager()->
messageBox("#{sBarterDialog4}");
return;
}
}
bool buying = isTradeWindow(); // buying or selling?
std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}";
if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end())
{
if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1)
{
sellAlreadyBoughtItem(NULL, count);
}
else if (MyGUI::InputManager::getInstance().isControlPressed())
{
sellAlreadyBoughtItem(NULL, 1);
}
else
{
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
dialog->open(MWWorld::Class::get(object).getName(object), message, count);
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem);
}
}
else
{
if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1)
{
sellItem(NULL, count);
}
else if (MyGUI::InputManager::getInstance().isControlPressed())
{
sellItem(NULL, 1);
}
else
{
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
dialog->open(MWWorld::Class::get(object).getName(object), message, count);
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem);
}
}
}
else
{
onSelectedItemImpl(*_sender->getUserData<MWWorld::Ptr>());
}
}
void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count)
void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count)
{
MWWorld::Ptr object = *mSelectedItem->getUserData<MWWorld::Ptr>();
mItem = sourceModel->getItem(index);
mDraggedCount = count;
mSourceModel = sourceModel;
mSourceView = sourceView;
mSourceSortModel = sortModel;
mIsOnDragAndDrop = true;
mDragAndDropWidget->setVisible(true);
if (isInventory())
{
MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems();
}
else
{
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true);
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
}
std::string sound = MWWorld::Class::get(object).getUpSoundId(object);
std::string sound = MWWorld::Class::get(mItem.mBase).getUpSoundId(mItem.mBase);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
drawItems();
}
void ContainerBase::sellItem(MyGUI::Widget* _sender, int count)
{
MWWorld::Ptr object = *mSelectedItem->getUserData<MWWorld::Ptr>();
if (isInventory())
if (mSourceSortModel)
{
MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems();
mSourceSortModel->clearDragItems();
mSourceSortModel->addDragItem(mItem.mBase, count);
}
else
{
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false);
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
}
std::string sound = MWWorld::Class::get(object).getUpSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
drawItems();
}
void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count)
{
mDragAndDrop->mIsOnDragAndDrop = true;
mSelectedItem->detachFromWidget();
mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget);
MWWorld::Ptr object = *mSelectedItem->getUserData<MWWorld::Ptr>();
_unequipItem(object);
mDragAndDrop->mDraggedCount = count;
mDragAndDrop->mDraggedFrom = this;
std::string sound = MWWorld::Class::get(object).getUpSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
std::string path = std::string("icons\\");
path += MWWorld::Class::get(mItem.mBase).getInventoryIcon(mItem.mBase);
MyGUI::ImageBox* baseWidget = mDragAndDropWidget->createWidget<MyGUI::ImageBox>
("ImageBox", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default);
mDraggedWidget = baseWidget;
MyGUI::ImageBox* image = baseWidget->createWidget<MyGUI::ImageBox>("ImageBox",
MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
int pos = path.rfind(".");
path.erase(pos);
path.append(".dds");
image->setImageTexture(path);
image->setNeedMouseFocus(false);
mDragAndDrop->mDraggedWidget = mSelectedItem;
static_cast<MyGUI::ImageBox*>(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag)
static_cast<MyGUI::TextBox*>(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption(
getCountString(mDragAndDrop->mDraggedCount));
// text widget that shows item count
MyGUI::TextBox* text = image->createWidget<MyGUI::TextBox>("SandBrightText",
MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label"));
text->setTextAlign(MyGUI::Align::Right);
text->setNeedMouseFocus(false);
text->setTextShadow(true);
text->setTextShadowColour(MyGUI::Colour(0,0,0));
text->setCaption(getCountString(count));
drawItems();
sourceView->update();
MWBase::Environment::get().getWindowManager()->setDragDrop(true);
}
void ContainerBase::onContainerClicked(MyGUI::Widget* _sender)
void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView)
{
if (mDragAndDrop == NULL) return;
std::string sound = MWWorld::Class::get(mItem.mBase).getDownSoundId(mItem.mBase);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
if(mDragAndDrop->mIsOnDragAndDrop) //drop item here
{
MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData<MWWorld::Ptr>();
MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
mDragAndDropWidget->setVisible(false);
if (mDragAndDrop->mDraggedFrom != this)
{
assert(object.getContainerStore() && "Item is not in a container!");
targetModel->copyItem(mItem, mDraggedCount);
mSourceModel->removeItem(mItem, mDraggedCount);
// check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside
if (mPtr.getTypeName() == typeid(ESM::Container).name())
{
MWWorld::LiveCellRef<ESM::Container>* ref = mPtr.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Organic)
{
// user notification
MWBase::Environment::get().getWindowManager()->
messageBox("#{sContentsMessage2}");
mSourceModel->update();
return;
finish();
targetView->update();
}
}
int origCount = object.getRefData().getCount();
// check that we don't exceed the allowed weight (only for containers, not for inventory)
if (!isInventory())
void DragAndDrop::finish()
{
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(mPtr).getEncumbrance(mPtr);
if (curWeight > capacity)
{
it->getRefData().setCount(0);
object.getRefData().setCount(origCount);
// user notification
MWBase::Environment::get().getWindowManager()->
messageBox("#{sContentsMessage3}");
return;
}
else
{
object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount);
}
}
else
{
object.getRefData().setCount (mDragAndDrop->mDraggedCount);
containerStore.add(object);
object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount);
}
}
mDragAndDrop->mIsOnDragAndDrop = false;
MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget);
drawItems();
mDragAndDrop->mDraggedFrom->drawItems();
mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount);
notifyItemDragged(object, mDragAndDrop->mDraggedCount);
mIsOnDragAndDrop = false;
mSourceSortModel->clearDragItems();
MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget);
mDraggedWidget = 0;
MWBase::Environment::get().getWindowManager()->setDragDrop(false);
std::string sound = MWWorld::Class::get(object).getDownSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
}
}
void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel)
{
if (mItemView->getViewOffset().left + _rel*0.3 > 0)
mItemView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0));
}
void ContainerBase::setFilter(int filter)
{
mFilter = filter;
drawItems();
}
void ContainerBase::openContainer(MWWorld::Ptr container)
{
mPtr = container;
}
void ContainerBase::drawItems()
{
while (mContainerWidget->getChildCount())
{
MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0));
}
MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
int x = 0;
int y = 0;
int maxHeight = mItemView->getSize().height - 58;
bool onlyMagic = false;
bool noMagic = false;
int categories = 0;
if (mFilter & Filter_All)
categories |= MWWorld::ContainerStore::Type_All;
if (mFilter & Filter_Weapon)
categories |= MWWorld::ContainerStore::Type_Weapon;
if (mFilter & Filter_Apparel)
categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor;
if (mFilter & Filter_Magic)
{
categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor
| MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Book
| MWWorld::ContainerStore::Type_Potion;
onlyMagic = true;
}
if (mFilter & Filter_Misc)
{
categories |= MWWorld::ContainerStore::Type_Miscellaneous | MWWorld::ContainerStore::Type_Book
| MWWorld::ContainerStore::Type_Ingredient | MWWorld::ContainerStore::Type_Repair
| MWWorld::ContainerStore::Type_Lockpick | MWWorld::ContainerStore::Type_Light
| MWWorld::ContainerStore::Type_Apparatus | MWWorld::ContainerStore::Type_Probe;
}
if (mFilter & Filter_Ingredients)
categories |= MWWorld::ContainerStore::Type_Ingredient;
if (mFilter & Filter_ChargedSoulstones)
categories |= MWWorld::ContainerStore::Type_Miscellaneous;
if (mFilter & Filter_NoMagic)
noMagic = true;
/// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them
std::vector< std::pair<MWWorld::Ptr, ItemState> > items;
std::vector<MWWorld::Ptr> equippedItems = getEquippedItems();
// add bought items (always at the beginning)
std::vector<MWWorld::Ptr> boughtItems;
for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it)
{
boughtItems.push_back(*it);
}
std::sort(boughtItems.begin(), boughtItems.end(), sortItems);
for (std::vector<MWWorld::Ptr>::iterator it=boughtItems.begin();
it != boughtItems.end(); ++it)
{
items.push_back( std::make_pair(*it, ItemState_Barter) );
}
// filter out the equipped items of categories we don't want
std::vector<MWWorld::Ptr> unwantedItems = equippedItems;
for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter)
{
std::vector<MWWorld::Ptr>::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter);
if (found != unwantedItems.end())
{
unwantedItems.erase(found);
}
}
// now erase everything that's still in unwantedItems.
for (std::vector<MWWorld::Ptr>::iterator it=unwantedItems.begin();
it != unwantedItems.end(); ++it)
{
std::vector<MWWorld::Ptr>::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it);
assert(found != equippedItems.end());
equippedItems.erase(found);
}
// and add the items that are left (= have the correct category)
if (mDisplayEquippedItems && mHighlightEquippedItems)
{
for (std::vector<MWWorld::Ptr>::const_iterator it=equippedItems.begin();
it != equippedItems.end(); ++it)
ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop)
: WindowBase("openmw_container_window.layout")
, mDragAndDrop(dragAndDrop)
, mSelectedItem(-1)
, mModel(NULL)
, mSortModel(NULL)
{
items.push_back( std::make_pair(*it, ItemState_Equipped) );
}
}
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
getWidget(mTakeButton, "TakeButton");
getWidget(mCloseButton, "CloseButton");
std::vector<MWWorld::Ptr> ignoreItems = itemsToIgnore();
getWidget(mItemView, "ItemView");
mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &ContainerWindow::onBackgroundSelected);
mItemView->eventItemClicked += MyGUI::newDelegate(this, &ContainerWindow::onItemSelected);
// now add the regular items
std::vector<MWWorld::Ptr> regularItems;
for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter)
{
if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end()
|| (!mHighlightEquippedItems && mDisplayEquippedItems))
&& std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end()
&& std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end())
regularItems.push_back(*iter);
}
mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked);
mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked);
// sort them and add
std::sort(regularItems.begin(), regularItems.end(), sortItems);
for (std::vector<MWWorld::Ptr>::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it)
{
items.push_back( std::make_pair(*it, ItemState_Normal) );
setCoord(200,0,600,300);
}
for (std::vector< std::pair<MWWorld::Ptr, ItemState> >::const_iterator it=items.begin();
it != items.end(); ++it)
void ContainerWindow::onItemSelected(int index)
{
const MWWorld::Ptr* iter = &((*it).first);
if (onlyMagic
&& it->second != ItemState_Barter
&& MWWorld::Class::get(*iter).getEnchantment(*iter) == ""
&& iter->getTypeName() != typeid(ESM::Potion).name())
continue;
if (noMagic
&& it->second != ItemState_Barter
&& (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""
|| iter->getTypeName() == typeid(ESM::Potion).name()))
continue;
if ( (mFilter & Filter_ChargedSoulstones)
&& !isChargedSoulstone(*iter))
continue;
int displayCount = iter->getRefData().getCount();
if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData<MWWorld::Ptr>())
{
displayCount -= mDragAndDrop->mDraggedCount;
}
if(displayCount > 0)
if (mDragAndDrop->mIsOnDragAndDrop)
{
std::string path = std::string("icons\\");
path += MWWorld::Class::get(*iter).getInventoryIcon(*iter);
// background widget (for the "equipped" frame and magic item background image)
bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != "");
MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default);
backgroundWidget->setUserString("ToolTipType", "ItemPtr");
backgroundWidget->setUserData(*iter);
std::string backgroundTex = "textures\\menu_icon";
if (isMagic)
backgroundTex += "_magic";
if (it->second == ItemState_Normal)
{
if (!isMagic)
backgroundTex = "";
}
else if (it->second == ItemState_Equipped)
{
backgroundTex += "_equip";
}
else if (it->second == ItemState_Barter)
{
backgroundTex += "_barter";
if (!dynamic_cast<PickpocketItemModel*>(mModel))
dropItem();
return;
}
if (backgroundTex != "")
backgroundTex += ".dds";
backgroundWidget->setImageTexture(backgroundTex);
if (it->second == ItemState_Barter && !isMagic)
backgroundWidget->setProperty("ImageCoord", "2 2 42 42");
else
backgroundWidget->setProperty("ImageCoord", "0 0 42 42");
backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem);
backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel);
const ItemStack& item = mSortModel->getItem(index);
// image
MyGUI::ImageBox* image = backgroundWidget->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
int pos = path.rfind(".");
path.erase(pos);
path.append(".dds");
image->setImageTexture(path);
image->setNeedMouseFocus(false);
MWWorld::Ptr object = item.mBase;
int count = item.mCount;
bool shift = MyGUI::InputManager::getInstance().isShiftPressed();
if (MyGUI::InputManager::getInstance().isControlPressed())
count = 1;
// text widget that shows item count
MyGUI::TextBox* text = image->createWidget<MyGUI::TextBox>("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label"));
text->setTextAlign(MyGUI::Align::Right);
text->setNeedMouseFocus(false);
text->setTextShadow(true);
text->setTextShadowColour(MyGUI::Colour(0,0,0));
text->setCaption(getCountString(displayCount));
mSelectedItem = mSortModel->mapToSource(index);
y += 42;
if (y > maxHeight)
if (count > 1 && !shift)
{
x += 42;
y = 0;
}
}
}
MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height);
mItemView->setCanvasSize(size);
mContainerWidget->setSize(size);
notifyContentChanged();
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
dialog->open(MWWorld::Class::get(object).getName(object), "#{sTake}", count);
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem);
}
std::string ContainerBase::getCountString(const int count)
{
if (count == 1)
return "";
if (count > 9999)
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
else
return boost::lexical_cast<std::string>(count);
dragItem (NULL, count);
}
void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count)
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
{
int origCount = item.getRefData().getCount();
item.getRefData().setCount(count);
MWWorld::ContainerStoreIterator it = mBoughtItems.add(item);
item.getRefData().setCount(origCount - count);
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count);
}
void ContainerBase::addItem(MWWorld::Ptr item, int count)
void ContainerWindow::dropItem()
{
MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
int origCount = item.getRefData().getCount();
item.getRefData().setCount(count);
MWWorld::ContainerStoreIterator it = containerStore.add(item);
item.getRefData().setCount(origCount - count);
}
void ContainerBase::transferBoughtItems()
{
MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it)
{
containerStore.add(*it);
}
}
void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store)
if (mPtr.getTypeName() == typeid(ESM::Container).name())
{
for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it)
// check that we don't exceed container capacity
MWWorld::Ptr item = mDragAndDrop->mItem.mBase;
float weight = MWWorld::Class::get(item).getWeight(item) * mDragAndDrop->mDraggedCount;
if (MWWorld::Class::get(mPtr).getCapacity(mPtr) < MWWorld::Class::get(mPtr).getEncumbrance(mPtr) + weight)
{
store.add(*it);
}
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
return;
}
std::vector<MWWorld::Ptr> ContainerBase::getEquippedItems()
{
if (mPtr.getTypeName() != typeid(ESM::NPC).name())
return std::vector<MWWorld::Ptr>();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
std::vector<MWWorld::Ptr> items;
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
if (it != invStore.end())
// check container organic flag
MWWorld::LiveCellRef<ESM::Container>* ref = mPtr.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Organic)
{
items.push_back(*it);
}
MWBase::Environment::get().getWindowManager()->
messageBox("#{sContentsMessage2}");
return;
}
return items;
}
MWWorld::ContainerStore& ContainerBase::getContainerStore()
{
MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
return store;
}
// ------------------------------------------------------------------------------------------------
ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop)
: ContainerBase(dragAndDrop)
, WindowBase("openmw_container_window.layout")
{
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
getWidget(mTakeButton, "TakeButton");
getWidget(mCloseButton, "CloseButton");
MyGUI::ScrollView* itemView;
MyGUI::Widget* containerWidget;
getWidget(containerWidget, "Items");
getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView);
mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked);
mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked);
static_cast<MyGUI::Window*>(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize);
setCoord(200,0,600,300);
mDragAndDrop->drop(mModel, mItemView);
}
ContainerWindow::~ContainerWindow()
void ContainerWindow::onBackgroundSelected()
{
if (mDragAndDrop->mIsOnDragAndDrop && !dynamic_cast<PickpocketItemModel*>(mModel))
dropItem();
}
void ContainerWindow::onWindowResize(MyGUI::Window* window)
void ContainerWindow::open(const MWWorld::Ptr& container, bool loot)
{
drawItems();
}
mPtr = container;
void ContainerWindow::open(MWWorld::Ptr container, bool loot)
{
mDisplayEquippedItems = true;
mHighlightEquippedItems = false;
if (container.getTypeName() == typeid(ESM::NPC).name() && !loot)
{
// we are stealing stuff
mDisplayEquippedItems = false;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
mModel = new PickpocketItemModel(player, new InventoryItemModel(container));
}
else
mModel = new InventoryItemModel(container);
mDisposeCorpseButton->setVisible(loot);
openContainer(container);
setTitle(MWWorld::Class::get(container).getName(container));
drawItems();
mSortModel = new SortFilterItemModel(mModel);
mItemView->setModel (mSortModel);
}
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
@ -697,32 +232,19 @@ namespace MWGui
if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop)
{
// transfer everything into the player's inventory
MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
std::vector<MWWorld::Ptr> equippedItems = getEquippedItems();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player);
int i=0;
for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter)
ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel();
for (size_t i=0; i<mModel->getItemCount(); ++i)
{
if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end()
&& !mDisplayEquippedItems)
continue;
playerStore.add(*iter);
if (i==0)
{
// play the sound of the first object
std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter);
MWWorld::Ptr item = mModel->getItem(i).mBase;
std::string sound = MWWorld::Class::get(item).getUpSoundId(item);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
}
iter->getRefData().setCount(0);
++i;
playerModel->copyItem(mModel->getItem(i), mModel->getItem(i).mCount);
mModel->removeItem(mModel->getItem(i), mModel->getItem(i).mCount);
}
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
@ -735,10 +257,10 @@ namespace MWGui
{
onTakeAllButtonClicked(mTakeButton);
/// \todo I don't think this is the correct flag to check
if (MWWorld::Class::get(mPtr).isEssential(mPtr))
MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
else
/// \todo if corpse is non-disposable: messagebox #{sDisposeCorpseFail}
//if ()
// MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
//else
MWBase::Environment::get().getWorld()->deleteObject(mPtr);
mPtr = MWWorld::Ptr();

@ -4,9 +4,7 @@
#include "windowbase.hpp"
#include "referenceinterface.hpp"
#include "../mwclass/container.hpp"
#include "../mwworld/containerstore.hpp"
#include "itemmodel.hpp"
namespace MWWorld
{
@ -23,7 +21,8 @@ namespace MWGui
{
class WindowManager;
class ContainerWindow;
class ContainerBase;
class ItemView;
class SortFilterItemModel;
}
@ -35,114 +34,41 @@ namespace MWGui
bool mIsOnDragAndDrop;
MyGUI::Widget* mDraggedWidget;
MyGUI::Widget* mDragAndDropWidget;
ContainerBase* mDraggedFrom;
ItemModel* mSourceModel;
ItemView* mSourceView;
SortFilterItemModel* mSourceSortModel;
ItemStack mItem;
int mDraggedCount;
};
class ContainerBase : public ReferenceInterface
{
public:
ContainerBase(DragAndDrop* dragAndDrop);
virtual ~ContainerBase();
// basic types (inclusive)
static const int Filter_All = (1<<0);
static const int Filter_Weapon = (1<<1);
static const int Filter_Apparel = (1<<2);
static const int Filter_Ingredients = (1<<3);
static const int Filter_Misc = (1<<4);
// special filtering (exclusive)
static const int Filter_Magic = (1<<5);
static const int Filter_NoMagic = (1<<6);
static const int Filter_ChargedSoulstones = (1<<7);
enum ItemState
{
ItemState_Normal = 0x01,
ItemState_Equipped = 0x02,
ItemState_Barter = 0x03
};
void setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView); ///< only call once
void addBarteredItem(MWWorld::Ptr item, int count);
void addItem(MWWorld::Ptr item, int count);
void transferBoughtItems(); ///< transfer bought items into the inventory
void returnBoughtItems(MWWorld::ContainerStore& store); ///< return bought items into the specified ContainerStore
MWWorld::ContainerStore& getContainerStore();
MWWorld::ContainerStore& getBoughtItems() { return mBoughtItems; }
void openContainer(MWWorld::Ptr container);
void setFilter(int filter); ///< set category filter
void drawItems();
/// fired when an item was moved by drag&drop. \n
/// if it was removed from this container, count will be negative.
virtual void notifyItemDragged(MWWorld::Ptr item, int count) {}
protected:
bool mDisplayEquippedItems;
bool mHighlightEquippedItems;
MyGUI::ScrollView* mItemView;
MyGUI::Widget* mContainerWidget;
MyGUI::Widget* mSelectedItem;
void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count);
void drop (ItemModel* targetModel, ItemView* targetView);
DragAndDrop* mDragAndDrop;
int mFilter;
// bought items are put in a separate ContainerStore so that they don't stack with other (not bought) items.
MWWorld::ContainerStore mBoughtItems;
void onSelectedItem(MyGUI::Widget* _sender);
void onContainerClicked(MyGUI::Widget* _sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
/// start dragging an item (drag & drop)
void startDragItem(MyGUI::Widget* _sender, int count);
/// sell an item from this container
void sellItem(MyGUI::Widget* _sender, int count);
/// sell an item from this container, that was previously just bought
void sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count);
std::string getCountString(const int count);
virtual bool isTradeWindow() { return false; }
virtual bool isInventory() { return false; }
virtual std::vector<MWWorld::Ptr> getEquippedItems();
virtual void _unequipItem(MWWorld::Ptr item) { ; }
virtual bool isTrading() { return false; }
virtual void onSelectedItemImpl(MWWorld::Ptr item) { ; }
virtual std::vector<MWWorld::Ptr> itemsToIgnore() { return std::vector<MWWorld::Ptr>(); }
virtual void notifyContentChanged() { ; }
void finish();
};
class ContainerWindow : public ContainerBase, public WindowBase
class ContainerWindow : public WindowBase, public ReferenceInterface
{
public:
ContainerWindow(DragAndDrop* dragAndDrop);
virtual ~ContainerWindow();
void open(const MWWorld::Ptr& container, bool loot=false);
private:
DragAndDrop* mDragAndDrop;
void open(MWWorld::Ptr container, bool loot=false);
MWGui::ItemView* mItemView;
SortFilterItemModel* mSortModel;
ItemModel* mModel;
size_t mSelectedItem;
protected:
MyGUI::Button* mDisposeCorpseButton;
MyGUI::Button* mTakeButton;
MyGUI::Button* mCloseButton;
void onWindowResize(MyGUI::Window* window);
void onItemSelected(int index);
void onBackgroundSelected();
void dragItem(MyGUI::Widget* sender, int count);
void dropItem();
void onCloseButtonClicked(MyGUI::Widget* _sender);
void onTakeAllButtonClicked(MyGUI::Widget* _sender);
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);

@ -0,0 +1,113 @@
#include "containeritemmodel.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp"
namespace MWGui
{
ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSources)
: mItemSources(itemSources)
{
assert (mItemSources.size());
}
ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source)
{
mItemSources.push_back(source);
}
ItemStack ContainerItemModel::getItem (ModelIndex index)
{
if (index < 0)
throw std::runtime_error("Invalid index supplied");
if (mItems.size() <= static_cast<size_t>(index))
throw std::runtime_error("Item index out of range");
return mItems[index];
}
size_t ContainerItemModel::getItemCount()
{
return mItems.size();
}
ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item)
{
size_t i = 0;
for (std::vector<ItemStack>::iterator it = mItems.begin(); it != mItems.end(); ++it)
{
if (*it == item)
return i;
++i;
}
return -1;
}
void ContainerItemModel::copyItem (const ItemStack& item, size_t count)
{
const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1];
int origCount = item.mBase.getRefData().getCount();
item.mBase.getRefData().setCount(count);
MWWorld::ContainerStoreIterator it = MWWorld::Class::get(source).getContainerStore(source).add(item.mBase);
if (*it != item.mBase)
item.mBase.getRefData().setCount(origCount);
else
item.mBase.getRefData().setCount(origCount + count); // item copied onto itself
}
void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
{
int toRemove = count;
for (std::vector<MWWorld::Ptr>::iterator source = mItemSources.begin(); source != mItemSources.end(); ++source)
{
MWWorld::ContainerStore& store = MWWorld::Class::get(*source).getContainerStore(*source);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (*it == item.mBase || (store.stacks(*it, item.mBase) && item.mBase.getContainerStore()->stacks(*it, item.mBase)))
{
int refCount = it->getRefData().getCount();
it->getRefData().setCount(std::max(0, refCount - toRemove));
toRemove -= refCount;
if (toRemove <= 0)
return;
}
}
}
throw std::runtime_error("Not enough items to remove could be found");
}
void ContainerItemModel::update()
{
mItems.clear();
for (std::vector<MWWorld::Ptr>::iterator source = mItemSources.begin(); source != mItemSources.end(); ++source)
{
MWWorld::ContainerStore& store = MWWorld::Class::get(*source).getContainerStore(*source);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
std::vector<ItemStack>::iterator itemStack = mItems.begin();
for (; itemStack != mItems.end(); ++itemStack)
{
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (store.stacks(itemStack->mBase, *it) && it->getContainerStore()->stacks(itemStack->mBase, *it))
{
// we already have an item stack of this kind, add to it
itemStack->mCount += it->getRefData().getCount();
break;
}
}
if (itemStack == mItems.end())
{
// no stack yet, create one
ItemStack newItem (*it, this, it->getRefData().getCount());
mItems.push_back(newItem);
}
}
}
}
}

@ -0,0 +1,37 @@
#ifndef MWGUI_CONTAINER_ITEM_MODEL_H
#define MWGUI_CONTAINER_ITEM_MODEL_H
#include "itemmodel.hpp"
namespace MWGui
{
/// @brief The container item model supports multiple item sources, which are needed for
/// making NPCs sell items from containers owned by them
class ContainerItemModel : public ItemModel
{
public:
ContainerItemModel (const std::vector<MWWorld::Ptr>& itemSources);
///< @note The order of elements \a itemSources matters here. The first element has the highest priority for removal,
/// while the last element will be used to add new items to.
ContainerItemModel (const MWWorld::Ptr& source);
virtual ItemStack getItem (ModelIndex index);
virtual ModelIndex getIndex (ItemStack item);
virtual size_t getItemCount();
virtual void copyItem (const ItemStack& item, size_t count);
virtual void removeItem (const ItemStack& item, size_t count);
virtual void update();
private:
std::vector<MWWorld::Ptr> mItemSources;
std::vector<ItemStack> mItems;
};
}
#endif

@ -9,6 +9,8 @@
#include "../mwmechanics/npcstats.hpp"
#include "../mwworld/class.hpp"
#include "../mwdialogue/dialoguemanagerimp.hpp"
#include "widgets.hpp"

@ -6,11 +6,14 @@
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp"
#include "itemselection.hpp"
#include "container.hpp"
#include "inventorywindow.hpp"
#include "sortfilteritemmodel.hpp"
namespace MWGui
{
@ -139,13 +142,12 @@ namespace MWGui
void EnchantingDialog::onSelectItem(MyGUI::Widget *sender)
{
delete mItemSelectionDialog;
mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}",
ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic);
mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}");
mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected);
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel);
mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
mItemSelectionDialog->drawItems ();
mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable);
}
void EnchantingDialog::onItemSelected(MWWorld::Ptr item)
@ -227,13 +229,12 @@ namespace MWGui
void EnchantingDialog::onSelectSoul(MyGUI::Widget *sender)
{
delete mItemSelectionDialog;
mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}",
ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones);
mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}");
mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected);
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel);
mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
mItemSelectionDialog->drawItems ();
mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones);
//MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}");
}

@ -7,10 +7,13 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "inventorywindow.hpp"
#include "console.hpp"
#include "spellicons.hpp"
#include "itemmodel.hpp"
#include "container.hpp"
namespace MWGui
{
@ -195,7 +198,7 @@ namespace MWGui
if (mDragAndDrop->mIsOnDragAndDrop)
{
// drop item into the gameworld
MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData<MWWorld::Ptr>();
MWWorld::Ptr object = mDragAndDrop->mItem.mBase;
MWBase::World* world = MWBase::Environment::get().getWorld();
@ -217,16 +220,11 @@ namespace MWGui
std::string sound = MWWorld::Class::get(object).getDownSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
// remove object from the container it was coming from
object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount);
mDragAndDrop->mIsOnDragAndDrop = false;
MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget);
mDragAndDrop->mDraggedWidget = 0;
object.getRefData().setCount(origCount);
MWBase::Environment::get().getWindowManager()->setDragDrop(false);
mDragAndDrop->mDraggedFrom->drawItems();
mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount);
// remove object from the container it was coming from
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
mDragAndDrop->finish();
}
else
{

@ -0,0 +1,97 @@
#include "inventoryitemmodel.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
namespace MWGui
{
InventoryItemModel::InventoryItemModel(const MWWorld::Ptr &actor)
: mActor(actor)
{
}
ItemStack InventoryItemModel::getItem (ModelIndex index)
{
if (index < 0)
throw std::runtime_error("Invalid index supplied");
if (mItems.size() <= static_cast<size_t>(index))
throw std::runtime_error("Item index out of range");
return mItems[index];
}
size_t InventoryItemModel::getItemCount()
{
return mItems.size();
}
ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item)
{
size_t i = 0;
for (std::vector<ItemStack>::iterator it = mItems.begin(); it != mItems.end(); ++it)
{
if (*it == item)
return i;
++i;
}
return -1;
}
void InventoryItemModel::copyItem (const ItemStack& item, size_t count)
{
int origCount = item.mBase.getRefData().getCount();
item.mBase.getRefData().setCount(count);
MWWorld::ContainerStoreIterator it = MWWorld::Class::get(mActor).getContainerStore(mActor).add(item.mBase);
if (*it != item.mBase)
item.mBase.getRefData().setCount(origCount);
else
item.mBase.getRefData().setCount(origCount + count); // item copied onto itself
}
void InventoryItemModel::removeItem (const ItemStack& item, size_t count)
{
MWWorld::ContainerStore& store = MWWorld::Class::get(mActor).getContainerStore(mActor);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (*it == item.mBase)
{
if (it->getRefData().getCount() < static_cast<int>(count))
throw std::runtime_error("Not enough items in the stack to remove");
it->getRefData().setCount(it->getRefData().getCount() - count);
return;
}
}
throw std::runtime_error("Item to remove not found in container store");
}
void InventoryItemModel::update()
{
MWWorld::ContainerStore& store = MWWorld::Class::get(mActor).getContainerStore(mActor);
mItems.clear();
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
ItemStack newItem (*it, this, it->getRefData().getCount());
if (mActor.getTypeName() == typeid(ESM::NPC).name())
{
MWWorld::InventoryStore& store = MWWorld::Class::get(mActor).getInventoryStore(mActor);
for (int slot=0; slot<MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator equipped = store.getSlot(slot);
if (equipped == store.end())
continue;
if (*equipped == newItem.mBase)
newItem.mType = ItemStack::Type_Equipped;
}
}
mItems.push_back(newItem);
}
}
}

@ -0,0 +1,31 @@
#ifndef MWGUI_INVENTORY_ITEM_MODEL_H
#define MWGUI_INVENTORY_ITEM_MODEL_H
#include "itemmodel.hpp"
namespace MWGui
{
class InventoryItemModel : public ItemModel
{
public:
InventoryItemModel (const MWWorld::Ptr& actor);
virtual ItemStack getItem (ModelIndex index);
virtual ModelIndex getIndex (ItemStack item);
virtual size_t getItemCount();
virtual void copyItem (const ItemStack& item, size_t count);
virtual void removeItem (const ItemStack& item, size_t count);
virtual void update();
protected:
MWWorld::Ptr mActor;
private:
std::vector<ItemStack> mItems;
};
}
#endif

@ -1,5 +1,7 @@
#include "inventorywindow.hpp"
#include <stdexcept>
#include <boost/lexical_cast.hpp>
#include "../mwbase/world.hpp"
@ -9,22 +11,31 @@
#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)
: ContainerBase(dragAndDrop)
, WindowPinnableBase("openmw_inventory_window.layout")
: WindowPinnableBase("openmw_inventory_window.layout")
, mTrading(false)
, mLastXSize(0)
, mLastYSize(0)
, mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ())
, mPreviewDirty(true)
, mDragAndDrop(dragAndDrop)
{
static_cast<MyGUI::Window*>(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize);
@ -42,11 +53,14 @@ namespace MWGui
mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked);
MyGUI::ScrollView* itemView;
MyGUI::Widget* containerWidget;
getWidget(containerWidget, "Items");
getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView);
mPtr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
getWidget(mItemView, "ItemView");
mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr());
mSortModel = new SortFilterItemModel(mTradeModel);
mItemView->setModel(mSortModel);
mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected);
mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &InventoryWindow::onBackgroundSelected);
mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
@ -57,23 +71,127 @@ namespace MWGui
mFilterAll->setStateSelected(true);
setCoord(0, 342, 498, 258);
onWindowResize(static_cast<MyGUI::Window*>(mMainWidget));
mPreview.setup();
}
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
openContainer(player);
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();
mTrading = false;
mBoughtItems.clear();
mItemView->update();
onWindowResize(static_cast<MyGUI::Window*>(mMainWidget));
drawItems();
notifyContentChanged();
}
void InventoryWindow::onWindowResize(MyGUI::Window* _sender)
@ -87,24 +205,24 @@ namespace MWGui
if (mMainWidget->getSize().width != mLastXSize || mMainWidget->getSize().height != mLastYSize)
{
drawItems();
mLastXSize = mMainWidget->getSize().width;
mLastYSize = mMainWidget->getSize().height;
mPreviewDirty = true;
}
}
void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender)
{
if (_sender == mFilterAll)
setFilter(ContainerBase::Filter_All);
mSortModel->setCategory(SortFilterItemModel::Category_All);
else if (_sender == mFilterWeapon)
setFilter(ContainerBase::Filter_Weapon);
mSortModel->setCategory(SortFilterItemModel::Category_Weapon);
else if (_sender == mFilterApparel)
setFilter(ContainerBase::Filter_Apparel);
mSortModel->setCategory(SortFilterItemModel::Category_Apparel);
else if (_sender == mFilterMagic)
setFilter(ContainerBase::Filter_Magic);
mSortModel->setCategory(SortFilterItemModel::Category_Magic);
else if (_sender == mFilterMisc)
setFilter(ContainerBase::Filter_Misc);
mSortModel->setCategory(SortFilterItemModel::Category_Misc);
mFilterAll->setStateSelected(false);
mFilterWeapon->setStateSelected(false);
@ -112,6 +230,8 @@ namespace MWGui
mFilterMagic->setStateSelected(false);
mFilterMisc->setStateSelected(false);
mItemView->update();
static_cast<MyGUI::Button*>(_sender)->setStateSelected(true);
}
@ -124,24 +244,24 @@ namespace MWGui
{
if (mDragAndDrop->mIsOnDragAndDrop)
{
MWWorld::Ptr ptr = *mDragAndDrop->mDraggedWidget->getUserData<MWWorld::Ptr>();
MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase;
mDragAndDrop->finish();
if (mDragAndDrop->mDraggedFrom != this)
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(origCount - mDragAndDrop->mDraggedCount);
ptr.getRefData().setCount(mDragAndDrop->mDraggedCount);
it = invStore.add(ptr);
(*it).getRefData().setCount(mDragAndDrop->mDraggedCount);
ptr.getRefData().setCount(origCount);
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
ptr = *it;
mDragAndDrop->mDraggedFrom->notifyItemDragged(ptr, -mDragAndDrop->mDraggedCount);
}
/// \todo scripts
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(ptr).use(ptr);
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
@ -153,12 +273,7 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false);
MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false);
mDragAndDrop->mIsOnDragAndDrop = false;
MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget);
MWBase::Environment::get().getWindowManager()->setDragDrop(false);
drawItems();
mItemView->update();
notifyContentChanged();
}
@ -173,16 +288,15 @@ namespace MWGui
if (itemSelected.isEmpty ())
return;
for (unsigned int i=0; i < mContainerWidget->getChildCount (); ++i)
for (size_t i=0; i < mTradeModel->getItemCount (); ++i)
{
MyGUI::Widget* w = mContainerWidget->getChildAt (i);
if (*w->getUserData<MWWorld::Ptr>() == itemSelected)
if (mTradeModel->getItem(i).mBase == itemSelected)
{
onSelectedItem(w);
onItemSelectedFromSourceModel(i);
return;
}
}
throw std::runtime_error("Can't find clicked item");
}
}
@ -201,7 +315,7 @@ namespace MWGui
return MWWorld::Ptr();
}
void InventoryWindow::_unequipItem(MWWorld::Ptr item)
void InventoryWindow::unequipItem(const MWWorld::Ptr& item)
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
@ -252,9 +366,9 @@ namespace MWGui
return 0;
}
void InventoryWindow::startTrade()
void InventoryWindow::setTrading(bool trading)
{
mTrading = true;
mTrading = trading;
}
void InventoryWindow::doRenderUpdate ()
@ -282,7 +396,7 @@ namespace MWGui
if (weaponSlot == invStore.end())
MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon();
else
MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*weaponSlot); /// \todo track weapon durability
MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*weaponSlot);
mPreviewDirty = true;
@ -292,8 +406,6 @@ namespace MWGui
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
{
/// \todo scripts
// make sure the object is of a type that can be picked up
std::string type = object.getTypeName();
if ( (type != typeid(ESM::Apparatus).name())
@ -313,11 +425,9 @@ namespace MWGui
if (MWWorld::Class::get(object).getName(object) == "") // objects without name presented to user can never be picked up
return;
// sound
std::string sound = MWWorld::Class::get(object).getUpSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound(sound, 1, 1);
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
@ -326,31 +436,17 @@ namespace MWGui
// remove from world
MWBase::Environment::get().getWorld()->deleteObject (object);
mDragAndDrop->mIsOnDragAndDrop = true;
mDragAndDrop->mDraggedCount = count;
std::string path = std::string("icons\\");
path += MWWorld::Class::get(newObject).getInventoryIcon(newObject);
MyGUI::ImageBox* baseWidget = mContainerWidget->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default);
baseWidget->detachFromWidget();
baseWidget->attachToWidget(mDragAndDrop->mDragAndDropWidget);
baseWidget->setUserData(newObject);
mDragAndDrop->mDraggedWidget = baseWidget;
MyGUI::ImageBox* image = baseWidget->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
int pos = path.rfind(".");
path.erase(pos);
path.append(".dds");
image->setImageTexture(path);
image->setNeedMouseFocus(false);
// text widget that shows item count
MyGUI::TextBox* text = image->createWidget<MyGUI::TextBox>("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label"));
text->setTextAlign(MyGUI::Align::Right);
text->setNeedMouseFocus(false);
text->setTextShadow(true);
text->setTextShadowColour(MyGUI::Colour(0,0,0));
text->setCaption(getCountString(count));
mDragAndDrop->mDraggedFrom = this;
// 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 ()

@ -3,13 +3,18 @@
#include "../mwrender/characterpreview.hpp"
#include "container.hpp"
#include "windowpinnablebase.hpp"
#include "widgets.hpp"
namespace MWGui
{
class InventoryWindow : public ContainerBase, public WindowPinnableBase
class ItemView;
class SortFilterItemModel;
class TradeItemModel;
class DragAndDrop;
class ItemModel;
class InventoryWindow : public WindowPinnableBase
{
public:
InventoryWindow(DragAndDrop* dragAndDrop);
@ -19,7 +24,7 @@ namespace MWGui
void doRenderUpdate();
/// start trading, disables item drag&drop
void startTrade();
void setTrading(bool trading);
void onFrame();
@ -35,8 +40,22 @@ namespace MWGui
mPreview.rebuild();
}
protected:
TradeItemModel* getTradeModel();
ItemModel* getModel();
void updateItemView();
private:
DragAndDrop* mDragAndDrop;
bool mPreviewDirty;
size_t mSelectedItem;
MWWorld::Ptr mPtr;
MWGui::ItemView* mItemView;
SortFilterItemModel* mSortModel;
TradeItemModel* mTradeModel;
MyGUI::Widget* mAvatar;
MyGUI::ImageBox* mAvatarImage;
@ -59,20 +78,22 @@ namespace MWGui
bool mTrading;
void onItemSelected(int index);
void onItemSelectedFromSourceModel(int index);
void onBackgroundSelected();
void sellItem(MyGUI::Widget* sender, int count);
void dragItem(MyGUI::Widget* sender, int count);
void onWindowResize(MyGUI::Window* _sender);
void onFilterChanged(MyGUI::Widget* _sender);
void onAvatarClicked(MyGUI::Widget* _sender);
void onPinToggled();
void unequipItem(const MWWorld::Ptr& item);
void updateEncumbranceBar();
virtual bool isTrading() { return mTrading; }
virtual bool isInventory() { return true; }
virtual void _unequipItem(MWWorld::Ptr item);
virtual void onReferenceUnavailable() { ; }
virtual void notifyContentChanged();
void notifyContentChanged();
};
}

@ -0,0 +1,98 @@
#include "itemmodel.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
namespace MWGui
{
ItemStack::ItemStack(const MWWorld::Ptr &base, ItemModel *creator, size_t count)
: mCreator(creator)
, mCount(count)
, mFlags(0)
, mType(Type_Normal)
, mBase(base)
{
assert(base.getContainerStore());
if (MWWorld::Class::get(base).getEnchantment(base) != "")
mFlags |= Flag_Enchanted;
}
ItemStack::ItemStack()
: mCreator(NULL)
, mCount(0)
, mFlags(0)
, mType(Type_Normal)
{
}
bool ItemStack::stacks(const ItemStack &other)
{
if(mBase == other.mBase)
return true;
return mBase.getContainerStore()->stacks(mBase, other.mBase)
&& other.mBase.getContainerStore()->stacks(mBase, other.mBase);
}
bool operator == (const ItemStack& left, const ItemStack& right)
{
if (left.mType != right.mType)
return false;
if(left.mBase == right.mBase)
return true;
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase)
&& right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
}
ItemModel::ItemModel()
{
}
ProxyItemModel::~ProxyItemModel()
{
delete mSourceModel;
}
void ProxyItemModel::copyItem (const ItemStack& item, size_t count)
{
// no need to use mapToSource since itemIndex refers to an index in the sourceModel
mSourceModel->copyItem (item, count);
}
void ProxyItemModel::removeItem (const ItemStack& item, size_t count)
{
mSourceModel->removeItem (item, count);
}
ItemModel::ModelIndex ProxyItemModel::mapToSource (ModelIndex index)
{
const ItemStack& itemToSearch = getItem(index);
for (size_t i=0; i<mSourceModel->getItemCount(); ++i)
{
const ItemStack& item = mSourceModel->getItem(i);
if (item == itemToSearch)
return i;
}
return -1;
}
ItemModel::ModelIndex ProxyItemModel::mapFromSource (ModelIndex index)
{
const ItemStack& itemToSearch = mSourceModel->getItem(index);
for (size_t i=0; i<getItemCount(); ++i)
{
const ItemStack& item = getItem(i);
if (item == itemToSearch)
return i;
}
return -1;
}
ItemModel::ModelIndex ProxyItemModel::getIndex (ItemStack item)
{
return mSourceModel->getIndex(item);
}
}

@ -0,0 +1,84 @@
#ifndef MWGUI_ITEM_MODEL_H
#define MWGUI_ITEM_MODEL_H
#include "../mwworld/ptr.hpp"
namespace MWGui
{
class ItemModel;
/// @brief A single item stack managed by an item model
struct ItemStack
{
ItemStack (const MWWorld::Ptr& base, ItemModel* creator, size_t count);
ItemStack();
bool stacks (const ItemStack& other);
///< like operator==, only without checking mType
enum Type
{
Type_Barter,
Type_Equipped,
Type_Normal
};
Type mType;
enum Flags
{
Flag_Enchanted = (1<<0)
};
int mFlags;
ItemModel* mCreator;
size_t mCount;
MWWorld::Ptr mBase;
};
bool operator == (const ItemStack& left, const ItemStack& right);
/// @brief The base class that all item models should derive from.
class ItemModel
{
public:
ItemModel();
virtual ~ItemModel() {}
typedef int ModelIndex;
virtual ItemStack getItem (ModelIndex index) = 0;
///< throws for invalid index
virtual size_t getItemCount() = 0;
virtual ModelIndex getIndex (ItemStack item) = 0;
virtual void update() = 0;
virtual void copyItem (const ItemStack& item, size_t count) = 0;
virtual void removeItem (const ItemStack& item, size_t count) = 0;
private:
ItemModel(const ItemModel&);
ItemModel& operator=(const ItemModel&);
};
/// @brief A proxy item model can be used to filter or rearrange items from a source model (or even add new items to it).
/// The neat thing is that this does not actually alter the source model.
class ProxyItemModel : public ItemModel
{
public:
virtual ~ProxyItemModel();
virtual void copyItem (const ItemStack& item, size_t count);
virtual void removeItem (const ItemStack& item, size_t count);
virtual ModelIndex getIndex (ItemStack item);
ModelIndex mapToSource (ModelIndex index);
ModelIndex mapFromSource (ModelIndex index);
protected:
ItemModel* mSourceModel;
};
}
#endif

@ -1,19 +1,17 @@
#include "itemselection.hpp"
#include "itemview.hpp"
#include "inventoryitemmodel.hpp"
#include "sortfilteritemmodel.hpp"
namespace MWGui
{
ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter)
: ContainerBase(NULL)
, WindowModal("openmw_itemselection_dialog.layout")
ItemSelectionDialog::ItemSelectionDialog(const std::string &label)
: WindowModal("openmw_itemselection_dialog.layout")
{
mFilter = filter;
MyGUI::ScrollView* itemView;
MyGUI::Widget* containerWidget;
getWidget(containerWidget, "Items");
getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView);
getWidget(mItemView, "ItemView");
mItemView->eventItemClicked += MyGUI::newDelegate(this, &ItemSelectionDialog::onSelectedItem);
MyGUI::TextBox* l;
getWidget(l, "Label");
@ -26,9 +24,29 @@ namespace MWGui
center();
}
void ItemSelectionDialog::onSelectedItemImpl(MWWorld::Ptr item)
void ItemSelectionDialog::openContainer(const MWWorld::Ptr& container)
{
mModel = new InventoryItemModel(container);
mSortModel = new SortFilterItemModel(mModel);
mItemView->setModel(mSortModel);
}
void ItemSelectionDialog::setCategory(int category)
{
mSortModel->setCategory(category);
mItemView->update();
}
void ItemSelectionDialog::setFilter(int filter)
{
mSortModel->setFilter(filter);
mItemView->update();
}
void ItemSelectionDialog::onSelectedItem(int index)
{
eventItemSelected(item);
ItemStack item = mSortModel->getItem(index);
eventItemSelected(item.mBase);
}
void ItemSelectionDialog::onCancelButtonClicked(MyGUI::Widget* sender)

@ -2,11 +2,14 @@
namespace MWGui
{
class ItemView;
class SortFilterItemModel;
class InventoryItemModel;
class ItemSelectionDialog : public ContainerBase, public WindowModal
class ItemSelectionDialog : public WindowModal
{
public:
ItemSelectionDialog(const std::string& label, int filter);
ItemSelectionDialog(const std::string& label);
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
typedef MyGUI::delegates::CMultiDelegate1<MWWorld::Ptr> EventHandle_Item;
@ -14,11 +17,16 @@ namespace MWGui
EventHandle_Item eventItemSelected;
EventHandle_Void eventDialogCanceled;
void openContainer (const MWWorld::Ptr& container);
void setCategory(int category);
void setFilter(int filter);
private:
virtual void onReferenceUnavailable() { ; }
ItemView* mItemView;
SortFilterItemModel* mSortModel;
InventoryItemModel* mModel;
virtual void onSelectedItemImpl(MWWorld::Ptr item);
void onSelectedItem(int index);
void onCancelButtonClicked(MyGUI::Widget* sender);
};

@ -0,0 +1,200 @@
#include "itemview.hpp"
#include <boost/lexical_cast.hpp>
#include <MyGUI_FactoryManager.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_TextBox.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_Button.h>
#include "../mwworld/class.hpp"
#include "itemmodel.hpp"
namespace
{
std::string getCountString(const int count)
{
if (count == 1)
return "";
if (count > 9999)
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
else
return boost::lexical_cast<std::string>(count);
}
}
namespace MWGui
{
ItemView::ItemView()
: mModel(NULL)
{
}
ItemView::~ItemView()
{
delete mModel;
}
void ItemView::setModel(ItemModel *model)
{
delete mModel;
mModel = model;
update();
}
void ItemView::initialiseOverride()
{
Base::initialiseOverride();
assignWidget(mScrollView, "ScrollView");
if (mScrollView == NULL)
throw std::runtime_error("Item view needs a scroll view");
mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top);
}
void ItemView::update()
{
while (mScrollView->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0));
if (!mModel)
return;
int x = 0;
int y = 0;
int maxHeight = mScrollView->getSize().height - 58;
mModel->update();
MyGUI::Widget* dragArea = mScrollView->createWidget<MyGUI::Widget>("",0,0,mScrollView->getWidth(),mScrollView->getHeight(),
MyGUI::Align::Stretch);
dragArea->setNeedMouseFocus(true);
dragArea->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedBackground);
dragArea->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel);
for (ItemModel::ModelIndex i=0; i<static_cast<int>(mModel->getItemCount()); ++i)
{
const ItemStack& item = mModel->getItem(i);
/// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them
std::string path = std::string("icons\\");
path += MWWorld::Class::get(item.mBase).getInventoryIcon(item.mBase);
// background widget (for the "equipped" frame and magic item background image)
bool isMagic = (item.mFlags & ItemStack::Flag_Enchanted);
MyGUI::ImageBox* backgroundWidget = dragArea->createWidget<MyGUI::ImageBox>("ImageBox",
MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default);
backgroundWidget->setUserString("ToolTipType", "ItemModelIndex");
backgroundWidget->setUserData(std::make_pair(i, mModel));
std::string backgroundTex = "textures\\menu_icon";
if (isMagic)
backgroundTex += "_magic";
if (item.mType == ItemStack::Type_Normal)
{
if (!isMagic)
backgroundTex = "";
}
else if (item.mType == ItemStack::Type_Equipped)
backgroundTex += "_equip";
else if (item.mType == ItemStack::Type_Barter)
backgroundTex += "_barter";
if (backgroundTex != "")
backgroundTex += ".dds";
backgroundWidget->setImageTexture(backgroundTex);
if ((item.mType == ItemStack::Type_Barter) && !isMagic)
backgroundWidget->setProperty("ImageCoord", "2 2 42 42");
else
backgroundWidget->setProperty("ImageCoord", "0 0 42 42");
backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedItem);
backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel);
// image
MyGUI::ImageBox* image = backgroundWidget->createWidget<MyGUI::ImageBox>("ImageBox",
MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
int pos = path.rfind(".");
path.erase(pos);
path.append(".dds");
image->setImageTexture(path);
image->setNeedMouseFocus(false);
// text widget that shows item count
MyGUI::TextBox* text = image->createWidget<MyGUI::TextBox>("SandBrightText",
MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label"));
text->setTextAlign(MyGUI::Align::Right);
text->setNeedMouseFocus(false);
text->setTextShadow(true);
text->setTextShadowColour(MyGUI::Colour(0,0,0));
text->setCaption(getCountString(item.mCount));
y += 42;
if (y > maxHeight)
{
x += 42;
y = 0;
}
}
x += 42;
MyGUI::IntSize size = MyGUI::IntSize(std::max(mScrollView->getSize().width, x), mScrollView->getSize().height);
mScrollView->setCanvasSize(size);
dragArea->setSize(size);
}
void ItemView::onSelectedItem(MyGUI::Widget *sender)
{
ItemModel::ModelIndex index = (*sender->getUserData<std::pair<ItemModel::ModelIndex, ItemModel*> >()).first;
eventItemClicked(index);
}
void ItemView::onSelectedBackground(MyGUI::Widget *sender)
{
eventBackgroundClicked();
}
void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel)
{
if (mScrollView->getViewOffset().left + _rel*0.3 > 0)
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mScrollView->setViewOffset(MyGUI::IntPoint(mScrollView->getViewOffset().left + _rel*0.3, 0));
}
void ItemView::setSize(const MyGUI::IntSize &_value)
{
Base::setSize(_value);
update();
}
void ItemView::setSize(int _width, int _height)
{
Base::setSize(_width, _height);
update();
}
void ItemView::setCoord(const MyGUI::IntCoord &_value)
{
Base::setCoord(_value);
update();
}
void ItemView::setCoord(int _left, int _top, int _width, int _height)
{
Base::setCoord(_left, _top, _width, _height);
update();
}
void ItemView::registerComponents()
{
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ItemView>("Widget");
}
}

@ -0,0 +1,52 @@
#ifndef MWGUI_ITEMVIEW_H
#define MWGUI_ITEMVIEW_H
#include <MyGUI_Widget.h>
#include "itemmodel.hpp"
namespace MWGui
{
class ItemView : public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(ItemView)
public:
ItemView();
virtual ~ItemView();
/// Register needed components with MyGUI's factory manager
static void registerComponents ();
/// Takes ownership of \a model
void setModel (ItemModel* model);
typedef MyGUI::delegates::CMultiDelegate1<ItemModel::ModelIndex> EventHandle_ModelIndex;
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
/// Fired when an item was clicked
EventHandle_ModelIndex eventItemClicked;
/// Fired when the background was clicked (useful for drag and drop)
EventHandle_Void eventBackgroundClicked;
void update();
private:
virtual void initialiseOverride();
virtual void setSize(const MyGUI::IntSize& _value);
virtual void setCoord(const MyGUI::IntCoord& _value);
void setSize(int _width, int _height);
void setCoord(int _left, int _top, int _width, int _height);
void onSelectedItem (MyGUI::Widget* sender);
void onSelectedBackground (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
ItemModel* mModel;
MyGUI::ScrollView* mScrollView;
};
}
#endif

@ -9,6 +9,8 @@
#include "../mwbase/soundmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "inventorywindow.hpp"
#include "tradewindow.hpp"

@ -0,0 +1,55 @@
#include "pickpocketitemmodel.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwworld/class.hpp"
namespace MWGui
{
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel)
{
mSourceModel = sourceModel;
int chance = MWWorld::Class::get(thief).getNpcStats(thief).getSkill(ESM::Skill::Sneak).getModified();
mSourceModel->update();
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
{
if (std::rand() / static_cast<float>(RAND_MAX) * 100 > chance)
mHiddenItems.push_back(mSourceModel->getItem(i));
}
}
ItemStack PickpocketItemModel::getItem (ModelIndex index)
{
if (index < 0)
throw std::runtime_error("Invalid index supplied");
if (mItems.size() <= static_cast<size_t>(index))
throw std::runtime_error("Item index out of range");
return mItems[index];
}
size_t PickpocketItemModel::getItemCount()
{
return mItems.size();
}
void PickpocketItemModel::update()
{
mSourceModel->update();
mItems.clear();
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
{
const ItemStack& item = mSourceModel->getItem(i);
if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end()
&& item.mType != ItemStack::Type_Equipped)
mItems.push_back(item);
}
}
void PickpocketItemModel::removeItem (const ItemStack &item, size_t count)
{
ProxyItemModel::removeItem(item, count);
/// \todo check if player is detected
}
}

@ -0,0 +1,26 @@
#ifndef MWGUI_PICKPOCKET_ITEM_MODEL_H
#define MWGUI_PICKPOCKET_ITEM_MODEL_H
#include "itemmodel.hpp"
namespace MWGui
{
/// @brief The pickpocket item model randomly hides item stacks based on a specified chance. Equipped items are always hidden.
class PickpocketItemModel : public ProxyItemModel
{
public:
PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel);
virtual ItemStack getItem (ModelIndex index);
virtual size_t getItemCount();
virtual void update();
virtual void removeItem (const ItemStack& item, size_t count);
private:
std::vector<ItemStack> mHiddenItems;
std::vector<ItemStack> mItems;
};
}
#endif

@ -120,13 +120,12 @@ namespace MWGui
{
if (!mItemSelectionDialog )
{
mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All);
mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}");
mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem);
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel);
}
mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
mItemSelectionDialog->drawItems ();
mAssignDialog->setVisible (false);
}
@ -303,7 +302,7 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false);
// since we changed equipping status, update the inventory window
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
}
else if (type == Type_MagicItem)
{
@ -337,7 +336,7 @@ namespace MWGui
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ());
// since we changed equipping status, update the inventory window
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
}
store.setSelectedEnchantItem(it);

@ -0,0 +1,170 @@
#include "sortfilteritemmodel.hpp"
#include "../mwworld/class.hpp"
namespace
{
bool compareType(const std::string& type1, const std::string& type2)
{
// this defines the sorting order of types. types that are first in the vector appear before other types.
std::vector<std::string> mapping;
mapping.push_back( typeid(ESM::Weapon).name() );
mapping.push_back( typeid(ESM::Armor).name() );
mapping.push_back( typeid(ESM::Clothing).name() );
mapping.push_back( typeid(ESM::Potion).name() );
mapping.push_back( typeid(ESM::Ingredient).name() );
mapping.push_back( typeid(ESM::Apparatus).name() );
mapping.push_back( typeid(ESM::Book).name() );
mapping.push_back( typeid(ESM::Light).name() );
mapping.push_back( typeid(ESM::Miscellaneous).name() );
mapping.push_back( typeid(ESM::Lockpick).name() );
mapping.push_back( typeid(ESM::Repair).name() );
mapping.push_back( typeid(ESM::Probe).name() );
assert( std::find(mapping.begin(), mapping.end(), type1) != mapping.end() );
assert( std::find(mapping.begin(), mapping.end(), type2) != mapping.end() );
return std::find(mapping.begin(), mapping.end(), type1) < std::find(mapping.begin(), mapping.end(), type2);
}
bool compare (const MWGui::ItemStack& left, const MWGui::ItemStack& right)
{
if (left.mType != right.mType)
return left.mType < right.mType;
if (left.mBase.getTypeName() == right.mBase.getTypeName())
{
int cmp = MWWorld::Class::get(left.mBase).getName(left.mBase).compare(
MWWorld::Class::get(right.mBase).getName(right.mBase));
return cmp < 0;
}
else
return compareType(left.mBase.getTypeName(), right.mBase.getTypeName());
}
}
namespace MWGui
{
SortFilterItemModel::SortFilterItemModel(ItemModel *sourceModel)
: mCategory(Category_All)
, mShowEquipped(true)
, mFilter(0)
{
mSourceModel = sourceModel;
}
void SortFilterItemModel::addDragItem (const MWWorld::Ptr& dragItem, size_t count)
{
mDragItems.push_back(std::make_pair(dragItem, count));
}
void SortFilterItemModel::clearDragItems()
{
mDragItems.clear();
}
bool SortFilterItemModel::filterAccepts (const ItemStack& item)
{
MWWorld::Ptr base = item.mBase;
if (item.mType == ItemStack::Type_Equipped && !mShowEquipped)
return false;
int category;
if (base.getTypeName() == typeid(ESM::Armor).name()
|| base.getTypeName() == typeid(ESM::Clothing).name())
category = Category_Apparel;
else if (base.getTypeName() == typeid(ESM::Weapon).name())
category = Category_Weapon;
else if (base.getTypeName() == typeid(ESM::Ingredient).name()
|| base.getTypeName() == typeid(ESM::Potion).name())
category = Category_Magic;
else if (base.getTypeName() == typeid(ESM::Miscellaneous).name()
|| base.getTypeName() == typeid(ESM::Ingredient).name()
|| base.getTypeName() == typeid(ESM::Repair).name()
|| base.getTypeName() == typeid(ESM::Lockpick).name()
|| base.getTypeName() == typeid(ESM::Light).name()
|| base.getTypeName() == typeid(ESM::Apparatus).name()
|| base.getTypeName() == typeid(ESM::Book).name()
|| base.getTypeName() == typeid(ESM::Probe).name())
category = Category_Misc;
if (item.mFlags & ItemStack::Flag_Enchanted)
category |= Category_Magic;
if (!(category & mCategory))
return false;
if ((mFilter & Filter_OnlyIngredients) && base.getTypeName() != typeid(ESM::Ingredient).name())
return false;
if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted))
return false;
if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name()
|| base.getCellRef().mSoul == ""))
return false;
if ((mFilter & Filter_OnlyEnchantable) && (item.mFlags & ItemStack::Flag_Enchanted
|| (base.getTypeName() != typeid(ESM::Armor).name()
&& base.getTypeName() != typeid(ESM::Clothing).name()
&& base.getTypeName() != typeid(ESM::Book).name())))
return false;
if ((mFilter & Filter_OnlyEnchantable) && base.getTypeName() == typeid(ESM::Book).name()
&& !base.get<ESM::Book>()->mBase->mData.mIsScroll)
return false;
return true;
}
ItemStack SortFilterItemModel::getItem (ModelIndex index)
{
if (index < 0)
throw std::runtime_error("Invalid index supplied");
if (mItems.size() <= static_cast<size_t>(index))
throw std::runtime_error("Item index out of range");
return mItems[index];
}
size_t SortFilterItemModel::getItemCount()
{
return mItems.size();
}
void SortFilterItemModel::setCategory (int category)
{
mCategory = category;
}
void SortFilterItemModel::setFilter (int filter)
{
mFilter = filter;
}
void SortFilterItemModel::update()
{
mSourceModel->update();
size_t count = mSourceModel->getItemCount();
mItems.clear();
for (size_t i=0; i<count; ++i)
{
ItemStack item = mSourceModel->getItem(i);
for (std::vector<std::pair<MWWorld::Ptr, size_t> >::iterator it = mDragItems.begin(); it != mDragItems.end(); ++it)
{
if (item.mBase == it->first)
{
if (item.mCount < it->second)
throw std::runtime_error("Dragging more than present in the model");
item.mCount -= it->second;
}
}
if (item.mCount > 0 && filterAccepts(item))
mItems.push_back(item);
}
std::sort(mItems.begin(), mItems.end(), compare);
}
}

@ -0,0 +1,53 @@
#ifndef MWGUI_SORT_FILTER_ITEM_MODEL_H
#define MWGUI_SORT_FILTER_ITEM_MODEL_H
#include "itemmodel.hpp"
namespace MWGui
{
class SortFilterItemModel : public ProxyItemModel
{
public:
SortFilterItemModel (ItemModel* sourceModel);
virtual void update();
bool filterAccepts (const ItemStack& item);
virtual ItemStack getItem (ModelIndex index);
virtual size_t getItemCount();
/// Dragged items are not displayed.
void addDragItem (const MWWorld::Ptr& dragItem, size_t count);
void clearDragItems();
void setCategory (int category);
void setFilter (int filter);
void setShowEquipped (bool show) { mShowEquipped = show; }
static const int Category_Weapon = (1<<1);
static const int Category_Apparel = (1<<2);
static const int Category_Misc = (1<<3);
static const int Category_Magic = (1<<4);
static const int Category_All = 255;
static const int Filter_OnlyIngredients = (1<<0);
static const int Filter_OnlyEnchanted = (1<<1);
static const int Filter_OnlyEnchantable = (1<<2);
static const int Filter_OnlyChargedSoulstones = (1<<3);
private:
std::vector<ItemStack> mItems;
std::vector<std::pair<MWWorld::Ptr, size_t> > mDragItems;
int mCategory;
int mFilter;
bool mShowEquipped;
};
}
#endif

@ -9,6 +9,7 @@
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/creaturestats.hpp"

@ -369,7 +369,7 @@ namespace MWGui
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ());
// since we changed equipping status, update the inventory window
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
}
store.setSelectedEnchantItem(it);

@ -6,9 +6,13 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/class.hpp"
#include "mapwindow.hpp"
#include "inventorywindow.hpp"
#include "itemmodel.hpp"
namespace MWGui
{
@ -176,6 +180,16 @@ namespace MWGui
mFocusObject = *focus->getUserData<MWWorld::Ptr>();
tooltipSize = getToolTipViaPtr(false);
}
else if (type == "ItemModelIndex")
{
std::pair<ItemModel::ModelIndex, ItemModel*> pair = *focus->getUserData<std::pair<ItemModel::ModelIndex, ItemModel*> >();
mFocusObject = pair.second->getItem(pair.first).mBase;
// HACK: To get the correct count for multiple item stack sources
int oldCount = mFocusObject.getRefData().getCount();
mFocusObject.getRefData().setCount(pair.second->getItem(pair.first).mCount);
tooltipSize = getToolTipViaPtr(false);
mFocusObject.getRefData().setCount(oldCount);
}
else if (type == "ToolTipInfo")
{
tooltipSize = createToolTip(*focus->getUserData<MWGui::ToolTipInfo>());

@ -0,0 +1,198 @@
#include "tradeitemmodel.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/inventorystore.hpp"
namespace MWGui
{
TradeItemModel::TradeItemModel(ItemModel *sourceModel, const MWWorld::Ptr& merchant)
: mMerchant(merchant)
{
mSourceModel = sourceModel;
}
ItemStack TradeItemModel::getItem (ModelIndex index)
{
if (index < 0)
throw std::runtime_error("Invalid index supplied");
if (mItems.size() <= static_cast<size_t>(index))
throw std::runtime_error("Item index out of range");
return mItems[index];
}
size_t TradeItemModel::getItemCount()
{
return mItems.size();
}
void TradeItemModel::borrowImpl(const ItemStack &item, std::vector<ItemStack> &out)
{
std::vector<ItemStack>::iterator it = out.begin();
bool found = false;
for (; it != out.end(); ++it)
{
if (it->stacks(item))
{
it->mCount += item.mCount;
found = true;
break;
}
}
if (!found)
out.push_back(item);
}
void TradeItemModel::unborrowImpl(const ItemStack &item, size_t count, std::vector<ItemStack> &out)
{
std::vector<ItemStack>::iterator it = out.begin();
bool found = false;
for (; it != out.end(); ++it)
{
if (it->stacks(item))
{
if (it->mCount < count)
throw std::runtime_error("Not enough borrowed items to return");
it->mCount -= count;
if (it->mCount == 0)
out.erase(it);
found = true;
break;
}
}
if (!found)
throw std::runtime_error("Can't find borrowed item to return");
}
void TradeItemModel::borrowItemFromUs (ModelIndex itemIndex, size_t count)
{
ItemStack item = getItem(itemIndex);
item.mCount = count;
borrowImpl(item, mBorrowedFromUs);
}
void TradeItemModel::borrowItemToUs (ModelIndex itemIndex, ItemModel* source, size_t count)
{
ItemStack item = source->getItem(itemIndex);
item.mCount = count;
borrowImpl(item, mBorrowedToUs);
}
void TradeItemModel::returnItemBorrowedToUs (ModelIndex itemIndex, size_t count)
{
ItemStack item = getItem(itemIndex);
unborrowImpl(item, count, mBorrowedToUs);
}
void TradeItemModel::returnItemBorrowedFromUs (ModelIndex itemIndex, ItemModel* source, size_t count)
{
ItemStack item = source->getItem(itemIndex);
unborrowImpl(item, count, mBorrowedFromUs);
}
void TradeItemModel::abort()
{
mBorrowedFromUs.clear();
mBorrowedToUs.clear();
}
std::vector<ItemStack> TradeItemModel::getItemsBorrowedToUs()
{
return mBorrowedToUs;
}
void TradeItemModel::transferItems()
{
std::vector<ItemStack>::iterator it = mBorrowedToUs.begin();
for (; it != mBorrowedToUs.end(); ++it)
{
// get index in the source model
ItemModel* sourceModel = it->mCreator;
size_t i=0;
for (; i<sourceModel->getItemCount(); ++i)
{
if (it->stacks(sourceModel->getItem(i)))
break;
}
if (i == sourceModel->getItemCount())
throw std::runtime_error("The borrowed item disappeared");
// reset owner before copying
const ItemStack& item = sourceModel->getItem(i);
std::string owner = item.mBase.getCellRef().mOwner;
if (mMerchant.isEmpty()) // only for items bought by player
item.mBase.getCellRef().mOwner = "";
// copy the borrowed items to our model
copyItem(item, it->mCount);
item.mBase.getCellRef().mOwner = owner;
// then remove them from the source model
sourceModel->removeItem(item, it->mCount);
}
mBorrowedToUs.clear();
mBorrowedFromUs.clear();
}
void TradeItemModel::update()
{
mSourceModel->update();
int services = 0;
if (!mMerchant.isEmpty())
services = MWWorld::Class::get(mMerchant).getServices(mMerchant);
mItems.clear();
// add regular items
for (size_t i=0; i<mSourceModel->getItemCount(); ++i)
{
ItemStack item = mSourceModel->getItem(i);
MWWorld::Ptr base = item.mBase;
if (!mMerchant.isEmpty() && Misc::StringUtils::ciEqual(base.getCellRef().mRefID, "gold_001"))
continue;
if (!mMerchant.isEmpty() && !MWWorld::Class::get(base).canSell(base, services))
continue;
// don't show equipped items
if (mMerchant.getTypeName() == typeid(ESM::NPC).name())
{
bool isEquipped = false;
MWWorld::InventoryStore& store = MWWorld::Class::get(mMerchant).getInventoryStore(mMerchant);
for (int slot=0; slot<MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator equipped = store.getSlot(slot);
if (equipped == store.end())
continue;
if (*equipped == base)
isEquipped = true;
}
if (isEquipped)
continue;
}
// don't show items that we borrowed to someone else
std::vector<ItemStack>::iterator it = mBorrowedFromUs.begin();
for (; it != mBorrowedFromUs.end(); ++it)
{
if (it->stacks(item))
{
if (item.mCount < it->mCount)
throw std::runtime_error("Lent more items than present");
item.mCount -= it->mCount;
}
}
if (item.mCount > 0)
mItems.push_back(item);
}
// add items borrowed to us
std::vector<ItemStack>::iterator it = mBorrowedToUs.begin();
for (; it != mBorrowedToUs.end(); ++it)
{
ItemStack item = *it;
item.mType = ItemStack::Type_Barter;
mItems.push_back(item);
}
}
}

@ -0,0 +1,53 @@
#ifndef MWGUI_TRADE_ITEM_MODEL_H
#define MWGUI_TRADE_ITEM_MODEL_H
#include "itemmodel.hpp"
namespace MWGui
{
class ItemModel;
/// @brief An item model that allows 'borrowing' items from another item model. Used for previewing barter offers.
/// Also filters items that the merchant does not sell.
class TradeItemModel : public ProxyItemModel
{
public:
TradeItemModel (ItemModel* sourceModel, const MWWorld::Ptr& merchant);
virtual ItemStack getItem (ModelIndex index);
virtual size_t getItemCount();
virtual void update();
void borrowItemFromUs (ModelIndex itemIndex, size_t count);
void borrowItemToUs (ModelIndex itemIndex, ItemModel* source, size_t count);
///< @note itemIndex points to an item in \a source
void returnItemBorrowedToUs (ModelIndex itemIndex, size_t count);
void returnItemBorrowedFromUs (ModelIndex itemIndex, ItemModel* source, size_t count);
/// Permanently transfers items that were borrowed to us from another model to this model
void transferItems ();
/// Aborts trade
void abort();
std::vector<ItemStack> getItemsBorrowedToUs();
private:
void borrowImpl(const ItemStack& item, std::vector<ItemStack>& out);
void unborrowImpl(const ItemStack& item, size_t count, std::vector<ItemStack>& out);
std::vector<ItemStack> mItems;
std::vector<ItemStack> mBorrowedToUs;
std::vector<ItemStack> mBorrowedFromUs;
MWWorld::Ptr mMerchant;
};
}
#endif

@ -10,6 +10,8 @@
#include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
@ -17,28 +19,24 @@
#include "../mwworld/player.hpp"
#include "inventorywindow.hpp"
#include "itemview.hpp"
#include "sortfilteritemmodel.hpp"
#include "containeritemmodel.hpp"
#include "tradeitemmodel.hpp"
#include "countdialog.hpp"
namespace MWGui
{
const float TradeWindow::sBalanceChangeInitialPause = 0.5;
const float TradeWindow::sBalanceChangeInterval = 0.1;
TradeWindow::TradeWindow() :
WindowBase("openmw_trade_window.layout")
, ContainerBase(NULL) // no drag&drop
TradeWindow::TradeWindow()
: WindowBase("openmw_trade_window.layout")
, mCurrentBalance(0)
, mBalanceButtonsState(BBS_None)
, mBalanceChangePause(0.0)
, mItemToSell(-1)
{
// items the NPC is wearing should not be for trade
mDisplayEquippedItems = false;
MyGUI::ScrollView* itemView;
MyGUI::Widget* containerWidget;
getWidget(containerWidget, "Items");
getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView);
getWidget(mFilterAll, "AllButton");
getWidget(mFilterWeapon, "WeaponButton");
getWidget(mFilterApparel, "ApparelButton");
@ -56,6 +54,9 @@ namespace MWGui
getWidget(mTotalBalanceLabel, "TotalBalanceLabel");
getWidget(mBottomPane, "BottomPane");
getWidget(mItemView, "ItemView");
mItemView->eventItemClicked += MyGUI::newDelegate(this, &TradeWindow::onItemSelected);
mFilterAll->setStateSelected(true);
mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged);
@ -73,40 +74,40 @@ namespace MWGui
mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased);
setCoord(400, 0, 400, 300);
static_cast<MyGUI::Window*>(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &TradeWindow::onWindowResize);
}
void TradeWindow::startTrade(MWWorld::Ptr actor)
void TradeWindow::startTrade(const MWWorld::Ptr& actor)
{
mPtr = actor;
setTitle(MWWorld::Class::get(actor).getName(actor));
mCurrentBalance = 0;
mCurrentMerchantOffer = 0;
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->startTrade();
std::vector<MWWorld::Ptr> itemSources;
MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources);
// Important: actor goes last, so that items purchased by the merchant go into his inventory
itemSources.push_back(actor);
mBoughtItems.clear();
ContainerBase::openContainer(actor);
mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources), mPtr);
mSortModel = new SortFilterItemModel(mTradeModel);
mItemView->setModel (mSortModel);
updateLabels();
drawItems();
}
void TradeWindow::onFilterChanged(MyGUI::Widget* _sender)
{
if (_sender == mFilterAll)
setFilter(ContainerBase::Filter_All);
mSortModel->setCategory(SortFilterItemModel::Category_All);
else if (_sender == mFilterWeapon)
setFilter(ContainerBase::Filter_Weapon);
mSortModel->setCategory(SortFilterItemModel::Category_Weapon);
else if (_sender == mFilterApparel)
setFilter(ContainerBase::Filter_Apparel);
mSortModel->setCategory(SortFilterItemModel::Category_Apparel);
else if (_sender == mFilterMagic)
setFilter(ContainerBase::Filter_Magic);
mSortModel->setCategory(SortFilterItemModel::Category_Magic);
else if (_sender == mFilterMisc)
setFilter(ContainerBase::Filter_Misc);
mSortModel->setCategory(SortFilterItemModel::Category_Misc);
mFilterAll->setStateSelected(false);
mFilterWeapon->setStateSelected(false);
@ -115,18 +116,91 @@ namespace MWGui
mFilterMisc->setStateSelected(false);
static_cast<MyGUI::Button*>(_sender)->setStateSelected(true);
mItemView->update();
}
int TradeWindow::getMerchantServices()
{
return MWWorld::Class::get(mPtr).getServices(mPtr);
}
void TradeWindow::onItemSelected (int index)
{
const ItemStack& item = mSortModel->getItem(index);
MWWorld::Ptr object = item.mBase;
int count = item.mCount;
bool shift = MyGUI::InputManager::getInstance().isShiftPressed();
if (MyGUI::InputManager::getInstance().isControlPressed())
count = 1;
if (count > 1 && !shift)
{
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
std::string message = "#{sQuanityMenuMessage02}";
dialog->open(MWWorld::Class::get(object).getName(object), message, count);
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::sellItem);
mItemToSell = mSortModel->mapToSource(index);
}
else
{
mItemToSell = mSortModel->mapToSource(index);
sellItem (NULL, count);
}
}
void TradeWindow::sellItem(MyGUI::Widget* sender, int count)
{
const ItemStack& item = mTradeModel->getItem(mItemToSell);
std::string sound = MWWorld::Class::get(item.mBase).getDownSoundId(item.mBase);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
TradeItemModel* playerTradeModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel();
if (item.mType == ItemStack::Type_Barter)
{
// this was an item borrowed to us by the player
mTradeModel->returnItemBorrowedToUs(mItemToSell, count);
playerTradeModel->returnItemBorrowedFromUs(mItemToSell, mTradeModel, count);
buyFromNpc(item.mBase, count, true);
}
else
{
// borrow item to player
playerTradeModel->borrowItemToUs(mItemToSell, mTradeModel, count);
mTradeModel->borrowItemFromUs(mItemToSell, count);
buyFromNpc(item.mBase, count, false);
}
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
mItemView->update();
}
void TradeWindow::borrowItem (int index, size_t count)
{
TradeItemModel* playerTradeModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel();
mTradeModel->borrowItemToUs(index, playerTradeModel, count);
mItemView->update();
sellToNpc(playerTradeModel->getItem(index).mBase, count, false);
}
void TradeWindow::onWindowResize(MyGUI::Window* _sender)
void TradeWindow::returnItem (int index, size_t count)
{
drawItems();
TradeItemModel* playerTradeModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel();
const ItemStack& item = playerTradeModel->getItem(index);
mTradeModel->returnItemBorrowedFromUs(index, playerTradeModel, count);
mItemView->update();
sellToNpc(item.mBase, count, true);
}
void TradeWindow::addOrRemoveGold(int amount)
{
bool goldFound = false;
MWWorld::Ptr gold;
MWWorld::ContainerStore& playerStore = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player);
for (MWWorld::ContainerStoreIterator it = playerStore.begin();
it != playerStore.end(); ++it)
@ -167,13 +241,15 @@ namespace MWGui
void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender)
{
TradeItemModel* playerItemModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel();
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
// were there any items traded at all?
MWWorld::ContainerStore& playerBought = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getBoughtItems();
MWWorld::ContainerStore& merchantBought = getBoughtItems();
if (playerBought.begin() == playerBought.end() && merchantBought.begin() == merchantBought.end())
std::vector<ItemStack> playerBought = playerItemModel->getItemsBorrowedToUs();
std::vector<ItemStack> merchantBought = mTradeModel->getItemsBorrowedToUs();
if (!playerBought.size() && !merchantBought.size())
{
// user notification
MWBase::Environment::get().getWindowManager()->
@ -255,16 +331,9 @@ namespace MWGui
int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt();
MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition);
// success! make the item transfer.
MWWorld::ContainerStore& playerBoughtItems =
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getBoughtItems();
for (MWWorld::ContainerStoreIterator it = playerBoughtItems.begin(); it != playerBoughtItems.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->getCellRef().mOwner, MWWorld::Class::get(mPtr).getId(mPtr)))
it->getCellRef().mOwner = "";
}
transferBoughtItems();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->transferBoughtItems();
// make the item transfer
mTradeModel->transferItems();
playerItemModel->transferItems();
// add or remove gold from the player.
if (mCurrentBalance != 0)
@ -278,11 +347,8 @@ namespace MWGui
void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
{
// i give you back your stuff!
returnBoughtItems(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore());
// now gimme back my stuff!
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr));
mTradeModel->abort();
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->abort();
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter);
}
@ -343,44 +409,7 @@ namespace MWGui
mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast<std::string>(getMerchantGold()));
}
bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item)
{
if (Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001"))
return false;
int services = 0;
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
{
MWWorld::LiveCellRef<ESM::NPC>* ref = mPtr.get<ESM::NPC>();
if (ref->mBase->mHasAI)
services = ref->mBase->mAiData.mServices;
}
else if (mPtr.getTypeName() == typeid(ESM::Creature).name())
{
MWWorld::LiveCellRef<ESM::Creature>* ref = mPtr.get<ESM::Creature>();
if (ref->mBase->mHasAI)
services = ref->mBase->mAiData.mServices;
}
return MWWorld::Class::get(item).canSell(item, services);
}
std::vector<MWWorld::Ptr> TradeWindow::itemsToIgnore()
{
std::vector<MWWorld::Ptr> items;
MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
for (MWWorld::ContainerStoreIterator it = invStore.begin();
it != invStore.end(); ++it)
{
if (!npcAcceptsItem(*it))
items.push_back(*it);
}
return items;
}
void TradeWindow::sellToNpc(MWWorld::Ptr item, int count, bool boughtItem)
void TradeWindow::sellToNpc(const MWWorld::Ptr& item, int count, bool boughtItem)
{
int diff = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count, boughtItem);
@ -390,7 +419,7 @@ namespace MWGui
updateLabels();
}
void TradeWindow::buyFromNpc(MWWorld::Ptr item, int count, bool soldItem)
void TradeWindow::buyFromNpc(const MWWorld::Ptr& item, int count, bool soldItem)
{
int diff = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count, !soldItem);

@ -17,23 +17,32 @@ namespace MWGui
namespace MWGui
{
class TradeWindow : public ContainerBase, public WindowBase
class ItemView;
class SortFilterItemModel;
class TradeItemModel;
class TradeWindow : public WindowBase, public ReferenceInterface
{
public:
TradeWindow();
void startTrade(MWWorld::Ptr actor);
void sellToNpc(MWWorld::Ptr item, int count, bool boughtItem); ///< only used for adjusting the gold balance
void buyFromNpc(MWWorld::Ptr item, int count, bool soldItem); ///< only used for adjusting the gold balance
bool npcAcceptsItem(MWWorld::Ptr item);
void startTrade(const MWWorld::Ptr& actor);
void addOrRemoveGold(int gold);
void onFrame(float frameDuration);
protected:
void borrowItem (int index, size_t count);
void returnItem (int index, size_t count);
int getMerchantServices();
private:
ItemView* mItemView;
SortFilterItemModel* mSortModel;
TradeItemModel* mTradeModel;
static const float sBalanceChangeInitialPause; // in seconds
static const float sBalanceChangeInterval; // in seconds
@ -56,6 +65,8 @@ namespace MWGui
MyGUI::TextBox* mPlayerGold;
MyGUI::TextBox* mMerchantGold;
int mItemToSell;
int mCurrentBalance;
int mCurrentMerchantOffer;
@ -67,7 +78,12 @@ namespace MWGui
/// pause before next balance change will trigger while user holds +/- button pressed
float mBalanceChangePause;
void onWindowResize(MyGUI::Window* _sender);
void sellToNpc(const MWWorld::Ptr& item, int count, bool boughtItem); ///< only used for adjusting the gold balance
void buyFromNpc(const MWWorld::Ptr& item, int count, bool soldItem); ///< only used for adjusting the gold balance
void onItemSelected (int index);
void sellItem (MyGUI::Widget* sender, int count);
void onFilterChanged(MyGUI::Widget* _sender);
void onOfferButtonClicked(MyGUI::Widget* _sender);
void onCancelButtonClicked(MyGUI::Widget* _sender);
@ -79,16 +95,10 @@ namespace MWGui
void onIncreaseButtonTriggered();
void onDecreaseButtonTriggered();
virtual bool isTrading() { return true; }
virtual bool isTradeWindow() { return true; }
virtual std::vector<MWWorld::Ptr> itemsToIgnore();
void updateLabels();
virtual void onReferenceUnavailable();
private:
int getMerchantGold();
};
}

@ -10,6 +10,7 @@
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/npcstats.hpp"

@ -10,6 +10,7 @@
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "inventorywindow.hpp"
#include "tradewindow.hpp"

@ -5,6 +5,8 @@
#include "../mwbase/inputmanager.hpp"
#include "../mwworld/class.hpp"
#include "console.hpp"
#include "journalwindow.hpp"
#include "journalviewmodel.hpp"
@ -39,6 +41,7 @@
#include "companionwindow.hpp"
#include "inventorywindow.hpp"
#include "bookpage.hpp"
#include "itemview.hpp"
namespace MWGui
{
@ -123,6 +126,7 @@ namespace MWGui
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ExposedWindow>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWScrollView>("Widget");
BookPage::registerMyGUIComponents ();
ItemView::registerComponents();
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
MyGUI::ResourceManager::getInstance().load("core.xml");
@ -302,6 +306,7 @@ namespace MWGui
mMerchantRepair->setVisible(false);
mRepair->setVisible(false);
mCompanionWindow->setVisible(false);
mInventoryWindow->setTrading(false);
mHud->setVisible(mHudEnabled);
@ -411,6 +416,7 @@ namespace MWGui
break;
case GM_Barter:
mInventoryWindow->setVisible(true);
mInventoryWindow->setTrading(true);
mTradeWindow->setVisible(true);
break;
case GM_SpellBuying:
@ -632,17 +638,6 @@ namespace MWGui
return default_;
}
void WindowManager::onDialogueWindowBye()
{
if (mDialogueWindow)
{
//FIXME set some state and stuff?
//removeDialog(dialogueWindow);
mDialogueWindow->setVisible(false);
}
removeGuiMode(GM_Dialogue);
}
void WindowManager::onFrame (float frameDuration)
{
mMessageBoxManager->onFrame(frameDuration);
@ -677,6 +672,7 @@ namespace MWGui
mContainerWindow->checkReferenceAvailable();
mCompanionWindow->checkReferenceAvailable();
mConsole->checkReferenceAvailable();
mCompanionWindow->onFrame();
}
void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell)

@ -327,8 +327,6 @@ namespace MWGui
unsigned int mTriangleCount;
unsigned int mBatchCount;
void onDialogueWindowBye();
/**
* Called when MyGUI tries to retrieve a tag. This usually corresponds to a GMST string,
* so this method will retrieve the GMST with the name \a _tag and place the result in \a _result

@ -52,6 +52,11 @@ namespace MWWorld
return false;
}
int Class::getServices(const Ptr &actor) const
{
throw std::runtime_error ("class does not have services");
}
MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const
{
throw std::runtime_error ("class does not have creature stats");
@ -172,6 +177,11 @@ namespace MWWorld
throw std::runtime_error ("capacity not supported by this class");
}
float Class::getWeight(const Ptr &ptr) const
{
throw std::runtime_error ("weight not supported by this class");
}
float Class::getEncumbrance (const MWWorld::Ptr& ptr) const
{
throw std::runtime_error ("encumbrance not supported by class");

@ -241,6 +241,8 @@ namespace MWWorld
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
///< Determine whether or not \a item can be sold to an npc with the given \a npcServices
virtual int getServices (const MWWorld::Ptr& actor) const;
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
@ -249,6 +251,8 @@ namespace MWWorld
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
/// Second item in the pair specifies the error message
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual Ptr
copyToCell(const Ptr &ptr, CellStore &cell) const;

@ -79,11 +79,10 @@ namespace MWWorld
ContainerStoreIterator addImpl (const Ptr& ptr);
///< Add the item to this container (no stacking)
public:
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
///< @return true if the two specified objects can stack with each other
/// @note ptr1 is the item that is already in this container
public:
void fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store);
///< Insert items into *this.

@ -276,6 +276,8 @@ bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
{
if (*iter != end() && ptr1 == **iter)
return false;
if (*iter != end() && ptr2 == **iter)
return false;
}
return true;

@ -90,8 +90,6 @@ namespace MWWorld
///< \attention This function is internal to the world model and should not be called from
/// outside.
protected:
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
///< @return true if the two specified objects can stack with each other
/// @note ptr1 is the item that is already in this container

@ -1653,4 +1653,22 @@ namespace MWWorld
else
return 0.f;
}
void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out)
{
std::string refId = npc.getCellRef().mRefID;
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{
MWWorld::CellRefList<ESM::Container>& containers = (*cellIt)->mContainers;
CellRefList<ESM::Container>::List& refList = containers.mList;
for (CellRefList<ESM::Container>::List::iterator container = refList.begin(); container != refList.end(); ++container)
{
MWWorld::Ptr ptr (&*container, *cellIt);
if (Misc::StringUtils::ciEqual(ptr.getCellRef().mOwner, npc.getCellRef().mRefID))
out.push_back(ptr);
}
}
}
}

@ -390,6 +390,9 @@ namespace MWWorld
virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
virtual float getWindSpeed();
virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out);
///< get all containers in active cells owned by this Npc
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);
virtual int canRest();

@ -59,11 +59,7 @@
</Widget>
<!-- Available ingredients -->
<Widget type="Widget" skin="MW_Box" position="8 126 247 238" name="box" align="Left Top Stretch">
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 239 230" name="ItemView" align="Left Top Stretch">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="Button" skin="" name="Items" position="0 0 239 230" name="Items" align="Left Top Stretch"/>
</Widget>
<Widget type="ItemView" skin="MW_ItemView" position="8 126 247 238" name="ItemView" align="Left Top Stretch">
</Widget>
<!-- Created effects -->

@ -4,11 +4,7 @@
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 600 300" name="_Main">
<!-- Items -->
<Widget type="Widget" skin="MW_Box" position="5 5 575 225" name="box" align="Left Top Stretch">
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 567 217" name="ItemView" align="Left Top Stretch">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="Button" skin="" name="Items" position="0 0 567 217" name="Items" align="Left Top Stretch"/>
</Widget>
<Widget type="ItemView" skin="MW_ItemView" position="5 5 575 225" name="ItemView" align="Left Top Stretch">
</Widget>
<Widget type="HBox" position="5 235 575 24" align="Bottom HStretch">

@ -4,11 +4,7 @@
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 600 300" name="_Main">
<!-- Items -->
<Widget type="Widget" skin="MW_Box" position="5 5 575 225" name="box" align="Left Top Stretch">
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 567 217" name="ItemView" align="Left Top Stretch">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="Button" skin="" name="Items" position="0 0 567 217" name="Items" align="Left Top Stretch"/>
</Widget>
<Widget type="ItemView" skin="MW_ItemView" position="5 5 575 225" name="ItemView" align="Left Top Stretch">
</Widget>
<Widget type="HBox" position="0 235 580 24" align="Right Bottom">

@ -25,11 +25,7 @@
<Widget type="Widget" skin="" position="228 0 350 223" align="Left Top" name="RightPane">
<!-- Items in inventory -->
<Widget type="Widget" skin="MW_Box" position="0 38 350 185" name="box" align="Left Top Stretch">
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 342 177" align="Left Top Stretch" name="ItemView">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="Button" skin="" name="Items" position="0 0 342 177" name="Items" align="Left Top Stretch"/>
</Widget>
<Widget type="ItemView" skin="MW_ItemView" position="0 38 350 185" name="ItemView" align="Left Top Stretch">
</Widget>
<!-- Categories -->

@ -4,11 +4,7 @@
<Widget type="TextBox" skin="SandText" position="8 8 300 18" name="Label"/>
<Widget type="Widget" skin="MW_Box" position="8 34 355 70" name="box" align="Left Top Stretch">
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 347 62" name="ItemView" align="Left Top Stretch">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="Button" skin="" name="Items" position="0 0 347 62" name="Items" align="Left Top Stretch"/>
</Widget>
<Widget type="ItemView" skin="MW_ItemView" position="8 34 355 70" name="ItemView" align="Left Top Stretch">
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="340 110 24 24" name="CancelButton">

@ -7,7 +7,7 @@
<Layer name="Console" overlapped="false" peek="true"/>
<Layer name="Notification" overlapped="false" peek="false"/>
<Layer name="Popup" overlapped="true" peek="true"/>
<Layer name="DragAndDrop" overlapped="false" peek="true"/>
<Layer name="DragAndDrop" overlapped="false" peek="false"/>
<Layer name="LoadingScreen" overlapped="false" peek="true"/>
<Layer name="Pointer" overlapped="false" peek="false"/>
</MyGUI>

@ -126,6 +126,15 @@
</Skin>
<Skin name="MW_ItemView" size="516 516" align="ALIGN_LEFT ALIGN_TOP">
<Child type="Widget" skin="MW_Box" offset="0 0 516 516" align="ALIGN_STRETCH"/>
<Child type="ScrollView" skin="MW_ScrollViewH" offset="3 3 509 509" align="ALIGN_STRETCH" name="ScrollView">
<Property key="CanvasAlign" value="Left Top"/>
<Property key="NeedMouse" value="true"/>
</Child>
</Skin>
<Skin name="MW_SimpleList" size="516 516" align="ALIGN_LEFT ALIGN_TOP">
<Child type="Widget" skin="MW_Box" offset="0 0 516 516" align="ALIGN_STRETCH"/>

@ -24,11 +24,7 @@
</Widget>
<!-- Items -->
<Widget type="Widget" skin="MW_Box" position="8 38 566 185" name="box" align="Left Top Stretch">
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 558 181" align="Left Top Stretch" name="ItemView">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="Button" skin="" name="Items" position="0 0 558 181" name="Items" align="Left Top Stretch"/>
</Widget>
<Widget type="ItemView" skin="MW_ItemView" position="8 38 566 185" name="ItemView" align="Left Top Stretch">
</Widget>
<Widget type="Widget" skin="" position="8 231 566 92" name="BottomPane" align="Left Bottom HStretch">

@ -612,10 +612,13 @@ namespace Physic
float d1 = 10000.;
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
if(raycastingObjectOnly) resultCallback1.m_collisionFilterMask = CollisionType_Raycasting;
else resultCallback1.m_collisionFilterMask = CollisionType_World;
if(raycastingObjectOnly)
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting;
else
resultCallback1.m_collisionFilterMask = CollisionType_World;
if(!ignoreHeightMap) resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask|| CollisionType_HeightMap;
if(!ignoreHeightMap)
resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap;
dynamicsWorld->rayTest(from, to, resultCallback1);
if (resultCallback1.hasHit())
{

Loading…
Cancel
Save