add cpp-lib example; some fixes

This commit is contained in:
pls.153 2022-01-22 17:49:00 +01:00
parent 7a4bff3c20
commit eb54b6fd41
12 changed files with 144 additions and 11 deletions

14
cpp-lib/cpp/cpp.pro Normal file
View file

@ -0,0 +1,14 @@
QT += core
TEMPLATE = lib
CONFIG += plugin release
DESTDIR = ../
TARGET = cpp
OBJECTS_DIR = ./tmp/
MOC_DIR = ./tmp/
win32 {
include(../../src/windows.pri)
}
HEADERS += lib.h
SOURCES += lib.cpp

27
cpp-lib/cpp/lib.cpp Normal file
View file

@ -0,0 +1,27 @@
#include "lib.h"
#include <QtDebug>
QT_BEGIN_NAMESPACE
QObject* ini() {
// any QObject inherited class will do
static QObject* cpp = 0;
if(!cpp) {
cpp = new CPP;
}
return cpp;
}
// insert here your function implementations
QVariant CPP::hello(const QVariant& arg) {
QString msg;
QDebug debug(&msg);
debug << arg;
qDebug() << "hello" << arg;
return arg;
}
QT_END_NAMESPACE

28
cpp-lib/cpp/lib.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef LIB_H
#define LIB_H
#include <QtCore>
#ifdef Q_CC_MSVC
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT
#endif
QT_BEGIN_NAMESPACE
extern "C" { LIB_EXPORT QObject* ini(); }
class CPP : public QObject
{
Q_OBJECT
public:
// max. 10 arguments of type QVariant
// return type must also be a QVariant
Q_INVOKABLE QVariant hello(const QVariant&);
};
QT_END_NAMESPACE
#endif

39
cpp-lib/readme.md Normal file
View file

@ -0,0 +1,39 @@
Build
-----
Switch to `cpp/` and do:
```
qmake lib.pro
make
```
Run
---
```
$ lqml ~/slime/qml-start-swank.lisp
$ emacs
```
In Slime do:
```
(defvar *cpp* (qload-c++ "cpp"))
(define-qt-wrappers *cpp*)
(hello *cpp* '(1 "two" (1.25 #(50 -50 75))))
```
Now look at the console output where you launched the `lqml` executable.
As you can see, although the argument and return type are simply defined as
`QVariant`, you may also pass lists, because a `QVariant` can also be of type
`QVariantList`, so this is a perfect fit for (nested) Lisp lists.
So, we pass a nested Lisp list, and it gets printed on Qt side with the
respective types. Then the `QVariantList` is returend to Lisp, where it is
automatically converted back to a nested Lisp list.
Realy convenient!

6
cpp-lib/run.lisp Normal file
View file

