Container.cpp 54 KB

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