Container.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  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 "JoystickControl.h"
  14. #include "ImageControl.h"
  15. #include "Form.h"
  16. #include "Game.h"
  17. #include "ControlFactory.h"
  18. namespace gameplay
  19. {
  20. // If the user stops scrolling for this amount of time (in millis) before touch/click release, don't apply inertia.
  21. static const long SCROLL_INERTIA_DELAY = 100L;
  22. // Factor to multiply friction by before applying to velocity.
  23. static const float SCROLL_FRICTION_FACTOR = 5.0f;
  24. // Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
  25. static const float SCROLL_THRESHOLD = 10.0f;
  26. // Number of milliseconds to fade auto-hide scrollbars out for
  27. static const long SCROLLBAR_FADE_TIME = 1500L;
  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), _activeControl(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),
  54. _selectButtonDown(false), _lastFrameTime(0), _totalWidth(0), _totalHeight(0),
  55. _initializedWithScroll(false), _scrollWheelRequiresFocus(false)
  56. {
  57. clearContacts();
  58. }
  59. Container::~Container()
  60. {
  61. std::vector<Control*>::iterator it;
  62. for (it = _controls.begin(); it < _controls.end(); it++)
  63. {
  64. SAFE_RELEASE((*it));
  65. }
  66. SAFE_RELEASE(_layout);
  67. }
  68. Container* Container::create(const char* id, Theme::Style* style, Layout::Type layout)
  69. {
  70. Container* container = new Container();
  71. container->_id = id ? id : "";
  72. container->_layout = createLayout(layout);
  73. container->initialize("Container", style, NULL);
  74. return container;
  75. }
  76. Control* Container::create(Theme::Style* style, Properties* properties)
  77. {
  78. Container* container = new Container();
  79. container->initialize("Container", style, properties);
  80. return container;
  81. }
  82. void Container::initialize(const char* typeName, Theme::Style* style, Properties* properties)
  83. {
  84. Control::initialize(typeName, style, properties);
  85. if (properties)
  86. {
  87. // Parse layout
  88. Properties* layoutNS = properties->getNamespace("layout", true, false);
  89. if (layoutNS)
  90. {
  91. _layout = createLayout(getLayoutType(layoutNS->getString("type")));
  92. switch (_layout->getType())
  93. {
  94. case Layout::LAYOUT_FLOW:
  95. static_cast<FlowLayout*>(_layout)->setSpacing(layoutNS->getInt("horizontalSpacing"), layoutNS->getInt("verticalSpacing"));
  96. break;
  97. case Layout::LAYOUT_VERTICAL:
  98. static_cast<VerticalLayout*>(_layout)->setSpacing(layoutNS->getInt("spacing"));
  99. break;
  100. }
  101. }
  102. else
  103. {
  104. _layout = createLayout(getLayoutType(properties->getString("layout")));
  105. }
  106. setScroll(getScroll(properties->getString("scroll")));
  107. _scrollBarsAutoHide = properties->getBool("scrollBarsAutoHide");
  108. if (_scrollBarsAutoHide)
  109. {
  110. _scrollBarOpacity = 0.0f;
  111. }
  112. _scrollWheelRequiresFocus = properties->getBool("scrollWheelRequiresFocus");
  113. if (properties->exists("scrollingFriction"))
  114. _scrollingFriction = properties->getFloat("scrollingFriction");
  115. if (properties->exists("scrollWheelSpeed"))
  116. _scrollWheelSpeed = properties->getFloat("scrollWheelSpeed");
  117. addControls(properties);
  118. const char* activeControl = properties->getString("activeControl");
  119. if (activeControl)
  120. {
  121. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  122. {
  123. if (_controls[i]->_id == activeControl)
  124. {
  125. _activeControl = _controls[i];
  126. break;
  127. }
  128. }
  129. }
  130. }
  131. // Create a default layout if one does not yet exist
  132. if (_layout == NULL)
  133. _layout = createLayout(Layout::LAYOUT_ABSOLUTE);
  134. }
  135. void Container::addControls(Properties* properties)
  136. {
  137. GP_ASSERT(properties);
  138. // Add all the controls to this container.
  139. Properties* controlSpace = properties->getNextNamespace();
  140. while (controlSpace != NULL)
  141. {
  142. const char* controlName = controlSpace->getNamespace();
  143. // Pass our own style into the creation of the child control.
  144. // The child control's style will be looked up using the passed in style's theme.
  145. Control* control = ControlFactory::getInstance()->createControl(controlName, _style, controlSpace);
  146. // Add the new control to the form.
  147. if (control)
  148. {
  149. addControl(control);
  150. control->release();
  151. }
  152. // Get the next control.
  153. controlSpace = properties->getNextNamespace();
  154. }
  155. // Sort controls by Z-Order.
  156. sortControls();
  157. }
  158. Layout* Container::getLayout()
  159. {
  160. return _layout;
  161. }
  162. void Container::setLayout(Layout::Type type)
  163. {
  164. if (_layout == NULL || _layout->getType() != type)
  165. {
  166. SAFE_RELEASE(_layout);
  167. _layout = createLayout(type);
  168. setDirty(Control::DIRTY_BOUNDS);
  169. }
  170. }
  171. unsigned int Container::addControl(Control* control)
  172. {
  173. GP_ASSERT(control);
  174. if( control->_parent == this )
  175. {
  176. // Control is already in this container.
  177. // Do nothing but determine and return control's index.
  178. const size_t size = _controls.size();
  179. for( size_t i = 0; i < size; ++i ) {
  180. Control* c = _controls[ i ];
  181. if( c == control ) {
  182. return (unsigned int)i;
  183. }
  184. }
  185. // Should never reach this.
  186. GP_ASSERT( false );
  187. return 0;
  188. }
  189. if( control->getZIndex() == -1 ) {
  190. control->setZIndex( _zIndexDefault++ );
  191. }
  192. if( control->getFocusIndex() == -1 ) {
  193. // Find the current largest focus index
  194. int maxFocusIndex = 0;
  195. for( size_t i = 0, count = _controls.size(); i < count; ++i ) {
  196. if( _controls[ i ]->_focusIndex > maxFocusIndex )
  197. maxFocusIndex = _controls[ i ]->_focusIndex;
  198. }
  199. control->setFocusIndex( maxFocusIndex + 1 );
  200. }
  201. _controls.push_back( control );
  202. control->addRef();
  203. // Remove the control from its current parent
  204. if( control->_parent )
  205. {
  206. control->_parent->removeControl( control );
  207. }
  208. control->_parent = this;
  209. sortControls();
  210. return (unsigned int)( _controls.size() - 1 );
  211. }
  212. void Container::insertControl(Control* control, unsigned int index)
  213. {
  214. GP_ASSERT(control);
  215. if (control->_parent && control->_parent != this)
  216. {
  217. control->_parent->removeControl(control);
  218. }
  219. if (control->_parent != this)
  220. {
  221. std::vector<Control*>::iterator it = _controls.begin() + index;
  222. _controls.insert(it, control);
  223. control->addRef();
  224. control->_parent = this;
  225. }
  226. }
  227. void Container::removeControl(unsigned int index)
  228. {
  229. GP_ASSERT(index < _controls.size());
  230. std::vector<Control*>::iterator it = _controls.begin() + index;
  231. Control* control = *it;
  232. _controls.erase(it);
  233. control->_parent = NULL;
  234. if (_activeControl == control)
  235. _activeControl = NULL;
  236. Form::verifyRemovedControlState(control);
  237. SAFE_RELEASE(control);
  238. }
  239. void Container::removeControl(const char* id)
  240. {
  241. GP_ASSERT(id);
  242. for (size_t i = 0, size = _controls.size(); i < size; ++i)
  243. {
  244. Control* c = _controls[i];
  245. if (strcmp(id, c->getId()) == 0)
  246. {
  247. removeControl((unsigned int)i);
  248. return;
  249. }
  250. }
  251. }
  252. void Container::removeControl(Control* control)
  253. {
  254. GP_ASSERT(control);
  255. for (size_t i = 0, size = _controls.size(); i < size; ++i)
  256. {
  257. Control* c = _controls[i];
  258. if (c == control)
  259. {
  260. removeControl((unsigned int)i);
  261. return;
  262. }
  263. }
  264. }
  265. Control* Container::getControl(unsigned int index) const
  266. {
  267. GP_ASSERT(index < _controls.size());
  268. return _controls[index];
  269. }
  270. Control* Container::getControl(const char* id) const
  271. {
  272. GP_ASSERT(id);
  273. std::vector<Control*>::const_iterator it;
  274. for (it = _controls.begin(); it < _controls.end(); it++)
  275. {
  276. Control* c = *it;
  277. GP_ASSERT(c);
  278. if (strcmp(id, c->getId()) == 0)
  279. {
  280. return c;
  281. }
  282. else if (c->isContainer())
  283. {
  284. Control* cc = ((Container*)c)->getControl(id);
  285. if (cc)
  286. {
  287. return cc;
  288. }
  289. }
  290. }
  291. return NULL;
  292. }
  293. unsigned int Container::getControlCount() const
  294. {
  295. return (unsigned int)_controls.size();
  296. }
  297. const std::vector<Control*>& Container::getControls() const
  298. {
  299. return _controls;
  300. }
  301. bool Container::isForm() const
  302. {
  303. return false;
  304. }
  305. void Container::setScroll(Scroll scroll)
  306. {
  307. if (scroll != _scroll)
  308. {
  309. _scroll = scroll;
  310. if (_scroll == SCROLL_NONE)
  311. {
  312. _scrollPosition.set(0, 0);
  313. }
  314. else
  315. {
  316. // Scrollable containers can be focused (to allow scrolling)
  317. _canFocus = true;
  318. }
  319. setDirty(DIRTY_BOUNDS | DIRTY_STATE);
  320. }
  321. }
  322. Container::Scroll Container::getScroll() const
  323. {
  324. return _scroll;
  325. }
  326. void Container::setScrollBarsAutoHide(bool autoHide)
  327. {
  328. if (autoHide != _scrollBarsAutoHide)
  329. {
  330. _scrollBarsAutoHide = autoHide;
  331. setDirty(DIRTY_BOUNDS | DIRTY_STATE);
  332. }
  333. }
  334. bool Container::isScrollBarsAutoHide() const
  335. {
  336. return _scrollBarsAutoHide;
  337. }
  338. bool Container::isScrolling() const
  339. {
  340. if (_scrolling &&
  341. (abs(_scrollingLastX - _scrollingVeryFirstX) > SCROLL_THRESHOLD ||
  342. abs(_scrollingLastY - _scrollingVeryFirstY) > SCROLL_THRESHOLD))
  343. {
  344. return true;
  345. }
  346. if (_parent && _parent->isScrolling())
  347. return true;
  348. return false;
  349. }
  350. const Vector2& Container::getScrollPosition() const
  351. {
  352. return _scrollPosition;
  353. }
  354. void Container::setScrollPosition(const Vector2& scrollPosition)
  355. {
  356. _scrollPosition = scrollPosition;
  357. }
  358. Animation* Container::getAnimation(const char* id) const
  359. {
  360. std::vector<Control*>::const_iterator itr = _controls.begin();
  361. std::vector<Control*>::const_iterator end = _controls.end();
  362. Control* control = NULL;
  363. for (; itr != end; itr++)
  364. {
  365. control = *itr;
  366. GP_ASSERT(control);
  367. Animation* animation = control->getAnimation(id);
  368. if (animation)
  369. return animation;
  370. if (control->isContainer())
  371. {
  372. animation = ((Container*)control)->getAnimation(id);
  373. if (animation)
  374. return animation;
  375. }
  376. }
  377. return NULL;
  378. }
  379. const char* Container::getType() const
  380. {
  381. return "container";
  382. }
  383. bool Container::getScrollWheelRequiresFocus() const
  384. {
  385. return _scrollWheelRequiresFocus;
  386. }
  387. void Container::setScrollWheelRequiresFocus(bool required)
  388. {
  389. _scrollWheelRequiresFocus = required;
  390. }
  391. bool Container::setFocus()
  392. {
  393. // If this container (or one of its children) already has focus, do nothing
  394. if (Form::getFocusControl() && (Form::getFocusControl() == this || Form::getFocusControl()->isChild(this)))
  395. return true;
  396. // First try to set focus to our active control
  397. if (_activeControl)
  398. {
  399. if (_activeControl->setFocus())
  400. return true;
  401. }
  402. // Try to set focus to one of our children
  403. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  404. {
  405. if (_controls[i]->setFocus())
  406. return true;
  407. }
  408. // Lastly, try to set focus to ourself if none of our children will accept it
  409. return Control::setFocus();
  410. }
  411. Control* Container::getActiveControl() const
  412. {
  413. return _activeControl;
  414. }
  415. void Container::setActiveControl(Control* control)
  416. {
  417. if (std::find(_controls.begin(), _controls.end(), control) != _controls.end())
  418. {
  419. _activeControl = control;
  420. // If a control within this container currently has focus, switch focus to the new active control
  421. if (Form::getFocusControl() && Form::getFocusControl() != control && Form::getFocusControl()->isChild(this))
  422. Form::setFocusControl(control);
  423. }
  424. }
  425. void Container::setChildrenDirty(int bits, bool recursive)
  426. {
  427. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  428. {
  429. Control* ctrl = _controls[i];
  430. ctrl->setDirty(bits);
  431. if (recursive && ctrl->isContainer())
  432. static_cast<Container*>(ctrl)->setChildrenDirty(bits, true);
  433. }
  434. }
  435. void Container::update(float elapsedTime)
  436. {
  437. Control::update(elapsedTime);
  438. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  439. _controls[i]->update(elapsedTime);
  440. }
  441. void Container::updateState(State state)
  442. {
  443. Control::updateState(state);
  444. // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
  445. if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
  446. {
  447. _scrollBarLeftCap = getImage("scrollBarLeftCap", state);
  448. _scrollBarHorizontal = getImage("horizontalScrollBar", state);
  449. _scrollBarRightCap = getImage("scrollBarRightCap", state);
  450. }
  451. if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
  452. {
  453. _scrollBarTopCap = getImage("scrollBarTopCap", state);
  454. _scrollBarVertical = getImage("verticalScrollBar", state);
  455. _scrollBarBottomCap = getImage("scrollBarBottomCap", state);
  456. }
  457. }
  458. void Container::updateBounds()
  459. {
  460. // Compute total bounds of container
  461. Control::updateBounds();
  462. // Handle automatically sizing based on our children
  463. if (_autoSize != AUTO_SIZE_NONE)
  464. {
  465. if (_autoSize & AUTO_SIZE_WIDTH)
  466. {
  467. // Size ourself to tightly fit the width of our children
  468. float width = 0;
  469. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  470. {
  471. Control* ctrl = _controls[i];
  472. if (!ctrl->isXPercentage() && !ctrl->isWidthPercentage())
  473. {
  474. float w = ctrl->getX() + ctrl->getWidth();
  475. if (width < w)
  476. width = w;
  477. }
  478. }
  479. width += getBorder(NORMAL).left + getBorder(NORMAL).right + getPadding().left + getPadding().right;
  480. setWidthInternal(width);
  481. }
  482. if (_autoSize & AUTO_SIZE_HEIGHT)
  483. {
  484. // Size ourself to tightly fit the height of our children
  485. float height = 0;
  486. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  487. {
  488. Control* ctrl = _controls[i];
  489. if (!ctrl->isYPercentage() && !ctrl->isHeightPercentage())
  490. {
  491. float h = ctrl->getY() + ctrl->getHeight();
  492. if (height < h)
  493. height = h;
  494. }
  495. }
  496. height += getBorder(NORMAL).top + getBorder(NORMAL).bottom + getPadding().top + getPadding().bottom;
  497. setHeightInternal(height);
  498. }
  499. }
  500. // Update layout to position children correctly within us
  501. GP_ASSERT(_layout);
  502. _layout->update(this);
  503. }
  504. void Container::updateAbsoluteBounds(const Vector2& offset)
  505. {
  506. Control::updateAbsoluteBounds(offset);
  507. // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
  508. if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
  509. {
  510. GP_ASSERT(_scrollBarLeftCap && _scrollBarHorizontal && _scrollBarRightCap);
  511. _viewportBounds.height -= _scrollBarHorizontal->getRegion().height;
  512. _viewportClipBounds.height -= _scrollBarHorizontal->getRegion().height;
  513. }
  514. if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
  515. {
  516. GP_ASSERT(_scrollBarTopCap && _scrollBarVertical && _scrollBarBottomCap);
  517. _viewportBounds.width -= _scrollBarVertical->getRegion().width;
  518. _viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
  519. }
  520. // Update scroll position and scrollbars after updating absolute bounds since
  521. // computation relies on up-to-date absolute bounds information.
  522. updateScroll();
  523. }
  524. bool Container::updateChildBounds()
  525. {
  526. bool result = false;
  527. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  528. {
  529. Control* ctrl = _controls[i];
  530. GP_ASSERT(ctrl);
  531. if (ctrl->isVisible())
  532. {
  533. bool changed = ctrl->updateBoundsInternal(_scrollPosition);
  534. // If the child bounds have changed, dirty our bounds and all of our
  535. // parent bounds so that our layout and/or bounds are recomputed.
  536. if (changed)
  537. {
  538. Control* parent = this;
  539. while (parent && parent->_autoSize != AUTO_SIZE_NONE)
  540. {
  541. parent->setDirty(DIRTY_BOUNDS);
  542. parent = parent->_parent;
  543. }
  544. }
  545. result = result || changed;
  546. }
  547. }
  548. return result;
  549. }
  550. unsigned int Container::draw(Form* form, const Rectangle& clip)
  551. {
  552. if (!_visible)
  553. return 0;
  554. // Draw container skin
  555. unsigned int drawCalls = Control::draw(form, clip);
  556. // Draw child controls
  557. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  558. {
  559. Control* control = _controls[i];
  560. if (control && control->_absoluteClipBounds.intersects(_absoluteClipBounds))
  561. {
  562. drawCalls += control->draw(form, _viewportClipBounds);
  563. }
  564. }
  565. // Draw scrollbars
  566. if (_scroll != SCROLL_NONE && (_scrollBarOpacity > 0.0f))
  567. {
  568. // Draw scroll bars.
  569. Rectangle clipRegion(_absoluteClipBounds);
  570. SpriteBatch* batch = _style->getTheme()->getSpriteBatch();
  571. startBatch(form, batch);
  572. if (_scrollBarBounds.height > 0 && ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL))
  573. {
  574. const Rectangle& topRegion = _scrollBarTopCap->getRegion();
  575. const Theme::UVs& topUVs = _scrollBarTopCap->getUVs();
  576. Vector4 topColor = _scrollBarTopCap->getColor();
  577. topColor.w *= _scrollBarOpacity * _opacity;
  578. const Rectangle& verticalRegion = _scrollBarVertical->getRegion();
  579. const Theme::UVs& verticalUVs = _scrollBarVertical->getUVs();
  580. Vector4 verticalColor = _scrollBarVertical->getColor();
  581. verticalColor.w *= _scrollBarOpacity * _opacity;
  582. const Rectangle& bottomRegion = _scrollBarBottomCap->getRegion();
  583. const Theme::UVs& bottomUVs = _scrollBarBottomCap->getUVs();
  584. Vector4 bottomColor = _scrollBarBottomCap->getColor();
  585. bottomColor.w *= _scrollBarOpacity * _opacity;
  586. clipRegion.width += verticalRegion.width;
  587. Rectangle bounds(_viewportBounds.right() + (_absoluteBounds.right() - _viewportBounds.right())*0.5f - topRegion.width*0.5f, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
  588. batch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
  589. bounds.y += topRegion.height;
  590. bounds.height = _scrollBarBounds.height - topRegion.height - bottomRegion.height;
  591. batch->draw(bounds.x, bounds.y, bounds.width, bounds.height, verticalUVs.u1, verticalUVs.v1, verticalUVs.u2, verticalUVs.v2, verticalColor, clipRegion);
  592. bounds.y += bounds.height;
  593. bounds.height = bottomRegion.height;
  594. batch->draw(bounds.x, bounds.y, bounds.width, bounds.height, bottomUVs.u1, bottomUVs.v1, bottomUVs.u2, bottomUVs.v2, bottomColor, clipRegion);
  595. drawCalls += 3;
  596. }
  597. if (_scrollBarBounds.width > 0 && ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL))
  598. {
  599. const Rectangle& leftRegion = _scrollBarLeftCap->getRegion();
  600. const Theme::UVs& leftUVs = _scrollBarLeftCap->getUVs();
  601. Vector4 leftColor = _scrollBarLeftCap->getColor();
  602. leftColor.w *= _scrollBarOpacity * _opacity;
  603. const Rectangle& horizontalRegion = _scrollBarHorizontal->getRegion();
  604. const Theme::UVs& horizontalUVs = _scrollBarHorizontal->getUVs();
  605. Vector4 horizontalColor = _scrollBarHorizontal->getColor();
  606. horizontalColor.w *= _scrollBarOpacity * _opacity;
  607. const Rectangle& rightRegion = _scrollBarRightCap->getRegion();
  608. const Theme::UVs& rightUVs = _scrollBarRightCap->getUVs();
  609. Vector4 rightColor = _scrollBarRightCap->getColor();
  610. rightColor.w *= _scrollBarOpacity * _opacity;
  611. clipRegion.height += horizontalRegion.height;
  612. Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.bottom() + (_absoluteBounds.bottom() - _viewportBounds.bottom())*0.5f - leftRegion.height*0.5f, leftRegion.width, leftRegion.height);
  613. batch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
  614. bounds.x += leftRegion.width;
  615. bounds.width = _scrollBarBounds.width - leftRegion.width - rightRegion.width;
  616. batch->draw(bounds.x, bounds.y, bounds.width, bounds.height, horizontalUVs.u1, horizontalUVs.v1, horizontalUVs.u2, horizontalUVs.v2, horizontalColor, clipRegion);
  617. bounds.x += bounds.width;
  618. bounds.width = rightRegion.width;
  619. batch->draw(bounds.x, bounds.y, bounds.width, bounds.height, rightUVs.u1, rightUVs.v1, rightUVs.u2, rightUVs.v2, rightColor, clipRegion);
  620. drawCalls += 3;
  621. }
  622. finishBatch(form, batch);
  623. }
  624. return drawCalls;
  625. }
  626. static bool canReceiveFocus(Control* control)
  627. {
  628. if (control->getFocusIndex() < 0 || !(control->isEnabled() && control->isVisible()))
  629. return false;
  630. if (control->canFocus())
  631. return true;
  632. if (control->isContainer())
  633. {
  634. Container* container = static_cast<Container*>(control);
  635. for (unsigned int i = 0, count = (unsigned int)container->getControlCount(); i < count; ++i)
  636. {
  637. if (canReceiveFocus(container->getControl(i)))
  638. return true;
  639. }
  640. }
  641. return false;
  642. }
  643. bool Container::moveFocus(Direction direction)
  644. {
  645. switch (direction)
  646. {
  647. case NEXT:
  648. case PREVIOUS:
  649. return moveFocusNextPrevious(direction);
  650. case UP:
  651. case DOWN:
  652. case LEFT:
  653. case RIGHT:
  654. return moveFocusDirectional(direction);
  655. default:
  656. return false;
  657. }
  658. }
  659. bool Container::moveFocusNextPrevious(Direction direction)
  660. {
  661. // Get the current control that has focus (either directly or indirectly) within this container
  662. Control* currentFocus = Form::getFocusControl();
  663. Control* current = NULL;
  664. if (currentFocus && currentFocus->isChild(this))
  665. {
  666. if (currentFocus->_parent == this)
  667. {
  668. // Currently focused control is a direct child of us
  669. current = currentFocus;
  670. }
  671. else
  672. {
  673. // Currently focused control is a child of one of our child containers
  674. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  675. {
  676. if (currentFocus->isChild(_controls[i]))
  677. {
  678. current = _controls[i];
  679. break;
  680. }
  681. }
  682. }
  683. }
  684. Control* nextCtrl = NULL;
  685. int nextIndex = direction == NEXT ? INT_MAX : INT_MIN;
  686. bool moveFirst = false;
  687. if (current)
  688. {
  689. // There is a control inside us that currently has focus, so find the next control that
  690. // should receive focus.
  691. int focusableControlCount = 0; // track the number of valid focusable controls in this container
  692. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  693. {
  694. Control* ctrl = _controls[i];
  695. if (!canReceiveFocus(ctrl))
  696. continue;
  697. if ((direction == NEXT && ctrl->_focusIndex > current->_focusIndex && ctrl->_focusIndex < nextIndex) ||
  698. (direction == PREVIOUS && ctrl->_focusIndex < current->_focusIndex && ctrl->_focusIndex > nextIndex))
  699. {
  700. nextCtrl = ctrl;
  701. nextIndex = ctrl->_focusIndex;
  702. }
  703. ++focusableControlCount;
  704. }
  705. if (nextCtrl)
  706. {
  707. if (nextCtrl->isContainer() && static_cast<Container*>(nextCtrl)->moveFocus(direction))
  708. return true;
  709. if (nextCtrl->setFocus())
  710. return true;
  711. }
  712. // Search up into our parent container for a focus move
  713. if (_parent && _parent->moveFocus(direction))
  714. return true;
  715. // We didn't find a control to move to, so we must be the first or last focusable control in our parent.
  716. // Wrap focus to the other side of the container.
  717. if (focusableControlCount > 1)
  718. {
  719. moveFirst = true;
  720. }
  721. }
  722. else
  723. {
  724. moveFirst = true;
  725. }
  726. if (moveFirst)
  727. {
  728. nextIndex = direction == NEXT ? INT_MAX : INT_MIN;
  729. nextCtrl = NULL;
  730. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  731. {
  732. Control* ctrl = _controls[i];
  733. if (!canReceiveFocus(ctrl))
  734. continue;
  735. if ((direction == NEXT && ctrl->_focusIndex < nextIndex) ||
  736. (direction == PREVIOUS && ctrl->_focusIndex > nextIndex))
  737. {
  738. nextCtrl = ctrl;
  739. nextIndex = ctrl->_focusIndex;
  740. }
  741. }
  742. if (nextCtrl)
  743. {
  744. if (nextCtrl->isContainer() && static_cast<Container*>(nextCtrl)->moveFocus(direction))
  745. return true;
  746. if (nextCtrl->setFocus())
  747. return true;
  748. }
  749. }
  750. return false;
  751. }
  752. bool Container::moveFocusDirectional(Direction direction)
  753. {
  754. Control* startControl = Form::getFocusControl();
  755. if (startControl == NULL)
  756. return false;
  757. const Rectangle& startBounds = startControl->_absoluteBounds;
  758. Control* next = NULL;
  759. Vector2 vStart, vNext;
  760. float distance = FLT_MAX;
  761. switch (direction)
  762. {
  763. case UP:
  764. vStart.set(startBounds.x + startBounds.width * 0.5f, startBounds.y);
  765. break;
  766. case DOWN:
  767. vStart.set(startBounds.x + startBounds.width * 0.5f, startBounds.bottom());
  768. break;
  769. case LEFT:
  770. vStart.set(startBounds.x, startBounds.y + startBounds.height * 0.5f);
  771. break;
  772. case RIGHT:
  773. vStart.set(startBounds.right(), startBounds.y + startBounds.height * 0.5f);
  774. break;
  775. }
  776. for (size_t i = 0, count = _controls.size(); i < count; ++i)
  777. {
  778. Control* ctrl = _controls[i];
  779. if (!canReceiveFocus(ctrl))
  780. continue;
  781. const Rectangle& nextBounds = ctrl->getAbsoluteBounds();
  782. switch (direction)
  783. {
  784. case UP:
  785. vNext.set(nextBounds.x + nextBounds.width * 0.5f, nextBounds.bottom());
  786. if (vNext.y > vStart.y)
  787. continue;
  788. break;
  789. case DOWN:
  790. vNext.set(nextBounds.x + nextBounds.width * 0.5f, nextBounds.y);
  791. if (vNext.y < vStart.y)
  792. continue;
  793. break;
  794. case LEFT:
  795. vNext.set(nextBounds.right(), nextBounds.y + nextBounds.height * 0.5f);
  796. if (vNext.x > vStart.x)
  797. continue;
  798. break;
  799. case RIGHT:
  800. vNext.set(nextBounds.x, nextBounds.y + nextBounds.height * 0.5f);
  801. if (vNext.x < vStart.x)
  802. continue;
  803. break;
  804. }
  805. float nextDistance = vStart.distance(vNext);
  806. if (std::fabs(nextDistance) < distance)
  807. {
  808. distance = nextDistance;
  809. next = ctrl;
  810. }
  811. }
  812. if (next)
  813. {
  814. // If this control is a container, try to move focus to the first control within it
  815. if (next->isContainer())
  816. {
  817. if (static_cast<Container*>(next)->moveFocusDirectional(direction))
  818. return true;
  819. }
  820. if (next->setFocus())
  821. return true;
  822. }
  823. else
  824. {
  825. // If no control was found, try searching in our parent container
  826. if (_parent && _parent->moveFocusDirectional(direction))
  827. return true;
  828. }
  829. return false;
  830. }
  831. void Container::startScrolling(float x, float y, bool resetTime)
  832. {
  833. _scrollingVelocity.set(-x, y);
  834. _scrolling = true;
  835. _scrollBarOpacity = 1.0f;
  836. setDirty(DIRTY_BOUNDS);
  837. if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
  838. {
  839. _scrollBarOpacityClip->stop();
  840. _scrollBarOpacityClip = NULL;
  841. }
  842. if (resetTime)
  843. {
  844. _lastFrameTime = Game::getAbsoluteTime();
  845. }
  846. }
  847. void Container::stopScrolling()
  848. {
  849. _scrollingVelocity.set(0, 0);
  850. _scrolling = false;
  851. setDirty(DIRTY_BOUNDS);
  852. if (_parent)
  853. _parent->stopScrolling();
  854. }
  855. bool Container::isContainer() const
  856. {
  857. return true;
  858. }
  859. Layout::Type Container::getLayoutType(const char* layoutString)
  860. {
  861. if (!layoutString)
  862. {
  863. return Layout::LAYOUT_ABSOLUTE;
  864. }
  865. std::string layoutName(layoutString);
  866. std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
  867. if (layoutName == "LAYOUT_ABSOLUTE")
  868. {
  869. return Layout::LAYOUT_ABSOLUTE;
  870. }
  871. else if (layoutName == "LAYOUT_VERTICAL")
  872. {
  873. return Layout::LAYOUT_VERTICAL;
  874. }
  875. else if (layoutName == "LAYOUT_FLOW")
  876. {
  877. return Layout::LAYOUT_FLOW;
  878. }
  879. else
  880. {
  881. // Default.
  882. return Layout::LAYOUT_ABSOLUTE;
  883. }
  884. }
  885. Layout* Container::createLayout(Layout::Type type)
  886. {
  887. switch (type)
  888. {
  889. case Layout::LAYOUT_ABSOLUTE:
  890. return AbsoluteLayout::create();
  891. case Layout::LAYOUT_FLOW:
  892. return FlowLayout::create();
  893. case Layout::LAYOUT_VERTICAL:
  894. return VerticalLayout::create();
  895. default:
  896. return AbsoluteLayout::create();
  897. }
  898. }
  899. void Container::updateScroll()
  900. {
  901. if (_scroll == SCROLL_NONE)
  902. return;
  903. Control::State state = getState();
  904. // Update time.
  905. if (!_lastFrameTime)
  906. {
  907. _lastFrameTime = Game::getAbsoluteTime();
  908. }
  909. double frameTime = Game::getAbsoluteTime();
  910. float elapsedTime = (float)(frameTime - _lastFrameTime);
  911. _lastFrameTime = frameTime;
  912. const Theme::Border& containerBorder = getBorder(state);
  913. const Theme::Padding& containerPadding = getPadding();
  914. // Calculate total width and height.
  915. _totalWidth = _totalHeight = 0.0f;
  916. std::vector<Control*> controls = getControls();
  917. for (size_t i = 0, count = controls.size(); i < count; ++i)
  918. {
  919. Control* control = _controls[i];
  920. const Rectangle& bounds = control->getBounds();
  921. const Theme::Margin& margin = control->getMargin();
  922. float newWidth = bounds.x + bounds.width + margin.right;
  923. if (newWidth > _totalWidth)
  924. {
  925. _totalWidth = newWidth;
  926. }
  927. float newHeight = bounds.y + bounds.height + margin.bottom;
  928. if (newHeight > _totalHeight)
  929. {
  930. _totalHeight = newHeight;
  931. }
  932. }
  933. float vWidth = getImageRegion("verticalScrollBar", state).width;
  934. float hHeight = getImageRegion("horizontalScrollBar", state).height;
  935. float clipWidth = _absoluteBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right - vWidth;
  936. float clipHeight = _absoluteBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
  937. bool dirty = false;
  938. // Apply and dampen inertia.
  939. if (!_scrollingVelocity.isZero())
  940. {
  941. // Calculate the time passed since last update.
  942. float elapsedSecs = (float)elapsedTime * 0.001f;
  943. _scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
  944. _scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
  945. if (!_scrolling)
  946. {
  947. float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
  948. _scrollingVelocity.x *= dampening;
  949. _scrollingVelocity.y *= dampening;
  950. if (fabs(_scrollingVelocity.x) < 100.0f)
  951. _scrollingVelocity.x = 0.0f;
  952. if (fabs(_scrollingVelocity.y) < 100.0f)
  953. _scrollingVelocity.y = 0.0f;
  954. }
  955. dirty = true;
  956. }
  957. // Stop scrolling when the far edge is reached.
  958. if (-_scrollPosition.x > _totalWidth - clipWidth)
  959. {
  960. _scrollPosition.x = -(_totalWidth - clipWidth);
  961. _scrollingVelocity.x = 0;
  962. dirty = true;
  963. }
  964. if (-_scrollPosition.y > _totalHeight - clipHeight)
  965. {
  966. _scrollPosition.y = -(_totalHeight - clipHeight);
  967. _scrollingVelocity.y = 0;
  968. dirty = true;
  969. }
  970. if (_scrollPosition.x > 0)
  971. {
  972. _scrollPosition.x = 0;
  973. _scrollingVelocity.x = 0;
  974. dirty = true;
  975. }
  976. if (_scrollPosition.y > 0)
  977. {
  978. _scrollPosition.y = 0;
  979. _scrollingVelocity.y = 0;
  980. dirty = true;
  981. }
  982. float scrollWidth = 0;
  983. if (clipWidth < _totalWidth)
  984. scrollWidth = (clipWidth / _totalWidth) * clipWidth;
  985. float scrollHeight = 0;
  986. if (clipHeight < _totalHeight)
  987. scrollHeight = (clipHeight / _totalHeight) * clipHeight;
  988. _scrollBarBounds.set(((-_scrollPosition.x) / _totalWidth) * clipWidth,
  989. ((-_scrollPosition.y) / _totalHeight) * clipHeight,
  990. scrollWidth, scrollHeight);
  991. // If scroll velocity is 0 and scrollbars are not always visible, trigger fade-out animation.
  992. if (!_scrolling && _scrollingVelocity.isZero() && _scrollBarsAutoHide && _scrollBarOpacity == 1.0f)
  993. {
  994. float to = 0;
  995. _scrollBarOpacity = 0.99f;
  996. if (!_scrollBarOpacityClip)
  997. {
  998. Animation* animation = createAnimationFromTo("scrollbar-fade-out", ANIMATE_SCROLLBAR_OPACITY, &_scrollBarOpacity, &to, Curve::QUADRATIC_IN_OUT, SCROLLBAR_FADE_TIME);
  999. _scrollBarOpacityClip = animation->getClip();
  1000. }
  1001. _scrollBarOpacityClip->play();
  1002. }
  1003. // When scroll position is updated, we need to recompute bounds since children
  1004. // absolute bounds offset will need to be updated.
  1005. if (dirty)
  1006. {
  1007. setDirty(DIRTY_BOUNDS);
  1008. setChildrenDirty(DIRTY_BOUNDS, true);
  1009. }
  1010. }
  1011. void Container::sortControls()
  1012. {
  1013. if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
  1014. {
  1015. std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
  1016. }
  1017. }
  1018. bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  1019. {
  1020. switch (evt)
  1021. {
  1022. case Touch::TOUCH_PRESS:
  1023. if (_contactIndex == INVALID_CONTACT_INDEX)
  1024. {
  1025. bool dirty = !_scrollingVelocity.isZero();
  1026. _contactIndex = (int)contactIndex;
  1027. _scrollingLastX = _scrollingFirstX = _scrollingVeryFirstX = x;
  1028. _scrollingLastY = _scrollingFirstY = _scrollingVeryFirstY = y;
  1029. _scrollingVelocity.set(0, 0);
  1030. _scrolling = true;
  1031. _scrollingStartTimeX = _scrollingStartTimeY = 0;
  1032. if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
  1033. {
  1034. _scrollBarOpacityClip->stop();
  1035. _scrollBarOpacityClip = NULL;
  1036. }
  1037. _scrollBarOpacity = 1.0f;
  1038. if (dirty)
  1039. setDirty(DIRTY_BOUNDS);
  1040. return false;
  1041. }
  1042. break;
  1043. case Touch::TOUCH_MOVE:
  1044. if (_scrolling && _contactIndex == (int)contactIndex)
  1045. {
  1046. double gameTime = Game::getAbsoluteTime();
  1047. // Calculate the latest movement delta for the next update to use.
  1048. int vx = x - _scrollingLastX;
  1049. int vy = y - _scrollingLastY;
  1050. if (_scrollingMouseVertically)
  1051. {
  1052. float yRatio = _totalHeight / _absoluteBounds.height;
  1053. vy *= yRatio;
  1054. _scrollingVelocity.set(0, -vy);
  1055. _scrollPosition.y -= vy;
  1056. }
  1057. else if (_scrollingMouseHorizontally)
  1058. {
  1059. float xRatio = _totalWidth / _absoluteBounds.width;
  1060. vx *= xRatio;
  1061. _scrollingVelocity.set(-vx, 0);
  1062. _scrollPosition.x -= vx;
  1063. }
  1064. else
  1065. {
  1066. _scrollingVelocity.set(vx, vy);
  1067. _scrollPosition.x += vx;
  1068. _scrollPosition.y += vy;
  1069. }
  1070. _scrollingLastX = x;
  1071. _scrollingLastY = y;
  1072. // If the user changes direction, reset the start time and position.
  1073. bool goingRight = (vx > 0);
  1074. if (goingRight != _scrollingRight)
  1075. {
  1076. _scrollingFirstX = x;
  1077. _scrollingRight = goingRight;
  1078. _scrollingStartTimeX = gameTime;
  1079. }
  1080. bool goingDown = (vy > 0);
  1081. if (goingDown != _scrollingDown)
  1082. {
  1083. _scrollingFirstY = y;
  1084. _scrollingDown = goingDown;
  1085. _scrollingStartTimeY = gameTime;
  1086. }
  1087. if (!_scrollingStartTimeX)
  1088. _scrollingStartTimeX = gameTime;
  1089. if (!_scrollingStartTimeY)
  1090. _scrollingStartTimeY = gameTime;
  1091. _scrollingLastTime = gameTime;
  1092. setDirty(DIRTY_BOUNDS);
  1093. setChildrenDirty(DIRTY_BOUNDS, true);
  1094. return false;
  1095. }
  1096. break;
  1097. case Touch::TOUCH_RELEASE:
  1098. if (_contactIndex == (int) contactIndex)
  1099. {
  1100. _contactIndex = INVALID_CONTACT_INDEX;
  1101. _scrolling = false;
  1102. double gameTime = Game::getAbsoluteTime();
  1103. float timeSinceLastMove = (float)(gameTime - _scrollingLastTime);
  1104. if (timeSinceLastMove > SCROLL_INERTIA_DELAY)
  1105. {
  1106. _scrollingVelocity.set(0, 0);
  1107. _scrollingMouseVertically = _scrollingMouseHorizontally = false;
  1108. return false;
  1109. }
  1110. int dx = _scrollingLastX - _scrollingFirstX;
  1111. int dy = _scrollingLastY - _scrollingFirstY;
  1112. float timeTakenX = (float)(gameTime - _scrollingStartTimeX);
  1113. float elapsedSecsX = timeTakenX * 0.001f;
  1114. float timeTakenY = (float)(gameTime - _scrollingStartTimeY);
  1115. float elapsedSecsY = timeTakenY * 0.001f;
  1116. float vx = dx;
  1117. float vy = dy;
  1118. if (elapsedSecsX > 0)
  1119. vx = (float)dx / elapsedSecsX;
  1120. if (elapsedSecsY > 0)
  1121. vy = (float)dy / elapsedSecsY;
  1122. if (_scrollingMouseVertically)
  1123. {
  1124. float yRatio = _totalHeight / _absoluteBounds.height;
  1125. vy *= yRatio;
  1126. _scrollingVelocity.set(0, -vy);
  1127. }
  1128. else if (_scrollingMouseHorizontally)
  1129. {
  1130. float xRatio = _totalWidth / _absoluteBounds.width;
  1131. vx *= xRatio;
  1132. _scrollingVelocity.set(-vx, 0);
  1133. }
  1134. else
  1135. {
  1136. _scrollingVelocity.set(vx, vy);
  1137. }
  1138. _scrollingMouseVertically = _scrollingMouseHorizontally = false;
  1139. setDirty(DIRTY_BOUNDS);
  1140. return false;
  1141. }
  1142. break;
  1143. }
  1144. return false;
  1145. }
  1146. bool Container::mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  1147. {
  1148. switch (evt)
  1149. {
  1150. case Mouse::MOUSE_PRESS_LEFT_BUTTON:
  1151. {
  1152. bool dirty = false;
  1153. if (_scrollBarVertical)
  1154. {
  1155. float vWidth = _scrollBarVertical->getRegion().width;
  1156. float rightPadding = _absoluteBounds.right() - _viewportBounds.right();
  1157. float topPadding = _viewportBounds.y - _absoluteBounds.y;
  1158. float localVpRight = _bounds.width - rightPadding;
  1159. Rectangle vBounds(
  1160. localVpRight + rightPadding*0.5f - vWidth*0.5f,
  1161. topPadding + _scrollBarBounds.y,
  1162. vWidth, _scrollBarBounds.height);
  1163. if (x >= vBounds.x && x <= vBounds.right())
  1164. {
  1165. // Then we're within the horizontal bounds of the vertical scrollbar.
  1166. // We want to either jump up or down, or drag the scrollbar itself.
  1167. if (y < vBounds.y)
  1168. {
  1169. _scrollPosition.y += _totalHeight / 5.0f;
  1170. dirty = true;
  1171. }
  1172. else if (y > vBounds.bottom())
  1173. {
  1174. _scrollPosition.y -= _totalHeight / 5.0f;
  1175. dirty = true;
  1176. }
  1177. else
  1178. {
  1179. _scrollingMouseVertically = true;
  1180. }
  1181. }
  1182. }
  1183. if (_scrollBarHorizontal)
  1184. {
  1185. float hHeight = _scrollBarHorizontal->getRegion().height;
  1186. float bottomPadding = _absoluteBounds.bottom() - _viewportBounds.bottom();
  1187. float leftPadding = _viewportBounds.x - _absoluteBounds.x;
  1188. float localVpBottom = _bounds.height - bottomPadding;
  1189. Rectangle hBounds(
  1190. leftPadding + _scrollBarBounds.x,
  1191. localVpBottom + bottomPadding*0.5f - hHeight*0.5f,
  1192. _scrollBarBounds.width, hHeight);
  1193. if (y >= hBounds.y && y <= hBounds.bottom())
  1194. {
  1195. // We're within the vertical bounds of the horizontal scrollbar.
  1196. if (x < hBounds.x)
  1197. {
  1198. _scrollPosition.x += _totalWidth / 5.0f;
  1199. dirty = true;
  1200. }
  1201. else if (x > hBounds.x + hBounds.width)
  1202. {
  1203. _scrollPosition.x -= _totalWidth / 5.0f;
  1204. dirty = true;
  1205. }
  1206. else
  1207. {
  1208. _scrollingMouseHorizontally = true;
  1209. }
  1210. }
  1211. }
  1212. if (dirty)
  1213. {
  1214. setDirty(DIRTY_BOUNDS);
  1215. setChildrenDirty(DIRTY_BOUNDS, true);
  1216. }
  1217. return touchEventScroll(Touch::TOUCH_PRESS, x, y, 0);
  1218. }
  1219. case Mouse::MOUSE_MOVE:
  1220. return touchEventScroll(Touch::TOUCH_MOVE, x, y, 0);
  1221. case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
  1222. return touchEventScroll(Touch::TOUCH_RELEASE, x, y, 0);
  1223. case Mouse::MOUSE_WHEEL:
  1224. {
  1225. if (_scrollingVelocity.isZero())
  1226. {
  1227. _lastFrameTime = Game::getAbsoluteTime();
  1228. }
  1229. _scrolling = _scrollingMouseVertically = _scrollingMouseHorizontally = false;
  1230. _scrollingVelocity.y += _scrollWheelSpeed * wheelDelta;
  1231. if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
  1232. {
  1233. _scrollBarOpacityClip->stop();
  1234. _scrollBarOpacityClip = NULL;
  1235. }
  1236. _scrollBarOpacity = 1.0f;
  1237. setDirty(DIRTY_BOUNDS);
  1238. return false;
  1239. }
  1240. }
  1241. return false;
  1242. }
  1243. bool Container::inContact()
  1244. {
  1245. for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
  1246. {
  1247. if (_contactIndices[i])
  1248. return true;
  1249. }
  1250. return false;
  1251. }
  1252. Container::Scroll Container::getScroll(const char* scroll)
  1253. {
  1254. if (!scroll)
  1255. return Container::SCROLL_NONE;
  1256. if (strcmp(scroll, "SCROLL_NONE") == 0)
  1257. {
  1258. return Container::SCROLL_NONE;
  1259. }
  1260. else if (strcmp(scroll, "SCROLL_HORIZONTAL") == 0)
  1261. {
  1262. return Container::SCROLL_HORIZONTAL;
  1263. }
  1264. else if (strcmp(scroll, "SCROLL_VERTICAL") == 0)
  1265. {
  1266. return Container::SCROLL_VERTICAL;
  1267. }
  1268. else if (strcmp(scroll, "SCROLL_BOTH") == 0)
  1269. {
  1270. return Container::SCROLL_BOTH;
  1271. }
  1272. else
  1273. {
  1274. GP_ERROR("Failed to get corresponding scroll state for unsupported value '%s'.", scroll);
  1275. }
  1276. return Container::SCROLL_NONE;
  1277. }
  1278. float Container::getScrollingFriction() const
  1279. {
  1280. return _scrollingFriction;
  1281. }
  1282. void Container::setScrollingFriction(float friction)
  1283. {
  1284. _scrollingFriction = friction;
  1285. }
  1286. float Container::getScrollWheelSpeed() const
  1287. {
  1288. return _scrollWheelSpeed;
  1289. }
  1290. void Container::setScrollWheelSpeed(float speed)
  1291. {
  1292. _scrollWheelSpeed = speed;
  1293. }
  1294. static bool sortControlsByZOrder(Control* c1, Control* c2)
  1295. {
  1296. if (c1->getZIndex() < c2->getZIndex())
  1297. return true;
  1298. return false;
  1299. }
  1300. unsigned int Container::getAnimationPropertyComponentCount(int propertyId) const
  1301. {
  1302. switch(propertyId)
  1303. {
  1304. case ANIMATE_SCROLLBAR_OPACITY:
  1305. return 1;
  1306. default:
  1307. return Control::getAnimationPropertyComponentCount(propertyId);
  1308. }
  1309. }
  1310. void Container::getAnimationPropertyValue(int propertyId, AnimationValue* value)
  1311. {
  1312. GP_ASSERT(value);
  1313. switch(propertyId)
  1314. {
  1315. case ANIMATE_SCROLLBAR_OPACITY:
  1316. value->setFloat(0, _scrollBarOpacity);
  1317. break;
  1318. default:
  1319. Control::getAnimationPropertyValue(propertyId, value);
  1320. break;
  1321. }
  1322. }
  1323. void Container::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
  1324. {
  1325. GP_ASSERT(value);
  1326. switch(propertyId)
  1327. {
  1328. case ANIMATE_SCROLLBAR_OPACITY:
  1329. _scrollBarOpacity = Curve::lerp(blendWeight, _opacity, value->getFloat(0));
  1330. break;
  1331. default:
  1332. Control::setAnimationPropertyValue(propertyId, value, blendWeight);
  1333. break;
  1334. }
  1335. }
  1336. }