@ -0,0 +1,6 @@
(defvar *cpp* (qload-c++ "cpp"))
(define-qt-wrappers *cpp*)
(print (hello *cpp* '(1 "two" (1.25 #(50 -50 75)))))

View file

@ -24,6 +24,16 @@
(define-qt-wrappers *c++*) ; Lisp wrapper functions (define-qt-wrappers *c++*) ; Lisp wrapper functions
<b>define-qt-wrappers (qt-library &rest what)</b>
Defines Lisp methods for all Qt methods/signals/slots of given library,
previously loaded with QLOAD-C++.
(define-qt-wrappers *c++*) ; generate wrappers
(define-qt-wrappers *c++* :methods) ; Qt methods only (no slots/signals)
(my-qt-function *c++* x y) ; call from Lisp
<b>find-quick-item (object-name)</b> <b>find-quick-item (object-name)</b>
Finds the first QQuickItem matching OBJECT-NAME. Locally set *ROOT-ITEM* if Finds the first QQuickItem matching OBJECT-NAME. Locally set *ROOT-ITEM* if
@ -125,7 +135,8 @@
Fast and convenient way to call JS functions defined in QML. You may pass Fast and convenient way to call JS functions defined in QML. You may pass
up to 10 arguments of the following types: up to 10 arguments of the following types:
T, NIL, INTEGER, FLOAT, STRING, and (nested) lists of mentioned arguments. T, NIL, INTEGER, FLOAT, STRING, VECTOR of octets, and (nested) lists of
mentioned arguments.
N.B: Does not work with JS default arguments. N.B: Does not work with JS default arguments.

View file

@ -27,5 +27,4 @@ TODO
* make example work on iOS * make example work on iOS
* add item model example * add item model example
* add sokoban example * add sokoban example
* add cpp-lib example

View file

@ -250,7 +250,8 @@ cl_object qload_cpp(cl_object l_lib_name, cl_object l_unload) { /// qload-c++
if (ini) { if (ini) {
QObject* main = ini(); QObject* main = ini();
if (main) { if (main) {
ecl_return1(ecl_process_env(), ECL_T); cl_object l_ret = from_qobject_pointer(main);
ecl_return1(ecl_process_env(), l_ret);
} }
} }
} }
@ -391,8 +392,9 @@ cl_object qlog2(cl_object l_msg) {
cl_object qinvoke_method2(cl_object l_obj, cl_object l_name, cl_object l_args) { cl_object qinvoke_method2(cl_object l_obj, cl_object l_name, cl_object l_args) {
// for internal use: this is used to call user defined JS functions, and to // for internal use: this is used to call user defined JS functions, and to
// call user defined Qt/C++ plugin functions. // call user defined Qt/C++ plugin functions.
// Max. 10 arguments of type T, NIL, INTEGER, FLOAT, STRING, (nested) LIST of // Max. 10 arguments of type T, NIL, INTEGER, FLOAT, STRING, VECTOR of
// mentioned arguments. On Qt side, only QVariant arguments are allowed. // octets, (nested) LIST of mentioned arguments. On Qt side, only QVariant
// arguments are allowed.
// N.B. does not support default arguments, if used to call JS functions // N.B. does not support default arguments, if used to call JS functions
ecl_process_env()->nvalues = 1; ecl_process_env()->nvalues = 1;
const int MAX = 10; const int MAX = 10;

View file

@ -132,9 +132,10 @@ TO_QT_FLOAT_4 (QRectF)
QVariant toQVariant(cl_object l_arg, int type) { QVariant toQVariant(cl_object l_arg, int type) {
QVariant var; QVariant var;
switch (type) { switch (type) {
case QMetaType::QPointF: var = toQPointF(l_arg); break; case QMetaType::QByteArray: var = toQByteArray(l_arg); break;
case QMetaType::QRectF: var = toQRectF(l_arg); break; case QMetaType::QPointF: var = toQPointF(l_arg); break;
case QMetaType::QSizeF: var = toQSizeF(l_arg); break; case QMetaType::QRectF: var = toQRectF(l_arg); break;
case QMetaType::QSizeF: var = toQSizeF(l_arg); break;
default: default:
if (cl_integerp(l_arg) == ECL_T) { // int if (cl_integerp(l_arg) == ECL_T) { // int
var = QVariant(toInt(l_arg)); var = QVariant(toInt(l_arg));
@ -154,6 +155,9 @@ QVariant toQVariant(cl_object l_arg, int type) {
else if (cl_listp(l_arg) == ECL_T) { // list else if (cl_listp(l_arg) == ECL_T) { // list
var = QVariant::fromValue(toQVariantList(l_arg)); var = QVariant::fromValue(toQVariantList(l_arg));
} }
else if (cl_vectorp(l_arg) == ECL_T) { // vector (of octets)
var = QVariant(toQByteArray(l_arg));
}
else { // default: undefined else { // default: undefined
var = QVariant(); var = QVariant();
} }

View file

@ -116,7 +116,8 @@
(define-qt-wrappers *c++*) ; generate wrappers (define-qt-wrappers *c++*) ; generate wrappers
(define-qt-wrappers *c++* :methods) ; Qt methods only (no slots/signals) (define-qt-wrappers *c++* :methods) ; Qt methods only (no slots/signals)
(my-qt-function *c++* x y) ; call from Lisp" (my-qt-function *c++* x y) ; call from Lisp"
(let ((all-functions (qapropos* nil (ensure-qt-object qt-library))) (assert (qobject-p qt-library))
(let ((all-functions (qapropos* nil qt-library))
(lispify (not (find :do-not-lispify what)))) (lispify (not (find :do-not-lispify what))))
(setf what (remove-if (lambda (x) (find x '(:do-not-lispify t))) (setf what (remove-if (lambda (x) (find x '(:do-not-lispify t)))
what)) what))
@ -142,7 +143,7 @@
;; there seems to be no simple way to avoid EVAL here ;; there seems to be no simple way to avoid EVAL here
;; (excluding non-portable hacks) ;; (excluding non-portable hacks)
(eval `(defgeneric ,lisp-name (object &rest arguments))) (eval `(defgeneric ,lisp-name (object &rest arguments)))
(eval `(defmethod ,lisp-name ((object qt-object) &rest arguments) (eval `(defmethod ,lisp-name ((object si:foreign-data) &rest arguments)
(%qinvoke-method object ,qt-name arguments))))))))) (%qinvoke-method object ,qt-name arguments)))))))))
(defun qinvoke-method (object function-name &rest arguments) (defun qinvoke-method (object function-name &rest arguments)

View file

@ -7,6 +7,7 @@
#:*root-item* #:*root-item*
#:*caller* #:*caller*
#:children #:children
#:define-qt-wrappers
#:find-quick-item #:find-quick-item
#:js #:js
#:make-qobject #:make-qobject

View file

@ -179,7 +179,8 @@
"args: (method-name item/name &rest arguments "args: (method-name item/name &rest arguments
Fast and convenient way to call JS functions defined in QML. You may pass Fast and convenient way to call JS functions defined in QML. You may pass
up to 10 arguments of the following types: up to 10 arguments of the following types:
T, NIL, INTEGER, FLOAT, STRING, and (nested) lists of mentioned arguments. T, NIL, INTEGER, FLOAT, STRING, VECTOR of octets, and (nested) lists of
mentioned arguments.
N.B: Does not work with JS default arguments." N.B: Does not work with JS default arguments."
`(qrun* (qfun (quick-item ,item/name) `(qrun* (qfun (quick-item ,item/name)
,(if (symbolp method-name) ,(if (symbolp method-name)