Procházet zdrojové kódy

gesture for quick backpack window

SoundSSGood před 1 rokem
rodič
revize
e5c532beb4

+ 14 - 0
client/widgets/CArtifactHolder.cpp

@@ -192,6 +192,15 @@ void CArtPlace::showPopupWindow(const Point & cursorPosition)
 		showPopupCallback(*this, cursorPosition);
 }
 
+void CArtPlace::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
+{
+	if(!on)
+		return;
+
+	if(gestureCallback)
+		gestureCallback(*this, initialPosition);
+}
+
 void CArtPlace::showAll(Canvas & to)
 {
 	CIntObject::showAll(to);
@@ -226,6 +235,11 @@ void CArtPlace::setShowPopupCallback(ClickFunctor callback)
 	showPopupCallback = callback;
 }
 
+void CArtPlace::setGestureCallback(ClickFunctor callback)
+{
+	gestureCallback = callback;
+}
+
 void CHeroArtPlace::addCombinedArtInfo(std::map<const CArtifact*, int> & arts)
 {
 	for(const auto & combinedArt : arts)

+ 3 - 0
client/widgets/CArtifactHolder.h

@@ -46,8 +46,10 @@ public:
 	void setArtifact(const CArtifactInstance * art);
 	void setClickPressedCallback(ClickFunctor callback);
 	void setShowPopupCallback(ClickFunctor callback);
+	void setGestureCallback(ClickFunctor callback);
 	void clickPressed(const Point & cursorPosition) override;
 	void showPopupWindow(const Point & cursorPosition) override;
+	void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
 
 protected:
 	std::shared_ptr<CAnimImage> image;
@@ -57,6 +59,7 @@ protected:
 	bool locked;
 	ClickFunctor clickPressedCallback;
 	ClickFunctor showPopupCallback;
+	ClickFunctor gestureCallback;
 
 	void setInternals(const CArtifactInstance * artInst);
 };

+ 2 - 2
client/widgets/CArtifactsOfHeroAltar.cpp

@@ -23,8 +23,8 @@ CArtifactsOfHeroAltar::CArtifactsOfHeroAltar(const Point & position)
 	: visibleArtSet(ArtBearer::ArtBearer::HERO)
 {
 	init(
-		std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1, _2),
-		std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1, _2),
+		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
+		std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
 		position,
 		std::bind(&CArtifactsOfHeroAltar::scrollBackpack, this, _1));
 	pickedArtFromSlot = ArtifactPosition::PRE_FIRST;

+ 55 - 24
client/widgets/CArtifactsOfHeroBackpack.cpp

@@ -23,18 +23,18 @@
 
 #include "../../CCallback.h"
 
-CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack()
+CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(size_t slotsColumnsMax, size_t slotsRowsMax)
+	: slotsColumnsMax(slotsColumnsMax)
+	, slotsRowsMax(slotsRowsMax)
 {
 	setRedrawParent(true);
 }
 
-CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(const Point & position)
-	: CArtifactsOfHeroBackpack()
+CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack()
+	: CArtifactsOfHeroBackpack(8, 8)
 {
-	pos += position;
-
 	const auto backpackCap = VLC->settings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP);
-	auto visibleCapacityMax = slots_rows_max * slots_columns_max;
+	auto visibleCapacityMax = slotsRowsMax * slotsColumnsMax;
 	if(backpackCap >= 0)
 		visibleCapacityMax = visibleCapacityMax > backpackCap ? backpackCap : visibleCapacityMax;
 
@@ -75,7 +75,7 @@ void CArtifactsOfHeroBackpack::updateBackpackSlots()
 
 size_t CArtifactsOfHeroBackpack::getActiveSlotRowsNum()
 {
-	return (curHero->artifactsInBackpack.size() + slots_columns_max - 1) / slots_columns_max;
+	return (curHero->artifactsInBackpack.size() + slotsColumnsMax - 1) / slotsColumnsMax;
 }
 
 size_t CArtifactsOfHeroBackpack::getSlotsNum()
