Form.cpp 37 KB

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