"quick": add example "painted-item"; small revisions;

This commit is contained in:
polos 2017-02-04 12:37:26 +01:00
parent fcbf75464c
commit 0ff3dee53c
20 changed files with 350 additions and 15 deletions

View file

@ -1,9 +1,10 @@
If you are new to QML/EQL5, you probably want to go through the examples
in this order:
(and READMEs) in this order:
1) qml-lisp
2) Tic-Tac-Toe
3) item-model
* qml-lisp
* Tic-Tac-Toe
* item-model
* painted-item
The trivial "quickwidget" example just demonstrates that you can integrate
a QML widget in any Qt application, combining both traditional Qt and QML.

View file

@ -10,7 +10,8 @@ static QObject* lisp_provider(QQmlEngine*, QJSEngine*) { return lisp; }
QObject* ini() {
if(!lisp) {
lisp = new Lisp;
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider); }
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider);
qmlRegisterType<PaintedItem>("EQL5", 1, 0, "PaintedItem"); }
return lisp; }
QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantList& arguments) {
@ -19,4 +20,9 @@ QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantLis
Q_ARG(QString, function),
Q_ARG(QVariantList, arguments)); }
void PaintedItem::paint(QPainter* painter) {
eql_fun("qml:paint",
Q_ARG(QQuickPaintedItem*, this),
Q_ARG(QPainter*, painter)); }
QT_END_NAMESPACE

View file

@ -2,6 +2,7 @@
#define LIB_H
#include <QtQml>
#include <QQuickPaintedItem>
#ifdef Q_OS_WIN
#define LIB_EXPORT __declspec(dllexport)
@ -20,6 +21,17 @@ public:
Q_INVOKABLE QVariant apply(QObject*, const QString&, const QVariantList& = QVariantList());
};
class PaintedItem : public QQuickPaintedItem {
Q_OBJECT
public:
PaintedItem(QQuickItem* parent = 0) : QQuickPaintedItem(parent) {}
void paint(QPainter*);
};
QT_END_NAMESPACE
#endif

View file

@ -1,4 +1,4 @@
QT += qml
QT += qml quick
TEMPLATE = lib
CONFIG += plugin release
INCLUDEPATH += ../../../../../src

View file

@ -55,8 +55,8 @@
(or data *empty-variant*))))
(qoverride *animal-model* "roleNames()"
(lambda ()
(list (cons +kind-role+ "kind")
(cons +size-role+ "size")))))
(list (cons +kind-role+ "kind") ; see 'kind' in QML
(cons +size-role+ "size"))))) ; see 'size' in QML
(defun run ()
;; data
@ -66,7 +66,7 @@
(add-animal "mouse" "small")
;; view
(setf qml:*quick-view* (qnew "QQuickView"))
(|setContextProperty| (|rootContext| qml:*quick-view*) "myModel" *animal-model*)
(|setContextProperty| (|rootContext| qml:*quick-view*) "myModel" *animal-model*) ; see 'myModel' in QML
(|setSource| qml:*quick-view* (|fromLocalFile.QUrl| "qml/abstract-model.qml"))
(|setResizeMode| qml:*quick-view* |QQuickView.SizeRootObjectToView|)
(|resize| qml:*quick-view* '(200 250))

View file

@ -10,7 +10,8 @@ static QObject* lisp_provider(QQmlEngine*, QJSEngine*) { return lisp; }
QObject* ini() {
if(!lisp) {
lisp = new Lisp;
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider); }
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider);
qmlRegisterType<PaintedItem>("EQL5", 1, 0, "PaintedItem"); }
return lisp; }
QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantList& arguments) {
@ -19,4 +20,9 @@ QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantLis
Q_ARG(QString, function),
Q_ARG(QVariantList, arguments)); }
void PaintedItem::paint(QPainter* painter) {
eql_fun("qml:paint",
Q_ARG(QQuickPaintedItem*, this),
Q_ARG(QPainter*, painter)); }
QT_END_NAMESPACE

