mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-05 18:20:33 -08:00
add new example 'qsqlite': use SQL from Lisp, load QML images from DB
This commit is contained in:
parent
a9d93035b6
commit
121170fcbd
17 changed files with 577 additions and 0 deletions
9
examples/qsqlite/app.asd
Normal file
9
examples/qsqlite/app.asd
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
(defsystem :app
|
||||||
|
:serial t
|
||||||
|
:depends-on ()
|
||||||
|
:components ((:file "lisp/package")
|
||||||
|
(:file "lisp/qt")
|
||||||
|
(:file "lisp/ui-vars")
|
||||||
|
(:file "lisp/db")
|
||||||
|
(:file "lisp/main")))
|
||||||
|
|
||||||
127
examples/qsqlite/app.pro
Normal file
127
examples/qsqlite/app.pro
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
LISP_FILES = $$files(lisp/*) app.asd make.lisp
|
||||||
|
|
||||||
|
exists(/etc/sailfish-release) {
|
||||||
|
CONFIG += sfos
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
32bit {
|
||||||
|
ECL = $$(ECL_ANDROID_32)
|
||||||
|
} else {
|
||||||
|
ECL = $$(ECL_ANDROID)
|
||||||
|
}
|
||||||
|
lisp.commands = $$ECL/../ecl-android-host/bin/ecl \
|
||||||
|
-norc -shell $$PWD/make.lisp
|
||||||
|
} else:ios {
|
||||||
|
lisp.commands = $$(ECL_IOS)/../ecl-ios-host/bin/ecl \
|
||||||
|
-norc -shell $$PWD/make.lisp
|
||||||
|
} else:unix {
|
||||||
|
lisp.commands = /usr/local/bin/ecl -shell $$PWD/make.lisp
|
||||||
|
} else:win32 {
|
||||||
|
lisp.commands = ecl.exe -shell $$PWD/make.lisp
|
||||||
|
}
|
||||||
|
|
||||||
|
lisp.input = LISP_FILES
|
||||||
|
|
||||||
|
win32: lisp.output = tmp/app.lib
|
||||||
|
!win32: lisp.output = tmp/libapp.a
|
||||||
|
|
||||||
|
QMAKE_EXTRA_COMPILERS += lisp
|
||||||
|
|
||||||
|
win32: PRE_TARGETDEPS = tmp/app.lib
|
||||||
|
!win32: PRE_TARGETDEPS = tmp/libapp.a
|
||||||
|
|
||||||
|
QT += quick qml quickcontrols2 sql
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += c++17 no_keywords release
|
||||||
|
DEFINES = DESKTOP_APP INI_LISP QT_EXTENSION
|
||||||
|
INCLUDEPATH = /usr/local/include
|
||||||
|
LIBS = -L/usr/local/lib -lecl
|
||||||
|
DESTDIR = .
|
||||||
|
TARGET = app
|
||||||
|
OBJECTS_DIR = tmp
|
||||||
|
MOC_DIR = tmp
|
||||||
|
|
||||||
|
linux: LIBS += -L../../../platforms/linux/lib
|
||||||
|
macx: LIBS += -L../../../platforms/macos/lib
|
||||||
|
win32: LIBS += -L../../../platforms/windows/lib
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
include(../../src/windows.pri)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
DEFINES -= DESKTOP_APP
|
||||||
|
INCLUDEPATH = $$ECL/include
|
||||||
|
LIBS = -L$$ECL/lib -lecl
|
||||||
|
LIBS += -L../../../platforms/android/lib
|
||||||
|
|
||||||
|
equals(QT_MAJOR_VERSION, 6) {
|
||||||
|
QT += core-private
|
||||||
|
}
|
||||||
|
lessThan(QT_MAJOR_VERSION, 6) {
|
||||||
|
QT += androidextras
|
||||||
|
}
|
||||||
|
|
||||||
|
ANDROID_EXTRA_LIBS += $$ECL/lib/libecl.so
|
||||||
|
ANDROID_PACKAGE_SOURCE_DIR = ../platforms/android
|
||||||
|
|
||||||
|
32bit {
|
||||||
|
ANDROID_ABIS = "armeabi-v7a"
|
||||||
|
} else {
|
||||||
|
ANDROID_ABIS = "arm64-v8a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ios {
|
||||||
|
DEFINES -= DESKTOP_APP
|
||||||
|
INCLUDEPATH = $$(ECL_IOS)/include
|
||||||
|
LIBS = -L$$(ECL_IOS)/lib -lecl
|
||||||
|
LIBS += -leclatomic -leclffi -leclgc -leclgmp
|
||||||
|
LIBS += -L../../../platforms/ios/lib
|
||||||
|
}
|
||||||
|
|
||||||
|
32bit {
|
||||||
|
android {
|
||||||
|
equals(QT_MAJOR_VERSION, 6) {
|
||||||
|
LIBS += -llqml32_armeabi-v7a
|
||||||
|
}
|
||||||
|
lessThan(QT_MAJOR_VERSION, 6) {
|
||||||
|
LIBS += -llqml32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!android {
|
||||||
|
LIBS += -llqml32
|
||||||
|
}
|
||||||
|
LIBS += -llisp32
|
||||||
|
} else {
|
||||||
|
android {
|
||||||
|
equals(QT_MAJOR_VERSION, 6) {
|
||||||
|
LIBS += -llqml_arm64-v8a
|
||||||
|
}
|
||||||
|
lessThan(QT_MAJOR_VERSION, 6) {
|
||||||
|
LIBS += -llqml
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!android {
|
||||||
|
LIBS += -llqml
|
||||||
|
}
|
||||||
|
LIBS += -llisp
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBS += -Ltmp -lapp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
../../src/cpp/main.h \
|
||||||
|
cpp/qt.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
../../src/cpp/main.cpp \
|
||||||
|
cpp/qt.cpp
|
||||||
|
|
||||||
|
RESOURCES += $$files(qml/*)
|
||||||
|
RESOURCES += $$files(i18n/*.qm)
|
||||||
|
|
||||||
|
lupdate_only {
|
||||||
|
SOURCES += i18n/tr.h
|
||||||
|
}
|
||||||
BIN
examples/qsqlite/blob/logo-064.png
Executable file
BIN
examples/qsqlite/blob/logo-064.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
examples/qsqlite/blob/logo-128.png
Executable file
BIN
examples/qsqlite/blob/logo-128.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
examples/qsqlite/blob/logo-256.png
Executable file
BIN
examples/qsqlite/blob/logo-256.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
94
examples/qsqlite/cpp/qt.cpp
Normal file
94
examples/qsqlite/cpp/qt.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include "qt.h"
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlError>
|
||||||
|
#include <QQuickView>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
QObject* ini() {
|
||||||
|
static QObject* qt = nullptr;
|
||||||
|
if (qt == nullptr) {
|
||||||
|
qt = new QT;
|
||||||
|
}
|
||||||
|
return qt;
|
||||||
|
}
|
||||||
|
|
||||||
|
QT::QT() : QObject() {
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant QT::dataPath(const QVariant& prefix) {
|
||||||
|
// for desktop
|
||||||
|
QString path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
|
||||||
|
path.truncate(path.lastIndexOf(QChar('/')));
|
||||||
|
path.append(QStringLiteral("/lqml-qsqlite/") + prefix.toString());
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQL
|
||||||
|
|
||||||
|
QVariant QT::iniDb(const QVariant& vName, const QVariant& vQuickView) {
|
||||||
|
// add database image provider, in order to load images in QML directly from a SQL database
|
||||||
|
auto quickView = vQuickView.value<QQuickView*>();
|
||||||
|
quickView->engine()->addImageProvider(QLatin1String("db"), new DatabaseImageProvider(this));
|
||||||
|
// ini
|
||||||
|
db = QSqlDatabase::addDatabase("QSQLITE");
|
||||||
|
db.setDatabaseName(vName.toString());
|
||||||
|
return vName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant QT::sqlQuery(const QVariant& vQuery, const QVariant& vValues, const QVariant& vCols) {
|
||||||
|
QVariantList results;
|
||||||
|
QSqlQuery sqlQuery(db);
|
||||||
|
if (db.open()) {
|
||||||
|
QString query = vQuery.toString();
|
||||||
|
sqlQuery.prepare(vQuery.toString());
|
||||||
|
const QVariantList values = vValues.value<QVariantList>();
|
||||||
|
for (auto value : values) {
|
||||||
|
sqlQuery.addBindValue(value);
|
||||||
|
}
|
||||||
|
if (sqlQuery.exec()) {
|
||||||
|
auto cols = vCols.toInt();
|
||||||
|
while (sqlQuery.next()) {
|
||||||
|
if (cols > 1) {
|
||||||
|
QVariantList list;
|
||||||
|
for (auto r = 0; r < cols; r++) {
|
||||||
|
list << sqlQuery.value(r);
|
||||||
|
}
|
||||||
|
results << QVariant(list);
|
||||||
|
} else {
|
||||||
|
results << sqlQuery.value(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cols && query.startsWith("insert", Qt::CaseInsensitive)) {
|
||||||
|
results << sqlQuery.lastInsertId();
|
||||||
|
}
|
||||||
|
db.close();
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
QString text;
|
||||||
|
if (sqlQuery.lastError().isValid()) {
|
||||||
|
text = sqlQuery.lastError().text();
|
||||||
|
} else {
|
||||||
|
text = db.lastError().text();
|
||||||
|
}
|
||||||
|
qDebug() << "SQL error:" << text;
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// database image provider
|
||||||
|
|
||||||
|
QPixmap DatabaseImageProvider::requestPixmap(const QString& name, QSize* size, const QSize& requestedSize) {
|
||||||
|
auto result = qt->sqlQuery(
|
||||||
|
"select data from images where name = ?",
|
||||||
|
QVariantList() << name,
|
||||||
|
1); // number of returned columns
|
||||||
|
QPixmap pixmap;
|
||||||
|
pixmap.loadFromData(result.value<QVariantList>().first().toByteArray());
|
||||||
|
*size = pixmap.size();
|
||||||
|
if (requestedSize.isValid() && (pixmap.size() != requestedSize)) {
|
||||||
|
pixmap = pixmap.scaled(requestedSize);
|
||||||
|
}
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
36
examples/qsqlite/cpp/qt.h
Normal file
36
examples/qsqlite/cpp/qt.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QQuickImageProvider>
|
||||||
|
|
||||||
|
#ifdef Q_CC_MSVC
|
||||||
|
#define LIB_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define LIB_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" { LIB_EXPORT QObject* ini(); }
|
||||||
|
|
||||||
|
class QT : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE QVariant dataPath(const QVariant&);
|
||||||
|
Q_INVOKABLE QVariant iniDb(const QVariant&, const QVariant&);
|
||||||
|
Q_INVOKABLE QVariant sqlQuery(const QVariant&, const QVariant&, const QVariant&);
|
||||||
|
|
||||||
|
QT();
|
||||||
|
|
||||||
|
QSqlDatabase db;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DatabaseImageProvider : public QQuickImageProvider {
|
||||||
|
|
||||||
|
public:
|
||||||
|
DatabaseImageProvider(QT* _qt) : QQuickImageProvider(QQuickImageProvider::Pixmap), qt(_qt) {}
|
||||||
|
|
||||||
|
QPixmap requestPixmap(const QString&, QSize*, const QSize&);
|
||||||
|
|
||||||
|
QT* qt;
|
||||||
|
};
|
||||||
27
examples/qsqlite/cpp/qt.pro
Normal file
27
examples/qsqlite/cpp/qt.pro
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
QT += sql quick
|
||||||
|
TEMPLATE = lib
|
||||||
|
CONFIG += c++17 plugin release no_keywords
|
||||||
|
DEFINES += PLUGIN
|
||||||
|
INCLUDEPATH = /usr/local/include ../../../src/cpp
|
||||||
|
LIBS = -L/usr/local/lib -lecl
|
||||||
|
DESTDIR = ./
|
||||||
|
TARGET = qt
|
||||||
|
OBJECTS_DIR = ./tmp/
|
||||||
|
MOC_DIR = ./tmp/
|
||||||
|
|
||||||
|
HEADERS += qt.h
|
||||||
|
SOURCES += qt.cpp
|
||||||
|
|
||||||
|
linux {
|
||||||
|
LIBS += -L../../../platforms/linux/lib
|
||||||
|
}
|
||||||
|
|
||||||
|
macx {
|
||||||
|
LIBS += -L../../../platforms/macos/lib
|
||||||
|
}
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
include(../../../src/windows.pri)
|
||||||
|
|
||||||
|
LIBS += -L../../../platforms/windows/lib
|
||||||
|
}
|
||||||
34
examples/qsqlite/lisp/db.lisp
Normal file
34
examples/qsqlite/lisp/db.lisp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
(in-package :db)
|
||||||
|
|
||||||
|
(defvar *file* nil)
|
||||||
|
|
||||||
|
(defun query (query &rest values)
|
||||||
|
(let ((rows (and (x:starts-with "select" query)
|
||||||
|
(1+ (count #\, (subseq query 0 (search "from" query)))))))
|
||||||
|
(qrun* (qt:sql-query qt:*cpp* query values rows))))
|
||||||
|
|
||||||
|
(defun ini ()
|
||||||
|
(setf *file* (app:in-data-path "db"))
|
||||||
|
(ensure-directories-exist *file*)
|
||||||
|
(qt:ini-db qt:*cpp* (namestring *file*) *quick-view*)
|
||||||
|
(query "create table if not exists images (id integer primary key autoincrement, name text, data blob)"))
|
||||||
|
|
||||||
|
(defun size ()
|
||||||
|
(first (query "select count(*) from images")))
|
||||||
|
|
||||||
|
(defun save-image (name data)
|
||||||
|
"Inserts image NAME, DATA (vector of octets) and returns the new image ID."
|
||||||
|
(first (query "insert into images (name, data) values (?, ?)"
|
||||||
|
name data)))
|
||||||
|
|
||||||
|
(defun load-images ()
|
||||||
|
(query "select name, data from images order by id"))
|
||||||
|
|
||||||
|
(defun delete-image (id)
|
||||||
|
(query "delete from images where id = ?"
|
||||||
|
id)
|
||||||
|
(values))
|
||||||
|
|
||||||
|
(defun delete-all-images ()
|
||||||
|
(query "delete from images"))
|
||||||
|
|
||||||
35
examples/qsqlite/lisp/main.lisp
Normal file
35
examples/qsqlite/lisp/main.lisp
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
(in-package :app)
|
||||||
|
|
||||||
|
(defun ini ()
|
||||||
|
(qt:ini)
|
||||||
|
(db:ini)
|
||||||
|
(populate-db)
|
||||||
|
;; loads image directly from database, see 'cpp/qt.cpp::DatabaseImageProvider'
|
||||||
|
(q> |source| ui:*logo* "image://db/logo-128"))
|
||||||
|
|
||||||
|
(defun in-data-path (&optional (file "") (prefix "data/"))
|
||||||
|
#+mobile
|
||||||
|
(merge-pathnames (x:cc prefix file))
|
||||||
|
#-mobile
|
||||||
|
(x:cc (qrun* (qt:data-path qt:*cpp* prefix)) file))
|
||||||
|
|
||||||
|
(defun file-bytes (file)
|
||||||
|
(with-open-file (s file :element-type '(unsigned-byte 8))
|
||||||
|
(let ((arr (make-array (file-length s) :element-type '(unsigned-byte 8))))
|
||||||
|
(read-sequence arr s)
|
||||||
|
arr)))
|
||||||
|
|
||||||
|
;; put images in database
|
||||||
|
|
||||||
|
(defun populate-db ()
|
||||||
|
(let ((files (sort (directory (merge-pathnames "blob/*.png"))
|
||||||
|
'string< :key 'pathname-name)))
|
||||||
|
(when (/= (length files) (db:size))
|
||||||
|
(if (probe-file (merge-pathnames "blob/"))
|
||||||
|
(progn
|
||||||
|
(db:delete-all-images)
|
||||||
|
(dolist (file files)
|
||||||
|
(db:save-image (pathname-name file) (file-bytes file)))))
|
||||||
|
(x:d "No 'blob/' directory found."))))
|
||||||
|
|
||||||
|
(qlater 'ini)
|
||||||
15
examples/qsqlite/lisp/package.lisp
Normal file
15
examples/qsqlite/lisp/package.lisp
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
(defpackage :app
|
||||||
|
(:use :cl :qml)
|
||||||
|
(:export
|
||||||
|
#:in-data-path))
|
||||||
|
|
||||||
|
(defpackage :db
|
||||||
|
(:use :cl :qml)
|
||||||
|
(:export
|
||||||
|
#:delete-image
|
||||||
|
#:delete-all-images
|
||||||
|
#:ini
|
||||||
|
#:load-images
|
||||||
|
#:save-image
|
||||||
|
#:size))
|
||||||
|
|
||||||
19
examples/qsqlite/lisp/qt.lisp
Normal file
19
examples/qsqlite/lisp/qt.lisp
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
(defpackage :qt
|
||||||
|
(:use :cl :qml)
|
||||||
|
(:export
|
||||||
|
#:*cpp*
|
||||||
|
#:data-path
|
||||||
|
#:ini
|
||||||
|
#:ini-db
|
||||||
|
#:sql-query))
|
||||||
|
|
||||||
|
(in-package :qt)
|
||||||
|
|
||||||
|
(defvar *cpp* nil)
|
||||||
|
|
||||||
|
(defun ini ()
|
||||||
|
(setf *cpp*
|
||||||
|
#+qt-plugin (qload-c++ "cpp/qt")
|
||||||
|
#-qt-plugin (qfind-child nil "QT"))
|
||||||
|
(let ((*package* (find-package :qt)))
|
||||||
|
(define-qt-wrappers *cpp*)))
|
||||||
9
examples/qsqlite/lisp/ui-vars.lisp
Normal file
9
examples/qsqlite/lisp/ui-vars.lisp
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
(defpackage ui
|
||||||
|
(:use :cl :qml)
|
||||||
|
(:export
|
||||||
|
#:*logo*))
|
||||||
|
|
||||||
|
(in-package :ui)
|
||||||
|
|
||||||
|
(defparameter *logo* "logo")
|
||||||
|
|
||||||
88
examples/qsqlite/make.lisp
Normal file
88
examples/qsqlite/make.lisp
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
;; check target
|
||||||
|
(let ((arg (first (ext:command-args))))
|
||||||
|
(mapc (lambda (name feature)
|
||||||
|
(when (search name arg)
|
||||||
|
(pushnew feature *features*)))
|
||||||
|
(list "/ecl-android" "/ecl-ios")
|
||||||
|
(list :android :ios)))
|
||||||
|
|
||||||
|
#+(or android ios)
|
||||||
|
(pushnew :mobile *features*)
|
||||||
|
|
||||||
|
(when (probe-file "/etc/sailfish-release")
|
||||||
|
(pushnew :sfos *features*))
|
||||||
|
|
||||||
|
(defun cc (&rest args)
|
||||||
|
(apply 'concatenate 'string args))
|
||||||
|
|
||||||
|
#+mobile
|
||||||
|
(defvar *assets* #+android "../platforms/android/assets/lib/"
|
||||||
|
#+ios "../platforms/ios/assets/Library/")
|
||||||
|
|
||||||
|
#+mobile
|
||||||
|
(defun shell (command)
|
||||||
|
(ext:run-program "sh" (list "-c" command)))
|
||||||
|
|
||||||
|
#+mobile
|
||||||
|
(let ((blob #+android *assets*
|
||||||
|
#+ios (cc *assets* "../Documents/")))
|
||||||
|
(ensure-directories-exist blob)
|
||||||
|
(shell (cc "cp -r ../blob " blob)))
|
||||||
|
|
||||||
|
(require :asdf)
|
||||||
|
(require :cmp)
|
||||||
|
|
||||||
|
(push (merge-pathnames "../")
|
||||||
|
asdf:*central-registry*)
|
||||||
|
|
||||||
|
(setf *default-pathname-defaults*
|
||||||
|
(truename (merge-pathnames "../../../"))) ; LQML root
|
||||||
|
|
||||||
|
(defvar *current*
|
||||||
|
(let ((name (namestring *load-truename*)))
|
||||||
|
(subseq name
|
||||||
|
(length (namestring *default-pathname-defaults*))
|
||||||
|
(1+ (position #\/ name :from-end t)))))
|
||||||
|
|
||||||
|
(dolist (file (list "package" "x" "ecl-ext" "ini" "qml")) ; load LQML symbols
|
||||||
|
(load (merge-pathnames file "src/lisp/")))
|
||||||
|
|
||||||
|
(defun cc (&rest args)
|
||||||
|
(apply 'concatenate 'string args))
|
||||||
|
|
||||||
|
(progn
|
||||||
|
(defvar cl-user::*tr-path* (truename (cc *current* "i18n/")))
|
||||||
|
(load "src/lisp/tr"))
|
||||||
|
|
||||||
|
#-mobile
|
||||||
|
(asdf:make-build "app"
|
||||||
|
:monolithic t
|
||||||
|
:type :static-library
|
||||||
|
:move-here (cc *current* "build/tmp/")
|
||||||
|
:init-name "ini_app")
|
||||||
|
|
||||||
|
#+mobile
|
||||||
|
(progn
|
||||||
|
(pushnew :interpreter *features*)
|
||||||
|
(defvar *asdf-system* "app")
|
||||||
|
(defvar *ql-libs* (cc *current* "ql-libs.lisp"))
|
||||||
|
(defvar *init-name* "ini_app")
|
||||||
|
(defvar *library-path* (format nil "~Abuild-~A/tmp/"
|
||||||
|
*current*
|
||||||
|
#+android "android"
|
||||||
|
#+ios "ios"))
|
||||||
|
(defvar *require* (list :ecl-curl))
|
||||||
|
(load "platforms/shared/make"))
|
||||||
|
|
||||||
|
;; rename lib
|
||||||
|
(let* ((from #-mobile (cc *current* (format nil "build/tmp/app--all-systems.~A"
|
||||||
|
#+msvc "lib"
|
||||||
|
#-msvc "a"))
|
||||||
|
#+mobile (cc *library-path* "app--all-systems.a"))
|
||||||
|
(to #-msvc "libapp.a"
|
||||||
|
#+msvc "app.lib")
|
||||||
|
(to* #-mobile (cc *current* "build/tmp/" to)
|
||||||
|
#+mobile (cc *library-path* to)))
|
||||||
|
(when (probe-file to*)
|
||||||
|
(delete-file to*))
|
||||||
|
(rename-file from to))
|
||||||
12
examples/qsqlite/qml/main.qml
Normal file
12
examples/qsqlite/qml/main.qml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: 300
|
||||||
|
height: 500
|
||||||
|
|
||||||
|
Image {
|
||||||
|
objectName: "logo"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
43
examples/qsqlite/readme.md
Normal file
43
examples/qsqlite/readme.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
Info
|
||||||
|
----
|
||||||
|
|
||||||
|
This is a simple example of:
|
||||||
|
|
||||||
|
* using the **qsqlite** (Qt specific SQLite DB) library directly from Lisp
|
||||||
|
* providing a custom image provider, so we can directly load images in QML from
|
||||||
|
an SQL database
|
||||||
|
|
||||||
|
The qsqlite library that comes with Qt has the advantage of being pulled in
|
||||||
|
automatically as a dependency, and behaving exactly the same, no matter what OS
|
||||||
|
is used. This is especially convenient on mobile.
|
||||||
|
|
||||||
|
If you run the example with:
|
||||||
|
```
|
||||||
|
$ lqml run.lisp -slime
|
||||||
|
```
|
||||||
|
you can then try to change the image source from the REPL:
|
||||||
|
```
|
||||||
|
(in-package :app)
|
||||||
|
|
||||||
|
(q> |source| ui:*logo* "image://db/logo-256")
|
||||||
|
```
|
||||||
|
This will load the image directly from the database.
|
||||||
|
|
||||||
|
|
||||||
|
Run
|
||||||
|
---
|
||||||
|
```
|
||||||
|
lqml run.lisp
|
||||||
|
```
|
||||||
|
Optionally pass `-slime` to start a Swank server, and connect from Emacs with
|
||||||
|
`M-x slime-connect`.
|
||||||
|
|
||||||
|
During development you can pass `-auto`, which will reload all QML files after
|
||||||
|
you made a change to any of them and saved it. For re-initialization after
|
||||||
|
reloading, file `lisp/qml-reload/on-reloaded` will be loaded.
|
||||||
|
|
||||||
|
Closing the window quits the app. If you try to kill it with `ctrl-c`, you need
|
||||||
|
an additional `ctrl-d` to exit from ECL. To quit from Slime, do `(qq)` which is
|
||||||
|
short for `(qquit)`.
|
||||||
|
|
||||||
29
examples/qsqlite/run.lisp
Normal file
29
examples/qsqlite/run.lisp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
(in-package :qml-user)
|
||||||
|
|
||||||
|
(pushnew :qt-plugin *features*)
|
||||||
|
|
||||||
|
(require :asdf)
|
||||||
|
|
||||||
|
(push (merge-pathnames "./")
|
||||||
|
asdf:*central-registry*)
|
||||||
|
|
||||||
|
(asdf:operate 'asdf:load-source-op :app)
|
||||||
|
|
||||||
|
(qset *quick-view*
|
||||||
|
|x| 75
|
||||||
|
|y| 75)
|
||||||
|
|
||||||
|
(defun option (name)
|
||||||
|
(find name (ext:command-args) :test 'search))
|
||||||
|
|
||||||
|
;;; trivial auto reload of all QML files after saving any change
|
||||||
|
|
||||||
|
(when (option "-auto")
|
||||||
|
(load "lisp/qml-reload/auto-reload"))
|
||||||
|
|
||||||
|
;;; for Slime after copying 'lqml-start-swank.lisp' from LQML sources
|
||||||
|
;;; to your Slime directory, which is assumed to be '~/slime/'
|
||||||
|
|
||||||
|
(when (option "-slime")
|
||||||
|
(load "~/slime/lqml-start-swank")) ; for 'slime-connect' from Emacs
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue