Form.cpp 37 KB

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