UIObject.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /************************************************************************
  2. * UIObject.js
  3. ************************************************************************
  4. * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
  5. *
  6. * This file is part of Pandora.
  7. *
  8. * Pandora is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * Pandora is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with Pandora. If not, see <https://www.gnu.org/licenses/>.
  20. *************************************************************************/
  21. /**
  22. * The {@code UIObject} class represents a minimal structure for any GameObject that
  23. * hold an HTML interface element.
  24. *
  25. * ! All GameObjects need to be inside the tree to do anything (can be added as a child
  26. * ! of another GameObject on the tree or as a root).
  27. *
  28. * @author Pedro Schneider
  29. *
  30. * @class
  31. */
  32. class UIObject extends GameObject
  33. {
  34. /**
  35. * Initializes an empty UIObject.
  36. *
  37. * @param {String} name name for this UIObject.
  38. *
  39. * @constructor
  40. */
  41. constructor(name)
  42. {
  43. super(name);
  44. this.P5Element = null; // This UIOBject's p5.Element (that holds an HTML element).
  45. this.visible = true; // Is this UIObject visible at the moment?
  46. this.position = new Vector2(0, 0); // This UIObject's position on the secondary buffer.
  47. this.size = new Vector2(300, 100); // The UIObject's size on the secondary buffer.
  48. this.fontSize = STYLE.DEFAULT_FONT_SIZE; // This UIObject's font style.
  49. }
  50. /**
  51. * Connects this UIObject's p5.Element's events to this GameObject's appropriate
  52. * methods.
  53. */
  54. connectCallbacks()
  55. {
  56. this.P5Element.mousePressed(this.onMousePressed);
  57. this.P5Element.doubleClicked(this.onDoubleClicked);
  58. this.P5Element.mouseWheel(this.onMouseWheel);
  59. this.P5Element.mouseReleased(this.onMouseReleased);
  60. this.P5Element.mouseClicked(this.onMouseClicked);
  61. this.P5Element.mouseMoved(this.onMouseMoved);
  62. this.P5Element.mouseOver(this.onMouseOver);
  63. this.P5Element.mouseOut(this.onMouseOut);
  64. this.P5Element.touchStarted(this.onTouchStarted);
  65. this.P5Element.touchMoved(this.onTouchMoved);
  66. this.P5Element.touchEnded(this.onTouchEnded);
  67. this.P5Element.dragOver(this.onDragOver);
  68. this.P5Element.dragLeave(this.onDragLeave);
  69. this.P5Element.pandoraObject = this;
  70. }
  71. /**
  72. * Sets the position of this UIObject on the secondary buffer.
  73. *
  74. * @param {number} x pixel position on the X axis.
  75. * @param {number} y pixel position on the Y axis.
  76. */
  77. setPosition(x, y)
  78. {
  79. this.position.x = x;
  80. this.position.y = y;
  81. }
  82. /**
  83. * Sets the size of this UIObject on the secondary buffer.
  84. *
  85. * @param {number} w pixel width of this UIObject.
  86. * @param {number} h pixel height of this UIObject.
  87. */
  88. setSize(w, h)
  89. {
  90. this.size.x = w;
  91. this.size.y = h;
  92. }
  93. /**
  94. * Sets this UIObject's font size.
  95. *
  96. * @param {number} fs new font size.
  97. */
  98. setFontSize(fs)
  99. {
  100. this.fontSize = fs;
  101. }
  102. /**
  103. * Sets the visibility of this UIObject's p5.Element's visibility.
  104. *
  105. * @param {boolean} vis new value for the visibility of the UIObject.
  106. */
  107. setVisibility(vis)
  108. {
  109. if (vis) this.P5Element.show();
  110. else this.P5Element.hide();
  111. this.visible = !this.visible;
  112. }
  113. /**
  114. * Sets the inner html value of this UIObject's p5.Element.
  115. *
  116. * @param {*} val new inner HTML value for this UIObject.
  117. */
  118. setValue(val)
  119. {
  120. this.P5Element.value(val)
  121. }
  122. /**
  123. * Sets the CSS style of this UIObject's p5.Element.
  124. *
  125. * @param {Object} style object containing the CSS style for this
  126. * UIObject.
  127. */
  128. setStyle(style)
  129. {
  130. for (const [key, value] of Object.entries(style))
  131. {
  132. this.P5Element.style(`${key}`, value);
  133. }
  134. }
  135. /**
  136. * Returns this UIOBject's position on the secondary buffer.
  137. *
  138. * @returns {Vector2} this UIObject's position on the secondary buffer.
  139. */
  140. getPosition()
  141. {
  142. return this.position;
  143. }
  144. /**
  145. * Returns this Object's position on the secondary buffer.
  146. *
  147. * @returns {Vector2} this UIObject's size on the secondary buffer.
  148. */
  149. getSize()
  150. {
  151. return this.size;
  152. }
  153. /**
  154. * Returns this UIObject's font size.
  155. *
  156. * @returns {number} this UIObject's font size.
  157. */
  158. getFontSize()
  159. {
  160. return this.fontSize;
  161. }
  162. /**
  163. * Returns this UIObject's visibility flag.
  164. *
  165. * @returns {boolean} true if this UIObject is visible, false if not.
  166. */
  167. getVisibility()
  168. {
  169. return this.visible;
  170. }
  171. /**
  172. * Return the inner HTML value of this UIObject's p5.Element.
  173. *
  174. * @returns {String} inner HTML value of this UIObject's p5.Element.
  175. */
  176. getValue()
  177. {
  178. return this.P5Element.value();
  179. }
  180. /**
  181. * Sets this UIObject's visibility flag to true, shows the p5.Element, and
  182. * recursively calls the show() method on all of this GameObject's children
  183. * if they have it.
  184. */
  185. show()
  186. {
  187. this.visible = true;
  188. this.P5Element.show();
  189. for (let i = 0; i < this.children.length; i++)
  190. {
  191. if (!this.children[i].show) continue;
  192. this.children[i].show();
  193. }
  194. }
  195. /**
  196. * Sets this UIObject's visibility flag to false, hides the p5.Element, and
  197. * recursively calls the hide() method on all of this GameObject's children
  198. * if they have it.
  199. */
  200. hide()
  201. {
  202. this.visible = false;
  203. this.P5Element.hide();
  204. for (let i = 0; i < this.children.length; i++)
  205. {
  206. if (!this.children[i].hide) continue;
  207. this.children[i].hide();
  208. }
  209. }
  210. /**
  211. * Adds a GameObject as a child of this UIObject, and parents the child's p5.Element
  212. * if they are a UIObject.
  213. *
  214. * @param {GameObject} child
  215. *
  216. * @override
  217. */
  218. addChild(child)
  219. {
  220. child.parent = this;
  221. child.parented = true;
  222. this.children.push(child);
  223. if (child.P5Element)
  224. child.P5Element.parent(this.P5Element);
  225. }
  226. /**
  227. * Recursively marks this GameObject's and all of its children's
  228. * memory for garbage collection. Also removes this UIObject's p5.Element.
  229. *
  230. * @override
  231. */
  232. destroy()
  233. {
  234. for (let i = 0; i < this.children.length; i++)
  235. this.children[i].destroy();
  236. if (this.P5Element)
  237. this.P5Element.remove();
  238. for (var prop in this)
  239. this[prop] = null;
  240. }
  241. /**
  242. * Defines default signals for UIObjects and serves as the caller to this UIObject's
  243. * _initSignals() callbacks.
  244. *
  245. * @signal mousePressed emited once every time a mouse button is pressed over this
  246. * UIObject.
  247. * @signal doubleClicked emited once every time a mouse button is pressed twice over
  248. * this UIObject.
  249. * @signal mouseWheel emited once everty time a mouse wheel is scrolled over this
  250. * UIObject. Passes one argument {event} that holds the deltaY
  251. * property, that holds a number based on how much was vertically
  252. * scrolled (up is positive) and the deltaX property, that holds a
  253. * number based on how much was horizontaly scrolled (right is positive).
  254. * @signal mouseReleased emited once every time a mouse button is released over this
  255. * UIObject.
  256. * @signal mouseClicked emited once every time a mouse button is pressed and released
  257. * over this UIObject.
  258. * @signal mouseMoved emited once every time a mouse moves over this UIObject.
  259. * @signal mouseOver emited once every time a mouse moves onto this UIObject.
  260. * @signal mouseOut emited once every time a mouse moves out of this UIObject.
  261. * @signal touchStarted emited once every time a touch is regiestered over this UIObject.
  262. * @signal touchMoved emited once every time a touch move is regiestered over this
  263. * UIObject.
  264. * @signal touchEnded emited once every time a touch is regiestered over this UIObject.
  265. * @signal dragOver emited once every time a file is dragged over this UIObject.
  266. * @signal dragLeave emited once every time a dragged file leaves this UIObject's area.
  267. *
  268. * @override
  269. */
  270. initSignals()
  271. {
  272. this.addSignal("mousePressed");
  273. this.addSignal("doubleClicked");
  274. this.addSignal("mouseWheel");
  275. this.addSignal("mouseReleased");
  276. this.addSignal("mouseClicked");
  277. this.addSignal("mouseMoved");
  278. this.addSignal("mouseOver");
  279. this.addSignal("mouseOut");
  280. this.addSignal("touchStarted");
  281. this.addSignal("touchMoved");
  282. this.addSignal("touchEnded");
  283. this.addSignal("dragOver");
  284. this.addSignal("dragLeave");
  285. this._initSignals();
  286. }
  287. /**
  288. * Updates this UIObject's p5.Element size, position and font size based
  289. * on the secondary buffer's size on the actual window. This gives the
  290. * impression that the HTML element is actually beeing drawn to the secondary
  291. * buffer instead of the main one.
  292. * ? is it possible to draw them directly to the secondary buffer?
  293. *
  294. * @param {number} delta number of ellapsed seconds since the last frame.
  295. * @param {p5.Graphics} db secondary buffer to draw to.
  296. *
  297. * @override
  298. */
  299. draw(delta, db)
  300. {
  301. let ar = db.screenWidth / db.width;
  302. let offsetx = (windowWidth - db.screenWidth) / 2;
  303. let offsety = (windowHeight - db.screenHeight) / 2;
  304. this.P5Element.position(offsetx + this.position.x * ar, offsety + this.position.y * ar);
  305. this.P5Element.size(this.size.x * ar, this.size.y * ar);
  306. this.setStyle(
  307. {
  308. "font-size": `${this.fontSize * ar}px`
  309. });
  310. this._draw(delta, db);
  311. for (let i = 0; i < this.children.length; i++)
  312. this.children[i].draw(delta, db);
  313. }
  314. /**
  315. * Called once every time a mouse button is pressed over this UIObject.
  316. * Connected to the mousePressed event from this UIObject's p5.Element.
  317. * Serves as an emiter to the mousePressed signal and calls the _onMousePressed()
  318. * callback.
  319. */
  320. onMousePressed()
  321. {
  322. this.pandoraObject.emitSignal("mousePressed");
  323. this.pandoraObject._onMousePressed();
  324. }
  325. /**
  326. * Called once every time a mouse button in pressed twice over this UIObject.
  327. * Connected to the doubleClicked event from this UIObject's p5.Element.
  328. * Serves as an emiter to the doubleClicked signal and calls the _onDoubleClicked()
  329. * callback.
  330. */
  331. onDoubleClicked()
  332. {
  333. this.pandoraObject.emitSignal("doubleClicked");
  334. this.pandoraObject._onDoubleClicked();
  335. }
  336. /**
  337. * Called once every time a mouse wheel is scrolled over this UIObject.
  338. * Connected to the mouseWheel event from this UIObject's p5.Element.
  339. * Serves as an emiter to the mouseWheel signal and calls the _onMouseWheel()
  340. * callback.
  341. *
  342. * @param {Object} event contains data about the wheen scroll, with the deltaY
  343. * and deltaX property, containing data about the vertical
  344. * and horizontal scrolling, repsctively.
  345. */
  346. onMouseWheel(event)
  347. {
  348. this.pandoraObject.emitSignal("mouseWheel", event);
  349. this.pandoraObject._onMouseWheel(event);
  350. }
  351. /**
  352. * Called once every time a mouse button is released over this UIObject.
  353. * Connected to the mouseReleased event from this UIObject's p5.Element.
  354. * Serves as an emiter to the mouseReleased signal and calls the _onMouseReleased()
  355. * callback.
  356. */
  357. onMouseReleased()
  358. {
  359. this.pandoraObject.emitSignal("mouseReleased");
  360. this.pandoraObject._onMouseReleased();
  361. }
  362. /**
  363. * Called once every time a mouse button is pressed and released over this UIObject.
  364. * Connected to the mouseClicked event from this UIObject's p5.Element.
  365. * Serves as an emiter to the mouseClicked signal and calls the _onMouseClicked()
  366. * callback.
  367. */
  368. onMouseClicked()
  369. {
  370. this.pandoraObject.emitSignal("mouseClicked");
  371. this.pandoraObject._onMouseClicked();
  372. }
  373. /**
  374. * Called once everty time a mouse moves over this UIObject.
  375. * Connected to the mouseMoved event from this UIObject's p5.Element.
  376. * Serves as an emiter to the mouseMoved signal and calls the _onMouseMoved()
  377. * callback.
  378. */
  379. onMouseMoved()
  380. {
  381. this.pandoraObject.emitSignal("mouseMoved");
  382. this.pandoraObject._onMouseMoved();
  383. }
  384. /**
  385. * Called once every time a mouse moves onto this UIObject.
  386. * Connected to the mouseOver event from this UIObject's p5.Element.
  387. * Serves as an emiter to the mouseOver signal and calls the _onMouseOver()
  388. * callback.
  389. */
  390. onMouseOver()
  391. {
  392. this.pandoraObject.emitSignal("mouseOver");
  393. this.pandoraObject._onMouseOver();
  394. }
  395. /**
  396. * Called once every time a mouse moves off the UIObject.
  397. * Connected to the mouseOut event from this UIObject's p5.Element.
  398. * Serves as an emiter to the mouseOut signal and calls the _onMouseOut()
  399. * callback.
  400. */
  401. onMouseOut()
  402. {
  403. this.pandoraObject.emitSignal("mouseOut");
  404. this.pandoraObject._onMouseOut();
  405. }
  406. /**
  407. * Called once every time a touch is registered over this UIObject.
  408. * Connected to the touchStarted event from this UIObject's p5.Element.
  409. * Serves as an emiter to the touchStarted signal and calls the _onTouchStarted()
  410. * callback.
  411. */
  412. onTouchStarted()
  413. {
  414. this.pandoraObject.emitSignal("touchStarted");
  415. this.pandoraObject._onTouchStarted();
  416. }
  417. /**
  418. * Called once every time a touch move is registered over this UIObject.
  419. * Connected to the touchMoved event from this UIObject's p5.Element.
  420. * Serves as an emiter to the touchMoved signal and calls the _onTouchMoved()
  421. * callback.
  422. */
  423. onTouchMoved()
  424. {
  425. this.pandoraObject.emitSignal("touchMoved");
  426. this.pandoraObject._onTouchMoved();
  427. }
  428. /**
  429. * Called once every time a touch is registered over this UIObject.
  430. * Connected to the touchEnded event from this UIObject's p5.Element.
  431. * Serves as an emiter to the touchEnded signal and calls the _onTouchEnded()
  432. * callback.
  433. */
  434. onTouchEnded()
  435. {
  436. this.pandoraObject.emitSignal("touchEnded");
  437. this.pandoraObject._onTouchEnded();
  438. }
  439. /**
  440. * Called once every time a file is dragged over this UIObject's area.
  441. * Connected to the dragOver event from this UIObject's p5.Element.
  442. * Serves as an emiter to the dragOver signal and calls the _onDragOver()
  443. * callback.
  444. */
  445. onDragOver()
  446. {
  447. this.pandoraObject.emitSignal("dragOver");
  448. this.pandoraObject._onDragOver();
  449. }
  450. /**
  451. * Called once every time a dragged file leaves tis UIObject's area.
  452. * Connected to the dragLeave event from this UIObject's p5.Element.
  453. * Serves as an emiter to the dragLeave signal and calls the _onDragLeave()
  454. * callback.
  455. */
  456. onDragLeave()
  457. {
  458. this.pandoraObject.emitSignal("dragLeave");
  459. this.pandoraObject._onDragLeave();
  460. }
  461. /**
  462. * ! This function should be overriden, it provides no default functionality.
  463. * Called once every time a mouse button is pressed over this UIObject.
  464. *
  465. * @callback
  466. */
  467. _onMousePressed()
  468. {
  469. }
  470. /**
  471. * ! This function should be overriden, it provides no default functionality.
  472. * Called once every time a mouse button in pressed twice over this UIObject.
  473. *
  474. * @callback
  475. */
  476. _onDoubleClicked()
  477. {
  478. }
  479. /**
  480. * ! This function should be overriden, it provides no default functionality.
  481. * Called once every time a mouse wheel is scrolled over this UIObject.
  482. *
  483. * @callback
  484. *
  485. * @param {Object} event contains data about the wheen scroll, with the deltaY
  486. * and deltaX property, containing data about the vertical
  487. * and horizontal scrolling, repsctively.
  488. */
  489. _onMouseWheel(event)
  490. {
  491. }
  492. /**
  493. * ! This function should be overriden, it provides no default functionality.
  494. * Called once every time a mouse button is released over this UIObject.
  495. *
  496. * @callback
  497. */
  498. _onMouseReleased()
  499. {
  500. }
  501. /**
  502. * ! This function should be overriden, it provides no default functionality.
  503. * Called once every time a mouse button is pressed and released over this UIObject.
  504. *
  505. * @callback
  506. */
  507. _onMouseClicked()
  508. {
  509. }
  510. /**
  511. * ! This function should be overriden, it provides no default functionality.
  512. * Called once everty time a mouse moves over this UIObject.
  513. *
  514. * @callback
  515. */
  516. _onMouseMoved()
  517. {
  518. }
  519. /**
  520. * ! This function should be overriden, it provides no default functionality.
  521. * Called once every time a mouse moves onto this UIObject.
  522. *
  523. * @callback
  524. */
  525. _onMouseOver()
  526. {
  527. }
  528. /**
  529. * ! This function should be overriden, it provides no default functionality.
  530. * Called once every time a mouse moves off the UIObject.
  531. *
  532. * @callback
  533. */
  534. _onMouseOut()
  535. {
  536. }
  537. /**
  538. * ! This function should be overriden, it provides no default functionality.
  539. * Called once every time a touch is registered over this UIObject.
  540. *
  541. * @callback
  542. */
  543. _onTouchStarted()
  544. {
  545. }
  546. /**
  547. * ! This function should be overriden, it provides no default functionality.
  548. * Called once every time a touch move is registered over this UIObject.
  549. *
  550. * @callback
  551. */
  552. _onTouchMoved()
  553. {
  554. }
  555. /**
  556. * ! This function should be overriden, it provides no default functionality.
  557. * Called once every time a touch is registered over this UIObject.
  558. *
  559. * @callback
  560. */
  561. _onTouchEnded()
  562. {
  563. }
  564. /**
  565. * ! This function should be overriden, it provides no default functionality.
  566. * Called once every time a file is dragged over this UIObject's area.
  567. *
  568. * @callback
  569. */
  570. _onDragOver()
  571. {
  572. }
  573. /**
  574. * ! This function should be overriden, it provides no default functionality.
  575. * Called once every time a dragged file leaves tis UIObject's area.
  576. *
  577. * @callback
  578. */
  579. _onDragLeave()
  580. {
  581. }
  582. }