View file

@ -2,6 +2,7 @@
#define LIB_H
#include <QtQml>
#include <QQuickPaintedItem>
#ifdef Q_OS_WIN
#define LIB_EXPORT __declspec(dllexport)
@ -20,6 +21,17 @@ public:
Q_INVOKABLE QVariant apply(QObject*, const QString&, const QVariantList& = QVariantList());
};
class PaintedItem : public QQuickPaintedItem {
Q_OBJECT
public:
PaintedItem(QQuickItem* parent = 0) : QQuickPaintedItem(parent) {}
void paint(QPainter*);
};
QT_END_NAMESPACE
#endif

View file

@ -1,4 +1,4 @@
QT += qml
QT += qml quick
TEMPLATE = lib
CONFIG += plugin release
INCLUDEPATH += ../../../../../src

View file

@ -16,7 +16,7 @@
(defun set-my-model ()
;; this function needs to be called after every change to *items*
(qlet ((data (qvariant-from-value *items* "QStringList")))
(|setContextProperty| (|rootContext| qml:*quick-view*) "myModel" data)))
(|setContextProperty| (|rootContext| qml:*quick-view*) "myModel" data))) ; see 'myModel' in QML
(defun change-items (items)
(setf *items* items)

View file

@ -0,0 +1,11 @@
INFO
====
This is an alternative to 'Canvas' in QML, using a QQuickPaintedItem,
which means using QPainter from Lisp (instead of JS in QML).
RUN
===
Please run it from this directory.

View file

@ -0,0 +1,28 @@
#include "qml_lisp.h"
#include <eql_fun.h>
QT_BEGIN_NAMESPACE
static Lisp* lisp = 0;
static QObject* lisp_provider(QQmlEngine*, QJSEngine*) { return lisp; }
QObject* ini() {
if(!lisp) {
lisp = new Lisp;
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider);
qmlRegisterType<PaintedItem>("EQL5", 1, 0, "PaintedItem"); }
return lisp; }
QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantList& arguments) {
return eql_fun("qml:qml-apply", QVariant::String,
Q_ARG(QObject*, caller),
Q_ARG(QString, function),
Q_ARG(QVariantList, arguments)); }
void PaintedItem::paint(QPainter* painter) {
eql_fun("qml:paint",
Q_ARG(QQuickPaintedItem*, this),
Q_ARG(QPainter*, painter)); }
QT_END_NAMESPACE

View file

@ -0,0 +1,37 @@
#ifndef LIB_H
#define LIB_H
#include <QtQml>
#include <QQuickPaintedItem>
#ifdef Q_OS_WIN
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT
#endif
QT_BEGIN_NAMESPACE
extern "C" { LIB_EXPORT QObject* ini(); }
class Lisp : public QObject {
Q_OBJECT
public:
Q_INVOKABLE QVariant apply(QObject*, const QString&, const QVariantList& = QVariantList());
};
class PaintedItem : public QQuickPaintedItem {
Q_OBJECT
public:
PaintedItem(QQuickItem* parent = 0) : QQuickPaintedItem(parent) {}
void paint(QPainter*);
};
QT_END_NAMESPACE
#endif

View file

@ -0,0 +1,15 @@
QT += qml quick
TEMPLATE = lib
CONFIG += plugin release
INCLUDEPATH += ../../../../../src
LIBS += -L../../../../.. -leql5
DESTDIR = ./
TARGET = qml_lisp
OBJECTS_DIR = ./tmp/
MOC_DIR = ./tmp/
include(../../../../../src/windows.pri)
HEADERS += qml_lisp.h
SOURCES += qml_lisp.cpp

View file

