Control.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. #include "Base.h"
  2. #include "Control.h"
  3. namespace gameplay
  4. {
  5. Control::Control()
  6. : _id(""), _state(Control::NORMAL), _position(Vector2::zero()), _size(Vector2::zero()), _bounds(Rectangle::empty()), _clip(Rectangle::empty()),
  7. _autoWidth(true), _autoHeight(true), _dirty(true), _consumeTouchEvents(true), _listeners(NULL)
  8. {
  9. }
  10. Control::Control(const Control& copy)
  11. {
  12. }
  13. Control::~Control()
  14. {
  15. if (_listeners)
  16. {
  17. for (ListenerMap::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
  18. {
  19. std::list<Listener*>* list = itr->second;
  20. SAFE_DELETE(list);
  21. }
  22. SAFE_DELETE(_listeners);
  23. }
  24. }
  25. void Control::init(Theme::Style* style, Properties* properties)
  26. {
  27. _style = style;
  28. properties->getVector2("position", &_position);
  29. properties->getVector2("size", &_size);
  30. _state = Control::getStateFromString(properties->getString("state"));
  31. const char* id = properties->getId();
  32. if (id)
  33. {
  34. _id = id;
  35. }
  36. }
  37. const char* Control::getID() const
  38. {
  39. return _id.c_str();
  40. }
  41. void Control::setPosition(float x, float y)
  42. {
  43. _position.set(x, y);
  44. }
  45. const Vector2& Control::getPosition() const
  46. {
  47. return _position;
  48. }
  49. void Control::setSize(float width, float height)
  50. {
  51. _size.set(width, height);
  52. }
  53. const Vector2& Control::getSize() const
  54. {
  55. return _size;
  56. }
  57. const Rectangle& Control::getBounds() const
  58. {
  59. return _bounds;
  60. }
  61. const Rectangle& Control::getClip() const
  62. {
  63. return _clip;
  64. }
  65. void Control::setAutoSize(bool width, bool height)
  66. {
  67. _autoWidth = width;
  68. _autoHeight = height;
  69. }
  70. void Control::setStyle(Theme::Style* style)
  71. {
  72. if (style != _style)
  73. {
  74. _dirty = true;
  75. }
  76. _style = style;
  77. }
  78. Theme::Style* Control::getStyle() const
  79. {
  80. return _style;
  81. }
  82. void Control::setState(State state)
  83. {
  84. _state = state;
  85. }
  86. Control::State Control::getState()
  87. {
  88. return _state;
  89. }
  90. void Control::disable()
  91. {
  92. _state = DISABLED;
  93. }
  94. void Control::enable()
  95. {
  96. _state = NORMAL;
  97. }
  98. bool Control::isEnabled()
  99. {
  100. return _state != DISABLED;
  101. }
  102. Theme::Style::OverlayType Control::getOverlayType() const
  103. {
  104. switch (_state)
  105. {
  106. case Control::NORMAL:
  107. return Theme::Style::OVERLAY_NORMAL;
  108. case Control::FOCUS:
  109. return Theme::Style::OVERLAY_FOCUS;
  110. case Control::ACTIVE:
  111. return Theme::Style::OVERLAY_ACTIVE;
  112. case Control::DISABLED:
  113. return Theme::Style::OVERLAY_DISABLED;
  114. default:
  115. return Theme::Style::OVERLAY_NORMAL;
  116. }
  117. }
  118. void Control::setConsumeTouchEvents(bool consume)
  119. {
  120. _consumeTouchEvents = consume;
  121. }
  122. bool Control::getConsumeTouchEvents()
  123. {
  124. return _consumeTouchEvents;
  125. }
  126. void Control::addListener(Control::Listener* listener, int eventFlags)
  127. {
  128. if ((eventFlags & Listener::PRESS) == Listener::PRESS)
  129. {
  130. addSpecificListener(listener, Listener::PRESS);
  131. }
  132. if ((eventFlags & Listener::RELEASE) == Listener::RELEASE)
  133. {
  134. addSpecificListener(listener, Listener::RELEASE);
  135. }
  136. if ((eventFlags & Listener::CLICK) == Listener::CLICK)
  137. {
  138. addSpecificListener(listener, Listener::CLICK);
  139. }
  140. if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
  141. {
  142. addSpecificListener(listener, Listener::VALUE_CHANGED);
  143. }
  144. if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
  145. {
  146. addSpecificListener(listener, Listener::TEXT_CHANGED);
  147. }
  148. }
  149. void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
  150. {
  151. if (!_listeners)
  152. {
  153. _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
  154. }
  155. ListenerMap::const_iterator itr = _listeners->find(eventType);
  156. if (itr == _listeners->end())
  157. {
  158. _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
  159. itr = _listeners->find(eventType);
  160. }
  161. std::list<Listener*>* listenerList = itr->second;
  162. listenerList->push_back(listener);
  163. }
  164. bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  165. {
  166. if (!isEnabled())
  167. {
  168. return false;
  169. }
  170. switch (evt)
  171. {
  172. case Touch::TOUCH_PRESS:
  173. notifyListeners(Listener::PRESS);
  174. break;
  175. case Touch::TOUCH_RELEASE:
  176. // Always trigger Listener::RELEASE
  177. notifyListeners(Listener::RELEASE);
  178. // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
  179. if (x > 0 && x <= _bounds.width &&
  180. y > 0 && y <= _bounds.height)
  181. {
  182. notifyListeners(Listener::CLICK);
  183. }
  184. break;
  185. }
  186. return _consumeTouchEvents;
  187. }
  188. void Control::keyEvent(Keyboard::KeyEvent evt, int key)
  189. {
  190. }
  191. void Control::notifyListeners(Listener::EventType eventType)
  192. {
  193. if (_listeners)
  194. {
  195. ListenerMap::const_iterator itr = _listeners->find(eventType);
  196. if (itr != _listeners->end())
  197. {
  198. std::list<Listener*>* listenerList = itr->second;
  199. for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); listenerItr++)
  200. {
  201. (*listenerItr)->controlEvent(this, eventType);
  202. }
  203. }
  204. }
  205. }
  206. void Control::update(const Rectangle& clip)
  207. {
  208. // Calculate the bounds.
  209. float x = clip.x + _position.x;
  210. float y = clip.y + _position.y;
  211. float width = _size.x;
  212. float height = _size.y;
  213. float clipX2 = clip.x + clip.width;
  214. float x2 = x + width;
  215. if (x2 > clipX2)
  216. {
  217. width = clipX2 - x;
  218. }
  219. float clipY2 = clip.y + clip.height;
  220. float y2 = y + height;
  221. if (y2 > clipY2)
  222. {
  223. height = clipY2 - y;
  224. }
  225. _bounds.set(_position.x, _position.y, width, height);
  226. // Calculate the clipping viewport.
  227. Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
  228. Theme::Border border;
  229. Theme::ContainerRegion* containerRegion = overlay->getContainerRegion();
  230. if (containerRegion)
  231. {
  232. border = overlay->getContainerRegion()->getBorder();
  233. }
  234. Theme::Padding padding = _style->getPadding();
  235. x += border.left + padding.left;
  236. y += border.top + padding.top;
  237. width = _size.x - border.left - padding.left - border.right - padding.right;
  238. height = _size.y - border.top - padding.top - border.bottom - padding.bottom;
  239. _textBounds.set(x, y, width, height);
  240. clipX2 = clip.x + clip.width;
  241. x2 = x + width;
  242. if (x2 > clipX2)
  243. {
  244. width = clipX2 - x;
  245. }
  246. clipY2 = clip.y + clip.height;
  247. y2 = y + height;
  248. if (y2 > clipY2)
  249. {
  250. height = clipY2 - y;
  251. }
  252. if (x < clip.x)
  253. {
  254. x = clip.x;
  255. }
  256. if (y < clip.y)
  257. {
  258. y = clip.y;
  259. }
  260. _clip.set(x, y, width, height);
  261. }
  262. void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
  263. {
  264. Vector2 pos(clip.x + _position.x, clip.y + _position.y);
  265. // Get the border and background images for this control's current state.
  266. Theme::ContainerRegion* containerRegion = _style->getOverlay(getOverlayType())->getContainerRegion();
  267. if (containerRegion)
  268. {
  269. // Get the UVs.
  270. Theme::UVs topLeft, top, topRight, left, center, right, bottomLeft, bottom, bottomRight;
  271. topLeft = containerRegion->getUVs(Theme::ContainerRegion::TOP_LEFT);
  272. top = containerRegion->getUVs(Theme::ContainerRegion::TOP);
  273. topRight = containerRegion->getUVs(Theme::ContainerRegion::TOP_RIGHT);
  274. left = containerRegion->getUVs(Theme::ContainerRegion::LEFT);
  275. center = containerRegion->getUVs(Theme::ContainerRegion::CENTER);
  276. right = containerRegion->getUVs(Theme::ContainerRegion::RIGHT);
  277. bottomLeft = containerRegion->getUVs(Theme::ContainerRegion::BOTTOM_LEFT);
  278. bottom = containerRegion->getUVs(Theme::ContainerRegion::BOTTOM);
  279. bottomRight = containerRegion->getUVs(Theme::ContainerRegion::BOTTOM_RIGHT);
  280. // Calculate screen-space positions.
  281. Theme::Border border = containerRegion->getBorder();
  282. Theme::Padding padding = _style->getPadding();
  283. Vector4 borderColor = containerRegion->getColor();
  284. float midWidth = _size.x - border.left - border.right;
  285. float midHeight = _size.y - border.top - border.bottom;
  286. float midX = pos.x + border.left;
  287. float midY = pos.y + border.top;
  288. float rightX = pos.x + _size.x - border.right;
  289. float bottomY = pos.y + _size.y - border.bottom;
  290. // Draw themed border sprites.
  291. if (!border.left && !border.right && !border.top && !border.bottom)
  292. {
  293. // No border, just draw the image.
  294. spriteBatch->draw(pos.x, pos.y, _size.x, _size.y, center.u1, center.v1, center.u2, center.v2, borderColor, clip);
  295. }
  296. else
  297. {
  298. if (border.left && border.top)
  299. spriteBatch->draw(pos.x, pos.y, border.left, border.top, topLeft.u1, topLeft.v1, topLeft.u2, topLeft.v2, borderColor, clip);
  300. if (border.top)
  301. spriteBatch->draw(pos.x + border.left, pos.y, midWidth, border.top, top.u1, top.v1, top.u2, top.v2, borderColor, clip);
  302. if (border.right && border.top)
  303. spriteBatch->draw(rightX, pos.y, border.right, border.top, topRight.u1, topRight.v1, topRight.u2, topRight.v2, borderColor, clip);
  304. if (border.left)
  305. spriteBatch->draw(pos.x, midY, border.left, midHeight, left.u1, left.v1, left.u2, left.v2, borderColor, clip);
  306. if (border.left && border.right && border.top && border.bottom)
  307. spriteBatch->draw(pos.x + border.left, pos.y + border.top, _size.x - border.left - border.right, _size.y - border.top - border.bottom,
  308. center.u1, center.v1, center.u2, center.v2, borderColor, clip);
  309. if (border.right)
  310. spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, borderColor, clip);
  311. if (border.bottom && border.left)
  312. spriteBatch->draw(pos.x, bottomY, border.left, border.bottom, bottomLeft.u1, bottomLeft.v1, bottomLeft.u2, bottomLeft.v2, borderColor, clip);
  313. if (border.bottom)
  314. spriteBatch->draw(midX, bottomY, midWidth, border.bottom, bottom.u1, bottom.v1, bottom.u2, bottom.v2, borderColor, clip);
  315. if (border.bottom && border.right)
  316. spriteBatch->draw(rightX, bottomY, border.right, border.bottom, bottomRight.u1, bottomRight.v1, bottomRight.u2, bottomRight.v2, borderColor, clip);
  317. }
  318. }
  319. }
  320. void Control::drawSprites(SpriteBatch* spriteBatch, const Rectangle& position)
  321. {
  322. }
  323. void Control::drawText(const Rectangle& position)
  324. {
  325. }
  326. bool Control::isDirty()
  327. {
  328. return _dirty;
  329. }
  330. bool Control::isContainer()
  331. {
  332. return false;
  333. }
  334. Control::State Control::getStateFromString(const char* state)
  335. {
  336. if (!state)
  337. {
  338. return NORMAL;
  339. }
  340. if (strcmp(state, "NORMAL") == 0)
  341. {
  342. return NORMAL;
  343. }
  344. else if (strcmp(state, "ACTIVE") == 0)
  345. {
  346. return ACTIVE;
  347. }
  348. else if (strcmp(state, "FOCUS") == 0)
  349. {
  350. return FOCUS;
  351. }
  352. else if (strcmp(state, "DISABLED") == 0)
  353. {
  354. return DISABLED;
  355. }
  356. return NORMAL;
  357. }
  358. }