Container.cpp 60 KB

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