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

506 lines
11 KiB

7 years ago
  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. #ifndef UI_HPP
  20. #define UI_HPP
  21. #include "../input.hpp"
  22. #include "../materials.hpp"
  23. #include <vector>
  24. #include <functional>
  25. #include <emergent/emergent.hpp>
  26. using namespace Emergent;
  27. namespace Anchor
  28. {
  29. static const Vector2& TOP_LEFT = Vector2(0.0f, 0.0f);
  30. static const Vector2& TOP_RIGHT = Vector2(1.0f, 0.0f);
  31. static const Vector2& BOTTOM_LEFT = Vector2(0.0f, 1.0f);
  32. static const Vector2& BOTTOM_RIGHT = Vector2(1.0f, 1.0f);
  33. static const Vector2& CENTER = Vector2(0.5f, 0.5f);
  34. }
  35. class UIElement: public MouseMotionObserver, public MouseButtonObserver
  36. {
  37. public:
  38. enum class Type
  39. {
  40. CONTAINER,
  41. LABEL,
  42. IMAGE
  43. };
  44. UIElement();
  45. virtual ~UIElement();
  46. /// Sets the anchor vector. Possible values are 0, 0.5, and 1, corresponding to the left, center, and right, respectively, and the top, center, and bottom.
  47. void setAnchor(const Vector2& anchor);
  48. /// Sets the layer offset, relative to its parent layer + 1
  49. void setLayerOffset(int offset);
  50. /// Sets the local origin of the element
  51. void setOrigin(const Vector2& origin);
  52. /// Sets the translation of the element, relative to its position in its parent element
  53. void setTranslation(const Vector2& translation);
  54. /// Sets the dimensions of the element
  55. void setDimensions(const Vector2& dimensions);
  56. /// Sets the tint color of the element
  57. void setTintColor(const Vector4& color);
  58. /// Sets the visibility of the element
  59. void setVisible(bool visible);
  60. /// Enables or disables callbacks
  61. void setActive(bool active);
  62. /// Returns the type of this element
  63. virtual UIElement::Type getElementType() const = 0;
  64. /// Returns the material of this element
  65. const UIMaterial* getMaterial() const;
  66. /// @copydoc UIElement::getMaterial() const
  67. UIMaterial* getMaterial();
  68. /// Returns the parent of this element
  69. const UIElement* getParent() const;
  70. /// @copydoc UIElement::getParent() const
  71. UIElement* getParent();
  72. /// Returns the number of child elements
  73. std::size_t getChildCount() const;
  74. /// Returns the child element at the specified index
  75. const UIElement* getChild(std::size_t index) const;
  76. /// @copydoc UIElement::getChild() const
  77. UIElement* getChild(std::size_t index);
  78. /// Returns the anchor vector
  79. const Vector2& getAnchor() const;
  80. /// Returns the layer offset
  81. int getLayerOffset() const;
  82. /// Returns the layer of this element
  83. int getLayer() const;
  84. /// Returns the origin of this element
  85. const Vector2& getOrigin() const;
  86. /// Returns the translation of this element, relative to its parent
  87. const Vector2& getTranslation() const;
  88. /// Returns the dimensions of this element
  89. const Vector2& getDimensions() const;
  90. /// Returns the world-space position of this element. Only accurate after update() is called
  91. const Vector2& getPosition() const;
  92. /// Returns the world-space bounds of this element.
  93. const Rect& getBounds() const;
  94. /// Returns the tint color of this element
  95. const Vector4& getTintColor() const;
  96. /// Returns the final color of this element, relative to its ancestor's tint colors
  97. const Vector4& getColor() const;
  98. /// Returns the visibility of this element
  99. bool isVisible() const;
  100. /// Returns `true` if the element is active (callbacks enabled)
  101. bool isActive() const;
  102. /// Calculates the world-space position and bounds of this element and its children
  103. virtual void update();
  104. /// Adds a child to this element
  105. void addChild(UIElement* element);
  106. /// Removes a child from this element
  107. void removeChild(UIElement* element);
  108. void setMouseOverCallback(std::function<void()> callback);
  109. void setMouseOutCallback(std::function<void()> callback);
  110. void setMouseMovedCallback(std::function<void()> callback);
  111. void setMousePressedCallback(std::function<void(int)> callback);
  112. void setMouseReleasedCallback(std::function<void(int)> callback);
  113. void mouseMoved(int x, int y);
  114. void mouseButtonPressed(int button, int x, int y);
  115. void mouseButtonReleased(int button, int x, int y);
  116. protected:
  117. UIMaterial material;
  118. private:
  119. UIElement* parent;
  120. std::vector<UIElement*> children;
  121. Vector2 anchor;
  122. int layerOffset;
  123. int layer;
  124. Vector2 origin;
  125. Vector2 translation;
  126. Vector2 dimensions;
  127. Vector2 position;
  128. Rect bounds;
  129. Vector4 tintColor;
  130. Vector4 color;
  131. bool visible;
  132. bool active;
  133. bool mouseOver;
  134. std::function<void()> mouseOverCallback;
  135. std::function<void()> mouseOutCallback;
  136. std::function<void()> mouseMovedCallback;
  137. std::function<void(int)> mousePressedCallback;
  138. std::function<void(int)> mouseReleasedCallback;
  139. };
  140. inline void UIElement::setAnchor(const Vector2& anchor)
  141. {
  142. this->anchor = anchor;
  143. }
  144. inline void UIElement::setLayerOffset(int offset)
  145. {
  146. this->layerOffset = offset;
  147. }
  148. inline void UIElement::setOrigin(const Vector2& origin)
  149. {
  150. this->origin = origin;
  151. }
  152. inline void UIElement::setTranslation(const Vector2& translation)
  153. {
  154. this->translation = translation;
  155. }
  156. inline void UIElement::setDimensions(const Vector2& dimensions)
  157. {
  158. this->dimensions = dimensions;
  159. }
  160. inline void UIElement::setTintColor(const Vector4& color)
  161. {
  162. this->tintColor = color;
  163. }
  164. inline void UIElement::setVisible(bool visible)
  165. {
  166. this->visible = visible;
  167. }
  168. inline void UIElement::setActive(bool active)
  169. {
  170. this->active = active;
  171. }
  172. inline const UIElement* UIElement::getParent() const
  173. {
  174. return parent;
  175. }
  176. inline const UIMaterial* UIElement::getMaterial() const
  177. {
  178. return &material;
  179. }
  180. inline UIMaterial* UIElement::getMaterial()
  181. {
  182. return &material;
  183. }
  184. inline UIElement* UIElement::getParent()
  185. {
  186. return parent;
  187. }
  188. inline std::size_t UIElement::getChildCount() const
  189. {
  190. return children.size();
  191. }
  192. inline const UIElement* UIElement::getChild(std::size_t index) const
  193. {
  194. return children[index];
  195. }
  196. inline UIElement* UIElement::getChild(std::size_t index)
  197. {
  198. return children[index];
  199. }
  200. inline const Vector2& UIElement::getAnchor() const
  201. {
  202. return anchor;
  203. }
  204. inline int UIElement::getLayerOffset() const
  205. {
  206. return layerOffset;
  207. }
  208. inline int UIElement::getLayer() const
  209. {
  210. return layer;
  211. }
  212. inline const Vector2& UIElement::getOrigin() const
  213. {
  214. return origin;
  215. }
  216. inline const Vector2& UIElement::getTranslation() const
  217. {
  218. return translation;
  219. }
  220. inline const Vector2& UIElement::getDimensions() const
  221. {
  222. return dimensions;
  223. }
  224. inline const Vector2& UIElement::getPosition() const
  225. {
  226. return position;
  227. }
  228. inline const Rect& UIElement::getBounds() const
  229. {
  230. return bounds;
  231. }
  232. inline const Vector4& UIElement::getTintColor() const
  233. {
  234. return tintColor;
  235. }
  236. inline const Vector4& UIElement::getColor() const
  237. {
  238. return color;
  239. }
  240. inline bool UIElement::isVisible() const
  241. {
  242. return visible;
  243. }
  244. inline bool UIElement::isActive() const
  245. {
  246. return active;
  247. }
  248. class UIContainer: public UIElement
  249. {
  250. public:
  251. virtual UIElement::Type getElementType() const;
  252. };
  253. inline UIElement::Type UIContainer::getElementType() const
  254. {
  255. return UIElement::Type::CONTAINER;
  256. }
  257. class UILabel: public UIElement
  258. {
  259. public:
  260. UILabel();
  261. virtual ~UILabel();
  262. virtual UIElement::Type getElementType() const;
  263. void setFont(Font* font);
  264. void setText(const std::string& text);
  265. const Font* getFont() const;
  266. Font* getFont();
  267. const std::string& getText() const;
  268. private:
  269. void calculateDimensions();
  270. Font* font;
  271. std::string text;
  272. };
  273. inline UIElement::Type UILabel::getElementType() const
  274. {
  275. return UIElement::Type::LABEL;
  276. }
  277. inline const Font* UILabel::getFont() const
  278. {
  279. return font;
  280. }
  281. inline Font* UILabel::getFont()
  282. {
  283. return font;
  284. }
  285. inline const std::string& UILabel::getText() const
  286. {
  287. return text;
  288. }
  289. class UIImage: public UIElement
  290. {
  291. public:
  292. UIImage();
  293. virtual ~UIImage();
  294. virtual UIElement::Type getElementType() const;
  295. virtual const Texture* getTexture() const;
  296. void setTexture(Texture* texture);
  297. void setTextureBounds(const Rect& bounds);
  298. const Rect& getTextureBounds() const;
  299. private:
  300. Rect textureBounds;
  301. };
  302. inline UIElement::Type UIImage::getElementType() const
  303. {
  304. return UIElement::Type::IMAGE;
  305. }
  306. inline const Texture* UIImage::getTexture() const
  307. {
  308. return material.texture;
  309. }
  310. inline void UIImage::setTexture(Texture* texture)
  311. {
  312. material.texture = texture;
  313. }
  314. inline void UIImage::setTextureBounds(const Rect& bounds)
  315. {
  316. this->textureBounds = bounds;
  317. }
  318. inline const Rect& UIImage::getTextureBounds() const
  319. {
  320. return textureBounds;
  321. }
  322. // Creates a scene from a root UI element (follows visitor pattern?)
  323. class UIBatcher
  324. {
  325. public:
  326. void batch(BillboardBatch* result, const UIElement* ui);
  327. private:
  328. void queueElements(std::list<const UIElement*>* elements, const UIElement* element) const;
  329. BillboardBatch::Range* getRange(BillboardBatch* result, const UIElement* element) const;
  330. void batchElement(BillboardBatch* result, const UIElement* element);
  331. void batchLabel(BillboardBatch* result, const UILabel* label);
  332. void batchImage(BillboardBatch* result, const UIImage* image);
  333. };
  334. class Menu;
  335. class MenuItem
  336. {
  337. public:
  338. void select();
  339. void deselect();
  340. void activate();
  341. void setSelectedCallback(std::function<void()> callback);
  342. void setDeselectedCallback(std::function<void()> callback);
  343. void setActivatedCallback(std::function<void()> callback);
  344. std::size_t getIndex() const;
  345. bool isSelected() const;
  346. private:
  347. friend class Menu;
  348. MenuItem(Menu* parent, std::size_t index);
  349. Menu* parent;
  350. std::size_t index;
  351. bool selected;
  352. std::function<void()> selectedCallback;
  353. std::function<void()> deselectedCallback;
  354. std::function<void()> activatedCallback;
  355. };
  356. inline std::size_t MenuItem::getIndex() const
  357. {
  358. return index;
  359. }
  360. inline bool MenuItem::isSelected() const
  361. {
  362. return selected;
  363. }
  364. class Menu
  365. {
  366. public:
  367. Menu();
  368. ~Menu();
  369. void enter();
  370. void exit();
  371. MenuItem* addItem();
  372. void removeItems();
  373. void setEnteredCallback(std::function<void()> callback);
  374. void setExitedCallback(std::function<void()> callback);
  375. std::size_t getItemCount();
  376. const MenuItem* getItem(std::size_t index) const;
  377. MenuItem* getItem(std::size_t index);
  378. private:
  379. std::vector<MenuItem*> items;
  380. std::function<void()> enteredCallback;
  381. std::function<void()> exitedCallback;
  382. };
  383. inline std::size_t Menu::getItemCount()
  384. {
  385. return items.size();
  386. }
  387. inline const MenuItem* Menu::getItem(std::size_t index) const
  388. {
  389. return items[index];
  390. }
  391. inline MenuItem* Menu::getItem(std::size_t index)
  392. {
  393. return items[index];
  394. }
  395. #endif // UI_HPP