Form.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  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. // Default form shaders
  13. #define FORM_VSH "res/shaders/form.vert"
  14. #define FORM_FSH "res/shaders/form.frag"
  15. // Scroll speed when using a DPad -- max scroll speed when using a joystick.
  16. static const float GAMEPAD_SCROLL_SPEED = 500.0f;
  17. // Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
  18. static const float JOYSTICK_THRESHOLD = 0.75f;
  19. // If the DPad or joystick is held down, this is the initial delay in milliseconds between focus changes.
  20. static const float GAMEPAD_FOCUS_REPEAT_DELAY = 300.0f;
  21. namespace gameplay
  22. {
  23. static Effect* __formEffect = NULL;
  24. static std::vector<Form*> __forms;
  25. Control* Form::_focusControl = NULL;
  26. Control* Form::_activeControl = NULL;
  27. Control::State Form::_activeControlState = Control::NORMAL;
  28. static bool _shiftKeyDown = false;
  29. Form::Form() : _theme(NULL), _frameBuffer(NULL), _spriteBatch(NULL), _node(NULL),
  30. _nodeQuad(NULL), _nodeMaterial(NULL) , _u2(0), _v1(0)
  31. {
  32. }
  33. Form::~Form()
  34. {
  35. SAFE_DELETE(_spriteBatch);
  36. SAFE_RELEASE(_frameBuffer);
  37. SAFE_RELEASE(_theme);
  38. if (__formEffect)
  39. {
  40. if (__formEffect->getRefCount() == 1)
  41. {
  42. __formEffect->release();
  43. __formEffect = NULL;
  44. }
  45. }
  46. // Remove this Form from the global list.
  47. std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
  48. if (it != __forms.end())
  49. {
  50. __forms.erase(it);
  51. }
  52. }
  53. Form* Form::create(const char* id, Theme::Style* style, Layout::Type layoutType)
  54. {
  55. GP_ASSERT(style);
  56. Layout* layout;
  57. switch (layoutType)
  58. {
  59. case Layout::LAYOUT_ABSOLUTE:
  60. layout = AbsoluteLayout::create();
  61. break;
  62. case Layout::LAYOUT_FLOW:
  63. layout = FlowLayout::create();
  64. break;
  65. case Layout::LAYOUT_VERTICAL:
  66. layout = VerticalLayout::create();
  67. break;
  68. default:
  69. GP_ERROR("Unsupported layout type '%d'.", layoutType);
  70. break;
  71. }
  72. Form* form = new Form();
  73. if (id)
  74. form->_id = id;
  75. form->_style = style;
  76. form->_layout = layout;
  77. form->_theme = style->getTheme();
  78. form->_theme->addRef();
  79. form->updateFrameBuffer();
  80. __forms.push_back(form);
  81. return form;
  82. }
  83. Form* Form::create(const char* url)
  84. {
  85. // Load Form from .form file.
  86. Properties* properties = Properties::create(url);
  87. if (properties == NULL)
  88. {
  89. GP_ASSERT(properties);
  90. return NULL;
  91. }
  92. // Check if the Properties is valid and has a valid namespace.
  93. Properties* formProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
  94. assert(formProperties);
  95. if (!formProperties || !(strcmp(formProperties->getNamespace(), "form") == 0))
  96. {
  97. GP_ASSERT(formProperties);
  98. SAFE_DELETE(properties);
  99. return NULL;
  100. }
  101. // Parse theme
  102. std::string themeFile;
  103. formProperties->getPath("theme", &themeFile);
  104. Theme* theme = Theme::create(themeFile.c_str());
  105. GP_ASSERT(theme);
  106. // Parse style
  107. const char* styleName = formProperties->getString("style");
  108. Theme::Style* style = styleName ? theme->getStyle(styleName) : theme->getEmptyStyle();
  109. // Create new form
  110. Form* form = new Form();
  111. form->_theme = theme;
  112. // Initialize common container properties
  113. form->initialize(style, formProperties);
  114. form->updateFrameBuffer();
  115. __forms.push_back(form);
  116. SAFE_DELETE(properties);
  117. return form;
  118. }
  119. Form* Form::getForm(const char* id)
  120. {
  121. for (size_t i = 0, size = __forms.size(); i < size; ++i)
  122. {
  123. Form* f = __forms[i];
  124. GP_ASSERT(f);
  125. if (strcmp(id, f->getId()) == 0)
  126. {
  127. return f;
  128. }
  129. }
  130. return NULL;
  131. }
  132. Control* Form::getFocusControl()
  133. {
  134. return _focusControl;
  135. }
  136. void Form::clearFocus()
  137. {
  138. setFocusControl(NULL);
  139. }
  140. bool Form::isForm() const
  141. {
  142. return true;
  143. }
  144. Theme* Form::getTheme() const
  145. {
  146. return _theme;
  147. }
  148. void Form::updateFrameBuffer()
  149. {
  150. float width = _absoluteClipBounds.width;
  151. float height = _absoluteClipBounds.height;
  152. SAFE_RELEASE(_frameBuffer);
  153. SAFE_DELETE(_spriteBatch);
  154. if (width != 0.0f && height != 0.0f)
  155. {
  156. // Width and height must be powers of two to create a texture.
  157. unsigned int w = nextPowerOfTwo(width);
  158. unsigned int h = nextPowerOfTwo(height);
  159. _u2 = width / (float)w;
  160. _v1 = height / (float)h;
  161. _frameBuffer = FrameBuffer::create(_id.c_str(), w, h);
  162. GP_ASSERT(_frameBuffer);
  163. // Re-create projection matrix for drawing onto framebuffer
  164. Matrix::createOrthographicOffCenter(0, width, height, 0, 0, 1, &_projectionMatrix);
  165. // Re-create sprite batch
  166. _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
  167. GP_ASSERT(_spriteBatch);
  168. // Compute full-viewport ortho matrix for drawing frame buffer onto screen
  169. Matrix viewportProjection;
  170. Matrix::createOrthographicOffCenter(0, Game::getInstance()->getViewport().width, Game::getInstance()->getViewport().height, 0, 0, 1, &viewportProjection);
  171. _spriteBatch->setProjectionMatrix(viewportProjection);
  172. // Clear the framebuffer black
  173. Game* game = Game::getInstance();
  174. FrameBuffer* previousFrameBuffer = _frameBuffer->bind();
  175. Rectangle previousViewport = game->getViewport();
  176. game->setViewport(Rectangle(0, 0, width, height));
  177. _theme->setProjectionMatrix(_projectionMatrix);
  178. game->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0, 0);
  179. previousFrameBuffer->bind();
  180. game->setViewport(previousViewport);
  181. // Force any attached node to be updated
  182. setNode(_node);
  183. }
  184. }
  185. static Effect* createEffect()
  186. {
  187. Effect* effect = NULL;
  188. if (__formEffect == NULL)
  189. {
  190. __formEffect = Effect::createFromFile(FORM_VSH, FORM_FSH);
  191. if (__formEffect == NULL)
  192. {
  193. GP_ERROR("Unable to load form effect.");
  194. return NULL;
  195. }
  196. effect = __formEffect;
  197. }
  198. else
  199. {
  200. effect = __formEffect;
  201. }
  202. return effect;
  203. }
  204. void Form::setNode(Node* node)
  205. {
  206. // If we were already attached to a node, remove ourself from it
  207. if (_node)
  208. {
  209. _node->setModel(NULL);
  210. _nodeQuad = NULL;
  211. _nodeMaterial = NULL;
  212. _node = NULL;
  213. }
  214. if (node)
  215. {
  216. // Set this Form up to be 3D by initializing a quad.
  217. float x2 = _absoluteBounds.width;
  218. float y2 = _absoluteBounds.height;
  219. float vertices[] =
  220. {
  221. 0, y2, 0, 0, _v1,
  222. 0, 0, 0, 0, 0,
  223. x2, y2, 0, _u2, _v1,
  224. x2, 0, 0, _u2, 0
  225. };
  226. VertexFormat::Element elements[] =
  227. {
  228. VertexFormat::Element(VertexFormat::POSITION, 3),
  229. VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
  230. };
  231. Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
  232. GP_ASSERT(mesh);
  233. mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
  234. mesh->setVertexData(vertices, 0, 4);
  235. _nodeQuad = Model::create(mesh);
  236. SAFE_RELEASE(mesh);
  237. GP_ASSERT(_nodeQuad);
  238. // Create the effect and material
  239. Effect* effect = createEffect();
  240. GP_ASSERT(effect);
  241. _nodeMaterial = Material::create(effect);
  242. GP_ASSERT(_nodeMaterial);
  243. _nodeQuad->setMaterial(_nodeMaterial);
  244. _nodeMaterial->release();
  245. node->setModel(_nodeQuad);
  246. _nodeQuad->release();
  247. // Bind the WorldViewProjection matrix.
  248. _nodeMaterial->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
  249. // Bind the texture from the framebuffer and set the texture to clamp
  250. if (_frameBuffer)
  251. {
  252. Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
  253. GP_ASSERT(sampler);
  254. sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
  255. _nodeMaterial->getParameter("u_texture")->setValue(sampler);
  256. sampler->release();
  257. }
  258. RenderState::StateBlock* rsBlock = _nodeMaterial->getStateBlock();
  259. rsBlock->setDepthWrite(true);
  260. rsBlock->setBlend(true);
  261. rsBlock->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
  262. rsBlock->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
  263. }
  264. _node = node;
  265. }
  266. void Form::update(float elapsedTime)
  267. {
  268. if (isDirty())
  269. {
  270. update(NULL, Vector2::zero());
  271. Control::State state = getState();
  272. // Cache themed attributes for performance.
  273. _skin = getSkin(state);
  274. _opacity = getOpacity(state);
  275. GP_ASSERT(_layout);
  276. if (_scroll != SCROLL_NONE)
  277. {
  278. updateScroll();
  279. }
  280. else
  281. {
  282. _layout->update(this, Vector2::zero());
  283. }
  284. }
  285. }
  286. void Form::update(const Control* container, const Vector2& offset)
  287. {
  288. // Store previous absolute bounds
  289. Rectangle oldAbsoluteClipBounds = _absoluteClipBounds;
  290. Container::update(container, offset);
  291. _layout->align(this, NULL);
  292. if (_absoluteClipBounds.width != oldAbsoluteClipBounds.width || _absoluteClipBounds.height != oldAbsoluteClipBounds.height)
  293. {
  294. updateFrameBuffer();
  295. }
  296. }
  297. unsigned int Form::draw()
  298. {
  299. if (!_visible || !_frameBuffer)
  300. return 0;
  301. // The first time a form is drawn, its contents are rendered into a framebuffer.
  302. // The framebuffer will only be drawn into again when the contents of the form change.
  303. // If this form has a node then it's a 3D form and the framebuffer will be used
  304. // to texture a quad. The quad will be given the same dimensions as the form and
  305. // must be transformed appropriately by the user, unless they call setQuad() themselves.
  306. // On the other hand, if this form has not been set on a node, SpriteBatch will be used
  307. // to render the contents of the framebuffer directly to the display.
  308. // Check whether this form has changed since the last call to draw() and if so, render into the framebuffer.
  309. if (isDirty())
  310. {
  311. FrameBuffer* previousFrameBuffer = _frameBuffer->bind();
  312. Game* game = Game::getInstance();
  313. Rectangle prevViewport = game->getViewport();
  314. game->setViewport(Rectangle(0, 0, _absoluteClipBounds.width, _absoluteClipBounds.height));
  315. GP_ASSERT(_theme);
  316. _theme->setProjectionMatrix(_projectionMatrix);
  317. // By setting needsClear to true here, an optimization meant to clear and redraw only areas of the form
  318. // that have changed is disabled. Currently, repositioning controls can result in areas of the screen being cleared
  319. // after another control has been drawn there. This should probably be done in two passes -- one to clear areas where
  320. // dirty controls were last frame, and another to draw them where they are now.
  321. Container::draw(_theme->getSpriteBatch(), _absoluteClipBounds, /*_skin != NULL*/ true, false, _absoluteClipBounds.height);
  322. // Restore the previous game viewport.
  323. game->setViewport(prevViewport);
  324. // Rebind the previous framebuffer and game viewport.
  325. previousFrameBuffer->bind();
  326. }
  327. // Draw either with a 3D quad or sprite batch.
  328. if (_node)
  329. {
  330. // If we have the node set, then draw a 3D quad model.
  331. _nodeQuad->draw();
  332. }
  333. else
  334. {
  335. // Otherwise we draw the framebuffer in ortho space with a spritebatch.
  336. _spriteBatch->start();
  337. _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
  338. _spriteBatch->finish();
  339. }
  340. return 2;
  341. }
  342. const char* Form::getType() const
  343. {
  344. return "form";
  345. }
  346. Control* Form::getActiveControl()
  347. {
  348. return _activeControl;
  349. }
  350. void Form::updateInternal(float elapsedTime)
  351. {
  352. pollGamepads();
  353. for (size_t i = 0, size = __forms.size(); i < size; ++i)
  354. {
  355. Form* form = __forms[i];
  356. if (form && form->isEnabled() && form->isVisible())
  357. {
  358. form->update(elapsedTime);
  359. }
  360. }
  361. }
  362. bool Form::screenToForm(Control* ctrl, int* x, int* y)
  363. {
  364. Form* form = ctrl->getTopLevelForm();
  365. if (form)
  366. {
  367. if (form->_node)
  368. {
  369. // Form is attached to a scene node, so project the screen space point into the
  370. // form's coordinate space (which may be transformed by the node).
  371. Vector3 point;
  372. if (form->projectPoint(*x, *y, &point))
  373. {
  374. *x = (int)point.x;
  375. *y = form->_bounds.height - (int)point.y;
  376. }
  377. else
  378. {
  379. return false;
  380. }
  381. }
  382. *x -= form->_bounds.x;
  383. *y -= form->_bounds.y;
  384. return true;
  385. }
  386. return false;
  387. }
  388. Control* Form::findInputControl(int* x, int* y, bool focus)
  389. {
  390. for (int i = (int)__forms.size() - 1; i >= 0; --i)
  391. {
  392. Form* form = __forms[i];
  393. if (!form || !form->isEnabled() || !form->isVisible())
  394. continue;
  395. // Convert to local form coordinates
  396. int formX = *x;
  397. int formY = *y;
  398. if (!screenToForm(form, &formX, &formY))
  399. continue;
  400. // Search for an input control within this form
  401. Control* ctrl = findInputControl(form, formX, formY, focus);
  402. if (ctrl)
  403. {
  404. *x = formX;
  405. *y = formY;
  406. return ctrl;
  407. }
  408. // If the form consumes input events and the point intersects the form,
  409. // don't traverse other forms below it.
  410. if (form->_consumeInputEvents && form->_absoluteClipBounds.contains(formX, formY))
  411. return NULL;
  412. }
  413. return NULL;
  414. }
  415. Control* Form::findInputControl(Control* control, int x, int y, bool focus)
  416. {
  417. Control* result = NULL;
  418. // Does the passed in control's bounds intersect the specified coordinates - and
  419. // does the control support the specified input state?
  420. if (control->_consumeInputEvents && control->_visible && control->_enabled && (!focus || control->canFocus()))
  421. {
  422. if (control->_absoluteClipBounds.contains(x, y))
  423. result = control;
  424. }
  425. // If the control has children, search for an input control inside it that also
  426. // supports the above conditions.
  427. if (control->isContainer())
  428. {
  429. Container* container = static_cast<Container*>(control);
  430. for (int i = (int)container->getControlCount() - 1; i >= 0; --i)
  431. {
  432. Control* ctrl = findInputControl(container->getControl((unsigned int)i), x, y, focus);
  433. if (ctrl)
  434. result = ctrl;
  435. }
  436. }
  437. return result;
  438. }
  439. Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
  440. {
  441. Control* ctrl = NULL;
  442. int newX = *x;
  443. int newY = *y;
  444. if (pressed)
  445. {
  446. // Update active state changes
  447. if ((ctrl = findInputControl(&newX, &newY, false)) != NULL)
  448. {
  449. if (_activeControl != ctrl || _activeControlState != Control::ACTIVE)
  450. {
  451. if (_activeControl)
  452. _activeControl->_dirty = true;
  453. _activeControl = ctrl;
  454. _activeControlState = Control::ACTIVE;
  455. _activeControl->_dirty = true;
  456. }
  457. ctrl->notifyListeners(Control::Listener::PRESS);
  458. }
  459. }
  460. else // !pressed
  461. {
  462. Control* active = _activeControlState == Control::ACTIVE ? _activeControl : NULL;
  463. if (active)
  464. {
  465. active->addRef(); // protect against event-hanlder evil
  466. // Release happened for the active control (that was pressed)
  467. ctrl = active;
  468. // Transform point to form-space
  469. screenToForm(ctrl, &newX, &newY);
  470. // No longer any active control
  471. _activeControl->_dirty = true;
  472. _activeControl = NULL;
  473. _activeControlState = Control::NORMAL;
  474. }
  475. else
  476. {
  477. // Update active and hover control state on release
  478. Control* inputControl = findInputControl(&newX, &newY, false);
  479. if (inputControl)
  480. {
  481. ctrl = inputControl;
  482. if (_activeControl != ctrl || _activeControlState != Control::HOVER)
  483. {
  484. if (_activeControl)
  485. _activeControl->_dirty = true;
  486. _activeControl = ctrl;
  487. _activeControlState = Control::HOVER;
  488. _activeControl->_dirty = true;
  489. }
  490. }
  491. else
  492. {
  493. // No longer any active control
  494. if (_activeControl)
  495. _activeControl->_dirty = true;
  496. _activeControl = NULL;
  497. _activeControlState = Control::NORMAL;
  498. }
  499. }
  500. if (active)
  501. {
  502. // Fire release event for the previously active control
  503. active->notifyListeners(Control::Listener::RELEASE);
  504. // If the release event was received on the same control that was
  505. // originally pressed, fire a click event
  506. if (active->_absoluteClipBounds.contains(newX, newY))
  507. {
  508. if (!active->_parent || !active->_parent->isScrolling())
  509. {
  510. active->notifyListeners(Control::Listener::CLICK);
  511. }
  512. }
  513. active->release();
  514. }
  515. }
  516. *x = newX;
  517. *y = newY;
  518. return ctrl;
  519. }
  520. Control* Form::handlePointerMove(int* x, int* y)
  521. {
  522. Control* ctrl = NULL;
  523. // Handle hover control changes on move, only if there is no currently active control
  524. // (i.e. when the mouse or a finger is not down).
  525. if (_activeControl && (_activeControlState == Control::ACTIVE))
  526. {
  527. ctrl = _activeControl;
  528. screenToForm(ctrl, x, y);
  529. }
  530. else
  531. {
  532. ctrl = findInputControl(x, y, false);
  533. if (ctrl)
  534. {
  535. // Update hover control
  536. if (_activeControl != ctrl || _activeControlState != Control::HOVER)
  537. {
  538. if (_activeControl)
  539. _activeControl->_dirty = true;
  540. _activeControl = ctrl;
  541. _activeControlState = Control::HOVER;
  542. _activeControl->_dirty = true;
  543. }
  544. }
  545. else
  546. {
  547. // No active/hover control
  548. if (_activeControl)
  549. _activeControl->_dirty = true;
  550. _activeControl = NULL;
  551. _activeControlState = Control::NORMAL;
  552. }
  553. }
  554. return ctrl;
  555. }
  556. void Form::verifyRemovedControlState(Control* control)
  557. {
  558. if (_focusControl == control)
  559. _focusControl = NULL;
  560. if (_activeControl == control)
  561. {
  562. _activeControl = NULL;
  563. _activeControlState = Control::NORMAL;
  564. }
  565. }
  566. // Generic pointer event handler that both touch and mouse events map to.
  567. // Mappings:
  568. // mouse - true for mouse events, false for touch events
  569. // evt - Mouse::MouseEvent or Touch::TouchEvent
  570. // x, y - Point of event
  571. // param - wheelData for mouse events, contactIndex for touch events
  572. bool Form::pointerEventInternal(bool mouse, int evt, int x, int y, int param)
  573. {
  574. // Do not process mouse input when mouse is captured
  575. if (mouse && Game::getInstance()->isMouseCaptured())
  576. return false;
  577. // Is this a press event (TOUCH_PRESS has the same value as MOUSE_PRESS_LEFT_BUTTON)
  578. bool pressEvent = evt == Touch::TOUCH_PRESS || (mouse && (evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON || evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON));
  579. Control* ctrl = NULL;
  580. int formX = x;
  581. int formY = y;
  582. if (mouse || (param == 0))
  583. {
  584. // Note: TOUCH_PRESS and TOUCH_RELEASE have same values as MOUSE_PRESS_LEFT_BUTTON and MOUSE_RELEASE_LEFT_BUTTON
  585. if (evt == Touch::TOUCH_PRESS)
  586. {
  587. ctrl = handlePointerPressRelease(&formX, &formY, true);
  588. }
  589. else if (evt == Touch::TOUCH_RELEASE)
  590. {
  591. ctrl = handlePointerPressRelease(&formX, &formY, false);
  592. }
  593. else if ((mouse && evt == Mouse::MOUSE_MOVE) || (!mouse && evt == Touch::TOUCH_MOVE))
  594. {
  595. ctrl = handlePointerMove(&formX, &formY);
  596. }
  597. }
  598. // Dispatch input events to all controls that intersect this point
  599. if (ctrl == NULL)
  600. {
  601. formX = x;
  602. formY = y;
  603. ctrl = findInputControl(&formX, &formY, false);
  604. }
  605. if (ctrl)
  606. {
  607. // Handle container scrolling
  608. Control* tmp = ctrl;
  609. while (tmp)
  610. {
  611. if (tmp->isContainer())
  612. {
  613. Container* container = static_cast<Container*>(tmp);
  614. if (container->_scroll != SCROLL_NONE)
  615. {
  616. if (mouse)
  617. {
  618. if (container->mouseEventScroll((Mouse::MouseEvent)evt, formX - tmp->_absoluteBounds.x, formY - tmp->_absoluteBounds.y, param))
  619. return true;
  620. }
  621. else
  622. {
  623. if (container->touchEventScroll((Touch::TouchEvent)evt, formX - tmp->_absoluteBounds.x, formY - tmp->_absoluteBounds.y, param))
  624. return true;
  625. }
  626. break; // scrollable parent container found
  627. }
  628. }
  629. tmp = tmp->_parent;
  630. }
  631. // Handle setting focus for all press events
  632. if (pressEvent)
  633. {
  634. Control* focusControl = ctrl;
  635. while (focusControl && !focusControl->setFocus())
  636. focusControl = focusControl->_parent;
  637. if (focusControl == NULL)
  638. {
  639. // Nothing got focus on this press, so remove current focused control
  640. setFocusControl(NULL);
  641. }
  642. }
  643. // Dispatch the event from the bottom upwards, until a control intersecting the point consumes the event
  644. while (ctrl)
  645. {
  646. int localX = formX - ctrl->_absoluteBounds.x;
  647. int localY = formY - ctrl->_absoluteBounds.y;
  648. if (mouse)
  649. {
  650. if (ctrl->mouseEvent((Mouse::MouseEvent)evt, localX, localY, param))
  651. return true;
  652. // Forward to touch event hanlder if unhandled by mouse handler
  653. switch (evt)
  654. {
  655. case Mouse::MOUSE_PRESS_LEFT_BUTTON:
  656. if (ctrl->touchEvent(Touch::TOUCH_PRESS, localX, localY, 0))
  657. return true;
  658. break;
  659. case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
  660. if (ctrl->touchEvent(Touch::TOUCH_RELEASE, localX, localY, 0))
  661. return true;
  662. break;
  663. case Mouse::MOUSE_MOVE:
  664. if (ctrl->touchEvent(Touch::TOUCH_MOVE, localX, localY, 0))
  665. return true;
  666. break;
  667. }
  668. }
  669. else
  670. {
  671. if (ctrl->touchEvent((Touch::TouchEvent)evt, localX, localY, param))
  672. return true;
  673. }
  674. // Consume all input events anyways?
  675. if (ctrl->getConsumeInputEvents())
  676. return true;
  677. ctrl = ctrl->getParent();
  678. }
  679. }
  680. else
  681. {
  682. // If this was a press event, remove all focus
  683. if (pressEvent)
  684. {
  685. setFocusControl(NULL);
  686. }
  687. }
  688. return false;
  689. }
  690. bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  691. {
  692. return pointerEventInternal(false, evt, x, y, (int)contactIndex);
  693. }
  694. bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  695. {
  696. return pointerEventInternal(true, evt, x, y, wheelDelta);
  697. }
  698. bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
  699. {
  700. switch (key)
  701. {
  702. case Keyboard::KEY_ESCAPE:
  703. return false; // ignore escape key presses
  704. case Keyboard::KEY_SHIFT:
  705. if (evt == Keyboard::KEY_PRESS)
  706. _shiftKeyDown = true;
  707. else if (evt == Keyboard::KEY_RELEASE)
  708. _shiftKeyDown = false;
  709. break;
  710. }
  711. if (key == Keyboard::KEY_ESCAPE)
  712. return false;
  713. // Handle focus changing
  714. if (_focusControl)
  715. {
  716. switch (evt)
  717. {
  718. case Keyboard::KEY_CHAR:
  719. switch (key)
  720. {
  721. case Keyboard::KEY_TAB:
  722. if (_focusControl->_parent)
  723. {
  724. if (_focusControl->_parent->moveFocus(_shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
  725. return true;
  726. }
  727. break;
  728. }
  729. break;
  730. }
  731. }
  732. // Dispatch key events
  733. Control* ctrl = _focusControl;
  734. while (ctrl)
  735. {
  736. if (ctrl->isEnabled() && ctrl->isVisible())
  737. {
  738. if (ctrl->keyEvent(evt, key))
  739. return true;
  740. }
  741. ctrl = ctrl->getParent();
  742. }
  743. return false;
  744. }
  745. void Form::pollGamepads()
  746. {
  747. Game* game = Game::getInstance();
  748. // If no gamepads are connected, return immediately
  749. unsigned int gamepadCount = game->getGamepadCount();
  750. if (gamepadCount == 0)
  751. return;
  752. // For now, always use gamepad zero for controlling the UI.
  753. // Possibly allow the developer to set the active gamepad for UI later.
  754. Gamepad* gamepad = game->getGamepad(0, true);
  755. if (!gamepad)
  756. return;
  757. pollGamepad(gamepad);
  758. }
  759. bool Form::pollGamepad(Gamepad* gamepad)
  760. {
  761. // Get the currently focused control's container for focus management and scrolling
  762. if (!_focusControl)
  763. return false;
  764. // Get parent container
  765. Container* parentContainer = NULL;
  766. if (_focusControl->_parent)
  767. parentContainer = _focusControl->_parent;
  768. // Get scroll container
  769. Container* scrollContainer = NULL;
  770. if (_focusControl->isContainer())
  771. {
  772. scrollContainer = static_cast<Container*>(_focusControl);
  773. if (scrollContainer->_scroll == SCROLL_NONE)
  774. scrollContainer = NULL;
  775. }
  776. if (!scrollContainer && parentContainer && parentContainer->_scroll != SCROLL_NONE)
  777. scrollContainer = parentContainer;
  778. // Static static maintained across function calls
  779. static bool scrolling = false;
  780. static double lastFocusChangeTime = 0;
  781. bool focusPressed = false;
  782. bool stillScrolling = false;
  783. double currentTime = Game::getAbsoluteTime();
  784. double focusChangeElapsedTime = currentTime - lastFocusChangeTime;
  785. // Is a selection button down (i.e. buttons used for UI clicking/interactions)?
  786. bool selectButtonDown = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
  787. if (!selectButtonDown)
  788. {
  789. // Get values of analog joysticks 1 and 2 (assume left and right analog sticks)
  790. Vector2 joystick;
  791. unsigned int joystickCount = gamepad->getJoystickCount();
  792. gamepad->getJoystickValues(0, &joystick);
  793. if (parentContainer)
  794. {
  795. // The Dpad and left analog stick (i.e. first analog stick when there are two joysticks) controls focus
  796. if (gamepad->isButtonDown(Gamepad::BUTTON_UP) || (joystickCount > 1 && joystick.y > JOYSTICK_THRESHOLD))
  797. {
  798. focusPressed = true;
  799. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(UP))
  800. {
  801. lastFocusChangeTime = currentTime;
  802. }
  803. }
  804. if (gamepad->isButtonDown(Gamepad::BUTTON_DOWN) || (joystickCount > 1 && joystick.y < -JOYSTICK_THRESHOLD))
  805. {
  806. focusPressed = true;
  807. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(DOWN))
  808. {
  809. lastFocusChangeTime = currentTime;
  810. }
  811. }
  812. if (gamepad->isButtonDown(Gamepad::BUTTON_LEFT) || (joystickCount > 1 && joystick.x < -JOYSTICK_THRESHOLD))
  813. {
  814. focusPressed = true;
  815. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(LEFT))
  816. {
  817. lastFocusChangeTime = currentTime;
  818. }
  819. }
  820. if (gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) || (joystickCount > 1 && joystick.x > JOYSTICK_THRESHOLD))
  821. {
  822. focusPressed = true;
  823. if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(RIGHT))
  824. {
  825. lastFocusChangeTime = currentTime;
  826. }
  827. }
  828. }
  829. // The RIGHT analog stick (i.e. second), or ONLY analog stick (when only 1 joystick), is used to scroll.
  830. if (scrollContainer && joystickCount > 0)
  831. {
  832. if (joystickCount > 1)
  833. gamepad->getJoystickValues(1, &joystick);
  834. if (std::fabs(joystick.x) > JOYSTICK_THRESHOLD || std::fabs(joystick.y) > JOYSTICK_THRESHOLD)
  835. {
  836. scrollContainer->startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, !scrolling);
  837. scrolling = stillScrolling = true;
  838. }
  839. }
  840. }
  841. if (!focusPressed)
  842. {
  843. // Reset focus repeat
  844. lastFocusChangeTime = 0;
  845. }
  846. if (scrolling && !stillScrolling)
  847. {
  848. scrolling = false;
  849. if (scrollContainer)
  850. scrollContainer->stopScrolling();
  851. }
  852. return focusPressed || scrolling;
  853. }
  854. bool Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
  855. {
  856. if (!_focusControl)
  857. return false;
  858. bool selectButtonPressed = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
  859. // Fire press, release and click events to focused controls
  860. switch (evt)
  861. {
  862. case Gamepad::BUTTON_EVENT:
  863. if (selectButtonPressed && (_activeControl != _focusControl || _activeControlState != Control::ACTIVE))
  864. {
  865. _activeControl = _focusControl;
  866. _activeControlState = Control::ACTIVE;
  867. _activeControl->notifyListeners(Control::Listener::PRESS);
  868. return true;
  869. }
  870. else if (!selectButtonPressed && _activeControl == _focusControl && _activeControlState == Control::ACTIVE)
  871. {
  872. _activeControlState = Control::NORMAL;
  873. _activeControl->notifyListeners(Control::Listener::RELEASE);
  874. _activeControl->notifyListeners(Control::Listener::CLICK);
  875. return true;
  876. }
  877. break;
  878. }
  879. // Dispatch gamepad events to focused controls (or their parents)
  880. Control * ctrl = _focusControl;
  881. while (ctrl)
  882. {
  883. if (ctrl->isEnabled() && ctrl->isVisible())
  884. {
  885. if (ctrl->gamepadEvent(evt, gamepad, analogIndex))
  886. return true;
  887. }
  888. ctrl = ctrl->getParent();
  889. }
  890. return false;
  891. }
  892. void Form::resizeEventInternal(unsigned int width, unsigned int height)
  893. {
  894. for (size_t i = 0, size = __forms.size(); i < size; ++i)
  895. {
  896. Form* form = __forms[i];
  897. if (form)
  898. {
  899. if (form->_spriteBatch)
  900. {
  901. // Update viewport projection matrix
  902. Matrix viewportProjection;
  903. Matrix::createOrthographicOffCenter(0, Game::getInstance()->getViewport().width, Game::getInstance()->getViewport().height, 0, 0, 1, &viewportProjection);
  904. form->_spriteBatch->setProjectionMatrix(viewportProjection);
  905. }
  906. // Dirty the form
  907. form->_dirty = true;
  908. }
  909. }
  910. }
  911. bool Form::projectPoint(int x, int y, Vector3* point)
  912. {
  913. if (!_node)
  914. return false;
  915. Scene* scene = _node->getScene();
  916. Camera* camera;
  917. if (scene && (camera = scene->getActiveCamera()))
  918. {
  919. // Get info about the form's position.
  920. Matrix m = _node->getWorldMatrix();
  921. Vector3 pointOnPlane(0, 0, 0);
  922. m.transformPoint(&pointOnPlane);
  923. // Unproject point into world space.
  924. Ray ray;
  925. camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
  926. // Find the quad's plane. We know its normal is the quad's forward vector.
  927. Vector3 normal = _node->getForwardVectorWorld().normalize();
  928. // To get the plane's distance from the origin, we project a point on the
  929. // plane onto the plane's normal vector.
  930. const float distance = fabs(Vector3::dot(pointOnPlane, normal));
  931. Plane plane(normal, -distance);
  932. // Check for collision with plane.
  933. float collisionDistance = ray.intersects(plane);
  934. if (collisionDistance != Ray::INTERSECTS_NONE)
  935. {
  936. // Multiply the ray's direction vector by collision distance and add that to the ray's origin.
  937. point->set(ray.getOrigin() + collisionDistance*ray.getDirection());
  938. // Project this point into the plane.
  939. m.invert();
  940. m.transformPoint(point);
  941. return true;
  942. }
  943. }
  944. return false;
  945. }
  946. unsigned int Form::nextPowerOfTwo(unsigned int v)
  947. {
  948. if (!((v & (v - 1)) == 0))
  949. {
  950. v--;
  951. v |= v >> 1;
  952. v |= v >> 2;
  953. v |= v >> 4;
  954. v |= v >> 8;
  955. v |= v >> 16;
  956. return v + 1;
  957. }
  958. else
  959. {
  960. return v;
  961. }
  962. }
  963. void Form::controlDisabled(Control* control)
  964. {
  965. if (Form::_focusControl && (Form::_focusControl == control || Form::_focusControl->isChild(control)))
  966. {
  967. setFocusControl(NULL);
  968. }
  969. if (Form::_activeControl)
  970. {
  971. if (Form::_activeControl == control || Form::_activeControl->isChild(control))
  972. {
  973. Form::_activeControl = NULL;
  974. Form::_activeControlState = Control::NORMAL;
  975. }
  976. }
  977. }
  978. void Form::setFocusControl(Control* control)
  979. {
  980. Control* oldFocus = _focusControl;
  981. _focusControl = control;
  982. // Deactivate the old focus control
  983. if (oldFocus)
  984. {
  985. oldFocus->_dirty = true;
  986. oldFocus->notifyListeners(Control::Listener::FOCUS_LOST);
  987. }
  988. // Activate the new focus control
  989. if (_focusControl)
  990. {
  991. _focusControl->_dirty = true;
  992. _focusControl->notifyListeners(Control::Listener::FOCUS_GAINED);
  993. // Set the activeControl property of the control's parent container
  994. Container* parent = NULL;
  995. if (_focusControl->_parent)
  996. {
  997. parent = _focusControl->_parent;
  998. parent->_activeControl = _focusControl;
  999. }
  1000. // If this control is inside a scrollable container and is not fully visible,
  1001. // scroll the container so that it is.
  1002. if (parent && parent->_scroll != SCROLL_NONE && !parent->_viewportBounds.isEmpty())
  1003. {
  1004. const Rectangle& bounds = _focusControl->getBounds();
  1005. if (bounds.x < parent->_scrollPosition.x)
  1006. {
  1007. // Control is to the left of the scrolled viewport.
  1008. parent->_scrollPosition.x = -bounds.x;
  1009. }
  1010. else if (bounds.x + bounds.width > parent->_scrollPosition.x + parent->_viewportBounds.width)
  1011. {
  1012. // Control is off to the right.
  1013. parent->_scrollPosition.x = -(bounds.x + bounds.width - parent->_viewportBounds.width);
  1014. }
  1015. if (bounds.y < parent->_viewportBounds.y - parent->_scrollPosition.y)
  1016. {
  1017. // Control is above the viewport.
  1018. parent->_scrollPosition.y = -bounds.y;
  1019. }
  1020. else if (bounds.y + bounds.height > parent->_viewportBounds.height - parent->_scrollPosition.y)
  1021. {
  1022. // Control is below the viewport.
  1023. parent->_scrollPosition.y = -(bounds.y + bounds.height - parent->_viewportBounds.height);
  1024. }
  1025. }
  1026. }
  1027. }
  1028. }