@@ -91,13 +91,13 @@ void CArtifactsOfHeroBackpack::initAOHbackpack(size_t slots, bool slider)
 	size_t artPlaceIdx = 0;
 	for(auto & artPlace : backpack)
 	{
-		const auto pos = Point(slotSizeWithMargin * (artPlaceIdx % slots_columns_max),
-			slotSizeWithMargin * (artPlaceIdx / slots_columns_max));
+		const auto pos = Point(slotSizeWithMargin * (artPlaceIdx % slotsColumnsMax),
+			slotSizeWithMargin * (artPlaceIdx / slotsColumnsMax));
 		backpackSlotsBackgrounds.emplace_back(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/artifactSlotEmpty"), pos));
 		artPlace = std::make_shared<CHeroArtPlace>(pos);
 		artPlace->setArtifact(nullptr);
-		artPlace->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1, _2));
-		artPlace->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1, _2));
+		artPlace->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2));
+		artPlace->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2));
 		artPlaceIdx++;
 	}
 
@@ -109,27 +109,36 @@ void CArtifactsOfHeroBackpack::initAOHbackpack(size_t slots, bool slider)
 		};
 		CListBoxWithCallback::MovedPosCallback posMoved = [this](size_t pos) -> void
 		{
-			scrollBackpack(static_cast<int>(pos) * slots_columns_max - backpackPos);
+			scrollBackpack(static_cast<int>(pos) * slotsColumnsMax - backpackPos);
 		};
 		backpackListBox = std::make_shared<CListBoxWithCallback>(
-			posMoved, onCreate, Point(0, 0), Point(0, 0), slots_rows_max, 0, 0, 1,
-			Rect(slots_columns_max * slotSizeWithMargin + sliderPosOffsetX, 0, slots_rows_max * slotSizeWithMargin - 2, 0));
+			posMoved, onCreate, Point(0, 0), Point(0, 0), slotsRowsMax, 0, 0, 1,
+			Rect(slotsColumnsMax * slotSizeWithMargin + sliderPosOffsetX, 0, slotsRowsMax * slotSizeWithMargin - 2, 0));
 	}
 
-	pos.w = slots > slots_columns_max ? slots_columns_max : slots;
+	pos.w = slots > slotsColumnsMax ? slotsColumnsMax : slots;
 	pos.w *= slotSizeWithMargin;
 	if(slider)
 		pos.w += sliderPosOffsetX + 16; // 16 is slider width. TODO: get it from CListBox directly;
+	pos.h = calcRows(slots) * slotSizeWithMargin;
+}
 
-	pos.h = slots / slots_columns_max;
-	if(slots % slots_columns_max != 0)
-		pos.h += 1;
-	pos.h *= slotSizeWithMargin;
+size_t CArtifactsOfHeroBackpack::calcRows(size_t slots)
+{
+	size_t rows = 0;
+	if(slotsColumnsMax != 0)
+	{
+		rows = slots / slotsColumnsMax;
+		if(slots % slotsColumnsMax != 0)
+			rows += 1;
+	}
+	return rows;
 }
 
-CArtifactsOfHeroQuickBackpack::CArtifactsOfHeroQuickBackpack(const Point & position, const ArtifactPosition filterBySlot)
+CArtifactsOfHeroQuickBackpack::CArtifactsOfHeroQuickBackpack(const ArtifactPosition filterBySlot)
+	: CArtifactsOfHeroBackpack(0, 0)
 {
-	pos += position;
+	assert(filterBySlot != ArtifactPosition::FIRST_AVAILABLE);
 
 	if(!ArtifactUtils::isSlotEquipment(filterBySlot))
 		return;
@@ -153,12 +162,12 @@ void CArtifactsOfHeroQuickBackpack::setHero(const CGHeroInstance * hero)
 			scrollInSlotSpellId = artInSlot->getScrollSpellID();
 		}
 
-		std::map<const CArtifact*, const CArtifactInstance*> filteredArts;
+		std::map<const ArtifactID, const CArtifactInstance*> filteredArts;
 		for(auto & slotInfo : curHero->artifactsInBackpack)
 			if(slotInfo.artifact->getTypeId() != artInSlotId &&	!slotInfo.artifact->isScroll() &&
 				slotInfo.artifact->artType->canBePutAt(curHero, filterBySlot, true))
 			{
-				filteredArts.insert(std::pair(slotInfo.artifact->artType, slotInfo.artifact));
+				filteredArts.insert(std::pair(slotInfo.artifact->getTypeId(), slotInfo.artifact));
 			}
 
 		std::map<const SpellID, const CArtifactInstance*> filteredScrolls;
@@ -173,7 +182,10 @@ void CArtifactsOfHeroQuickBackpack::setHero(const CGHeroInstance * hero)
 		}
 
 		backpack.clear();
