diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c1deb543..04e62390 100644
--- a/.github/workflows/test.yml
+++ b/.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
diff --git a/LICENSE b/LICENSE
index 05c06944..1c85d715 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020 Ethosa
+Copyright (c) 2021 Ethosa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 2450013e..3be9abf4 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ The Nim GUI/2D framework based on OpenGL and SDL2.
[](https://t.me/nim1love)
[](https://t.me/nodesnim)
-
Stable version - 0.3.2
+Stable version - 0.4.0
## Install
@@ -67,7 +67,7 @@ This section contains links to documentation for all nodes.
|[Anchor][] |[Node][] |[Control][] |[Node2D][] |[Node3D][] |[Drawable][] |
|[Color][] |[Canvas][] |[ColorRect][] |[Sprite][] |[GeometryInstance][]|[GradientDrawable][]|
|[Font][] |[Scene][] |[TextureRect][] |[AnimatedSprite][] |[Camera3D][] | |
-|[Enums][] |[AudioStreamPlayer][]|[Label][] |[YSort][] | | |
+|[Enums][] |[AudioStreamPlayer][]|[Label][] |[YSort][] |[Sprite3D][] | |
|[Exceptions][] |[AnimationPlayer][] |[Button][] |[CollisionShape2D][]| | |
|[Image][] | |[EditText][] |[Camera2D][] | | |
|[Input][] | |[Box][] |[TileMap][] | | |
@@ -84,6 +84,7 @@ This section contains links to documentation for all nodes.
| | |[Switch][] | | | |
| | |[SubWindow][] | | | |
| | |[CheckBox][] | | | |
+| | |[ToolTip][] | | | |
@@ -154,6 +155,7 @@ Also use [`niminst`](https://github.com/nim-lang/niminst) tool for generate an i
[Font]:https://ethosa.github.io/nodesnim/nodesnim/core/font.html
[StyleSheet]:https://ethosa.github.io/nodesnim/nodesnim/core/stylesheet.html
[TileSet]:https://ethosa.github.io/nodesnim/nodesnim/core/tileset.html
+[Scripts]:https://ethosa.github.io/nodesnim/nodesnim/core/scripts.html
[Node]:https://ethosa.github.io/nodesnim/nodesnim/nodes/node.html
[Canvas]:https://ethosa.github.io/nodesnim/nodesnim/nodes/canvas.html
@@ -183,6 +185,7 @@ Also use [`niminst`](https://github.com/nim-lang/niminst) tool for generate an i
[Switch]:https://ethosa.github.io/nodesnim/nodesnim/nodescontrol/switch.html
[SubWindow]:https://ethosa.github.io/nodesnim/nodesnim/nodescontrol/subwindow.html
[CheckBox]:https://ethosa.github.io/nodesnim/nodesnim/nodescontrol/checkbox.html
+[ToolTip]:https://ethosa.github.io/nodesnim/nodesnim/nodescontrol/tooltip.html
[Node2D]:https://ethosa.github.io/nodesnim/nodesnim/nodes2d/node2d.html
[Sprite]:https://ethosa.github.io/nodesnim/nodesnim/nodes2d/sprite.html
@@ -197,6 +200,7 @@ Also use [`niminst`](https://github.com/nim-lang/niminst) tool for generate an i
[Node3D]:https://ethosa.github.io/nodesnim/nodesnim/nodes3d/node3d.html
[GeometryInstance]:https://ethosa.github.io/nodesnim/nodesnim/nodes3d/geometry_instance.html
[Camera3D]:https://ethosa.github.io/nodesnim/nodesnim/nodes3d/camera3d.html
+[Sprite3D]:https://ethosa.github.io/nodesnim/nodesnim/nodes3d/sprite3d.html
[Drawable]:https://ethosa.github.io/nodesnim/nodesnim/graphics/drawable.html
[GradientDrawable]:https://ethosa.github.io/nodesnim/nodesnim/graphics/gradient_drawable.html
diff --git a/examples/builder_features/main.nim b/examples/builder_features/main.nim
new file mode 100644
index 00000000..3dbbe72a
--- /dev/null
+++ b/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()
diff --git a/examples/builder_features/nim.cfg b/examples/builder_features/nim.cfg
new file mode 100644
index 00000000..cf9b2a26
--- /dev/null
+++ b/examples/builder_features/nim.cfg
@@ -0,0 +1 @@
+--path:"../../src"
\ No newline at end of file
diff --git a/examples/builder_features/readme.md b/examples/builder_features/readme.md
new file mode 100644
index 00000000..8b7be07f
--- /dev/null
+++ b/examples/builder_features/readme.md
@@ -0,0 +1 @@
+# SceneBuilder features
\ No newline at end of file
diff --git a/examples/calculator/material_ui.nim b/examples/calculator/material_ui.nim
new file mode 100644
index 00000000..4adcb376
--- /dev/null
+++ b/examples/calculator/material_ui.nim
@@ -0,0 +1,204 @@
+# --- Material UI calculator --- #
+import
+ strutils,
+ nodesnim
+
+
+type
+ TokenType {.size: sizeof(int8).} = enum
+ NUMBER,
+ OPERATOR,
+ RPAR,
+ LPAR
+ Token = ref object
+ token_type: TokenType
+ token_value: string
+ TokenTree = seq[Token]
+
+proc parseQuery(query: string): TokenTree =
+ result = @[]
+ for c in query:
+ if c.isDigit() or c == '.':
+ if result.len > 0 and not result[^1].isNil() and result[^1].token_type == NUMBER:
+ result[^1].token_value &= $c
+ else:
+ result.add(Token(token_type: NUMBER, token_value: $c))
+ elif c in "+-/*":
+ result.add(Token(token_type: OPERATOR, token_value: $c))
+ when false:
+ for i in result:
+ echo i.token_value
+
+proc findHigh(tree: TokenTree): int =
+ result = -1
+ let tokens = "/*-+"
+ for token in tokens:
+ for i in tree.low..tree.high:
+ if tree[i].token_type == OPERATOR and tree[i].token_value == $token:
+ return i-1
+
+
+proc calculate(tree: TokenTree): float =
+ result = 0f
+
+ var
+ t = tree
+ index = t.findHigh()
+
+ while index != -1:
+ case t[index+1].token_value
+ of "/":
+ t[index].token_value = $(t[index].token_value.parseFloat() / t[index+2].token_value.parseFloat())
+ of "*":
+ t[index].token_value = $(t[index].token_value.parseFloat() * t[index+2].token_value.parseFloat())
+ of "-":
+ t[index].token_value = $(t[index].token_value.parseFloat() - t[index+2].token_value.parseFloat())
+ of "+":
+ t[index].token_value = $(t[index].token_value.parseFloat() + t[index+2].token_value.parseFloat())
+ t.del(index+2)
+ t.del(index+1)
+ index = t.findHigh()
+ if t.len == 1:
+ result = parseFloat(t[0].token_value)
+
+Window("material ui calculator", ((64+32)*4)+16, 480)
+env.setBackgroundColor(Color("#FAFAFA"))
+
+
+var
+ query: string = ""
+ big_font = loadFont(standard_font_path, 32)
+ medium = loadFont(standard_font_path, 24)
+ small = loadFont(standard_font_path, 16)
+
+build:
+ - Button number_button:
+ call setStyle(style({color: "#EEEEEE"}))
+ call resize(64+32, 64)
+ call setTextFont(loadFont(standard_font_path, 24))
+ - Button operator_button:
+ call setStyle(style({color: "#F5F5F5"}))
+ call resize(64+32, 51.2f)
+ call setTextFont(loadFont(standard_font_path, 22))
+
+number_button.normal_background.setStyle(style({background-color: "#424242"}))
+number_button.hover_background.setStyle(style({background-color: "#616161"}))
+number_button.press_background.setStyle(style({background-color: "#757575"}))
+
+operator_button.normal_background.setStyle(style({background-color: "#616161"}))
+operator_button.hover_background.setStyle(style({background-color: "#757575"}))
+operator_button.press_background.setStyle(style({background-color: "#9E9E9E"}))
+
+
+when false:
+ query = "123+1*5-200/10"
+ var
+ parsed = parseQuery(query)
+ calculated = calculate(parsed)
+
+
+build:
+ - Scene main:
+ - HBox hbox:
+ separator: 0
+ call setPadding(8, 8, 8, 8)
+ call move(0, 200)
+ - GridBox numbers:
+ separator: 0
+ call setRow(3)
+ - Vbox operators:
+ separator: 0
+ - Control result_back:
+ call resize(((64+32)*4), 200)
+ call move(8, 8)
+ call setStyle(style({
+ background-color: "#4DD0E1",
+ shadow: true,
+ shadow-offset: "0 8"
+ }))
+ - Label text:
+ call setTextFont(loadFont(standard_font_path, 32))
+ call setTextColor(Color("#fff"))
+ call setTextAlign(1, 1, 1, 1)
+ call setAnchor(1, 1, 1, 1)
+ call setSizeAnchor(1, 0.5)
+ call setPadding(16, 16, 16, 16)
+
+
+for i in 0..11:
+ numbers.addChild(number_button.duplicate())
+ if i < 9:
+ numbers.getChild(i).ButtonRef.setText($(i+1))
+ numbers.getChild(i).ButtonRef@onClick(self, x, y):
+ query &= self.ButtonRef.getText()
+ text.setText(query)
+ elif i == 9:
+ numbers.getChild(i).ButtonRef.setText(".")
+ numbers.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0 and query[^1] != '.':
+ query &= self.ButtonRef.getText()
+ text.setText(query)
+ elif i == 10:
+ numbers.getChild(i).ButtonRef.setText("0")
+ numbers.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0:
+ query &= self.ButtonRef.getText()
+ text.setText(query)
+ elif i == 11:
+ numbers.getChild(i).ButtonRef.setText("=")
+ numbers.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0 and query[^1] in "/*-+":
+ query = "0"
+ var calculated = parseQuery(query).calculate()
+ query = $calculated
+ text.setText(query)
+
+for i in 0..4:
+ operators.addChild(operator_button.duplicate())
+ case i
+ of 0:
+ operators.getChild(i).ButtonRef.setText("DEL")
+ operators.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0:
+ query = query[0..^2]
+ text.setText(query)
+ of 1:
+ operators.getChild(i).ButtonRef.setText("+")
+ operators.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0:
+ if query[^1] notin "-+/*":
+ query &= "+"
+ else:
+ query = query[0..^2] & "+"
+ text.setText(query)
+ of 2:
+ operators.getChild(i).ButtonRef.setText("−")
+ operators.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0:
+ if query[^1] notin "-+/*":
+ query &= "-"
+ else:
+ query = query[0..^2] & "-"
+ text.setText(query)
+ of 3:
+ operators.getChild(i).ButtonRef.setText("÷")
+ operators.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0:
+ if query[^1] notin "-+/*":
+ query &= "/"
+ else:
+ query = query[0..^2] & "/"
+ text.setText(query)
+ else:
+ operators.getChild(i).ButtonRef.setText("×")
+ operators.getChild(i).ButtonRef@onClick(self, x, y):
+ if query.len > 0:
+ if query[^1] notin "-+/*":
+ query &= "*"
+ else:
+ query = query[0..^2] & "*"
+ text.setText(query)
+
+
+addMainScene(main)
+windowLaunch()
diff --git a/examples/novel/main.nim b/examples/novel/main.nim
index d9233964..573a60b3 100644
--- a/examples/novel/main.nim
+++ b/examples/novel/main.nim
@@ -34,7 +34,7 @@ build:
call setTexture(akiko_default)
call setTextureAnchor(0.5, 0.5, 0.5, 0.5)
texture_mode: TEXTURE_KEEP_ASPECT_RATIO
- visible: GONE
+ visibility: GONE
- Label dialog_text:
call setSizeAnchor(0.8, 0.3)
call setAnchor(0.1, 0.6, 0, 0)
@@ -65,7 +65,7 @@ foreground_rect@on_input(self, event):
if stage < dialog.len():
name_charapter.setText(dialog[stage][0])
dialog_text.setText(dialog[stage][1])
- charapter.visible = dialog[stage][2]
+ charapter.visibility = dialog[stage][2]
inc stage
diff --git a/examples/readme.md b/examples/readme.md
index deeeb5ce..915f8e0f 100644
--- a/examples/readme.md
+++ b/examples/readme.md
@@ -1,22 +1,24 @@
# Examples
-## [Hello world](https://github.com/Ethosa/nodesnim/blob/master/examples/hello_world)
+## [Hello world](https://github.com/Ethosa/nodesnim/blob/nightly/examples/hello_world)

-## [Calculator](https://github.com/Ethosa/nodesnim/blob/master/examples/calculator)
+## [Calculator](https://github.com/Ethosa/nodesnim/blob/nightly/examples/calculator)

-## [Snake game](https://github.com/Ethosa/nodesnim/blob/master/examples/snake)
+## [Snake game](https://github.com/Ethosa/nodesnim/blob/nightly/examples/snake)

-## [Screen saver](https://github.com/Ethosa/nodesnim/blob/master/examples/screensaver)
+## [Screen saver](https://github.com/Ethosa/nodesnim/blob/nightly/examples/screensaver)

-## [Novel](https://github.com/Ethosa/nodesnim/blob/master/examples/novel)
+## [Novel](https://github.com/Ethosa/nodesnim/blob/nightly/examples/novel)

-## [Roguelike](https://github.com/Ethosa/nodesnim/blob/master/examples/roguelike)
+## [Roguelike](https://github.com/Ethosa/nodesnim/blob/nightly/examples/roguelike)

-## [Sample messenger](https://github.com/Ethosa/nodesnim/blob/master/examples/sample_messenger)
+## [Sample messenger](https://github.com/Ethosa/nodesnim/blob/nightly/examples/sample_messenger)

+
+## [Builder features](https://github.com/Ethosa/nodesnim/blob/nightly/examples/builder_features)
diff --git a/examples/roguelike/main.nim b/examples/roguelike/main.nim
index 107815b2..01cf1227 100644
--- a/examples/roguelike/main.nim
+++ b/examples/roguelike/main.nim
@@ -18,7 +18,7 @@ build:
- Scene main:
- TileMap map:
call setTileSet(tileset)
- call resizeMap(newVector2(LEVEL_WIDTH, 15), 2)
+ call resizeMap(Vector2(LEVEL_WIDTH, 15), 2)
# Player
- KinematicBody2D player:
@@ -51,18 +51,18 @@ build:
# Draw grass
for i in 0..512:
- map.drawTile(rand(99), rand(14), newVector2(0, 1), 1)
+ map.drawTile(rand(99), rand(14), Vector2(0, 1), 1)
# Draw trees
for i in 0..128:
- map.drawTile(rand(99), rand(14), newVector2(rand(13..16).float, 0), 1)
+ map.drawTile(rand(99), rand(14), Vector2(rand(13..16).float, 0), 1)
# Draw houses
for i in 0..32:
var
pos = Vector2(rand(99).float, rand(14).float)
collider = CollisionShape2D()
- map.drawTile(pos.x.int, pos.y.int, newVector2(rand(13..16).float, 2), 1)
+ map.drawTile(pos.x.int, pos.y.int, Vector2(rand(13..16).float, 2), 1)
collider.resize(PLAYER_SIZE, PLAYER_SIZE)
collider.move(pos.x*PLAYER_SIZE, pos.y*PLAYER_SIZE)
main.addChild(collider)
@@ -74,7 +74,7 @@ addKeyAction("backward", "s")
addKeyAction("right", "d")
addKeyAction("left", "a")
-player@onInput(self, event):
+player@onProcess(self):
if isActionPressed("right"):
player.moveAndCollide(Vector2(PLAYER_SPEED, 0))
elif isActionPressed("left"):
diff --git a/nodesnim.nimble b/nodesnim.nimble
index 30b70d80..f65975a8 100644
--- a/nodesnim.nimble
+++ b/nodesnim.nimble
@@ -1,10 +1,11 @@
[Package]
name = "nodesnim"
author = "Ethosa"
-version = "0.3.2"
+version = "0.4.0"
description = "The Nim GUI/2D framework based on OpenGL and SDL2."
license = "MIT"
srcDir = "src"
[Deps]
Requires: "nim >= 1.0.0"
+Requires: "compiler >= 1.0.0"
diff --git a/src/nodesnim.nim b/src/nodesnim.nim
index bf8cae41..21a9090b 100644
--- a/src/nodesnim.nim
+++ b/src/nodesnim.nim
@@ -10,9 +10,9 @@ when defined(debug):
info("Compiled in debug mode.")
+import nodesnim/thirdparty/sdl2 except Color
import
nodesnim/thirdparty/opengl,
- nodesnim/thirdparty/sdl2,
nodesnim/window,
nodesnim/environment,
diff --git a/src/nodesnim/core/audio_stream.nim b/src/nodesnim/core/audio_stream.nim
index 505cd8b6..460bf60a 100644
--- a/src/nodesnim/core/audio_stream.nim
+++ b/src/nodesnim/core/audio_stream.nim
@@ -7,7 +7,6 @@ import
discard mixer.init(MIX_INIT_OGG)
discard mixer.openAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)
-
type
AudioStreamRef* = ref object of RootObj
chunk*: ptr Chunk
diff --git a/src/nodesnim/core/circle.nim b/src/nodesnim/core/circle.nim
index ae6fa2ff..bfcae233 100644
--- a/src/nodesnim/core/circle.nim
+++ b/src/nodesnim/core/circle.nim
@@ -77,7 +77,7 @@ proc contains*(self: CircleObj, a, b: Vector2Obj): bool =
let tmin = if -b - discr > 0: -b - discr else: 0
if tmin > d:
return false
- return true
+ true
# --- Operators --- #
diff --git a/src/nodesnim/core/color.nim b/src/nodesnim/core/color.nim
index 54f8348e..b68b7780 100644
--- a/src/nodesnim/core/color.nim
+++ b/src/nodesnim/core/color.nim
@@ -49,11 +49,12 @@ proc Color*(src: uint32): ColorRef =
echo clr3
echo clr4
+ let clr = src.int
ColorRef(
- r: ((src shr 24) and 255).int / 255,
- g: ((src shr 16) and 255).int / 255,
- b: ((src shr 8) and 255).int / 255,
- a: (src and 255).int / 255
+ r: ((clr shr 24) and 255) / 255,
+ g: ((clr shr 16) and 255) / 255,
+ b: ((clr shr 8) and 255) / 255,
+ a: (clr and 255) / 255
)
proc Color*(src: string): ColorRef =
@@ -73,16 +74,23 @@ proc Color*(src: string): ColorRef =
target = src
matched: array[20, string]
- # #FFFFFFFF, #FFF, #FFFFFF, etc
+ # #FFFFFFFF, #FFF, #FFFFFF, #FFFF, etc
if target.startsWith('#') or target.startsWith("0x") or target.startsWith("0X"):
target = target[1..^1]
- if target[0] == 'x' or target[0] == 'X':
+ if target[0] in {'x', 'X'}:
target = target[1..^1]
- if target.len() == 3: # #fff -> #ffffffff
+ let length = target.len
+ case length
+ of 3:
target = target[0] & target[0] & target[1] & target[1] & target[2] & target[2] & "ff"
- elif target.len() == 6: # #ffffff -> #ffffffff
+ of 4: # #1234 -> #11223344
+ target = target[0] & target[0] & target[1] & target[1] & target[2] & target[2] & target[3] & target[3]
+ of 6: # #ffffff -> #ffffffff
target &= "ff"
+ else:
+ discard
+
return Color(parseHexInt(target).uint32)
# rgba(255, 255, 255, 1.0)
@@ -97,6 +105,9 @@ proc Color*(): ColorRef {.inline.} =
## Creates a new Color object with RGBA value (0, 0, 0, 0)
ColorRef(r: 0, g: 0, b: 0, a: 0)
+proc Color*(clr: ColorRef): ColorRef {.inline.} =
+ ColorRef(r: clr.r, g: clr.g, b: clr.b, a: clr.a)
+
proc getBrightness*(self: ColorRef): float {.inline.} =
(self.r + self.g + self.b) / 3f
diff --git a/src/nodesnim/core/enums.nim b/src/nodesnim/core/enums.nim
index 359a3085..31efb7b3 100644
--- a/src/nodesnim/core/enums.nim
+++ b/src/nodesnim/core/enums.nim
@@ -1,18 +1,21 @@
# author: Ethosa
+{.push pure, size: sizeof(int8).}
+
type
- MouseMode* {.size: sizeof(int8).} = enum
+ MouseMode* = enum
MOUSEMODE_IGNORE = 0x00000001 ## Igore mouse input. This used in Control nodes
MOUSEMODE_SEE = 0x00000002 ## Handle mouse input.
- PauseMode* {.size: sizeof(int8).} = enum
+ PauseMode* = enum
PROCESS, ## Continue to work when the window paused.
PAUSE, ## Pause work when the window paused.
INHERIT ## Take parent value.
- TextureMode* {.size: sizeof(int8).} = enum
+ TextureMode* = enum
TEXTURE_FILL_XY, ## Fill texture without keeping the aspect ratio.
TEXTURE_KEEP_ASPECT_RATIO, ## Fill texture with keeping the aspect ratio.
TEXTURE_CROP ## Crop and fill texture.
- NodeKind* {.pure, size: sizeof(int8).} = enum
+
+ NodeKind* = enum
NODE_NODE,
CANVAS_NODE,
SCENE_NODE,
@@ -50,13 +53,50 @@ type
# 3D nodes
NODE3D_NODE,
GEOMETRY_INSTANCE_NODE,
- CAMERA_3D_NODE
- NodeTypes* {.pure, size: sizeof(int8).} = enum
+ CAMERA_3D_NODE,
+ SPRITE_3D_NODE
+
+ NodeTypes* = enum
NODE_TYPE_DEFAULT,
NODE_TYPE_CONTROL,
NODE_TYPE_2D,
NODE_TYPE_3D
- Visibility* {.pure, size: sizeof(int8).} = enum
+
+ Visibility* = enum
VISIBLE,
INVISIBLE,
GONE
+
+ ProgressBarType* = enum
+ PROGRESS_BAR_HORIZONTAL,
+ PROGRESS_BAR_VERTICAL,
+ PROGRESS_BAR_CIRCLE
+
+ SliderType* = enum
+ SLIDER_HORIZONTAL,
+ SLIDER_VERTICAL
+
+ GeometryType* = enum
+ GEOMETRY_CUBE, ## Uses for cube rendering.
+ GEOMETRY_CYLINDER, ## Uses for cylinder rendering.
+ GEOMETRY_SPHERE ## Uses for sphere rendering.
+
+ TileMapMode* = enum
+ TILEMAP_2D, ## Default 2D mode.
+ TILEMAP_ISOMETRIC ## Isometric mode.
+
+ CollisionShape2DType* = enum
+ COLLISION_SHAPE_2D_RECTANGLE, ## Uses for handle rect collision.
+ COLLISION_SHAPE_2D_CIRCLE, ## Uses for handle circle collision.
+ COLLISION_SHAPE_2D_POLYGON ## Uses for handle polygon collision.
+
+ AnimationMode* = enum
+ ANIMATION_NORMAL, ## specific speed per second.
+ ANIMATION_EASE, ## ease mode.
+ ANIMATION_BEZIER ## specific bezier curve for speed.
+
+ ScreenMode* = enum
+ SCREEN_MODE_NONE, ## default mode.
+ SCREEN_MODE_EXPANDED ## Keep screen size.
+
+{.pop.}
diff --git a/src/nodesnim/core/exceptions.nim b/src/nodesnim/core/exceptions.nim
index 5ca6af3c..2ac0ebd9 100644
--- a/src/nodesnim/core/exceptions.nim
+++ b/src/nodesnim/core/exceptions.nim
@@ -1,6 +1,16 @@
# author: Ethosa
+import logging
+{.push pure, size: sizeof(int8).}
type
- ResourceError* {.size: sizeof(int8).} = object of ValueError
- SceneError* {.size: sizeof(int8).} = object of ValueError
- WindowError* {.size: sizeof(int8).} = object of ValueError
+ ResourceError* = object of ValueError
+ SceneError* = object of ValueError
+ VMError* = object of ValueError
+ WindowError* = object of ValueError
+{.pop.}
+
+
+template throwError*(err: typedesc, msg: string) =
+ when defined(debug):
+ error(msg)
+ raise newException(err, msg)
diff --git a/src/nodesnim/core/font.nim b/src/nodesnim/core/font.nim
index 131cff39..c5963451 100644
--- a/src/nodesnim/core/font.nim
+++ b/src/nodesnim/core/font.nim
@@ -1,7 +1,7 @@
# author: Ethosa
## Provides TTF text rendering. Use SDL2_ttf.
+import ../thirdparty/sdl2 except Color
import
- ../thirdparty/sdl2,
../thirdparty/sdl2/ttf,
../thirdparty/opengl,
@@ -16,8 +16,9 @@ import
type
StyleUnicode* = ref object
- underline*: bool
- c*: string
+ is_url*: bool
+ style*: cint
+ c*, url*: string
color*: ColorRef
StyleText* = ref object
font*: FontPtr
@@ -27,14 +28,18 @@ type
texture*: GlTextureObj
chars*: seq[StyleUnicode]
+let URL_COLOR = Color(0.45, 0.45, 0.9)
-proc schar*(c: string, color: ColorRef = Color(1f, 1f, 1f), underline: bool = false): StyleUnicode =
- StyleUnicode(c: c, color: color, underline: underline)
-proc stext*(text: string, color: ColorRef = Color(1f, 1f, 1f), underline: bool = false): StyleText =
+proc schar*(c: string, color: ColorRef = Color(1f, 1f, 1f),
+ style: cint = TTF_STYLE_NORMAL, is_url: bool = false): StyleUnicode =
+ StyleUnicode(c: c, color: color, style: style, is_url: is_url, url: "")
+
+proc stext*(text: string, color: ColorRef = Color(1f, 1f, 1f),
+ style: cint = TTF_STYLE_NORMAL): StyleText =
result = StyleText(texture: GlTextureObj(size: Vector2()), spacing: 2, max_lines: -1)
for i in text.utf8():
- result.chars.add(schar(i, color, underline))
+ result.chars.add(schar(i, color, style))
result.font = standard_font
result.rendered = false
@@ -63,28 +68,19 @@ proc `&`*(text, t: StyleText): StyleText =
proc `&`*(text: StyleText, t: string): StyleText =
text & stext(t)
-proc `&`*(text: string, c: StyleUnicode): string =
+proc `&`*(text: string, c: StyleUnicode | StyleText): string =
text & $c
-proc `&`*(text: string, t: StyleText): string =
- text & $t
-
-proc `&=`*(text: var StyleText, c: StyleUnicode) =
- text = text & c
-
-proc `&=`*(text: var StyleText, t: StyleText) =
- text = text & t
+proc `&=`*(text: var StyleText, c: StyleUnicode | StyleText) =
+ text &= c
-proc `&=`*(text: var string, c: StyleUnicode) =
- text = text & $c
-
-proc `&=`*(text: var string, t: StyleText) =
- text = text & $t
+proc `&=`*(text: var string, c: StyleUnicode | StyleText) =
+ text &= $c
proc `&=`*(text: var StyleText, t: string) =
text &= stext(t)
-proc `[]`*(text: StyleText, index: int): StyleUnicode =
+proc `[]`*(text: StyleText, index: int | BackwardsIndex): StyleUnicode =
text.chars[index]
proc `[]`*[T, U](text: StyleText, slice: HSlice[T, U]): StyleText =
@@ -94,6 +90,11 @@ proc `[]`*[T, U](text: StyleText, slice: HSlice[T, U]): StyleText =
# ------ Funcs ------ #
+proc applyStyle*(symbol: StyleUnicode, style: cint, enabled: bool = true) =
+ if (symbol.style and style) == 0 and enabled:
+ symbol.style = symbol.style or style
+ elif (symbol.style and style) != 0 and not enabled:
+ symbol.style = symbol.style xor style
proc toUpper*(text: StyleText): StyleText =
result = text.deepCopy()
@@ -118,19 +119,29 @@ proc setColor*(text: StyleText, s, e: int, color: ColorRef) =
for i in s..e:
text.chars[i].color = color
-proc setUnderline*(c: StyleUnicode, val: bool) =
- c.underline = val
-
-proc setUnderline*(text: StyleText, val: bool) =
- for i in text.chars:
- i.underline = val
-
-proc setUnderline*(text: StyleText, index: int, val: bool) =
- text.chars[index].underline = val
-
-proc setUnderline*(text: StyleText, s, e: int, val: bool) =
+template styleFunc(setter, style_type: untyped): untyped =
+ proc `setter`*(c: StyleUnicode, val: bool = true) =
+ c.applyStyle(`style_type`, val)
+ proc `setter`*(text: StyleText, val: bool) =
+ for i in text.chars:
+ i.`setter`(val)
+ proc `setter`*(text: StyleText, index: int, val: bool) =
+ text.chars[index].`setter`(val)
+ proc `setter`*(text: StyleText, s, e: int, val: bool) =
+ for i in s..e:
+ text.chars[i].`setter`(val)
+
+styleFunc(setNormal, TTF_STYLE_NORMAL)
+styleFunc(setBold, TTF_STYLE_BOLD)
+styleFunc(setItalic, TTF_STYLE_ITALIC)
+styleFunc(setUnderline, TTF_STYLE_UNDERLINE)
+styleFunc(setStrikethrough, TTF_STYLE_STRIKETHROUGH)
+
+proc setURL*(text: StyleText, s, e: int, url: string) =
for i in s..e:
- text.chars[i].underline = val
+ text.chars[i].is_url = true
+ text.chars[i].url = url
+ text.chars[i].color = URL_COLOR
proc setFont*(text: StyleText, font: cstring, size: cint) =
text.font = openFont(font, size)
@@ -245,6 +256,14 @@ proc getPosUnderPoint*(text: StyleText, global_pos, text_pos: Vector2Obj,
if position.x == -1f:
result = 0
+proc getCharUnderPoint*(text: StyleText, global_pos, text_pos: Vector2Obj,
+ text_align: AnchorObj = Anchor(0, 0, 0, 0)): tuple[c: StyleUnicode, pos: uint32] =
+ let pos = text.getPosUnderPoint(global_pos, text_pos, text_align)
+ if pos > 0:
+ (c: text.chars[pos-1], pos: pos-1)
+ else:
+ (c: text.chars[pos], pos: pos)
+
# ------ Render ------ #
@@ -255,7 +274,7 @@ proc renderSurface*(text: StyleText, align: AnchorObj): SurfacePtr =
## - `align` -- text align.
when defined(debug):
if text.font.isNil():
- raise newException(ResourceError, "Font isn't loaded!")
+ throwError(ResourceError, "Font isn't loaded!")
if not text.font.isNil() and $text != "":
let
@@ -263,7 +282,7 @@ proc renderSurface*(text: StyleText, align: AnchorObj): SurfacePtr =
textsize = text.getTextSize()
var
surface = createRGBSurface(
- 0, textsize.x.cint, textsize.y.cint, 32,
+ 0, textsize.x.cint + 8, textsize.y.cint, 32,
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000u32)
y: cint = 0
w: cint
@@ -273,6 +292,7 @@ proc renderSurface*(text: StyleText, align: AnchorObj): SurfacePtr =
discard text.font.sizeUtf8(($line).cstring, addr w, addr h)
var x = (textsize.x * align.x1 - w.float * align.x2).cint
for c in line.chars:
+ text.font.setFontStyle(c.style)
discard text.font.sizeUtf8(($c).cstring, addr w, addr h)
var
rendered = text.font.renderUtf8Blended(
@@ -353,6 +373,7 @@ proc renderTo*(text: StyleText, pos, size: Vector2Obj, align: AnchorObj) =
glBindTexture(GL_TEXTURE_2D, text.texture.texture)
glEnable(GL_TEXTURE_2D)
glBegin(GL_QUADS)
+ glTexCoord2f(texcord[0], texcord[3])
glVertex2f(pos1.x + size1.x, pos1.y)
glTexCoord2f(texcord[0], texcord[1])
glVertex2f(pos1.x + size1.x, pos1.y - size1.y)
@@ -360,7 +381,6 @@ proc renderTo*(text: StyleText, pos, size: Vector2Obj, align: AnchorObj) =
glVertex2f(pos1.x, pos1.y - size1.y)
glTexCoord2f(texcord[2], texcord[3])
glVertex2f(pos1.x, pos1.y)
- glTexCoord2f(texcord[0], texcord[3])
glEnd()
glDisable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
diff --git a/src/nodesnim/core/image.nim b/src/nodesnim/core/image.nim
index 1c38c84c..eb3b28f4 100644
--- a/src/nodesnim/core/image.nim
+++ b/src/nodesnim/core/image.nim
@@ -22,9 +22,8 @@ proc load*(file: string, x, y: var float, mode: Glenum = GL_RGB): Gluint =
var
surface = image.load(file) # load image from file
textureid: Gluint
- when defined(debug):
- if surface.isNil():
- raise newException(ResourceError, "image \"" & file & "\" not loaded!")
+ if surface.isNil():
+ throwError(ResourceError, "image \"" & file & "\" not loaded!")
x = surface.w.float
y = surface.h.float
diff --git a/src/nodesnim/core/input.nim b/src/nodesnim/core/input.nim
index 0f57db2f..c76d7976 100644
--- a/src/nodesnim/core/input.nim
+++ b/src/nodesnim/core/input.nim
@@ -20,7 +20,6 @@ type
InputAction* = object
kind*: InputEventType
key_int*: cint
- key_cint*: cint
button_index*: cint
name*, key*: string
@@ -28,7 +27,6 @@ type
kind*: InputEventType
pressed*: bool
key_int*: cint
- key_cint*: cint
button_index*: cint
x*, y*, xrel*, yrel*: float
key*: string
@@ -52,9 +50,7 @@ var
mouse_pressed*: bool = false
press_state*: int = 0
last_event*: InputEvent = InputEvent()
- pressed_keys*: seq[string] = @[]
- pressed_keys_ints*: seq[cint] = @[]
- pressed_keys_cints*: seq[cint] = @[]
+ pressed_keys_cint*: seq[cint] = @[]
actionlist*: seq[InputAction] = @[]
@@ -101,7 +97,7 @@ proc addKeyAction*(name, key: string) {.inline.} =
## Arguments:
## - `name` - action name.
## - `key` - key, e.g.: "w", "1", etc.
- actionlist.add(InputAction(kind: KEYBOARD, name: name, key: key, key_int: ord(key[0]).cint))
+ actionlist.add(InputAction(kind: KEYBOARD, name: name, key_int: ord(key[0]).cint))
proc addKeyAction*(name: string, key: cint) {.inline.} =
## Adds a new action on keyboard.
@@ -127,7 +123,7 @@ proc isActionJustPressed*(name: string): bool =
result = false
for action in actionlist:
if action.name == name:
- if action.kind == MOUSE and (last_event.kind == MOUSE or last_event.kind == MOTION):
+ if action.kind == MOUSE and last_event.kind in [MOUSE, MOTION]:
if action.button_index == last_event.button_index and mouse_pressed:
if press_state == 0:
result = true
@@ -155,10 +151,9 @@ proc isActionPressed*(name: string): bool =
elif action.kind == TOUCH and last_event.kind == TOUCH:
if press_state > 0:
result = true
- elif action.kind == KEYBOARD and last_event.kind == KEYBOARD:
- if action.key_int in pressed_keys_ints or action.key in pressed_keys:
- if press_state > 0:
- result = true
+ elif action.kind == KEYBOARD:
+ if action.key_int in pressed_keys_cint:
+ result = true
proc isActionReleased*(name: string): bool =
## Returns true, when action no more active.
@@ -168,12 +163,14 @@ proc isActionReleased*(name: string): bool =
result = false
for action in actionlist:
if action.name == name:
- if action.kind == MOUSE and (last_event.kind == MOUSE or last_event.kind == MOTION):
+ if action.kind == MOUSE and last_event.kind in [MOUSE, MOTION]:
if action.button_index == last_event.button_index and not mouse_pressed:
if press_state == 0:
result = true
elif action.kind == KEYBOARD and last_event.kind == KEYBOARD:
- if action.key notin pressed_keys or action.key_int notin pressed_keys_ints:
+ if last_event.key_int > 255:
+ continue
+ if action.key == $chr(last_event.key_int) or action.key_int == last_event.key_int:
if press_state == 0:
result = true
@@ -200,3 +197,15 @@ proc `$`*(event: InputEvent): string =
"InputEventKeyboard(key: " & event.key & ", pressed:" & $event.pressed & ")"
of TEXT:
"InputEventText(key: " & event.key & ", pressed:" & $event.pressed & ")"
+
+
+proc `$`*(action: InputAction): string =
+ case action.kind
+ of MOUSE:
+ "InputAction[Mouse](button: " & $action.button_index & ")"
+ of KEYBOARD:
+ "InputAction[Keyboard](key: " & $action.key_int & ")"
+ of TOUCH:
+ "InputAction[Touch]()"
+ else:
+ ""
diff --git a/src/nodesnim/core/nodes_os.nim b/src/nodesnim/core/nodes_os.nim
index e62ae6c8..393032b1 100644
--- a/src/nodesnim/core/nodes_os.nim
+++ b/src/nodesnim/core/nodes_os.nim
@@ -6,13 +6,21 @@ import
discard ttfInit()
-const
+let
home_folder* = getHomeDir()
nodesnim_folder* = home_folder / "NodesNim"
- saves_folder* = "NodesNim" / "saves"
+ saves_folder* = nodesnim_folder / "saves"
discard existsOrCreateDir(nodesnim_folder)
-discard existsOrCreateDir(home_folder / saves_folder)
+discard existsOrCreateDir(saves_folder)
+
+let standard_font_path* =
+ when defined(windows):
+ "C://Windows/Fonts/segoeuib.ttf"
+ elif defined(android):
+ "/system/fonts/DroidSans.ttf"
+ else:
+ currentSourcePath().parentDir() / "unifont.ttf"
var standard_font*: FontPtr = nil
@@ -21,9 +29,12 @@ proc setStandardFont*(path: cstring, size: cint) =
standard_font.close()
standard_font = openFont(path, size)
-when defined(windows):
- setStandardFont("C://Windows/Fonts/segoeuib.ttf", 16)
-elif defined(android):
- setStandardFont("/system/fonts/DroidSans.ttf", 16)
-else:
- setStandardFont(currentSourcePath().parentDir() / "unifont.ttf", 16)
+proc norm*(a, b, c: float): float =
+ if c < a:
+ a
+ elif c > b:
+ b
+ else:
+ c
+
+setStandardFont(standard_font_path, 16)
diff --git a/src/nodesnim/core/scene_builder.nim b/src/nodesnim/core/scene_builder.nim
index f711747a..b2cfeaaf 100644
--- a/src/nodesnim/core/scene_builder.nim
+++ b/src/nodesnim/core/scene_builder.nim
@@ -4,47 +4,76 @@ 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:
- if $line[0] == "-":
- if line[1][1].kind == nnkIdent:
- result.add(newVarStmt(line[1][1], newCall($line[1][0], newStrLitNode($line[1][1]))))
- elif line[1][1].kind == nnkObjConstr:
- result.add(newVarStmt(line[1][1][0], newCall($line[1][0], newStrLitNode($line[1][1][0]))))
- elif line[1][1].kind == nnkPar:
- result.add(newVarStmt(postfix(line[1][1][0], "*"), newCall($line[1][0], newStrLitNode($line[1][1][0]))))
- if level.len() > 0:
- # - Scene main_scene:
- if line[1][1].kind == nnkIdent:
- result.add(newCall("addChild", level[^1], line[1][1]))
- elif line[1][1].kind == nnkPar:
- 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)
+ if line.kind == nnkPrefix and line[0].kind == nnkIdent and line[1].kind == nnkCommand:
+ # - Node name:
+ if $line[0] == "-":
+ case line[1][1].kind
+ of nnkIdent: # - Node name:
+ result.add(newVarStmt(line[1][1], newCall($line[1][0], newStrLitNode($line[1][1]))))
+ of nnkObjConstr: # - Node name(a: .., b: ...)
+ result.add(newVarStmt(line[1][1][0], newCall($line[1][0], newStrLitNode($line[1][1][0]))))
+ 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:
+ case line[1][1].kind:
+ of nnkIdent:
+ result.add(newCall("addChild", level[^1], line[1][1]))
+ of nnkPar, nnkObjConstr, nnkCall:
+ result.add(newCall("addChild", level[^1], line[1][1][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 methodName(arg1, arg2) -> currentNode.methodName(arg1, arg2)
- elif line.kind == nnkCommand and $line[0] == "call" and level.len() > 0:
+ 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 +85,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] = @[]
diff --git a/src/nodesnim/core/tileset.nim b/src/nodesnim/core/tileset.nim
index 4e6740b1..643299d3 100644
--- a/src/nodesnim/core/tileset.nim
+++ b/src/nodesnim/core/tileset.nim
@@ -19,9 +19,8 @@ proc TileSet*(img: string, tile_size: Vector2Obj, mode: Glenum = GL_RGB): TileSe
var
surface = image.load(img) # load image from file
textureid: Gluint = 0
- when defined(debug):
- if surface.isNil():
- raise newException(ResourceError, "image \"" & img & "\" not loaded!")
+ if surface.isNil():
+ throwError(ResourceError, "image \"" & img & "\" not loaded!")
glGenTextures(1, textureid.addr)
glBindTexture(GL_TEXTURE_2D, textureid)
@@ -41,7 +40,7 @@ proc TileSet*(img: string, tile_size: Vector2Obj, mode: Glenum = GL_RGB): TileSe
surface.freeSurface()
surface = nil
-proc draw*(self: TileSetObj, tilex, tiley, x, y: float) =
+proc draw*(self: TileSetObj, tilex, tiley, x, y, z: float) =
## Draws tile at position `tilex`,`tiley` to `x`,`y` position.
if self.texture > 0:
let
@@ -49,15 +48,18 @@ proc draw*(self: TileSetObj, tilex, tiley, x, y: float) =
texy1 = self.grid.y*tiley / self.size.y
texx2 = self.grid.x*(tilex+1f) / self.size.x
texy2 = self.grid.y*(tiley+1f) / self.size.y
+ glPushMatrix()
+ glTranslatef(x, y, z)
glBindTexture(GL_TEXTURE_2D, self.texture)
glBegin(GL_QUADS)
glTexCoord2f(texx1, texy1)
- glVertex2f(x, y)
+ glVertex3f(0, 0, 0)
glTexCoord2f(texx1, texy2)
- glVertex2f(x, y - self.grid.y)
+ glVertex3f(0, -self.grid.y, 0)
glTexCoord2f(texx2, texy2)
- glVertex2f(x + self.grid.x, y - self.grid.y)
+ glVertex3f(self.grid.x, -self.grid.y, 0)
glTexCoord2f(texx2, texy1)
- glVertex2f(x + self.grid.x, y)
+ glVertex3f(self.grid.x, 0, 0)
glEnd()
glBindTexture(GL_TEXTURE_2D, 0)
+ glPopMatrix()
diff --git a/src/nodesnim/core/vector2.nim b/src/nodesnim/core/vector2.nim
index f154e25c..70f79867 100644
--- a/src/nodesnim/core/vector2.nim
+++ b/src/nodesnim/core/vector2.nim
@@ -4,9 +4,8 @@ import math
type
- Vector2Obj* = object
+ Vector2Obj* = ref object
x*, y*: float
- Vector2Ref* = ref Vector2Obj
proc Vector2*(x, y: float): Vector2Obj {.inline.} =
@@ -15,26 +14,13 @@ proc Vector2*(x, y: float): Vector2Obj {.inline.} =
proc Vector2*(b: Vector2Obj): Vector2Obj {.inline.} =
Vector2Obj(x: b.x, y: b.y)
-proc Vector2*(num: float): Vector2Obj {.inline.} =
- Vector2Obj(x: num, y: num)
+proc Vector2*(x: float): Vector2Obj {.inline.} =
+ Vector2Obj(x: x, y: x)
proc Vector2*(): Vector2Obj {.inline.} =
Vector2Obj(x: 0, y: 0)
-proc newVector2*(x, y: float): Vector2Ref {.inline.} =
- Vector2Ref(x: x, y: y)
-
-proc newVector2*(o: Vector2Obj): Vector2Ref {.inline.} =
- Vector2Ref(x: o.x, y: o.y)
-
-proc newVector2*(o: float): Vector2Ref {.inline.} =
- Vector2Ref(x: o, y: o)
-
-proc newVector2*(): Vector2Ref {.inline.} =
- Vector2Ref(x: 0f, y: 0f)
-
-
proc abs*(a: Vector2Obj): Vector2Obj =
Vector2(abs(a.x), abs(a.y))
diff --git a/src/nodesnim/core/vector3.nim b/src/nodesnim/core/vector3.nim
index c3dc8286..5ed70b69 100644
--- a/src/nodesnim/core/vector3.nim
+++ b/src/nodesnim/core/vector3.nim
@@ -3,7 +3,7 @@ import math
type
- Vector3Obj* = object
+ Vector3Obj* = ref object
x*, y*, z*: float
diff --git a/src/nodesnim/environment.nim b/src/nodesnim/environment.nim
index 0465e360..0c0c553e 100644
--- a/src/nodesnim/environment.nim
+++ b/src/nodesnim/environment.nim
@@ -1,31 +1,29 @@
# author: Ethosa
-import core/color
+import
+ core/color,
+ core/enums
{.used.}
type
- ScreenMode* {.pure.} = enum
- SCREEN_MODE_NONE, ## default mode.
- SCREEN_MODE_EXPANDED ## Keep screen size.
EnvironmentObj* = object
- delay*: int ## window delay.
- color*: ColorRef ## background environment color.
- brightness*: float
+ color*: ColorRef ## background environment color.
screen_mode*: ScreenMode
+ delay*: int ## window delay.
EnvironmentRef* = ref EnvironmentObj
-proc newEnvironment*(color: ColorRef, brightness: float): EnvironmentRef =
+proc newEnvironment*(color: ColorRef): EnvironmentRef =
## Creates a new EnvironmentRef object.
##
## Arguments:
## - `color`: ColorRef object for background environment color.
## - `brightness` - window brightness with value in range `0..1`
- EnvironmentRef(color: color, delay: 17, brightness: brightness, screen_mode: SCREEN_MODE_NONE)
+ EnvironmentRef(color: color, delay: 17,screen_mode: SCREEN_MODE_NONE)
proc newEnvironment*(): EnvironmentRef {.inline.} =
## Creates a new EnvironmentRef object.
- newEnvironment(Color(0x313131ff), 1.0)
+ newEnvironment(Color(0x313131ff))
proc setBackgroundColor*(env: EnvironmentRef, color: ColorRef) =
@@ -42,13 +40,6 @@ proc setBackgroundColor*(env: EnvironmentRef, color: uint32) =
## - `color`: uint32 color, e.g.: 0xFF64FF
env.color = Color(color)
-proc setBrightness*(env: EnvironmentRef, brightness: float) =
- ## Changes window brightness.
- ##
- ## Arguments:
- ## - `brightness` - window brightness with value in range `0..1`
- env.brightness = brightness
-
proc setDelay*(env: EnvironmentRef, delay: int) =
## Changes window delay.
##
diff --git a/src/nodesnim/graphics/drawable.nim b/src/nodesnim/graphics/drawable.nim
index 073ccafd..fc446722 100644
--- a/src/nodesnim/graphics/drawable.nim
+++ b/src/nodesnim/graphics/drawable.nim
@@ -17,14 +17,8 @@ type
DrawableObj* = object of RootObj
shadow*: bool
border_width*: float
- border_detail_lefttop*: int
- border_detail_righttop*: int
- border_detail_leftbottom*: int
- border_detail_rightbottom*: int
- border_radius_lefttop*: float
- border_radius_righttop*: float
- border_radius_leftbottom*: float
- border_radius_rightbottom*: float
+ border_detail*: array[4, int] ## left-top, right-top, right-bottom, left-bottom
+ border_radius*: array[4, float] ## left-top, right-top, right-bottom, left-bottom
shadow_offset*: Vector2Obj
border_color*: ColorRef
background_color*: ColorRef
@@ -35,14 +29,8 @@ type
template drawablepattern*(`type`: untyped): untyped =
result = `type`(
texture: GlTextureObj(), border_width: 0,
- border_detail_lefttop: 20,
- border_detail_righttop: 20,
- border_detail_leftbottom: 20,
- border_detail_rightbottom: 20,
- border_radius_lefttop: 0,
- border_radius_righttop: 0,
- border_radius_leftbottom: 0,
- border_radius_rightbottom: 0,
+ border_detail: [8, 8, 8, 8],
+ border_radius: [0.float, 0, 0, 0],
border_color: Color(0, 0, 0, 0),
background_color: Color(0, 0, 0, 0),
shadow_offset: Vector2(0, 0), shadow: false
@@ -60,64 +48,65 @@ template vd* =
template recalc*(shadow: bool = false) =
## Calculates vertex positions.
+ let (xw, yh) = (x + width, y - height)
when not shadow:
# left top
- for i in bezier_iter(1f/self.border_detail_lefttop.float, Vector2(0, -self.border_radius_lefttop),
- Vector2(0, 0), Vector2(self.border_radius_lefttop, 0)):
- vertex.add(Vector2(x+i.x, y+i.y))
+ for i in bezier_iter(1f/self.border_detail[0].float, Vector2(0, -self.border_radius[0]),
+ Vector2(0, 0), Vector2(self.border_radius[0], 0)):
+ vertex.add(Vector2(x + i.x, y + i.y))
# right top
- for i in bezier_iter(1f/self.border_detail_righttop.float, Vector2(-self.border_radius_righttop, 0),
- Vector2(0, 0), Vector2(0, -self.border_radius_righttop)):
- vertex.add(Vector2(x+width+i.x, y+i.y))
+ for i in bezier_iter(1f/self.border_detail[1].float, Vector2(-self.border_radius[01], 0),
+ Vector2(0, 0), Vector2(0, -self.border_radius[1])):
+ vertex.add(Vector2(xw + i.x, y + i.y))
# right bottom
- for i in bezier_iter(1f/self.border_detail_rightbottom.float, Vector2(0, -self.border_radius_rightbottom),
- Vector2(0, 0), Vector2(-self.border_radius_rightbottom, 0)):
- vertex.add(Vector2(x+width+i.x, y-height-i.y))
+ for i in bezier_iter(1f/self.border_detail[2].float, Vector2(0, -self.border_radius[2]),
+ Vector2(0, 0), Vector2(-self.border_radius[2], 0)):
+ vertex.add(Vector2(xw + i.x, yh - i.y))
# left bottom
- for i in bezier_iter(1f/self.border_detail_leftbottom.float, Vector2(self.border_radius_leftbottom, 0),
- Vector2(0, 0), Vector2(0, self.border_radius_leftbottom)):
- vertex.add(Vector2(x+i.x, y-height+i.y))
+ for i in bezier_iter(1f/self.border_detail[3].float, Vector2(self.border_radius[3], 0),
+ Vector2(0, 0), Vector2(0, self.border_radius[3])):
+ vertex.add(Vector2(x + i.x, yh + i.y))
else:
glBegin(GL_QUAD_STRIP)
# left top
- for i in bezier_iter(1f/self.border_detail_lefttop.float, Vector2(0, -self.border_radius_lefttop),
- Vector2(0, 0), Vector2(self.border_radius_lefttop, 0)):
+ for i in bezier_iter(1f/self.border_detail[0].float, Vector2(0, -self.border_radius[0]),
+ Vector2(0, 0), Vector2(self.border_radius[0], 0)):
glColor4f(0, 0, 0, 0)
- glVertex2f(x+i.x+self.shadow_offset.x, y+i.y-self.shadow_offset.y)
+ glVertex2f(x + i.x + self.shadow_offset.x, y + i.y - self.shadow_offset.y)
glColor4f(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a)
- glVertex2f(x+i.x, y+i.y)
+ glVertex2f(x + i.x, y + i.y)
# right top
- for i in bezier_iter(1f/self.border_detail_righttop.float, Vector2(-self.border_radius_righttop, 0),
- Vector2(0, 0), Vector2(0, -self.border_radius_righttop)):
+ for i in bezier_iter(1f/self.border_detail[1].float, Vector2(-self.border_radius[1], 0),
+ Vector2(0, 0), Vector2(0, -self.border_radius[1])):
glColor4f(0, 0, 0, 0)
- glVertex2f(x+width+i.x+self.shadow_offset.x, y+i.y-self.shadow_offset.y)
+ glVertex2f(xw + i.x + self.shadow_offset.x, y + i.y - self.shadow_offset.y)
glColor4f(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a)
- glVertex2f(x+width+i.x, y+i.y)
+ glVertex2f(xw + i.x, y + i.y)
# right bottom
- for i in bezier_iter(1f/self.border_detail_rightbottom.float, Vector2(0, -self.border_radius_rightbottom),
- Vector2(0, 0), Vector2(-self.border_radius_rightbottom, 0)):
+ for i in bezier_iter(1f/self.border_detail[2].float, Vector2(0, -self.border_radius[2]),
+ Vector2(0, 0), Vector2(-self.border_radius[2], 0)):
glColor4f(0, 0, 0, 0)
- glVertex2f(x+width+i.x+self.shadow_offset.x, y-height-i.y-self.shadow_offset.y)
+ glVertex2f(xw + i.x + self.shadow_offset.x, yh - i.y - self.shadow_offset.y)
glColor4f(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a)
- glVertex2f(x+width+i.x, y-height-i.y)
+ glVertex2f(xw + i.x, yh - i.y)
# left bottom
- for i in bezier_iter(1f/self.border_detail_leftbottom.float, Vector2(self.border_radius_leftbottom, 0),
- Vector2(0, 0), Vector2(0, self.border_radius_leftbottom)):
+ for i in bezier_iter(1f/self.border_detail[3].float, Vector2(self.border_radius[3], 0),
+ Vector2(0, 0), Vector2(0, self.border_radius[3])):
glColor4f(0, 0, 0, 0)
- glVertex2f(x+i.x+self.shadow_offset.x, y-height+i.y-self.shadow_offset.y)
+ glVertex2f(x + i.x + self.shadow_offset.x, yh + i.y - self.shadow_offset.y)
glColor4f(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a)
- glVertex2f(x+i.x, y-height+i.y)
+ glVertex2f(x + i.x, yh + i.y)
glColor4f(0, 0, 0, 0)
- glVertex2f(x+self.shadow_offset.x, y-self.border_radius_lefttop-self.shadow_offset.y)
+ glVertex2f(x + self.shadow_offset.x, y - self.border_radius[0] - self.shadow_offset.y)
glColor4f(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a)
- glVertex2f(x, y-self.border_radius_lefttop)
+ glVertex2f(x, y - self.border_radius[0])
glEnd()
@@ -166,7 +155,8 @@ template draw_texture_template*(drawtype, color, function, secondfunc: untyped):
h -= texture_size.y/2
for i in vertex:
- glTexCoord2f((-x + i.x - w + texture_size.x) / width, 1f - ((-y + i.y - h + texture_size.y) / texture_size.y))
+ glTexCoord2f((-x + i.x - w + texture_size.x) / width,
+ 1f - ((-y + i.y - h + texture_size.y) / texture_size.y))
glVertex2f(i.x, i.y)
glEnd()
@@ -174,7 +164,7 @@ template draw_texture_template*(drawtype, color, function, secondfunc: untyped):
glDisable(GL_TEXTURE_2D)
-method enableShadow*(self: DrawableRef, val: bool) {.base.} =
+method enableShadow*(self: DrawableRef, val: bool = true) {.base.} =
## Enables shadow, when `val` is true.
self.shadow = val
@@ -225,10 +215,7 @@ method setCornerRadius*(self: DrawableRef, radius: float) {.base.} =
##
## Arguments:
## - `radius` is a new corner radius.
- self.border_radius_lefttop = radius
- self.border_radius_righttop = radius
- self.border_radius_leftbottom = radius
- self.border_radius_rightbottom = radius
+ self.border_radius = [radius, radius, radius, radius]
method setCornerRadius*(self: DrawableRef, r1, r2, r3, r4: float) {.base.} =
## Changes corner radius.
@@ -238,20 +225,14 @@ method setCornerRadius*(self: DrawableRef, r1, r2, r3, r4: float) {.base.} =
## - `r2` is a new right-top radius.
## - `r3` is a new right-bottm radius.
## - `r4` is a new left-bottm radius.
- self.border_radius_lefttop = r1
- self.border_radius_righttop = r2
- self.border_radius_rightbottom = r3
- self.border_radius_leftbottom = r4
+ self.border_radius = [r1, r2, r3, r4]
method setCornerDetail*(self: DrawableRef, detail: int) {.base.} =
## Changes corner detail.
##
## Arguments:
## - `detail` is a new corner detail.
- self.border_detail_lefttop = detail
- self.border_detail_righttop = detail
- self.border_detail_leftbottom = detail
- self.border_detail_rightbottom = detail
+ self.border_detail = [detail, detail, detail, detail]
method setCornerDetail*(self: DrawableRef, d1, d2, d3, d4: int) {.base.} =
## Changes corner detail.
@@ -261,10 +242,7 @@ method setCornerDetail*(self: DrawableRef, d1, d2, d3, d4: int) {.base.} =
## - `d2` is a new right-top detail.
## - `d3` is a new right-bottm detail.
## - `d4` is a new left-bottm detail.
- self.border_detail_lefttop = d1
- self.border_detail_righttop = d2
- self.border_detail_leftbottom = d4
- self.border_detail_rightbottom = d3
+ self.border_detail = [d1, d2, d3, d4]
method setTexture*(self: DrawableRef, texture: GlTextureObj) {.base.} =
## Changes drawable texture.
@@ -289,16 +267,19 @@ method setStyle*(self: DrawableRef, s: StyleSheetRef) {.base.} =
# background-image: "assets/img.jpg"
of "background-image":
self.loadTexture(i.value)
- # background: "path/to/img.jpg"
- # background: rgb(125, 82, 196)
- # background: "img.jpg" #f6f
+ # background: "url(path/to/img.jpg)"
+ # background: "rgb(125, 82, 196)"
+ # background: "url(img.jpg) #f6f"
of "background":
+ # #fff | rgba(1, 1, 1)
if i.value.match(re"\A\s*(rgba?\([^\)]+\)\s*|#[a-f0-9]{3,8})\s*\Z", matches):
let tmpclr = Color(matches[0])
if not tmpclr.isNil():
self.setColor(tmpclr)
+ # url(path/to/image)
elif i.value.match(re"\A\s*url\(([^\)]+)\)\s*\Z", matches):
self.loadTexture(matches[0])
+ # url(path to image) #fff | rgba(1, 1, 1)
elif i.value.match(re"\A\s*url\(([^\)]+)\)\s+(rgba?\([^\)]+\)\s*|#[a-f0-9]{3,8})\s*\Z", matches):
self.loadTexture(matches[0])
let tmpclr = Color(matches[1])
diff --git a/src/nodesnim/graphics/gradient_drawable.nim b/src/nodesnim/graphics/gradient_drawable.nim
index bbd05817..f15e81a2 100644
--- a/src/nodesnim/graphics/gradient_drawable.nim
+++ b/src/nodesnim/graphics/gradient_drawable.nim
@@ -12,18 +12,16 @@ import
type
GradientDrawableObj* = object of DrawableObj
- corners*: tuple[p0, p1, p2, p3: ColorRef]
+ corners*: array[4, ColorRef]
GradientDrawableRef* = ref GradientDrawableObj
proc GradientDrawable*: GradientDrawableRef =
drawablepattern(GradientDrawableRef)
- result.corners = (Color(1f, 1f, 1f, 1.0),
+ result.corners = [Color(1f, 1f, 1f, 1.0),
Color(1f, 1f, 1f, 1.0),
Color(1f, 1f, 1f, 1.0),
- Color(1f, 1f, 1f, 1.0))
-
-let shadow_color: ColorRef = Color(0f, 0f, 0f, 0.5f)
+ Color(1f, 1f, 1f, 1.0)]
template draw_template*(drawtype, color, function, secondfunc: untyped, is_gradient: bool = true): untyped =
@@ -76,9 +74,6 @@ method draw*(self: GradientDrawableRef, x1, y1, width, height: float) =
if self.border_width > 0f:
draw_template(GL_LINE_LOOP, self.border_color, glLineWidth(self.border_width), glLineWidth(1), false)
-method setCornerColors*(self: GradientDrawableRef, corners: tuple[p0, p1, p2, p3: ColorRef]) {.base.} =
- self.corners = corners
-
method setCornerColors*(self: GradientDrawableRef, c0, c1, c2, c3: ColorRef) {.base.} =
## Changes corners colors
##
@@ -87,10 +82,23 @@ method setCornerColors*(self: GradientDrawableRef, c0, c1, c2, c3: ColorRef) {.b
## - `c1` is right-top color.
## - `c2` is right-bottom color.
## - `c3` is left-bottom color.
- self.corners[0] = c0
- self.corners[1] = c1
- self.corners[2] = c2
- self.corners[3] = c3
+ self.corners = [c0, c1, c2, c3]
+
+method setCornerColors*(self: GradientDrawableRef, corners: array[4, ColorRef]) {.base.} =
+ ## Changes corners colors
+ ##
+ ## See also:
+ ## * `setCornerColors method <#setCornerColors.e,GradientDrawableRef,ColorRef,ColorRef,ColorRef,ColorRef>`_
+ ## * `setCornerColors(GradientDrawableRef, ColorRef) method <#setCornerColors.e,GradientDrawableRef,ColorRef>`_
+ self.corners = corners
+
+method setCornerColors*(self: GradientDrawableRef, clr: ColorRef) {.base.} =
+ ## Changes corners colors
+ ##
+ ## See also:
+ ## * `setCornerColors method <#setCornerColors.e,GradientDrawableRef,ColorRef,ColorRef,ColorRef,ColorRef>`_
+ ## * `setCornerColors(GradientDrawableRef, array[4, ColorRef]) method <#setCornerColors.e,GradientDrawableRef,array[,ColorRef]>`_
+ self.corners = [Color(clr), Color(clr), Color(clr), Color(clr)]
method setStyle*(self: GradientDrawableRef, s: StyleSheetRef) =
## Sets a new stylesheet.
@@ -102,7 +110,7 @@ method setStyle*(self: GradientDrawableRef, s: StyleSheetRef) =
of "corner-color":
let tmp = i.value.split(" ")
if tmp.len() == 1:
- self.setCornerColors(Color(tmp[0]), Color(tmp[0]), Color(tmp[0]), Color(tmp[0]))
+ self.setCornerColors(Color(tmp[0]))
elif tmp.len() == 4:
self.setCornerColors(Color(tmp[0]), Color(tmp[1]), Color(tmp[2]), Color(tmp[3]))
else:
diff --git a/src/nodesnim/nodes/animation_player.nim b/src/nodesnim/nodes/animation_player.nim
index 8c2c8373..12d65220 100644
--- a/src/nodesnim/nodes/animation_player.nim
+++ b/src/nodesnim/nodes/animation_player.nim
@@ -8,10 +8,6 @@ import
type
- AnimationMode* {.pure, size: sizeof(int8).} = enum
- ANIMATION_NORMAL,
- ANIMATION_EASE,
- ANIMATION_BEZIER
AnimationObject* = object
states: seq[tuple[tick: int, value: float]]
obj: ptr float
@@ -41,23 +37,28 @@ proc AnimationPlayer*(name: string = "AnimationPlayer"): AnimationPlayerRef =
result.mode = ANIMATION_NORMAL
-proc ease(self: AnimationPlayerRef, states: seq[tuple[tick: int, value: float]]): float =
- var time = (self.tick - states[0].tick).float / ((states[1].tick - states[0].tick).float / 2.0)
+# --- Private --- #
+proc ease(self: AnimationPlayerRef,
+ states: seq[tuple[tick: int, value: float]]): float =
+ var time = (self.tick - states[0].tick).float /
+ ((states[1].tick - states[0].tick).float / 2.0)
let diff = states[1].value - states[0].value
if time < 1:
return diff / 2 * time * time + states[0].value
time -= 1
- return -diff / 2 * (time * (time - 2) - 1) + states[0].value
+ -diff / 2 * (time * (time - 2) - 1) + states[0].value
-proc bezier(self: AnimationPlayerRef, states: seq[tuple[tick: int, value: float]], current: float): float =
+proc bezier(self: AnimationPlayerRef,
+ states: seq[tuple[tick: int, value: float]], current: float): float =
let
step = 1f / (states[1].tick - states[0].tick).float
t = step * (self.tick - states[0].tick).float
diff = states[1].value - states[0].value
result = cubic_bezier(t, 0.0, self.bezier[0], self.bezier[1], 1.0)
- result = states[0].value + diff*result
+ return states[0].value + diff*result
+# --- Public --- #
method addState*(self: AnimationPlayerRef, obj: ptr float, states: seq[tuple[tick: int, value: float]]) {.base.} =
## Adds a new state to AnimationPlayer.
self.objects.add(AnimationObject(
@@ -65,14 +66,15 @@ method addState*(self: AnimationPlayerRef, obj: ptr float, states: seq[tuple[tic
obj: obj
))
+
method draw*(self: AnimationPlayerRef, w: GLfloat, h: GLfloat) =
## This uses in the `window.nim`.
if self.is_played:
if self.tick > self.duration:
- self.tick = 0
- if not self.loop:
- self.is_played = false
- return
+ self.tick = 0
+ if not self.loop:
+ self.is_played = false
+ return
var
current_states: seq[tuple[tick: int, value: float]] = @[]
@@ -85,21 +87,22 @@ method draw*(self: AnimationPlayerRef, w: GLfloat, h: GLfloat) =
if self.tick == obj.states[i].tick:
current[] = obj.states[i].value
break
- if current_states.len() == 1:
+ if current_states.len == 1:
for i in 0..obj.states.high:
if current_states[0].tick < obj.states[i].tick:
current_states.add(obj.states[i])
break
- if current_states.len() == 2:
- if self.mode == ANIMATION_NORMAL:
+ if current_states.len == 2:
+ case self.mode
+ of ANIMATION_NORMAL:
let
diff_time: float = (current_states[1].tick - current_states[0].tick).float
diff: float = current_states[1].value - current_states[0].value
current[] = current_states[0].value + (self.tick - current_states[0].tick).float/diff_time * diff
- elif self.mode == ANIMATION_EASE:
- current[] = self.ease(current_states)
- elif self.mode == ANIMATION_BEZIER:
+ of ANIMATION_EASE:
+ current[] = ease(self, current_states)
+ of ANIMATION_BEZIER:
current[] = bezier(self, current_states, current[])
current_states = @[]
diff --git a/src/nodesnim/nodes/canvas.nim b/src/nodesnim/nodes/canvas.nim
index 45cd77ab..370478a0 100644
--- a/src/nodesnim/nodes/canvas.nim
+++ b/src/nodesnim/nodes/canvas.nim
@@ -2,10 +2,10 @@
## Canvas is the root type of all 2D and Control nodes.
##
## Canvas used for drawing primitive geometry.
+import ../thirdparty/sdl2 except Color
import
math,
../thirdparty/opengl,
- ../thirdparty/sdl2,
../thirdparty/sdl2/image,
../core/vector2,
@@ -53,7 +53,7 @@ proc Canvas*(name: string = "Canvas"): CanvasRef =
result.canvas_texture = 0
result.surface = createRGBSurface(
0, 40, 40, 32,
- 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000'u32)
+ 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000u32)
result.renderer = result.surface.createSoftwareRenderer()
result.kind = CANVAS_NODE
result.type_of_node = NODE_TYPE_CONTROL
@@ -120,6 +120,10 @@ method move*(self: CanvasRef, vec2: Vector2Obj) {.base, inline.} =
##
## Arguments:
## - `vec2`: how much to add to the position on the X,Y axes.
+ ##
+ ## See also:
+ ## - `move method <#move.e,CanvasRef,float,float>`_
+ ## - `moveTo method <#moveTo.e,CanvasRef,Vector2Obj>`_
self.position += vec2
self.anchor.clear()
@@ -129,9 +133,30 @@ method move*(self: CanvasRef, x, y: float) {.base, inline.} =
## Arguments:
## - `x`: how much to add to the position on the X axis.
## - `y`: how much to add to the position on the Y axis.
+ ##
+ ## See also:
+ ## - `move method <#move.e,CanvasRef,Vector2Obj>`_
+ ## - `moveTo method <#moveTo.e,CanvasRef,float,float>`_
self.position += Vector2(x, y)
self.anchor.clear()
+method moveTo*(self: CanvasRef, x, y: float) {.base, inline.} =
+ ## Change node position.
+ ##
+ ## Arguments:
+ ## - `x`: how much to add to the position on the X axis.
+ ## - `y`: how much to add to the position on the Y axis.
+ self.position = Vector2(x, y)
+ self.anchor.clear()
+
+method moveTo*(self: CanvasRef, vec2: Vector2Obj) {.base, inline.} =
+ ## Change node position.
+ ##
+ ## Arguments:
+ ## - `vec2`: how much to add to the position on the X,Y axes.
+ self.position = vec2
+ self.anchor.clear()
+
method resize*(self: CanvasRef, w, h: GLfloat, save_anchor: bool = false) {.base.} =
## Resizes canvas.
##
@@ -178,15 +203,25 @@ method setAnchor*(self: CanvasRef, x1, y1, x2, y2: float) {.base.} =
method setSizeAnchor*(self: CanvasRef, anchor: Vector2Obj) {.base.} =
+ ## Changes the size anchor to the size of the parent.
self.size_anchor = anchor
method setSizeAnchor*(self: CanvasRef, x, y: float) {.base.} =
+ ## Changes the size anchor to the size of the parent.
self.size_anchor = Vector2(x, y)
# --- Draw functions --- #
proc bezier*(canvas: CanvasRef, x1, y1, x2, y2, x3, y3: GLfloat, color: ColorRef) =
## Draws a quadric bezier curve at 3 points.
+ ##
+ ## Arguments:
+ ## - `x1` `y1` - first point.
+ ## - `x2` `y2` - second point.
+ ## - `x3` `y3` - third point.
+ ##
+ ## See also:
+ ## - `cubicBezier proc <#cubicBezier,CanvasRef,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,ColorRef>`_
loadColor(color)
for pnt in bezier_iter(0.001, Vector2(x1, y1), Vector2(x2, y2), Vector2(x3, y3)):
canvas.renderer.drawPoint(pnt.x.cint, pnt.y.cint)
@@ -207,8 +242,17 @@ proc circle*(canvas: CanvasRef, x, y, radius: GLfloat, color: ColorRef, quality:
canvas.renderer.drawPoint((x + radius*cos(angle)).cint, (y + radius*sin(angle)).cint)
loadGL(canvas)
-proc cubic_bezier*(canvas: CanvasRef, x1, y1, x2, y2, x3, y3, x4, y4: GLfloat, color: ColorRef) =
- ## Draws a quadric bezier curve at 3 points.
+proc cubicBezier*(canvas: CanvasRef, x1, y1, x2, y2, x3, y3, x4, y4: GLfloat, color: ColorRef) =
+ ## Draws a quadric bezier curve at 4 points.
+ ##
+ ## Arguments:
+ ## - `x1` `y1` - first point.
+ ## - `x2` `y2` - second point.
+ ## - `x3` `y3` - third point.
+ ## - `x4` `y4` - fourth point.
+ ##
+ ## See also:
+ ## - `bezier proc <#bezier,CanvasRef,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,ColorRef>`_
loadColor(color)
for pnt in cubic_bezier_iter(0.001, Vector2(x1, y1), Vector2(x2, y2), Vector2(x3, y3), Vector2(x4, y4)):
canvas.renderer.drawPoint(pnt.x.cint, pnt.y.cint)
diff --git a/src/nodesnim/nodes/node.nim b/src/nodesnim/nodes/node.nim
index 4b6455cf..6b1a231f 100644
--- a/src/nodesnim/nodes/node.nim
+++ b/src/nodesnim/nodes/node.nim
@@ -13,20 +13,22 @@ import
type
+ NodeHandler* = proc(self: NodeRef)
+ NodeEvHandler* = proc(self: NodeRef, event: InputEvent)
NodeObj* = object of RootObj
kind*: NodeKind
- type_of_node*: NodeTypes
- visible*: Visibility
- is_ready*: bool
- pausemode*: PauseMode ## Pause mode, by default is INHERIT.
- name*: string ## Node name.
- parent*: NodeRef ## Node parent.
- children*: seq[NodeRef] ## Node children.
- on_enter*: proc(self: NodeRef) ## This called when scene changed.
- on_exit*: proc(self: NodeRef) ## This called when exit from the scene.
- on_input*: proc(self: NodeRef, event: InputEvent) ## This called on user input.
- on_ready*: proc(self: NodeRef) ## This called when the scene changed and the `enter` was called.
- on_process*: proc(self: NodeRef) ## This called every frame.
+ type_of_node*: NodeTypes ## default, gui, 2d or 3d.
+ visibility*: Visibility ## visible, invisible or gone.
+ is_ready*: bool ## true, when scene is ready.
+ pausemode*: PauseMode ## Pause mode, by default is INHERIT.
+ name*: string ## Node name.
+ parent*: NodeRef ## Node parent.
+ children*: seq[NodeRef] ## Node children.
+ on_enter*: NodeHandler ## This called when scene changed.
+ on_exit*: NodeHandler ## This called when exit from the scene.
+ on_input*: NodeEvHandler ## This called on user input.
+ on_ready*: NodeHandler ## This called when the scene changed and the `enter` was called.
+ on_process*: NodeHandler ## This called every frame.
NodeRef* = ref NodeObj
@@ -39,7 +41,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
@@ -54,15 +56,22 @@ method addChild*(self: NodeRef, child: NodeRef) {.base.} =
##
## Arguments:
## - `child`: other node.
+ ##
+ ## See also:
+ ## - `addChildren method <#addChildren.e,NodeRef,varargs[NodeRef]>`_
+ ## - `getChild method <#getChild.e,NodeRef,int>`_
self.children.add(child)
child.parent = self
-method addChilds*(self: NodeRef, childs: varargs[NodeRef]) {.base.} =
+method addChildren*(self: NodeRef, childs: varargs[NodeRef]) {.base.} =
## Adds new child in current node.
##
## Arguments:
## - `child`: other node.
+ ##
+ ## See also:
+ ## - `addChild method <#addChild.e,NodeRef,NodeRef>`_
for node in childs:
self.addChild(node)
@@ -80,29 +89,42 @@ method getChild*(self: NodeRef, index: int): NodeRef {.base.} =
##
## Arguments:
## - `index`: child index.
+ ##
+ ## See also:
+ ## - `addChild method <#addChild.e,NodeRef,NodeRef>`_
+ ## - `getChildCount method <#getChildCount.e,NodeRef>`_
self.children[index]
method getChildCount*(self: NodeRef): int {.base, inline.} =
## Returns child count.
+ ##
+ ## See also:
+ ## - `getChild method <#getChild.e,NodeRef,int>`_
self.children.len()
method getChildIndex*(self: NodeRef, name: string): int {.base.} =
## Returns `child` index or -1, if another node is not the child.
+ ##
+ ## See also:
+ ## - `getChildIndex method <#getChildIndex.e,NodeRef,NodeRef>`_
var i = 0
for node in self.children:
if node.name == name:
return i
inc i
- return -1
+ -1
method getChildIndex*(self: NodeRef, child: NodeRef): int {.base.} =
## Returns `child` index or -1, if another node is not the child.
+ ##
+ ## See also:
+ ## - `getChildIndex method <#getChildIndex.e,NodeRef,string>`_
var i = 0
for node in self.children:
if child == node:
return i
inc i
- return -1
+ -1
method getChildIter*(self: NodeRef): seq[NodeRef] {.base.} =
## Returns all children iter.
@@ -171,14 +193,14 @@ method handle*(self: NodeRef, event: InputEvent, mouse_on: var NodeRef) {.base.}
## This used in the Window object.
discard
-method hasNode*(self: NodeRef, name: string): bool {.base.} =
+method hasNode*(self: NodeRef, name: string): bool {.base, inline.} =
## Returns true, if a node with name `name` in children.
##
## Arguments:
## - `name`: node name.
self.getChildIndex(name) != -1
-method hasNode*(self: NodeRef, other: NodeRef): bool {.base.} =
+method hasNode*(self: NodeRef, other: NodeRef): bool {.base, inline.} =
## Returns true, if `other` in self children.
##
## Arguments:
@@ -187,10 +209,10 @@ method hasNode*(self: NodeRef, other: NodeRef): bool {.base.} =
method hasParent*(self: NodeRef): bool {.base, inline.} =
## Returns true, when node has parent.
- self.parent != nil
+ not self.parent.isNil()
method hide*(self: NodeRef) {.base.} =
- self.visible = INVISIBLE
+ self.visibility = INVISIBLE
method postdraw*(self: NodeRef, w, h: GLfloat) {.base.} =
## Draws node.
@@ -205,6 +227,9 @@ method removeChild*(self: NodeRef, index: int) {.base.} =
##
## Arguments:
## - `index`: child index.
+ ##
+ ## See also:
+ ## - `addChild method <#addChild.e,NodeRef,NodeRef>`_
self.children[index].parent = nil
self.children.delete(index)
@@ -213,12 +238,12 @@ method removeChild*(self: NodeRef, other: NodeRef) {.base.} =
##
## Arguments:
## - `other`: other node.
- var index: int = self.getChildIndex(other)
+ let index: int = self.getChildIndex(other)
if index != -1:
self.removeChild(index)
method show*(self: NodeRef) {.base.} =
- self.visible = VISIBLE
+ self.visibility = VISIBLE
method delete*(self: NodeRef) {.base.} =
## Deletes current node.
diff --git a/src/nodesnim/nodes/scene.nim b/src/nodesnim/nodes/scene.nim
index 44a7129a..74ddb22b 100644
--- a/src/nodesnim/nodes/scene.nim
+++ b/src/nodesnim/nodes/scene.nim
@@ -36,10 +36,11 @@ proc Scene*(name: string = "Scene"): SceneRef =
method drawScene*(scene: SceneRef, w, h: GLfloat, paused: bool) {.base.} =
## Draws scene
## This used in the window.nim.
+ scene.on_process(scene)
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()
@@ -57,17 +58,13 @@ method drawScene*(scene: SceneRef, w, h: GLfloat, paused: bool) {.base.} =
child.Node3DRef.calcGlobalPosition3()
gluPerspective(45.0, w/h, 1.0, 5000.0)
if current_camera.isNil():
- gluLookAt(0, 0, -1,
- 0, 0, 1,
- 0, 1, 0)
+ gluLookAt(0, 0, -1, 0, 0, 1, 0, 1, 0)
else:
let
pos = current_camera.global_translation
front = current_camera.front + pos
up = current_camera.up
- gluLookAt(pos.x, pos.y, pos.z,
- front.x, front.y, front.z,
- up.x, up.y, up.z)
+ gluLookAt(pos.x, pos.y, pos.z, front.x, front.y, front.z, up.x, up.y, up.z)
if not child.is_ready:
child.on_ready(child)
@@ -77,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()
@@ -101,11 +98,12 @@ method exit*(scene: SceneRef) {.base.} =
method handleScene*(scene: SceneRef, event: InputEvent, mouse_on: var NodeRef, paused: bool) {.base.} =
## Handles user input. This called on any input.
+ scene.on_input(scene, event)
var childs = scene.getChildIter()
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)
diff --git a/src/nodesnim/nodes2d/animated_sprite.nim b/src/nodesnim/nodes2d/animated_sprite.nim
index 49562a94..7bf37408 100644
--- a/src/nodesnim/nodes2d/animated_sprite.nim
+++ b/src/nodesnim/nodes2d/animated_sprite.nim
@@ -55,11 +55,8 @@ method draw*(self: AnimatedSpriteRef, w, h: GLfloat) =
self.rect_size = texture.size
# Recalculate position.
- self.position = self.timed_position
- if self.centered:
- self.position = self.timed_position - self.rect_size/2
- else:
- self.position = self.timed_position
+ procCall self.Node2DRef.draw(w, h)
+ self.calcGlobalPosition()
let
x = -w/2 + self.global_position.x
@@ -69,6 +66,7 @@ method draw*(self: AnimatedSpriteRef, w, h: GLfloat) =
if frame >= 0 and frame < frames_count:
var texture = self.animations[self.animation].frames[frame]
if texture.texture > 0'u32:
+ glPushMatrix()
if self.centered:
glTranslatef(x + (self.rect_size.x / 2), y - (self.rect_size.y / 2), self.z_index_global)
self.position = self.rect_size / 2
@@ -94,13 +92,7 @@ method draw*(self: AnimatedSpriteRef, w, h: GLfloat) =
glEnd()
glDisable(GL_DEPTH_TEST)
glDisable(GL_TEXTURE_2D)
- glRotatef(-self.rotation, 0, 0, 1)
- if self.centered:
- glTranslatef(-x - (self.rect_size.x / 2), -y + (self.rect_size.y / 2), -self.z_index_global)
- self.position = self.timed_position - self.rect_size/2
- else:
- glTranslatef(-x, -y, -self.z_index_global)
- self.position = self.timed_position
+ glPopMatrix()
else:
self.rect_size = Vector2()
@@ -126,10 +118,6 @@ method duplicate*(self: AnimatedSpriteRef): AnimatedSpriteRef {.base.} =
## Duplicates AnimatedSprite object and create a new AnimatedSprite.
self.deepCopy()
-method getGlobalMousePosition*(self: AnimatedSpriteRef): Vector2Obj {.inline.} =
- ## Returns mouse position.
- Vector2Obj(x: last_event.x, y: last_event.y)
-
method addAnimation*(self: AnimatedSpriteRef, name: string, speed: float = 2f) {.base.} =
## Adds a new animation to the AnimatedSprite animations.
##
diff --git a/src/nodesnim/nodes2d/camera2d.nim b/src/nodesnim/nodes2d/camera2d.nim
index ba73bae6..2f9c3e45 100644
--- a/src/nodesnim/nodes2d/camera2d.nim
+++ b/src/nodesnim/nodes2d/camera2d.nim
@@ -15,14 +15,14 @@ import
type
Camera2DObj* = object of Node2DObj
- current*, smooth*: bool
+ smooth*: bool
smooth_speed*: float
target*: NodeRef
- limit*: AnchorObj
+ limit*: AnchorObj ## left, top, right, bottom
Camera2DRef* = ref Camera2DObj
-var nodes: seq[Camera2DRef] = @[]
+var current_camera: Camera2DRef = nil
proc Camera2D*(name: string = "Camera2D"): Camera2DRef =
@@ -35,11 +35,9 @@ proc Camera2D*(name: string = "Camera2D"): Camera2DRef =
nodepattern(Camera2DRef)
node2dpattern()
result.limit = Anchor(-100000, -100000, 100000, 100000)
- result.current = false
result.smooth = false
result.smooth_speed = 0.1
result.kind = CAMERA_2D_NODE
- nodes.add(result)
method changeTarget*(self: Camera2DRef, target: NodeRef) {.base.} =
@@ -57,6 +55,9 @@ method changeSmoothSpeed*(self: Camera2DRef, speed: float) {.base.} =
method disableSmooth*(self: Camera2DRef) {.base.} =
## Disables smooth mode.
+ ##
+ ## See also:
+ ## - `enableSmooth method <#enableSmooth.e,Camera2DRef,float>`_
self.smooth = false
@@ -65,7 +66,7 @@ method draw*(self: Camera2DRef, w, h: GLfloat) =
{.warning[LockLevel]: off.}
procCall self.Node2DRef.draw(w, h)
- if self.target != nil and self.current:
+ if self.target != nil and self == current_camera:
var root = self.getRootNode().CanvasRef
let
x = self.target.CanvasRef.position.x
@@ -93,15 +94,20 @@ method enableSmooth*(self: Camera2DRef, speed: float = 0.1) {.base.} =
##
## Arguments:
## - `speed` is a smooth speed. The closer to 0, the smoother the camera. The default is 0.1.
+ ##
+ ## See also:
+ ## - `disableSmooth method <#disableSmooth.e,Camera2DRef>`_
self.smooth = true
self.smooth_speed = speed
+method isCurrent*(self: Camera2DRef): bool {.base.} =
+ self == current_camera
+
+
method setCurrent*(self: Camera2DRef) {.base.} =
## Changes the current camera. It also automatically disable other cameras.
- for c in nodes:
- c.current = false
- self.current = true
+ current_camera = self
method setLimit*(self: Camera2DRef, x1, y1, x2, y2: float) {.base.} =
diff --git a/src/nodesnim/nodes2d/collision_shape2d.nim b/src/nodesnim/nodes2d/collision_shape2d.nim
index 5bbb5e4d..182a534b 100644
--- a/src/nodesnim/nodes2d/collision_shape2d.nim
+++ b/src/nodesnim/nodes2d/collision_shape2d.nim
@@ -22,10 +22,6 @@ when defined(debug):
type
- CollisionShape2DType* {.size: sizeof(int8), pure.} = enum
- COLLISION_SHAPE_2D_RECTANGLE,
- COLLISION_SHAPE_2D_CIRCLE,
- COLLISION_SHAPE_2D_POLYGON
CollisionShape2DObj* = object of Node2DObj
disable*: bool
x1*, y1*, radius*: float
@@ -99,6 +95,7 @@ when defined(debug):
glColor4f(0.5, 0.5, 0.5, 0.7)
else:
glColor4f(0.5, 0.6, 0.9, 0.7)
+ glEnable(GL_DEPTH_TEST)
case self.shape_type
of COLLISION_SHAPE_2D_RECTANGLE:
@@ -116,6 +113,7 @@ when defined(debug):
glVertex3f(x + vec2.x, y - vec2.y, self.z_index_global)
glEnd()
glColor4f(1, 1, 1, 1)
+ glDisable(GL_DEPTH_TEST)
method duplicate*(self: CollisionShape2DRef): CollisionShape2DRef {.base.} =
diff --git a/src/nodesnim/nodes2d/kinematic_body2d.nim b/src/nodesnim/nodes2d/kinematic_body2d.nim
index f07e46dc..161185ea 100644
--- a/src/nodesnim/nodes2d/kinematic_body2d.nim
+++ b/src/nodesnim/nodes2d/kinematic_body2d.nim
@@ -96,7 +96,7 @@ method moveAndCollide*(self: KinematicBody2DRef, vel: Vector2Obj) {.base.} =
## - `vel` is a velocity vector.
# TODO: normal algorithn
let
- biggest = abs(if max(vel.x, vel.y) == 0.0: min(vel.x, vel.y) else: max(vel.x, vel.y))
+ biggest = max(vel.x.abs(), vel.y.abs())
step = Vector2(vel.x/biggest, vel.y/biggest)
vec = vel.abs()
scene = self.getRootNode()
diff --git a/src/nodesnim/nodes2d/sprite.nim b/src/nodesnim/nodes2d/sprite.nim
index a17569df..880dcc02 100644
--- a/src/nodesnim/nodes2d/sprite.nim
+++ b/src/nodesnim/nodes2d/sprite.nim
@@ -47,7 +47,7 @@ method draw*(self: SpriteRef, w, h: GLfloat) =
# Recalculate position.
procCall self.Node2DRef.draw(w, h)
- self.CanvasRef.calcGlobalPosition()
+ self.calcGlobalPosition()
let
x = -w/2 + self.global_position.x
@@ -55,6 +55,7 @@ method draw*(self: SpriteRef, w, h: GLfloat) =
# Draw
if self.texture.texture > 0'u32:
+ glPushMatrix()
if self.centered:
glTranslatef(x + (self.rect_size.x / 2), y - (self.rect_size.y / 2), self.z_index_global)
self.position = self.rect_size / 2
@@ -80,13 +81,7 @@ method draw*(self: SpriteRef, w, h: GLfloat) =
glEnd()
glDisable(GL_DEPTH_TEST)
glDisable(GL_TEXTURE_2D)
- glRotatef(-self.rotation, 0, 0, 1)
- if self.centered:
- glTranslatef(-x - (self.rect_size.x / 2), -y + (self.rect_size.y / 2), -self.z_index_global)
- self.position = self.timed_position - self.rect_size/2
- else:
- glTranslatef(-x, -y, -self.z_index_global)
- self.position = self.timed_position
+ glPopMatrix()
else:
self.rect_size = Vector2()
diff --git a/src/nodesnim/nodes2d/tilemap.nim b/src/nodesnim/nodes2d/tilemap.nim
index 532ab63f..14383547 100644
--- a/src/nodesnim/nodes2d/tilemap.nim
+++ b/src/nodesnim/nodes2d/tilemap.nim
@@ -12,14 +12,11 @@ import
type
- TileMapMode* {.pure, size: sizeof(int8).} = enum
- TILEMAP_2D, ## Default 2D mode.
- TILEMAP_ISOMETRIC ## Isometric mode.
TileMapObj* = object of Node2DObj
mode*: TileMapMode
map_size*: tuple[x, y, z: int]
tileset*: TileSetObj
- map*: seq[Vector2Ref]
+ map*: seq[Vector2Obj]
TileMapRef = ref TileMapObj
@@ -51,8 +48,10 @@ method draw*(self: TileMapRef, w, h: GLfloat) =
viewport[2] = self.map_size.x-1
glEnable(GL_TEXTURE_2D)
+ glColor4f(1, 1, 1, 1)
case self.mode
of TILEMAP_2D:
+ glEnable(GL_DEPTH_TEST)
for z in 0.. 0'u32:
+ let height = (self.texture.size.y/self.texture.size.x).float
+ glPushMatrix()
+ glTranslatef(self.global_translation.x, self.global_translation.y, self.global_translation.z)
+ glRotatef(self.global_rotation.x, 1, 0, 0)
+ glRotatef(self.global_rotation.y, 0, 1, 0)
+ glRotatef(self.global_rotation.z, 0, 0, 1)
+ glScalef(self.scale.x, self.scale.y, self.scale.z)
+ glColor4f(self.filter.r, self.filter.g, self.filter.b, self.filter.a)
+
+ glEnable(GL_TEXTURE_2D)
+ glEnable(GL_DEPTH_TEST)
+ glBindTexture(GL_TEXTURE_2D, self.texture.texture)
+
+ glBegin(GL_QUADS)
+ glTexCoord2f(0, 0)
+ glVertex3f(-1, height, 0)
+ glTexCoord2f(0, 1)
+ glVertex3f(-1, -height, 0)
+ glTexCoord2f(1, 1)
+ glVertex3f(1, -height, 0)
+ glTexCoord2f(1, 0)
+ glVertex3f(1, height, 0)
+ glEnd()
+
+ glDisable(GL_DEPTH_TEST)
+ glDisable(GL_TEXTURE_2D)
+ glPopMatrix()
+
+method duplicate*(self: Sprite3DRef): Sprite3DRef {.base.} =
+ ## Duplicates Sprite object and create a new Sprite.
+ self.deepCopy()
+
+method loadTexture*(self: Sprite3DRef, file: string, mode = GL_RGB) {.base.} =
+ ## Loads a new texture from file.
+ ##
+ ## Arguments:
+ ## - `file` is a texture path.
+ ## - `mode` is a GLenum. can be GL_RGB or GL_RGBA.
+ self.texture = load(file, mode)
+
+method setTexture*(self: Sprite3DRef, texture: GlTextureObj) {.base.} =
+ ## Loads a new texture from file.
+ ##
+ ## Arguments:
+ ## - `texture` is a GlTexture object.
+ self.texture = texture
diff --git a/src/nodesnim/nodescontrol.nim b/src/nodesnim/nodescontrol.nim
index 64034585..5117a765 100644
--- a/src/nodesnim/nodescontrol.nim
+++ b/src/nodesnim/nodescontrol.nim
@@ -18,10 +18,11 @@ import
nodescontrol/counter,
nodescontrol/switch,
nodescontrol/subwindow,
- nodescontrol/checkbox
+ nodescontrol/checkbox,
+ nodescontrol/tooltip
export
control, color_rect, texture_rect, label, button,
box, hbox, vbox, grid_box, edittext, scroll, progress_bar,
slider, popup, texture_button, texture_progress_bar,
- counter, switch, subwindow, checkbox
+ counter, switch, subwindow, checkbox, tooltip
diff --git a/src/nodesnim/nodescontrol/box.nim b/src/nodesnim/nodescontrol/box.nim
index 41ff9e71..c74a987d 100644
--- a/src/nodesnim/nodescontrol/box.nim
+++ b/src/nodesnim/nodescontrol/box.nim
@@ -95,6 +95,9 @@ method setChildAnchor*(self: BoxRef, anchor: AnchorObj) {.base.} =
##
## Arguments:
## - `anchor` - Anchor object.
+ ##
+ ## See also:
+ ## - `setChildAnchor method <#setChildAnchor.e,BoxRef,float,float,float,float>`_
self.child_anchor = anchor
method setChildAnchor*(self: BoxRef, x1, y1, x2, y2: float) {.base.} =
@@ -103,4 +106,7 @@ method setChildAnchor*(self: BoxRef, x1, y1, x2, y2: float) {.base.} =
## Arguments:
## - `x1` and `y1` is an anchor relative to Box size.
## - `x2` and `y2` is an anchor relative to child size.
+ ##
+ ## See also:
+ ## - `setChildAnchor method <#setChildAnchor.e,BoxRef,AnchorObj>`_
self.child_anchor = Anchor(x1, y1, x2, y2)
diff --git a/src/nodesnim/nodescontrol/button.nim b/src/nodesnim/nodescontrol/button.nim
index 48339fd6..a4faf0c2 100644
--- a/src/nodesnim/nodescontrol/button.nim
+++ b/src/nodesnim/nodescontrol/button.nim
@@ -1,8 +1,8 @@
# author: Ethosa
## Handles mouse clicks.
+import ../thirdparty/sdl2 except Color
import
../thirdparty/opengl,
- ../thirdparty/sdl2,
../core/vector2,
../core/rect2,
diff --git a/src/nodesnim/nodescontrol/control.nim b/src/nodesnim/nodescontrol/control.nim
index 83b2afcb..e851e009 100644
--- a/src/nodesnim/nodescontrol/control.nim
+++ b/src/nodesnim/nodescontrol/control.nim
@@ -19,23 +19,25 @@ import
type
+ ControlXYHandler* = proc(self: ControlRef, x, y: float)
+ ControlHandler* = proc(self: ControlRef)
ControlObj* = object of CanvasObj
hovered*: bool
pressed*: bool
focused*: bool
mousemode*: MouseMode
- padding*: AnchorObj ## Only for Box, VBox, HBox, GridBox and Label objects!
- margin*: AnchorObj ## Only for HBox and VBox objects!
+ padding*: AnchorObj ## Only for Box, VBox, HBox, GridBox and Label objects!
+ margin*: AnchorObj ## Only for HBox and VBox objects!
background*: DrawableRef
- on_mouse_enter*: proc(self: ControlRef, x, y: float): void ## This called when the mouse enters the Control node.
- on_mouse_exit*: proc(self: ControlRef, x, y: float): void ## This called when the mouse exit from the Control node.
- on_click*: proc(self: ControlRef, x, y: float): void ## This called when the user clicks on the Control node.
- on_press*: proc(self: ControlRef, x, y: float): void ## This called when the user holds on the mouse on the Control node.
- on_release*: proc(self: ControlRef, x, y: float): void ## This called when the user no more holds on the mouse.
- on_focus*: proc(self: ControlRef): void ## This called when the Control node gets focus.
- on_unfocus*: proc(self: ControlRef): void ## This called when the Control node loses focus.
+ on_mouse_enter*: ControlXYHandler ## This called when the mouse enters the Control node.
+ on_mouse_exit*: ControlXYHandler ## This called when the mouse exit from the Control node.
+ on_click*: ControlXYHandler ## This called when the user clicks on the Control node.
+ on_press*: ControlXYHandler ## This called when the user holds on the mouse on the Control node.
+ on_release*: ControlXYHandler ## This called when the user no more holds on the mouse.
+ on_focus*: ControlHandler ## This called when the Control node gets focus.
+ on_unfocus*: ControlHandler ## This called when the Control node loses focus.
ControlRef* = ref ControlObj
@@ -143,31 +145,66 @@ method handle*(self: ControlRef, event: InputEvent, mouse_on: var NodeRef) =
self.pressed = false
self.on_release(self, event.x, event.y)
-method setBackground*(self: ControlRef, drawable: DrawableRef) {.base.} =
+method setBackground*(self: ControlRef, drawable: DrawableRef) {.base, inline.} =
+ ## Changes background drawable.
+ ##
+ ## Arguments:
+ ## - `drawable` - can be `DrawableRef` or `GradientDrawableRef`.
self.background = drawable
-method setBackgroundColor*(self: ControlRef, color: ColorRef) {.base.} =
+method setBackgroundColor*(self: ControlRef, color: ColorRef) {.base, inline.} =
## Changes Control background color.
self.background.setColor(color)
-method setMargin*(self: ControlRef, margin: AnchorObj) {.base.} =
+method setMargin*(self: ControlRef, margin: AnchorObj) {.base, inline.} =
## Changes Control margin.
+ ##
+ ## See also:
+ ## - `setMargin method <#setMargin.e,ControlRef,float,float,float,float>`_
self.margin = margin
-method setMargin*(self: ControlRef, x1, y1, x2, y2: float) {.base.} =
+method setMargin*(self: ControlRef, x1, y1, x2, y2: float) {.base, inline.} =
## Changes Control margin.
- self.setMargin(Anchor(x1, y1, x2, y2))
+ ##
+ ## Arguments:
+ ## - `x1` - left margin.
+ ## - `y1` - top margin.
+ ## - `x2` - right margin.
+ ## - `y2` - bottom margin.
+ ##
+ ## See also:
+ ## - `setMargin method <#setMargin.e,ControlRef,AnchorObj>`_
+ self.margin = Anchor(x1, y1, x2, y2)
-method setPadding*(self: ControlRef, padding: AnchorObj) {.base.} =
+method setPadding*(self: ControlRef, padding: AnchorObj) {.base, inline.} =
## Changes Control padding.
+ ##
+ ## See also:
+ ## - `setPadding method <#setPadding.e,ControlRef,float,float,float,float>`_
self.padding = padding
-method setPadding*(self: ControlRef, x1, y1, x2, y2: float) {.base.} =
+method setPadding*(self: ControlRef, x1, y1, x2, y2: float) {.base, inline.} =
## Changes Control padding.
- self.setPadding(Anchor(x1, y1, x2, y2))
+ ##
+ ## Arguments:
+ ## - `x1` - left padding.
+ ## - `y1` - top padding.
+ ## - `x2` - right padding.
+ ## - `y2` - bottom padding.
+ ##
+ ## See also:
+ ## - `setPadding method <#setPadding.e,ControlRef,AnchorObj>`_
+ self.padding = Anchor(x1, y1, x2, y2)
method setStyle*(self: ControlRef, style: StyleSheetRef) {.base.} =
+ ## Changes control node style.
+ ##
+ ## Styles:
+ ## - `size-anchor` - `1`, `1.0`, `0.5 1`
+ ## - `position-anchor` - `1`, `0.5 1 0.5 1`
+ ## - `margin` - `8`, `2 4 6 8`
+ ## - `padding` - `8`, `2 4 6 8`
self.background.setStyle(style)
for i in style.dict:
case i.key
diff --git a/src/nodesnim/nodescontrol/counter.nim b/src/nodesnim/nodescontrol/counter.nim
index 9242757e..6aeb5d7a 100644
--- a/src/nodesnim/nodescontrol/counter.nim
+++ b/src/nodesnim/nodescontrol/counter.nim
@@ -1,8 +1,8 @@
# author: Ethosa
## Number counter box.
+import ../thirdparty/sdl2 except Color
import
../thirdparty/opengl,
- ../thirdparty/sdl2,
../core/vector2,
../core/rect2,
@@ -10,6 +10,7 @@ import
../core/input,
../core/enums,
../core/color,
+ ../core/font,
../nodes/node,
../nodes/canvas,
@@ -44,6 +45,7 @@ proc Counter*(name: string = "Counter"): CounterRef =
result.label = Label()
result.label.mousemode = MOUSEMODE_IGNORE
result.label.parent = result
+ result.label.setTextAlign(0.1, 0.5, 0.1, 0.5)
result.background.setColor(Color(0x212121ff))
result.kind = COUNTER_NODE
@@ -66,14 +68,13 @@ method draw*(self: CounterRef, w, h: GLfloat) =
self.background.draw(x, y, self.rect_size.x, self.rect_size.y)
- self.label.calcGlobalPosition()
- self.label.resize(self.rect_size.x - 40, self.rect_size.y)
- self.label.setTextAlign(0.5, 0.5, 0.5, 0.5)
if self.as_int:
self.label.setText($self.value.int)
else:
self.label.setText($self.value)
- self.label.draw(w, h)
+ self.label.text.renderTo(
+ Vector2(x + self.label.padding.x1, y - self.label.padding.y1),
+ self.rect_size, self.label.text_align)
glColor4f(1f, 1f, 1f, 1f)
@@ -102,7 +103,6 @@ method duplicate*(self: CounterRef): CounterRef {.base.} =
method handle*(self: CounterRef, event: InputEvent, mouse_on: var NodeRef) =
procCall self.ControlRef.handle(event, mouse_on)
-
let
first_button = Rect2(
self.global_position.x + self.rect_size.x - 20, self.global_position.y,
@@ -129,10 +129,16 @@ method handle*(self: CounterRef, event: InputEvent, mouse_on: var NodeRef) =
method setMaxValue*(self: CounterRef, value: float) {.base.} =
## Changes max value, if it more then current `value`.
+ ##
+ ## See also:
+ ## - `setMinValue method <#setMinValue.e,CounterRef,float>`_
if value > self.value:
self.max_value = value
method setMinValue*(self: CounterRef, value: float) {.base.} =
## Changes max value, if it less then current `value`.
+ ##
+ ## See also:
+ ## - `setMaxValue method <#setMaxValue.e,CounterRef,float>`_
if value < self.value:
self.min_value = value
diff --git a/src/nodesnim/nodescontrol/edittext.nim b/src/nodesnim/nodescontrol/edittext.nim
index 0a74e0c0..1ff07cc4 100644
--- a/src/nodesnim/nodescontrol/edittext.nim
+++ b/src/nodesnim/nodescontrol/edittext.nim
@@ -1,7 +1,7 @@
# author: Ethosa
+import ../thirdparty/sdl2 except Color
import
../thirdparty/opengl,
- ../thirdparty/sdl2,
../thirdparty/sdl2/ttf,
../core/font,
@@ -122,7 +122,7 @@ template changeText(self, `text`, `save_properties`, t: untyped): untyped =
for i in 0.. 0:
self.moveCursorBy(-1)
diff --git a/src/nodesnim/nodescontrol/label.nim b/src/nodesnim/nodescontrol/label.nim
index 489e4b5b..44d0a00c 100644
--- a/src/nodesnim/nodescontrol/label.nim
+++ b/src/nodesnim/nodescontrol/label.nim
@@ -19,6 +19,7 @@ import
../nodes/node,
../nodes/canvas,
+ browsers,
control
@@ -59,14 +60,46 @@ method duplicate*(self: LabelRef): LabelRef {.base.} =
self.deepCopy()
method getText*(self: LabelRef): string {.base.} =
+ ## Returns `StyleText` as `string`.
+ ##
+ ## See also:
+ ## * `setText method <#setText.e,LabelRef,string,bool>`_
$self.text
+method handle*(self: LabelRef, event: InputEvent, mouse_on: var NodeRef) =
+ ## Handles user input. Thi uses in the `window.nim`.
+ procCall self.ControlRef.handle(event, mouse_on)
+
+ if event.kind in [MOUSE, MOTION]:
+ let (c, pos) = self.text.getCharUnderPoint(
+ self.getGlobalMousePosition(), self.global_position + self.rect_size/2 - self.text.getTextSize()/2,
+ self.text_align)
+
+ if c.is_url:
+ var (i, j) = (pos.int, pos.int)
+ while i - 1 > 0 and self.text.chars[i - 1].is_url:
+ dec i
+ while j + 1 < self.text.len and self.text.chars[j + 1].is_url:
+ inc j
+ self.text.setUnderline(i, j, true)
+ self.text.rendered = false
+ if last_event.pressed and last_event.kind == MOUSE:
+ openDefaultBrowser(c.url)
+ else:
+ for i in self.text.chars:
+ if i.is_url:
+ i.setUnderline(false)
+ self.text.rendered = false
+
method setText*(self: LabelRef, text: string, save_properties: bool = false) {.base.} =
## Changes text.
##
## Arguments:
## - `text` is a new Label text.
## - `save_properties` - saves old text properties, if `true`.
+ ##
+ ## See also:
+ ## * `getText method <#getText.e,LabelRef>`_
var st = stext(text)
if self.text.font.isNil():
self.text.font = standard_font
@@ -76,25 +109,45 @@ method setText*(self: LabelRef, text: string, save_properties: bool = false) {.b
for i in 0..`_
self.text_align = Anchor(x1, y1, x2, y2)
self.text.rendered = false
method setTextAlign*(self: LabelRef, align: AnchorObj) {.base.} =
+ ## Changes text alignment.
+ ##
+ ## See also:
+ ## * `setTextAlign method <#setTextAlign.e,LabelRef,float,float,float,float>`_
self.text_align = align
self.text.rendered = false
method setTextColor*(self: LabelRef, color: ColorRef) {.base.} =
+ ## Changes text color.
+ ##
+ ## Arguments:
+ ## - `color` - new text color.
self.text.setColor(color)
self.text.rendered = false
method setTextFont*(self: LabelRef, font: FontPtr) {.base.} =
+ ## Changes text font.
+ ##
+ ## Arguments:
+ ## - `font` - new text font.
self.text.font = font
self.text.rendered = false
diff --git a/src/nodesnim/nodescontrol/popup.nim b/src/nodesnim/nodescontrol/popup.nim
index fc03bfcb..b95a8d07 100644
--- a/src/nodesnim/nodescontrol/popup.nim
+++ b/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,30 +30,36 @@ 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.visibility == GONE:
+ self.show()
+ else:
+ self.hide()
+
method calcPositionAnchor*(self: PopupRef) =
## This uses in the `scene.nim`.
{.warning[LockLevel]: off.}
diff --git a/src/nodesnim/nodescontrol/progress_bar.nim b/src/nodesnim/nodescontrol/progress_bar.nim
index d374eb18..28ef86f9 100644
--- a/src/nodesnim/nodescontrol/progress_bar.nim
+++ b/src/nodesnim/nodescontrol/progress_bar.nim
@@ -9,6 +9,7 @@ import
../core/input,
../core/color,
../core/enums,
+ ../core/nodes_os,
../nodes/node,
../nodes/canvas,
@@ -19,10 +20,6 @@ import
const CIRCLE_STEP: float = TAU * 0.01
type
- ProgressBarType* {.pure.} = enum
- PROGRESS_BAR_HORIZONTAL,
- PROGRESS_BAR_VERTICAL,
- PROGRESS_BAR_CIRCLE
ProgressBarObj* = object of ControlRef
max_value*, value*: float
progress_color*: ColorRef
@@ -72,8 +69,8 @@ method draw*(self: ProgressBarRef, w, h: GLfloat) =
else:
self.indeterminate_val = -progress_width
glRectf(
- normalize(x + self.indeterminate_val, x, x + self.rect_size.x), y,
- normalize(x + self.indeterminate_val + progress_width, x, x + self.rect_size.x), y - self.rect_size.y)
+ norm(x, x + self.rect_size.x, x + self.indeterminate_val), y,
+ norm(x, x + self.rect_size.x, x + self.indeterminate_val + progress_width), y - self.rect_size.y)
else:
glRectf(x, y, x + progress_width, y - self.rect_size.y)
@@ -87,8 +84,8 @@ method draw*(self: ProgressBarRef, w, h: GLfloat) =
else:
self.indeterminate_val = -progress_width
glRectf(
- x, normalize(y - self.indeterminate_val, y - self.rect_size.y, y),
- x + self.rect_size.x, normalize(y - self.indeterminate_val - progress_width, y - self.rect_size.y, y))
+ x, norm(y - self.rect_size.y, y, y - self.indeterminate_val),
+ x + self.rect_size.x, norm(y - self.rect_size.y, y, y - self.indeterminate_val - progress_width))
else:
glRectf(x, y, x + self.rect_size.x, y - progress_width)
diff --git a/src/nodesnim/nodescontrol/scroll.nim b/src/nodesnim/nodescontrol/scroll.nim
index 7bedad32..e8dd8118 100644
--- a/src/nodesnim/nodescontrol/scroll.nim
+++ b/src/nodesnim/nodescontrol/scroll.nim
@@ -1,8 +1,8 @@
# author: Ethosa
## It provides primitive scroll box.
+import ../thirdparty/sdl2 except Color
import
../thirdparty/opengl,
- ../thirdparty/sdl2,
../core/vector2,
../core/rect2,
@@ -68,16 +68,6 @@ method duplicate*(self: ScrollRef): ScrollRef {.base.} =
self.deepCopy()
-method resize*(canvas: ScrollRef, w, h: GLfloat, save_anchor: bool = false) =
- ## Resizes scroll.
- ##
- ## Arguments:
- ## - `w` is a new width.
- ## - `h` is a new height.
- canvas.rect_size.x = w
- canvas.rect_size.y = h
-
-
method draw*(self: ScrollRef, w, h: GLfloat) =
## This uses in the `window.nim`.
let
@@ -150,10 +140,10 @@ method handle*(self: ScrollRef, event: InputEvent, mouse_on: var NodeRef) =
if mouse_in: # Keyboard movement
if event.kind == KEYBOARD:
- if event.key_cint in pressed_keys_cints: # Special chars
- if event.key_cint == K_UP:
+ if event.key_int in pressed_keys_cint: # Special chars
+ if event.key_int == K_UP:
self.scrollBy(0, -40)
- elif event.key_cint == K_DOWN:
+ elif event.key_int == K_DOWN:
self.scrollBy(0, 40)
elif event.kind == WHEEL:
self.scrollBy(0, -20 * event.yrel)
diff --git a/src/nodesnim/nodescontrol/slider.nim b/src/nodesnim/nodescontrol/slider.nim
index 743c9c34..04302521 100644
--- a/src/nodesnim/nodescontrol/slider.nim
+++ b/src/nodesnim/nodescontrol/slider.nim
@@ -16,9 +16,6 @@ import
type
- SliderType*{.pure, size: sizeof(int8).} = enum
- SLIDER_HORIZONTAL,
- SLIDER_VERTICAL
SliderObj* = object of ControlRef
slider_type*: SliderType
max_value*, value*: uint
@@ -76,7 +73,7 @@ method draw*(self: SliderRef, w, h: GLfloat) =
glRectf(x, y - self.rect_size.y + progress, x + self.rect_size.x, y - self.rect_size.y)
# Thumb
- self.thumb.draw(x, progress-10, self.rect_size.x, 10)
+ self.thumb.draw(x, y-self.rect_size.y+progress, self.rect_size.x, 10)
# Press
if self.pressed:
diff --git a/src/nodesnim/nodescontrol/subwindow.nim b/src/nodesnim/nodescontrol/subwindow.nim
index 48f8661a..dba82761 100644
--- a/src/nodesnim/nodescontrol/subwindow.nim
+++ b/src/nodesnim/nodescontrol/subwindow.nim
@@ -1,8 +1,8 @@
# author: Ethosa
## Extended version of SubWindow node.
+import ../thirdparty/sdl2 except Color
import
../thirdparty/opengl,
- ../thirdparty/sdl2,
../core/vector2,
../core/rect2,
@@ -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)
diff --git a/src/nodesnim/nodescontrol/texture_button.nim b/src/nodesnim/nodescontrol/texture_button.nim
index 6e58a5b8..31c73afe 100644
--- a/src/nodesnim/nodescontrol/texture_button.nim
+++ b/src/nodesnim/nodescontrol/texture_button.nim
@@ -1,8 +1,8 @@
# author: Ethosa
## It is the convenient alternative of the Button node.
+import ../thirdparty/sdl2 except Color
import
../thirdparty/opengl,
- ../thirdparty/sdl2,
../core/vector2,
../core/rect2,
@@ -68,6 +68,7 @@ method draw*(self: TextureButtonRef, w, h: GLfloat) =
# Texture
if texture.texture > 0'u32:
+ glColor4f(0.8, 0.8, 0.8, 1f)
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, texture.texture)
diff --git a/src/nodesnim/nodescontrol/texture_progress_bar.nim b/src/nodesnim/nodescontrol/texture_progress_bar.nim
index c29980c6..121c2539 100644
--- a/src/nodesnim/nodescontrol/texture_progress_bar.nim
+++ b/src/nodesnim/nodescontrol/texture_progress_bar.nim
@@ -69,6 +69,7 @@ method draw*(self: TextureProgressBarRef, w, h: GLfloat) =
glVertex2f(x + self.rect_size.x, y)
glEnd()
+ glBindTexture(GL_TEXTURE_2D, 0)
glDisable(GL_TEXTURE_2D)
if self.progress_texture.texture > 0'u32:
@@ -86,6 +87,7 @@ method draw*(self: TextureProgressBarRef, w, h: GLfloat) =
glVertex2f(x + progress, y)
glEnd()
+ glBindTexture(GL_TEXTURE_2D, 0)
glDisable(GL_TEXTURE_2D)
# Press
diff --git a/src/nodesnim/nodescontrol/tooltip.nim b/src/nodesnim/nodescontrol/tooltip.nim
new file mode 100644
index 00000000..1aba8859
--- /dev/null
+++ b/src/nodesnim/nodescontrol/tooltip.nim
@@ -0,0 +1,77 @@
+# author: Ethosa
+import
+ ../thirdparty/opengl,
+
+ ../core/vector2,
+ ../core/font,
+ ../core/enums,
+ ../core/color,
+ ../core/anchor,
+
+ ../nodes/node,
+ ../nodes/canvas,
+
+ ../graphics/drawable,
+
+ ../window,
+
+ control
+
+
+type
+ ToolTipObj* = object of ControlObj
+ text*: StyleText
+ ToolTipRef* = ref ToolTipObj
+
+const TOOLTIP_SPACE: float = 32f
+
+
+proc ToolTip*(name: string = "ToolTip",
+ tooltip: string = "Tooltip"): ToolTipRef =
+ nodepattern(ToolTipRef)
+ controlpattern()
+ result.text = stext(tooltip)
+ result.background.setColor(Color("#444"))
+ result.background.setBorderColor(Color("#555"))
+ result.background.setBorderWidth(0.5)
+ result.background.setCornerRadius(4)
+ result.background.setCornerDetail(4)
+ result.background.enableShadow(true)
+ result.background.setShadowOffset(Vector2(0, 5))
+ result.mousemode = MOUSEMODE_IGNORE
+ result.hide()
+
+
+method postdraw*(self: ToolTipRef, w, h: GLfloat) =
+ {.warning[LockLevel]: off.}
+ procCall self.ControlRef.draw(w, h)
+ let
+ x = -w/2 + self.global_position.x
+ y = h/2 - self.global_position.y
+
+ self.text.renderTo(Vector2(x, y), self.rect_size, Anchor(0, 0, 0, 0))
+
+method showAt*(self: ToolTipRef, x, y: float) {.base.} =
+ self.moveTo(x, y)
+ self.rect_min_size = self.text.getTextSize()
+ self.resize(self.rect_size.x, self.rect_size.y, true)
+ self.show()
+
+method showAtMouse*(self: ToolTipRef) {.base.} =
+ let
+ pos = self.getGlobalMousePosition()
+ textsize = self.text.getTextSize()
+ windowsize = getWindowSize()
+ self.moveTo(pos)
+
+ if pos.x + TOOLTIP_SPACE + textsize.x > windowsize.x:
+ self.move(-TOOLTIP_SPACE - textsize.x, 0)
+
+ if pos.y - TOOLTIP_SPACE - textsize.y < 0:
+ self.move(0, TOOLTIP_SPACE)
+ else:
+ self.move(0, -TOOLTIP_SPACE)
+
+ self.rect_min_size = self.text.getTextSize()
+ self.resize(self.rect_size.x, self.rect_size.y, true)
+ self.show()
diff --git a/src/nodesnim/runtime/scripts.nim b/src/nodesnim/runtime/scripts.nim
new file mode 100644
index 00000000..a6aa36d2
--- /dev/null
+++ b/src/nodesnim/runtime/scripts.nim
@@ -0,0 +1,126 @@
+# author: Ethosa
+## It provides runtime scripts loader.
+import
+ compiler / [
+ astalgo, ast, vmdef, vm, options,
+ modulegraphs, idents, modules,
+ pathutils, llstream, passes, sem,
+ condsyms
+ ],
+
+ ../core/exceptions,
+ ../core/vector2,
+ scripts_impl,
+
+ os
+
+
+var
+ ident_cache = newIdentCache()
+ cfg = newConfigRef()
+
+once:
+ let std = AbsoluteDir(getHomeDir() / ".nimble" / "lib")
+ # Search .nimble/lib folder 👀
+ cfg.libpath = std
+ cfg.searchPaths.add(cfg.libpath)
+ cfg.searchPaths.add(AbsoluteDir($std / "pure"))
+ cfg.searchPaths.add(AbsoluteDir($std / "pure" / "collections"))
+ cfg.searchPaths.add(AbsoluteDir($std / "core"))
+ cfg.searchPaths.add(AbsoluteDir($std / "impure"))
+ cfg.searchPaths.add(AbsoluteDir($std / "std"))
+ cfg.implicitIncludes.add(getCurrentDir() / "scripts_api.nim")
+
+
+# --- Convert default Nim types to PNode --- #
+converter toNode*(x: float): PNode = newFloatNode(nkFloatLit, x)
+converter toNode*(x: int): PNode = newIntNode(nkIntLit, x)
+converter toNode*(x: string): PNode = newStrNode(nkStrLit, x)
+converter toNode*(x: bool): PNode = x.ord.toNode()
+converter toNode*(x: enum): PNode = x.ord.toNode()
+
+converter toNode*(x: openarray[int|float|string|bool|enum]): PNode =
+ result = newNode(nkBracket)
+ result.sons.initialize(x.len)
+ for i in x.low..x.high:
+ result[i] = x[i].toNode()
+
+converter toNode*(x: tuple | object): PNode =
+ result = newTree(nkPar)
+ for field in x.fields:
+ result.sons.add(field.toNode())
+
+converter toNode*(x: ref tuple | ref object): PNode =
+ result = newTree(nkPar)
+ if x.isNil():
+ return result
+ for field in x.fields:
+ result.sons.add(field.toNode())
+
+
+proc setupModule(self: CompiledScript) =
+ self.graph.connectCallbacks()
+ initDefines(cfg.symbols)
+ defineSymbol(cfg.symbols, "nimscript")
+ defineSymbol(cfg.symbols, "nimconfig")
+ self.graph.registerPass(semPass)
+ self.graph.registerPass(evalPass)
+
+
+proc cleanupModule(self: CompiledScript) =
+ initDefines(cfg.symbols)
+ undefSymbol(cfg.symbols, "nimscript")
+ undefSymbol(cfg.symbols, "nimconfig")
+ clearPasses(self.graph)
+
+
+proc compileScript*(file: string): CompiledScript =
+ ## Compiles script with std module.
+ new result
+ result.filename = file
+ result.graph = newModuleGraph(ident_cache, cfg)
+ result.setupModule()
+ result.module = makeModule(result.graph, file)
+
+ # Create context
+ incl(result.module.flags, sfMainModule)
+ result.pctx = newCtx(result.module, identCache, result.graph)
+ result.pctx.mode = emRepl
+
+ # Setup context
+ setupGlobalCtx(result.module, result.graph)
+ registerAdditionalOps(result.pctx)
+
+ # Compile std
+ compileSystemModule(result.graph)
+
+ # Compile module
+ if not processModule(result.graph, result.module, llStreamOpen(AbsoluteFile(file), fmRead)):
+ raise newException(VMError, "Failed to process `" & file & "`")
+
+ # Cleanup
+ setupGlobalCtx(nil, result.graph)
+ result.cleanupModule()
+
+
+proc getProc*(self: CompiledScript, routine: string): PSym =
+ strTableGet(self.module.tab, getIdent(identCache, routine))
+
+proc hasProc*(self: CompiledScript, routine: string): bool =
+ ## Returns true, if `routine` available.
+ not self.getProc(routine).isNil()
+
+
+proc call*(self: CompiledScript, routine: string,
+ args: varargs[PNode]): PNode {.discardable.} =
+ ## Calls routine by name
+ # Setup context
+ setupGlobalCtx(self.module, self.graph)
+
+ # Find routine
+ let prc = self.getProc(routine)
+ if prc.isNil():
+ raise newException(VMError, "\nUnable to locate proc `" & routine & "` in `" & self.filename & "`")
+
+ # Call routine
+ result = execProc(self.pctx, prc, args)
diff --git a/src/nodesnim/runtime/scripts_api.nim b/src/nodesnim/runtime/scripts_api.nim
new file mode 100644
index 00000000..3f39c1ed
--- /dev/null
+++ b/src/nodesnim/runtime/scripts_api.nim
@@ -0,0 +1,2 @@
+# author: Ethosa
+## Built-ins for writing scripts.
diff --git a/src/nodesnim/runtime/scripts_impl.nim b/src/nodesnim/runtime/scripts_impl.nim
new file mode 100644
index 00000000..3322f0af
--- /dev/null
+++ b/src/nodesnim/runtime/scripts_impl.nim
@@ -0,0 +1,24 @@
+import
+ compiler / [vmdef, modulegraphs, vm, ast]
+
+
+type
+ CompiledScript* = ref object
+ pctx*: PCtx
+ graph*: ModuleGraph
+ module*: PSym
+ filename*: string
+
+
+proc exposeScriptApi* (self: CompiledScript) =
+ template expose (routine, body: untyped) {.dirty.} =
+ self.pctx.registerCallback self.filename & "." & astToStr(routine),
+ proc (a: VmArgs) =
+ body
+
+ expose add:
+ # We need to use procs like getInt to retrieve the argument values from VmArgs
+ # Instead of using the return statement we need to use setResult
+ setResult(a,
+ getInt(a, 0) +
+ getInt(a, 1))
diff --git a/src/nodesnim/window.nim b/src/nodesnim/window.nim
index a3ac028c..a4a1e702 100644
--- a/src/nodesnim/window.nim
+++ b/src/nodesnim/window.nim
@@ -1,13 +1,15 @@
# author: Ethosa
+import thirdparty/sdl2 except Color
import
thirdparty/opengl,
thirdparty/opengl/glu,
- thirdparty/sdl2,
thirdparty/sdl2/image,
core/color,
core/input,
core/exceptions,
+ core/vector2,
+ core/enums,
nodes/node,
nodes/scene,
@@ -112,13 +114,10 @@ proc keyboardpress(c: cint) {.cdecl.} =
## Called when press any key on keyboard.
if c < 0:
return
- var key = $c
check(InputEventKeyboard, last_event.pressed, true)
- last_event.key = key
last_event.key_int = c
- if key notin pressed_keys:
- pressed_keys.add(key)
- pressed_keys_ints.add(c)
+ if c notin pressed_keys_cint:
+ pressed_keys_cint.add(c)
last_event.kind = KEYBOARD
last_key_state = key_state
key_state = true
@@ -138,28 +137,23 @@ proc keyboardup(c: cint) {.cdecl.} =
## Called when any key no more pressed.
if c < 0:
return
- let key = $c
check(InputEventKeyboard, false, false)
- last_event.key = key
last_event.key_int = c
last_event.kind = KEYBOARD
last_key_state = key_state
key_state = false
- var i = 0
- for k in pressed_keys:
- if k == key:
- pressed_keys.delete(i)
- pressed_keys_ints.delete(i)
+ for i in pressed_keys_cint.low..pressed_keys_cint.high:
+ if pressed_keys_cint[i] == c:
+ pressed_keys_cint.delete(i)
break
- inc i
current_scene.handleScene(last_event, mouse_on, paused)
-proc motion(x, y: cint) {.cdecl.} =
+proc motion(x, y, xrel, yrel: cint) {.cdecl.} =
## Called on any mouse motion.
last_event.kind = MOTION
- last_event.xrel = last_event.x - x.float
- last_event.yrel = last_event.y - y.float
+ last_event.xrel = xrel.float
+ last_event.yrel = yrel.float
last_event.x = x.float
last_event.y = y.float
@@ -189,6 +183,7 @@ proc addMainScene*(scene: SceneRef) =
main_scene = scene
proc centeredWindow* =
+ ## Moves window to the display center.
var dm: DisplayMode
discard getCurrentDisplayMode(0, dm)
windowptr.setPosition((dm.w/2 - width/2).cint, (dm.h/2 - height/2).cint)
@@ -214,7 +209,18 @@ proc changeScene*(name: string, extra: seq[tuple[k: string, v: string]] = @[]):
when defined(debug):
debug("result of `changeScene` is ", result)
+proc getSceneByName*(name: string): SceneRef =
+ for scene in scenes:
+ if scene.name == name:
+ return scene
+
+proc getWindowSize*(): Vector2Obj =
+ Vector2(width.float, height.float)
+
proc resizeWindow*(x, y: cint) =
+ ## Resizes window.
+ width = x
+ height = y
windowptr.setSize(x, y)
proc setMainScene*(name: string) =
@@ -232,14 +238,14 @@ proc setTitle*(title: cstring) =
if window_created:
windowptr.setTitle(title)
else:
- raise newException(WindowError, "Window not launched!")
+ throwError(WindowError, "Window not launched!")
proc setIcon*(icon_path: cstring) =
## Changes window title.
if window_created:
windowptr.setIcon(image.load(icon_path))
else:
- raise newException(WindowError, "Window not launched!")
+ throwError(WindowError, "Window not launched!")
proc Window*(title: cstring, w: cint = 640, h: cint = 360) {.cdecl.} =
## Creates a new window pointer
@@ -248,13 +254,14 @@ proc Window*(title: cstring, w: cint = 640, h: cint = 360) {.cdecl.} =
## - `title` - window title.
# Set up window.
once:
- when not defined(android) and not defined(ios):
+ when not defined(android) and not defined(ios) and not defined(useGlew):
loadExtensions() # Load OpenGL extensions.
discard captureMouse(True32)
windowptr = createWindow(
title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h,
SDL_WINDOW_SHOWN or SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE or
- SDL_WINDOW_ALLOW_HIGHDPI or SDL_WINDOW_FOREIGN or SDL_WINDOW_INPUT_FOCUS or SDL_WINDOW_MOUSE_FOCUS)
+ SDL_WINDOW_ALLOW_HIGHDPI or SDL_WINDOW_FOREIGN or
+ SDL_WINDOW_INPUT_FOCUS or SDL_WINDOW_MOUSE_FOCUS)
glcontext = windowptr.glCreateContext()
# Set up OpenGL
@@ -280,8 +287,8 @@ proc onReshape(userdata: pointer; event: ptr Event): Bool32 {.cdecl.} =
False32
proc windowLaunch* =
- if main_scene == nil:
- raise newException(SceneError, "Main scene is not indicated!")
+ if main_scene.isNil():
+ throwError(SceneError, "Main scene is not indicated!")
changeScene(main_scene.name)
when defined(debug):
info("window launched")
@@ -304,7 +311,7 @@ proc windowLaunch* =
textinput(e)
of MouseMotion:
let e = evMouseMotion(event)
- motion(e.x, e.y)
+ motion(e.x, e.y, e.xrel, e.yrel)
of MouseButtonDown:
let e = evMouseButton(event)
mouse(e.button.cint, e.x, e.y, true)
diff --git a/tests/README.md b/tests/README.md
index cb20f083..b7fd556d 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,52 +1,23 @@
Tests
-- [Create a window and set up the main scene.](https://github.com/Ethosa/nodesnim/blob/master/tests/test1.nim)
-- [Use Canvas node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test2.nim)
-- [Window events handling.](https://github.com/Ethosa/nodesnim/blob/master/tests/test3.nim)
-- [Use ColorRect node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test4.nim)
-- [Handle Control node events.](https://github.com/Ethosa/nodesnim/blob/master/tests/test5.nim)
-- [Anchor setting.](https://github.com/Ethosa/nodesnim/blob/master/tests/test6.nim)
-- [Change scenes.](https://github.com/Ethosa/nodesnim/blob/master/tests/test7.nim)
-- [Use TextureRect node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test8.nim)
-- [Use Label node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test9.nim)
-- [Use Button node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test10.nim)
-- [Environment setting.](https://github.com/Ethosa/nodesnim/blob/master/tests/test11.nim)
-- [Use Box node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test12.nim)
-- [Use HBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test13.nim)
-- [Use VBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test14.nim)
-- [Use GridBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test15.nim)
-- [Use EditText node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test16.nim)
-- [Duplicate nodes.](https://github.com/Ethosa/nodesnim/blob/master/tests/test17.nim)
-- [Use Scroll node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test18.nim)
-- [Use ProgressBar node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test19.nim)
-- [Use Slider node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test20.nim)
-- [Use Popup node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test21.nim)
-- [Use AudioStreamPlayer node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test22.nim)
-- [Use Node2D node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test23.nim)
-- [Use Sprite node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test24.nim)
-- [Use TextureButton node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test25.nim)
-- [Use AnimatedSprite node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test26.nim)
-- [Use TextureProgressBar node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test27.nim)
-- [Use YSort node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test28.nim)
-- [Use Counter node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test29.nim)
-- [Use CollisionShape2D node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test30.nim)
-- [Use KinematicBody2D node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test31.nim)
-- [Use Switch node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test32.nim)
-- [Event handlers with macros.](https://github.com/Ethosa/nodesnim/blob/master/tests/test33.nim)
-- [Rotation.](https://github.com/Ethosa/nodesnim/blob/master/tests/test34.nim)
-- [Use Camera2D node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test35.nim)
-- [Use Node3D.](https://github.com/Ethosa/nodesnim/blob/master/tests/test36.nim)
-- [Use GeometryInstance node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test37.nim)
-- [Use SubWindow node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test38.nim)
-- [Use Scene builder.](https://github.com/Ethosa/nodesnim/blob/master/tests/test39.nim)
-- [Use AnimationPlayer node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test40.nim)
-- [Use StyleSheet object.](https://github.com/Ethosa/nodesnim/blob/master/tests/test41.nim)
-- [Use Drawable and Control.](https://github.com/Ethosa/nodesnim/blob/master/tests/test42.nim)
-- [Use CheckBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test43.nim)
-- [Use GradientDrawable and Control.](https://github.com/Ethosa/nodesnim/blob/master/tests/test44.nim)
-- [Use TileMap node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test45.nim)
-- [Use padding.](https://github.com/Ethosa/nodesnim/blob/master/tests/test46.nim)
-- [Use margin.](https://github.com/Ethosa/nodesnim/blob/master/tests/test47.nim)
-- [Use Camera3D node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test48.nim)
-- [Use TileMap Isometric mode](https://github.com/Ethosa/nodesnim/blob/master/tests/test49.nim)
-- [Make your own node](https://github.com/Ethosa/nodesnim/blob/master/tests/test50.nim)
+- [Work with window](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test1.nim)
+
+ [](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test1.nim)
+- [Work with default nodes](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test2.nim)
+
+ [](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test2.nim)
+- [Work with Control nodes](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test3.nim)
+
+ [](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test3.nim)
+- [Work with core](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test4.nim)
+
+- [Work with graphics](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test5.nim)
+
+ [](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test5.nim)
+- [Work with 2D nodes.](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test6.nim)
+
+ [](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test6.nim)
+- [Work with 3D nodes.](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test7.nim)
+
+ [](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test7.nim)
+- [Make your own node.](https://github.com/Ethosa/nodesnim/blob/nightly/tests/test8.nim)
diff --git a/tests/assets/canvas.png b/tests/assets/canvas.png
index 11a2ebab..a177206b 100644
Binary files a/tests/assets/canvas.png and b/tests/assets/canvas.png differ
diff --git a/tests/assets/tilesets/foreground.png b/tests/assets/tilesets/foreground.png
deleted file mode 100644
index 6fab88f8..00000000
Binary files a/tests/assets/tilesets/foreground.png and /dev/null differ
diff --git a/tests/assets/tilesets/isometric_desert.png b/tests/assets/tilesets/isometric_desert.png
index 3e11c6e9..b6b87fb5 100644
Binary files a/tests/assets/tilesets/isometric_desert.png and b/tests/assets/tilesets/isometric_desert.png differ
diff --git a/tests/test1.nim b/tests/test1.nim
index 4e859fbf..030fb4a6 100644
--- a/tests/test1.nim
+++ b/tests/test1.nim
@@ -1,16 +1,44 @@
-# --- Test 1. Create a window and set up the main scene. --- #
-import nodesnim
+# --- Test 1. Work with Window.. --- #
+import
+ nodesnim,
+ unittest
-Window(
- "hello world", # Window name
- 640, # Window width,
- 360 # Window height
-)
+suite "Work with Window":
-var main = Scene("Main") # Create a new Scene object.
+ test "Create window":
+ # Window(title, width, height)
+ Window(title = "MyWindow",
+ w = 720, h = 480)
+ test "Change Window title":
+ setTitle("My own window ^^")
-addScene(main) # Add new scene in window.
-setMainScene("Main") # Set main scene.
-windowLaunch() # Start main loop.
+ test "Change Window icon":
+ setIcon("assets/sharp.jpg")
+
+ test "Resize and centered window":
+ resizeWindow(1024, 640)
+ centeredWindow()
+
+ test "Setup environment":
+ env.color = Color(1, 0.6, 1) # window background color.
+ env.delay = 1000 div 120 # 120 frames per second.
+
+ test "Setup window":
+ build: # Node builder
+ - Scene main # Create an empty Scene node with the name "main".
+
+ test "Register events":
+ addKeyAction("forward", "w")
+ addKeyAction("backward", "s")
+
+ test "Handle events":
+ main@onProcess(self):
+ if isActionJustPressed("forward"):
+ echo "forward pressed!"
+ elif isActionJustPressed("backward"):
+ echo "backward pressed!"
+
+ addMainScene(main) # Adds scene to window and
+ windowLaunch()
diff --git a/tests/test10.nim b/tests/test10.nim
deleted file mode 100644
index 6d354040..00000000
--- a/tests/test10.nim
+++ /dev/null
@@ -1,25 +0,0 @@
-# --- Test 10. Use Button node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- button = Button()
-
-main.addChild(button)
-
-button.setText("Press me!")
-button.resize(256, 64)
-button.setAnchor(0.5, 0.5, 0.5, 0.5)
-
-button.on_touch =
- proc(self: ButtonRef, x, y: float) = # This called when user clicks on the button
- button.setText("Clicked in " & $x & ", " & $y & " position.")
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test11.nim b/tests/test11.nim
deleted file mode 100644
index e1dfaf53..00000000
--- a/tests/test11.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-# --- Test 11. Environment setting. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var main = Scene("Main")
-
-env.color = Color(1, 0.6, 1) # window background color.
-env.brightness = 0.5
-env.delay = 1000 div 30 # 30 frames per second.
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test12.nim b/tests/test12.nim
deleted file mode 100644
index 817a53c1..00000000
--- a/tests/test12.nim
+++ /dev/null
@@ -1,38 +0,0 @@
-# --- Test 12. Use Box node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- box = Box() # Create the BoxObj.
-
- red = ColorRect() # #ff6699
- pink = ColorRect() #ff64ff
- orange = ColorRect() # #ffaa00
-
-
-red.color = Color(0xff6699ff'u32)
-pink.color = Color(0xff64ffff'u32)
-orange.color = Color(0xffaa00ff'u32)
-
-red.resize(128, 128)
-pink.resize(64, 64)
-orange.resize(32, 32)
-
-# Add rects in the Box node.
-box.addChild(red)
-box.addChild(pink)
-box.addChild(orange)
-
-main.addChild(box)
-box.setAnchor(0, 0.5, 0, 0.5) # Box anchor in the scene.
-
-# Box node keeps child nodes in the Box center.
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test13.nim b/tests/test13.nim
deleted file mode 100644
index 74c212ed..00000000
--- a/tests/test13.nim
+++ /dev/null
@@ -1,36 +0,0 @@
-# --- Test 13. Use HBox node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- hbox = HBox() # Create the HBoxObj.
-
- red = ColorRect() # #ff6699
- pink = ColorRect() #ff64ff
- orange = ColorRect() # #ffaa00
-
-
-red.color = Color(0xff6699ff'u32)
-pink.color = Color(0xff64ffff'u32)
-orange.color = Color(0xffaa00ff'u32)
-
-red.resize(128, 128)
-pink.resize(64, 64)
-orange.resize(32, 32)
-
-# Add rects in the Box node.
-hbox.addChild(red)
-hbox.addChild(pink)
-hbox.addChild(orange)
-
-main.addChild(hbox)
-hbox.setAnchor(0, 0.5, 0, 0.5) # Box anchor in the scene.
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test14.nim b/tests/test14.nim
deleted file mode 100644
index f99eec30..00000000
--- a/tests/test14.nim
+++ /dev/null
@@ -1,38 +0,0 @@
-# --- Test 14. Use VBox node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- vbox = VBox() # Create the VBoxObj.
-
- red = ColorRect() # #ff6699
- pink = ColorRect() #ff64ff
- orange = ColorRect() # #ffaa00
-
-
-red.color = Color(0xff6699ff'u32)
-pink.color = Color(0xff64ffff'u32)
-orange.color = Color(0xffaa00ff'u32)
-
-red.resize(128, 128)
-pink.resize(64, 64)
-orange.resize(32, 32)
-
-# Add rects in the Box node.
-vbox.addChild(red)
-vbox.addChild(pink)
-vbox.addChild(orange)
-
-main.addChild(vbox)
-vbox.setAnchor(0, 0.5, 0, 0.5) # Box anchor in the scene.
-vbox.setChildAnchor(0, 1, 0, 1)
-vbox.setSizeAnchor(1, 1)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test15.nim b/tests/test15.nim
deleted file mode 100644
index db4c4cdc..00000000
--- a/tests/test15.nim
+++ /dev/null
@@ -1,49 +0,0 @@
-# --- Test 15. Use GridBox node. --- #
-import nodesnim
-
-
-Window("hello world")
-var
- main = Scene("Main")
-
- grid_box = GridBox() # Create the GridBoxObj.
-
- red = ColorRect() # #ff6699
- pink = ColorRect() #ff64ff
- orange = ColorRect() # #ffaa00
- mango = ColorRect() # #ffcc33
- yellow = ColorRect() # #ffcc66
- red2 = ColorRect() # #ff6655
-
-
-red.color = Color(0xff6699ff'u32)
-pink.color = Color(0xff64ffff'u32)
-orange.color = Color(0xffaa00ff'u32)
-mango.color = Color(0xffcc33ff'u32)
-yellow.color = Color(0xffcc66ff'u32)
-red2.color = Color(0xff6655ff'u32)
-
-red.resize(128, 128)
-pink.resize(128, 128)
-orange.resize(128, 128)
-mango.resize(128, 128)
-yellow.resize(128, 128)
-red2.resize(128, 128)
-
-# Add rects in the Box node.
-grid_box.addChild(red)
-grid_box.addChild(pink)
-grid_box.addChild(orange)
-grid_box.addChild(mango)
-grid_box.addChild(yellow)
-grid_box.addChild(red2)
-
-main.addChild(grid_box)
-grid_box.setAnchor(0.5, 0.5, 0.5, 0.5)
-grid_box.setRow(3)
-grid_box.setSeparator(16)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test16.nim b/tests/test16.nim
deleted file mode 100644
index f9258ca6..00000000
--- a/tests/test16.nim
+++ /dev/null
@@ -1,22 +0,0 @@
-# --- Test 16. Use EditText node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- edittext = EditText()
-
-main.addChild(edittext)
-
-edittext.resize(512, 256)
-edittext.setBackgroundColor(Color(0x212121ff))
-edittext.setTextAlign(0.5, 0.5, 0.5, 0.5)
-edittext.setAnchor(0.5, 0.5, 0.5, 0.5)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test17.nim b/tests/test17.nim
deleted file mode 100644
index e77ec092..00000000
--- a/tests/test17.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-# --- Test 17. Duplicate nodes. --- #
-import nodesnim
-
-var
- node1 = Node("Node1")
- node2 = node1.duplicate()
-
- control1 = Control("Control1")
- control2 = control1.duplicate()
-
-node2.name = "Node2"
-
-echo node1.name
-echo node2.name
-
-control2.name = "Control2"
-control2.rect_size = Vector2(100, 100)
-
-echo control1.name
-echo control2.name
-
-echo control1.rect_size
-echo control2.rect_size
diff --git a/tests/test18.nim b/tests/test18.nim
deleted file mode 100644
index f8f35a67..00000000
--- a/tests/test18.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-# --- Test 18. Use Scroll node. --- #
-import nodesnim
-
-
-Window("scroll")
-
-var
- main = Scene("Main")
-
- scroll = Scroll()
-
- grid_box = GridBox()
- red = ColorRect() # #ff6699
- pink = ColorRect() #ff64ff
- orange = ColorRect() # #ffaa00
- mango = ColorRect() # #ffcc33
- yellow = ColorRect() # #ffcc66
- red2 = ColorRect() # #ff6655
-
-
-red.color = Color(0xff6699ff'u32)
-pink.color = Color(0xff64ffff'u32)
-orange.color = Color(0xffaa00ff'u32)
-mango.color = Color(0xffcc33ff'u32)
-yellow.color = Color(0xffcc66ff'u32)
-red2.color = Color(0xff6655ff'u32)
-
-red.resize(150, 150)
-pink.resize(50, 50)
-orange.resize(50, 50)
-mango.resize(50, 50)
-yellow.resize(50, 50)
-red2.resize(150, 150)
-
-# Add rects in the Box node.
-grid_box.addChild(red)
-grid_box.addChild(pink)
-grid_box.addChild(orange)
-grid_box.addChild(mango)
-grid_box.addChild(yellow)
-grid_box.addChild(red2)
-
-main.addChild(scroll)
-grid_box.setAnchor(0.5, 0.5, 0.5, 0.5)
-grid_box.setRow(3)
-grid_box.setSeparator(2)
-scroll.addChild(grid_box)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test19.nim b/tests/test19.nim
deleted file mode 100644
index c34c826a..00000000
--- a/tests/test19.nim
+++ /dev/null
@@ -1,39 +0,0 @@
-# --- Test 19. Use ProgressBar node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- progressbar = ProgressBar()
- vprogressbar = ProgressBar()
- cprogressbar = ProgressBar()
-
-vprogressbar.progress_type = PROGRESS_BAR_VERTICAL
-cprogressbar.progress_type = PROGRESS_BAR_CIRCLE
-
-
-main.addChild(progressbar)
-main.addChild(vprogressbar)
-main.addChild(cprogressbar)
-
-progressbar.setProgress(50) # default max progress value is 100.
-progressbar.setMaxValue(150)
-
-vprogressbar.setProgress(2) # default max progress value is 100.
-vprogressbar.setMaxValue(5)
-vprogressbar.move(0, 64)
-vprogressbar.resize(20, 80)
-
-cprogressbar.move(64, 64)
-cprogressbar.resize(80, 80)
-cprogressbar.indeterminate = true
-cprogressbar.setMaxValue(15)
-cprogressbar.setProgress(5)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test2.nim b/tests/test2.nim
index 8c78b5a0..ad1ff399 100644
--- a/tests/test2.nim
+++ b/tests/test2.nim
@@ -1,29 +1,80 @@
-# --- Test 2. Use Canvas node. --- #
-import nodesnim
+# --- Test 2. Work with default nodes. --- #
+import
+ nodesnim,
+ unittest
-Window("hello world")
+suite "Work with default nodes.":
+
+ test "Setup window":
+ Window("default nodes test")
-var
- main = Scene("Main")
+ test "Setup scene":
+ build:
+ - Scene main
+ addMainScene(main)
- canvas = Canvas()
+ test "Canvas test":
+ build:
+ - Canvas canvas:
+ call resize(256, 256)
+ call fill(Color("#ffaacc"))
+ call point(5, 5, Color("#64ffff"))
+ call line(8, 16, 128, 64, Color("#ffff64ff"))
+ call circle(0, 240, 32, Color("#aaff6456"))
+ call line(200, -150, 0, 256, Color("#0e1317ff"))
+ call bezier(0, 0, 256, 0, 256, 256, Color("#227"))
+ call cubic_bezier(0, 0, 256, 0, 0, 256, 256, 256, Color("#272"))
+ call move(74.4, 89.4)
+ call text("hello!,\nworld!", 64, 64, Vector2(1, 1))
+ call saveAs("assets/canvas.png") # save result in file.
+ getSceneByName("main").addChild(canvas)
-main.addChild(canvas)
+ test "AudioStreamPlayer test":
+ build:
+ - AudioStreamPlayer audio1:
+ stream: loadAudio("assets/vug_ost_Weh.ogg")
+ call setVolume(64) # 64/100
+ call play()
+ getSceneByName("main").addChild(audio1)
-canvas.resize(256, 256)
-canvas.fill(Color(0xffaaccff'u32))
-canvas.point(5, 5, Color("#64ffffff"))
-canvas.line(8, 16, 128, 64, Color("#ffff64ff"))
-canvas.circle(0, 240, 32, Color("#aaff6456"))
-canvas.line(200, -150, 0, 256, Color("#0e1317ff"))
-canvas.bezier(0, 0, 256, 0, 256, 256, Color("#227"))
-canvas.cubic_bezier(0, 0, 256, 0, 0, 256, 256, 256, Color("#272"))
-canvas.move(74.4, 89.4)
-canvas.text("hello!,\nworld!", 64, 64, Vector2(1, 1))
-canvas.saveAs("assets/canvas.png") # save result in file.
+ test "Duplicate nodes":
+ build:
+ - Node node(name: "MyOwnNode")
+ var node1 = node.duplicate()
+ assert node.name == node1.name
+ test "AnimationPlayer node":
+ build:
+ - ColorRect rect:
+ color: Color(0, 0, 0)
+ call resize(100, 100)
+ - ColorRect rect1:
+ color: Color(0, 0, 0)
+ call resize(100, 100)
+ call move(0, 150)
+ - ColorRect rect2:
+ color: Color(0.5, 0.8, 0.5)
+ call resize(100, 100)
+ call move(0, 300)
+ - AnimationPlayer animation:
+ call addState(rect.color.r.addr, @[(tick: 0, value: 0.0), (tick: 200, value: 1.0)])
+ call addState(rect.position.x.addr, @[(tick: 0, value: 0.0), (tick: 100, value: 250.0)])
+ call setDuration(200)
+ call play()
+ mode: ANIMATION_NORMAL # Default animation mode.
+ - AnimationPlayer animation1:
+ call addState(rect1.position.x.addr, @[(tick: 0, value: 0.0), (tick: 100, value: 250.0)])
+ call setDuration(200)
+ call play()
+ mode: ANIMATION_EASE
+ - AnimationPlayer animation2:
+ call addState(rect2.position.x.addr, @[(tick: 0, value: 0.0), (tick: 100, value: 250.0)])
+ call setDuration(200)
+ call play()
+ mode: ANIMATION_BEZIER
+ bezier: (0.8, 0.9)
+ getSceneByName("main").addChildren(rect, rect1, rect2, animation, animation1, animation2)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
+ test "Launch window":
+ windowLaunch()
diff --git a/tests/test20.nim b/tests/test20.nim
deleted file mode 100644
index 292eb64c..00000000
--- a/tests/test20.nim
+++ /dev/null
@@ -1,38 +0,0 @@
-# --- Test 20. Use Slider node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- slider = Slider()
- vslider = Slider()
-
-main.addChild(slider)
-main.addChild(vslider)
-vslider.move(64, 64)
-vslider.setMaxValue(4)
-vslider.slider_type = SLIDER_VERTICAL
-slider.resize(256, 32)
-vslider.resize(32, 128)
-slider.setMaxValue(1000)
-
-vslider.on_changed =
- proc(self: SliderRef, v: uint) =
- if v > 2:
- vslider.setProgressColor(Color(0xccaaffff'u32))
- else:
- vslider.setProgressColor(Color(0xffaaccff'u32))
-
-slider.on_changed =
- proc(self: SliderRef, v: uint) =
- slider.setProgressColor(Color(
- 1f - v.float / slider.max_value.float, v.float / slider.max_value.float, 0
- ))
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test21.nim b/tests/test21.nim
deleted file mode 100644
index 832b01f8..00000000
--- a/tests/test21.nim
+++ /dev/null
@@ -1,42 +0,0 @@
-# --- Test 21. Use Popup node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- popup = Popup() # Create Popup node pointer.
-
- box = VBox()
-
- label = Label()
-
- smthnode = Node()
-
-
-label.setText("Hello")
-label.setTextAlign(0.5, 0.5, 0.5, 0.5)
-box.setChildAnchor(0.5, 0.1, 0.5, 0.1)
-box.setSizeAnchor(1, 1)
-
-popup.addChild(box)
-box.addChild(label)
-main.addChild(popup)
-main.addChild(smthnode)
-
-
-addKeyAction("space", K_SPACE)
-smthnode.on_process =
- proc(self: NodeRef) =
- if isActionJustPressed("space"):
- if popup.visible == VISIBLE:
- popup.hide()
- else:
- popup.show()
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test22.nim b/tests/test22.nim
deleted file mode 100644
index 20209b22..00000000
--- a/tests/test22.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-# --- Test 22. Use AudioStreamPlayer node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- stream1 = loadAudio("assets/vug_ost_Weh.ogg")
- stream2 = loadAudio("assets/vug_ost_Movement.ogg")
-
- audio = AudioStreamPlayer()
- audio1 = AudioStreamPlayer()
-
-audio.stream = stream1
-audio.setVolume(64)
-audio.play()
-
-when false: # use more than one channel
- audio1.stream = stream2
- audio1.setVolume(64)
- audio1.play()
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test23.nim b/tests/test23.nim
deleted file mode 100644
index f8d09f8b..00000000
--- a/tests/test23.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# --- Test 23. Use Node2D node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- node = Node2D()
-
-
-main.addChild(node)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test24.nim b/tests/test24.nim
deleted file mode 100644
index d697d721..00000000
--- a/tests/test24.nim
+++ /dev/null
@@ -1,24 +0,0 @@
-# --- Test 24. Use Sprite node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- sprite = Sprite()
-
- icon = load("assets/smile.png", GL_RGBA)
-
-
-main.addChild(sprite)
-
-sprite.move(128, 128) # Move sprite.
-sprite.setTexture(icon) # Change sprite image.
-
-sprite.centered = true # The default value is true. Try to change it.
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test25.nim b/tests/test25.nim
deleted file mode 100644
index 72daaa07..00000000
--- a/tests/test25.nim
+++ /dev/null
@@ -1,34 +0,0 @@
-# --- Test 25. Use TextureButton node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- button = TextureButton()
-
- norm_texture = load("assets/button_normal.png", GL_RGBA)
- hover_texture = load("assets/button_hover.png", GL_RGBA)
- press_texture = load("assets/button_press.png", GL_RGBA)
-
-main.addChild(button)
-env.setBackgroundColor(Color(0xf2f2f7ff'u32))
-
-button.setText("Press me!")
-button.resize(256, 64)
-button.setAnchor(0.5, 0.5, 0.5, 0.5)
-
-button.setNormalTexture(norm_texture)
-button.setHoverTexture(hover_texture)
-button.setPressTexture(press_texture)
-
-button.on_touch =
- proc(self: TextureButtonRef, x, y: float) = # This called when user clicks on the button
- button.setText("Clicked in " & $x & ", " & $y & " position.")
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test26.nim b/tests/test26.nim
deleted file mode 100644
index e9a76f47..00000000
--- a/tests/test26.nim
+++ /dev/null
@@ -1,32 +0,0 @@
-# --- Test 26. Use AnimatedSprite node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- sprite = AnimatedSprite()
-
- img0 = load("assets/anim/0.jpg")
- img1 = load("assets/anim/1.jpg")
- img2 = load("assets/anim/2.jpg")
- img3 = load("assets/anim/3.jpg")
- img4 = load("assets/anim/4.jpg")
-
-sprite.addFrame("default", img0)
-sprite.addFrame("default", img1)
-sprite.addFrame("default", img2)
-sprite.addFrame("default", img3)
-sprite.addFrame("default", img4)
-
-
-sprite.play("", false) # if `name` is "" than plays current animation.
-sprite.centered = false # disable centered.
-
-
-main.addChild(sprite)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test27.nim b/tests/test27.nim
deleted file mode 100644
index 6a5029fa..00000000
--- a/tests/test27.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-# --- Test 27. Use TextureProgressBar node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- progressbar = TextureProgressBar()
-
- back = load("assets/texture_progress_0.png", GL_RGBA)
- progress = load("assets/texture_progress_1.png", GL_RGBA)
-
-main.addChild(progressbar)
-
-progressbar.setProgress(50) # default max progress value is 100.
-progressbar.setMaxValue(150)
-progressbar.resize(256, 85)
-
-progressbar.setProgressTexture(progress)
-progressbar.setBackgroundTexture(back)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test28.nim b/tests/test28.nim
deleted file mode 100644
index 10c73641..00000000
--- a/tests/test28.nim
+++ /dev/null
@@ -1,46 +0,0 @@
-# --- Test 28. Use YSort node. --- #
-import nodesnim
-
-
-Window("hello world", 1024, 640)
-
-var
- main = Scene("Main")
-
- ysort = Ysort()
-
- sprite0 = Sprite("0")
- sprite1 = Sprite("1")
- sprite2 = Sprite("2")
- sprite3 = Sprite("3")
- sprite4 = Sprite("4")
-
- img0 = load("assets/anim/2.jpg")
-
-sprite0.setTexture(img0)
-sprite1.setTexture(img0)
-sprite2.setTexture(img0)
-sprite3.setTexture(img0)
-sprite4.setTexture(img0)
-
-
-sprite0.filter = Color(0xffccaaff'u32)
-sprite1.filter = Color(0xffaaccff'u32)
-sprite2.filter = Color(0xaaffccff'u32)
-sprite3.filter = Color(0xccffaaff'u32)
-sprite4.filter = Color(0xaaccffff'u32)
-
-
-sprite4.move(92, 92)
-sprite0.move(128, 128)
-sprite3.move(160, 160)
-sprite2.move(192, 192)
-sprite1.move(224, 224)
-
-ysort.addChilds(sprite0, sprite1, sprite2, sprite3, sprite4)
-
-
-main.addChild(ysort)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test29.nim b/tests/test29.nim
deleted file mode 100644
index ff807658..00000000
--- a/tests/test29.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# --- Test 29. Use Counter node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- counter = Counter()
-
-main.addChild(counter)
-counter.move(128, 64)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test3.nim b/tests/test3.nim
index 95c3762b..ce5d13b0 100644
--- a/tests/test3.nim
+++ b/tests/test3.nim
@@ -1,47 +1,337 @@
-# --- Test 3. Window events handling. --- #
-import nodesnim
+# --- Test 3. Work with Control nodes. --- #
+import
+ nodesnim,
+ unittest
-Window("newwindow")
+suite "Work with Control nodes.":
+
+ test "Setup window":
+ Window("Control test", 1280, 640)
-var
- main = Scene("Main")
- node = Node("My node")
+ test "Setup scenes":
+ build:
+ - Scene main
+ - Scene second_scene
+ addMainScene(main)
+ addScene(second_scene)
-main.addChild(node)
-# Bind actions:
-addKeyAction("forward", "w")
-addKeyAction("backward", "s")
-addKeyAction("left", "a")
-addKeyAction("right", "d")
-addButtonAction("click", BUTTON_LEFT)
-addButtonAction("release", BUTTON_RIGHT)
+ test "Register events":
+ addButtonAction("click", BUTTON_LEFT)
+ addKeyAction("space", K_SPACE)
+ addKeyAction("enter", 13)
-node.on_process =
- proc(self: NodeRef) = # This called every frame.
- if isActionJustPressed("click"): # returns true, when the user clicks the left button one time.
- echo "clicked!"
+ test "Control test":
+ build:
+ - Control control
+ getSceneByName("main").addChild(control)
- if isActionReleased("release"): # returns true, when the user no more press on the right button.
- echo "release!"
-node.on_input =
- proc(self: NodeRef, event: InputEvent) = # This called only on user input.
- if event.isInputEventMouseButton() and event.pressed:
- echo "hi"
- if isActionPressed("forward"): # returns true, when user press "w"
- echo "forward"
- if isActionPressed("backward"): # returns true, when user press "s"
- echo "backward"
- if isActionPressed("left"): # returns true, when user press "a"
- echo "left"
- if isActionPressed("right"): # returns true, when user press "d"
- echo "right"
+ test "ColorRect test":
+ build:
+ - ColorRect rect:
+ color: Color(1, 0.8, 0.95, 0.8)
+ test "Handle Control events":
+ rect@onFocus(self):
+ echo "focused"
+ rect@onUnfocus(self):
+ echo "unfocused"
-addScene(main)
-setMainScene("Main")
-windowLaunch()
+ rect@onClick(self, x, y):
+ echo "clicked in (", x, ", ", y, ")"
+ rect@onRelease(self, x, y):
+ echo "released in (", x, ", ", y, ")"
+ rect.color.r = 1f
+ rect@onPress(self, x, y):
+ rect.color.r -= 0.01
+
+ rect@onMouseEnter(self, x, y):
+ rect.color.g = 0.5f
+ rect@onMouseExit(self, x, y):
+ rect.color.g = 0.8f
+
+ getSceneByName("main").addChild(rect)
+
+
+ test "Anchor settings test":
+ build:
+ - ColorRect rect1:
+ color: Color(0.2, 0.3, 0.4)
+ call move(40, 0)
+ call resize(80, 80)
+ - ColorRect rect2:
+ color: Color(0.4, 0.3, 0.2)
+ call setSizeAnchor(0.25, 0.5)
+ call setAnchor(1, 1, 1, 1) # anchor to bottom-right
+ getSceneByName("main").addChild(rect1)
+
+
+ test "Change scenes test": # Press Space to change scene
+ getSceneByName("main")@onProcess(self):
+ if isActionJustPressed("space"):
+ changeScene("second_scene")
+ getSceneByName("second_scene")@onProcess(self):
+ if isActionJustPressed("space"):
+ changeScene("main")
+
+
+ test "TextureRect test":
+ build:
+ - TextureRect texturerect1:
+ texture_mode: TEXTURE_KEEP_ASPECT_RATIO
+ texture_anchor: Anchor(0.5, 0.5, 0.5, 0.5)
+ call setTexture(load("assets/sharp.jpg"))
+ call resize(100, 100)
+ call move(120, 0)
+ - TextureRect texturerect2:
+ texture_mode: TEXTURE_CROP
+ texture_anchor: Anchor(0.5, 0.5, 0.5, 0.5)
+ call setTexture(load("assets/sharp.jpg"))
+ call resize(100, 100)
+ call move(220, 0)
+ - TextureRect texturerect3:
+ texture_mode: TEXTURE_FILL_XY
+ call setTexture(load("assets/sharp.jpg"))
+ call resize(100, 100)
+ call move(320, 0)
+ getSceneByName("main").addChildren(texturerect1, texturerect2, texturerect3)
+
+
+ test "Label test":
+ build:
+ - Label label:
+ call setText("hello,\nworld!\n VK!")
+ call move(0, 40)
+ label.text.setColor(6, 12, Color("#664fff"))
+ label.text.setURL(18, 19, "https://vk.com")
+ label.text.setUnderline(0, 2, true)
+ label.text.setStrikethrough(1, 3, true)
+ label.text.setItalic(0, true)
+ getSceneByName("main").addChild(label)
+
+
+ test "Button test":
+ build:
+ - Button btn:
+ call setText("Press me ^^")
+ call resize(196, 32)
+ call move(420, 0)
+ btn@onTouch(self, x, y):
+ echo "clicked btn!"
+ getSceneByName("main").addChild(btn)
+
+
+ test "Box test":
+ build:
+ - Box box:
+ call setChildAnchor(0.5, 0.5, 0.5, 0.5)
+ call setPadding(2, 4, 8, 16)
+ call move(420, 30)
+ call setBackgroundColor(Color(1f, 1f, 1f))
+ - ColorRect first:
+ color: Color(0xff6699ff'u32)
+ call resize(80, 80)
+ - ColorRect second:
+ color: Color(0xff64ffff'u32)
+ call resize(60, 60)
+ - ColorRect third:
+ color: Color(0xffaa00ff'u32)
+ getSceneByName("main").addChild(box)
+
+
+ test "HBox test":
+ build:
+ - HBox hbox:
+ call setChildAnchor(1, 1, 1, 1)
+ call setPadding(2, 4, 8, 16)
+ call move(520, 30)
+ call setBackgroundColor(Color(1f, 1f, 1f))
+ - ColorRect first:
+ color: Color(0xff6699ff'u32)
+ call resize(80, 80)
+ - ColorRect second:
+ color: Color(0xff64ffff'u32)
+ call resize(60, 60)
+ - ColorRect third:
+ color: Color(0xffaa00ff'u32)
+ getSceneByName("main").addChild(hbox)
+
+
+ test "VBox test":
+ build:
+ - VBox vbox:
+ call setChildAnchor(1, 1, 1, 1)
+ call setPadding(2, 4, 8, 16)
+ call move(420, 144)
+ call setBackgroundColor(Color(1f, 1f, 1f))
+ - ColorRect first:
+ color: Color(0xff6699ff'u32)
+ call resize(80, 80)
+ - ColorRect second:
+ color: Color(0xff64ffff'u32)
+ call resize(60, 60)
+ - ColorRect third:
+ color: Color(0xffaa00ff'u32)
+ getSceneByName("main").addChild(vbox)
+
+
+ test "GridBox test":
+ build:
+ - GridBox grid:
+ call setPadding(2, 4, 8, 16)
+ call move(530, 144)
+ call setRow(3)
+ call setBackgroundColor(Color(1f, 1f, 1f))
+ - ColorRect first(color: Color(0xff6699ff'u32))
+ - ColorRect second(color: Color(0xff64ffff'u32))
+ - ColorRect third(color: Color(0xffaa00ff'u32))
+ - ColorRect fourth(color: Color(0xffcc33ff'u32))
+ - ColorRect fifth(color: Color(0xffcc66ff'u32))
+ - ColorRect sixth(color: Color(0xff6655ff'u32))
+ getSceneByName("main").addChild(grid)
+
+
+ test "EditText test":
+ build:
+ - EditText edit:
+ call move(0, 150)
+ getSceneByName("main").addChild(edit)
+
+
+ test "Scroll test":
+ # TODO: Fix it with glFramebuffer
+ build:
+ - Scroll scroll:
+ call setAnchor(1, 0, 1, 0)
+ - GridBox grid:
+ call setPadding(2, 4, 8, 16)
+ call setRow(3)
+ call setBackgroundColor(Color(1f, 1f, 1f))
+ - ColorRect first(color: Color(0xff6699ff'u32), rect_size: Vector2(100, 200))
+ - ColorRect second(color: Color(0xff64ffff'u32))
+ - ColorRect third(color: Color(0xffaa00ff'u32))
+ - ColorRect fourth(color: Color(0xffcc33ff'u32))
+ - ColorRect fifth(color: Color(0xffcc66ff'u32))
+ - ColorRect sixth(color: Color(0xff6655ff'u32))
+ getSceneByName("main").addChild(scroll)
+
+
+ test "ProgressBar test":
+ build:
+ - ProgressBar bar1:
+ progress_type: PROGRESS_BAR_HORIZONTAL
+ indeterminate: true
+ call setProgress(50)
+ call move(120, 110)
+ call resize(100, 20)
+ - ProgressBar bar2:
+ progress_type: PROGRESS_BAR_VERTICAL
+ indeterminate: true
+ call setProgress(50)
+ call move(220, 100)
+ call resize(20, 110)
+ - ProgressBar bar3:
+ progress_type: PROGRESS_BAR_CIRCLE
+ indeterminate: true
+ call setProgress(50)
+ call move(320, 110)
+ call resize(100, 100)
+ getSceneByName("main").addChildren(bar1, bar2, bar3)
+
+
+ test "Popup test":
+ build:
+ - Popup popup:
+ call setAnchor(0, 1, 0, 1)
+ - Label text:
+ call setText("popup!")
+ getSceneByName("main").getNode("control")@onProcess(self):
+ if isActionJustPressed("enter"):
+ popup.toggle()
+ getSceneByName("main").addChild(popup)
+
+
+ test "TextureButton test":
+ build:
+ - TextureButton button:
+ call setNormalTexture(load("assets/button_normal.png", GL_RGBA))
+ call setHoverTexture(load("assets/button_hover.png", GL_RGBA))
+ call setPressTexture(load("assets/button_press.png", GL_RGBA))
+ call resize(256, 64)
+ call move(120, 220)
+ call setText("Texture button")
+ getSceneByName("main").addChild(button)
+
+
+ test "TextureProgressBar test":
+ build:
+ - TextureProgressBar progress:
+ call setProgressTexture(load("assets/texture_progress_1.png", GL_RGBA))
+ call setBackgroundTexture(load("assets/texture_progress_0.png", GL_RGBA))
+ call setProgress(50)
+ call resize(256, 85)
+ call move(100, 300)
+ getSceneByName("main").addChild(progress)
+
+
+ test "Counter test":
+ build:
+ - Counter counter:
+ call move(360, 360)
+ call setMaxValue(100)
+ getSceneByName("main").addChild(counter)
+
+
+ test "Switch test":
+ build:
+ - Switch switch:
+ call move(360, 400)
+ getSceneByName("main").addChild(switch)
+
+
+ test "CheckBox test":
+ build:
+ - CheckBox check:
+ call setText("smth checkbox")
+ call enable()
+ call move(700, 300)
+ getSceneByName("main").addChild(check)
+
+
+ test "SubWindow test":
+ build:
+ - SubWindow window1:
+ call setIcon("assets/anim/0.jpg")
+ call setTitle("subwindow")
+ call move(500, 400)
+ call open()
+ getSceneByName("main").addChild(window1)
+
+
+ test "Slider test":
+ build:
+ - Slider slider1:
+ slider_type: SLIDER_HORIZONTAL
+ call resize(100, 10)
+ call move(600, 300)
+ - Slider slider2:
+ slider_type: SLIDER_VERTICAL
+ call resize(10, 100)
+ call move(600, 310)
+ getSceneByName("main").addChildren(slider1, slider2)
+
+ test "ToolTip test":
+ build:
+ - ToolTip tooltip:
+ call showAtMouse()
+ @onProcess():
+ tooltip.showAtMouse()
+ getSceneByName("main").addChild(tooltip)
+
+
+ test "Launch window":
+ windowLaunch()
diff --git a/tests/test30.nim b/tests/test30.nim
deleted file mode 100644
index 1be24213..00000000
--- a/tests/test30.nim
+++ /dev/null
@@ -1,33 +0,0 @@
-# --- Test 30. use CollisionShape2D. --- #
-# Please, compile with `--define:debug` or with `-d:debug` for see collision shapes.
-import nodesnim
-
-
-Window("hello world")
-
-
-var
- main = Scene("Main")
-
- shape1 = CollisionShape2D()
- shape2 = CollisionShape2D()
- shape3 = CollisionShape2D()
-
-
-shape1.move(100, 100)
-shape2.move(125, 125)
-shape3.move(170, 125)
-shape3.setShapeTypeCircle(0, 0, 35) # by default shape type is a rect, but you can change it at any time.
-shape2.disable = true # by default shape enabled, but you can change it at any time.
-
-echo shape1.isCollide(shape2) # if one of two shapes is disabled - return false.
-echo shape1.isCollide(shape3)
-echo shape2.isCollide(shape3)
-
-
-main.addChild(shape1)
-main.addChild(shape2)
-main.addChild(shape3)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test31.nim b/tests/test31.nim
deleted file mode 100644
index bfa469e9..00000000
--- a/tests/test31.nim
+++ /dev/null
@@ -1,49 +0,0 @@
-# --- Test 31. use KinematicBody2D node. --- #
-# Please, compile with `--define:debug` or with `-d:debug` for see collision shapes.
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- shape1 = CollisionShape2D()
- shape2 = CollisionShape2D()
- shape3 = CollisionShape2D()
- shape4 = CollisionShape2D()
-
- body = KinematicBody2D()
-
-
-shape1.move(100, 100)
-shape2.move(125, 125)
-shape4.move(360, 25)
-shape1.setShapeTypeCircle(0, 0, 35)
-shape2.resize(150, 50)
-# shape3.setShapeTypeCircle(0, 0, 35)
-shape3.setShapeTypePolygon(Vector2(0, 0), Vector2(15, 5), Vector2(28, 15), Vector2(35, 25), Vector2(5, 45))
-shape4.setShapeTypePolygon(Vector2(0, 0), Vector2(150, 65), Vector2(25, 150))
-
-
-addButtonAction("left", BUTTON_LEFT)
-body.on_process =
- proc(self: NodeRef) =
- if isActionPressed("left"):
- let
- mouse_pos = body.getGlobalMousePosition()
- distance = body.global_position.distance(mouse_pos)
- direction = body.global_position.directionTo(mouse_pos)
- speed = 3f
- if distance >= 5:
- body.moveAndCollide(direction*speed)
-
-
-main.addChild(shape1)
-main.addChild(shape2)
-main.addChild(shape4)
-main.addChild(body)
-body.addChild(shape3)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test32.nim b/tests/test32.nim
deleted file mode 100644
index 98abc2a6..00000000
--- a/tests/test32.nim
+++ /dev/null
@@ -1,22 +0,0 @@
-# --- Test 32. Use Switch node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- switch = Switch()
-
-main.addChild(switch)
-switch.move(128, 64)
-
-switch.on_switch =
- proc(self: SwitchRef, toggled: bool) = # this called when the user toggles switch.
- echo toggled
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test33.nim b/tests/test33.nim
deleted file mode 100644
index 3a0f2888..00000000
--- a/tests/test33.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-# --- Test 33. Event handlers with macros. --- #
-import nodesnim
-
-
-Window("test35")
-
-var
- main = Scene("Main")
- node = Button()
-
-node.setText("Hello")
-node.setAnchor(0.5, 0.5, 0.5, 0.5)
-
-
-node@onReady(self):
- echo "hello!"
-
-node@onInput(self, event):
- if event.isInputEventMouseButton() and event.pressed:
- echo "clicked"
-
-node@onClick(self, x, y):
- node.setText("clicked in " & $x & "," & $y & ".")
-
-
-main.addChild(node)
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test34.nim b/tests/test34.nim
deleted file mode 100644
index 3a225fba..00000000
--- a/tests/test34.nim
+++ /dev/null
@@ -1,26 +0,0 @@
-# --- Test 34. Rotation. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- sprite = Sprite()
-
-main.addChild(sprite)
-
-sprite.loadTexture("assets/anim/2.jpg")
-
-sprite.move(128, 128)
-sprite.centered = false
-
-
-sprite@on_process(self):
- sprite.rotation += 0.1
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test35.nim b/tests/test35.nim
deleted file mode 100644
index 4e2d001b..00000000
--- a/tests/test35.nim
+++ /dev/null
@@ -1,50 +0,0 @@
-# --- Test 35. use Camera2D node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-
-var
- main = Scene("Main")
-
- body = KinematicBody2D()
-
- sprite = Sprite()
-
- sprite1 = Sprite()
-
- camera = Camera2D()
-
- img = load("assets/anim/2.jpg")
- img1 = load("assets/anim/4.jpg")
-
-sprite.setTexture(img)
-sprite1.setTexture(img1)
-body.addChild(sprite)
-body.addChild(camera)
-
-camera.setTarget(body)
-camera.setLimit(-600, -400, 600, 400)
-camera.setCurrent()
-camera.enableSmooth()
-
-
-
-addButtonAction("left", BUTTON_LEFT)
-body.on_process =
- proc(self: NodeRef) =
- if isActionPressed("left"):
- let
- mouse_pos = body.getGlobalMousePosition()
- distance = body.global_position.distance(mouse_pos)
- direction = body.global_position.directionTo(mouse_pos)
- speed = 4f
- if distance >= 5:
- body.moveAndCollide(direction*speed)
-
-main.addChild(body)
-main.addChild(sprite1)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
diff --git a/tests/test36.nim b/tests/test36.nim
deleted file mode 100644
index f8f2ba59..00000000
--- a/tests/test36.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-# --- Test 36. Use Node3D. --- #
-import nodesnim
-
-Window("smth here")
-
-var
- scene = Scene("Main")
- node = Node3D()
-
-scene.addChild(node)
-
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test37.nim b/tests/test37.nim
deleted file mode 100644
index 74e16598..00000000
--- a/tests/test37.nim
+++ /dev/null
@@ -1,37 +0,0 @@
-# --- Test 37. Use GeometryInstance node. --- #
-import nodesnim
-
-
-Window("smth")
-
-build:
- - Scene scene:
- - GeometryInstance geometry1:
- translation: Vector3(1, 0, 5)
- color: Color(144, 133, 122, 0.8)
- - Sprite sprite:
- call setTexture(load("assets/anim/2.jpg"))
- call move(96, 96)
- - GeometryInstance geometry2:
- translation: Vector3(-1, 0, 2)
- color: Color(122, 133, 144, 0.8)
- - GeometryInstance geometry3:
- translation: Vector3(1, 0, 2)
- color: Color(144, 111, 144)
- geometry: GEOMETRY_SPHERE
- - Button button:
- text: stext"Hello! ^^"
- call resize(256, 64)
- call setAnchor(0.5, 0.5, 0.5, 0.5)
-
-geometry1@on_input(self, event):
- if event.isInputEventMouseMotion() and event.pressed:
- geometry1.rotateX(-event.yrel)
- geometry1.rotateY(-event.xrel)
- geometry2.rotateX(event.yrel)
- geometry2.rotateY(-event.xrel)
- geometry3.rotateX(event.yrel)
- geometry3.rotateY(-event.xrel)
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test38.nim b/tests/test38.nim
deleted file mode 100644
index 926d77f4..00000000
--- a/tests/test38.nim
+++ /dev/null
@@ -1,36 +0,0 @@
-# --- Test 38. Use SubWindow node. --- #
-import nodesnim
-
-
-Window("subwindow ._.")
-
-var
- main = Scene()
- window = SubWindow()
- window1 = SubWindow()
- window2 = SubWindow()
-
-
-main.addChild(window)
-main.addChild(window1)
-main.addChild(window2)
-
-window.move(64, 64)
-window.setIcon("assets/anim/0.jpg")
-window.open()
-
-window1.move(64, 64)
-window1.setIcon("assets/anim/0.jpg")
-window1.setBackgroundColor(Color("#efefef"))
-window1.setTitle("Hello, lol")
-window1.open()
-
-window2.move(64, 64)
-window2.setIcon("assets/anim/0.jpg")
-window2.setBackgroundColor(Color("#212112"))
-window2.setTitle("Aboba")
-window2.open()
-
-
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test39.nim b/tests/test39.nim
deleted file mode 100644
index 09b7b8e1..00000000
--- a/tests/test39.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-# --- Test 39. Use Scene builder. --- #
-import nodesnim
-
-Window("scene builder")
-
-build:
- - Scene scene:
- name: "Main scene"
- - Vbox background: # Instead of var background = Vbox()
- call setBackgroundColor(Color(21, 33, 48)) # You can change params without `objname`.param = value syntax.
- call setSizeAnchor(1.0, 0.1) # You can also call any method without `objname`.method(args) syntax. :eyes:
- call setAnchor(0.5, 0.5, 0.5, 0.5)
-
-echo background.size_anchor
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test4.nim b/tests/test4.nim
index 4fae0606..d85eb6a3 100644
--- a/tests/test4.nim
+++ b/tests/test4.nim
@@ -1,19 +1,41 @@
-# --- Test 4. Use ColorRect node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- colorrect = ColorRect()
-
-main.addChild(colorrect)
-
-colorrect.color = Color(1f, 1f, 1f) # default ColorRect color.
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
+# --- Test 4. Work with core. --- #
+import
+ nodesnim,
+ unittest
+
+
+suite "Work with core":
+ test "Anchor":
+ var anchor = Anchor(1, 0.5, 1, 0.5)
+ echo anchor
+
+ test "Color":
+ var
+ clr1 = Color(255, 100, 155, 1f) # RGBA
+ clr2 = Color(255, 100, 155, 255)
+ clr3 = Color(0xAACCFFFF'u32)
+ clr4 = Color("#AACCFFFF")
+ clr5 = Color("rgb(255, 100, 155)")
+ clr6 = Color("#acf")
+ assert clr1 == clr2
+ assert clr1 == clr5
+ assert clr3 == clr4
+ assert clr3 == clr6
+
+ test "Vector2":
+ var
+ vec1 = Vector2()
+ vec2 = Vector2(0, 0)
+ vec3 = Vector2(1, 2).normalized()
+ assert vec1 == vec2
+ echo vec3
+
+ test "stylesheet":
+ var
+ s = style({
+ nums: 0 0 0 0 0 0 0 1,
+ clr: rgba(255, 100, 255, 0.1),
+ padding: 0 0 0 0,
+ background-color: "#fff"
+ })
+ echo s
diff --git a/tests/test40.nim b/tests/test40.nim
deleted file mode 100644
index bbd2aa21..00000000
--- a/tests/test40.nim
+++ /dev/null
@@ -1,38 +0,0 @@
-# --- Test 40. Use AnimationPlayer. --- #
-import nodesnim
-
-Window("AnimationPlayer")
-
-build:
- - Scene scene:
- - ColorRect rect:
- color: Color(0, 0, 0)
- call resize(100, 100)
- - ColorRect rect1:
- color: Color(0, 0, 0)
- call resize(100, 100)
- call move(0, 150)
- - ColorRect rect2:
- color: Color(0.5, 0.8, 0.5)
- call resize(100, 100)
- call move(0, 300)
- - AnimationPlayer animation:
- call addState(rect.color.r.addr, @[(tick: 0, value: 0.0), (tick: 200, value: 1.0)])
- call addState(rect.position.x.addr, @[(tick: 0, value: 0.0), (tick: 100, value: 250.0)])
- call setDuration(200)
- call play()
- mode: ANIMATION_NORMAL # Default animation mode.
- - AnimationPlayer animation1:
- call addState(rect1.position.x.addr, @[(tick: 0, value: 0.0), (tick: 100, value: 250.0)])
- call setDuration(200)
- call play()
- mode: ANIMATION_EASE
- - AnimationPlayer animation2:
- call addState(rect2.position.x.addr, @[(tick: 0, value: 0.0), (tick: 100, value: 250.0)])
- call setDuration(200)
- call play()
- mode: ANIMATION_BEZIER
- bezier: (0.8, 0.9)
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test41.nim b/tests/test41.nim
deleted file mode 100644
index 57474f42..00000000
--- a/tests/test41.nim
+++ /dev/null
@@ -1,22 +0,0 @@
-# --- Test 41. Use StyleSheet object. --- #
-import nodesnim
-
-
-var mystyle = style(
- {
- background-color: rgba(255, 125, 255, 0.7),
- color: rgb(34, 34, 34),
- font-size: 1,
- text-align: center
- })
-echo mystyle
-
-var background = Color(mystyle["background-color"])
-
-assert background == Color(255, 125, 255, 0.7)
-
-echo StyleSheet(
- {
- "background-color": "#f2f2f7"
- }
-)
diff --git a/tests/test42.nim b/tests/test42.nim
deleted file mode 100644
index 9e1f3881..00000000
--- a/tests/test42.nim
+++ /dev/null
@@ -1,36 +0,0 @@
-# --- Test 42. Use Drawable and Control. --- #
-import nodesnim
-
-
-Window("drawable oops")
-
-build:
- - Scene scene:
- - Control ctrl
- - Control ctrl1:
- call move(350, 100)
- call setSizeAnchor(0.2, 0.2)
-
-ctrl1.background.setTexture(load("assets/sharp.jpg"))
-ctrl1.background.setCornerRadius(25)
-ctrl1.background.setCornerDetail(8)
-ctrl1.background.enableShadow(true)
-ctrl1.background.setShadowOffset(Vector2(0, 8))
-
-
-ctrl.resize(256, 96)
-ctrl.move(64, 64)
-ctrl.setStyle(style(
- {
- background-color: rgb(33, 65, 87),
- border-radius: 8,
- border-width: 1,
- border-color: rgb(0, 0, 0),
- shadow: true,
- shadow-offset: 8,
- size-anchor: 0.5 0.7
- }
-))
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test43.nim b/tests/test43.nim
deleted file mode 100644
index 2dbeab50..00000000
--- a/tests/test43.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-# --- Test 43. Use CheckBox node. --- #
-import nodesnim
-
-
-Window("drawable oops")
-
-build:
- - Scene scene:
- - CheckBox box:
- call setText("smth checkbox")
- call enable()
- - ColorRect rect:
- call move(100, 100)
-
-box@on_toggle(self, value):
- if value:
- rect.color.a = 1f
- else:
- rect.color.a = 0f
-
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test44.nim b/tests/test44.nim
deleted file mode 100644
index 06fe299f..00000000
--- a/tests/test44.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-# --- Test 44. Use GradientDrawable and Control. --- #
-import nodesnim
-
-
-Window("drawable oops")
-
-build:
- - Scene scene:
- - Control ctrl:
- call resize(256, 256)
- call move(150, 50)
-
-var gradient = GradientDrawable()
-gradient.setCornerRadius(16)
-gradient.setCornerDetail(16)
-gradient.enableShadow(true)
-gradient.setShadowOffset(Vector2(15, 15))
-gradient.setBorderColor(Color(1.0, 0.5, 0.5, 0.1))
-gradient.setBorderWidth(5)
-gradient.setStyle(style({
- corner-color: "#ff7 #ff7 #f77 #f77"
- }))
-ctrl.setBackground(gradient)
-
-
-addMainScene(scene)
-windowLaunch()
diff --git a/tests/test45.nim b/tests/test45.nim
deleted file mode 100644
index dfa7e0ba..00000000
--- a/tests/test45.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-# --- Test 45. Use TileMap node. --- #
-import nodesnim
-
-Window("Tilemap test")
-
-var
- tileset = TileSet("assets/tilesets/land.png", Vector2(64, 64), GL_RGBA)
-
-build:
- - Scene main:
- - TileMap map:
- call setTileSet(tileset)
- # map size layer count
- call resizeMap(newVector2(8096, 512), 1)
- call fill(newVector2(1, 0))
- call drawRect(3, 3, 10, 5, newVector2(9, 7))
- call drawTile(0, 0, newVector2(3, 0))
- call drawTile(1, 0, newVector2(7, 4.5))
- call drawTile(0, 1, newVector2(6.5, 5))
- call drawTile(1, 1, newVector2(7, 5))
-
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test46.nim b/tests/test46.nim
deleted file mode 100644
index c1df5090..00000000
--- a/tests/test46.nim
+++ /dev/null
@@ -1,62 +0,0 @@
-# --- Test 46. Use padding. --- #
-import nodesnim
-
-
-Window("Padding")
-
-
-build:
- - Scene main:
- - Box box:
- call setPadding(8, 16, 2, 8)
- call setBackgroundColor(Color("#5aa"))
- - ColorRect rect1:
- color: Color("#ff7")
- call resize(64, 64)
- - ColorRect rect2:
- color: Color("#f7f")
- - VBox vbox:
- call setPadding(2, 4, 8, 16)
- call move(100, 64)
- call setChildAnchor(1, 1, 1, 1)
- call setBackgroundColor(Color("#5aa"))
- - ColorRect rect3:
- color: Color("#ff7")
- call resize(64, 64)
- - ColorRect rect4:
- color: Color("#f7f")
- - HBox hbox:
- call setPadding(2, 4, 8, 16)
- call move(200, 64)
- call setChildAnchor(1, 1, 1, 1)
- call setBackgroundColor(Color("#5aa"))
- - ColorRect rect5:
- color: Color("#ff7")
- call resize(64, 64)
- - ColorRect rect6:
- color: Color("#f7f")
- - GridBox gridbox:
- call setPadding(2, 4, 8, 16)
- call move(300, 200)
- call setChildAnchor(1, 1, 1, 1)
- call setBackgroundColor(Color("#5aa"))
- - ColorRect rect7:
- color: Color("#ff7")
- call resize(64, 64)
- - ColorRect rect8:
- color: Color("#f7f")
- - ColorRect rect9:
- color: Color("#ff7")
- call resize(64, 64)
- - ColorRect rect10:
- color: Color("#f7f")
- - Label text:
- call setText("Hello, world!")
- call setBackgroundColor(Color("#324"))
- call resize(0, 0)
- call setPadding(8, 8, 8, 8)
- call move(32, 200)
-
-
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test47.nim b/tests/test47.nim
deleted file mode 100644
index f921873e..00000000
--- a/tests/test47.nim
+++ /dev/null
@@ -1,39 +0,0 @@
-# --- Test 47. Use margin. --- #
-import nodesnim
-
-
-Window("Margin test")
-
-
-build:
- - Scene main:
- - HBox box1:
- call setBackgroundColor(Color("#55c"))
- call setPadding(8, 8, 8, 8)
- call move(64, 64)
- separator: 0
- - ColorRect rect1:
- color: Color("#ee5")
- call setMargin(0, 16, 0, 0)
- - ColorRect rect2:
- color: Color("#5ee")
- call setMargin(8, 0, 32, 0)
- - ColorRect rect3:
- color: Color("#e5e")
- - VBox box2:
- call setBackgroundColor(Color("#55c"))
- call setPadding(8, 8, 8, 8)
- call move(256, 64)
- separator: 0
- - ColorRect rect4:
- color: Color("#ee5")
- call setMargin(16, 0, 0, 0)
- - ColorRect rect5:
- color: Color("#5ee")
- call setMargin(0, 8, 0, 32)
- - ColorRect rect6:
- color: Color("#e5e")
-
-
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test48.nim b/tests/test48.nim
deleted file mode 100644
index 55de4d9b..00000000
--- a/tests/test48.nim
+++ /dev/null
@@ -1,53 +0,0 @@
-# --- Test 48. Use Camera3D node. --- #
-import nodesnim
-
-Window("camera 3d test", 1024, 640)
-
-
-build:
- - Scene main:
- - Node3D root:
- call translate(2, 2, -5)
- - Camera3D camera:
- call setCurrent()
- call changeTarget(root)
- - GeometryInstance cube:
- translation: Vector3(-1, 0, 2)
- color: Color(122, 133, 144, 0.8)
- - GeometryInstance cube1:
- translation: Vector3(2, 0, -2)
- color: Color(144, 144, 122, 0.8)
- - GeometryInstance cube2:
- translation: Vector3(1, 2.5, 1)
- color: Color(144, 111, 144, 0.8)
- - GeometryInstance sphere:
- translation: Vector3(-1, -1, 1)
- color: Color(144, 77, 144, 1.0)
- geometry: GEOMETRY_SPHERE
- - ProgressBar health:
- call resize(256, 48)
- call setAnchor(0, 1, 0, 1)
- call setProgress(50)
- call setProgressColor(Color("#a77"))
- call setBackgroundColor(Color(222, 222, 222, 0.5))
-
-addKeyAction("forward", "w")
-addKeyAction("back", "s")
-addKeyAction("left", "a")
-addKeyAction("right", "d")
-
-root@on_input(self, event):
- if event.isInputEventMouseMotion() and event.pressed:
- camera.rotate(-event.xrel*0.1, event.yrel*0.1)
- if isActionPressed("left"):
- root.translate(camera.right * -0.1)
- if isActionPressed("right"):
- root.translate(camera.right * 0.1)
- if isActionPressed("forward"):
- root.translate(camera.front*0.1)
- if isActionPressed("back"):
- root.translate(camera.front*(-0.1))
-
-
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test49.nim b/tests/test49.nim
deleted file mode 100644
index 495d5ffd..00000000
--- a/tests/test49.nim
+++ /dev/null
@@ -1,38 +0,0 @@
-# --- Use TileMap ISOMETRIC mode --- #
-import nodesnim
-
-Window("Tilemap test", 1024, 640)
-
-var
- tileset = TileSet("assets/tilesets/isometric_desert.png", Vector2(64, 32), GL_RGBA)
-
-build:
- - Scene main:
- - TileMap map:
- call setTileSet(tileset)
- call resizeMap(newVector2(8096, 512), layer_count=4)
- call setMode(TILEMAP_ISOMETRIC)
- call fill(newVector2(1, 0))
- call drawRect(3, 3, 10, 5, newVector2(15, 1))
-
- # platform
- call drawTile(2, 4, newVector2(0, 27), 1)
- call drawTile(1, 5, newVector2(0, 28), 1)
-
- # cross
- call drawTile(4, 6, newVector2(14, 13), 1)
- call drawTile(3, 7, newVector2(14, 14), 1)
-
- # sign
- call drawTile(4, 5, newVector2(11, 12), 1)
- call drawTile(4, 5, newVector2(11, 13), 2)
- call drawTile(4, 5, newVector2(11, 14), 3)
-
- # magic
- call drawTile(5, 10, newVector2(2, 33), 1)
- call drawTile(6, 11, newVector2(3, 33), 1)
- call drawTile(4, 11, newVector2(2, 34), 1)
- call drawTile(5, 12, newVector2(3, 34), 1)
-
-addMainScene(main)
-windowLaunch()
diff --git a/tests/test5.nim b/tests/test5.nim
index c8c3a900..df7106fc 100644
--- a/tests/test5.nim
+++ b/tests/test5.nim
@@ -1,49 +1,76 @@
-# --- Test 5. Handle Control node events. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- colorrect = ColorRect()
-
- colorrect1 = ColorRect()
-
-main.addChild(colorrect)
-colorrect.addChild(colorrect1)
-
-
-colorrect1.on_click =
- proc(self: ControlRef, x, y: float) = # This called when the user clicks on the Control node (ColorRect in this case).
- colorrect1.move(3, 3)
-
-colorrect.on_press =
- proc(self: ControlRef, x, y: float) = # This called when the user holds on the mouse on the Control node.
- colorrect.color.r -= 0.001
-
-colorrect.on_release =
- proc(self: ControlRef, x, y: float) = # This called when the user no more holds on the mouse.
- colorrect.color.r = 1
-
-colorrect.on_focus =
- proc(self: ControlRef) = # This called when the Control node gets focus.
- echo "hello ^^."
-
-colorrect.on_unfocus =
- proc(self: ControlRef) = # This called when the Control node loses focus.
- echo "bye :("
-
-colorrect1.on_mouse_enter =
- proc(self: ControlRef, x, y: float) = # This called when the mouse enters the Control node.
- colorrect1.color = Color(1, 0.6, 1, 0.5)
-
-colorrect1.on_mouse_exit =
- proc(self: ControlRef, x, y: float) = # This called when the mouse exit from the Control node.
- colorrect1.color = Color(1f, 1f, 1f)
-
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
+# --- Test 5. Work with graphics. --- #
+import
+ nodesnim,
+ unittest
+
+
+suite "Work with graphics.":
+
+ test "Setup window":
+ Window("graphics test")
+
+
+ test "Setup scene":
+ build:
+ - Scene main
+
+ addMainScene(main)
+
+ test "Color background":
+ build:
+ - Control ctrl
+
+ ctrl.resize(256, 96)
+ ctrl.move(64, 64)
+ ctrl.setStyle(style(
+ {
+ background-color: rgb(33, 65, 87),
+ border-radius: 8,
+ border-width: 1,
+ border-color: rgb(0, 0, 0),
+ shadow: true,
+ shadow-offset: 8,
+ size-anchor: 0.5 0.7
+ }
+ ))
+
+ getSceneByName("main").addChild(ctrl)
+
+
+ test "Image background":
+ build:
+ - Control ctrl1:
+ call move(350, 100)
+ call setSizeAnchor(0.2, 0.2)
+
+ ctrl1.background.setTexture(load("assets/sharp.jpg"))
+ ctrl1.background.setCornerRadius(25)
+ ctrl1.background.setCornerDetail(8)
+ ctrl1.background.enableShadow(true)
+ ctrl1.background.setShadowOffset(Vector2(0, 8))
+
+ getSceneByName("main").addChild(ctrl1)
+
+
+ test "Gradient background":
+ build:
+ - Control ctrl2:
+ call resize(96, 96)
+ call setAnchor(0, 0.5, 0, 0.5)
+ var gradient = GradientDrawable()
+ gradient.setCornerRadius(16)
+ gradient.setCornerDetail(16)
+ gradient.enableShadow(true)
+ gradient.setShadowOffset(Vector2(15, 15))
+ gradient.setBorderColor(Color(1.0, 0.5, 0.5, 0.1))
+ gradient.setBorderWidth(5)
+ gradient.setStyle(style({
+ corner-color: "#ff7 #ff7 #f77 #f77"
+ }))
+ ctrl2.setBackground(gradient)
+
+ getSceneByName("main").addChild(ctrl2)
+
+
+ test "Launch window":
+ windowLaunch()
diff --git a/tests/test50.nim b/tests/test50.nim
deleted file mode 100644
index 0322e8e9..00000000
--- a/tests/test50.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-# --- Make your own node --- #
-import nodesnim
-
-
-type
- MyOwnNodeRef = ref MyOwnNodeObj
- MyOwnNodeObj = object of NodeRef # NodeRef/Node2DRef/ControlRef/Node3DRef
- property: int
-
-
-proc MyOwnNode(name: string = "MyOwnNode"): MyOwnNodeRef =
- nodepattern(MyOwnNodeRef)
- # controlpattern()/node2dpattern()/node3dpattern()
- result.property = 100
-
-
-build:
- - MyOwnNode node:
- property: 10
-
-echo node.property
diff --git a/tests/test6.nim b/tests/test6.nim
index 357ec11c..079ccabc 100644
--- a/tests/test6.nim
+++ b/tests/test6.nim
@@ -1,38 +1,182 @@
-# --- Test 6. Anchor setting. --- #
-import nodesnim
+# --- Test 6. Work with 2D nodes. --- #
+import
+ nodesnim,
+ unittest
-Window("hello world")
+suite "Work with 2D nodes.":
+
+ test "Setup window":
+ Window("2D nodes test", 1024, 640)
-var
- main = Scene("Main")
- lightblue = ColorRect()
- violet = ColorRect()
+ test "Register events":
+ addButtonAction("left", BUTTON_LEFT)
+ addKeyAction("w", "w")
+ addKeyAction("a", "a")
+ addKeyAction("s", "s")
+ addKeyAction("d", "d")
-main.addChild(lightblue)
-lightblue.addChild(violet)
+ test "Setup scene":
+ build:
+ - Scene main
+ addMainScene(main)
-lightblue.resize(256, 128)
-lightblue.move(128, 64)
-violet.setAnchor( # Try to change it! ^^
- 0.5, # parent anchor at X-axis.
- 0.5, # parent anchor at Y-axis.
- 0.5, # anchor at X-axis.
- 0.5 # anchor at Y-axis.
-)
-lightblue.setAnchor(1, 1, 1, 1)
-lightblue.setSizeAnchor(
- 0, # size anchor at X-axis. If 0 then not used.
- 1 # size anchor at Y-axis. If 0 then not used.
-)
+ test "Node2D test":
+ build:
+ - Node2D node2d(name: "2d node")
+ getSceneByName("main").addChild(node2d)
-lightblue.color = Color(0xaaccffff'u32)
-violet.color = Color(0xccaaffff'u32)
+ test "Sprite test":
+ build:
+ - Sprite sprite:
+ centered: true
+ call loadTexture("assets/anim/2.jpg")
+ call move(80, 80)
+ getSceneByName("main").addChild(sprite)
-addScene(main)
-setMainScene("Main")
-windowLaunch()
+
+ test "AnimatedSprite test":
+ build:
+ - AnimatedSprite animation:
+ centered: false
+ z_index: -10
+ call addFrame("default", load("assets/anim/0.jpg"))
+ call addFrame("default", load("assets/anim/1.jpg"))
+ call addFrame("default", load("assets/anim/2.jpg"))
+ call addFrame("default", load("assets/anim/3.jpg"))
+ call addFrame("default", load("assets/anim/4.jpg"))
+ call play(name = "", backward = false)
+ call setSpeed("default", 5) # name, frames-per-second
+ getSceneByName("main").addChild(animation)
+
+
+ test "YSort test":
+ var image = load("assets/anim/2.jpg")
+ build:
+ - YSort sort:
+ z_index: 1
+ call move(720, 80)
+ - Sprite s1:
+ filter: Color("#6644ff")
+ call setTexture(image)
+ - Sprite s2:
+ filter: Color("#997799")
+ call setTexture(image)
+ call move(0, 80)
+ - Sprite s3:
+ filter: Color("#9f9")
+ call setTexture(image)
+ call move(0, 160)
+ getSceneByName("main").addChild(sort)
+
+ test "KinematicBody2D test":
+ build:
+ - KinematicBody2D body:
+ - CollisionShape2D collision:
+ call setShapeTypePolygon(Vector2(0, 0), Vector2(15, 5), Vector2(28, 15),
+ Vector2(35, 25), Vector2(5, 45))
+ - CollisionShape2D rect_collision:
+ call resize(160, 40)
+ call move(100, 200)
+ - CollisionShape2D polygon_collision:
+ call setShapeTypePolygon(Vector2(0, 0), Vector2(150, 65), Vector2(25, 150))
+ call move(300, 200)
+ - CollisionShape2D circle_collision:
+ call setShapeTypeCircle(0, 0, 64)
+ call move(100, 300)
+ body@onProcess(self):
+ if isActionPressed("left"):
+ let
+ mouse_pos = body.getGlobalMousePosition()
+ distance = body.global_position.distance(mouse_pos)
+ direction = body.global_position.directionTo(mouse_pos)
+ speed = 3f
+ if distance >= 5:
+ body.moveAndCollide(direction*speed)
+ getSceneByName("main").addChildren(body, rect_collision, polygon_collision, circle_collision)
+
+
+ test "Camera2D test":
+ build:
+ - KinematicBody2D player:
+ z_index: 50
+ - Sprite player_sprite:
+ z_index: 50
+ centered: true
+ filter: Color("#555")
+ call loadTexture("assets/anim/2.jpg")
+ - Camera2D camera:
+ call setTarget(player)
+ call setLimit(-2048, -1024, 2048, 1024)
+ call setCurrent()
+ call enableSmooth()
+ player@onProcess(self):
+ if isActionPressed("w"):
+ player.move(0, -10)
+ elif isActionPressed("s"):
+ player.move(0, 10)
+ if isActionPressed("a"):
+ player.move(-10, 0)
+ elif isActionPressed("d"):
+ player.move(10, 0)
+ getSceneByName("main").addChildren(player, camera)
+
+
+ test "TileMap 2d test":
+ var tileset = TileSet("assets/tilesets/land.png", Vector2(64, 64), GL_RGBA)
+ build:
+ - TileMap map:
+ z_index: -100
+ call setTileSet(tileset)
+ call move(-2048, -1024)
+ # map size layer count
+ call resizeMap(Vector2(512, 128), 1)
+ call fill(Vector2(1, 0))
+ call drawRect(3, 3, 10, 5, Vector2(9, 7))
+ call drawTile(0, 0, Vector2(3, 0))
+ call drawTile(1, 0, Vector2(7, 4.5))
+ call drawTile(0, 1, Vector2(6.5, 5))
+ call drawTile(1, 1, Vector2(7, 5))
+ getSceneByName("main").addChild(map)
+
+
+ test "TileMap isometric test":
+ var tileset = TileSet("assets/tilesets/isometric_desert.png", Vector2(64, 32), GL_RGBA)
+ build:
+ - TileMap map:
+ z_index: -80
+ call setMode(TILEMAP_ISOMETRIC)
+ call setTileSet(tileset)
+ call move(-2048, -1024)
+ # map size layer count
+ call resizeMap(Vector2(32, 32), layer_count=4)
+ call fill(Vector2(1, 0))
+ call drawRect(3, 3, 10, 5, Vector2(15, 1))
+
+ # platform
+ call drawTile(2, 4, Vector2(0, 27), 1)
+ call drawTile(1, 5, Vector2(0, 28), 1)
+
+ # cross
+ call drawTile(4, 6, Vector2(14, 13), 1)
+ call drawTile(3, 7, Vector2(14, 14), 1)
+
+ # sign
+ call drawTile(4, 5, Vector2(11, 12), 1)
+ call drawTile(4, 5, Vector2(11, 13), 2)
+ call drawTile(4, 5, Vector2(11, 14), 3)
+
+ # magic
+ call drawTile(5, 10, Vector2(2, 33), 1)
+ call drawTile(6, 11, Vector2(3, 33), 1)
+ call drawTile(4, 11, Vector2(2, 34), 1)
+ call drawTile(5, 12, Vector2(3, 34), 1)
+ getSceneByName("main").addChild(map)
+
+
+ test "Launch window":
+ windowLaunch()
diff --git a/tests/test7.nim b/tests/test7.nim
index 7bad2d73..0080eb44 100644
--- a/tests/test7.nim
+++ b/tests/test7.nim
@@ -1,41 +1,83 @@
-# --- Test 7. Change scenes. --- #
-import nodesnim
+# --- Test 7. Work with 3D nodes. --- #
+import
+ nodesnim,
+ unittest
-Window("hello world")
+suite "Work with 3D nodes.":
+
+ test "Setup window":
+ Window("3D nodes test", 1024, 640)
-var
- main = Scene("Main")
- second = Scene("Second scene")
- lightblue = ColorRect()
+ test "Setup scene":
+ build:
+ - Scene main
+ addMainScene(main)
- violet = ColorRect()
+ test "Register events":
+ addKeyAction("forward", "w")
+ addKeyAction("back", "s")
+ addKeyAction("left", "a")
+ addKeyAction("right", "d")
-addKeyAction("change_scene", K_SPACE)
-main.addChild(violet)
-second.addChild(lightblue)
+ test "GeometryInstance test":
+ build:
+ - GeometryInstance cube:
+ translation: Vector3(-1, 0, 2)
+ color: Color(122, 133, 144, 0.8)
+ - GeometryInstance cube1:
+ translation: Vector3(2, 0, -2)
+ color: Color(144, 144, 122, 0.8)
+ - GeometryInstance cube2:
+ translation: Vector3(1, 2.5, 1)
+ color: Color(144, 111, 144, 0.8)
+ - GeometryInstance sphere:
+ translation: Vector3(-1, -1, 1)
+ color: Color(144, 77, 144, 1.0)
+ geometry: GEOMETRY_SPHERE
+ - GeometryInstance cylinder:
+ translation: Vector3(2, -1, 1)
+ color: Color(144, 77, 144, 1.0)
+ geometry: GEOMETRY_CYLINDER
+ getSceneByName("main").addChildren(cube, cube1, cube2, sphere, cylinder)
-violet.color = Color(0xccaaffff'u32)
-lightblue.color = Color(0xaaccffff'u32)
-lightblue.setAnchor(0.5, 0.5, 0.5, 0.5)
-violet.on_process =
- proc(self: NodeRef) =
- if isActionJustPressed("change_scene"):
- echo "bye from main scene :("
- changeScene("Second scene") # This function changes current scene.
+ test "Camera3D test":
+ build:
+ - Node3D root:
+ call translate(2, 2, -5)
+ - Camera3D camera:
+ call setCurrent()
+ call changeTarget(root)
+ root@onInput(self, event):
+ if event.isInputEventMouseMotion() and event.pressed:
+ camera.rotate(-event.xrel*0.25, event.yrel*0.25)
-lightblue.on_process =
- proc(self: NodeRef) =
- if isActionJustPressed("change_scene"):
- echo "bye from second scene :("
- changeScene("Main")
+ root@onProcess(self):
+ if isActionPressed("left"):
+ root.translate(camera.right * -0.1)
+ if isActionPressed("right"):
+ root.translate(camera.right * 0.1)
+ if isActionPressed("forward"):
+ root.translate(camera.front*0.1)
+ if isActionPressed("back"):
+ root.translate(camera.front*(-0.1))
+ getSceneByName("main").addChild(root)
-addScene(main)
-addScene(second)
-setMainScene("Main")
-windowLaunch()
+ test "Sprite3D test":
+ build:
+ - Sprite3D sprite:
+ call loadTexture("assets/anim/2.jpg", GL_RGB)
+ call translate(-3, -2, 2)
+
+ sprite@onProcess(self):
+ sprite.rotateY(0.5)
+ getSceneByName("main").addChild(sprite)
+
+
+ test "Launch window":
+ windowLaunch()
diff --git a/tests/test8.nim b/tests/test8.nim
index dc91b45c..69e49456 100644
--- a/tests/test8.nim
+++ b/tests/test8.nim
@@ -1,26 +1,21 @@
-# --- Test 8. Use TextureRect node. --- #
+# --- Test 8. Make your own node. --- #
import nodesnim
-Window("hello world")
+type
+ MyOwnNodeRef = ref MyOwnNodeObj
+ MyOwnNodeObj = object of NodeRef # NodeRef/Node2DRef/ControlRef/Node3DRef
+ property: int
-var
- main = Scene("Main")
- texturerect = TextureRect()
+proc MyOwnNode(name: string = "MyOwnNode"): MyOwnNodeRef =
+ nodepattern(MyOwnNodeRef)
+ # controlpattern()/node2dpattern()/node3dpattern()
+ result.property = 100
-main.addChild(texturerect)
-var texture = load("assets/sharp.jpg") # Load image from file.
-texturerect.setTexture(texture)
-texturerect.resize(256, 256)
-texturerect.setBackgroundColor(Color(1, 0.6, 1, 0.6))
-texturerect.setTextureFilter(Color(1f, 1f, 1f))
-# texture mode can be TEXTURE_CROP, TEXTURE_KEEP_ASPECT_RATIO or TEXTURE_FILL_XY
-texturerect.texture_mode = TEXTURE_CROP
-texturerect.texture_anchor = Anchor(0.5, 1, 0.5, 1)
+build:
+ - MyOwnNode node:
+ property: 10
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()
+echo node.property
diff --git a/tests/test9.nim b/tests/test9.nim
deleted file mode 100644
index 59b736da..00000000
--- a/tests/test9.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-# --- Test 9. Use Label node. --- #
-import nodesnim
-
-
-Window("hello world")
-
-var
- main = Scene("Main")
-
- label = Label()
-
-main.addChild(label)
-
-label.setText("Hello, world!\nsecondline\nThis is a long sentence.") # Change label text.
-label.setTextAlign(0.2, 0.5, 0.2, 0.5) # try to change it ^^.
-label.setSizeAnchor(1, 1)
-label.setTextColor(Color(1f, 1f, 1f)) # default text color.
-
-addScene(main)
-setMainScene("Main")
-windowLaunch()