Skip to content

Commit 20f683d

Browse files
committed
Released version 0.9.0
* Updated to DOtherSide 0.8.0 * Added basic support for QObject connections * Added support for defining multiple QObject in the same nim file
1 parent 5f16243 commit 20f683d

23 files changed

+494
-56
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ nimcache
44
*.nimproject*
55
*.exe
66
*.qmlc
7+
*.idea
8+
*main

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
QML binding for the Nim programming language
44

55
## Requirements
6-
* [DOtherside](https://github.com/filcuc/DOtherSide) 0.7.X
6+
* [DOtherside](https://github.com/filcuc/DOtherSide) 0.8.X
77
* [Nim](http://nim-lang.org/) 1.2.0 or higher
88

99
## Build instructions

doc/nimqml.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
Filippo Cucchetto <filippocucchetto@gmail.com>
33

44
Will Szumski <will@cowboycoders.org>
5-
:Version: 0.8.0
6-
:Date: 2021/01/05
5+
:Version: 0.9.0
6+
:Date: 2021/05/01
77

88

99
Introduction

examples/abstractitemmodel/abstractitemmodel.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ description = "abstractitemmodel"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"

examples/charts/charts.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ description = "charts"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"
1111

examples/connections/main.nim

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import nimqml
2+
3+
4+
QtObject:
5+
type Contact* = ref object of QObject
6+
name: string
7+
8+
proc delete*(self: Contact) =
9+
self.QObject.delete
10+
11+
proc setup(self: Contact) =
12+
self.QObject.setup
13+
14+
proc newContact(): Contact =
15+
new(result, delete)
16+
result.name = ""
17+
result.setup
18+
19+
proc name*(self: Contact): string {.slot.} =
20+
result = self.name
21+
22+
proc nameChanged*(self: Contact, firstName: string) {.signal.}
23+
24+
proc setName*(self: Contact, name: string) {.slot.} =
25+
if self.name != name:
26+
self.name = name
27+
self.nameChanged(name)
28+
29+
proc `name=`*(self: Contact, name: string) = self.setName(name)
30+
31+
QtProperty[string] name:
32+
read = name
33+
write = setName
34+
notify = nameChanged
35+
36+
37+
proc main() =
38+
block: # Raw string connection
39+
let c1 = newContact()
40+
let c2 = newContact()
41+
discard QObject.connect(c1, SIGNAL("nameChanged(QString)"), c2, SLOT("setName(QString)"))
42+
assert(c1.name != "John" and c2.name != "John")
43+
c1.setName("John")
44+
assert(c2.name == "John")
45+
block: # Signal and slot connection
46+
let c1 = newContact()
47+
let c2 = newContact()
48+
discard QObject.connect(c1, nameChanged, c2, setName)
49+
assert(c1.name != "John" and c2.name != "John")
50+
c1.setName("John")
51+
assert(c2.name == "John")
52+
block: # Signal and lambda connection
53+
let c1 = newContact()
54+
let c2 = newContact()
55+
proc callback(name: string) =
56+
c2.setName(name)
57+
discard QObject.connect(c1, nameChanged, callback)
58+
assert(c1.name != "John" and c2.name != "John")
59+
c1.setName("John")
60+
assert(c2.name == "John")
61+
block: # Signal and lambda with context
62+
let c1 = newContact()
63+
let c2 = newContact()
64+
proc callback(name: string) =
65+
c2.setName(name)
66+
discard QObject.connect(c1, nameChanged, c2, callback)
67+
assert(c1.name != "John" and c2.name != "John")
68+
c1.setName("John")
69+
assert(c2.name == "John")
70+
block: # Signal and slot disconnection with connection
71+
let c1 = newContact()
72+
let c2 = newContact()
73+
let c = QObject.connect(c1, nameChanged, c2, setName)
74+
assert(c1.name != "John" and c2.name != "John")
75+
c1.setName("John")
76+
assert(c2.name == "John")
77+
QObject.disconnect(c)
78+
c1.setName("Doo")
79+
assert(c2.name == "John")
80+
block: # Signal and slot disconnection automatic with destruction
81+
let c1 = newContact()
82+
block:
83+
let c2 = newContact()
84+
defer: c2.delete
85+
discard QObject.connect(c1, nameChanged, c2, setName)
86+
assert(c1.name != "John" and c2.name != "John")
87+
c1.setName("John")
88+
assert(c2.name == "John")
89+
c1.setName("Doo")
90+
91+
if isMainModule:
92+
main()
93+
GC_fullcollect()

examples/connections/main.nim.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--path:"../../src"

examples/contactapp/contactapp.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ description = "contactapp"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"

examples/helloworld/helloworld.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ description = "helloworld"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"

examples/qmlregistertype/qmlregistertype.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ description = "qmlregistertype"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"

examples/resourcebundling/resourcebundling.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ bin = @["main"]
99

1010
# Dependencies
1111

12-
requires @["nim >= 1.0.0", "nimqml >= 0.8.0"]
12+
requires @["nim >= 1.2.0", "nimqml >= 0.9.0"]
1313

1414
task build, "Compile the binary":
1515
exec ("nim c main")

examples/simpledata/simpledata.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ description = "simpledata"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"
1111

examples/slotsandproperties/slotsandproperties.nimble

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ description = "slotsandproperties"
77
license = "MIT"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0, nimqml >= 0.8.0"
10+
Requires: "nim >= 1.2.0, nimqml >= 0.9.0"

nimqml.nimble

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
[Package]
22
name = "nimqml"
3-
version = "0.8.0"
3+
version = "0.9.0"
44
author = "Filippo Cucchetto"
55
description = "QML bindings for Nim"
66
license = "LGPLv3"
77
srcDir = "src"
88

99
[Deps]
10-
Requires: "nim >= 1.0.0"
10+
Requires: "nim >= 1.2.0"

src/nimqml.nim

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ template debugMsg(typeName: string, procName: string) =
1010
message &= procName
1111
debugMsg(message)
1212

13+
include "nimqml/private/nimqmlmacros.nim"
1314
include "nimqml/private/dotherside.nim"
1415
include "nimqml/private/nimqmltypes.nim"
15-
include "nimqml/private/qmetaobject.nim"
1616
include "nimqml/private/qvariant.nim"
17+
include "nimqml/private/lambdainvoker.nim"
18+
include "nimqml/private/qmetaobjectconnection.nim"
19+
include "nimqml/private/qmetaobject.nim"
1720
include "nimqml/private/qobject.nim"
1821
include "nimqml/private/qqmlapplicationengine.nim"
1922
include "nimqml/private/qcoreapplication.nim"
@@ -28,4 +31,4 @@ include "nimqml/private/qabstractlistmodel.nim"
2831
include "nimqml/private/qabstracttablemodel.nim"
2932
include "nimqml/private/qresource.nim"
3033
include "nimqml/private/qdeclarative.nim"
31-
include "nimqml/private/nimqmlmacros.nim"
34+

src/nimqml/private/dotherside.nim

+19-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ const dynLibName =
77
of "macosx":
88
"libDOtherSide.dylib"
99
else:
10-
"libDOtherSide.so.0.7"
10+
"libDOtherSide.so.0.8"
1111

1212
type
1313
NimQObject = pointer
1414
NimQAbstractItemModel = pointer
1515
NimQAbstractListModel = pointer
1616
NimQAbstractTableModel = pointer
1717
DosQMetaObject = distinct pointer
18-
DosQObject = distinct pointer
18+
DosQObject* = distinct pointer
1919
DosQObjectWrapper = distinct pointer
2020
DosQVariant = distinct pointer
2121
DosQQmlContext = distinct pointer
@@ -30,6 +30,7 @@ type
3030
DosQAbstractItemModel = distinct pointer
3131
DosQAbstractTableModel = distinct pointer
3232
DosQAbstractListModel = distinct pointer
33+
DosQMetaObjectConnection = distinct pointer
3334

3435
DosParameterDefinition = object
3536
name: cstring
@@ -106,6 +107,8 @@ type
106107
canFetchMore: DosCanFetchMoreCallback
107108
fetchMore: DosFetchMoreCallback
108109

110+
DosQObjectConnectLambdaCallback = proc(data: pointer, numArguments: cint, arguments: ptr DosQVariantArray) {.cdecl.}
111+
DosQMetaObjectInvokeMethodCallback = proc(data: pointer) {.cdecl.}
109112

110113
# Conversion
111114
proc resetToNil[T](x: var T) = x = nil.pointer.T
@@ -117,6 +120,7 @@ proc isNil(x: DosQUrl): bool = x.pointer.isNil
117120
proc isNil(x: DosQQuickView): bool = x.pointer.isNil
118121
proc isNil(x: DosQHashIntByteArray): bool = x.pointer.isNil
119122
proc isNil(x: DosQModelIndex): bool = x.pointer.isNil
123+
proc isNil(x: DosQMetaObjectConnection): bool = x.pointer.isNil
120124

121125
# CharArray
122126
proc dos_chararray_delete(str: cstring) {.cdecl, dynlib: dynLibName, importc.}
@@ -177,8 +181,19 @@ proc dos_qobject_qmetaobject(): DosQMetaObject {.cdecl, dynlib: dynLibName, impo
177181
proc dos_qobject_create(nimobject: NimQObject, metaObject: DosQMetaObject, dosQObjectCallback: DosQObjectCallBack): DosQObject {.cdecl, dynlib: dynLibName, importc.}
178182
proc dos_qobject_objectName(qobject: DosQObject): cstring {.cdecl, dynlib: dynLibName, importc.}
179183
proc dos_qobject_setObjectName(qobject: DosQObject, name: cstring) {.cdecl, dynlib: dynLibName, importc.}
180-
proc dos_qobject_signal_emit(qobject: DosQObject, signalName: cstring, argumentsCount: cint, arguments: ptr DosQVariantArray) {.cdecl, dynlib: dynLibName, importc.}
184+
proc dos_qobject_signal_emit(qobject: DosQObject, signalName: cstring, argumentsCount: cint, arguments: ptr DosQVariantArray) {.cdecl, dynlib: dynLibName, importc.}
185+
proc dos_qobject_connect_static(sender: DosQObject, senderFunc: cstring, receiver: DosQObject, receiverFunc: cstring, connectionType: cint): DosQMetaObjectConnection {.cdecl, dynlib: dynLibName, importc.}
186+
proc dos_qobject_connect_lambda_static(sender: DosQObject, senderFunc: cstring, callback: DosQObjectConnectLambdaCallback, data: pointer, connectionType: cint): DosQMetaObjectConnection {.cdecl, dynlib: dynLibName, importc.}
187+
proc dos_qobject_connect_lambda_with_context_static(sender: DosQObject, senderFunc: cstring, context: DosQObject, callback: DosQObjectConnectLambdaCallback, data: pointer, connectionType: cint): DosQMetaObjectConnection {.cdecl, dynlib: dynLibName, importc.}
188+
proc dos_qobject_disconnect_static(sender: DosQObject, senderFunc: cstring, receiver: DosQObject, receiverFunc: cstring) {.cdecl, dynlib: dynLibName, importc.}
189+
proc dos_qobject_disconnect_with_connection_static(connection: DosQMetaObjectConnection) {.cdecl, dynlib: dynLibName, importc.}
181190
proc dos_qobject_delete(qobject: DosQObject) {.cdecl, dynlib: dynLibName, importc.}
191+
proc dos_qobject_deleteLater(qobject: DosQObject) {.cdecl, dynlib: dynLibName, importc.}
192+
proc dos_signal_macro*(name: cstring): cstring {.cdecl, dynlib: dynLibName, importc.}
193+
proc dos_slot_macro*(name: cstring): cstring {.cdecl, dynlib: dynLibName, importc.}
194+
195+
# QMetaObject::Connection
196+
proc dos_qmetaobject_connection_delete(connection: DosQMetaObjectConnection) {.cdecl, dynlib: dynLibName, importc.}
182197

183198
# QAbstractItemModel
184199
proc dos_qabstractitemmodel_qmetaobject(): DosQMetaObject {.cdecl dynlib: dynLibName, importc.}
@@ -190,6 +205,7 @@ proc dos_qmetaobject_create(superclassMetaObject: DosQMetaObject,
190205
slotDefinitions: ptr DosSlotDefinitions,
191206
propertyDefinitions: ptr DosPropertyDefinitions): DosQMetaObject {.cdecl, dynlib: dynLibName, importc.}
192207
proc dos_qmetaobject_delete(vptr: DosQMetaObject) {.cdecl, dynlib: dynLibName, importc.}
208+
proc dos_qmetaobject_invoke_method(context: DosQObject, callback: DosQMetaObjectInvokeMethodCallback, callbackData: pointer, connectionType: cint): bool {.cdecl, dynlib: dynLibName, importc.}
193209

194210
# QUrl
195211
proc dos_qurl_create(url: cstring, parsingMode: cint): DosQUrl {.cdecl, dynlib: dynLibName, importc.}

src/nimqml/private/lambdainvoker.nim

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import locks
2+
import tables
3+
4+
type
5+
LambdaInvokerProc = proc(arguments: seq[QVariant]) {.closure.}
6+
LambdaInvoker = ref object
7+
id: int
8+
lock: Lock
9+
lambdas: Table[int, LambdaInvokerProc]
10+
11+
12+
proc new(typ: type LambdaInvoker): LambdaInvoker =
13+
## Create the lambda invoker
14+
new(result)
15+
result.id = 0
16+
result.lock.initLock()
17+
result.lambdas = initTable[int, LambdaInvokerProc]()
18+
19+
20+
proc add(self: LambdaInvoker, l: LambdaInvokerProc): int =
21+
## Add a lambda and return its id
22+
self.lock.acquire()
23+
result = self.id
24+
self.id.inc()
25+
self.lambdas[result] = l
26+
self.lock.release()
27+
28+
proc add(self: LambdaInvoker, l: proc()): int =
29+
let k = proc(args: seq[QVariant]) = l()
30+
return self.add(k)
31+
32+
proc add[T0](self: LambdaInvoker, l: proc(t0: T0)): int =
33+
let k = proc(args: seq[QVariant]) =
34+
if args.len > 0:
35+
l(args[0].value(T0))
36+
else:
37+
echo "Too few arguments during lambda invokation"
38+
return self.add(k)
39+
40+
proc add[T0, T1](self: LambdaInvoker, l: proc(t0: T0, t1: T1)): int =
41+
let k = proc(args: seq[QVariant]) =
42+
if args.len > 1:
43+
l(args[0].value(T0), args[1].value(T1))
44+
else:
45+
echo "Too few arguments during lambda invokation"
46+
return self.add(k)
47+
48+
proc add[T0, T1, T2](self: LambdaInvoker, l: proc(t0: T0, t1: T1, t2: T2)): int =
49+
let k = proc(args: seq[QVariant]) =
50+
if args.len > 2:
51+
l(args[0].value(T0), args[1].value(T1), args[2].value(T2))
52+
else:
53+
echo "Too few arguments during lambda invokation"
54+
return self.add(k)
55+
56+
proc get(self: LambdaInvoker, id: int): LambdaInvokerProc =
57+
## Return the lambda with the given id
58+
self.lock.acquire()
59+
result = self.lambdas.getOrDefault(id)
60+
self.lock.release()
61+
62+
proc invoke(self: LambdaInvoker, id: int, arguments: seq[QVariant]) =
63+
let l = self.get(id)
64+
if l != nil:
65+
l(arguments)
66+
67+
let invokerInstance = LambdaInvoker.new()
68+
69+
proc instance(typ: type LambdaInvoker): LambdaInvoker =
70+
result = invokerInstance
71+
72+
proc lambdaCallback(data: pointer, numArguments: cint, arguments: ptr DosQVariantArray) {.cdecl, exportc.} =
73+
let id = cast[int](data)
74+
let arguments = toQVariantSequence(arguments, numArguments, Ownership.Clone)
75+
LambdaInvoker.instance.invoke(id, arguments)

0 commit comments

Comments
 (0)