Form.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. #include "Base.h"
  2. #include "Form.h"
  3. #include "AbsoluteLayout.h"
  4. #include "FlowLayout.h"
  5. #include "VerticalLayout.h"
  6. #include "Game.h"
  7. #include "Theme.h"
  8. #include "Label.h"
  9. #include "Button.h"
  10. #include "CheckBox.h"
  11. #include "Scene.h"
  12. // Scroll speed when using a DPad -- max scroll speed when using a joystick.
  13. static const float GAMEPAD_SCROLL_SPEED = 500.0f;
  14. // Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
  15. static const float JOYSTICK_THRESHOLD = 0.75f;
  16. // If the DPad or joystick is held down, this is the initial delay in milliseconds between focus changes.
  17. static const float GAMEPAD_FOCUS_REPEAT_DELAY = 300.0f;
  18. // Shaders used for drawing offscreen quad when form is attached to a node
  19. #define FORM_VSH "res/shaders/sprite.vert"
  20. #define FORM_FSH "res/shaders/sprite.frag"
  21. namespace gameplay
  22. {
  23. static std::vector<Form*> __forms;
  24. Control* Form::_focusControl = NULL;
  25. Control* Form::_activeControl = NULL;
  26. Control::State Form::_activeControlState = Control::NORMAL;
  27. static bool _shiftKeyDown = false;
  28. Form::Form() : _node(NULL), _batched(true)
  29. {
  30. }
  31. Form::~Form()
  32. {
  33. // Remove this Form from the global list.
  34. std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
  35. if (it != __forms.end())
  36. {
  37. __forms.erase(it);
  38. }
  39. }
  40. Form* Form::create(const char* url)
  41. {
  42. Form* form = new Form();
  43. // Load Form from .form file.
  44. Properties* properties = Properties::create(url);
  45. if (!properties)
  46. {
  47. GP_WARN("Failed to load properties file for Form.");
  48. return NULL;
  49. }
  50. // Check if the Properties is valid and has a valid namespace.
  51. Properties* formProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
  52. if (!formProperties || !(strcmpnocase(formProperties->getNamespace(), "form") == 0))
  53. {
  54. GP_WARN("Invalid properties file for form: %s", url);
  55. SAFE_DELETE(properties);
  56. return NULL;
  57. }
  58. // Load the form's theme style.
  59. Theme* theme = NULL;
  60. Theme::Style* style = NULL;
  61. if (formProperties->exists("theme"))
  62. {
  63. std::string themeFile;
  64. if (formProperties->getPath("theme", &themeFile))
  65. {
  66. theme = Theme::create(themeFile.c_str());
  67. }
  68. }
  69. if (!theme)
  70. {
  71. theme = Theme::getDefault();
  72. }
  73. if (theme)
  74. {
  75. // Load the form's style
  76. const char* styleName = formProperties->getString("style", "Form");
  77. style = theme->getStyle(styleName);
  78. if (!style)
  79. style = theme->getEmptyStyle();
  80. }
  81. form->_batched = formProperties->getBool("batchingEnabled", true);
  82. // Initialize the form and all of its child controls
  83. form->initialize("Form", style, formProperties);
  84. // Release the theme: its lifetime is controlled by addRef() and release() calls in initialize (above) and ~Control.
  85. if (theme != Theme::getDefault())
  86. {
  87. SAFE_RELEASE(theme);
  88. }
  89. SAFE_DELETE(properties);
  90. return form;
  91. }
  92. Form* Form::create(const char* id, Theme::Style* style, Layout::Type layoutType)
  93. {
  94. Form* form = new Form();
  95. form->_id = id ? id : "";
  96. form->_layout = createLayout(layoutType);
  97. form->initialize("Form", style, NULL);
  98. return form;
  99. }
  100. void Form::initialize(const char* typeName, Theme::Style* style, Properties* properties)
  101. {
  102. Container::initialize(typeName, style, properties);
  103. __forms.push_back(this);
  104. // After creation, update our bounds once so code that runs immediately after form
  105. // creation has access to up-to-date bounds.
  106. if (updateBoundsInternal(Vector2::zero()))
  107. updateBoundsInternal(Vector2::zero());
  108. }
  109. Form* Form::getForm(const char* id)
  110. {
  111. for (size_t i = 0, size = __forms.size(); i < size; ++i)
  112. {
  113. Form* f = __forms[i];
  114. GP_ASSERT(f);
  115. if (strcmp(id, f->getId()) == 0)
  116. {
  117. return f;
  118. }
  119. }
  120. return NULL;
  121. }
  122. Control* Form::getActiveControl()
  123. {
  124. return _activeControl;
  125. }
  126. Control* Form::getFocusControl()
  127. {
  128. return _focusControl;
  129. }
  130. void Form::clearFocus()
  131. {
  132. setFocusControl(NULL);
  133. }
  134. bool Form::isForm() const
  135. {
  136. return true;
  137. }
  138. void Form::setNode(Node* node)
  139. {
  140. if (_node != node)
  141. {
  142. _node = node;
  143. }
  144. }
  145. static unsigned int nextPowerOfTwo(unsigned int v)
  146. {
  147. if (!((v & (v - 1)) == 0))
  148. {
  149. v--;
  150. v |= v >> 1;
  151. v |= v >> 2;
  152. v |= v >> 4;
  153. v |= v >> 8;
  154. v |= v >> 16;
  155. return v + 1;
  156. }
  157. return v;
  158. }
  159. void Form::update(float elapsedTime)
  160. {
  161. Container::update(elapsedTime);
  162. // Do a two-pass bounds update:
  163. // 1. First pass updates leaf controls
  164. // 2. Second pass updates parent controls that depend on child sizes
  165. if (updateBoundsInternal(Vector2::zero()))
  166. updateBoundsInternal(Vector2::zero());
  167. }
  168. void Form::startBatch(SpriteBatch* batch)
  169. {
  170. // TODO (note: might want to pass a level number/depth here so that batch draw calls can be sorted correctly, such as all text on top)
  171. if (!batch->isStarted())
  172. {
  173. batch->setProjectionMatrix(_projectionMatrix);
  174. batch->start();
  175. if (_batched)
  176. _batches.push_back(batch);
  177. }
  178. }
  179. void Form::finishBatch(SpriteBatch* batch)
  180. {
  181. if (!_batched)
  182. {
  183. batch->finish();
  184. }
  185. }
  186. const Matrix& Form::getProjectionMatrix() const
  187. {
  188. return _projectionMatrix;
  189. }
  190. unsigned int Form::draw()
  191. {
  192. if (!_visible || _absoluteClipBounds.width == 0 || _absoluteClipBounds.height == 0)
  193. return 0;
  194. Game* game = Game::getInstance();
  195. Rectangle viewport = game->getViewport();
  196. // If we're drawing in 2D (i.e. not attached to a node), we need to clear the depth buffer
  197. if (_node)
  198. {
  199. // Drawing in 3D.
  200. // Setup a projection matrix for drawing the form via the node's world transform.
  201. Matrix world(_node->getWorldMatrix());
  202. world.scale(1, -1, 1);
  203. world.translate(0, -_absoluteClipBounds.height, 0);
  204. Matrix::multiply(_node->getViewProjectionMatrix(), world, &_projectionMatrix);
  205. }
  206. else
  207. {
  208. // Drawing in 2D, so we need to clear the depth buffer
  209. Game::getInstance()->clear(Game::CLEAR_DEPTH, Vector4::zero(), 1, 0);
  210. // Setup an ortho matrix that maps to the current viewport
  211. const Rectangle& viewport = Game::getInstance()->getViewport();
  212. Matrix::createOrthographicOffCenter(0, viewport.width, viewport.height, 0, 0, 1, &_projectionMatrix);
  213. }
  214. // Draw the form
  215. unsigned int drawCalls = Container::draw(this, _absoluteClipBounds);
  216. // Flush all batches that were queued during drawing and then empty the batch list
  217. if (_batched)
  218. {
  219. unsigned int batchCount = _batches.size();
  220. for (unsigned int i = 0; i < batchCount; ++i)
  221. _batches[i]->finish();
  222. _batches.clear();
  223. drawCalls = batchCount;
  224. }
  225. return drawCalls;
  226. }
  227. const char* Form::getType() const
  228. {
  229. return "form";
  230. }
  231. bool Form::isBatchingEnabled() const
  232. {
  233. return _batched;
  234. }
  235. void Form::setBatchingEnabled(bool enabled)
  236. {
  237. _batched = enabled;
  238. }
  239. void Form::updateInternal(float elapsedTime)
  240. {
  241. pollGamepads();
  242. for (size_t i = 0, size = __forms.size(); i < size; ++i)
  243. {
  244. Form* form = __forms[i];
  245. if (form && form->isEnabled() && form->isVisible())
  246. {
  247. form->update(elapsedTime);
  248. }
  249. }
  250. }
  251. bool Form::screenToForm(Control* ctrl, int* x, int* y)
  252. {
  253. Form* form = ctrl->getTopLevelForm();
  254. if (form)
  255. {
  256. if (form->_node)
  257. {
  258. // Form is attached to a scene node, so project the screen space point into the
  259. // form's coordinate space (which may be transformed by the node).
  260. Vector3 point;
  261. if (form->projectPoint(*x, *y, &point))
  262. {
  263. *x = (int)point.x;
  264. *y = form->_absoluteBounds.height - (int)point.y;
  265. }
  266. else
  267. {
  268. return false;
  269. }
  270. }
  271. return true;
  272. }
  273. return false;
  274. }
  275. Control* Form::findInputControl(int* x, int* y, bool focus)
  276. {
  277. for (int i = (int)__forms.size() - 1; i >= 0; --i)
  278. {
  279. Form* form = __forms[i];
  280. if (!form || !form->isEnabled() || !form->isVisible())
  281. continue;
  282. // Convert to local form coordinates
  283. int formX = *x;
  284. int formY = *y;
  285. if (!screenToForm(form, &formX, &formY))
  286. continue;
  287. // Search for an input control within this form
  288. Control* ctrl = findInputControl(form, formX, formY, focus);
  289. if (ctrl)
  290. {
  291. *x = formX;
  292. *y = formY;
  293. return ctrl;
  294. }
  295. // If the form consumes input events and the point intersects the form,
  296. // don't traverse other forms below it.
  297. if (form->_consumeInputEvents && form->_absoluteClipBounds.contains(formX, formY))
  298. return NULL;
  299. }
  300. return NULL;
  301. }
  302. Control* Form::findInputControl(Control* control, int x, int y, bool focus)
  303. {
  304. if (!(control->_visible && control->_enabled))
  305. return NULL;
  306. Control* result = NULL;
  307. // Does the passed in control's bounds intersect the specified coordinates - and
  308. // does the control support the specified input state?
  309. if (control->_consumeInputEvents && (!focus || control->canFocus()))
  310. {
  311. if (control->_absoluteClipBounds.contains(x, y))
  312. result = control;
  313. }
  314. // If the control has children, search for an input control inside it that also
  315. // supports the above conditions.
  316. if (control->isContainer())
  317. {
  318. Container* container = static_cast<Container*>(control);
  319. for (unsigned int i = 0, childCount = container->getControlCount(); i < childCount; ++i)
  320. {
  321. Control* ctrl = findInputControl(container->getControl(i), x, y, focus);
  322. if (ctrl)
  323. result = ctrl;
  324. }
  325. }
  326. return result;
  327. }
  328. Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
  329. {
  330. Control* ctrl = NULL;
  331. int newX = *x;
  332. int newY = *y;
  333. if (pressed)
  334. {
  335. // Update active state changes
  336. if ((ctrl = findInputControl(&newX, &newY, false)) != NULL)
  337. {
  338. if (_activeControl != ctrl || _activeControlState != Control::ACTIVE)
  339. {
  340. if (_activeControl)
  341. _activeControl->setDirty(Control::DIRTY_STATE);
  342. _activeControl = ctrl;
  343. _activeControlState = Control::ACTIVE;
  344. _activeControl->setDirty(Control::DIRTY_STATE);
  345. }
  346. ctrl->notifyListeners(Control::Listener::PRESS);
  347. }
  348. }
  349. else // !pressed
  350. {
  351. Control* active = _activeControlState == Control::ACTIVE ? _activeControl : NULL;
  352. if (active)
  353. {
  354. active->addRef(); // protect against event-hanlder evil
  355. // Release happened for the active control (that was pressed)
  356. ctrl = active;
  357. // Transform point to form-space
  358. screenToForm(ctrl, &newX, &newY);
  359. // No longer any active control
  360. _activeControl->setDirty(Control::DIRTY_STATE);
  361. _activeControl = NULL;
  362. _activeControlState = Control::NORMAL;
  363. }
  364. else
  365. {
  366. // Update active and hover control state on release
  367. Control* inputControl = findInputControl(&newX, &newY, false);
  368. if (inputControl)
  369. {
  370. ctrl = inputControl;
  371. if (_activeControl != ctrl || _activeControlState != Control::HOVER)
  372. {
  373. if (_activeControl)
  374. _activeControl->setDirty(Control::DIRTY_STATE);
  375. _activeControl = ctrl;
  376. _activeControlState = Control::HOVER;
  377. _activeControl->setDirty(Control::DIRTY_STATE);
  378. }
  379. }
  380. else
  381. {
  382. // No longer any active control
  383. if (_activeControl)
  384. _activeControl->setDirty(Control::DIRTY_STATE);
  385. _activeControl = NULL;
  386. _activeControlState = Control::NORMAL;
  387. }
  388. }
  389. if (active)
  390. {
  391. // Fire release event for the previously active control
  392. active->notifyListeners(Control::Listener::RELEASE);
  393. // If the release event was received on the same control that was
  394. // originally pressed, fire a click event
  395. if (active->_absoluteClipBounds.contains(newX, newY))
  396. {
  397. if (!active->_parent || !active->_parent->isScrolling())
  398. {
  399. active->notifyListeners(Control::Listener::CLICK);
  400. }
  401. }
  402. active->release();
  403. }
  404. }
  405. *x = newX;
  406. *y = newY;
  407. return ctrl;
  408. }
  409. Control* Form::handlePointerMove(int* x, int* y)
  410. {
  411. Control* ctrl = NULL;
  412. // Handle hover control changes on move, only if there is no currently active control
  413. // (i.e. when the mouse or a finger is not down).
  414. if (_activeControl && (_activeControlState == Control::ACTIVE))
  415. {
  416. ctrl = _activeControl;
  417. screenToForm(ctrl, x, y);
  418. }
  419. else
  420. {
  421. ctrl = findInputControl(x, y, false);
  422. if (ctrl)
  423. {
  424. // Update hover control
  425. if (_activeControl != ctrl || _activeControlState != Control::HOVER)
  426. {
  427. if (_activeControl)
  428. _activeControl->setDirty(Control::DIRTY_STATE);
  429. _activeControl = ctrl;
  430. _activeControlState = Control::HOVER;
  431. _activeControl->setDirty(Control::DIRTY_STATE);
  432. }
  433. }
  434. else
  435. {
  436. // No active/hover control
  437. if (_activeControl)
  438. _activeControl->setDirty(Control::DIRTY_STATE);
  439. _activeControl = NULL;
  440. _activeControlState = Control::NORMAL;
  441. }
  442. }
  443. return ctrl;
  444. }
  445. void Form::verifyRemovedControlState(Control* control)
  446. {
  447. if (_focusControl == control)
  448. _focusControl = NULL;
  449. if (_activeControl == control)
  450. {
  451. _activeControl = NULL;
  452. _activeControlState = Control::NORMAL;
  453. }
  454. }
  455. // Generic pointer event handler that both touch and mouse events map to.
  456. // Mappings:
  457. // mouse - true for mouse events, false for touch events
  458. // evt - Mouse::MouseEvent or Touch::TouchEvent
  459. // x, y - Point of event
  460. // param - wheelData for mouse events, contactIndex for touch events
  461. bool Form::pointerEventInternal(bool mouse, int evt, int x, int y, int param)
  462. {
  463. // Do not process mouse input when mouse is captured
  464. if (mouse && Game::getInstance()->isMouseCaptured())
  465. return false;
  466. // Is this a press event (TOUCH_PRESS has the same value as MOUSE_PRESS_LEFT_BUTTON)
  467. bool pressEvent = evt == Touch::TOUCH_PRESS || (mouse && (evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON || evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON));
  468. Control* ctrl = NULL;
  469. int formX = x;
  470. int formY = y;
  471. if (mouse || (param == 0))
  472. {
  473. // Note: TOUCH_PRESS and TOUCH_RELEASE have same values as MOUSE_PRESS_LEFT_BUTTON and MOUSE_RELEASE_LEFT_BUTTON
  474. if (evt == Touch::TOUCH_PRESS)
  475. {
  476. ctrl = handlePointerPressRelease(&formX, &formY, true);
  477. }
  478. else if (evt == Touch::TOUCH_RELEASE)
  479. {
  480. ctrl = handlePointerPressRelease(&formX, &formY, false);
  481. }
  482. else if ((mouse && evt == Mouse::MOUSE_MOVE) || (!mouse && evt == Touch::TOUCH_MOVE))
  483. {
  484. ctrl = handlePointerMove(&formX, &formY);
  485. }
  486. }
  487. // Dispatch input events to all controls that intersect this point
  488. if (ctrl == NULL)
  489. {
  490. formX = x;
  491. formY = y;
  492. ctrl = findInputControl(&formX, &formY, false);
  493. }
  494. if (ctrl)
  495. {
  496. // Handle setting focus for all press events
  497. if (pressEvent)
  498. {
  499. Control* focusControl = ctrl;
  500. while (focusControl && !focusControl->setFocus())
  501. focusControl = focusControl->_parent;
  502. if (focusControl == NULL)
  503. {
  504. // Nothing got focus on this press, so remove current focused control
  505. setFocusControl(NULL);
  506. }
  507. }
  508. // Dispatch the event from the bottom upwards, until a control intersecting the point consumes the event
  509. while (ctrl)
  510. {
  511. int localX = formX - ctrl->_absoluteBounds.x;
  512. int localY = formY - ctrl->_absoluteBounds.y;
  513. if (mouse)
  514. {
  515. if (ctrl->mouseEvent((Mouse::MouseEvent)evt, localX, localY, param))
  516. return true;
  517. // Forward to touch event hanlder if unhandled by mouse handler
  518. switch (evt)
  519. {
  520. case Mouse::MOUSE_PRESS_LEFT_BUTTON:
  521. if (ctrl->touchEvent(Touch::TOUCH_PRESS, localX, localY, 0))
  522. return true;
  523. break;
  524. case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
  525. if (ctrl->touchEvent(Touch::TOUCH_RELEASE, localX, localY, 0))
  526. return true;
  527. break;
  528. case Mouse::MOUSE_MOVE:
  529. if (ctrl->touchEvent(Touch::TOUCH_MOVE, localX, localY, 0))
  530. return true;
  531. break;
  532. }
  533. }
  534. else
  535. {
  536. if (ctrl->touchEvent((Touch::TouchEvent)evt, localX, localY, param))
  537. return true;
  538. }
  539. // Handle container scrolling
  540. Control* tmp = ctrl;
  541. while (tmp)
  542. {
  543. if (tmp->isContainer())
  544. {
  545. Container* container = static_cast<Container*>(tmp);
  546. if (container->_scroll != SCROLL_NONE)
  547. {
  548. if (mouse)
  549. {
  550. if (container->mouseEventScroll((Mouse::MouseEvent)evt, formX - tmp->_absoluteBounds.x, formY - tmp->_absoluteBounds.y, param))
  551. return true;
  552. }
  553. else
  554. {
  555. if (container->touchEventScroll((Touch::TouchEvent)evt, formX - tmp->_absoluteBounds.x, formY - tmp->_absoluteBounds.y, param))
  556. return true;
  557. }
  558. break; // scrollable parent container found
  559. }
  560. }
  561. tmp = tmp->_parent;
  562. }
  563. // Consume all input events anyways?
  564. if (ctrl->getConsumeInputEvents())
  565. return true;
  566. ctrl = ctrl->getParent();
  567. }
  568. }
  569. else
  570. {
  571. // If this was a press event, remove all focus
  572. if (pressEvent)
  573. {
  574. setFocusControl(NULL);
  575. }
  576. }
  577. return false;
  578. }
  579. bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  580. {
  581. return pointerEventInternal(false, evt, x, y, (int)contactIndex);
  582. }
  583. bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  584. {
  585. return pointerEventInternal(true, evt, x, y, wheelDelta);
  586. }
  587. bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
  588. {
  589. switch (key)
  590. {
  591. case Keyboard::KEY_ESCAPE:
  592. return false; // ignore escape key presses
  593. case Keyboard::KEY_SHIFT:
  594. if (evt == Keyboard::KEY_PRESS)
  595. _shiftKeyDown = true;
  596. else if (evt == Keyboard::KEY_RELEASE)
  597. _shiftKeyDown = false;
  598. break;
  599. }
  600. if (key == Keyboard::KEY_ESCAPE)
  601. return false;
  602. // Handle focus changing
  603. if (_focusControl)
  604. {
  605. switch (evt)
  606. {
  607. case Keyboard::KEY_CHAR:
  608. switch (key)
  609. {
  610. case Keyboard::KEY_TAB:
  611. if (_focusControl->_parent)
  612. {
  613. if (_focusControl->_parent->moveFocus(_shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
  614. return true;
  615. }
  616. break;
  617. }
  618. break;
  619. }
  620. }
  621. // Dispatch key events
  622. Control* ctrl = _focusControl;
  623. while (ctrl)
  624. {
  625. if (ctrl->isEnabled() && ctrl->isVisible())
  626. {
  627. if (ctrl->keyEvent(evt, key))
  628. return true;
  629. }
  630. ctrl = ctrl->getParent();
  631. }
  632. return false;
  633. }
  634. void Form::pollGamepads()
  635. {
  636. Game* game = Game::getInstance();
  637. // If no gamepads are connected, return immediately
  638. unsigned int gamepadCount = game->getGamepadCount();
  639. if (gamepadCount == 0)
  640. return;
  641. // For now, always use gamepad zero for controlling the UI.
  642. // Possibly allow the developer to set the active gamepad for UI later.
  643. Gamepad* gamepad = game->getGamepad(0, true);
  644. if (!gamepad)
  645. return;
  646. pollGamepad(gamepad);
  647. }
  648. bool Form::pollGamepad(Gamepad* gamepad)
  649. {
  650. // Get the currently focused control's container for focus management and scrolling
  651. if (!_focusControl)
  652. return false;
  653. // Get parent container
  654. Container* parentContainer = NULL;
  655. if (_focusControl->_parent)
  656. parentContainer = _focusControl->_parent;
  657. // Get scroll container
  658. Container* scrollContainer = NULL;
  659. if (_focusControl->isContainer())
  660. {
  661. scrollContainer = static_cast<Container*>(_focusControl);
  662. if (scrollContainer->_scroll == SCROLL_NONE)
  663. scrollContainer = NULL;
  664. }
  665. if (!scrollContainer && parentContainer && parentContainer->_scroll != SCROLL_NONE)
  666. scrollContainer = parentContainer;
  667. // Static static maintained across function calls
  668. static bool scrolling = false;
  669. static double lastFocusChangeTime = 0;
  670. bool focusPressed = false;
  671. bool stillScrolling = false;
  672. double currentTime = Game::getAbsoluteTime();
  673. double focusChangeElapsedTime = currentTime - lastFocusChangeTime;
  674. // Is a selection button down (i.e. buttons used for UI clicking/interactions)?
  675. bool selectButtonDown = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
  676. if (!selectButtonDown)
  677. {
  678. // Get values of analog joysticks 1 and 2 (assume left and right analog sticks)
  679. Vector2 joystick;
  680. unsigned int joystickCount = gamepad->getJoystickCount();
  681. gamepad->getJoystickValues(0, &joystick);
  682. if (parentContainer)
  683. {
  684. // The Dpad and left analog stick (i.e. first analog stick when there are two joysticks) controls focus
  685. if (gamepad->isButtonDown(Gamepad::BUTTON_UP) || (joystickCount > 1 && joystick.y > JOYSTICK_THRESHOLD))
  686. {
  687. focusPressed = true;
  688. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(UP))
  689. {
  690. lastFocusChangeTime = currentTime;
  691. }
  692. }
  693. if (gamepad->isButtonDown(Gamepad::BUTTON_DOWN) || (joystickCount > 1 && joystick.y < -JOYSTICK_THRESHOLD))
  694. {
  695. focusPressed = true;
  696. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(DOWN))
  697. {
  698. lastFocusChangeTime = currentTime;
  699. }
  700. }
  701. if (gamepad->isButtonDown(Gamepad::BUTTON_LEFT) || (joystickCount > 1 && joystick.x < -JOYSTICK_THRESHOLD))
  702. {
  703. focusPressed = true;
  704. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(LEFT))
  705. {
  706. lastFocusChangeTime = currentTime;
  707. }
  708. }
  709. if (gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) || (joystickCount > 1 && joystick.x > JOYSTICK_THRESHOLD))
  710. {
  711. focusPressed = true;
  712. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(RIGHT))
  713. {
  714. lastFocusChangeTime = currentTime;
  715. }
  716. }
  717. }
  718. // The RIGHT analog stick (i.e. second), or ONLY analog stick (when only 1 joystick), is used to scroll.
  719. if (scrollContainer && joystickCount > 0)
  720. {
  721. if (joystickCount > 1)
  722. gamepad->getJoystickValues(1, &joystick);
  723. if (std::fabs(joystick.x) > JOYSTICK_THRESHOLD || std::fabs(joystick.y) > JOYSTICK_THRESHOLD)
  724. {
  725. scrollContainer->startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, !scrolling);
  726. scrolling = stillScrolling = true;
  727. }
  728. }
  729. }
  730. if (!focusPressed)
  731. {
  732. // Reset focus repeat
  733. lastFocusChangeTime = 0;
  734. }
  735. if (scrolling && !stillScrolling)
  736. {
  737. scrolling = false;
  738. if (scrollContainer)
  739. scrollContainer->stopScrolling();
  740. }
  741. return focusPressed || scrolling;
  742. }
  743. bool Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
  744. {
  745. if (!_focusControl)
  746. return false;
  747. bool selectButtonPressed = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
  748. // Fire press, release and click events to focused controls
  749. switch (evt)
  750. {
  751. case Gamepad::BUTTON_EVENT:
  752. if (selectButtonPressed && (_activeControl != _focusControl || _activeControlState != Control::ACTIVE))
  753. {
  754. _activeControl = _focusControl;
  755. _activeControlState = Control::ACTIVE;
  756. _activeControl->notifyListeners(Control::Listener::PRESS);
  757. return true;
  758. }
  759. else if (!selectButtonPressed && _activeControl == _focusControl && _activeControlState == Control::ACTIVE)
  760. {
  761. _activeControlState = Control::NORMAL;
  762. _activeControl->notifyListeners(Control::Listener::RELEASE);
  763. _activeControl->notifyListeners(Control::Listener::CLICK);
  764. return true;
  765. }
  766. break;
  767. }
  768. // Dispatch gamepad events to focused controls (or their parents)
  769. Control * ctrl = _focusControl;
  770. while (ctrl)
  771. {
  772. if (ctrl->isEnabled() && ctrl->isVisible())
  773. {
  774. if (ctrl->gamepadEvent(evt, gamepad, analogIndex))
  775. return true;
  776. }
  777. ctrl = ctrl->getParent();
  778. }
  779. return false;
  780. }
  781. void Form::resizeEventInternal(unsigned int width, unsigned int height)
  782. {
  783. for (size_t i = 0, size = __forms.size(); i < size; ++i)
  784. {
  785. Form* form = __forms[i];
  786. if (form)
  787. {
  788. // Dirty the form
  789. form->setDirty(Control::DIRTY_STATE);
  790. }
  791. }
  792. }
  793. bool Form::projectPoint(int x, int y, Vector3* point)
  794. {
  795. if (!_node)
  796. return false;
  797. Scene* scene = _node->getScene();
  798. Camera* camera;
  799. if (scene && (camera = scene->getActiveCamera()))
  800. {
  801. // Get info about the form's position.
  802. Matrix m = _node->getWorldMatrix();
  803. Vector3 pointOnPlane(0, 0, 0);
  804. m.transformPoint(&pointOnPlane);
  805. // Unproject point into world space.
  806. Ray ray;
  807. camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
  808. // Find the quad's plane. We know its normal is the quad's forward vector.
  809. Vector3 normal = _node->getForwardVectorWorld().normalize();
  810. // To get the plane's distance from the origin, we project a point on the
  811. // plane onto the plane's normal vector.
  812. const float distance = fabs(Vector3::dot(pointOnPlane, normal));
  813. Plane plane(normal, -distance);
  814. // Check for collision with plane.
  815. float collisionDistance = ray.intersects(plane);
  816. if (collisionDistance != Ray::INTERSECTS_NONE)
  817. {
  818. // Multiply the ray's direction vector by collision distance and add that to the ray's origin.
  819. point->set(ray.getOrigin() + collisionDistance*ray.getDirection());
  820. // Project this point into the plane.
  821. m.invert();
  822. m.transformPoint(point);
  823. return true;
  824. }
  825. }
  826. return false;
  827. }
  828. void Form::controlDisabled(Control* control)
  829. {
  830. if (Form::_focusControl && (Form::_focusControl == control || Form::_focusControl->isChild(control)))
  831. {
  832. setFocusControl(NULL);
  833. }
  834. if (Form::_activeControl)
  835. {
  836. if (Form::_activeControl == control || Form::_activeControl->isChild(control))
  837. {
  838. Form::_activeControl = NULL;
  839. Form::_activeControlState = Control::NORMAL;
  840. }
  841. }
  842. }
  843. void Form::setFocusControl(Control* control)
  844. {
  845. Control* oldFocus = _focusControl;
  846. _focusControl = control;
  847. // Deactivate the old focus control
  848. if (oldFocus)
  849. {
  850. oldFocus->setDirty(Control::DIRTY_STATE);
  851. oldFocus->notifyListeners(Control::Listener::FOCUS_LOST);
  852. }
  853. // Activate the new focus control
  854. if (_focusControl)
  855. {
  856. _focusControl->setDirty(Control::DIRTY_STATE);
  857. _focusControl->notifyListeners(Control::Listener::FOCUS_GAINED);
  858. // Set the activeControl property of the control's parent container
  859. Container* parent = NULL;
  860. if (_focusControl->_parent)
  861. {
  862. parent = _focusControl->_parent;
  863. parent->_activeControl = _focusControl;
  864. }
  865. // If this control is inside a scrollable container and is not fully visible,
  866. // scroll the container so that it is.
  867. if (parent && parent->_scroll != SCROLL_NONE && !parent->_viewportBounds.isEmpty())
  868. {
  869. const Rectangle& bounds = _focusControl->getBounds();
  870. if (bounds.x < parent->_scrollPosition.x)
  871. {
  872. // Control is to the left of the scrolled viewport.
  873. parent->_scrollPosition.x = -bounds.x;
  874. }
  875. else if (bounds.x + bounds.width > parent->_scrollPosition.x + parent->_viewportBounds.width)
  876. {
  877. // Control is off to the right.
  878. parent->_scrollPosition.x = -(bounds.x + bounds.width - parent->_viewportBounds.width);
  879. }
  880. if (bounds.y < parent->_viewportBounds.y - parent->_scrollPosition.y)
  881. {
  882. // Control is above the viewport.
  883. parent->_scrollPosition.y = -bounds.y;
  884. }
  885. else if (bounds.y + bounds.height > parent->_viewportBounds.height - parent->_scrollPosition.y)
  886. {
  887. // Control is below the viewport.
  888. parent->_scrollPosition.y = -(bounds.y + bounds.height - parent->_viewportBounds.height);
  889. }
  890. }
  891. }
  892. }
  893. }