Browse Source

upgrade `builder` macro :eyes:

Ethosa 3 years ago
parent
commit
ca9b6a79a9

+ 12 - 0
.github/FUNDING.yml

@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: Ethosa
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

+ 1 - 1
.github/workflows/test.yml

@@ -57,7 +57,7 @@ jobs:
       - name: Build examples
         run: |
           cd examples
-          for dir in hello_world calculator novel snake screensaver roguelike; do
+          for dir in hello_world calculator novel snake screensaver roguelike builder_features; do
             (
               cd "$dir"
               nim c main.nim

+ 41 - 0
examples/builder_features/main.nim

@@ -0,0 +1,41 @@
+# author: Ethosa
+import nodesnim
+
+
+Window("SceneBuilder")
+
+
+build:
+  # Create node.
+  # var main = Scene(name = "main")
+  - Scene main:
+    # Create node with params.
+    # var rect = ColorRect(name = "rect")
+    # rect.color = Color(0.6, 0.5, 1)
+    - ColorRect rect(color: Color(0.6, 0.5, 1)):
+      # handle Mouse press event.
+      # rect.on_press = proc(self: NodeRef, x, y: float) =
+      @onPress(x, y):
+        rect.color.r -= 0.01
+      # handle Mouse release event.
+      # rect.on_release = proc(self: NodeRef, x, y: float) =
+      @onRelease(x, y):
+        rect.color.r = 0.6
+
+    # Create a new Label with params.
+    # var hw = Label(name = "hw")
+    # hw.anchor = Anchor(0.5, 0.5, 0.5, 0.5)
+    - Label hw(anchor: Anchor(0.5, 0.5, 0.5, 0.5)):
+      # Call Label method:
+      # hw.setText("Hello, world!")
+      call setText("Hello, world!")
+
+    # Repeating nodes can be written briefly:
+    - Node node0(is_ready: true, call hide())
+    - Node2D node1(is_ready: true, call hide())
+    - Node3D node2(is_ready: true, call hide())
+    - Control node3(is_ready: true, call hide())
+
+
+addMainScene(main)
+windowLaunch()

+ 1 - 0
examples/builder_features/nim.cfg

@@ -0,0 +1 @@
+--path:"../../src"

+ 1 - 0
examples/builder_features/readme.md

@@ -0,0 +1 @@
+# SceneBuilder features

+ 2 - 0
examples/readme.md

@@ -20,3 +20,5 @@
 
 ## [Sample messenger](https://github.com/Ethosa/nodesnim/blob/master/examples/sample_messenger)
 ![Sample messenger](https://github.com/Ethosa/nodesnim/blob/nightly/screenshots/7.png)
+
+## [Builder features](https://github.com/Ethosa/nodesnim/blob/master/examples/builder_features)

+ 54 - 23
src/nodesnim/core/scene_builder.nim

@@ -4,47 +4,77 @@ import
 
 proc addNode(level: var seq[NimNode], code: NimNode): NimNode {.compileTime.} =
   result = newStmtList()
-  if code.kind in [nnkStmtList, nnkObjConstr]:
+  if code.kind in [nnkStmtList, nnkObjConstr, nnkCall]:
     for line in code.children():
       if line.kind == nnkPrefix:
         if line[0].kind == nnkIdent and line[1].kind == nnkCommand:
+          # - Node name:
           if $line[0] == "-":
-            if line[1][1].kind == nnkIdent:
+            case line[1][1].kind
+            of nnkIdent:  # - Node name:
               result.add(newVarStmt(line[1][1], newCall($line[1][0], newStrLitNode($line[1][1]))))
-            elif line[1][1].kind == nnkObjConstr:
+            of nnkObjConstr:  # - Node name(a: .., b: ...)
               result.add(newVarStmt(line[1][1][0], newCall($line[1][0], newStrLitNode($line[1][1][0]))))
-            elif line[1][1].kind == nnkPar:
+            of nnkPar:  # Node (name):
               result.add(newVarStmt(postfix(line[1][1][0], "*"), newCall($line[1][0], newStrLitNode($line[1][1][0]))))
+            of nnkCall:  # Node name(call smth()):
+              result.add(newVarStmt(line[1][1][0], newCall($line[1][0], newStrLitNode($line[1][1][0]))))
+            else:
+              discard
+
             if level.len() > 0:
-              # - Scene main_scene:
-              if line[1][1].kind == nnkIdent:
+              case line[1][1].kind:
+              of nnkIdent:
                 result.add(newCall("addChild", level[^1], line[1][1]))
-              elif line[1][1].kind == nnkPar:
+              of nnkPar, nnkObjConstr, nnkCall:
                 result.add(newCall("addChild", level[^1], line[1][1][0]))
-              elif line[1][1].kind == nnkObjConstr:
-                result.add(newCall("addChild", level[^1], line[1][1][0]))
-                level.add(line[1][1][0])
-                var nodes = addNode(level, line[1][1])
-                for i in nodes.children():
-                  result.add(i)
-      # call methodName(arg1, arg2) -> currentNode.methodName(arg1, arg2)
-      elif line.kind == nnkCommand and $line[0] == "call" and level.len() > 0:
+              else:
+                discard
+
+            if line[1][1].kind == nnkObjConstr:  # - Node node(...)
+              level.add(line[1][1][0])
+              let nodes = addNode(level, line[1][1])
+              for i in nodes.children():
+                result.add(i)
+      # call  hodName(arg1, arg2) -> currentNode.methodName(arg1, arg2)
+      elif line.kind == nnkCommand and $line[0] == "call" and level.len > 0:
         line[1].insert(1, level[^1])
         result.add(line[1])
+      # @onProcess() -> parent@onProcess(self)
+      # @onPress(x, y) -> parent@onPress(self, x, y)
+      elif line.kind == nnkCall and line[0].kind == nnkPrefix and level.len > 0:
+        if $line[0][0] == "@":
+          var tmp = newCall(line[0][1], ident"self")
+          for arg in 1..line.len-2:
+            tmp.add(line[arg])
+          result.add(newCall("@", level[^1], tmp, line[^1]))
       # property: value -> currentNode.property = value
-      elif line.kind in [nnkCall, nnkExprColonExpr] and level.len() > 0:
-        var attr = newNimNode(nnkAsgn)
+      elif line.kind in [nnkCall, nnkExprColonExpr] and level.len > 0:
+        let attr = newNimNode(nnkAsgn)
         attr.add(newNimNode(nnkDotExpr))
         attr[0].add(level[^1])
         attr[0].add(line[0])
         attr.add(line[1])
         result.add(attr)
-      if len(line) == 3 and line[2].kind == nnkStmtList and line[1].kind == nnkCommand:
-        level.add(line[1][1])
-        var nodes = addNode(level, line[2])
+
+      if line.len == 3 and line[2].kind == nnkStmtList and line[1].kind == nnkCommand:
+        case line[1][1].kind
+        of nnkIdent:
+          level.add(line[1][1])
+        of nnkObjConstr:
+          level.add(line[1][1][0])
+        else:
+          discard
+        let nodes = addNode(level, line[2])
+        for i in nodes.children():
+          result.add(i)
+
+      elif line.len == 2 and line[1].kind == nnkCommand and line[1][1].kind == nnkCall:
+        level.add(line[1][1][0])
+        let nodes = addNode(level, line[1][1])
         for i in nodes.children():
           result.add(i)
-    if level.len() > 0:
+    if level.len > 0:
       discard level.pop()
 
 
@@ -56,9 +86,10 @@ macro build*(code: untyped): untyped =
   ##
   ##   build:
   ##     - Scene scene:
-  ##       Node test_node
-  ##       Label text:
+  ##       - Node test_node
+  ##       - Label text:
   ##         call setText("Hello, world!")
+  ##       - Button btn(call setText(""))
   result = newStmtList()
   var
     current_level: seq[NimNode] = @[]

+ 4 - 4
src/nodesnim/nodes/node.nim

@@ -16,7 +16,7 @@ type
   NodeObj* = object of RootObj
     kind*: NodeKind
     type_of_node*: NodeTypes
-    visible*: Visibility
+    visibility*: Visibility
     is_ready*: bool
     pausemode*: PauseMode            ## Pause mode, by default is INHERIT.
     name*: string                    ## Node name.
@@ -39,7 +39,7 @@ template nodepattern*(nodetype: untyped): untyped =
     on_input: proc(self: NodeRef, event: InputEvent) = discard,
     on_enter: proc(self: NodeRef) = discard,
     on_exit: proc(self: NodeRef) = discard,
-    is_ready: false, pausemode: INHERIT, visible: VISIBLE
+    is_ready: false, pausemode: INHERIT, visibility: VISIBLE
   )
   result.type_of_node = NODE_TYPE_DEFAULT
 
@@ -190,7 +190,7 @@ method hasParent*(self: NodeRef): bool {.base, inline.} =
   self.parent != nil
 
 method hide*(self: NodeRef) {.base.} =
-  self.visible = INVISIBLE
+  self.visibility = INVISIBLE
 
 method postdraw*(self: NodeRef, w, h: GLfloat) {.base.} =
   ## Draws node.
@@ -218,7 +218,7 @@ method removeChild*(self: NodeRef, other: NodeRef) {.base.} =
     self.removeChild(index)
 
 method show*(self: NodeRef) {.base.} =
-  self.visible = VISIBLE
+  self.visibility = VISIBLE
 
 method delete*(self: NodeRef) {.base.} =
   ## Deletes current node.

+ 3 - 3
src/nodesnim/nodes/scene.nim

@@ -40,7 +40,7 @@ method drawScene*(scene: SceneRef, w, h: GLfloat, paused: bool) {.base.} =
   for child in scene.getChildIter():
     if paused and child.getPauseMode() != PROCESS:
       continue
-    if child.visible != GONE:
+    if child.visibility != GONE:
       # load opengl
       if child.type_of_node != NODE_TYPE_DEFAULT:
         glLoadIdentity()
@@ -74,7 +74,7 @@ method drawScene*(scene: SceneRef, w, h: GLfloat, paused: bool) {.base.} =
   for child in scene.getChildIter():
     if paused and child.getPauseMode() != PROCESS:
       continue
-    if child.visible != GONE:
+    if child.visibility != GONE:
       child.postdraw(w, h)
   scene.calcGlobalPosition()
 
@@ -103,7 +103,7 @@ method handleScene*(scene: SceneRef, event: InputEvent, mouse_on: var NodeRef, p
   for i in countdown(childs.len()-1, 0):
     if paused and childs[i].getPauseMode() != PROCESS:
       continue
-    if childs[i].visible != GONE:
+    if childs[i].visibility != GONE:
       childs[i].handle(event, mouse_on)
       childs[i].on_input(childs[i], event)
 

+ 9 - 9
src/nodesnim/nodescontrol/popup.nim

@@ -1,5 +1,5 @@
 # author: Ethosa
-## By default popup visible is false. Popup, unlike other nodes, changes children visible when calling show() and hide().
+## By default popup visibility is false. Popup, unlike other nodes, changes children visibility when calling show() and hide().
 import
   ../core/vector2,
   ../core/rect2,
@@ -30,32 +30,32 @@ proc Popup*(name: string = "Popup"): PopupRef =
   result.background.setColor(Color(0x212121ff))
   result.rect_size.x = 160
   result.rect_size.y = 160
-  result.visible = GONE
+  result.visibility = GONE
   result.kind = POPUP_NODE
 
 
 template recalc =
   for child in self.getChildIter():
-    if child.visible != GONE and self.visible == GONE:
-      child.visible = GONE
-    elif child.visible != VISIBLE and self.visible == VISIBLE:
-      child.visible = VISIBLE
+    if child.visibility != GONE and self.visibility == GONE:
+      child.visibility = GONE
+    elif child.visibility != VISIBLE and self.visibility == VISIBLE:
+      child.visibility = VISIBLE
 
 
 method hide*(self: PopupRef) =
   ## Hides popup.
   {.warning[LockLevel]: off.}
-  self.visible = GONE
+  self.visibility = GONE
   recalc()
 
 method show*(self: PopupRef) =
   ## Shws popup.
   {.warning[LockLevel]: off.}
-  self.visible = VISIBLE
+  self.visibility = VISIBLE
   recalc()
 
 method toggle*(self: PopupRef) {.base.} =
-  if self.visible == GONE:
+  if self.visibility == GONE:
     self.show()
   else:
     self.hide()

+ 6 - 6
src/nodesnim/nodescontrol/subwindow.nim

@@ -48,7 +48,7 @@ proc SubWindow*(name: string = "SubWindow"): SubWindowRef =
   result.background.setBorderWidth(1)
   result.rect_size.x = 320
   result.rect_size.y = 220
-  result.visible = GONE
+  result.visibility = GONE
   result.title = Label("Title")
   result.title.setText("Title")
   result.title.parent = result
@@ -83,15 +83,15 @@ method draw*(self: SubWindowRef, w, h: GLfloat) =
   for child in self.getChildIter():
     child.CanvasRef.calcGlobalPosition()
     if child.CanvasRef.global_position.x > self.global_position.x + self.rect_size.x:
-      child.visible = GONE
+      child.visibility = GONE
     elif child.CanvasRef.global_position.y > self.global_position.y + self.rect_size.y:
-      child.visible = GONE
+      child.visibility = GONE
     elif child.CanvasRef.global_position.x + child.CanvasRef.rect_size.x < self.global_position.x:
-      child.visible = GONE
+      child.visibility = GONE
     elif child.CanvasRef.global_position.y + child.CanvasRef.rect_size.y < self.global_position.y:
-      child.visible = GONE
+      child.visibility = GONE
     else:
-      child.visible = VISIBLE
+      child.visibility = VISIBLE
 
   self.title_bar.draw(x, y, self.rect_size.x, 32)