diff --git a/NimQml.nim b/NimQml.nim index ecd36e2..cd40e6c 100644 --- a/NimQml.nim +++ b/NimQml.nim @@ -1,13 +1,19 @@ import NimQmlTypes import tables +## NimQml aims to provide binding to the QML for the Nim programming language + export QObject export QApplication export QVariant export QQmlApplicationEngine export QQmlContext -type QMetaType* {.pure.} = enum +type QMetaType* {.pure.} = enum ## \ + ## Qt metatypes values used for specifing the + ## signals and slots argument and return types. + ## + ## This enum mimic the QMetaType::Type C++ enum UnknownType = cint(0), Bool = cint(1), Int = cint(2), @@ -50,53 +56,65 @@ proc dos_qvariant_setString(variant: pointer, value: cstring) {.cdecl, dynlib:"l proc dos_chararray_delete(rawCString: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc create*(variant: var QVariant) = + ## Create a new QVariant var data: pointer dos_qvariant_create(data) variant = QVariant(data) proc create*(variant: var QVariant, value: cint) = + ## Create a new QVariant given a cint value var data: pointer dos_qvariant_create_int(data, value) variant = QVariant(data) proc create*(variant: var QVariant, value: bool) = + ## Create a new QVariant given a bool value var data: pointer dos_qvariant_create_bool(data, value) variant = QVariant(data) proc create*(variant: var QVariant, value: string) = + ## Create a new QVariant given a string value var data: pointer dos_qvariant_create_string(data, value) variant = QVariant(data) proc create*(variant: var QVariant, value: QObject) = + ## Create a new QVariant given a QObject var data: pointer dos_qvariant_create_qobject(data, value.data) variant = QVariant(data) proc delete*(variant: QVariant) = + ## Delete a QVariant debugMsg("QVariant", "delete") dos_qvariant_delete(pointer(variant)) proc isNull*(variant: QVariant): bool = + ## Return true if the QVariant value is null, false otherwise dos_qvariant_isnull(pointer(variant), result) proc intVal*(variant: QVariant): int = + ## Return the QVariant value as int var rawValue: cint dos_qvariant_toInt(pointer(variant), rawValue) result = cast[int](rawValue) proc `intVal=`*(variant: QVariant, value: int) = + ## Sets the QVariant value int value var rawValue = cast[cint](value) dos_qvariant_setInt(pointer(variant), rawValue) proc boolVal*(variant: QVariant): bool = + ## Return the QVariant value as bool dos_qvariant_toBool(pointer(variant), result) proc `boolVal=`*(variant: QVariant, value: bool) = + ## Sets the QVariant bool value dos_qvariant_setBool(pointer(variant), value) proc stringVal*(variant: QVariant): string = + ## Return the QVariant value as string var rawCString: cstring var rawCStringLength: cint dos_qvariant_toString(pointer(variant), rawCString, rawCStringLength) @@ -104,6 +122,7 @@ proc stringVal*(variant: QVariant): string = dos_chararray_delete(rawCString) proc `stringVal=`*(variant: QVariant, value: string) = + ## Sets the QVariant string value dos_qvariant_setString(pointer(variant), value) @@ -114,19 +133,23 @@ proc dos_qqmlapplicationengine_context(engine: pointer, context: var pointer) {. proc dos_qqmlapplicationengine_delete(engine: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc create*(engine: var QQmlApplicationEngine) = + ## Create an new QQmlApplicationEngine var temp: pointer dos_qqmlapplicationengine_create(temp) engine = QQmlApplicationEngine(temp) proc load*(engine: QQmlApplicationEngine, filename: cstring) = + ## Load the given Qml file dos_qqmlapplicationengine_load(pointer(engine), filename) proc rootContext*(engine: QQmlApplicationEngine): QQmlContext = + ## Return the engine root context var context: pointer dos_qqmlapplicationengine_context(pointer(engine), context) result = cast[QQmlContext](context) proc delete*(engine: QQmlApplicationEngine) = + ## Delete the given QQmlApplicationEngine debugMsg("QQmlApplicationEngine", "delete") dos_qqmlapplicationengine_delete(pointer(engine)) @@ -134,6 +157,7 @@ proc delete*(engine: QQmlApplicationEngine) = proc dos_qqmlcontext_setcontextproperty(context: pointer, propertyName: cstring, propertyValue: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc setContextProperty*(context: QQmlContext, propertyName: string, propertyValue: QVariant) = + ## Sets a new property with the given value dos_qqmlcontext_setcontextproperty(pointer(context), propertyName, pointer(propertyValue)) # QApplication @@ -142,21 +166,31 @@ proc dos_qguiapplication_exec() {.cdecl, dynlib:"libDOtherSide.so", importc.} proc dos_qguiapplication_delete() {.cdecl, dynlib:"libDOtherSide.so", importc.} proc create*(application: QApplication) = - debugMsg("QApplication", "create") + ## Create a new QApplication dos_qguiapplication_create() proc exec*(application: QApplication) = - debugMsg("QApplication", "exec") + ## Start the Qt event loop dos_qguiapplication_exec() proc delete*(application: QApplication) = - debugMsg("QApplication", "delete") + ## Delete the given QApplication dos_qguiapplication_delete() # QObject type QVariantArray {.unchecked.} = array[0..0, QVariant] type QVariantArrayPtr = ptr QVariantArray +proc toVariantSeq(args: QVariantArrayPtr, numArgs: cint): seq[QVariant] = + result = @[] + for i in 0..numArgs-1: + result.add(args[i]) + +proc toCIntSeq(metaTypes: openarray[QMetaType]): seq[cint] = + result = @[] + for metaType in metaTypes: + result.add(cint(metaType)) + proc dos_qobject_create(qobject: var pointer, nimobject: pointer, qobjectCallback: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc dos_qobject_delete(qobject: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc dos_qobject_slot_create(qobject: pointer, slotName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, slotIndex: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.} @@ -164,40 +198,31 @@ proc dos_qobject_signal_create(qobject: pointer, signalName: cstring, argumentsC proc dos_qobject_signal_emit(qobject: pointer, signalName: cstring, argumentsCount: cint, arguments: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc dos_qobject_property_create(qobject: pointer, propertyName: cstring, propertyType: cint, readSlot: cstring, writeSlot: cstring, notifySignal: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.} -method onSlotCalled*(nimobject: QObject, slotName: string, args: openarray[QVariant]) = - debugMsg("QObject", "onSlotCalled", "begin") - debugMsg("QObject", "onSlotCalled", "end") +method onSlotCalled*(nimobject: QObject, slotName: string, args: openarray[QVariant]) = + ## Called from the NimQml bridge when a slot is called from Qml. + ## Subclasses can override the given method for handling the slot call + discard() -proc toVariantSeq(args: QVariantArrayPtr, numArgs: cint): seq[QVariant] = - result = @[] - for i in 0..numArgs-1: - result.add(args[i]) - -proc qobjectCallback(nimobject: pointer, slotName: QVariant, numArguments: cint, arguments: QVariantArrayPtr) {.exportc.} = - debugMsg("QObject", "qobjectCallback", "begin") +proc qobjectCallback(nimobject: pointer, slotName: QVariant, numArguments: cint, arguments: QVariantArrayPtr) {.exportc.} = var nimQObjectCasted = cast[ptr QObject](nimobject) # forward to the QObject subtype instance nimQObjectCasted[].onSlotCalled(slotName.stringVal, arguments.toVariantSeq(numArguments)) - debugMsg("QObject", "qobjectCallback", "end") - -proc toCIntSeq(metaTypes: openarray[QMetaType]): seq[cint] = - result = @[] - for metaType in metaTypes: - result.add(cint(metaType)) proc create*(qobject: var QObject) = + ## Create a new QObject qobject.name = "QObject" qobject.slots = initTable[string,cint]() qobject.signals = initTable[string, cint]() dos_qobject_create(qobject.data, addr(qobject), qobjectCallback) proc delete*(qobject: QObject) = - debugMsg("QObject", "delete") + ## Delete the given QObject dos_qobject_delete(qobject.data) proc registerSlot*(qobject: var QObject, slotName: string, metaTypes: openarray[QMetaType]) = + ## Register a slot in the QObject with the given name and signature # Copy the metatypes array var copy = toCIntSeq(metatypes) var index: cint @@ -207,6 +232,7 @@ proc registerSlot*(qobject: var QObject, proc registerSignal*(qobject: var QObject, signalName: string, metatypes: openarray[QMetaType]) = + ## Register a signal in the QObject with the given name and signature var index: cint if metatypes.len > 0: var copy = toCIntSeq(metatypes) @@ -220,10 +246,12 @@ proc registerProperty*(qobject: var QObject, propertyType: QMetaType, readSlot: string, writeSlot: string, - notifySignal: string) = + notifySignal: string) = + ## Register a property in the QObject with the given name and type. dos_qobject_property_create(qobject.data, propertyName, cast[cint](propertyType), readSlot, writeSlot, notifySignal) proc emit*(qobject: QObject, signalName: string, args: openarray[QVariant] = []) = + ## Emit the signal with the given name and values if args.len > 0: var copy: seq[QVariant] for i in 0..args.len-1: @@ -239,23 +267,27 @@ proc dos_qquickview_show(view: pointer) {.cdecl, dynlib:"libDOtherSide.so", impo proc dos_qquickview_source(view: pointer, filename: var cstring, length: var int) {.cdecl, dynlib:"libDOtherSide.so", importc.} proc dos_qquickview_set_source(view: pointer, filename: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.} -proc create(view: var QQuickView) = +proc create(view: var QQuickView) = + ## Create a new QQuickView var temp: pointer dos_qquickview_create(temp) view = QQuickView(temp) proc source(view: QQuickView): cstring = + ## Return the source Qml file loaded by the view var length: int dos_qquickview_source(pointer(view), result, length) proc `source=`(view: QQuickView, filename: cstring) = + ## Sets the source Qml file laoded by the view dos_qquickview_set_source(pointer(view), filename) proc show(view: QQuickView) = + ## Sets the view visible dos_qquickview_show(pointer(view)) -proc delete(view: QQuickView) = - debugMsg("QQuickView", "delete") +proc delete(view: QQuickView) = + ## Delete the given QQuickView dos_qquickview_delete(pointer(view)) diff --git a/NimQml.nimble b/NimQml.nimble index 3a334b1..ef79830 100644 --- a/NimQml.nimble +++ b/NimQml.nimble @@ -1,7 +1,7 @@ [Package] name = "NimQml" -version = "0.01" -author = "Filippo Cucchetto" +version = "0.2.0" +author = "Filippo Cucchetto, Will Szumski" description = "QML bindings for Nimrod" license = "GPLv3" diff --git a/NimQmlMacros.nim b/NimQmlMacros.nim new file mode 100644 index 0000000..40372d7 --- /dev/null +++ b/NimQmlMacros.nim @@ -0,0 +1,460 @@ +## Contains helper macros for NimQml + +import macros +import strutils +import typetraits +import tables + +template debug(body: stmt): stmt = + {.push warning[user]: off.} + when defined(debug): + {.pop.} + body + else: + {.pop.} + +let nimFromQtVariant {.compileTime.} = { + "int" : "intVal", + "string" : "stringVal", + "bool" : "boolVal", +}.toTable + +let nim2QtMeta {.compileTime.} = { + "bool": "Bool", + "int" : "Int", + "string" : "QString", + "pointer" : "VoidStar", + "QVariant": "QVariant", + "" : "Void", # no return, which is represented by an nnkEmpty node +}.toTable + +proc getNodeOf*(tree: PNimrodNode, kind: TNimrodNodeKind): PNimrodNode {.compileTime.} = + ## recursively looks for a node of kind, ``kind``, in the tree provided as ``tree`` + ## Returnsthe first node that satisfies this condition + for i in 0.. 2: # more args than just type + for i in 2..