Skip to content

Commit 0d462e2

Browse files
committed
added signal declaration
1 parent 388bea9 commit 0d462e2

File tree

2 files changed

+106
-5
lines changed

2 files changed

+106
-5
lines changed

godot/internal/godotinternaltypes.nim

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,14 @@ type
9292
RID,
9393
Object,
9494
Dictionary,
95-
Array, ## 20
95+
Array,
9696
# arrays
97-
PoolByteArray,
97+
PoolByteArray, ## 20
9898
PoolIntArray,
9999
PoolRealArray,
100100
PoolStringArray,
101-
PoolVector2Array, ## 25
102-
PoolVector3Array,
101+
PoolVector2Array,
102+
PoolVector3Array, ## 25
103103
PoolColorArray
104104

105105
VariantCallErrorType* {.size: sizeof(cint), pure.} = enum
@@ -291,7 +291,7 @@ type
291291
methodData*: pointer
292292
freeFunc*: proc (a2: pointer) {.noconv.}
293293

294-
GodotSignalArgument* {.bycopy.} = object
294+
GodotSignalArgument* {.bycopy, packed.} = object
295295
name*: GodotString
296296
typ*: cint
297297
hint*: GodotPropertyHint

godot/nim/godotmacros.nim

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,23 @@ type
2323
nimNode: NimNode
2424
isNoGodot: bool
2525

26+
SignalArgDecl = ref object
27+
name: string
28+
typ: NimNode
29+
30+
SignalDecl = ref object
31+
name: string
32+
args: seq[SignalArgDecl]
33+
2634
ObjectDecl = ref object
2735
name: string
2836
parentName: string
2937
fields: seq[VarDecl]
38+
signals: seq[SignalDecl]
3039
methods: seq[MethodDecl]
3140
isTool: bool
3241

42+
3343
ParseError = object of Exception
3444

3545
include "internal/backwardcompat.inc.nim"
@@ -178,11 +188,34 @@ proc parseVarSection(decl: NimNode): seq[VarDecl] =
178188
else:
179189
result.add(identDefsToVarDecls(decl[i]))
180190

191+
proc parseSignal(sig: NimNode): SignalDecl =
192+
let errorMsg = "Signal declaration must have this format: signal my_signal(param1: int, param2: string)"
193+
194+
if sig.kind != nnkCommand:
195+
parseError(sig, errorMsg)
196+
if not (sig[1].kind == nnkCall or sig[1].kind == nnkObjConstr):
197+
parseError(sig, errorMsg)
198+
199+
result = SignalDecl(
200+
name: $sig[1][0],
201+
args: newSeq[SignalArgDecl]()
202+
)
203+
204+
if sig[1].kind == nnkObjConstr:
205+
for i in 1..<sig[1].len:
206+
var nexpr = sig[1][i]
207+
case nexpr.kind:
208+
of nnkExprColonExpr:
209+
result.args.add(SignalArgDecl(name: nexpr[0].repr, typ: nexpr[1]))
210+
else:
211+
parseError(sig, errorMsg)
212+
181213
proc parseType(ast: NimNode): ObjectDecl =
182214
let definition = ast[0]
183215
let body = ast[^1]
184216
result = ObjectDecl(
185217
fields: newSeq[VarDecl](),
218+
signals: newSeq[SignalDecl](),
186219
methods: newSeq[MethodDecl]()
187220
)
188221
(result.name, result.parentName) = extractNames(definition)
@@ -207,6 +240,10 @@ proc parseType(ast: NimNode): ObjectDecl =
207240
of nnkProcDef, nnkMethodDef:
208241
let meth = parseMethod(statement)
209242
result.methods.add(meth)
243+
of nnkCommand:
244+
if statement[0].strVal == "signal":
245+
let sig = parseSignal(statement)
246+
result.signals.add(sig)
210247
of nnkCommentStmt:
211248
discard
212249
else:
@@ -619,6 +656,60 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
619656
argTypes, genSym(nskProc, "methFunc"),
620657
hasReturnValue)))
621658

