Control.cpp 36 KB

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