UIObject.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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.drawChildren(delta, db);
  311. }
  312. /**
  313. * Called once every time a mouse button is pressed over this UIObject.
  314. * Connected to the mousePressed event from this UIObject's p5.Element.
  315. * Serves as an emiter to the mousePressed signal and calls the _onMousePressed()
  316. * callback.
  317. */
  318. onMousePressed()
  319. {
  320. this.pandoraObject.emitSignal("mousePressed");
  321. this.pandoraObject._onMousePressed();
  322. }
  323. /**
  324. * Called once every time a mouse button in pressed twice over this UIObject.
  325. * Connected to the doubleClicked event from this UIObject's p5.Element.
  326. * Serves as an emiter to the doubleClicked signal and calls the _onDoubleClicked()
  327. * callback.
  328. */
  329. onDoubleClicked()
  330. {
  331. this.pandoraObject.emitSignal("doubleClicked");
  332. this.pandoraObject._onDoubleClicked();
  333. }
  334. /**
  335. * Called once every time a mouse wheel is scrolled over this UIObject.
  336. * Connected to the mouseWheel event from this UIObject's p5.Element.
  337. * Serves as an emiter to the mouseWheel signal and calls the _onMouseWheel()
  338. * callback.
  339. *
  340. * @param {Object} event contains data about the wheen scroll, with the deltaY
  341. * and deltaX property, containing data about the vertical
  342. * and horizontal scrolling, repsctively.
  343. */
  344. onMouseWheel(event)
  345. {
  346. this.pandoraObject.emitSignal("mouseWheel", event);
  347. this.pandoraObject._onMouseWheel(event);
  348. }
  349. /**
  350. * Called once every time a mouse button is released over this UIObject.
  351. * Connected to the mouseReleased event from this UIObject's p5.Element.
  352. * Serves as an emiter to the mouseReleased signal and calls the _onMouseReleased()
  353. * callback.
  354. */
  355. onMouseReleased()
  356. {
  357. this.pandoraObject.emitSignal("mouseReleased");
  358. this.pandoraObject._onMouseReleased();
  359. }
  360. /**
  361. * Called once every time a mouse button is pressed and released over this UIObject.
  362. * Connected to the mouseClicked event from this UIObject's p5.Element.
  363. * Serves as an emiter to the mouseClicked signal and calls the _onMouseClicked()
  364. * callback.
  365. */
  366. onMouseClicked()
  367. {
  368. this.pandoraObject.emitSignal("mouseClicked");
  369. this.pandoraObject._onMouseClicked();
  370. }
  371. /**
  372. * Called once everty time a mouse moves over this UIObject.
  373. * Connected to the mouseMoved event from this UIObject's p5.Element.
  374. * Serves as an emiter to the mouseMoved signal and calls the _onMouseMoved()
  375. * callback.
  376. */
  377. onMouseMoved()
  378. {
  379. this.pandoraObject.emitSignal("mouseMoved");
  380. this.pandoraObject._onMouseMoved();
  381. }
  382. /**
  383. * Called once every time a mouse moves onto this UIObject.
  384. * Connected to the mouseOver event from this UIObject's p5.Element.
  385. * Serves as an emiter to the mouseOver signal and calls the _onMouseOver()
  386. * callback.
  387. */
  388. onMouseOver()
  389. {
  390. this.pandoraObject.emitSignal("mouseOver");
  391. this.pandoraObject._onMouseOver();
  392. }
  393. /**
  394. * Called once every time a mouse moves off the UIObject.
  395. * Connected to the mouseOut event from this UIObject's p5.Element.
  396. * Serves as an emiter to the mouseOut signal and calls the _onMouseOut()
  397. * callback.
  398. */
  399. onMouseOut()
  400. {
  401. this.pandoraObject.emitSignal("mouseOut");
  402. this.pandoraObject._onMouseOut();
  403. }
  404. /**
  405. * Called once every time a touch is registered over this UIObject.
  406. * Connected to the touchStarted event from this UIObject's p5.Element.
  407. * Serves as an emiter to the touchStarted signal and calls the _onTouchStarted()
  408. * callback.
  409. */
  410. onTouchStarted()
  411. {
  412. this.pandoraObject.emitSignal("touchStarted");
  413. this.pandoraObject._onTouchStarted();
  414. }
  415. /**
  416. * Called once every time a touch move is registered over this UIObject.
  417. * Connected to the touchMoved event from this UIObject's p5.Element.
  418. * Serves as an emiter to the touchMoved signal and calls the _onTouchMoved()
  419. * callback.
  420. */
  421. onTouchMoved()
  422. {
  423. this.pandoraObject.emitSignal("touchMoved");
  424. this.pandoraObject._onTouchMoved();
  425. }
  426. /**
  427. * Called once every time a touch is registered over this UIObject.
  428. * Connected to the touchEnded event from this UIObject's p5.Element.
  429. * Serves as an emiter to the touchEnded signal and calls the _onTouchEnded()
  430. * callback.
  431. */
  432. onTouchEnded()
  433. {
  434. this.pandoraObject.emitSignal("touchEnded");
  435. this.pandoraObject._onTouchEnded();
  436. }
  437. /**
  438. * Called once every time a file is dragged over this UIObject's area.
  439. * Connected to the dragOver event from this UIObject's p5.Element.
  440. * Serves as an emiter to the dragOver signal and calls the _onDragOver()
  441. * callback.
  442. */
  443. onDragOver()
  444. {
  445. this.pandoraObject.emitSignal("dragOver");
  446. this.pandoraObject._onDragOver();
  447. }
  448. /**
  449. * Called once every time a dragged file leaves tis UIObject's area.
  450. * Connected to the dragLeave event from this UIObject's p5.Element.
  451. * Serves as an emiter to the dragLeave signal and calls the _onDragLeave()
  452. * callback.
  453. */
  454. onDragLeave()
  455. {
  456. this.pandoraObject.emitSignal("dragLeave");
  457. this.pandoraObject._onDragLeave();
  458. }
  459. /**
  460. * ! This function should be overriden, it provides no default functionality.
  461. * Called once every time a mouse button is pressed over this UIObject.
  462. *
  463. * @callback
  464. */
  465. _onMousePressed()
  466. {
  467. }
  468. /**
  469. * ! This function should be overriden, it provides no default functionality.
  470. * Called once every time a mouse button in pressed twice over this UIObject.
  471. *
  472. * @callback
  473. */
  474. _onDoubleClicked()
  475. {
  476. }
  477. /**
  478. * ! This function should be overriden, it provides no default functionality.
  479. * Called once every time a mouse wheel is scrolled over this UIObject.
  480. *
  481. * @callback
  482. *
  483. * @param {Object} event contains data about the wheen scroll, with the deltaY
  484. * and deltaX property, containing data about the vertical
  485. * and horizontal scrolling, repsctively.
  486. */
  487. _onMouseWheel(event)
  488. {
  489. }
  490. /**
  491. * ! This function should be overriden, it provides no default functionality.
  492. * Called once every time a mouse button is released over this UIObject.
  493. *
  494. * @callback
  495. */
  496. _onMouseReleased()
  497. {
  498. }
  499. /**
  500. * ! This function should be overriden, it provides no default functionality.
  501. * Called once every time a mouse button is pressed and released over this UIObject.
  502. *
  503. * @callback
  504. */
  505. _onMouseClicked()
  506. {
  507. }
  508. /**
  509. * ! This function should be overriden, it provides no default functionality.
  510. * Called once everty time a mouse moves over this UIObject.
  511. *
  512. * @callback
  513. */
  514. _onMouseMoved()
  515. {
  516. }
  517. /**
  518. * ! This function should be overriden, it provides no default functionality.
  519. * Called once every time a mouse moves onto this UIObject.
  520. *
  521. * @callback
  522. */
  523. _onMouseOver()
  524. {
  525. }
  526. /**
  527. * ! This function should be overriden, it provides no default functionality.
  528. * Called once every time a mouse moves off the UIObject.
  529. *
  530. * @callback
  531. */
  532. _onMouseOut()
  533. {
  534. }
  535. /**
  536. * ! This function should be overriden, it provides no default functionality.
  537. * Called once every time a touch is registered over this UIObject.
  538. *
  539. * @callback
  540. */
  541. _onTouchStarted()
  542. {
  543. }
  544. /**
  545. * ! This function should be overriden, it provides no default functionality.
  546. * Called once every time a touch move is registered over this UIObject.
  547. *
  548. * @callback
  549. */
  550. _onTouchMoved()
  551. {
  552. }
  553. /**
  554. * ! This function should be overriden, it provides no default functionality.
  555. * Called once every time a touch is registered over this UIObject.
  556. *
  557. * @callback
  558. */
  559. _onTouchEnded()
  560. {
  561. }
  562. /**
  563. * ! This function should be overriden, it provides no default functionality.
  564. * Called once every time a file is dragged over this UIObject's area.
  565. *
  566. * @callback
  567. */
  568. _onDragOver()
  569. {
  570. }
  571. /**
  572. * ! This function should be overriden, it provides no default functionality.
  573. * Called once every time a dragged file leaves tis UIObject's area.
  574. *
  575. * @callback
  576. */
  577. _onDragLeave()
  578. {
  579. }
  580. }