node.nim 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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. NodeObj* = object of RootObj
  13. kind*: NodeKind
  14. type_of_node*: NodeTypes
  15. visible*: bool
  16. is_ready*: bool
  17. pausemode*: PauseMode ## Pause mode, by default is INHERIT.
  18. name*: string ## Node name.
  19. parent*: NodeRef ## Node parent.
  20. children*: seq[NodeRef] ## Node children.
  21. on_enter*: proc(self: NodeRef) ## This called when scene changed.
  22. on_exit*: proc(self: NodeRef) ## This called when exit from the scene.
  23. on_input*: proc(self: NodeRef, event: InputEvent) ## This called on user input.
  24. on_ready*: proc(self: NodeRef) ## This called when the scene changed and the `enter` was called.
  25. on_process*: proc(self: NodeRef) ## This called every frame.
  26. NodeRef* = ref NodeObj
  27. template nodepattern*(nodetype: untyped): untyped =
  28. ## This used in childs of the NodeObj.
  29. result = `nodetype`(
  30. name: name, children: @[],
  31. on_ready: proc(self: NodeRef) = discard,
  32. on_process: proc(self: NodeRef) = discard,
  33. on_input: proc(self: NodeRef, event: InputEvent) = discard,
  34. on_enter: proc(self: NodeRef) = discard,
  35. on_exit: proc(self: NodeRef) = discard,
  36. is_ready: false, pausemode: INHERIT, visible: true
  37. )
  38. result.type_of_node = NODE_TYPE_DEFAULT
  39. proc Node*(name: string = "Node"): NodeRef =
  40. ## Creates a new Node.
  41. nodepattern(NodeRef)
  42. result.kind = NODE_NODE
  43. method addChild*(self: NodeRef, child: NodeRef) {.base.} =
  44. ## Adds new child in current node.
  45. ##
  46. ## Arguments:
  47. ## - `child`: other node.
  48. self.children.add(child)
  49. child.parent = self
  50. method addChilds*(self: NodeRef, childs: varargs[NodeRef]) {.base.} =
  51. ## Adds new child in current node.
  52. ##
  53. ## Arguments:
  54. ## - `child`: other node.
  55. for node in childs:
  56. self.addChild(node)
  57. method draw*(self: NodeRef, w, h: GLfloat) {.base.} =
  58. ## Draws node.
  59. ## This used in the Window object.
  60. discard
  61. method draw2stage*(self: NodeRef, w, h: GLfloat) {.base.} =
  62. ## Draws node.
  63. ## This used in the Window object.
  64. discard
  65. method duplicate*(self: NodeRef): NodeRef {.base.} =
  66. ## Duplicates Node object and create a new Node.
  67. self.deepCopy()
  68. method getChild*(self: NodeRef, index: int): NodeRef {.base.} =
  69. ## Returns child at `index` position, if available.
  70. ##
  71. ## Arguments:
  72. ## - `index`: child index.
  73. self.children[index]
  74. method getChildCount*(self: NodeRef): int {.base, inline.} =
  75. ## Returns child count.
  76. self.children.len()
  77. method getChildIndex*(self: NodeRef, name: string): int {.base.} =
  78. ## Returns `child` index or -1, if another node is not the child.
  79. var i = 0
  80. for node in self.children:
  81. if node.name == name:
  82. return i
  83. inc i
  84. return -1
  85. method getChildIndex*(self: NodeRef, child: NodeRef): int {.base.} =
  86. ## Returns `child` index or -1, if another node is not the child.
  87. var i = 0
  88. for node in self.children:
  89. if child == node:
  90. return i
  91. inc i
  92. return -1
  93. method getChildIter*(self: NodeRef): seq[NodeRef] {.base.} =
  94. ## Returns all children iter.
  95. result = @[]
  96. for child in self.children:
  97. if child notin result:
  98. result.add(child)
  99. if child.children.len() > 0:
  100. for node in child.getChildIter():
  101. if node notin result:
  102. result.add(node)
  103. method getNode*(self: NodeRef, path: string): NodeRef {.base.} =
  104. ## Returns child by `path`
  105. var
  106. p = path.split("/")
  107. current: NodeRef = self
  108. for name in p:
  109. if current == nil:
  110. break
  111. case name
  112. of "..":
  113. current = current.parent
  114. of "":
  115. continue
  116. else:
  117. for child in current.children:
  118. if child.name == name:
  119. current = child
  120. break
  121. return current
  122. method getPath*(self: NodeRef): string {.base.} =
  123. ## Returns node path.
  124. var current = self
  125. result = current.name
  126. while current.parent != nil:
  127. current = current.parent
  128. result = current.name & "/" & result
  129. method getParent*(self: NodeRef): NodeRef {.base.} =
  130. ## Returns node parent.
  131. self.parent
  132. method getPauseMode*(self: NodeRef): PauseMode {.base.} =
  133. ## Calculates pause mode
  134. result = self.pausemode
  135. var current = self
  136. while result == INHERIT and current.parent != nil:
  137. current = current.parent
  138. result = current.pausemode
  139. method getRootNode*(self: NodeRef): NodeRef {.base.} =
  140. ## Gets root node.
  141. result = self
  142. while result.parent != nil:
  143. result = result.parent
  144. method isParentOf*(self, other: NodeRef): bool {.base, inline.} =
  145. other in self.children
  146. method handle*(self: NodeRef, event: InputEvent, mouse_on: var NodeRef) {.base.} =
  147. ## Handles user input.
  148. ## This used in the Window object.
  149. discard
  150. method hasNode*(self: NodeRef, name: string): bool {.base.} =
  151. ## Returns true, if a node with name `name` in children.
  152. ##
  153. ## Arguments:
  154. ## - `name`: node name.
  155. self.getChildIndex(name) != -1
  156. method hasNode*(self: NodeRef, other: NodeRef): bool {.base.} =
  157. ## Returns true, if `other` in self children.
  158. ##
  159. ## Arguments:
  160. ## - `other`: other node.
  161. self.getChildIndex(other) != -1
  162. method hasParent*(self: NodeRef): bool {.base, inline.} =
  163. ## Returns true, when node has parent.
  164. self.parent != nil
  165. method hide*(self: NodeRef) {.base.} =
  166. self.visible = false
  167. method rename*(self: NodeRef, new_name: string) {.base.} =
  168. self.name = new_name
  169. method removeChild*(self: NodeRef, index: int) {.base.} =
  170. ## Removes node child at a specific position.
  171. ##
  172. ## Arguments:
  173. ## - `index`: child index.
  174. self.children[index].parent = nil
  175. self.children.delete(index)
  176. method removeChild*(self: NodeRef, other: NodeRef) {.base.} =
  177. ## Removes another node from `self`, if `other` in `self` children.
  178. ##
  179. ## Arguments:
  180. ## - `other`: other node.
  181. var index: int = self.getChildIndex(other)
  182. if index != -1:
  183. self.removeChild(index)
  184. method show*(self: NodeRef) {.base.} =
  185. self.visible = true
  186. method delete*(self: NodeRef) {.base.} =
  187. ## Deletes current node.
  188. if self.parent != nil:
  189. self.parent.removeChild(self)
  190. # --- Macros --- #
  191. import
  192. macros
  193. macro `@`*(node: NodeRef, event_name, code: untyped): untyped =
  194. ## It provides a convenient wrapper for the event handler.
  195. ##
  196. ## Arguments:
  197. ## - `node` is an any node pointer.
  198. ## - `event_name` is an event name, e.g.: process.
  199. ## - `code` is the proc code.
  200. ##
  201. ## ## Examples
  202. ## .. code-block:: nim
  203. ##
  204. ## var
  205. ## smth_node = Node("Simple node")
  206. ##
  207. ## smth_node@ready:
  208. ## echo "node is ready!"
  209. ##
  210. ## smth_node@input(event):
  211. ## if event.isInputEventMouseButton():
  212. ## echo event
  213. var ename: string
  214. # Gets event name.
  215. if event_name.kind == nnkIdent:
  216. ename = $event_name
  217. elif event_name.kind == nnkCall:
  218. ename = $event_name[0]
  219. case ename
  220. of "on_process", "on_ready", "on_enter", "on_exit":
  221. var
  222. name = event_name[0]
  223. self = event_name[1]
  224. result = quote do:
  225. `node`.`name` =
  226. proc(`self`: NodeRef): void =
  227. `code`
  228. of "on_focus", "on_unfocus":
  229. var
  230. name = event_name[0]
  231. self = event_name[1]
  232. result = quote do:
  233. `node`.`name` =
  234. proc(`self`: ControlRef): void =
  235. `code`
  236. of "on_touch":
  237. var
  238. name = event_name[0]
  239. self = event_name[1]
  240. x = event_name[2]
  241. y = event_name[3]
  242. result = quote do:
  243. `node`.`name` =
  244. proc(`self`: ButtonRef, `x`, `y`: float) =
  245. `code`
  246. of "on_mouse_exit", "on_mouse_enter", "on_click", "on_release", "on_press":
  247. var
  248. name = event_name[0]
  249. self = event_name[1]
  250. x = event_name[2]
  251. y = event_name[3]
  252. result = quote do:
  253. `node`.`name` =
  254. proc(`self`: ControlRef, `x`, `y`: float) =
  255. `code`
  256. of "on_input":
  257. var
  258. name = event_name[0]
  259. self = event_name[1]
  260. arg = event_name[2]
  261. result = quote do:
  262. `node`.`name` =
  263. proc(`self`: NodeRef, `arg`: InputEvent) =
  264. `code`
  265. of "on_toggle":
  266. var
  267. name = event_name[0]
  268. self = event_name[1]
  269. arg = event_name[2]
  270. result = quote do:
  271. `node`.`name` =
  272. proc(`self`: SwitchRef, `arg`: bool) =
  273. `code`
  274. of "on_changed":
  275. var
  276. name = event_name[0]
  277. self = event_name[1]
  278. arg = event_name[2]
  279. result = quote do:
  280. `node`.`name` =
  281. proc(`self`: SliderRef, `arg`: uint) =
  282. `code`
  283. else:
  284. discard