Container.cpp 46 KB

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