mirror of
https://github.com/OpenMW/openmw.git
synced 2025-10-24 03:26:40 +00:00
Support player's inventory, container and companion windows with dropping and picking up items from the world. Add ItemTransfer class to handle transfers similar to DragAndDrop. When a container window is opened the view is added to the set of targets and removed when closed. If ALT is pressed instead of starting dragging an item perform a transfer. If there is 1 target which is not a source move item there. If there is no target drop item into the world using WorldItemModel. Special case is picking up an item. Don't start dragging, just update the player's inventory view because the item is already there.
164 lines
5.5 KiB
C++
164 lines
5.5 KiB
C++
#include "draganddrop.hpp"
|
|
|
|
#include <MyGUI_ControllerManager.h>
|
|
#include <MyGUI_Gui.h>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/windowmanager.hpp"
|
|
|
|
#include "../mwworld/class.hpp"
|
|
|
|
#include "controllers.hpp"
|
|
#include "inventorywindow.hpp"
|
|
#include "itemview.hpp"
|
|
#include "sortfilteritemmodel.hpp"
|
|
|
|
namespace MWGui
|
|
{
|
|
|
|
DragAndDrop::DragAndDrop()
|
|
: mIsOnDragAndDrop(false)
|
|
, mDraggedWidget(nullptr)
|
|
, mSourceModel(nullptr)
|
|
, mSourceView(nullptr)
|
|
, mSourceSortModel(nullptr)
|
|
, mDraggedCount(0)
|
|
{
|
|
}
|
|
|
|
void DragAndDrop::startDrag(
|
|
int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count)
|
|
{
|
|
mItem = sourceModel->getItem(index);
|
|
mDraggedCount = count;
|
|
mSourceModel = sourceModel;
|
|
mSourceView = sourceView;
|
|
mSourceSortModel = sortModel;
|
|
|
|
// If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend
|
|
// immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive,
|
|
// but this is how it works in vanilla, and not doing so would break quests (BM_beasts for instance).
|
|
ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel();
|
|
if (mSourceModel != playerModel)
|
|
{
|
|
MWWorld::Ptr item = mSourceModel->moveItem(mItem, mDraggedCount, playerModel);
|
|
|
|
playerModel->update();
|
|
|
|
ItemModel::ModelIndex newIndex = -1;
|
|
for (size_t i = 0; i < playerModel->getItemCount(); ++i)
|
|
{
|
|
if (playerModel->getItem(i).mBase == item)
|
|
{
|
|
newIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
mItem = playerModel->getItem(newIndex);
|
|
mSourceModel = playerModel;
|
|
|
|
SortFilterItemModel* playerFilterModel
|
|
= MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getSortFilterModel();
|
|
mSourceSortModel = playerFilterModel;
|
|
}
|
|
|
|
const ESM::RefId& sound = mItem.mBase.getClass().getUpSoundId(mItem.mBase);
|
|
MWBase::Environment::get().getWindowManager()->playSound(sound);
|
|
|
|
if (mSourceSortModel)
|
|
{
|
|
mSourceSortModel->clearDragItems();
|
|
mSourceSortModel->addDragItem(mItem.mBase, count);
|
|
}
|
|
|
|
mDraggedWidget = MyGUI::Gui::getInstance().createWidget<ItemWidget>(
|
|
"MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop");
|
|
|
|
Controllers::ControllerFollowMouse* controller
|
|
= MyGUI::ControllerManager::getInstance()
|
|
.createItem(Controllers::ControllerFollowMouse::getClassTypeName())
|
|
->castType<Controllers::ControllerFollowMouse>();
|
|
MyGUI::ControllerManager::getInstance().addItem(mDraggedWidget, controller);
|
|
|
|
mDraggedWidget->setItem(mItem.mBase);
|
|
mDraggedWidget->setNeedMouseFocus(false);
|
|
mDraggedWidget->setCount(count);
|
|
|
|
MWBase::Environment::get().getWindowManager()->setDragDrop(true);
|
|
|
|
mIsOnDragAndDrop = true;
|
|
|
|
// Update item view after completing drag-and-drop setup
|
|
mSourceView->update();
|
|
}
|
|
|
|
void DragAndDrop::drop(ItemModel* targetModel, ItemView* targetView)
|
|
{
|
|
const ESM::RefId& sound = mItem.mBase.getClass().getDownSoundId(mItem.mBase);
|
|
MWBase::Environment::get().getWindowManager()->playSound(sound);
|
|
|
|
// We can't drop a conjured item to the ground; the target container should always be the source container
|
|
if (mItem.mFlags & ItemStack::Flag_Bound && targetModel != mSourceModel)
|
|
{
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
|
|
return;
|
|
}
|
|
|
|
// If item is dropped where it was taken from, we don't need to do anything -
|
|
// otherwise, do the transfer
|
|
if (targetModel != mSourceModel)
|
|
{
|
|
mSourceModel->moveItem(mItem, mDraggedCount, targetModel);
|
|
}
|
|
|
|
mSourceModel->update();
|
|
|
|
finish();
|
|
if (targetView)
|
|
targetView->update();
|
|
|
|
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
|
|
|
|
// We need to update the view since an other item could be auto-equipped.
|
|
mSourceView->update();
|
|
}
|
|
|
|
void DragAndDrop::update()
|
|
{
|
|
if (!mIsOnDragAndDrop)
|
|
return;
|
|
|
|
const unsigned count = mItem.mBase.getCellRef().getAbsCount();
|
|
if (count >= mDraggedCount)
|
|
return;
|
|
|
|
mItem.mCount = count;
|
|
mDraggedCount = count;
|
|
mDraggedWidget->setCount(mDraggedCount);
|
|
mSourceSortModel->clearDragItems();
|
|
mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount);
|
|
}
|
|
|
|
void DragAndDrop::onFrame()
|
|
{
|
|
if (mIsOnDragAndDrop && mItem.mBase.getCellRef().getCount() == 0)
|
|
finish();
|
|
}
|
|
|
|
void DragAndDrop::finish()
|
|
{
|
|
mIsOnDragAndDrop = false;
|
|
mSourceSortModel->clearDragItems();
|
|
// since mSourceView doesn't get updated in drag()
|
|
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
|
|
|
|
if (mDraggedWidget)
|
|
{
|
|
MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget);
|
|
mDraggedWidget = nullptr;
|
|
}
|
|
|
|
MWBase::Environment::get().getWindowManager()->setDragDrop(false);
|
|
}
|
|
|
|
}
|