659+
template registerGodotSignalNoArgs(classNameLit, signalName) =
660+
var godotSignal = GodotSignal(
661+
name: signalName.toGodotString())
662+
nativeScriptRegisterSignal(getNativeLibHandle(), classNameLit, godotSignal)
663+
664+
template initSignalArgumentParameters(argName, argTypeIdent, typeInfoIdent,
665+
godotStringIdent, godotVariantIdent)=
666+
var godotStringIdent = argName.toGodotString()
667+
mixin godotTypeInfo
668+
const typeInfoIdent = when compiles(godotTypeInfo(argTypeIdent)):
669+
godotTypeInfo(argTypeIdent)
670+
else: GodotTypeInfo()
671+
var godotVariantIdent:GodotVariant
672+
initGodotVariant(godotVariantIdent)
673+
674+
template deinitSignalArgumentParameters(godotStringIdent, godotVariantIdent)=
675+
godotStringIdent.deinit()
676+
godotVariantIdent.deinit()
677+
678+
template createSignalArgument(typeInfoIdent, godotStringIdent, godotVariantIdent) =
679+
GodotSignalArgument(name: godotStringIdent,
680+
typ: ord(typeInfoIdent.variantType),
681+
defaultValue: godotVariantIdent)
682+
683+
template registerGodotSignal(classNameLit, signalName, argCount, sigArgs) =
684+
var sigArgsArr = sigArgs
685+
var godotSignal = GodotSignal(
686+
name: signalName.toGodotString(),
687+
numArgs: argCount,
688+
args: addr(sigArgsArr[0]))
689+
nativeScriptRegisterSignal(getNativeLibHandle(), classNameLit, godotSignal)
690+
691+
for sig in obj.signals:
692+
if sig.args.len == 0:
693+
result.add(getAst(
694+
registerGodotSignalNoArgs(classNameLit, sig.name)))
695+
else:
696+
var sigArgsParams:seq[(NimNode, NimNode, NimNode)]
697+
for arg in sig.args:
698+
var p = (genSym(nskConst, "typeInfo"), genSym(nskVar, "godotString"), genSym(nskVar, "godotVariant"))
699+
sigArgsParams.add p
700+
result.add(getAst(
701+
initSignalArgumentParameters(arg.name, arg.typ, p[0], p[1], p[2])))
702+
703+
var sigArgs = newNimNode(nnkBracket)
704+
for p in sigArgsParams:
705+
sigArgs.add(getAst(
706+
createSignalArgument(p[0], p[1], p[2])))
707+
result.add(getAst(
708+
registerGodotSignal(classNameLit, sig.name, sig.args.len, sigArgs)))
709+
for p in sigArgsParams:
710+
result.add(getAst(
711+
deinitSignalArgumentParameters(p[1], p[2])))
712+
622713
if isRef:
623714
# add ref/unref for types inherited from Reference
624715
template registerRefIncDec(classNameLit) =
@@ -653,17 +744,27 @@ macro gdobj*(ast: varargs[untyped]): untyped =
653744
## ## ``hintStr`` depends on the value of ``hint``, its format is
654745
## ## described in ``GodotPropertyHint`` documentation.
655746
##
747+
## signal my_signal(amount:int, message:string)
748+
## ## Defines a signal ``my_signal`` with parameters
749+
##
656750
## method ready*() =
657751
## ## Exported methods are exported to Godot by default,
658752
## ## and their Godot names are prefixed with ``_``
659753
## ## (in this case ``_ready``)
660754
## print("I am ready! myString is: " & self.myString)
661755
##
756+
## ## connect to the signal and then emit it
757+
## discard self.connect("my_signal", self, "on_my_signal")
758+
## self.emit_signal("my_signal", 123.toVariant, "hello godot".toVariant)
759+
##
662760
## proc myProc*() {.gdExport.} =
663761
## ## Exported to Godot as ``my_proc``
664762
## print("myProc is called! Incrementing myField.")
665763
## inc self.myField
666764
##
765+
## proc on_my_signal(amount:int, message:string) {.gdExport.} =
766+
## print("received my_signal " & amount & " " & message)
767+
##
667768
## If parent type is omitted, the type is inherited from ``Object``.
668769
##
669770
## ``tool`` specifier can be added to mark the type as an

0 commit comments

Comments
 (0)