2023-07-07 00:08:29 +02:00
|
|
|
/*
|
|
|
|
* RadialMenu.cpp, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "StdInc.h"
|
|
|
|
#include "RadialMenu.h"
|
|
|
|
|
|
|
|
#include "Images.h"
|
2023-07-16 13:49:48 +02:00
|
|
|
#include "TextControls.h"
|
2023-07-07 00:08:29 +02:00
|
|
|
|
|
|
|
#include "../gui/CGuiHandler.h"
|
2023-07-16 13:49:48 +02:00
|
|
|
#include "../gui/WindowHandler.h"
|
2023-07-07 00:08:29 +02:00
|
|
|
#include "../render/IImage.h"
|
|
|
|
|
2023-07-16 16:56:47 +02:00
|
|
|
RadialMenuItem::RadialMenuItem(const std::string & imageName, const std::string & hoverText, const std::function<void()> & callback)
|
2023-07-07 00:08:29 +02:00
|
|
|
: callback(callback)
|
2023-07-16 16:56:47 +02:00
|
|
|
, hoverText(hoverText)
|
2023-07-07 00:08:29 +02:00
|
|
|
{
|
|
|
|
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
|
|
|
|
2023-07-17 14:28:45 +02:00
|
|
|
image = IImage::createFromFile("radialMenu/" + imageName, EImageBlitMode::COLORKEY);
|
2023-07-16 13:49:48 +02:00
|
|
|
picture = std::make_shared<CPicture>(image, Point(0, 0));
|
2023-07-07 00:08:29 +02:00
|
|
|
pos = picture->pos;
|
|
|
|
}
|
|
|
|
|
2023-07-16 16:56:47 +02:00
|
|
|
RadialMenu::RadialMenu(const Point & positionToCenter, const std::vector<RadialMenuConfig> & menuConfig)
|
2023-07-07 00:08:29 +02:00
|
|
|
{
|
|
|
|
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
2023-07-16 13:49:48 +02:00
|
|
|
pos += positionToCenter;
|
2023-07-07 00:08:29 +02:00
|
|
|
|
2023-07-16 16:56:47 +02:00
|
|
|
addItem(Point(0,0), "itemEmpty", "", [](){});
|
2023-07-16 13:49:48 +02:00
|
|
|
|
|
|
|
Point itemSize = items.back()->pos.dimensions();
|
|
|
|
moveBy(-itemSize / 2);
|
|
|
|
|
2023-07-16 16:56:47 +02:00
|
|
|
for (auto const & item : menuConfig)
|
|
|
|
addItem(item.itemPosition, item.imageName, item.hoverText, item.callback);
|
2023-07-07 00:08:29 +02:00
|
|
|
|
2023-07-16 16:56:47 +02:00
|
|
|
statusBar = CGStatusBar::create(-80, -100, "radialMenu/statusBar");
|
2023-07-16 13:49:48 +02:00
|
|
|
|
2023-07-07 00:08:29 +02:00
|
|
|
for(const auto & item : items)
|
|
|
|
pos = pos.include(item->pos);
|
|
|
|
|
2023-07-16 13:49:48 +02:00
|
|
|
fitToScreen(10);
|
|
|
|
|
|
|
|
addUsedEvents(GESTURE);
|
2023-07-07 00:08:29 +02:00
|
|
|
}
|
|
|
|
|
2023-07-16 16:56:47 +02:00
|
|
|
void RadialMenu::addItem(const Point & offset, const std::string & path, const std::string & hoverText, const std::function<void()>& callback )
|
2023-07-07 00:08:29 +02:00
|
|
|
{
|
2023-07-16 16:56:47 +02:00
|
|
|
auto item = std::make_shared<RadialMenuItem>(path, hoverText, callback);
|
2023-07-07 00:08:29 +02:00
|
|
|
|
|
|
|
item->moveBy(offset);
|
|
|
|
|
|
|
|
items.push_back(item);
|
|
|
|
}
|
|
|
|
|
2023-07-19 16:36:05 +02:00
|
|
|
std::shared_ptr<RadialMenuItem> RadialMenu::findNearestItem(const Point & cursorPosition) const
|
2023-07-07 00:08:29 +02:00
|
|
|
{
|
2023-07-19 16:36:05 +02:00
|
|
|
int bestDistance = std::numeric_limits<int>::max();
|
|
|
|
std::shared_ptr<RadialMenuItem> bestItem;
|
2023-07-07 00:08:29 +02:00
|
|
|
|
2023-07-19 16:08:15 +02:00
|
|
|
for(const auto & item : items)
|
|
|
|
{
|
2023-07-19 16:36:05 +02:00
|
|
|
Point vector = item->pos.center() - cursorPosition;
|
|
|
|
|
|
|
|
if (vector.length() < bestDistance)
|
2023-07-19 16:08:15 +02:00
|
|
|
{
|
2023-07-19 16:36:05 +02:00
|
|
|
bestDistance = vector.length();
|
|
|
|
bestItem = item;
|
2023-07-19 16:08:15 +02:00
|
|
|
}
|
|
|
|
}
|
2023-07-19 16:36:05 +02:00
|
|
|
|
|
|
|
assert(bestItem);
|
|
|
|
return bestItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RadialMenu::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
|
|
|
|
{
|
|
|
|
auto item = findNearestItem(currentPosition);
|
|
|
|
GH.statusbar()->write(item->hoverText);
|
2023-07-07 00:08:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RadialMenu::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
|
|
|
{
|
2023-07-19 16:36:05 +02:00
|
|
|
if (on)
|
|
|
|
return;
|
2023-07-16 13:49:48 +02:00
|
|
|
|
2023-07-19 16:36:05 +02:00
|
|
|
auto item = findNearestItem(finalPosition);
|
|
|
|
|
|
|
|
// we need to close this window first so if action spawns a new window it won't be closed instead
|
|
|
|
GH.windows().popWindows(1);
|
|
|
|
item->callback();
|
2023-07-07 00:08:29 +02:00
|
|
|
}
|