Container.cpp 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732
  1. #include "Base.h"
  2. #include "Container.h"
  3. #include "Layout.h"
  4. #include "AbsoluteLayout.h"
  5. #include "FlowLayout.h"
  6. #include "VerticalLayout.h"
  7. #include "Label.h"
  8. #include "Button.h"
  9. #include "CheckBox.h"
  10. #include "RadioButton.h"
  11. #include "Slider.h"
  12. #include "TextBox.h"
  13. #include "Joystick.h"
  14. #include "ImageControl.h"
  15. #include "Game.h"
  16. namespace gameplay
  17. {
  18. // If the user stops scrolling for this amount of time (in millis) before touch/click release, don't apply inertia.
  19. static const long SCROLL_INERTIA_DELAY = 100L;
  20. // Factor to multiply friction by before applying to velocity.
  21. static const float SCROLL_FRICTION_FACTOR = 5.0f;
  22. // Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
  23. static const float SCROLL_THRESHOLD = 10.0f;
  24. // Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
  25. static const float JOYSTICK_THRESHOLD = 0.75f;
  26. // Scroll speed when using a DPad -- max scroll speed when using a joystick.
  27. static const float GAMEPAD_SCROLL_SPEED = 500.0f;
  28. // If the DPad or joystick is held down, this is the initial delay in milliseconds between focus change events.
  29. static const float FOCUS_CHANGE_REPEAT_DELAY = 300.0f;
  30. /**
  31. * Sort function for use with _controls.sort(), based on Z-Order.
  32. *
  33. * @param c1 The first control
  34. * @param c2 The second control
  35. * return true if the first controls z index is less than the second.
  36. */
  37. static bool sortControlsByZOrder(Control* c1, Control* c2);
  38. Container::Container()
  39. : _layout(NULL), _scrollBarTopCap(NULL), _scrollBarVertical(NULL), _scrollBarBottomCap(NULL),
  40. _scrollBarLeftCap(NULL), _scrollBarHorizontal(NULL), _scrollBarRightCap(NULL),
  41. _scroll(SCROLL_NONE), _scrollBarBounds(Rectangle::empty()), _scrollPosition(Vector2::zero()),
  42. _scrollBarsAutoHide(false), _scrollBarOpacity(1.0f), _scrolling(false),
  43. _scrollingVeryFirstX(0), _scrollingVeryFirstY(0), _scrollingFirstX(0), _scrollingFirstY(0), _scrollingLastX(0), _scrollingLastY(0),
  44. _scrollingStartTimeX(0), _scrollingStartTimeY(0), _scrollingLastTime(0),
  45. _scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f),
  46. _scrollingRight(false), _scrollingDown(false),
  47. _scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
  48. _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0),
  49. _focusPressed(0), _selectButtonDown(false),
  50. _lastFrameTime(0), _focusChangeRepeat(false),
  51. _focusChangeStartTime(0), _focusChangeRepeatDelay(FOCUS_CHANGE_REPEAT_DELAY), _focusChangeCount(0),
  52. _totalWidth(0), _totalHeight(0),
  53. _contactIndices(0), _initializedWithScroll(false)
  54. {
  55. }
  56. Container::~Container()
  57. {
  58. std::vector<Control*>::iterator it;
  59. for (it = _controls.begin(); it < _controls.end(); it++)
  60. {
  61. SAFE_RELEASE((*it));
  62. }
  63. SAFE_RELEASE(_layout);
  64. }
  65. Container* Container::create(const char* id, Theme::Style* style, Layout::Type layoutType)
  66. {
  67. GP_ASSERT(style);
  68. Container* container = Container::create(layoutType);
  69. if (id)
  70. container->_id = id;
  71. container->_style = style;
  72. return container;
  73. }
  74. Container* Container::create(Layout::Type type)
  75. {
  76. Layout* layout = NULL;
  77. switch (type)
  78. {
  79. case Layout::LAYOUT_ABSOLUTE:
  80. layout = AbsoluteLayout::create();
  81. break;
  82. case Layout::LAYOUT_FLOW:
  83. layout = FlowLayout::create();
  84. break;
  85. case Layout::LAYOUT_VERTICAL:
  86. layout = VerticalLayout::create();
  87. break;
  88. }
  89. Container* container = new Container();
  90. container->_layout = layout;
  91. return container;
  92. }
  93. Container* Container::create(Theme::Style* style, Properties* properties, Theme* theme)
  94. {
  95. GP_ASSERT(properties);
  96. const char* layoutString = properties->getString("layout");
  97. Container* container = Container::create(getLayoutType(layoutString));
  98. container->initialize(style, properties);
  99. container->_scroll = getScroll(properties->getString("scroll"));
  100. container->_scrollBarsAutoHide = properties->getBool("scrollBarsAutoHide");
  101. if (container->_scrollBarsAutoHide)
  102. {
  103. container->_scrollBarOpacity = 0.0f;
  104. }
  105. container->addControls(theme, properties);
  106. container->_layout->update(container, container->_scrollPosition);
  107. return container;
  108. }
  109. void Container::addControls(Theme* theme, Properties* properties)
  110. {
  111. GP_ASSERT(theme);
  112. GP_ASSERT(properties);
  113. // Add all the controls to this container.
  114. Properties* controlSpace = properties->getNextNamespace();
  115. while (controlSpace != NULL)
  116. {
  117. Control* control = NULL;
  118. const char* controlStyleName = controlSpace->getString("style");
  119. Theme::Style* controlStyle = NULL;
  120. if (controlStyleName)
  121. {
  122. controlStyle = theme->getStyle(controlStyleName);
  123. }
  124. else
  125. {
  126. controlStyle = theme->getEmptyStyle();
  127. }
  128. std::string controlName(controlSpace->getNamespace());
  129. std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);
  130. if (controlName == "LABEL")
  131. {
  132. control = Label::create(controlStyle, controlSpace);
  133. }
  134. else if (controlName == "BUTTON")
  135. {
  136. control = Button::create(controlStyle, controlSpace);
  137. }
  138. else if (controlName == "CHECKBOX")
  139. {
  140. control = CheckBox::create(controlStyle, controlSpace);
  141. }
  142. else if (controlName == "RADIOBUTTON")
  143. {
  144. control = RadioButton::create(controlStyle, controlSpace);
  145. }
  146. else if (controlName == "CONTAINER")
  147. {
  148. control = Container::create(controlStyle, controlSpace, theme);
  149. }
  150. else if (controlName == "SLIDER")
  151. {
  152. control = Slider::create(controlStyle, controlSpace);
  153. }
  154. else if (controlName == "TEXTBOX")
  155. {
  156. control = TextBox::create(controlStyle, controlSpace);
  157. }
  158. else if (controlName == "JOYSTICK")
  159. {
  160. control = Joystick::create(controlStyle, controlSpace);
  161. }
  162. else if (controlName == "IMAGE")
  163. {
  164. control = ImageControl::create(controlStyle, controlSpace);
  165. }
  166. else
  167. {
  168. // Ignore - not a valid control name.
  169. // This used to fail, but I see no reason to hard fail here (this also fixes not being able
  170. // to set padding on containers).
  171. }
  172. // Add the new control to the form.
  173. if (control)
  174. {
  175. addControl(control);
  176. control->release();
  177. }
  178. // Get the next control.
  179. controlSpace = properties->getNextNamespace();
  180. }
  181. // Sort controls by Z-Order.
  182. sortControls();
  183. }
  184. Layout* Container::getLayout()
  185. {
  186. return _layout;
  187. }
  188. unsigned int Container::addControl(Control* control)
  189. {
  190. GP_ASSERT(control);
  191. if (control->_parent && control->_parent != this)
  192. {
  193. control->_parent->removeControl(control);
  194. }
  195. if (control->getZIndex() == -1)
  196. {
  197. control->setZIndex(_zIndexDefault++);
  198. }
  199. if (control->getFocusIndex() == -1)
  200. {
  201. control->setFocusIndex(_focusIndexDefault++);
  202. }
  203. int focusIndex = control->getFocusIndex();
  204. if (focusIndex > _focusIndexMax)
  205. _focusIndexMax = focusIndex;
  206. if (control->_parent != this)
  207. {
  208. _controls.push_back(control);
  209. control->addRef();
  210. control->_parent = this;
  211. sortControls();
  212. return (unsigned int)(_controls.size() - 1);
  213. }
  214. else
  215. {
  216. // Control is already in this container.
  217. // Do nothing but determine and return control's index.
  218. const size_t size = _controls.size();
  219. for (size_t i = 0; i < size; ++i)
  220. {
  221. Control* c = _controls[i];
  222. if (c == control)
  223. {
  224. return (unsigned int)i;
  225. }
  226. }
  227. // Should never reach this.
  228. GP_ASSERT(false);
  229. return 0;
  230. }
  231. }
  232. void Container::insertControl(Control* control, unsigned int index)
  233. {
  234. GP_ASSERT(control);
  235. if (control->_parent && control->_parent != this)
  236. {
  237. control->_parent->removeControl(control);
  238. }
  239. if (control->_parent != this)
  240. {
  241. std::vector<Control*>::iterator it = _controls.begin() + index;
  242. _controls.insert(it, control);
  243. control->addRef();
  244. control->_parent = this;
  245. }
  246. }
  247. void Container::removeControl(unsigned int index)
  248. {
  249. GP_ASSERT(index < _controls.size());
  250. std::vector<Control*>::iterator it = _controls.begin() + index;
  251. _controls.erase(it);
  252. Control* control = *it;
  253. control->_parent = NULL;
  254. SAFE_RELEASE(control);
  255. }
  256. void Container::removeControl(const char* id)
  257. {
  258. GP_ASSERT(id);
  259. std::vector<Control*>::iterator it;
  260. for (it = _controls.begin(); it < _controls.end(); it++)
  261. {
  262. Control* c = *it;
  263. if (strcmp(id, c->getId()) == 0)
  264. {
  265. c->_parent = NULL;
  266. SAFE_RELEASE(c);
  267. _controls.erase(it);
  268. return;
  269. }
  270. }
  271. }
  272. void Container::removeControl(Control* control)
  273. {
  274. GP_ASSERT(control);
  275. std::vector<Control*>::iterator it;
  276. for (it = _controls.begin(); it < _controls.end(); it++)
  277. {
  278. if (*it == control)
  279. {
  280. control->_parent = NULL;
  281. SAFE_RELEASE(control);
  282. _controls.erase(it);
  283. return;
  284. }
  285. }
  286. }
  287. Control* Container::getControl(unsigned int index) const
  288. {
  289. std::vector<Control*>::const_iterator it = _controls.begin() + index;
  290. return *it;
  291. }
  292. Control* Container::getControl(const char* id) const
  293. {
  294. GP_ASSERT(id);
  295. std::vector<Control*>::const_iterator it;
  296. for (it = _controls.begin(); it < _controls.end(); it++)
  297. {
  298. Control* c = *it;
  299. GP_ASSERT(c);
  300. if (strcmp(id, c->getId()) == 0)
  301. {
  302. return c;
  303. }
  304. else if (c->isContainer())
  305. {
  306. Control* cc = ((Container*)c)->getControl(id);
  307. if (cc)
  308. {
  309. return cc;
  310. }
  311. }
  312. }
  313. return NULL;
  314. }
  315. const std::vector<Control*>& Container::getControls() const
  316. {
  317. return _controls;
  318. }
  319. void Container::setScroll(Scroll scroll)
  320. {
  321. if (scroll != _scroll)
  322. {
  323. _scroll = scroll;
  324. _dirty = true;
  325. }
  326. }
  327. Container::Scroll Container::getScroll() const
  328. {
  329. return _scroll;
  330. }
  331. void Container::setScrollBarsAutoHide(bool autoHide)
  332. {
  333. if (autoHide != _scrollBarsAutoHide)
  334. {
  335. _scrollBarsAutoHide = autoHide;
  336. _dirty = true;
  337. }
  338. }
  339. bool Container::isScrollBarsAutoHide() const
  340. {
  341. return _scrollBarsAutoHide;
  342. }
  343. bool Container::isScrolling() const
  344. {
  345. if (_parent && _parent->isScrolling())
  346. return true;
  347. return (_scrolling &&
  348. (abs(_scrollingLastX - _scrollingVeryFirstX) > SCROLL_THRESHOLD ||
  349. abs(_scrollingLastY - _scrollingVeryFirstY) > SCROLL_THRESHOLD));
  350. }
  351. Animation* Container::getAnimation(const char* id) const
  352. {
  353. std::vector<Control*>::const_iterator itr = _controls.begin();
  354. std::vector<Control*>::const_iterator end = _controls.end();
  355. Control* control = NULL;
  356. for (; itr != end; itr++)
  357. {
  358. control = *itr;
  359. GP_ASSERT(control);
  360. Animation* animation = control->getAnimation(id);
  361. if (animation)
  362. return animation;
  363. if (control->isContainer())
  364. {
  365. animation = ((Container*)control)->getAnimation(id);
  366. if (animation)
  367. return animation;
  368. }
  369. }
  370. return NULL;
  371. }
  372. const char* Container::getType() const
  373. {
  374. return "container";
  375. }
  376. void Container::update(const Control* container, const Vector2& offset)
  377. {
  378. // Update this container's viewport.
  379. Control::update(container, offset);
  380. // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
  381. if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
  382. {
  383. _scrollBarLeftCap = getImage("scrollBarLeftCap", _state);
  384. _scrollBarHorizontal = getImage("horizontalScrollBar", _state);
  385. _scrollBarRightCap = getImage("scrollBarRightCap", _state);
  386. GP_ASSERT(_scrollBarLeftCap && _scrollBarHorizontal && _scrollBarRightCap);
  387. _viewportClipBounds.height -= _scrollBarHorizontal->getRegion().height;
  388. }
  389. if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
  390. {
  391. _scrollBarTopCap = getImage("scrollBarTopCap", _state);
  392. _scrollBarVertical = getImage("verticalScrollBar", _state);
  393. _scrollBarBottomCap = getImage("scrollBarBottomCap", _state);
  394. GP_ASSERT(_scrollBarTopCap && _scrollBarVertical && _scrollBarBottomCap);
  395. _viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
  396. }
  397. GP_ASSERT(_layout);
  398. if (_scroll != SCROLL_NONE)
  399. {
  400. updateScroll();
  401. }
  402. else
  403. {
  404. _layout->update(this, Vector2::zero());
  405. }
  406. }
  407. void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
  408. {
  409. if (needsClear)
  410. {
  411. GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
  412. float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
  413. GL_ASSERT( glScissor(_clearBounds.x, clearY, _clearBounds.width, _clearBounds.height) );
  414. Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
  415. GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
  416. needsClear = false;
  417. cleared = true;
  418. }
  419. else if (!cleared)
  420. {
  421. needsClear = true;
  422. }
  423. if (!_visible)
  424. return;
  425. spriteBatch->start();
  426. Control::drawBorder(spriteBatch, clip);
  427. spriteBatch->finish();
  428. std::vector<Control*>::const_iterator it;
  429. Rectangle boundsUnion = Rectangle::empty();
  430. for (it = _controls.begin(); it < _controls.end(); it++)
  431. {
  432. Control* control = *it;
  433. GP_ASSERT(control);
  434. if (!needsClear || control->isDirty() || control->_clearBounds.intersects(boundsUnion))
  435. {
  436. control->draw(spriteBatch, _viewportClipBounds, needsClear, cleared, targetHeight);
  437. Rectangle::combine(control->_clearBounds, boundsUnion, &boundsUnion);
  438. }
  439. }
  440. if (_scroll != SCROLL_NONE && (_scrollBarOpacity > 0.0f))
  441. {
  442. // Draw scroll bars.
  443. Rectangle clipRegion(_viewportClipBounds);
  444. spriteBatch->start();
  445. if (_scrollBarBounds.height > 0 &&((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL))
  446. {
  447. const Rectangle& topRegion = _scrollBarTopCap->getRegion();
  448. const Theme::UVs& topUVs = _scrollBarTopCap->getUVs();
  449. Vector4 topColor = _scrollBarTopCap->getColor();
  450. topColor.w *= _scrollBarOpacity * _opacity;
  451. const Rectangle& verticalRegion = _scrollBarVertical->getRegion();
  452. const Theme::UVs& verticalUVs = _scrollBarVertical->getUVs();
  453. Vector4 verticalColor = _scrollBarVertical->getColor();
  454. verticalColor.w *= _scrollBarOpacity * _opacity;
  455. const Rectangle& bottomRegion = _scrollBarBottomCap->getRegion();
  456. const Theme::UVs& bottomUVs = _scrollBarBottomCap->getUVs();
  457. Vector4 bottomColor = _scrollBarBottomCap->getColor();
  458. bottomColor.w *= _scrollBarOpacity * _opacity;
  459. clipRegion.width += verticalRegion.width;
  460. Rectangle bounds(_viewportBounds.x + _viewportBounds.width - verticalRegion.width, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
  461. spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
  462. bounds.y += topRegion.height;
  463. bounds.height = _scrollBarBounds.height - topRegion.height - bottomRegion.height;
  464. spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, verticalUVs.u1, verticalUVs.v1, verticalUVs.u2, verticalUVs.v2, verticalColor, clipRegion);
  465. bounds.y += bounds.height;
  466. bounds.height = bottomRegion.height;
  467. spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, bottomUVs.u1, bottomUVs.v1, bottomUVs.u2, bottomUVs.v2, bottomColor, clipRegion);
  468. }
  469. if (_scrollBarBounds.width > 0 && ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL))
  470. {
  471. const Rectangle& leftRegion = _scrollBarLeftCap->getRegion();
  472. const Theme::UVs& leftUVs = _scrollBarLeftCap->getUVs();
  473. Vector4 leftColor = _scrollBarLeftCap->getColor();
  474. leftColor.w *= _scrollBarOpacity * _opacity;
  475. const Rectangle& horizontalRegion = _scrollBarHorizontal->getRegion();
  476. const Theme::UVs& horizontalUVs = _scrollBarHorizontal->getUVs();
  477. Vector4 horizontalColor = _scrollBarHorizontal->getColor();
  478. horizontalColor.w *= _scrollBarOpacity * _opacity;
  479. const Rectangle& rightRegion = _scrollBarRightCap->getRegion();
  480. const Theme::UVs& rightUVs = _scrollBarRightCap->getUVs();
  481. Vector4 rightColor = _scrollBarRightCap->getColor();
  482. rightColor.w *= _scrollBarOpacity * _opacity;
  483. clipRegion.height += horizontalRegion.height;
  484. Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.y + _viewportBounds.height - horizontalRegion.height, leftRegion.width, leftRegion.height);
  485. spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
  486. bounds.x += leftRegion.width;
  487. bounds.width = _scrollBarBounds.width - leftRegion.width - rightRegion.width;
  488. spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, horizontalUVs.u1, horizontalUVs.v1, horizontalUVs.u2, horizontalUVs.v2, horizontalColor, clipRegion);
  489. bounds.x += bounds.width;
  490. bounds.width = rightRegion.width;
  491. spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, rightUVs.u1, rightUVs.v1, rightUVs.u2, rightUVs.v2, rightColor, clipRegion);
  492. }
  493. spriteBatch->finish();
  494. if (_scrollingVelocity.isZero())
  495. {
  496. _dirty = false;
  497. }
  498. }
  499. else
  500. {
  501. _dirty = false;
  502. }
  503. }
  504. bool Container::isDirty()
  505. {
  506. if (_dirty)
  507. {
  508. return true;
  509. }
  510. else
  511. {
  512. std::vector<Control*>::const_iterator it;
  513. for (it = _controls.begin(); it < _controls.end(); it++)
  514. {
  515. GP_ASSERT(*it);
  516. if ((*it)->isDirty())
  517. {
  518. return true;
  519. }
  520. }
  521. }
  522. return false;
  523. }
  524. bool Container::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  525. {
  526. return pointerEvent(false, evt, x, y, (int)contactIndex);
  527. }
  528. bool Container::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  529. {
  530. return pointerEvent(true, evt, x, y, wheelDelta);
  531. }
  532. bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
  533. {
  534. // This event may run untrusted code by notifying listeners of events.
  535. // If the user calls exit() or otherwise releases this container, we
  536. // need to keep it alive until the method returns.
  537. addRef();
  538. std::vector<Control*>::const_iterator it;
  539. for (it = _controls.begin(); it < _controls.end(); it++)
  540. {
  541. Control* control = *it;
  542. GP_ASSERT(control);
  543. if (!control->isEnabled() || !control->isVisible())
  544. {
  545. continue;
  546. }
  547. if (control->getState() == Control::FOCUS && control->keyEvent(evt, key))
  548. {
  549. release();
  550. return true;
  551. }
  552. }
  553. // If we made it this far, no control handled the event.
  554. if (evt == Keyboard::KEY_CHAR && key == Keyboard::KEY_TAB)
  555. {
  556. moveFocus(NEXT);
  557. return _consumeInputEvents;
  558. }
  559. release();
  560. return false;
  561. }
  562. void Container::guaranteeFocus(Control* inFocus)
  563. {
  564. std::vector<Control*>::const_iterator it;
  565. for (it = _controls.begin(); it < _controls.end(); it++)
  566. {
  567. Control* control = *it;
  568. GP_ASSERT(control);
  569. if (control == inFocus)
  570. continue;
  571. if (control->isContainer())
  572. {
  573. ((Container*)control)->guaranteeFocus(inFocus);
  574. }
  575. else if (control->getState() == Control::FOCUS)
  576. {
  577. control->setState(NORMAL);
  578. return;
  579. }
  580. }
  581. }
  582. bool Container::moveFocus(Direction direction, Control* outsideControl)
  583. {
  584. _direction = direction;
  585. Control* start = outsideControl;
  586. if (!start)
  587. {
  588. std::vector<Control*>::const_iterator it;
  589. for (it = _controls.begin(); it < _controls.end(); it++)
  590. {
  591. Control* control = *it;
  592. GP_ASSERT(control);
  593. if (control->getState() == Control::FOCUS)
  594. {
  595. start = control;
  596. break;
  597. }
  598. }
  599. }
  600. int focusIndex = 0;
  601. Control* next = NULL;
  602. if (start)
  603. {
  604. const Rectangle& startBounds = start->getAbsoluteBounds();
  605. Vector2 vStart, vNext;
  606. float distance = FLT_MAX;
  607. start->setState(Control::NORMAL);
  608. switch(direction)
  609. {
  610. case UP:
  611. vStart.set(startBounds.x + startBounds.width * 0.5f,
  612. startBounds.y);
  613. break;
  614. case DOWN:
  615. vStart.set(startBounds.x + startBounds.width * 0.5f,
  616. startBounds.bottom());
  617. break;
  618. case LEFT:
  619. vStart.set(startBounds.x,
  620. startBounds.y + startBounds.height * 0.5f);
  621. break;
  622. case RIGHT:
  623. vStart.set(startBounds.right(),
  624. startBounds.y + startBounds.height * 0.5f);
  625. break;
  626. case NEXT:
  627. break;
  628. }
  629. if (direction != NEXT)
  630. {
  631. std::vector<Control*>::const_iterator itt;
  632. for (itt = _controls.begin(); itt < _controls.end(); itt++)
  633. {
  634. Control* nextControl = *itt;
  635. if (nextControl == start || nextControl->getFocusIndex() < 0 ||
  636. !nextControl->isEnabled() || !nextControl->isVisible())
  637. {
  638. // Control is not focusable.
  639. continue;
  640. }
  641. const Rectangle& nextBounds = nextControl->getAbsoluteBounds();
  642. switch(direction)
  643. {
  644. case UP:
  645. vNext.set(nextBounds.x + nextBounds.width * 0.5f,
  646. nextBounds.bottom());
  647. if (vNext.y > vStart.y) continue;
  648. break;
  649. case DOWN:
  650. vNext.set(nextBounds.x + nextBounds.width * 0.5f,
  651. nextBounds.y);
  652. if (vNext.y < vStart.y) continue;
  653. break;
  654. case LEFT:
  655. vNext.set(nextBounds.right(),
  656. nextBounds.y + nextBounds.height * 0.5f);
  657. if (vNext.x > vStart.x) continue;
  658. break;
  659. case RIGHT:
  660. vNext.set(nextBounds.x,
  661. nextBounds.y + nextBounds.height * 0.5f);
  662. if (vNext.x < vStart.x) continue;
  663. break;
  664. }
  665. float nextDistance = vStart.distance(vNext);
  666. if (abs(nextDistance) < distance)
  667. {
  668. distance = nextDistance;
  669. next = nextControl;
  670. }
  671. }
  672. }
  673. if (!next)
  674. {
  675. // Check for controls in the given direction in our parent container.
  676. if (!outsideControl && _parent && _parent->moveFocus(direction, start))
  677. {
  678. setState(NORMAL);
  679. _focusChangeRepeat = false;
  680. return true;
  681. }
  682. // No control is in the given direction. Move to the next control in the focus order.
  683. int focusDelta;
  684. switch(direction)
  685. {
  686. case UP:
  687. case LEFT:
  688. focusDelta = -1;
  689. break;
  690. case DOWN:
  691. case RIGHT:
  692. case NEXT:
  693. focusDelta = 1;
  694. break;
  695. }
  696. // Find the index to search for.
  697. if (outsideControl)
  698. {
  699. focusIndex = outsideControl->_parent->getFocusIndex() + focusDelta;
  700. }
  701. else
  702. {
  703. focusIndex = start->getFocusIndex() + focusDelta;
  704. }
  705. if (focusIndex > _focusIndexMax)
  706. {
  707. focusIndex = 0;
  708. }
  709. else if (focusIndex < 0)
  710. {
  711. focusIndex = _focusIndexMax;
  712. }
  713. }
  714. }
  715. if (!next)
  716. {
  717. std::vector<Control*>::const_iterator itt;
  718. for (itt = _controls.begin(); itt < _controls.end(); itt++)
  719. {
  720. Control* nextControl = *itt;
  721. if (nextControl->getFocusIndex() == focusIndex)
  722. {
  723. next = nextControl;
  724. }
  725. }
  726. }
  727. // If we haven't found next by now, then there are no focusable controls in this container.
  728. if (next)
  729. {
  730. next->setState(Control::FOCUS);
  731. _dirty = true;
  732. if (next->isContainer())
  733. {
  734. if (((Container*)next)->moveFocus(direction, start))
  735. {
  736. _focusChangeRepeat = false;
  737. return true;
  738. }
  739. }
  740. // If the next control is not fully visible, scroll the container so that it is.
  741. const Rectangle& bounds = next->getBounds();
  742. if (bounds.x < _scrollPosition.x)
  743. {
  744. // Control is to the left of the scrolled viewport.
  745. _scrollPosition.x = -bounds.x;
  746. }
  747. else if (bounds.x + bounds.width > _scrollPosition.x + _viewportBounds.width)
  748. {
  749. // Control is off to the right.
  750. _scrollPosition.x = -(bounds.x + bounds.width - _viewportBounds.width);
  751. }
  752. if (bounds.y < _viewportBounds.y - _scrollPosition.y)
  753. {
  754. // Control is above the viewport.
  755. _scrollPosition.y = -bounds.y;
  756. }
  757. else if (bounds.y + bounds.height > _viewportBounds.height - _scrollPosition.y)
  758. {
  759. // Control is below the viewport.
  760. _scrollPosition.y = -(bounds.y + bounds.height - _viewportBounds.height);
  761. }
  762. if (outsideControl && outsideControl->_parent)
  763. {
  764. _focusPressed = outsideControl->_parent->_focusPressed;
  765. _focusChangeCount = outsideControl->_parent->_focusChangeCount;
  766. _focusChangeRepeatDelay = outsideControl->_parent->_focusChangeRepeatDelay;
  767. outsideControl->_parent->guaranteeFocus(next);
  768. }
  769. _focusChangeStartTime = Game::getAbsoluteTime();
  770. _focusChangeRepeat = true;
  771. addRef();
  772. Game::getInstance()->schedule(_focusChangeRepeatDelay, this);
  773. return true;
  774. }
  775. return false;
  776. }
  777. void Container::timeEvent(long timeDiff, void* cookie)
  778. {
  779. double time = Game::getAbsoluteTime();
  780. if (_focusChangeRepeat && _state == FOCUS && _focusPressed &&
  781. abs(time - timeDiff - _focusChangeRepeatDelay - _focusChangeStartTime) < 50)
  782. {
  783. ++_focusChangeCount;
  784. if (_focusChangeCount == 5)
  785. {
  786. _focusChangeRepeatDelay *= 0.5;
  787. }
  788. moveFocus(_direction);
  789. }
  790. else
  791. {
  792. _focusChangeCount = 0;
  793. _focusChangeRepeatDelay = FOCUS_CHANGE_REPEAT_DELAY;
  794. }
  795. release();
  796. }
  797. void Container::startScrolling(float x, float y, bool resetTime)
  798. {
  799. _scrollingVelocity.set(-x, y);
  800. _scrolling = true;
  801. _scrollBarOpacity = 1.0f;
  802. _dirty = true;
  803. if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
  804. {
  805. _scrollBarOpacityClip->stop();
  806. _scrollBarOpacityClip = NULL;
  807. }
  808. if (resetTime)
  809. {
  810. _lastFrameTime = Game::getGameTime();
  811. }
  812. }
  813. void Container::stopScrolling()
  814. {
  815. _scrollingVelocity.set(0, 0);
  816. _scrolling = false;
  817. _dirty = true;
  818. }
  819. bool Container::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
  820. {
  821. addRef();
  822. bool eventConsumed = false;
  823. // Pass the event to any control that is active or in focus.
  824. std::vector<Control*>::const_iterator it;
  825. for (it = _controls.begin(); it < _controls.end(); it++)
  826. {
  827. Control* control = *it;
  828. GP_ASSERT(control);
  829. if (control->getState() == Control::FOCUS || control->getState() == Control::ACTIVE)
  830. {
  831. eventConsumed |= control->gamepadEvent(evt, gamepad, analogIndex);
  832. break;
  833. }
  834. }
  835. // First check if a selection button is down.
  836. if (!_selectButtonDown)
  837. {
  838. if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
  839. gamepad->isButtonDown(Gamepad::BUTTON_X))
  840. {
  841. _selectButtonDown = true;
  842. _focusChangeRepeat = false;
  843. eventConsumed |= _consumeInputEvents;
  844. }
  845. }
  846. else
  847. {
  848. if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
  849. !gamepad->isButtonDown(Gamepad::BUTTON_X))
  850. {
  851. _selectButtonDown = false;
  852. }
  853. }
  854. Vector2 joystick;
  855. gamepad->getJoystickValues(analogIndex, &joystick);
  856. // Don't allow focus changes or scrolling while a selection button is down.
  857. if (!_selectButtonDown && !eventConsumed)
  858. {
  859. switch (evt)
  860. {
  861. case Gamepad::BUTTON_EVENT:
  862. {
  863. // Shift focus forward or backward when the DPad is used.
  864. if (!(_focusPressed & DOWN) &&
  865. gamepad->isButtonDown(Gamepad::BUTTON_DOWN))
  866. {
  867. _focusPressed |= DOWN;
  868. eventConsumed |= _consumeInputEvents;
  869. if (moveFocus(DOWN))
  870. break;
  871. else
  872. startScrolling(0, -GAMEPAD_SCROLL_SPEED);
  873. }
  874. if (!(_focusPressed & RIGHT) &&
  875. gamepad->isButtonDown(Gamepad::BUTTON_RIGHT))
  876. {
  877. _focusPressed |= RIGHT;
  878. eventConsumed |= _consumeInputEvents;
  879. if (moveFocus(RIGHT))
  880. break;
  881. else
  882. startScrolling(GAMEPAD_SCROLL_SPEED, 0);
  883. }
  884. if (!(_focusPressed & UP) &&
  885. gamepad->isButtonDown(Gamepad::BUTTON_UP))
  886. {
  887. _focusPressed |= UP;
  888. eventConsumed |= _consumeInputEvents;
  889. if (moveFocus(UP))
  890. break;
  891. else
  892. startScrolling(0, GAMEPAD_SCROLL_SPEED);
  893. }
  894. if (!(_focusPressed & LEFT) &&
  895. gamepad->isButtonDown(Gamepad::BUTTON_LEFT))
  896. {
  897. _focusPressed |= LEFT;
  898. eventConsumed |= _consumeInputEvents;
  899. if (moveFocus(LEFT))
  900. break;
  901. else
  902. startScrolling(-GAMEPAD_SCROLL_SPEED, 0);
  903. }
  904. break;
  905. }
  906. case Gamepad::JOYSTICK_EVENT:
  907. {
  908. switch (analogIndex)
  909. {
  910. case 0:
  911. // The left analog stick can be used in the same way as the DPad.
  912. eventConsumed |= _consumeInputEvents;
  913. if (!(_focusPressed & RIGHT) &&
  914. joystick.x > JOYSTICK_THRESHOLD)
  915. {
  916. _focusPressed |= RIGHT;
  917. if (moveFocus(RIGHT))
  918. break;
  919. else
  920. startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
  921. }
  922. if (!(_focusPressed & DOWN) &&
  923. joystick.y < -JOYSTICK_THRESHOLD)
  924. {
  925. _focusPressed |= DOWN;
  926. if (moveFocus(DOWN))
  927. break;
  928. else
  929. startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
  930. }
  931. if (!(_focusPressed & LEFT) &&
  932. joystick.x < -JOYSTICK_THRESHOLD)
  933. {
  934. _focusPressed |= LEFT;
  935. if (moveFocus(LEFT))
  936. break;
  937. else
  938. startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
  939. }
  940. if (!(_focusPressed & UP) &&
  941. joystick.y > JOYSTICK_THRESHOLD)
  942. {
  943. _focusPressed |= UP;
  944. if (moveFocus(UP))
  945. break;
  946. else
  947. startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
  948. }
  949. break;
  950. case 1:
  951. // The right analog stick can be used to scroll.
  952. if (_scroll != SCROLL_NONE)
  953. {
  954. if (_scrolling)
  955. {
  956. if (joystick.isZero())
  957. {
  958. stopScrolling();
  959. }
  960. else
  961. {
  962. startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, false);
  963. }
  964. }
  965. else
  966. {
  967. startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y);
  968. }
  969. release();
  970. return _consumeInputEvents;
  971. }
  972. break;
  973. }
  974. }
  975. }
  976. }
  977. if ((evt == Gamepad::BUTTON_EVENT || evt == Gamepad::JOYSTICK_EVENT) &&
  978. analogIndex == 0)
  979. {
  980. if ((_focusPressed & DOWN) &&
  981. !gamepad->isButtonDown(Gamepad::BUTTON_DOWN) &&
  982. joystick.y > -JOYSTICK_THRESHOLD)
  983. {
  984. _focusPressed &= ~DOWN;
  985. eventConsumed |= _consumeInputEvents;
  986. }
  987. if ((_focusPressed & RIGHT) &&
  988. !gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) &&
  989. joystick.x < JOYSTICK_THRESHOLD)
  990. {
  991. _focusPressed &= ~RIGHT;
  992. eventConsumed |= _consumeInputEvents;
  993. }
  994. if ((_focusPressed & UP) &&
  995. !gamepad->isButtonDown(Gamepad::BUTTON_UP) &&
  996. joystick.y < JOYSTICK_THRESHOLD)
  997. {
  998. _focusPressed &= ~UP;
  999. eventConsumed |= _consumeInputEvents;
  1000. }
  1001. if ((_focusPressed & LEFT) &&
  1002. !gamepad->isButtonDown(Gamepad::BUTTON_LEFT) &&
  1003. joystick.x > -JOYSTICK_THRESHOLD)
  1004. {
  1005. _focusPressed &= ~LEFT;
  1006. eventConsumed |= _consumeInputEvents;
  1007. }
  1008. }
  1009. if (!_focusPressed && _scrolling)
  1010. {
  1011. stopScrolling();
  1012. }
  1013. release();
  1014. return eventConsumed;
  1015. }
  1016. bool Container::isContainer() const
  1017. {
  1018. return true;
  1019. }
  1020. Layout::Type Container::getLayoutType(const char* layoutString)
  1021. {
  1022. if (!layoutString)
  1023. {
  1024. return Layout::LAYOUT_ABSOLUTE;
  1025. }
  1026. std::string layoutName(layoutString);
  1027. std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
  1028. if (layoutName == "LAYOUT_ABSOLUTE")
  1029. {
  1030. return Layout::LAYOUT_ABSOLUTE;
  1031. }
  1032. else if (layoutName == "LAYOUT_VERTICAL")
  1033. {
  1034. return Layout::LAYOUT_VERTICAL;
  1035. }
  1036. else if (layoutName == "LAYOUT_FLOW")
  1037. {
  1038. return Layout::LAYOUT_FLOW;
  1039. }
  1040. else
  1041. {
  1042. // Default.
  1043. return Layout::LAYOUT_ABSOLUTE;
  1044. }
  1045. }
  1046. void Container::updateScroll()
  1047. {
  1048. if (!_initializedWithScroll)
  1049. {
  1050. _initializedWithScroll = true;
  1051. _layout->update(this, _scrollPosition);
  1052. }
  1053. // Update time.
  1054. if (!_lastFrameTime)
  1055. {
  1056. _lastFrameTime = Game::getGameTime();
  1057. }
  1058. double frameTime = Game::getGameTime();
  1059. float elapsedTime = (float)(frameTime - _lastFrameTime);
  1060. _lastFrameTime = frameTime;
  1061. const Theme::Border& containerBorder = getBorder(_state);
  1062. const Theme::Padding& containerPadding = getPadding();
  1063. // Calculate total width and height.
  1064. std::vector<Control*> controls = getControls();
  1065. for (size_t i = 0, controlsCount = controls.size(); i < controlsCount; i++)
  1066. {
  1067. Control* control = controls.at(i);
  1068. const Rectangle& bounds = control->getBounds();
  1069. const Theme::Margin& margin = control->getMargin();
  1070. float newWidth = bounds.x + bounds.width;
  1071. if (newWidth > _totalWidth)
  1072. {
  1073. _totalWidth = newWidth;
  1074. }
  1075. float newHeight = bounds.y + bounds.height;
  1076. if (newHeight > _totalHeight)
  1077. {
  1078. _totalHeight = newHeight;
  1079. }
  1080. }
  1081. float vWidth = getImageRegion("verticalScrollBar", _state).width;
  1082. float hHeight = getImageRegion("horizontalScrollBar", _state).height;
  1083. float clipWidth = _bounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right - vWidth;
  1084. float clipHeight = _bounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
  1085. // Apply and dampen inertia.
  1086. if (!_scrollingVelocity.isZero())
  1087. {
  1088. // Calculate the time passed since last update.
  1089. float elapsedSecs = (float)elapsedTime * 0.001f;
  1090. _scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
  1091. _scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
  1092. if (!_scrolling)
  1093. {
  1094. float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
  1095. _scrollingVelocity.x *= dampening;
  1096. _scrollingVelocity.y *= dampening;
  1097. if (fabs(_scrollingVelocity.x) < 100.0f)
  1098. _scrollingVelocity.x = 0.0f;
  1099. if (fabs(_scrollingVelocity.y) < 100.0f)
  1100. _scrollingVelocity.y = 0.0f;
  1101. }
  1102. }
  1103. // Stop scrolling when the far edge is reached.
  1104. if (-_scrollPosition.x > _totalWidth - clipWidth)
  1105. {
  1106. _scrollPosition.x = -(_totalWidth - clipWidth);
  1107. _scrollingVelocity.x = 0;
  1108. }
  1109. if (-_scrollPosition.y > _totalHeight - clipHeight)
  1110. {
  1111. _scrollPosition.y = -(_totalHeight - clipHeight);
  1112. _scrollingVelocity.y = 0;
  1113. }
  1114. if (_scrollPosition.x > 0)
  1115. {
  1116. _scrollPosition.x = 0;
  1117. _scrollingVelocity.x = 0;
  1118. }
  1119. if (_scrollPosition.y > 0)
  1120. {
  1121. _scrollPosition.y = 0;
  1122. _scrollingVelocity.y = 0;
  1123. }
  1124. float scrollWidth = 0;
  1125. if (clipWidth < _totalWidth)
  1126. scrollWidth = (clipWidth / _totalWidth) * clipWidth;
  1127. float scrollHeight = 0;
  1128. if (clipHeight < _totalHeight)
  1129. scrollHeight = (clipHeight / _totalHeight) * clipHeight;
  1130. _scrollBarBounds.set(((-_scrollPosition.x) / _totalWidth) * clipWidth,
  1131. ((-_scrollPosition.y) / _totalHeight) * clipHeight,
  1132. scrollWidth, scrollHeight);
  1133. // If scroll velocity is 0 and scrollbars are not always visible, trigger fade-out animation.
  1134. if (!_scrolling && _scrollingVelocity.isZero() && _scrollBarsAutoHide && _scrollBarOpacity == 1.0f)
  1135. {
  1136. float to = 0;
  1137. _scrollBarOpacity = 0.99f;
  1138. if (!_scrollBarOpacityClip)
  1139. {
  1140. Animation* animation = createAnimationFromTo("scrollbar-fade-out", ANIMATE_SCROLLBAR_OPACITY, &_scrollBarOpacity, &to, Curve::QUADRATIC_IN_OUT, 500L);
  1141. _scrollBarOpacityClip = animation->getClip();
  1142. }
  1143. _scrollBarOpacityClip->play();
  1144. }
  1145. // Position controls within scroll area.
  1146. _layout->update(this, _scrollPosition);
  1147. }
  1148. void Container::sortControls()
  1149. {
  1150. if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
  1151. {
  1152. std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
  1153. }
  1154. }
  1155. bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  1156. {
  1157. switch(evt)
  1158. {
  1159. case Touch::TOUCH_PRESS:
  1160. if (_contactIndex == INVALID_CONTACT_INDEX)
  1161. {
  1162. _contactIndex = (int) contactIndex;
  1163. _contactIndices++;
  1164. _scrollingLastX = _scrollingFirstX = _scrollingVeryFirstX = x;
  1165. _scrollingLastY = _scrollingFirstY = _scrollingVeryFirstY = y;
  1166. _scrollingVelocity.set(0, 0);
  1167. _scrolling = true;
  1168. _scrollingStartTimeX = _scrollingStartTimeY = 0;
  1169. if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
  1170. {
  1171. _scrollBarOpacityClip->stop();
  1172. _scrollBarOpacityClip = NULL;
  1173. }
  1174. _scrollBarOpacity = 1.0f;
  1175. _dirty = true;
  1176. return _consumeInputEvents;
  1177. }
  1178. break;
  1179. case Touch::TOUCH_MOVE:
  1180. if (_scrolling && _contactIndex == (int) contactIndex)
  1181. {
  1182. double gameTime = Game::getAbsoluteTime();
  1183. // Calculate the latest movement delta for the next update to use.
  1184. int vx = x - _scrollingLastX;
  1185. int vy = y - _scrollingLastY;
  1186. if (_scrollingMouseVertically)
  1187. {
  1188. float yRatio = _totalHeight / _absoluteBounds.height;
  1189. vy *= yRatio;
  1190. _scrollingVelocity.set(0, -vy);
  1191. _scrollPosition.y -= vy;
  1192. }
  1193. else if (_scrollingMouseHorizontally)
  1194. {
  1195. float xRatio = _totalWidth / _absoluteBounds.width;
  1196. vx *= xRatio;
  1197. _scrollingVelocity.set(-vx, 0);
  1198. _scrollPosition.x -= vx;
  1199. }
  1200. else
  1201. {
  1202. _scrollingVelocity.set(vx, vy);
  1203. _scrollPosition.x += vx;
  1204. _scrollPosition.y += vy;
  1205. }
  1206. _scrollingLastX = x;
  1207. _scrollingLastY = y;
  1208. // If the user changes direction, reset the start time and position.
  1209. bool goingRight = (vx > 0);
  1210. if (goingRight != _scrollingRight)
  1211. {
  1212. _scrollingFirstX = x;
  1213. _scrollingRight = goingRight;
  1214. _scrollingStartTimeX = gameTime;
  1215. }
  1216. bool goingDown = (vy > 0);
  1217. if (goingDown != _scrollingDown)
  1218. {
  1219. _scrollingFirstY = y;
  1220. _scrollingDown = goingDown;
  1221. _scrollingStartTimeY = gameTime;
  1222. }
  1223. if (!_scrollingStartTimeX)
  1224. _scrollingStartTimeX = gameTime;
  1225. if (!_scrollingStartTimeY)
  1226. _scrollingStartTimeY = gameTime;
  1227. _scrollingLastTime = gameTime;
  1228. _dirty = true;
  1229. return _consumeInputEvents;
  1230. }
  1231. break;
  1232. case Touch::TOUCH_RELEASE:
  1233. if (_contactIndex == (int) contactIndex)
  1234. {
  1235. _contactIndex = INVALID_CONTACT_INDEX;
  1236. _contactIndices--;
  1237. _scrolling = false;
  1238. double gameTime = Game::getAbsoluteTime();
  1239. float timeSinceLastMove = (float)(gameTime - _scrollingLastTime);
  1240. if (timeSinceLastMove > SCROLL_INERTIA_DELAY)
  1241. {
  1242. _scrollingVelocity.set(0, 0);
  1243. _scrollingMouseVertically = _scrollingMouseHorizontally = false;
  1244. _dirty = true;
  1245. return _consumeInputEvents;
  1246. }
  1247. int dx = _scrollingLastX - _scrollingFirstX;
  1248. int dy = _scrollingLastY - _scrollingFirstY;
  1249. float timeTakenX = (float)(gameTime - _scrollingStartTimeX);
  1250. float elapsedSecsX = timeTakenX * 0.001f;
  1251. float timeTakenY = (float)(gameTime - _scrollingStartTimeY);
  1252. float elapsedSecsY = timeTakenY * 0.001f;
  1253. float vx = dx;
  1254. float vy = dy;
  1255. if (elapsedSecsX > 0)
  1256. vx = (float)dx / elapsedSecsX;
  1257. if (elapsedSecsY > 0)
  1258. vy = (float)dy / elapsedSecsY;
  1259. if (_scrollingMouseVertically)
  1260. {
  1261. float yRatio = _totalHeight / _absoluteBounds.height;
  1262. vy *= yRatio;
  1263. _scrollingVelocity.set(0, -vy);
  1264. }
  1265. else if (_scrollingMouseHorizontally)
  1266. {
  1267. float xRatio = _totalWidth / _absoluteBounds.width;
  1268. vx *= xRatio;
  1269. _scrollingVelocity.set(-vx, 0);
  1270. }
  1271. else
  1272. {
  1273. _scrollingVelocity.set(vx, vy);
  1274. }
  1275. _scrollingMouseVertically = _scrollingMouseHorizontally = false;
  1276. _dirty = true;
  1277. return _consumeInputEvents;
  1278. }
  1279. break;
  1280. }
  1281. return false;
  1282. }
  1283. bool Container::mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  1284. {
  1285. switch(evt)
  1286. {
  1287. case Mouse::MOUSE_PRESS_LEFT_BUTTON:
  1288. {
  1289. if (_scrollBarVertical)
  1290. {
  1291. float vWidth = _scrollBarVertical->getRegion().width;
  1292. Rectangle vBounds(_viewportBounds.x + _viewportBounds.width - vWidth,
  1293. _scrollBarBounds.y,
  1294. vWidth, _scrollBarBounds.height);
  1295. if (x + _viewportBounds.x >= vBounds.x &&
  1296. x + _viewportBounds.x <= vBounds.x + vBounds.width)
  1297. {
  1298. // Then we're within the horizontal bounds of the vertical scrollbar.
  1299. // We want to either jump up or down, or drag the scrollbar itself.
  1300. if (y < vBounds.y)
  1301. {
  1302. _scrollPosition.y += _totalHeight / 5.0f;
  1303. }
  1304. else if (y > vBounds.y + vBounds.height)
  1305. {
  1306. _scrollPosition.y -= _totalHeight / 5.0f;
  1307. }
  1308. else
  1309. {
  1310. _scrollingMouseVertically = true;
  1311. }
  1312. }
  1313. }
  1314. if (_scrollBarHorizontal)
  1315. {
  1316. float hHeight = _scrollBarHorizontal->getRegion().height;
  1317. Rectangle hBounds(_scrollBarBounds.x,
  1318. _viewportBounds.y + _viewportBounds.height - hHeight,
  1319. _scrollBarBounds.width, hHeight);
  1320. if (y + _viewportBounds.y >= hBounds.y &&
  1321. y + _viewportBounds.y <= hBounds.y + hBounds.height)
  1322. {
  1323. // We're within the vertical bounds of the horizontal scrollbar.
  1324. if (x < hBounds.x)
  1325. _scrollPosition.x += _totalWidth / 5.0f;
  1326. else if (x > hBounds.x + hBounds.width)
  1327. _scrollPosition.x -= _totalWidth / 5.0f;
  1328. else
  1329. _scrollingMouseHorizontally = true;
  1330. }
  1331. }
  1332. return touchEventScroll(Touch::TOUCH_PRESS, x, y, 0);
  1333. }
  1334. case Mouse::MOUSE_MOVE:
  1335. return touchEventScroll(Touch::TOUCH_MOVE, x, y, 0);
  1336. case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
  1337. return touchEventScroll(Touch::TOUCH_RELEASE, x, y, 0);
  1338. case Mouse::MOUSE_WHEEL:
  1339. _scrollPosition.y += (_totalHeight / 10.0f) * wheelDelta;
  1340. if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
  1341. {
  1342. _scrollBarOpacityClip->stop();
  1343. _scrollBarOpacityClip = NULL;
  1344. }
  1345. _scrollBarOpacity = 1.0f;
  1346. _dirty = true;
  1347. return _consumeInputEvents;
  1348. }
  1349. return false;
  1350. }
  1351. bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
  1352. {
  1353. if (!isEnabled() || !isVisible())
  1354. {
  1355. return false;
  1356. }
  1357. // This event may run untrusted code by notifying listeners of events.
  1358. // If the user calls exit() or otherwise releases this container, we
  1359. // need to keep it alive until the method returns.
  1360. addRef();
  1361. bool eventConsumed = false;
  1362. const Theme::Border& border = getBorder(_state);
  1363. const Theme::Padding& padding = getPadding();
  1364. float xPos = border.left + padding.left;
  1365. float yPos = border.top + padding.top;
  1366. Vector2* offset = NULL;
  1367. if (_scroll != SCROLL_NONE)
  1368. {
  1369. offset = &_scrollPosition;
  1370. }
  1371. std::vector<Control*>::const_iterator it;
  1372. for (it = _controls.begin(); it < _controls.end(); it++)
  1373. {
  1374. Control* control = *it;
  1375. GP_ASSERT(control);
  1376. if (!control->isEnabled() || !control->isVisible())
  1377. {
  1378. continue;
  1379. }
  1380. const Rectangle& bounds = control->getBounds();
  1381. float boundsX = bounds.x;
  1382. float boundsY = bounds.y;
  1383. if (offset)
  1384. {
  1385. boundsX += offset->x;
  1386. boundsY += offset->y;
  1387. }
  1388. Control::State currentState = control->getState();
  1389. if ((control->isContainer() && currentState == Control::FOCUS) ||
  1390. (currentState != Control::NORMAL) ||
  1391. ((evt == Touch::TOUCH_PRESS ||
  1392. evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
  1393. evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
  1394. evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON) &&
  1395. x >= xPos + boundsX &&
  1396. x <= xPos + boundsX + bounds.width &&
  1397. y >= yPos + boundsY &&
  1398. y <= yPos + boundsY + bounds.height))
  1399. {
  1400. // Pass on the event's clip relative to the control.
  1401. if (mouse)
  1402. eventConsumed |= control->mouseEvent((Mouse::MouseEvent)evt, x - xPos - boundsX, y - yPos - boundsY, data);
  1403. else
  1404. eventConsumed |= control->touchEvent((Touch::TouchEvent)evt, x - xPos - boundsX, y - yPos - boundsY, (unsigned int)data);
  1405. }
  1406. }
  1407. if (!isEnabled() || !isVisible())
  1408. {
  1409. release();
  1410. return (_consumeInputEvents | eventConsumed);
  1411. }
  1412. bool withinClipBounds = false;
  1413. switch (evt)
  1414. {
  1415. case Touch::TOUCH_PRESS:
  1416. if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
  1417. y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
  1418. {
  1419. setState(Control::FOCUS);
  1420. withinClipBounds = true;
  1421. if (eventConsumed)
  1422. _contactIndices++;
  1423. }
  1424. else if (_contactIndices == 0)
  1425. {
  1426. setState(Control::NORMAL);
  1427. _contactIndex = INVALID_CONTACT_INDEX;
  1428. release();
  1429. return false;
  1430. }
  1431. break;
  1432. case Touch::TOUCH_RELEASE:
  1433. if (eventConsumed)
  1434. {
  1435. if (_contactIndices > 0)
  1436. _contactIndices--;
  1437. }
  1438. break;
  1439. }
  1440. if (!eventConsumed && _scroll != SCROLL_NONE && getState() == Control::FOCUS && (evt != Touch::TOUCH_PRESS || withinClipBounds))
  1441. {
  1442. if ((mouse && mouseEventScroll((Mouse::MouseEvent)evt, x - xPos, y - yPos, data)) ||
  1443. (!mouse && touchEventScroll((Touch::TouchEvent)evt, x - xPos, y - yPos, (unsigned int)data)))
  1444. {
  1445. eventConsumed = true;
  1446. }
  1447. }
  1448. release();
  1449. if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
  1450. y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
  1451. return (_consumeInputEvents | eventConsumed);
  1452. else
  1453. return eventConsumed;
  1454. }
  1455. Container::Scroll Container::getScroll(const char* scroll)
  1456. {
  1457. if (!scroll)
  1458. return Container::SCROLL_NONE;
  1459. if (strcmp(scroll, "SCROLL_NONE") == 0)
  1460. {
  1461. return Container::SCROLL_NONE;
  1462. }
  1463. else if (strcmp(scroll, "SCROLL_HORIZONTAL") == 0)
  1464. {
  1465. return Container::SCROLL_HORIZONTAL;
  1466. }
  1467. else if (strcmp(scroll, "SCROLL_VERTICAL") == 0)
  1468. {
  1469. return Container::SCROLL_VERTICAL;
  1470. }
  1471. else if (strcmp(scroll, "SCROLL_BOTH") == 0)
  1472. {
  1473. return Container::SCROLL_BOTH;
  1474. }
  1475. else
  1476. {
  1477. GP_ERROR("Failed to get corresponding scroll state for unsupported value '%s'.", scroll);
  1478. }
  1479. return Container::SCROLL_NONE;
  1480. }
  1481. static bool sortControlsByZOrder(Control* c1, Control* c2)
  1482. {
  1483. if (c1->getZIndex() < c2->getZIndex())
  1484. return true;
  1485. return false;
  1486. }
  1487. unsigned int Container::getAnimationPropertyComponentCount(int propertyId) const
  1488. {
  1489. switch(propertyId)
  1490. {
  1491. case ANIMATE_SCROLLBAR_OPACITY:
  1492. return 1;
  1493. default:
  1494. return Control::getAnimationPropertyComponentCount(propertyId);
  1495. }
  1496. }
  1497. void Container::getAnimationPropertyValue(int propertyId, AnimationValue* value)
  1498. {
  1499. GP_ASSERT(value);
  1500. switch(propertyId)
  1501. {
  1502. case ANIMATE_SCROLLBAR_OPACITY:
  1503. value->setFloat(0, _scrollBarOpacity);
  1504. break;
  1505. default:
  1506. Control::getAnimationPropertyValue(propertyId, value);
  1507. break;
  1508. }
  1509. }
  1510. void Container::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
  1511. {
  1512. GP_ASSERT(value);
  1513. switch(propertyId)
  1514. {
  1515. case ANIMATE_SCROLLBAR_OPACITY:
  1516. _scrollBarOpacity = Curve::lerp(blendWeight, _opacity, value->getFloat(0));
  1517. _dirty = true;
  1518. break;
  1519. default:
  1520. Control::setAnimationPropertyValue(propertyId, value, blendWeight);
  1521. break;
  1522. }
  1523. }
  1524. }