@ -0,0 +1,27 @@
;;; QQuickView loading Lisp enabled QML
#-qt-wrapper-functions ; see README-OPTIONAL.txt
(load (in-home "src/lisp/all-wrappers"))
(qrequire :quick)
(require :qml-lisp "qml-lisp")
(use-package :qml)
;; paint
(defun qml:paint (item painter)
"This function is called on every 'paint' request of QML type 'PaintedItem'."
(|fillRect| painter (|contentsBoundingRect| item)
(qml-get item "fillColor"))) ; QML property
(defun run ()
;; *quick-view* can be either a QQuickView or a QQuickWidget
(setf qml:*quick-view* (qnew "QQuickView(QUrl)"
(|fromLocalFile.QUrl| "qml/painted-item.qml")))
(|setResizeMode| qml:*quick-view* |QQuickView.SizeRootObjectToView|)
(|resize| qml:*quick-view* '(350 350))
(|show| qml:*quick-view*))
(run)

View file

@ -0,0 +1,140 @@
;;;
;;; * enables QML to call Lisp functions
;;; * allows to get/set any QML property from Lisp (needs 'objectName' to be set)
;;; * allows to evaluate JS code from Lisp (needs 'objectName' to be set)
;;;
;;; (requires a C++ plugin, see "lib/")
(defpackage :qml-lisp
(:use :common-lisp :eql)
(:nicknames :qml)
(:export
#:*quick-view*
#:*caller*
#:children
#:find-quick-item
#:js
#:paint
#:qml-get
#:qml-set
#:reload
#:root-item))
(provide :qml-lisp)
(in-package :qml-lisp)
(defvar *qml-lisp* (qload-c++ "lib/qml_lisp"))
(defvar *caller* nil)
(defvar *quick-view* nil)
(defun string-to-symbol (name)
(let ((upper (string-upcase name))
(p (position #\: name)))
(if p
(find-symbol (subseq upper (1+ (position #\: name :from-end t)))
(subseq upper 0 p))
(find-symbol upper))))
;;; function calls from QML
(defun print-js-readably (object)
"Prints (nested) lists, vectors, T, NIL, floats in JS notation, which will be passed to JS 'eval()'."
(if (and (not (stringp object))
(vectorp object))
(print-js-readably (coerce object 'list))
(typecase object
(cons
(write-char #\[)
(do ((list object (rest list)))
((null list) (write-char #\]))
(print-js-readably (first list))
(when (rest list)
(write-char #\,))))
(float
;; cut off Lisp specific notations
(princ (string-right-trim "dl0" (princ-to-string object))))
(t
(cond ((eql 't object)
(princ "true"))
((eql 'nil object)
(princ "false"))
(t
(prin1 object)))))))
(defun print-to-js-string (object)
(with-output-to-string (*standard-output*)
(princ "#<>") ; mark for passing to JS "eval()"
(print-js-readably object)))
(defun qml-apply (caller function arguments)
"Every 'Lisp.call()' or 'Lisp.apply()' function call in QML will call this function. The variable *CALLER* will be bound to the calling QQuickItem, if passed with 'this' as first argument to 'Lisp.call()' / 'Lisp.apply()'."
(let* ((*caller* (if (qnull caller) *caller* (qt-object-? caller)))
(object (apply (string-to-symbol function)
arguments)))
(if (stringp object)
object
(print-to-js-string object))))
;;; utils
(defun root-item ()
(when *quick-view*
(|rootObject| *quick-view*)))
(defun find-quick-item (object-name)
"Finds the first QQuickItem matching OBJECT-NAME."
(if (string= (|objectName| (root-item)) object-name)
(root-item)
(qt-object-? (qfind-child (root-item) object-name))))
(defun quick-item (item/name)
(cond ((stringp item/name)
(find-quick-item item/name))
((qt-object-p item/name)
item/name)
((not item/name)
(root-item))))
(defun children (item/name)
(|childItems| (quick-item item/name)))
(defun reload ()
"Force reloading of QML file after changes made to it."
(|clearComponentCache| (|engine| *quick-view*))
(|setSource| *quick-view* (|source| *quick-view*)))
;;; get/set QQmlProperty
(defun qml-get (item/name property-name)
"Gets QQmlProperty of either ITEM or first object matching NAME."
(qlet ((property "QQmlProperty(QObject*,QString)"
(quick-item item/name)
property-name))
(if (|isValid| property)
(qlet ((variant (|read| property)))
(values (qvariant-value variant)
t))
(eql::%error-msg "QML-GET" (list item/name property-name)))))
(defun qml-set (item/name property-name value)
"Sets QQmlProperty of either ITEM, or first object matching NAME. Returns T on success."
(qlet ((property "QQmlProperty(QObject*,QString)"
(quick-item item/name)
property-name))
(if (|isValid| property)
(qlet ((variant (qvariant-from-value value (|propertyTypeName| property))))
(|write| property variant))
(eql::%error-msg "QML-SET" (list item/name property-name value)))))
;;; JS
(defun js (item/name js-format-string &rest arguments)
"Evaluates a JS string, with 'this' bound to either ITEM, or first object matching NAME. Arguments are passed through FORMAT."
(qlet ((qml-exp "QQmlExpression(QQmlContext*,QObject*,QString)"
(|rootContext| *quick-view*)
(quick-item item/name)
(apply 'format nil js-format-string arguments))
(variant (|evaluate| qml-exp)))
(qvariant-value variant)))

View file

@ -0,0 +1,22 @@
import QtQuick 2.0
import EQL5 1.0
import "qrc:eql5.js" as Lisp
Rectangle {
color: "gray"
PaintedItem {
// see QML:PAINT in Lisp
property string fillColor: "red"
x: 10; y: 10; width: 100; height: 100
}
PaintedItem {
// see QML:PAINT in Lisp
property string fillColor: "blue"
x: 120; y: 10; width: 100; height: 100
}
}

View file

@ -10,7 +10,8 @@ static QObject* lisp_provider(QQmlEngine*, QJSEngine*) { return lisp; }
QObject* ini() {
if(!lisp) {
lisp = new Lisp;
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider); }
qmlRegisterSingletonType<Lisp>("EQL5", 1, 0, "EQL5", lisp_provider);
qmlRegisterType<PaintedItem>("EQL5", 1, 0, "PaintedItem"); }
return lisp; }
QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantList& arguments) {
@ -19,4 +20,9 @@ QVariant Lisp::apply(QObject* caller, const QString& function, const QVariantLis
Q_ARG(QString, function),
Q_ARG(QVariantList, arguments)); }
void PaintedItem::paint(QPainter* painter) {
eql_fun("qml:paint",
Q_ARG(QQuickPaintedItem*, this),
Q_ARG(QPainter*, painter)); }
QT_END_NAMESPACE

View file

@ -2,6 +2,7 @@
#define LIB_H
#include <QtQml>
#include <QQuickPaintedItem>
#ifdef Q_OS_WIN
#define LIB_EXPORT __declspec(dllexport)
@ -20,6 +21,17 @@ public:
Q_INVOKABLE QVariant apply(QObject*, const QString&, const QVariantList& = QVariantList());
};
class PaintedItem : public QQuickPaintedItem {
Q_OBJECT
public:
PaintedItem(QQuickItem* parent = 0) : QQuickPaintedItem(parent) {}
void paint(QPainter*);
};
QT_END_NAMESPACE
#endif

View file

@ -1,4 +1,4 @@
QT += qml
QT += qml quick
TEMPLATE = lib
CONFIG += plugin release
INCLUDEPATH += ../../../../../src

View file

@ -37,7 +37,7 @@ Item {
// (5) pass 'this' as first argument (can be accessed in Lisp via qml:*caller*)
Lisp.call(this, "eql-user:show-properties-dialog")
// (6) i18n
// (6) i........18........n
console.log(Lisp.tr("internationalization"))
}