💿🐜 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.

246 lines
4.5 KiB

  1. /*
  2. * Copyright (C) 2017 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "menu.hpp"
  20. #include "ui.hpp"
  21. #include <algorithm>
  22. MenuItem::MenuItem(Menu* parent, std::size_t index):
  23. parent(parent),
  24. index(index),
  25. selectedCallback(nullptr),
  26. deselectedCallback(nullptr),
  27. activatedCallback(nullptr)
  28. {
  29. label = new UILabel();
  30. label->setMouseOverCallback(std::bind(&Menu::select, parent, index));
  31. label->setMouseMovedCallback(std::bind(&Menu::select, parent, index));
  32. label->setMousePressedCallback(std::bind(&Menu::activate, parent));
  33. }
  34. MenuItem::~MenuItem()
  35. {
  36. delete label;
  37. }
  38. void MenuItem::select()
  39. {
  40. if (selectedCallback != nullptr)
  41. {
  42. selectedCallback();
  43. }
  44. }
  45. void MenuItem::deselect()
  46. {
  47. if (deselectedCallback != nullptr)
  48. {
  49. deselectedCallback();
  50. }
  51. }
  52. void MenuItem::activate()
  53. {
  54. if (activatedCallback != nullptr)
  55. {
  56. activatedCallback();
  57. }
  58. }
  59. void MenuItem::setSelectedCallback(std::function<void()> callback)
  60. {
  61. this->selectedCallback = callback = callback;
  62. }
  63. void MenuItem::setDeselectedCallback(std::function<void()> callback)
  64. {
  65. this->deselectedCallback = callback;
  66. }
  67. void MenuItem::setActivatedCallback(std::function<void()> callback)
  68. {
  69. this->activatedCallback = callback;
  70. }
  71. void MenuItem::setLabel(const std::string& text)
  72. {
  73. label->setText(text);
  74. parent->resize();
  75. }
  76. bool MenuItem::isSelected() const
  77. {
  78. return (parent->getSelectedItem() == this);
  79. }
  80. Menu::Menu():
  81. selectedItem(nullptr),
  82. enteredCallback(nullptr),
  83. exitedCallback(nullptr),
  84. font(nullptr),
  85. lineSpacing(1.0f)
  86. {
  87. container = new UIContainer();
  88. resize();
  89. }
  90. Menu::~Menu()
  91. {
  92. removeItems();
  93. delete container;
  94. }
  95. void Menu::enter()
  96. {
  97. if (enteredCallback != nullptr)
  98. {
  99. enteredCallback();
  100. }
  101. }
  102. void Menu::exit()
  103. {
  104. if (exitedCallback != nullptr)
  105. {
  106. exitedCallback();
  107. }
  108. }
  109. MenuItem* Menu::addItem()
  110. {
  111. // Allocate item and add to items
  112. MenuItem* item = new MenuItem(this, items.size());
  113. items.push_back(item);
  114. // Set item label font
  115. item->label->setFont(font);
  116. item->label->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.35f));
  117. // Add item label to UI container
  118. container->addChild(item->label);
  119. // Resize UI container
  120. resize();
  121. return item;
  122. }
  123. void Menu::removeItems()
  124. {
  125. for (MenuItem* item: items)
  126. {
  127. // Remove label from UI container
  128. container->removeChild(item->label);
  129. delete item;
  130. }
  131. items.clear();
  132. resize();
  133. }
  134. void Menu::setEnteredCallback(std::function<void()> callback)
  135. {
  136. this->enteredCallback = callback;
  137. }
  138. void Menu::setExitedCallback(std::function<void()> callback)
  139. {
  140. this->exitedCallback = callback;
  141. }
  142. void Menu::setFont(Font* font)
  143. {
  144. this->font = font;
  145. for (MenuItem* item: items)
  146. {
  147. item->label->setFont(font);
  148. }
  149. resize();
  150. }
  151. void Menu::setLineSpacing(float spacing)
  152. {
  153. lineSpacing = spacing;
  154. resize();
  155. }
  156. void Menu::deselect()
  157. {
  158. if (selectedItem != nullptr)
  159. {
  160. selectedItem->deselect();
  161. selectedItem->label->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.35f));
  162. selectedItem = nullptr;
  163. }
  164. }
  165. void Menu::select(std::size_t index)
  166. {
  167. deselect();
  168. MenuItem* item = items[index];
  169. item->select();
  170. selectedItem = item;
  171. selectedItem->label->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 1.0f));
  172. }
  173. void Menu::activate()
  174. {
  175. if (selectedItem != nullptr)
  176. {
  177. selectedItem->activate();
  178. }
  179. }
  180. void Menu::resize()
  181. {
  182. if (!font)
  183. {
  184. container->setDimensions(Vector2(0.0f));
  185. }
  186. else
  187. {
  188. Vector2 dimensions(0.0f);
  189. for (std::size_t i = 0; i < items.size(); ++i)
  190. {
  191. const MenuItem* item = items[i];
  192. item->label->setTranslation(Vector2(0.0f, static_cast<int>(font->getMetrics().getHeight() * lineSpacing * static_cast<float>(i))));
  193. dimensions.x = std::max<float>(dimensions.x, item->label->getDimensions().x);
  194. if (!i)
  195. {
  196. dimensions.y += font->getMetrics().getHeight();
  197. }
  198. else
  199. {
  200. dimensions.y += font->getMetrics().getHeight() * lineSpacing;
  201. }
  202. }
  203. container->setDimensions(dimensions);
  204. }
  205. }