Control.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. #include "Base.h"
  2. #include "Game.h"
  3. #include "Control.h"
  4. namespace gameplay
  5. {
  6. Control::Control()
  7. : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
  8. _dirty(true), _consumeTouchEvents(true), _listeners(NULL), _styleOverridden(false)
  9. {
  10. }
  11. Control::Control(const Control& copy)
  12. {
  13. }
  14. Control::~Control()
  15. {
  16. if (_listeners)
  17. {
  18. for (std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
  19. {
  20. std::list<Listener*>* list = itr->second;
  21. SAFE_DELETE(list);
  22. }
  23. SAFE_DELETE(_listeners);
  24. }
  25. if (_styleOverridden)
  26. {
  27. SAFE_DELETE(_style);
  28. }
  29. }
  30. void Control::initialize(Theme::Style* style, Properties* properties)
  31. {
  32. GP_ASSERT(properties);
  33. _style = style;
  34. // Properties not defined by the style.
  35. _alignment = getAlignment(properties->getString("alignment"));
  36. _autoWidth = properties->getBool("autoWidth");
  37. _autoHeight = properties->getBool("autoHeight");
  38. Vector2 position;
  39. Vector2 size;
  40. if (properties->exists("position"))
  41. {
  42. properties->getVector2("position", &position);
  43. }
  44. else
  45. {
  46. position.x = properties->getFloat("x");
  47. position.y = properties->getFloat("y");
  48. }
  49. if (properties->exists("size"))
  50. {
  51. properties->getVector2("size", &size);
  52. }
  53. else
  54. {
  55. size.x = properties->getFloat("width");
  56. size.y = properties->getFloat("height");
  57. }
  58. setBounds(Rectangle(position.x, position.y, size.x, size.y));
  59. _state = Control::getState(properties->getString("state"));
  60. const char* id = properties->getId();
  61. if (id)
  62. _id = id;
  63. // Potentially override themed properties for all states.
  64. overrideThemedProperties(properties, STATE_ALL);
  65. // Override themed properties on specific states.
  66. Properties* innerSpace = properties->getNextNamespace();
  67. while (innerSpace != NULL)
  68. {
  69. std::string spaceName(innerSpace->getNamespace());
  70. std::transform(spaceName.begin(), spaceName.end(), spaceName.begin(), (int(*)(int))toupper);
  71. if (spaceName == "STATENORMAL")
  72. {
  73. overrideThemedProperties(innerSpace, NORMAL);
  74. }
  75. else if (spaceName == "STATEFOCUS")
  76. {
  77. overrideThemedProperties(innerSpace, FOCUS);
  78. }
  79. else if (spaceName == "STATEACTIVE")
  80. {
  81. overrideThemedProperties(innerSpace, ACTIVE);
  82. }
  83. else if (spaceName == "STATEDISABLED")
  84. {
  85. overrideThemedProperties(innerSpace, DISABLED);
  86. }
  87. else if (spaceName == "MARGIN")
  88. {
  89. setMargin(innerSpace->getFloat("top"), innerSpace->getFloat("bottom"),
  90. innerSpace->getFloat("left"), innerSpace->getFloat("right"));
  91. }
  92. else if (spaceName == "PADDING")
  93. {
  94. setPadding(innerSpace->getFloat("top"), innerSpace->getFloat("bottom"),
  95. innerSpace->getFloat("left"), innerSpace->getFloat("right"));
  96. }
  97. innerSpace = properties->getNextNamespace();
  98. }
  99. }
  100. const char* Control::getID() const
  101. {
  102. return _id.c_str();
  103. }
  104. void Control::setPosition(float x, float y)
  105. {
  106. if (x != _bounds.x || y != _bounds.y)
  107. {
  108. _bounds.x = x;
  109. _bounds.y = y;
  110. _dirty = true;
  111. }
  112. }
  113. void Control::setSize(float width, float height)
  114. {
  115. if (width != _bounds.width || height != _bounds.height)
  116. {
  117. _bounds.width = width;
  118. _bounds.height = height;
  119. _dirty = true;
  120. }
  121. }
  122. void Control::setBounds(const Rectangle& bounds)
  123. {
  124. if (bounds != _bounds)
  125. {
  126. _bounds.set(bounds);
  127. _dirty = true;
  128. }
  129. }
  130. const Rectangle& Control::getBounds() const
  131. {
  132. return _bounds;
  133. }
  134. float Control::getX() const
  135. {
  136. return _bounds.x;
  137. }
  138. float Control::getY() const
  139. {
  140. return _bounds.y;
  141. }
  142. float Control::getWidth() const
  143. {
  144. return _bounds.width;
  145. }
  146. float Control::getHeight() const
  147. {
  148. return _bounds.height;
  149. }
  150. void Control::setAlignment(Alignment alignment)
  151. {
  152. _alignment = alignment;
  153. }
  154. Control::Alignment Control::getAlignment() const
  155. {
  156. return _alignment;
  157. }
  158. void Control::setAutoWidth(bool autoWidth)
  159. {
  160. if (_autoWidth != autoWidth)
  161. {
  162. _autoWidth = autoWidth;
  163. _dirty = true;
  164. }
  165. }
  166. bool Control::getAutoWidth() const
  167. {
  168. return _autoWidth;
  169. }
  170. void Control::setAutoHeight(bool autoHeight)
  171. {
  172. if (_autoHeight != autoHeight)
  173. {
  174. _autoHeight = autoHeight;
  175. _dirty = true;
  176. }
  177. }
  178. void Control::setOpacity(float opacity, unsigned char states)
  179. {
  180. overrideStyle();
  181. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  182. getOverlays(states, overlays);
  183. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  184. {
  185. overlays[i]->setOpacity(opacity);
  186. }
  187. _dirty = true;
  188. }
  189. float Control::getOpacity(State state) const
  190. {
  191. Theme::Style::Overlay* overlay = getOverlay(state);
  192. GP_ASSERT(overlay);
  193. return overlay->getOpacity();
  194. }
  195. void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
  196. {
  197. overrideStyle();
  198. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  199. getOverlays(states, overlays);
  200. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  201. {
  202. overlays[i]->setBorder(top, bottom, left, right);
  203. }
  204. _dirty = true;
  205. }
  206. const Theme::Border& Control::getBorder(State state) const
  207. {
  208. Theme::Style::Overlay* overlay = getOverlay(state);
  209. GP_ASSERT(overlay);
  210. return overlay->getBorder();
  211. }
  212. void Control::setSkinRegion(const Rectangle& region, unsigned char states)
  213. {
  214. overrideStyle();
  215. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  216. getOverlays(states, overlays);
  217. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  218. {
  219. overlays[i]->setSkinRegion(region, _style->_tw, _style->_th);
  220. }
  221. _dirty = true;
  222. }
  223. const Rectangle& Control::getSkinRegion(State state) const
  224. {
  225. Theme::Style::Overlay* overlay = getOverlay(state);
  226. GP_ASSERT(overlay);
  227. return overlay->getSkinRegion();
  228. }
  229. const Theme::UVs& Control::getSkinUVs(Theme::Skin::SkinArea area, State state) const
  230. {
  231. Theme::Style::Overlay* overlay = getOverlay(state);
  232. GP_ASSERT(overlay);
  233. return overlay->getSkinUVs(area);
  234. }
  235. void Control::setSkinColor(const Vector4& color, unsigned char states)
  236. {
  237. overrideStyle();
  238. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  239. getOverlays(states, overlays);
  240. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  241. {
  242. overlays[i]->setSkinColor(color);
  243. }
  244. _dirty = true;
  245. }
  246. const Vector4& Control::getSkinColor(State state) const
  247. {
  248. Theme::Style::Overlay* overlay = getOverlay(state);
  249. GP_ASSERT(overlay);
  250. return overlay->getSkinColor();
  251. }
  252. void Control::setMargin(float top, float bottom, float left, float right)
  253. {
  254. GP_ASSERT(_style);
  255. overrideStyle();
  256. _style->setMargin(top, bottom, left, right);
  257. _dirty = true;
  258. }
  259. const Theme::Margin& Control::getMargin() const
  260. {
  261. GP_ASSERT(_style);
  262. return _style->getMargin();
  263. }
  264. void Control::setPadding(float top, float bottom, float left, float right)
  265. {
  266. GP_ASSERT(_style);
  267. overrideStyle();
  268. _style->setPadding(top, bottom, left, right);
  269. _dirty = true;
  270. }
  271. const Theme::Padding& Control::getPadding() const
  272. {
  273. GP_ASSERT(_style);
  274. return _style->getPadding();
  275. }
  276. void Control::setImageRegion(const char* id, const Rectangle& region, unsigned char states)
  277. {
  278. overrideStyle();
  279. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  280. getOverlays(states, overlays);
  281. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  282. {
  283. overlays[i]->setImageRegion(id, region, _style->_tw, _style->_th);
  284. }
  285. _dirty = true;
  286. }
  287. const Rectangle& Control::getImageRegion(const char* id, State state) const
  288. {
  289. Theme::Style::Overlay* overlay = getOverlay(state);
  290. GP_ASSERT(overlay);
  291. return overlay->getImageRegion(id);
  292. }
  293. void Control::setImageColor(const char* id, const Vector4& color, unsigned char states)
  294. {
  295. overrideStyle();
  296. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  297. getOverlays(states, overlays);
  298. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  299. {
  300. overlays[i]->setImageColor(id, color);
  301. }
  302. _dirty = true;
  303. }
  304. const Vector4& Control::getImageColor(const char* id, State state) const
  305. {
  306. Theme::Style::Overlay* overlay = getOverlay(state);
  307. GP_ASSERT(overlay);
  308. return overlay->getImageColor(id);
  309. }
  310. const Theme::UVs& Control::getImageUVs(const char* id, State state) const
  311. {
  312. Theme::Style::Overlay* overlay = getOverlay(state);
  313. GP_ASSERT(overlay);
  314. return overlay->getImageUVs(id);
  315. }
  316. void Control::setCursorRegion(const Rectangle& region, unsigned char states)
  317. {
  318. overrideStyle();
  319. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  320. getOverlays(states, overlays);
  321. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  322. {
  323. overlays[i]->setCursorRegion(region, _style->_tw, _style->_th);
  324. }
  325. _dirty = true;
  326. }
  327. const Rectangle& Control::getCursorRegion(State state) const
  328. {
  329. Theme::Style::Overlay* overlay = getOverlay(state);
  330. GP_ASSERT(overlay);
  331. return overlay->getCursorRegion();
  332. }
  333. void Control::setCursorColor(const Vector4& color, unsigned char states)
  334. {
  335. overrideStyle();
  336. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  337. getOverlays(states, overlays);
  338. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  339. {
  340. overlays[i]->setCursorColor(color);
  341. }
  342. _dirty = true;
  343. }
  344. const Vector4& Control::getCursorColor(State state)
  345. {
  346. Theme::Style::Overlay* overlay = getOverlay(state);
  347. GP_ASSERT(overlay);
  348. return overlay->getCursorColor();
  349. }
  350. const Theme::UVs& Control::getCursorUVs(State state)
  351. {
  352. Theme::Style::Overlay* overlay = getOverlay(state);
  353. GP_ASSERT(overlay);
  354. return overlay->getCursorUVs();
  355. }
  356. void Control::setFont(Font* font, unsigned char states)
  357. {
  358. overrideStyle();
  359. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  360. getOverlays(states, overlays);
  361. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  362. {
  363. overlays[i]->setFont(font);
  364. }
  365. _dirty = true;
  366. }
  367. Font* Control::getFont(State state) const
  368. {
  369. Theme::Style::Overlay* overlay = getOverlay(state);
  370. GP_ASSERT(overlay);
  371. return overlay->getFont();
  372. }
  373. void Control::setFontSize(unsigned int fontSize, unsigned char states)
  374. {
  375. overrideStyle();
  376. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  377. getOverlays(states, overlays);
  378. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  379. {
  380. overlays[i]->setFontSize(fontSize);
  381. }
  382. _dirty = true;
  383. }
  384. unsigned int Control::getFontSize(State state) const
  385. {
  386. Theme::Style::Overlay* overlay = getOverlay(state);
  387. GP_ASSERT(overlay);
  388. return overlay->getFontSize();
  389. }
  390. void Control::setTextColor(const Vector4& color, unsigned char states)
  391. {
  392. overrideStyle();
  393. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  394. getOverlays(states, overlays);
  395. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  396. {
  397. overlays[i]->setTextColor(color);
  398. }
  399. _dirty = true;
  400. }
  401. const Vector4& Control::getTextColor(State state) const
  402. {
  403. Theme::Style::Overlay* overlay = getOverlay(state);
  404. GP_ASSERT(overlay);
  405. return overlay->getTextColor();
  406. }
  407. void Control::setTextAlignment(Font::Justify alignment, unsigned char states)
  408. {
  409. overrideStyle();
  410. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  411. getOverlays(states, overlays);
  412. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  413. {
  414. overlays[i]->setTextAlignment(alignment);
  415. }
  416. _dirty = true;
  417. }
  418. Font::Justify Control::getTextAlignment(State state) const
  419. {
  420. Theme::Style::Overlay* overlay = getOverlay(state);
  421. GP_ASSERT(overlay);
  422. return overlay->getTextAlignment();
  423. }
  424. void Control::setTextRightToLeft(bool rightToLeft, unsigned char states)
  425. {
  426. overrideStyle();
  427. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  428. getOverlays(states, overlays);
  429. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  430. {
  431. overlays[i]->setTextRightToLeft(rightToLeft);
  432. }
  433. _dirty = true;
  434. }
  435. bool Control::getTextRightToLeft(State state) const
  436. {
  437. Theme::Style::Overlay* overlay = getOverlay(state);
  438. GP_ASSERT(overlay);
  439. return overlay->getTextRightToLeft();
  440. }
  441. const Rectangle& Control::getClipBounds() const
  442. {
  443. return _clipBounds;
  444. }
  445. const Rectangle& Control::getClip() const
  446. {
  447. return _viewportClipBounds;
  448. }
  449. void Control::setStyle(Theme::Style* style)
  450. {
  451. if (style != _style)
  452. {
  453. _dirty = true;
  454. }
  455. _style = style;
  456. }
  457. Theme::Style* Control::getStyle() const
  458. {
  459. return _style;
  460. }
  461. void Control::setState(State state)
  462. {
  463. if (getOverlay(_state) != getOverlay(state))
  464. _dirty = true;
  465. _state = state;
  466. }
  467. Control::State Control::getState() const
  468. {
  469. return _state;
  470. }
  471. void Control::disable()
  472. {
  473. _state = DISABLED;
  474. _dirty = true;
  475. }
  476. void Control::enable()
  477. {
  478. _state = NORMAL;
  479. _dirty = true;
  480. }
  481. bool Control::isEnabled()
  482. {
  483. return _state != DISABLED;
  484. }
  485. Theme::Style::OverlayType Control::getOverlayType() const
  486. {
  487. switch (_state)
  488. {
  489. case Control::NORMAL:
  490. return Theme::Style::OVERLAY_NORMAL;
  491. case Control::FOCUS:
  492. return Theme::Style::OVERLAY_FOCUS;
  493. case Control::ACTIVE:
  494. return Theme::Style::OVERLAY_ACTIVE;
  495. case Control::DISABLED:
  496. return Theme::Style::OVERLAY_DISABLED;
  497. default:
  498. return Theme::Style::OVERLAY_NORMAL;
  499. }
  500. }
  501. void Control::setConsumeTouchEvents(bool consume)
  502. {
  503. _consumeTouchEvents = consume;
  504. }
  505. bool Control::getConsumeTouchEvents()
  506. {
  507. return _consumeTouchEvents;
  508. }
  509. void Control::addListener(Control::Listener* listener, int eventFlags)
  510. {
  511. GP_ASSERT(listener);
  512. if ((eventFlags & Listener::PRESS) == Listener::PRESS)
  513. {
  514. addSpecificListener(listener, Listener::PRESS);
  515. }
  516. if ((eventFlags & Listener::RELEASE) == Listener::RELEASE)
  517. {
  518. addSpecificListener(listener, Listener::RELEASE);
  519. }
  520. if ((eventFlags & Listener::CLICK) == Listener::CLICK)
  521. {
  522. addSpecificListener(listener, Listener::CLICK);
  523. }
  524. if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
  525. {
  526. addSpecificListener(listener, Listener::VALUE_CHANGED);
  527. }
  528. if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
  529. {
  530. addSpecificListener(listener, Listener::TEXT_CHANGED);
  531. }
  532. }
  533. void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
  534. {
  535. GP_ASSERT(listener);
  536. if (!_listeners)
  537. {
  538. _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
  539. }
  540. std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
  541. if (itr == _listeners->end())
  542. {
  543. _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
  544. itr = _listeners->find(eventType);
  545. }
  546. std::list<Listener*>* listenerList = itr->second;
  547. listenerList->push_back(listener);
  548. }
  549. bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  550. {
  551. if (!isEnabled())
  552. {
  553. return false;
  554. }
  555. switch (evt)
  556. {
  557. case Touch::TOUCH_PRESS:
  558. notifyListeners(Listener::PRESS);
  559. break;
  560. case Touch::TOUCH_RELEASE:
  561. // Always trigger Listener::RELEASE
  562. notifyListeners(Listener::RELEASE);
  563. // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
  564. if (x > 0 && x <= _bounds.width &&
  565. y > 0 && y <= _bounds.height)
  566. {
  567. notifyListeners(Listener::CLICK);
  568. }
  569. break;
  570. }
  571. return _consumeTouchEvents;
  572. }
  573. void Control::keyEvent(Keyboard::KeyEvent evt, int key)
  574. {
  575. }
  576. void Control::notifyListeners(Listener::EventType eventType)
  577. {
  578. if (_listeners)
  579. {
  580. std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
  581. if (itr != _listeners->end())
  582. {
  583. std::list<Listener*>* listenerList = itr->second;
  584. for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); listenerItr++)
  585. {
  586. GP_ASSERT(*listenerItr);
  587. (*listenerItr)->controlEvent(this, eventType);
  588. }
  589. }
  590. }
  591. }
  592. void Control::update(const Rectangle& clip, const Vector2& offset)
  593. {
  594. _clearBounds.set(_absoluteClipBounds);
  595. // Calculate the clipped bounds.
  596. float x = _bounds.x + offset.x;
  597. float y = _bounds.y + offset.y;
  598. float width = _bounds.width;
  599. float height = _bounds.height;
  600. float clipX2 = clip.x + clip.width;
  601. float x2 = clip.x + x + width;
  602. if (x2 > clipX2)
  603. width -= x2 - clipX2;
  604. float clipY2 = clip.y + clip.height;
  605. float y2 = clip.y + y + height;
  606. if (y2 > clipY2)
  607. height -= y2 - clipY2;
  608. if (x < 0)
  609. {
  610. width += x;
  611. x = -x;
  612. }
  613. else
  614. {
  615. x = 0;
  616. }
  617. if (y < 0)
  618. {
  619. height += y;
  620. y = -y;
  621. }
  622. else
  623. {
  624. y = 0;
  625. }
  626. _clipBounds.set(x, y, width, height);
  627. // Calculate the absolute bounds.
  628. x = _bounds.x + offset.x + clip.x;
  629. y = _bounds.y + offset.y + clip.y;
  630. _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
  631. // Calculate the absolute viewport bounds.
  632. // Absolute bounds minus border and padding.
  633. const Theme::Border& border = getBorder(_state);
  634. const Theme::Padding& padding = getPadding();
  635. x += border.left + padding.left;
  636. y += border.top + padding.top;
  637. width = _bounds.width - border.left - padding.left - border.right - padding.right;
  638. height = _bounds.height - border.top - padding.top - border.bottom - padding.bottom;
  639. _viewportBounds.set(x, y, width, height);
  640. // Calculate the clip area.
  641. // Absolute bounds, minus border and padding,
  642. // clipped to the parent container's clip area.
  643. clipX2 = clip.x + clip.width;
  644. x2 = x + width;
  645. if (x2 > clipX2)
  646. width = clipX2 - x;
  647. clipY2 = clip.y + clip.height;
  648. y2 = y + height;
  649. if (y2 > clipY2)
  650. height = clipY2 - y;
  651. if (x < clip.x)
  652. {
  653. float dx = clip.x - x;
  654. width -= dx;
  655. x = clip.x;
  656. }
  657. if (y < clip.y)
  658. {
  659. float dy = clip.y - y;
  660. height -= dy;
  661. y = clip.y;
  662. }
  663. _viewportClipBounds.set(x, y, width, height);
  664. _absoluteClipBounds.set(x - border.left - padding.left, y - border.top - padding.top,
  665. width + border.left + padding.left + border.right + padding.right,
  666. height + border.top + padding.top + border.bottom + padding.bottom);
  667. if (_clearBounds.isEmpty())
  668. {
  669. _clearBounds.set(_absoluteClipBounds);
  670. }
  671. // Cache themed attributes for performance.
  672. _skin = getSkin(_state);
  673. _opacity = getOpacity(_state);
  674. }
  675. void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
  676. {
  677. if (!spriteBatch || !_skin || _bounds.width <= 0 || _bounds.height <= 0)
  678. return;
  679. // Get the border and background images for this control's current state.
  680. const Theme::UVs& topLeft = _skin->getUVs(Theme::Skin::TOP_LEFT);
  681. const Theme::UVs& top = _skin->getUVs(Theme::Skin::TOP);
  682. const Theme::UVs& topRight = _skin->getUVs(Theme::Skin::TOP_RIGHT);
  683. const Theme::UVs& left = _skin->getUVs(Theme::Skin::LEFT);
  684. const Theme::UVs& center = _skin->getUVs(Theme::Skin::CENTER);
  685. const Theme::UVs& right = _skin->getUVs(Theme::Skin::RIGHT);
  686. const Theme::UVs& bottomLeft = _skin->getUVs(Theme::Skin::BOTTOM_LEFT);
  687. const Theme::UVs& bottom = _skin->getUVs(Theme::Skin::BOTTOM);
  688. const Theme::UVs& bottomRight = _skin->getUVs(Theme::Skin::BOTTOM_RIGHT);
  689. // Calculate screen-space positions.
  690. const Theme::Border& border = getBorder(_state);
  691. const Theme::Padding& padding = getPadding();
  692. Vector4 skinColor = _skin->getColor();
  693. skinColor.w *= _opacity;
  694. float midWidth = _bounds.width - border.left - border.right;
  695. float midHeight = _bounds.height - border.top - border.bottom;
  696. float midX = _absoluteBounds.x + border.left;
  697. float midY = _absoluteBounds.y + border.top;
  698. float rightX = _absoluteBounds.x + _bounds.width - border.right;
  699. float bottomY = _absoluteBounds.y + _bounds.height - border.bottom;
  700. // Draw themed border sprites.
  701. if (!border.left && !border.right && !border.top && !border.bottom)
  702. {
  703. // No border, just draw the image.
  704. spriteBatch->draw(_absoluteBounds.x, _absoluteBounds.y, _bounds.width, _bounds.height, center.u1, center.v1, center.u2, center.v2, skinColor, clip);
  705. }
  706. else
  707. {
  708. if (border.left && border.top)
  709. spriteBatch->draw(_absoluteBounds.x, _absoluteBounds.y, border.left, border.top, topLeft.u1, topLeft.v1, topLeft.u2, topLeft.v2, skinColor, clip);
  710. if (border.top)
  711. spriteBatch->draw(_absoluteBounds.x + border.left, _absoluteBounds.y, midWidth, border.top, top.u1, top.v1, top.u2, top.v2, skinColor, clip);
  712. if (border.right && border.top)
  713. spriteBatch->draw(rightX, _absoluteBounds.y, border.right, border.top, topRight.u1, topRight.v1, topRight.u2, topRight.v2, skinColor, clip);
  714. if (border.left)
  715. spriteBatch->draw(_absoluteBounds.x, midY, border.left, midHeight, left.u1, left.v1, left.u2, left.v2, skinColor, clip);
  716. if (border.left && border.right && border.top && border.bottom)
  717. spriteBatch->draw(_absoluteBounds.x + border.left, _absoluteBounds.y + border.top, _bounds.width - border.left - border.right, _bounds.height - border.top - border.bottom,
  718. center.u1, center.v1, center.u2, center.v2, skinColor, clip);
  719. if (border.right)
  720. spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, skinColor, clip);
  721. if (border.bottom && border.left)
  722. spriteBatch->draw(_absoluteBounds.x, bottomY, border.left, border.bottom, bottomLeft.u1, bottomLeft.v1, bottomLeft.u2, bottomLeft.v2, skinColor, clip);
  723. if (border.bottom)
  724. spriteBatch->draw(midX, bottomY, midWidth, border.bottom, bottom.u1, bottom.v1, bottom.u2, bottom.v2, skinColor, clip);
  725. if (border.bottom && border.right)
  726. spriteBatch->draw(rightX, bottomY, border.right, border.bottom, bottomRight.u1, bottomRight.v1, bottomRight.u2, bottomRight.v2, skinColor, clip);
  727. }
  728. }
  729. void Control::drawImages(SpriteBatch* spriteBatch, const Rectangle& position)
  730. {
  731. }
  732. void Control::drawText(const Rectangle& position)
  733. {
  734. }
  735. void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, float targetHeight)
  736. {
  737. if (needsClear)
  738. {
  739. GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
  740. GL_ASSERT( glClearColor(0, 0, 0, 1) );
  741. GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height,
  742. _clearBounds.width, _clearBounds.height) );
  743. GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
  744. GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
  745. }
  746. drawBorder(spriteBatch, clip);
  747. drawImages(spriteBatch, clip);
  748. drawText(clip);
  749. _dirty = false;
  750. }
  751. bool Control::isDirty()
  752. {
  753. return _dirty;
  754. }
  755. bool Control::isContainer()
  756. {
  757. return false;
  758. }
  759. Control::State Control::getState(const char* state)
  760. {
  761. if (!state)
  762. {
  763. return NORMAL;
  764. }
  765. if (strcmp(state, "NORMAL") == 0)
  766. {
  767. return NORMAL;
  768. }
  769. else if (strcmp(state, "ACTIVE") == 0)
  770. {
  771. return ACTIVE;
  772. }
  773. else if (strcmp(state, "FOCUS") == 0)
  774. {
  775. return FOCUS;
  776. }
  777. else if (strcmp(state, "DISABLED") == 0)
  778. {
  779. return DISABLED;
  780. }
  781. return NORMAL;
  782. }
  783. Theme::ThemeImage* Control::getImage(const char* id, State state)
  784. {
  785. Theme::Style::Overlay* overlay = getOverlay(state);
  786. GP_ASSERT(overlay);
  787. Theme::ImageList* imageList = overlay->getImageList();
  788. GP_ASSERT(imageList);
  789. return imageList->getImage(id);
  790. }
  791. // Implementation of AnimationHandler
  792. unsigned int Control::getAnimationPropertyComponentCount(int propertyId) const
  793. {
  794. switch(propertyId)
  795. {
  796. case ANIMATE_POSITION:
  797. case ANIMATE_SIZE:
  798. return 2;
  799. case ANIMATE_POSITION_X:
  800. case ANIMATE_POSITION_Y:
  801. case ANIMATE_SIZE_WIDTH:
  802. case ANIMATE_SIZE_HEIGHT:
  803. case ANIMATE_OPACITY:
  804. return 1;
  805. default:
  806. return -1;
  807. }
  808. }
  809. void Control::getAnimationPropertyValue(int propertyId, AnimationValue* value)
  810. {
  811. GP_ASSERT(value);
  812. switch(propertyId)
  813. {
  814. case ANIMATE_POSITION:
  815. value->setFloat(0, _bounds.x);
  816. value->setFloat(1, _bounds.y);
  817. break;
  818. case ANIMATE_SIZE:
  819. value->setFloat(0, _bounds.width);
  820. value->setFloat(1, _bounds.height);
  821. break;
  822. case ANIMATE_POSITION_X:
  823. value->setFloat(0, _bounds.x);
  824. break;
  825. case ANIMATE_POSITION_Y:
  826. value->setFloat(0, _bounds.y);
  827. break;
  828. case ANIMATE_SIZE_WIDTH:
  829. value->setFloat(0, _bounds.width);
  830. break;
  831. case ANIMATE_SIZE_HEIGHT:
  832. value->setFloat(0, _bounds.height);
  833. break;
  834. case ANIMATE_OPACITY:
  835. default:
  836. break;
  837. }
  838. }
  839. void Control::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
  840. {
  841. GP_ASSERT(value);
  842. switch(propertyId)
  843. {
  844. case ANIMATE_POSITION:
  845. _bounds.x = Curve::lerp(blendWeight, _bounds.x, value->getFloat(0));
  846. _bounds.y = Curve::lerp(blendWeight, _bounds.y, value->getFloat(1));
  847. _dirty = true;
  848. break;
  849. case ANIMATE_POSITION_X:
  850. _bounds.x = Curve::lerp(blendWeight, _bounds.x, value->getFloat(0));
  851. _dirty = true;
  852. break;
  853. case ANIMATE_POSITION_Y:
  854. _bounds.y = Curve::lerp(blendWeight, _bounds.y, value->getFloat(0));
  855. _dirty = true;
  856. break;
  857. case ANIMATE_SIZE:
  858. _bounds.width = Curve::lerp(blendWeight, _bounds.width, value->getFloat(0));
  859. _bounds.height = Curve::lerp(blendWeight, _bounds.height, value->getFloat(1));
  860. _dirty = true;
  861. break;
  862. case ANIMATE_SIZE_WIDTH:
  863. _bounds.width = Curve::lerp(blendWeight, _bounds.width, value->getFloat(0));
  864. _dirty = true;
  865. break;
  866. case ANIMATE_SIZE_HEIGHT:
  867. _bounds.height = Curve::lerp(blendWeight, _bounds.height, value->getFloat(0));
  868. _dirty = true;
  869. break;
  870. case ANIMATE_OPACITY:
  871. _dirty = true;
  872. default:
  873. break;
  874. }
  875. }
  876. Theme::Style::Overlay** Control::getOverlays(unsigned char overlayTypes, Theme::Style::Overlay** overlays)
  877. {
  878. GP_ASSERT(overlays);
  879. GP_ASSERT(_style);
  880. unsigned int index = 0;
  881. if ((overlayTypes & NORMAL) == NORMAL)
  882. {
  883. overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
  884. }
  885. if ((overlayTypes & FOCUS) == FOCUS)
  886. {
  887. overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
  888. }
  889. if ((overlayTypes & ACTIVE) == ACTIVE)
  890. {
  891. overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
  892. }
  893. if ((overlayTypes & DISABLED) == DISABLED)
  894. {
  895. overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
  896. }
  897. return overlays;
  898. }
  899. Theme::Style::Overlay* Control::getOverlay(State state) const
  900. {
  901. GP_ASSERT(_style);
  902. switch(state)
  903. {
  904. case Control::NORMAL:
  905. return _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
  906. case Control::FOCUS:
  907. return _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
  908. case Control::ACTIVE:
  909. return _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
  910. case Control::DISABLED:
  911. return _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
  912. default:
  913. return NULL;
  914. }
  915. }
  916. void Control::overrideStyle()
  917. {
  918. if (_styleOverridden)
  919. {
  920. return;
  921. }
  922. // Copy the style.
  923. GP_ASSERT(_style);
  924. _style = new Theme::Style(*_style);
  925. _styleOverridden = true;
  926. }
  927. void Control::overrideThemedProperties(Properties* properties, unsigned char states)
  928. {
  929. GP_ASSERT(properties);
  930. GP_ASSERT(_style);
  931. GP_ASSERT(_style->_theme);
  932. Theme::ImageList* imageList = NULL;
  933. Theme::ThemeImage* cursor = NULL;
  934. Theme::Skin* skin = NULL;
  935. _style->_theme->lookUpSprites(properties, &imageList, &cursor, &skin);
  936. if (imageList)
  937. {
  938. setImageList(imageList, states);
  939. }
  940. if (cursor)
  941. {
  942. setCursor(cursor, states);
  943. }
  944. if (skin)
  945. {
  946. setSkin(skin, states);
  947. }
  948. if (properties->exists("font"))
  949. {
  950. Font* font = Font::create(properties->getString("font"));
  951. setFont(font, states);
  952. font->release();
  953. }
  954. if (properties->exists("fontSize"))
  955. {
  956. setFontSize(properties->getInt("fontSize"), states);
  957. }
  958. if (properties->exists("textColor"))
  959. {
  960. Vector4 textColor(0, 0, 0, 1);
  961. properties->getColor("textColor", &textColor);
  962. setTextColor(textColor, states);
  963. }
  964. if (properties->exists("textAlignment"))
  965. {
  966. setTextAlignment(Font::getJustify(properties->getString("textAlignment")), states);
  967. }
  968. if (properties->exists("rightToLeft"))
  969. {
  970. setTextRightToLeft(properties->getBool("rightToLeft"), states);
  971. }
  972. if (properties->exists("opacity"))
  973. {
  974. setOpacity(properties->getFloat("opacity"), states);
  975. }
  976. }
  977. void Control::setImageList(Theme::ImageList* imageList, unsigned char states)
  978. {
  979. overrideStyle();
  980. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  981. getOverlays(states, overlays);
  982. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  983. {
  984. overlays[i]->setImageList(imageList);
  985. }
  986. _dirty = true;
  987. }
  988. void Control::setCursor(Theme::ThemeImage* cursor, unsigned char states)
  989. {
  990. overrideStyle();
  991. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  992. getOverlays(states, overlays);
  993. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  994. {
  995. overlays[i]->setCursor(cursor);
  996. }
  997. _dirty = true;
  998. }
  999. void Control::setSkin(Theme::Skin* skin, unsigned char states)
  1000. {
  1001. overrideStyle();
  1002. Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
  1003. getOverlays(states, overlays);
  1004. for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
  1005. {
  1006. overlays[i]->setSkin(skin);
  1007. }
  1008. _dirty = true;
  1009. }
  1010. Theme::Skin* Control::getSkin(State state)
  1011. {
  1012. Theme::Style::Overlay* overlay = getOverlay(state);
  1013. GP_ASSERT(overlay);
  1014. return overlay->getSkin();
  1015. }
  1016. Control::Alignment Control::getAlignment(const char* alignment)
  1017. {
  1018. if (!alignment)
  1019. {
  1020. return Control::ALIGN_TOP_LEFT;
  1021. }
  1022. if (strcmp(alignment, "ALIGN_LEFT") == 0)
  1023. {
  1024. return Control::ALIGN_LEFT;
  1025. }
  1026. else if (strcmp(alignment, "ALIGN_HCENTER") == 0)
  1027. {
  1028. return Control::ALIGN_HCENTER;
  1029. }
  1030. else if (strcmp(alignment, "ALIGN_RIGHT") == 0)
  1031. {
  1032. return Control::ALIGN_RIGHT;
  1033. }
  1034. else if (strcmp(alignment, "ALIGN_TOP") == 0)
  1035. {
  1036. return Control::ALIGN_TOP;
  1037. }
  1038. else if (strcmp(alignment, "ALIGN_VCENTER") == 0)
  1039. {
  1040. return Control::ALIGN_VCENTER;
  1041. }
  1042. else if (strcmp(alignment, "ALIGN_BOTTOM") == 0)
  1043. {
  1044. return Control::ALIGN_BOTTOM;
  1045. }
  1046. else if (strcmp(alignment, "ALIGN_TOP_LEFT") == 0)
  1047. {
  1048. return Control::ALIGN_TOP_LEFT;
  1049. }
  1050. else if (strcmp(alignment, "ALIGN_VCENTER_LEFT") == 0)
  1051. {
  1052. return Control::ALIGN_VCENTER_LEFT;
  1053. }
  1054. else if (strcmp(alignment, "ALIGN_BOTTOM_LEFT") == 0)
  1055. {
  1056. return Control::ALIGN_BOTTOM_LEFT;
  1057. }
  1058. else if (strcmp(alignment, "ALIGN_TOP_HCENTER") == 0)
  1059. {
  1060. return Control::ALIGN_TOP_HCENTER;
  1061. }
  1062. else if (strcmp(alignment, "ALIGN_VCENTER_HCENTER") == 0)
  1063. {
  1064. return Control::ALIGN_VCENTER_HCENTER;
  1065. }
  1066. else if (strcmp(alignment, "ALIGN_BOTTOM_HCENTER") == 0)
  1067. {
  1068. return Control::ALIGN_BOTTOM_HCENTER;
  1069. }
  1070. else if (strcmp(alignment, "ALIGN_TOP_RIGHT") == 0)
  1071. {
  1072. return Control::ALIGN_TOP_RIGHT;
  1073. }
  1074. else if (strcmp(alignment, "ALIGN_VCENTER_RIGHT") == 0)
  1075. {
  1076. return Control::ALIGN_VCENTER_RIGHT;
  1077. }
  1078. else if (strcmp(alignment, "ALIGN_BOTTOM_RIGHT") == 0)
  1079. {
  1080. return Control::ALIGN_BOTTOM_RIGHT;
  1081. }
  1082. else
  1083. {
  1084. GP_ERROR("Failed to get corresponding control alignment for unsupported value \'%s\'.", alignment);
  1085. }
  1086. // Default.
  1087. return Control::ALIGN_TOP_LEFT;
  1088. }
  1089. }