-		initAOHbackpack(filteredArts.size() + filteredScrolls.size(), false);
+		auto requiredSlots = filteredArts.size() + filteredScrolls.size();
+		slotsColumnsMax = ceilf(sqrtf(requiredSlots));
+		slotsRowsMax = calcRows(requiredSlots);
+		initAOHbackpack(requiredSlots, false);
 		auto artPlace = backpack.begin();
 		for(auto & art : filteredArts)
 			setSlotData(*artPlace++, curHero->getSlotByInstance(art.second), *curHero);
@@ -186,3 +198,22 @@ ArtifactPosition CArtifactsOfHeroQuickBackpack::getFilterSlot()
 {
 	return filterBySlot;
 }
+
+void CArtifactsOfHeroQuickBackpack::selectSlotAt(const Point & position)
+{
+	for(auto & artPlace : backpack)
+		artPlace->selectSlot(artPlace->pos.isInside(position));
+}
+
+void CArtifactsOfHeroQuickBackpack::swapSelected()
+{
+	ArtifactLocation backpackLoc(curHero->id, ArtifactPosition::PRE_FIRST);
+	for(auto & artPlace : backpack)
+		if(artPlace->isSelected())
+		{
+			backpackLoc.slot = artPlace->slot;
+			break;
+		}
+	if(backpackLoc.slot != ArtifactPosition::PRE_FIRST && filterBySlot != ArtifactPosition::PRE_FIRST && curHero)
+		swapArtifacts(backpackLoc, ArtifactLocation(curHero->id, filterBySlot));
+}

+ 7 - 4
client/widgets/CArtifactsOfHeroBackpack.h

@@ -22,8 +22,8 @@ class CListBoxWithCallback;
 class CArtifactsOfHeroBackpack : public CArtifactsOfHeroBase
 {
 public:
+	CArtifactsOfHeroBackpack(size_t slotsColumnsMax, size_t slotsRowsMax);
 	CArtifactsOfHeroBackpack();
-	CArtifactsOfHeroBackpack(const Point & position);
 	void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
 	void pickUpArtifact(CArtPlace & artPlace);
 	void scrollBackpack(int offset) override;
@@ -34,20 +34,23 @@ public:
 protected:
 	std::shared_ptr<CListBoxWithCallback> backpackListBox;
 	std::vector<std::shared_ptr<CPicture>> backpackSlotsBackgrounds;
-	const size_t slots_columns_max = 8;
-	const size_t slots_rows_max = 8;
+	size_t slotsColumnsMax;
+	size_t slotsRowsMax;
 	const int slotSizeWithMargin = 46;
 	const int sliderPosOffsetX = 5;
 
 	void initAOHbackpack(size_t slots, bool slider);
+	size_t calcRows(size_t slots);
 };
 
 class CArtifactsOfHeroQuickBackpack : public CArtifactsOfHeroBackpack
 {
 public:
-	CArtifactsOfHeroQuickBackpack(const Point & position, const ArtifactPosition filterBySlot);
+	CArtifactsOfHeroQuickBackpack(const ArtifactPosition filterBySlot);
 	void setHero(const CGHeroInstance * hero);
 	ArtifactPosition getFilterSlot();
+	void selectSlotAt(const Point & position);
+	void swapSelected();
 
 private:
 	ArtifactPosition filterBySlot;

+ 19 - 4
client/widgets/CArtifactsOfHeroBase.cpp

@@ -95,18 +95,24 @@ void CArtifactsOfHeroBase::init(
 	setRedrawParent(true);
 }
 
-void CArtifactsOfHeroBase::leftClickArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
+void CArtifactsOfHeroBase::clickPrassedArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
 {
-	if(leftClickCallback)
-		leftClickCallback(*this, artPlace, cursorPosition);
+	if(clickPressedCallback)
+		clickPressedCallback(*this, artPlace, cursorPosition);
 }
 
-void CArtifactsOfHeroBase::rightClickArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
+void CArtifactsOfHeroBase::showPopupArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
 {
 	if(showPopupCallback)
 		showPopupCallback(*this, artPlace, cursorPosition);
 }
 
+void CArtifactsOfHeroBase::gestureArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
+{
+	if(gestureCallback)
+		gestureCallback(*this, artPlace, cursorPosition);
+}
+
 void CArtifactsOfHeroBase::setHero(const CGHeroInstance * hero)
 {
 	curHero = hero;
@@ -241,6 +247,15 @@ const CArtifactInstance * CArtifactsOfHeroBase::getPickedArtifact()
 		return curHero->getArt(ArtifactPosition::TRANSITION_POS);
 }
 
+void CArtifactsOfHeroBase::addGestureCallback(CArtPlace::ClickFunctor callback)
+{
+	for(auto & artPlace : artWorn)
+	{
+		artPlace.second->setGestureCallback(callback);
+		artPlace.second->addUsedEvents(GESTURE);
+	}
+}
+
 void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosition & slot, const CArtifactSet & artSet)
 {
 	// Spurious call from artifactMoved in attempt to update hidden backpack slot

+ 6 - 3
client/widgets/CArtifactsOfHeroBase.h

@@ -24,14 +24,16 @@ public:
 	using ClickFunctor = std::function<void(CArtifactsOfHeroBase&, CArtPlace&, const Point&)>;
 	using PutBackPickedArtCallback = std::function<void()>;
 
-	ClickFunctor leftClickCallback;
+	ClickFunctor clickPressedCallback;
 	ClickFunctor showPopupCallback;
+	ClickFunctor gestureCallback;
 	
 	CArtifactsOfHeroBase();
 	virtual void putBackPickedArtifact();
 	virtual void setPutBackPickedArtifactCallback(PutBackPickedArtCallback callback);
-	virtual void leftClickArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
-	virtual void rightClickArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
+	virtual void clickPrassedArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
+	virtual void showPopupArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
+	virtual void gestureArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
 	virtual void setHero(const CGHeroInstance * hero);
 	virtual const CGHeroInstance * getHero() const;
 	virtual void scrollBackpack(int offset);
@@ -42,6 +44,7 @@ public:
 	virtual void updateBackpackSlots();
 	virtual void updateSlot(const ArtifactPosition & slot);
 	virtual const CArtifactInstance * getPickedArtifact();
+	void addGestureCallback(CArtPlace::ClickFunctor callback);
 
 protected:
 	const CGHeroInstance * curHero;

+ 5 - 4
client/widgets/CArtifactsOfHeroKingdom.cpp

@@ -30,14 +30,15 @@ CArtifactsOfHeroKingdom::CArtifactsOfHeroKingdom(ArtPlaceMap ArtWorn, std::vecto
 	{
 		artPlace.second->slot = artPlace.first;
 		artPlace.second->setArtifact(nullptr);
-		artPlace.second->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1, _2));
-		artPlace.second->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1, _2));
+		artPlace.second->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2));
+		artPlace.second->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2));
 	}
+	addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
 	for(auto artPlace : backpack)
 	{
 		artPlace->setArtifact(nullptr);
-		artPlace->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1, _2));
-		artPlace->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1, _2));
+		artPlace->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2));
+		artPlace->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2));
 	}
 	leftBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, -1));
 	rightBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, +1));

+ 3 - 2
client/widgets/CArtifactsOfHeroMain.cpp

@@ -19,10 +19,11 @@
 CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
 {
 	init(
-		std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1, _2),
-		std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1, _2),
+		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
+		std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
 		position,
 		std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1));
+	addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
 }
 
 CArtifactsOfHeroMain::~CArtifactsOfHeroMain()

+ 2 - 2
client/widgets/CArtifactsOfHeroMarket.cpp

@@ -15,8 +15,8 @@
 CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position)
 {
 	init(
-		std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1, _2),
-		std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1, _2),
+		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
+		std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
 		position,
 		std::bind(&CArtifactsOfHeroMarket::scrollBackpack, this, _1));
 };

+ 32 - 7
client/widgets/CWindowWithArtifacts.cpp

@@ -23,6 +23,7 @@
 #include "../windows/CHeroWindow.h"
 #include "../windows/CSpellWindow.h"
 #include "../windows/GUIClasses.h"
+#include "../windows/CHeroBackpackWindow.h"
 #include "../CPlayerInterface.h"
 #include "../CGameInfo.h"
 
@@ -39,18 +40,19 @@ void CWindowWithArtifacts::addSet(CArtifactsOfHeroPtr artSet)
 
 void CWindowWithArtifacts::addSetAndCallbacks(CArtifactsOfHeroPtr artSet)
 {
-	CArtifactsOfHeroBase::PutBackPickedArtCallback artPutBackHandler = []() -> void
+	CArtifactsOfHeroBase::PutBackPickedArtCallback artPutBackFunctor = []() -> void
 	{
 		CCS->curh->dragAndDropCursor(nullptr);
 	};
 
 	addSet(artSet);
-	std::visit([this, artPutBackHandler](auto artSetWeak)
+	std::visit([this, artPutBackFunctor](auto artSetWeak)
 		{
 			auto artSet = artSetWeak.lock();
-			artSet->leftClickCallback = std::bind(&CWindowWithArtifacts::leftClickArtPlaceHero, this, _1, _2, _3);
-			artSet->showPopupCallback = std::bind(&CWindowWithArtifacts::rightClickArtPlaceHero, this, _1, _2, _3);
-			artSet->setPutBackPickedArtifactCallback(artPutBackHandler);
+			artSet->clickPressedCallback = std::bind(&CWindowWithArtifacts::clickPressedArtPlaceHero, this, _1, _2, _3);
+			artSet->showPopupCallback = std::bind(&CWindowWithArtifacts::showPopupArtPlaceHero, this, _1, _2, _3);
+			artSet->gestureCallback = std::bind(&CWindowWithArtifacts::gestureArtPlaceHero, this, _1, _2, _3);
+			artSet->setPutBackPickedArtifactCallback(artPutBackFunctor);
 		}, artSet);
 }
 
@@ -77,7 +79,7 @@ const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact()
 		return nullptr;
 }
 
-void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+void CWindowWithArtifacts::clickPressedArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
 {
 	const auto artSetWeak = findAOHbyRef(artsInst);
 	assert(artSetWeak.has_value());
@@ -217,7 +219,7 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
 		}, artSetWeak.value());
 }
 
-void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+void CWindowWithArtifacts::showPopupArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
 {
 	const auto artSetWeak = findAOHbyRef(artsInst);
 	assert(artSetWeak.has_value());
@@ -262,6 +264,29 @@ void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsIns
 		}, artSetWeak.value());
 }
 
+void CWindowWithArtifacts::gestureArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+{
+	const auto artSetWeak = findAOHbyRef(artsInst);
+	assert(artSetWeak.has_value());
+	if(artPlace.isLocked())
+		return;
+
+	std::visit(
+		[&artPlace, cursorPosition](auto artSetWeak) -> void
+		{
+			const auto artSetPtr = artSetWeak.lock();
+			if constexpr(
+				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>> ||
+				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>>)
+			{
+				GH.windows().createAndPushWindow<CHeroQuickBackpackWindow>(artSetPtr->getHero(), artPlace.slot);
+				auto backpackWindow = GH.windows().topWindow<CHeroQuickBackpackWindow>();
+				backpackWindow->moveTo(cursorPosition - Point(1, 1));
+				backpackWindow->fitToScreen(15);
+			}
+		}, artSetWeak.value());
+}
+
 void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc)
 {
 	updateSlots();

+ 3 - 2
client/widgets/CWindowWithArtifacts.h

@@ -33,8 +33,9 @@ public:
 	void addCloseCallback(CloseCallback callback);
 	const CGHeroInstance * getHeroPickedArtifact();
 	const CArtifactInstance * getPickedArtifact();
-	void leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
-	void rightClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
+	void clickPressedArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
+	void showPopupArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
+	void gestureArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
 
 	void artifactRemoved(const ArtifactLocation & artLoc) override;
 	void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw) override;

+ 29 - 23
client/windows/CHeroBackpackWindow.cpp

@@ -19,34 +19,22 @@
 #include "render/Canvas.h"
 #include "CPlayerInterface.h"
 
-CHeroBackpackWindow::CHeroBackpackWindow()
+CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero)
 	: CWindowObject((EOptions)0)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
 	stretchedBackground = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, 0, 0));
-}
-
-CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero)
-	: CHeroBackpackWindow()
-{
-	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
-
-	arts = std::make_shared<CArtifactsOfHeroBackpack>(Point(windowMargin, windowMargin));
+	arts = std::make_shared<CArtifactsOfHeroBackpack>();
+	arts->moveBy(Point(windowMargin, windowMargin));
 	addSetAndCallbacks(arts);
 	arts->setHero(hero);
 	addCloseCallback(std::bind(&CHeroBackpackWindow::close, this));
-
-	init();
-	center();
-}
-
-void CHeroBackpackWindow::init()
-{
 	quitButton = std::make_shared<CButton>(Point(), AnimationPath::builtin("IOKAY32.def"), CButton::tooltip(""), [this]() { close(); }, EShortcut::GLOBAL_RETURN);
 	pos.w = stretchedBackground->pos.w = arts->pos.w + 2 * windowMargin;
 	pos.h = stretchedBackground->pos.h = arts->pos.h + quitButton->pos.h + 3 * windowMargin;
 	quitButton->moveTo(Point(pos.x + pos.w / 2 - quitButton->pos.w / 2, pos.y + arts->pos.h + 2 * windowMargin));
+	center();
 }
 
 void CHeroBackpackWindow::showAll(Canvas & to)
@@ -56,26 +44,44 @@ void CHeroBackpackWindow::showAll(Canvas & to)
 }
 
 CHeroQuickBackpackWindow::CHeroQuickBackpackWindow(const CGHeroInstance * hero, ArtifactPosition targetSlot)
-	: CHeroBackpackWindow()
+	: CWindowObject((EOptions)0)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
-	auto artsQuickBp = std::make_shared<CArtifactsOfHeroQuickBackpack>(Point(windowMargin, windowMargin), targetSlot);
-	addSetAndCallbacks(static_cast<std::weak_ptr<CArtifactsOfHeroQuickBackpack>>(artsQuickBp));
-	arts = artsQuickBp;
+	stretchedBackground = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, 0, 0));
+	arts = std::make_shared<CArtifactsOfHeroQuickBackpack>(targetSlot);
+	arts->moveBy(Point(windowMargin, windowMargin));
+	addSetAndCallbacks(static_cast<std::weak_ptr<CArtifactsOfHeroQuickBackpack>>(arts));
 	arts->setHero(hero);
 	addCloseCallback(std::bind(&CHeroQuickBackpackWindow::close, this));
+	addUsedEvents(GESTURE);
+	pos.w = stretchedBackground->pos.w = arts->pos.w + 2 * windowMargin;
+	pos.h = stretchedBackground->pos.h = arts->pos.h + windowMargin;
+}
+
+void CHeroQuickBackpackWindow::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
+{
+	if(on)
+		return;
+
+	arts->swapSelected();
+	close();
+}
 
-	init();
+void CHeroQuickBackpackWindow::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
+{
+	arts->selectSlotAt(currentPosition);
+	redraw();
 }
 
 void CHeroQuickBackpackWindow::showAll(Canvas & to)
 {
 	if(arts->getSlotsNum() == 0)
 	{
+		// Dirty solution for closing that window
 		close();
 		return;
 	}
-
-	CHeroBackpackWindow::showAll(to);
+	CMessage::drawBorder(PlayerColor(LOCPLINT->playerID), to.getInternalSurface(), pos.w + 28, pos.h + 29, pos.x - 14, pos.y - 15);
+	CIntObject::showAll(to);
 }

+ 7 - 3
client/windows/CHeroBackpackWindow.h

@@ -17,7 +17,6 @@ class CFilledTexture;
 class CHeroBackpackWindow : public CWindowObject, public CWindowWithArtifacts
 {
 public:
-	CHeroBackpackWindow();
 	CHeroBackpackWindow(const CGHeroInstance * hero);
 	
 protected:
@@ -26,15 +25,20 @@ protected:
 	std::shared_ptr<CFilledTexture> stretchedBackground;
 	const int windowMargin = 5;
 
-	void init();
 	void showAll(Canvas & to) override;
 };
 
-class CHeroQuickBackpackWindow : public CHeroBackpackWindow
+class CHeroQuickBackpackWindow : public CWindowObject, public CWindowWithArtifacts
 {
 public:
 	CHeroQuickBackpackWindow(const CGHeroInstance * hero, ArtifactPosition targetSlot);
+	void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
+	void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
 
 private:
+	std::shared_ptr<CArtifactsOfHeroQuickBackpack> arts;
+	std::shared_ptr<CFilledTexture> stretchedBackground;
+	const int windowMargin = 5;
+
 	void showAll(Canvas & to) override;
 };

+ 0 - 3
lib/CArtifactInstance.cpp

@@ -64,10 +64,7 @@ SpellID CScrollArtifactInstance::getScrollSpellID() const
 	auto artInst = static_cast<const CArtifactInstance*>(this);
 	const auto bonus = artInst->getBonusLocalFirst(Selector::type()(BonusType::SPELL));
 	if(!bonus)
-	{
-		logMod->warn("Warning: %s doesn't bear any spell!", artInst->nodeName());
 		return SpellID::NONE;
-	}
 	return bonus->subtype.as<SpellID>();
 }