node.nim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. # author: Ethosa
  2. ## Node is the root type of all other nodes.
  3. import
  4. strutils,
  5. ../thirdparty/opengl,
  6. ../core/vector2,
  7. ../core/enums,
  8. ../core/anchor,
  9. ../core/input
  10. {.used.}
  11. type
  12. NodeHandler* = proc(self: NodeRef)
  13. NodeEvHandler* = proc(self: NodeRef, event: InputEvent)
  14. NodeObj* = object of RootObj
  15. kind*: NodeKind
  16. type_of_node*: NodeTypes ## default, gui, 2d or 3d.
  17. visibility*: Visibility ## visible, invisible or gone.
  18. is_ready*: bool ## true, when scene is ready.
  19. pausemode*: PauseMode ## Pause mode, by default is INHERIT.
  20. name*: string ## Node name.
  21. parent*: NodeRef ## Node parent.
  22. children*: seq[NodeRef] ## Node children.
  23. on_enter*: NodeHandler ## This called when scene changed.
  24. on_exit*: NodeHandler ## This called when exit from the scene.
  25. on_input*: NodeEvHandler ## This called on user input.
  26. on_ready*: NodeHandler ## This called when the scene changed and the `enter` was called.
  27. on_process*: NodeHandler ## This called every frame.
  28. NodeRef* = ref NodeObj
  29. var
  30. handler_default = proc(self: NodeRef) = discard
  31. event_handler_default = proc(self: NodeRef, event: InputEvent) = discard
  32. template nodepattern*(nodetype: untyped): untyped =
  33. ## This used in childs of the NodeObj.
  34. result = `nodetype`(
  35. name: name, children: @[],
  36. on_ready: handler_default,
  37. on_process: handler_default,
  38. on_input: event_handler_default,
  39. on_enter: handler_default,
  40. on_exit: handler_default,
  41. is_ready: false, pausemode: INHERIT, visibility: VISIBLE
  42. )
  43. result.type_of_node = NODE_TYPE_DEFAULT
  44. proc Node*(name: string = "Node"): NodeRef =
  45. ## Creates a new Node.
  46. nodepattern(NodeRef)
  47. result.kind = NODE_NODE
  48. method addChild*(self: NodeRef, child: NodeRef) {.base.} =
  49. ## Adds new child in current node.
  50. ##
  51. ## Arguments:
  52. ## - `child`: other node.
  53. ##
  54. ## See also:
  55. ## - `addChildren method <#addChildren.e,NodeRef,varargs[NodeRef]>`_
  56. ## - `getChild method <#getChild.e,NodeRef,int>`_
  57. self.children.add(child)
  58. child.parent = self
  59. method addChildren*(self: NodeRef, childs: varargs[NodeRef]) {.base.} =
  60. ## Adds new child in current node.
  61. ##
  62. ## Arguments:
  63. ## - `child`: other node.
  64. ##
  65. ## See also:
  66. ## - `addChild method <#addChild.e,NodeRef,NodeRef>`_
  67. for node in childs:
  68. self.addChild(node)
  69. method draw*(self: NodeRef, w, h: GLfloat) {.base.} =
  70. ## Draws node.
  71. ## This used in the Window object.
  72. discard
  73. method duplicate*(self: NodeRef): NodeRef {.base.} =
  74. ## Duplicates Node object and create a new Node.
  75. self.deepCopy()
  76. method getChild*(self: NodeRef, index: int): NodeRef {.base.} =
  77. ## Returns child at `index` position, if available.
  78. ##
  79. ## Arguments:
  80. ## - `index`: child index.
  81. ##
  82. ## See also:
  83. ## - `addChild method <#addChild.e,NodeRef,NodeRef>`_
  84. ## - `getChildCount method <#getChildCount.e,NodeRef>`_
  85. self.children[index]
  86. method getChildCount*(self: NodeRef): int {.base, inline.} =
  87. ## Returns child count.
  88. ##
  89. ## See also:
  90. ## - `getChild method <#getChild.e,NodeRef,int>`_
  91. self.children.len()
  92. method getChildIndex*(self: NodeRef, name: string): int {.base.} =
  93. ## Returns `child` index or -1, if another node is not the child.
  94. ##
  95. ## See also:
  96. ## - `getChildIndex method <#getChildIndex.e,NodeRef,NodeRef>`_
  97. var i = 0
  98. for node in self.children:
  99. if node.name == name:
  100. return i
  101. inc i
  102. -1
  103. method getChildIndex*(self: NodeRef, child: NodeRef): int {.base.} =
  104. ## Returns `child` index or -1, if another node is not the child.
  105. ##
  106. ## See also:
  107. ## - `getChildIndex method <#getChildIndex.e,NodeRef,string>`_
  108. var i = 0
  109. for node in self.children:
  110. if child == node:
  111. return i
  112. inc i
  113. -1
  114. method getChildIter*(self: NodeRef): seq[NodeRef] {.base.} =
  115. ## Returns all children iter.
  116. result = @[]
  117. for child in self.children:
  118. if child notin result:
  119. result.add(child)
  120. if child.children.len() > 0:
  121. for node in child.getChildIter():
  122. if node notin result:
  123. result.add(node)
  124. method getNode*(self: NodeRef, path: string): NodeRef {.base.} =
  125. ## Returns child by `path`
  126. var
  127. p = path.split("/")
  128. current: NodeRef = self
  129. for name in p:
  130. if current == nil:
  131. break
  132. case name
  133. of "..":
  134. current = current.parent
  135. of "":
  136. continue
  137. else:
  138. for child in current.children:
  139. if child.name == name:
  140. current = child
  141. break
  142. return current
  143. method getPath*(self: NodeRef): string {.base.} =
  144. ## Returns node path.
  145. var current = self
  146. result = current.name
  147. while current.parent != nil:
  148. current = current.parent
  149. result = current.name & "/" & result
  150. method getParent*(self: NodeRef): NodeRef {.base.} =
  151. ## Returns node parent.
  152. self.parent
  153. method getPauseMode*(self: NodeRef): PauseMode {.base.} =
  154. ## Calculates pause mode
  155. result = self.pausemode
  156. var current = self
  157. while result == INHERIT and current.parent != nil:
  158. current = current.parent
  159. result = current.pausemode
  160. method getRootNode*(self: NodeRef): NodeRef {.base.} =
  161. ## Gets root node.
  162. result = self
  163. while result.parent != nil:
  164. result = result.parent
  165. method isParentOf*(self, other: NodeRef): bool {.base, inline.} =
  166. other in self.children
  167. method handle*(self: NodeRef, event: InputEvent, mouse_on: var NodeRef) {.base.} =
  168. ## Handles user input.
  169. ## This used in the Window object.
  170. discard
  171. method hasNode*(self: NodeRef, name: string): bool {.base, inline.} =
  172. ## Returns true, if a node with name `name` in children.
  173. ##
  174. ## Arguments:
  175. ## - `name`: node name.
  176. self.getChildIndex(name) != -1
  177. method hasNode*(self: NodeRef, other: NodeRef): bool {.base, inline.} =
  178. ## Returns true, if `other` in self children.
  179. ##
  180. ## Arguments:
  181. ## - `other`: other node.
  182. self.getChildIndex(other) != -1
  183. method hasParent*(self: NodeRef): bool {.base, inline.} =
  184. ## Returns true, when node has parent.
  185. not self.parent.isNil()
  186. method hide*(self: NodeRef) {.base.} =
  187. self.visibility = INVISIBLE
  188. method postdraw*(self: NodeRef, w, h: GLfloat) {.base.} =
  189. ## Draws node.
  190. ## This used in the Window object.
  191. discard
  192. method rename*(self: NodeRef, new_name: string) {.base.} =
  193. self.name = new_name
  194. method removeChild*(self: NodeRef, index: int) {.base.} =
  195. ## Removes node child at a specific position.
  196. ##
  197. ## Arguments:
  198. ## - `index`: child index.
  199. ##
  200. ## See also:
  201. ## - `addChild method <#addChild.e,NodeRef,NodeRef>`_
  202. self.children[index].parent = nil
  203. self.children.delete(index)
  204. method removeChild*(self: NodeRef, other: NodeRef) {.base.} =
  205. ## Removes another node from `self`, if `other` in `self` children.
  206. ##
  207. ## Arguments:
  208. ## - `other`: other node.
  209. let index: int = self.getChildIndex(other)
  210. if index != -1:
  211. self.removeChild(index)
  212. method show*(self: NodeRef) {.base.} =
  213. self.visibility = VISIBLE
  214. method delete*(self: NodeRef) {.base.} =
  215. ## Deletes current node.
  216. if self.parent != nil:
  217. self.parent.removeChild(self)
  218. # --- Macros --- #
  219. import
  220. macros
  221. macro expectParams(params_src: NimNode, params: static[seq[string]]): untyped =
  222. ## Gets values from the NimNode params_src which comes after the `@` when using the `@` macro.
  223. ## Also checks that the number of parameters lines up
  224. ## Arguments:
  225. ## - `params_src` The node that contains the parameters
  226. ## - `params` List of param variables to get from params_src
  227. result = newStmtList()
  228. result.add quote do:
  229. # This is done so params is only injected once
  230. let params = `params`
  231. let src_length = `params_src`.len - 1 # - 1 for name
  232. if src_length != params.len:
  233. # Tell the user that there was an unexpected number of params
  234. let error_msg = block:
  235. "Expected " & $params.len & " parameters (" & params.join(", ") & ") but got " & $src_length
  236. error_msg.error(`params_src`)
  237. # Convert all the passed parameters into variables with corresponding
  238. # value from the parameters source
  239. for i, param in params:
  240. let varName = ident param
  241. result.add quote do:
  242. var `varName` = `params_src`[`i` + 1] # + 1 since name is at the 0 index
  243. when not declared(nimIdentNormalize):
  244. proc nimIdentNormalize(s: string): string =
  245. ## Backported from https://github.com/nim-lang/Nim/blob/version-1-4/lib/pure/strutils.nim#L284
  246. result = newString(s.len)
  247. if s.len > 0:
  248. result[0] = s[0]
  249. var j = 1
  250. for i in 1..len(s) - 1:
  251. if s[i] in {'A'..'Z'}:
  252. result[j] = chr(ord(s[i]) + (ord('a') - ord('A')))
  253. inc j
  254. elif s[i] != '_':
  255. result[j] = s[i]
  256. inc j
  257. if j != s.len: setLen(result, j)
  258. macro `@`*(node: NodeRef, event_name, code: untyped): untyped =
  259. ## It provides a convenient wrapper for the event handler.
  260. ##
  261. ## Arguments:
  262. ## - `node` is an any node pointer.
  263. ## - `event_name` is an event name, e.g.: process.
  264. ## - `code` is the proc code.
  265. ##
  266. ## ## Examples
  267. ## .. code-block:: nim
  268. ##
  269. ## var
  270. ## smth_node = Node("Simple node")
  271. ##
  272. ## smth_node@on_ready(self):
  273. ## echo "node is ready!"
  274. ##
  275. ## smth_node@on_input(self, event):
  276. ## if event.isInputEventMouseButton():
  277. ## echo event
  278. var ename: string
  279. # Gets event name.
  280. # TODO, event_name[0] is used in all the case block so add a better error message for when it isn't called this way
  281. if event_name.kind == nnkIdent:
  282. ename = $event_name
  283. elif event_name.kind == nnkCall:
  284. ename = $event_name[0]
  285. # Do style insensitive comparision
  286. case nimIdentNormalize(ename)
  287. of "onprocess", "onready", "onenter", "onexit":
  288. var name = event_name[0]
  289. event_name.expectParams(@["self"])
  290. result = quote do:
  291. `node`.`name` =
  292. proc(`self`: NodeRef): void =
  293. `code`
  294. of "onfocus", "onunfocus":
  295. var name = event_name[0]
  296. event_name.expectParams(@["self"])
  297. result = quote do:
  298. `node`.`name` =
  299. proc(`self`: ControlRef): void =
  300. `code`
  301. of "ontouch":
  302. var name = event_name[0]
  303. event_name.expectParams(@["self", "x", "y"])
  304. result = quote do:
  305. `node`.`name` =
  306. proc(`self`: ButtonRef, `x`, `y`: float) =
  307. `code`
  308. of "onmouseexit", "onmouseenter", "onclick", "onrelease", "onpress":
  309. var name = event_name[0]
  310. event_name.expectParams(@["self", "x", "y"])
  311. result = quote do:
  312. `node`.`name` =
  313. proc(`self`: ControlRef, `x`, `y`: float) =
  314. `code`
  315. of "oninput":
  316. var name = event_name[0]
  317. event_name.expectParams(@["self", "arg"])
  318. result = quote do:
  319. `node`.`name` =
  320. proc(`self`: NodeRef, `arg`: InputEvent) =
  321. `code`
  322. of "onswitch":
  323. var name = event_name[0]
  324. event_name.expectParams(@["self", "arg"])
  325. result = quote do:
  326. `node`.`name` =
  327. proc(`self`: SwitchRef, `arg`: bool) =
  328. `code`
  329. of "ontoggle":
  330. var name = event_name[0]
  331. event_name.expectParams(@["self", "arg"])
  332. result = quote do:
  333. `node`.`name` =
  334. proc(`self`: CheckBoxRef, `arg`: bool) =
  335. `code`
  336. of "onchanged":
  337. var name = event_name[0]
  338. event_name.expectParams(@["self", "arg"])
  339. result = quote do:
  340. `node`.`name` =
  341. proc(`self`: SliderRef, `arg`: uint) =
  342. `code`
  343. of "onedit":
  344. var name = event_name[0]
  345. event_name.expectParams(@["self", "arg"])
  346. result = quote do:
  347. `node`.`name` =
  348. proc(`self`: EditTextRef, `arg`: string) =
  349. `code`
  350. else:
  351. error("Invalid event: " & ename, node)