|
|
@ -0,0 +1,218 @@ |
|
|
|
#include "pie-menu.hpp"
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
PieMenu::PieMenu(Tweener* tweener): |
|
|
|
tweener(tweener), |
|
|
|
scaleUpTween(nullptr), |
|
|
|
scaleDownTween(nullptr), |
|
|
|
scale(1.0f), |
|
|
|
selectionIndex(0), |
|
|
|
dragging(false), |
|
|
|
dragStart(0.0f) |
|
|
|
{ |
|
|
|
// Setup fullscreen container
|
|
|
|
fullscreenContainer.addChild(&croppedContainer); |
|
|
|
fullscreenContainer.setMouseMovedCallback(std::bind(PieMenu::mouseMoved, this, std::placeholders::_1, std::placeholders::_2)); |
|
|
|
fullscreenContainer.setMousePressedCallback(std::bind(PieMenu::mouseButtonPressed, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); |
|
|
|
fullscreenContainer.setMouseReleasedCallback(std::bind(PieMenu::mouseButtonReleased, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); |
|
|
|
|
|
|
|
// Setup cropped container
|
|
|
|
croppedContainer.addChild(&scalingContainer); |
|
|
|
|
|
|
|
// Setup scaling container
|
|
|
|
scalingContainer.setAnchor(Vector2(0.5f)); |
|
|
|
|
|
|
|
// Create tweens
|
|
|
|
scaleUpTween = new Tween<float>(EaseFunction::OUT_SINE, 0.0f, 0.1f, 0.0f, 1.0f); |
|
|
|
scaleUpTween->setUpdateCallback(std::bind(PieMenu::setScale, this, std::placeholders::_1)); |
|
|
|
scaleDownTween = new Tween<float>(EaseFunction::IN_SINE, 0.0f, 0.1f, 1.0f, -1.0f); |
|
|
|
scaleDownTween->setUpdateCallback(std::bind(PieMenu::setScale, this, std::placeholders::_1)); |
|
|
|
|
|
|
|
// Add tweens
|
|
|
|
tweener->addTween(scaleUpTween); |
|
|
|
tweener->addTween(scaleDownTween); |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::resize() |
|
|
|
{ |
|
|
|
float iconDistance = 0.0f; |
|
|
|
|
|
|
|
if (fullscreenContainer.getParent() == nullptr) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Resize fullscreen container
|
|
|
|
fullscreenContainer.setDimensions(fullscreenContainer.getParent()->getDimensions()); |
|
|
|
|
|
|
|
// Resize cropped container
|
|
|
|
croppedContainer.setDimensions(Vector2(options[0]->getTexture()->getWidth(), options[0]->getTexture()->getHeight())); |
|
|
|
|
|
|
|
// Place options
|
|
|
|
for (std::size_t i = 0; i < options.size(); ++i) |
|
|
|
{ |
|
|
|
float angle = glm::radians(360.0f) / static_cast<float>(i + 1) / static_cast<float>(options.size()); |
|
|
|
|
|
|
|
options[i]->setAnchor(Vector2(0.5f, 0.5f)); |
|
|
|
options[i]->setTranslation(Vector2(0.0f, 0.0f)); |
|
|
|
|
|
|
|
icons[i]->setAnchor(Vector2(0.5f, 0.5f)); |
|
|
|
icons[i]->setTranslation(Vector2(0.0f, 0.0f)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::setScale(float scale) |
|
|
|
{ |
|
|
|
for (std::size_t i = 0; i < options.size(); ++i) |
|
|
|
{ |
|
|
|
options[i]->setDimensions(Vector2(options[i]->getTexture()->getWidth(), options[i]->getTexture()->getHeight()) * scale); |
|
|
|
icons[i]->setDimensions(Vector2(icons[i]->getTexture()->getWidth(), icons[i]->getTexture()->getHeight()) * scale); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::addOption(Texture* backgroundTexture, Texture* iconTexture, std::function<void()> selectedCallback, std::function<void()> deselectedCallback) |
|
|
|
{ |
|
|
|
// Allocate new option
|
|
|
|
UIImage* option = new UIImage(); |
|
|
|
option->setTexture(backgroundTexture); |
|
|
|
option->setDimensions(Vector2(backgroundTexture->getWidth(), backgroundTexture->getHeight())); |
|
|
|
option->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f)); |
|
|
|
options.push_back(option); |
|
|
|
|
|
|
|
UIImage* icon = new UIImage(); |
|
|
|
icon->setTexture(iconTexture); |
|
|
|
icon->setDimensions(Vector2(iconTexture->getWidth(), iconTexture->getHeight())); |
|
|
|
icon->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f)); |
|
|
|
icons.push_back(icon); |
|
|
|
|
|
|
|
// Add icon to option
|
|
|
|
scalingContainer.addChild(icon); |
|
|
|
|
|
|
|
// Add option to menu
|
|
|
|
scalingContainer.addChild(option); |
|
|
|
|
|
|
|
// Setup callbacks
|
|
|
|
selectedCallbacks.push_back(selectedCallback); |
|
|
|
deselectedCallbacks.push_back(deselectedCallback); |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::select(std::size_t index) |
|
|
|
{ |
|
|
|
if (index != selectionIndex && selectionIndex < options.size()) |
|
|
|
{ |
|
|
|
deselect(selectionIndex); |
|
|
|
} |
|
|
|
|
|
|
|
selectionIndex = index; |
|
|
|
selectedCallbacks[index](); |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::deselect(std::size_t index) |
|
|
|
{ |
|
|
|
deselectedCallbacks[index](); |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::highlight(std::size_t index) |
|
|
|
{ |
|
|
|
options[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 1.0f)); |
|
|
|
icons[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 1.0f)); |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::unhighlight(std::size_t index) |
|
|
|
{ |
|
|
|
options[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f)); |
|
|
|
icons[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f)); |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::mouseMoved(int x, int y) |
|
|
|
{ |
|
|
|
if (dragging) |
|
|
|
{ |
|
|
|
Vector2 direction = Vector2(x, y) - dragStart; |
|
|
|
if (direction.x != 0.0f || direction.y != 0.0f) |
|
|
|
{ |
|
|
|
direction = glm::normalize(direction); |
|
|
|
|
|
|
|
// Calculate arc length
|
|
|
|
float arcLength = glm::radians(360.0f) / static_cast<float>(options.size()); |
|
|
|
|
|
|
|
// Calculate angle between cursor and pie menu
|
|
|
|
float angle = std::atan2(direction.y, direction.x) + glm::radians(90.0f) + arcLength * 0.5f; |
|
|
|
while (angle < 0.0f) angle += glm::radians(360.0f); |
|
|
|
|
|
|
|
// Determine option index from angle
|
|
|
|
std::size_t index = static_cast<std::size_t>(angle / arcLength); |
|
|
|
|
|
|
|
if (index != highlightedIndex) |
|
|
|
{ |
|
|
|
if (highlightedIndex < options.size()) |
|
|
|
{ |
|
|
|
unhighlight(highlightedIndex); |
|
|
|
} |
|
|
|
|
|
|
|
highlight(index); |
|
|
|
highlightedIndex = index; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::mouseButtonPressed(int button, int x, int y) |
|
|
|
{ |
|
|
|
if (button == 3) |
|
|
|
{ |
|
|
|
// Start dragging
|
|
|
|
dragging = true; |
|
|
|
dragStart.x = x; |
|
|
|
dragStart.y = y; |
|
|
|
|
|
|
|
// Set pie menu position
|
|
|
|
Vector2 halfDimensions = croppedContainer.getDimensions() * 0.5f; |
|
|
|
croppedContainer.setTranslation(Vector2(x - halfDimensions.x, y - halfDimensions.y)); |
|
|
|
|
|
|
|
// Clear highlights
|
|
|
|
for (std::size_t i = 0; i < options.size(); ++i) |
|
|
|
{ |
|
|
|
unhighlight(i); |
|
|
|
} |
|
|
|
|
|
|
|
// Reset highlighted index
|
|
|
|
highlightedIndex = options.size(); |
|
|
|
|
|
|
|
// Show pie menu
|
|
|
|
fullscreenContainer.setVisible(true); |
|
|
|
|
|
|
|
// Start scale-up tween
|
|
|
|
scaleDownTween->stop(); |
|
|
|
scaleUpTween->start(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void PieMenu::mouseButtonReleased(int button, int x, int y) |
|
|
|
{ |
|
|
|
if (button == 3) |
|
|
|
{ |
|
|
|
// Stop dragging
|
|
|
|
dragging = false; |
|
|
|
|
|
|
|
// Select highlighted index
|
|
|
|
if (highlightedIndex != selectionIndex && highlightedIndex < options.size()) |
|
|
|
{ |
|
|
|
select(highlightedIndex); |
|
|
|
} |
|
|
|
|
|
|
|
// Clear highlights
|
|
|
|
for (std::size_t i = 0; i < options.size(); ++i) |
|
|
|
{ |
|
|
|
unhighlight(i); |
|
|
|
} |
|
|
|
|
|
|
|
// Reset highlighted index
|
|
|
|
highlightedIndex = options.size(); |
|
|
|
|
|
|
|
// Start scale-down tween
|
|
|
|
scaleUpTween->stop(); |
|
|
|
scaleDownTween->start(); |
|
|
|
//fullscreenContainer.setVisible(false);
|
|
|
|
} |
|
|
|
} |