Container UI rewrite
parent
7e05b725d0
commit
0c4a963132
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue