|
|
@@ -15,6 +15,7 @@
|
|
|
|
|
|
#include "../gui/CGuiHandler.h"
|
|
|
#include "../gui/WindowHandler.h"
|
|
|
+#include "../render/IImage.h"
|
|
|
#include "../windows/CCreatureWindow.h"
|
|
|
#include "../windows/GUIClasses.h"
|
|
|
#include "../CGameInfo.h"
|
|
|
@@ -29,6 +30,90 @@
|
|
|
#include "../../lib/TextOperations.h"
|
|
|
#include "../../lib/gameState/CGameState.h"
|
|
|
|
|
|
+RadialMenuItem::RadialMenuItem(std::string imageName, std::function<void()> callback)
|
|
|
+ : callback(callback)
|
|
|
+{
|
|
|
+ OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
|
|
+
|
|
|
+ image = IImage::createFromFile("radialMenu/" + imageName);
|
|
|
+ picture = std::make_shared<CPicture>(image, Point(0,0));
|
|
|
+ pos = picture->pos;
|
|
|
+}
|
|
|
+
|
|
|
+bool RadialMenuItem::isInside(const Point & position)
|
|
|
+{
|
|
|
+ Point localPosition = position - pos.topLeft();
|
|
|
+
|
|
|
+ return !image->isTransparent(localPosition);
|
|
|
+}
|
|
|
+
|
|
|
+void RadialMenuItem::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void RadialMenuItem::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+RadialMenu::RadialMenu(CGarrisonInt * army, CGarrisonSlot * slot)
|
|
|
+{
|
|
|
+ OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
|
|
+
|
|
|
+ bool isExchange = army->armedObjs[0] && army->armedObjs[1]; // two armies exist
|
|
|
+
|
|
|
+ addItem(ITEM_NW, "stackMerge", [=](){army->bulkMergeStacks(slot);});
|
|
|
+ addItem(ITEM_NE, "stackInfo", [=](){slot->viewInfo();});
|
|
|
+
|
|
|
+ addItem(ITEM_WW, "stackSplitOne", [=](){slot->splitIntoParts(slot->upg, 1); });
|
|
|
+ addItem(ITEM_EE, "stackSplitEqual", [=](){army->bulkSmartSplitStack(slot);});
|
|
|
+
|
|
|
+ if (isExchange)
|
|
|
+ {
|
|
|
+ addItem(ITEM_SW, "stackMove", [=](){army->moveStackToAnotherArmy(slot);});
|
|
|
+ //FIXME: addItem(ITEM_SE, "stackSplitDialog", [=](){slot->split();});
|
|
|
+ }
|
|
|
+
|
|
|
+ for(const auto & item : items)
|
|
|
+ pos = pos.include(item->pos);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void RadialMenu::addItem(const Point & offset, const std::string & path, std::function<void()> callback )
|
|
|
+{
|
|
|
+ auto item = std::make_shared<RadialMenuItem>(path, callback);
|
|
|
+
|
|
|
+ item->moveBy(offset);
|
|
|
+
|
|
|
+ items.push_back(item);
|
|
|
+}
|
|
|
+
|
|
|
+void RadialMenu::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void RadialMenu::show(Canvas & to)
|
|
|
+{
|
|
|
+ showAll(to);
|
|
|
+}
|
|
|
+
|
|
|
+void RadialMenu::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
|
|
+{
|
|
|
+ if (!on)
|
|
|
+ {
|
|
|
+ for(const auto & item : items)
|
|
|
+ {
|
|
|
+ if (item->isInside(finalPosition))
|
|
|
+ {
|
|
|
+ item->callback();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void CGarrisonSlot::setHighlight(bool on)
|
|
|
{
|
|
|
if (on)
|
|
|
@@ -227,8 +312,6 @@ bool CGarrisonSlot::highlightOrDropArtifact()
|
|
|
bool CGarrisonSlot::split()
|
|
|
{
|
|
|
const CGarrisonSlot * selection = owner->getSelection();
|
|
|
- owner->p2 = ID; // store the second stack pos
|
|
|
- owner->pb = upg; // store the second stack owner (up or down army)
|
|
|
owner->setSplittingMode(false);
|
|
|
|
|
|
int minLeft=0, minRight=0;
|
|
|
@@ -252,8 +335,12 @@ bool CGarrisonSlot::split()
|
|
|
int countLeft = selection->myStack ? selection->myStack->count : 0;
|
|
|
int countRight = myStack ? myStack->count : 0;
|
|
|
|
|
|
- GH.windows().createAndPushWindow<CSplitWindow>(selection->creature, std::bind(&CGarrisonInt::splitStacks, owner, _1, _2),
|
|
|
- minLeft, minRight, countLeft, countRight);
|
|
|
+ auto splitFunctor = [this, selection](int amountLeft, int amountRight)
|
|
|
+ {
|
|
|
+ owner->splitStacks(selection, owner->armedObjs[upg], ID, amountRight);
|
|
|
+ };
|
|
|
+
|
|
|
+ GH.windows().createAndPushWindow<CSplitWindow>(selection->creature, splitFunctor, minLeft, minRight, countLeft, countRight);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -349,17 +436,50 @@ void CGarrisonSlot::clickPressed(const Point & cursorPosition)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void CGarrisonSlot::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
|
|
|
+{
|
|
|
+ assert(radialMenu);
|
|
|
+
|
|
|
+ if (radialMenu)
|
|
|
+ radialMenu->gesturePanning(initialPosition, currentPosition, lastUpdateDistance);
|
|
|
+}
|
|
|
+
|
|
|
+void CGarrisonSlot::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
|
|
+{
|
|
|
+ if (on)
|
|
|
+ {
|
|
|
+ OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
|
|
+
|
|
|
+ radialMenu = std::make_shared<RadialMenu>(owner, this);
|
|
|
+ radialMenu->center(pos.center());
|
|
|
+
|
|
|
+ auto topParent = parent;
|
|
|
+ while (topParent->parent)
|
|
|
+ topParent = topParent->parent;
|
|
|
+
|
|
|
+ // Add radial menu to current window / topmost parent for proper rendering order
|
|
|
+ topParent->addChild(radialMenu.get(), false);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ radialMenu->gesture(on, initialPosition, finalPosition);
|
|
|
+ radialMenu.reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ GH.windows().totalRedraw();
|
|
|
+}
|
|
|
+
|
|
|
void CGarrisonSlot::update()
|
|
|
{
|
|
|
if(getObj() != nullptr)
|
|
|
{
|
|
|
- addUsedEvents(LCLICK | SHOW_POPUP | HOVER);
|
|
|
+ addUsedEvents(LCLICK | SHOW_POPUP | GESTURE | HOVER);
|
|
|
myStack = getObj()->getStackPtr(ID);
|
|
|
creature = myStack ? myStack->type : nullptr;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- removeUsedEvents(LCLICK | SHOW_POPUP | HOVER);
|
|
|
+ removeUsedEvents(LCLICK | SHOW_POPUP | GESTURE | HOVER);
|
|
|
myStack = nullptr;
|
|
|
creature = nullptr;
|
|
|
}
|
|
|
@@ -434,9 +554,7 @@ void CGarrisonSlot::splitIntoParts(CGarrisonSlot::EGarrisonType type, int amount
|
|
|
if(empty == SlotID())
|
|
|
return;
|
|
|
|
|
|
- owner->pb = type;
|
|
|
- owner->p2 = empty;
|
|
|
- owner->splitStacks(1, amount);
|
|
|
+ owner->splitStacks(this, owner->armedObjs[type], empty, amount);
|
|
|
}
|
|
|
|
|
|
bool CGarrisonSlot::handleSplittingShortcuts()
|
|
|
@@ -555,9 +673,9 @@ void CGarrisonInt::splitClick()
|
|
|
setSplittingMode(!getSplittingMode());
|
|
|
redraw();
|
|
|
}
|
|
|
-void CGarrisonInt::splitStacks(int, int amountRight)
|
|
|
+void CGarrisonInt::splitStacks(const CGarrisonSlot * from, const CArmedInstance * armyDest, SlotID slotDest, int amount )
|
|
|
{
|
|
|
- LOCPLINT->cb->splitStack(armedObjs[getSelection()->upg], armedObjs[pb], getSelection()->ID, p2, amountRight);
|
|
|
+ LOCPLINT->cb->splitStack(armedObjs[from->upg], armyDest, from->ID, slotDest, amount);
|
|
|
}
|
|
|
|
|
|
bool CGarrisonInt::checkSelected(const CGarrisonSlot * selected, TQuantity min) const
|
|
|
@@ -669,17 +787,14 @@ void CGarrisonInt::bulkSmartSplitStack(const CGarrisonSlot * selected)
|
|
|
LOCPLINT->cb->bulkSmartSplitStack(armedObjs[type]->id, selected->ID);
|
|
|
}
|
|
|
|
|
|
-CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point & garsOffset,
|
|
|
- const CArmedInstance * s1, const CArmedInstance * s2,
|
|
|
- bool _removableUnits, bool smallImgs, ESlotsLayout _layout)
|
|
|
- : highlighted(nullptr),
|
|
|
- inSplittingMode(false),
|
|
|
- interx(inx),
|
|
|
- garOffset(garsOffset),
|
|
|
- pb(false),
|
|
|
- smallIcons(smallImgs),
|
|
|
- removableUnits(_removableUnits),
|
|
|
- layout(_layout)
|
|
|
+CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point & garsOffset, const CArmedInstance * s1, const CArmedInstance * s2, bool _removableUnits, bool smallImgs, ESlotsLayout _layout)
|
|
|
+ : highlighted(nullptr)
|
|
|
+ , inSplittingMode(false)
|
|
|
+ , interx(inx)
|
|
|
+ , garOffset(garsOffset)
|
|
|
+ , smallIcons(smallImgs)
|
|
|
+ , removableUnits(_removableUnits)
|
|
|
+ , layout(_layout)
|
|
|
{
|
|
|
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
|
|
|