mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 02:30:38 -08:00
add new example 'camera', showing how to use QML Camera on mobile (plus a web-server)
This commit is contained in:
parent
df4f72e2a9
commit
614737cbd4
13 changed files with 552 additions and 0 deletions
2
examples/camera/.gitignore
vendored
Normal file
2
examples/camera/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
7
examples/camera/app.asd
Normal file
7
examples/camera/app.asd
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
(defsystem :app
|
||||
:serial t
|
||||
:depends-on (#-:depends-loaded :s-http-server)
|
||||
:components ((:file "lisp/package")
|
||||
(:file "lisp/web-server")
|
||||
(:file "lisp/main")))
|
||||
|
||||
108
examples/camera/app.pro
Normal file
108
examples/camera/app.pro
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
LISP_FILES = $$files(lisp/*) app.asd make.lisp
|
||||
|
||||
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 multimedia
|
||||
TEMPLATE = app
|
||||
CONFIG += c++17 no_keywords release
|
||||
DEFINES = DESKTOP_APP INI_LISP INI_ECL_CONTRIB
|
||||
INCLUDEPATH = /usr/local/include
|
||||
ECL_VERSION = $$lower($$system(ecl -v))
|
||||
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
|
||||
LIBS = -L/usr/local/lib -lecl
|
||||
LIBS += -L/usr/local/lib/$$ECL_VERSION
|
||||
LIBS += -lecl-help -ldeflate -lecl-cdb -lecl-curl -lql-minitar -lsockets
|
||||
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 {
|
||||
LIBS += -lws2_32
|
||||
|
||||
include(../../src/windows.pri)
|
||||
}
|
||||
|
||||
android {
|
||||
QT += androidextras
|
||||
DEFINES -= DESKTOP_APP
|
||||
INCLUDEPATH = $$ECL/include
|
||||
ECL_VERSION = $$lower($$system($$ECL/../ecl-android-host/bin/ecl -v))
|
||||
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
|
||||
LIBS = -L$$ECL/lib -lecl
|
||||
LIBS += -L$$ECL/lib/$$ECL_VERSION
|
||||
LIBS += -lecl-help -ldeflate -lecl-cdb -lecl-curl -lql-minitar -lsockets
|
||||
LIBS += -L../../../platforms/android/lib
|
||||
|
||||
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
|
||||
ECL_VERSION = $$lower($$system($ECL_IOS/../ecl-ios-host/bin/ecl -v))
|
||||
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
|
||||
LIBS = -L$$(ECL_IOS)/lib -lecl
|
||||
LIBS += -leclatomic -leclffi -leclgc -leclgmp
|
||||
LIBS += -L$$(ECL_IOS)/lib/$$ECL_VERSION
|
||||
LIBS += -lecl-help -ldeflate -lecl-cdb -lecl-curl -lql-minitar -lsockets
|
||||
LIBS += -L../../../platforms/ios/lib
|
||||
|
||||
assets.files = $$files($$PWD/platforms/ios/assets)
|
||||
QMAKE_BUNDLE_DATA += assets
|
||||
|
||||
QMAKE_INFO_PLIST = platforms/ios/Info.plist
|
||||
}
|
||||
|
||||
32bit {
|
||||
LIBS += -llqml32 -llisp32
|
||||
} else {
|
||||
LIBS += -llqml -llisp
|
||||
}
|
||||
|
||||
LIBS += -Ltmp -lapp
|
||||
HEADERS += ../../src/cpp/main.h
|
||||
SOURCES += ../../src/cpp/main.cpp
|
||||
|
||||
RESOURCES += $$files(qml/*)
|
||||
RESOURCES += $$files(i18n/*.qm)
|
||||
|
||||
lupdate_only {
|
||||
SOURCES += i18n/tr.h
|
||||
}
|
||||
3
examples/camera/build-android/install-run.sh
Executable file
3
examples/camera/build-android/install-run.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# install/update (keeps app data)
|
||||
adb install -r android-build/*.apk
|
||||
adb shell am start -n org.qtproject.example.camera/org.qtproject.qt5.android.bindings.QtActivity # Qt5
|
||||
2
examples/camera/lisp/main.lisp
Normal file
2
examples/camera/lisp/main.lisp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
(in-package :camera)
|
||||
|
||||
7
examples/camera/lisp/package.lisp
Normal file
7
examples/camera/lisp/package.lisp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
(defpackage :camera
|
||||
(:use :cl :qml :s-http-server)
|
||||
(:export
|
||||
#:*image-path*
|
||||
#:*web-server*
|
||||
#:create-index.html))
|
||||
|
||||
48
examples/camera/lisp/web-server.lisp
Normal file
48
examples/camera/lisp/web-server.lisp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
;;; This starts a local web-server in order to preview/download the taken
|
||||
;;; pictures on your desktop computer. Make sure you are in the same WiFi,
|
||||
;;; and open:
|
||||
;;;
|
||||
;;; http://192.168.1.x:1701/
|
||||
|
||||
(in-package :camera)
|
||||
|
||||
(defvar *web-server* nil)
|
||||
(defvar *image-path* nil)
|
||||
|
||||
(defvar *index.html*
|
||||
"<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<style type=\"text/css\">
|
||||
img { width: 50px; border-width: 10px; border-style: solid; border-color: white }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
~A
|
||||
</body>
|
||||
</html>")
|
||||
|
||||
(defvar *img.htm* "<a href=~S><img src=~S /></a>")
|
||||
|
||||
(defun ini (image-path)
|
||||
(setf *web-server* (make-s-http-server))
|
||||
(start-server *web-server*)
|
||||
(register-context-handler *web-server* "/" 'static-resource-handler
|
||||
:arguments (list image-path)))
|
||||
|
||||
(defun create-index.html (image-path) ; called from QML
|
||||
"Creates 'index.html' for local web-server."
|
||||
(unless *image-path*
|
||||
(ini image-path))
|
||||
(setf *image-path* image-path)
|
||||
(with-open-file (s (merge-pathnames "index.html" image-path)
|
||||
:direction :output :if-exists :supersede)
|
||||
(format s *index.html*
|
||||
(x:join (mapcar (lambda (file)
|
||||
(let ((name (x:cc (pathname-name file) ".jpg")))
|
||||
(format nil *img.htm* name name)))
|
||||
(sort (directory (merge-pathnames "*_0*.jpg" image-path))
|
||||
'string< :key 'pathname-name))
|
||||
#\Newline)))
|
||||
(values)) ; no return value to QML
|
||||
|
||||
90
examples/camera/make.lisp
Normal file
90
examples/camera/make.lisp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
;;; 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*)
|
||||
|
||||
;;; copy ECL '*.doc' and 'encodings/' (mobile only)
|
||||
|
||||
(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
|
||||
(unless (probe-file (cc *assets* "encodings"))
|
||||
(ensure-directories-exist *assets*)
|
||||
(let ((lib (cc (ext:getenv #+android "ECL_ANDROID" #+ios "ECL_IOS")
|
||||
"/lib/ecl-*/")))
|
||||
(shell (cc "cp " lib "*.doc " *assets*))
|
||||
(shell (cc "cp -r " lib "encodings " *assets*))))
|
||||
|
||||
;;; compile ASDF system
|
||||
|
||||
(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/")))
|
||||
|
||||
(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 "app.lib"
|
||||
#-msvc "libapp.a")
|
||||
(to* #-mobile (cc *current* "build/tmp/" to)
|
||||
#+mobile (cc *library-path* to)))
|
||||
(when (probe-file to*)
|
||||
(delete-file to*))
|
||||
(rename-file from to))
|
||||
81
examples/camera/platforms/android/AndroidManifest.xml
Normal file
81
examples/camera/platforms/android/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0"?>
|
||||
<manifest package="org.qtproject.example.camera" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="false"/>
|
||||
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Camera" android:extractNativeLibs="true">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="Camera" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<!-- Application arguments -->
|
||||
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||
<!-- Application arguments -->
|
||||
<meta-data android:name="android.app.lib_name" android:value="app"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
<!-- Deploy Qt libs as part of package -->
|
||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>
|
||||
<!-- Run with local libs -->
|
||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="1"/>
|
||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||
<meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
|
||||
<meta-data android:name="android.app.load_local_jars" android:value="jar/QtAndroid.jar:jar/QtAndroidBearer.jar:jar/QtAndroidExtras.jar:jar/QtMultimedia.jar"/>
|
||||
<meta-data android:name="android.app.static_init_classes" android:value="org.qtproject.qt5.android.multimedia.QtMultimediaUtils"/>
|
||||
<!-- Used to specify custom system library path to run with local system libs -->
|
||||
<!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> -->
|
||||
<!-- Messages maps -->
|
||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
|
||||
<!-- Messages maps -->
|
||||
<!-- Splash screen -->
|
||||
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
|
||||
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
|
||||
use hideSplashScreen() with a fade-out animation from Qt Android Extras to hide the splash screen when you
|
||||
are done populating your window with content. -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" / -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" / -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||
<!-- Splash screen -->
|
||||
<!-- Background running -->
|
||||
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||
application still try to draw after
|
||||
"applicationStateChanged(Qt::ApplicationSuspended)"
|
||||
signal is sent! -->
|
||||
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||
<!-- Background running -->
|
||||
<!-- auto screen scale factor -->
|
||||
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||
<!-- auto screen scale factor -->
|
||||
<!-- extract android style -->
|
||||
<!-- available android:values :
|
||||
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
|
||||
* full - useful QWidget & Quick Controls 1 apps
|
||||
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
|
||||
* none - useful for apps that don't use any of the above Qt modules
|
||||
-->
|
||||
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||
<!-- extract android style -->
|
||||
</activity>
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
41
examples/camera/platforms/ios/Info.plist
Normal file
41
examples/camera/platforms/ios/Info.plist
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Camera</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${QMAKE_SHORT_VERSION}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>${QMAKE_PKGINFO_TYPEINFO}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${QMAKE_FULL_VERSION}</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>${IPHONEOS_DEPLOYMENT_TARGET}</string>
|
||||
<key>NOTE</key>
|
||||
<string>This file was generated by Qt/QMake.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>To manually take pictures.</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
90
examples/camera/qml/main.qml
Normal file
90
examples/camera/qml/main.qml
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtMultimedia 5.15
|
||||
|
||||
Rectangle {
|
||||
width: 640
|
||||
height: 360
|
||||
color: "gray"
|
||||
|
||||
Camera {
|
||||
id: camera
|
||||
objectName: "camera"
|
||||
|
||||
imageCapture {
|
||||
onImageSaved: {
|
||||
imagePaths.append({"path": "file://" + path})
|
||||
listView.positionViewAtEnd()
|
||||
Lisp.call("camera:create-index.html", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
objectName: "output"
|
||||
source: camera
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: listView.height + 10
|
||||
focus: visible // to receive focus and capture key events when visible
|
||||
}
|
||||
|
||||
// menu buttons
|
||||
|
||||
Column {
|
||||
anchors.right: parent.right
|
||||
padding: 10
|
||||
spacing: 10
|
||||
|
||||
ComboBox {
|
||||
id: cameras
|
||||
width: 170
|
||||
model: QtMultimedia.availableCameras
|
||||
textRole: "displayName"
|
||||
valueRole: "deviceId"
|
||||
|
||||
onActivated: camera.deviceId = currentValue
|
||||
}
|
||||
|
||||
RoundButton {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: parent.spacing
|
||||
width: 80
|
||||
height: width
|
||||
text: "Photo"
|
||||
|
||||
onClicked: camera.imageCapture.capture()
|
||||
}
|
||||
}
|
||||
|
||||
// list of taken images
|
||||
|
||||
ListModel {
|
||||
id: imagePaths
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
height: parent.height / 5
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: 10
|
||||
orientation: ListView.Horizontal
|
||||
model: imagePaths
|
||||
|
||||
delegate: Image {
|
||||
required property string path
|
||||
height: parent.height
|
||||
source: path
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: -10
|
||||
color: "black"
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
42
examples/camera/readme.md
Normal file
42
examples/camera/readme.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
Info
|
||||
----
|
||||
|
||||
This shows how to use the QML Camera item. Only very basic usage is covered
|
||||
here -- of course you can set many parameters, if you want to dive into all the
|
||||
details (see Qt Assistant).
|
||||
|
||||
Additionally, a basic web-server is integrated, in order to watch/download the
|
||||
images (mobile device) on the desktop computer. On every new image taken, the
|
||||
`index.html` is updated.
|
||||
|
||||
To display the images on the desktop, enter the following link, using the IP of
|
||||
the mobile device (assuming both desktop and mobile are in the same WiFi):
|
||||
|
||||
```
|
||||
http://192.168.1.x:1701/
|
||||
```
|
||||
**1701** is the default port of `:s-http-server` (from Quicklisp), which was
|
||||
chosen here because it's both relatively small and works well on mobile.
|
||||
|
||||
You may wonder about the "wrong" orientation of the images in the browser: this
|
||||
depends both on the camera orientation and on the mobile OS.
|
||||
|
||||
|
||||
|
||||
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 releoad 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)`.
|
||||
|
||||
31
examples/camera/run.lisp
Normal file
31
examples/camera/run.lisp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
(in-package :qml-user)
|
||||
|
||||
(require :asdf)
|
||||
|
||||
(asdf:load-system :s-http-server)
|
||||
|
||||
(push (merge-pathnames "./")
|
||||
asdf:*central-registry*)
|
||||
|
||||
(push :depends-loaded *features*)
|
||||
|
||||
(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