UIObject.js 19 KB

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