💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
6.0 KiB

  1. #include "pie-menu.hpp"
  2. #include <cmath>
  3. PieMenu::PieMenu(Tweener* tweener):
  4. tweener(tweener),
  5. scaleUpTween(nullptr),
  6. scaleDownTween(nullptr),
  7. scale(1.0f),
  8. selectionIndex(0),
  9. dragging(false),
  10. dragStart(0.0f)
  11. {
  12. // Setup fullscreen container
  13. fullscreenContainer.addChild(&croppedContainer);
  14. fullscreenContainer.setMouseMovedCallback(std::bind(&PieMenu::mouseMoved, this, std::placeholders::_1, std::placeholders::_2));
  15. fullscreenContainer.setMousePressedCallback(std::bind(&PieMenu::mouseButtonPressed, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
  16. fullscreenContainer.setMouseReleasedCallback(std::bind(&PieMenu::mouseButtonReleased, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
  17. // Setup cropped container
  18. croppedContainer.addChild(&scalingContainer);
  19. // Setup scaling container
  20. scalingContainer.setAnchor(Vector2(0.5f));
  21. // Create tweens
  22. scaleUpTween = new Tween<float>(EaseFunction::OUT_SINE, 0.0f, 0.1f, 0.0f, 1.0f);
  23. scaleUpTween->setUpdateCallback(std::bind(&PieMenu::setScale, this, std::placeholders::_1));
  24. scaleDownTween = new Tween<float>(EaseFunction::IN_SINE, 0.0f, 0.1f, 1.0f, -1.0f);
  25. scaleDownTween->setUpdateCallback(std::bind(&PieMenu::setScale, this, std::placeholders::_1));
  26. // Add tweens
  27. tweener->addTween(scaleUpTween);
  28. tweener->addTween(scaleDownTween);
  29. }
  30. void PieMenu::resize()
  31. {
  32. float iconDistance = 0.0f;
  33. if (fullscreenContainer.getParent() == nullptr)
  34. {
  35. return;
  36. }
  37. // Resize fullscreen container
  38. fullscreenContainer.setDimensions(fullscreenContainer.getParent()->getDimensions());
  39. // Resize cropped container
  40. croppedContainer.setDimensions(Vector2(options[0]->getTexture()->getWidth(), options[0]->getTexture()->getHeight()));
  41. // Place options
  42. for (std::size_t i = 0; i < options.size(); ++i)
  43. {
  44. float angle = glm::radians(360.0f) / static_cast<float>(i + 1) / static_cast<float>(options.size());
  45. options[i]->setAnchor(Vector2(0.5f, 0.5f));
  46. options[i]->setTranslation(Vector2(0.0f, 0.0f));
  47. icons[i]->setAnchor(Vector2(0.5f, 0.5f));
  48. icons[i]->setTranslation(Vector2(0.0f, 0.0f));
  49. }
  50. }
  51. void PieMenu::setScale(float scale)
  52. {
  53. for (std::size_t i = 0; i < options.size(); ++i)
  54. {
  55. options[i]->setDimensions(Vector2(options[i]->getTexture()->getWidth(), options[i]->getTexture()->getHeight()) * scale);
  56. icons[i]->setDimensions(Vector2(icons[i]->getTexture()->getWidth(), icons[i]->getTexture()->getHeight()) * scale);
  57. }
  58. }
  59. void PieMenu::addOption(Texture* backgroundTexture, Texture* iconTexture, std::function<void()> selectedCallback, std::function<void()> deselectedCallback)
  60. {
  61. // Allocate new option
  62. UIImage* option = new UIImage();
  63. option->setTexture(backgroundTexture);
  64. option->setDimensions(Vector2(backgroundTexture->getWidth(), backgroundTexture->getHeight()));
  65. option->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f));
  66. options.push_back(option);
  67. UIImage* icon = new UIImage();
  68. icon->setTexture(iconTexture);
  69. icon->setDimensions(Vector2(iconTexture->getWidth(), iconTexture->getHeight()));
  70. icon->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f));
  71. icons.push_back(icon);
  72. // Add icon to option
  73. scalingContainer.addChild(icon);
  74. // Add option to menu
  75. scalingContainer.addChild(option);
  76. // Setup callbacks
  77. selectedCallbacks.push_back(selectedCallback);
  78. deselectedCallbacks.push_back(deselectedCallback);
  79. }
  80. void PieMenu::select(std::size_t index)
  81. {
  82. if (index != selectionIndex && selectionIndex < options.size())
  83. {
  84. deselect(selectionIndex);
  85. }
  86. selectionIndex = index;
  87. selectedCallbacks[index]();
  88. }
  89. void PieMenu::deselect(std::size_t index)
  90. {
  91. deselectedCallbacks[index]();
  92. }
  93. void PieMenu::highlight(std::size_t index)
  94. {
  95. options[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 1.0f));
  96. icons[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 1.0f));
  97. }
  98. void PieMenu::unhighlight(std::size_t index)
  99. {
  100. options[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f));
  101. icons[index]->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.50f));
  102. }
  103. void PieMenu::mouseMoved(int x, int y)
  104. {
  105. if (dragging)
  106. {
  107. Vector2 direction = Vector2(x, y) - dragStart;
  108. if (direction.x != 0.0f || direction.y != 0.0f)
  109. {
  110. direction = glm::normalize(direction);
  111. // Calculate arc length
  112. float arcLength = glm::radians(360.0f) / static_cast<float>(options.size());
  113. // Calculate angle between cursor and pie menu
  114. float angle = std::atan2(direction.y, direction.x) + glm::radians(90.0f) + arcLength * 0.5f;
  115. while (angle < 0.0f) angle += glm::radians(360.0f);
  116. // Determine option index from angle
  117. std::size_t index = static_cast<std::size_t>(angle / arcLength);
  118. if (index != highlightedIndex)
  119. {
  120. if (highlightedIndex < options.size())
  121. {
  122. unhighlight(highlightedIndex);
  123. }
  124. highlight(index);
  125. highlightedIndex = index;
  126. }
  127. }
  128. }
  129. }
  130. void PieMenu::mouseButtonPressed(int button, int x, int y)
  131. {
  132. if (button == 3)
  133. {
  134. // Start dragging
  135. dragging = true;
  136. dragStart.x = x;
  137. dragStart.y = y;
  138. // Set pie menu position
  139. Vector2 halfDimensions = croppedContainer.getDimensions() * 0.5f;
  140. croppedContainer.setTranslation(Vector2(x - halfDimensions.x, y - halfDimensions.y));
  141. // Clear highlights
  142. for (std::size_t i = 0; i < options.size(); ++i)
  143. {
  144. unhighlight(i);
  145. }
  146. // Reset highlighted index
  147. highlightedIndex = options.size();
  148. // Show pie menu
  149. fullscreenContainer.setVisible(true);
  150. // Start scale-up tween
  151. scaleDownTween->stop();
  152. scaleUpTween->start();
  153. }
  154. }
  155. void PieMenu::mouseButtonReleased(int button, int x, int y)
  156. {
  157. if (button == 3)
  158. {
  159. // Stop dragging
  160. dragging = false;
  161. // Select highlighted index
  162. if (highlightedIndex != selectionIndex && highlightedIndex < options.size())
  163. {
  164. select(highlightedIndex);
  165. }
  166. // Clear highlights
  167. for (std::size_t i = 0; i < options.size(); ++i)
  168. {
  169. unhighlight(i);
  170. }
  171. // Reset highlighted index
  172. highlightedIndex = options.size();
  173. // Start scale-down tween
  174. scaleUpTween->stop();
  175. scaleDownTween->start();
  176. //fullscreenContainer.setVisible(false);
  177. }
  178. }