mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 10:31:34 -08:00
add examples 'tilt-sensor' (sensor reading on mobile devices)
This commit is contained in:
parent
834440953b
commit
15fc8c062a
9 changed files with 335 additions and 0 deletions
8
examples/tilt-sensor/app.asd
Normal file
8
examples/tilt-sensor/app.asd
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
(defsystem :app
|
||||||
|
:serial t
|
||||||
|
:depends-on ()
|
||||||
|
:components ((:file "lisp/package")
|
||||||
|
(:file "lisp/ui-vars")
|
||||||
|
(:file "lisp/maze")
|
||||||
|
(:file "lisp/main")))
|
||||||
|
|
||||||
3
examples/tilt-sensor/build-android/install-run.sh
Executable file
3
examples/tilt-sensor/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.lqml.example.maze/org.qtproject.qt5.android.bindings.QtActivity # Qt5
|
||||||
57
examples/tilt-sensor/lisp/main.lisp
Normal file
57
examples/tilt-sensor/lisp/main.lisp
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
(in-package :maze)
|
||||||
|
|
||||||
|
(defconstant +w+ 13) ; ball width
|
||||||
|
|
||||||
|
(defvar *x*) ; ball x
|
||||||
|
(defvar *y*) ; ball y
|
||||||
|
|
||||||
|
(defun move (x-rotation y-rotation) ; called from QML
|
||||||
|
(labels ((add (x)
|
||||||
|
(truncate (signum x)))
|
||||||
|
(to-pos (x)
|
||||||
|
(truncate (/ (+ x (/ +w+ 2))
|
||||||
|
+w+)))
|
||||||
|
(normalize (x)
|
||||||
|
(* (to-pos x) +w+)))
|
||||||
|
(let* ((dx (min (* 0.2 x-rotation) (1- +w+)))
|
||||||
|
(dy (min (* 0.2 y-rotation) (1- +w+)))
|
||||||
|
(add-x (add dx))
|
||||||
|
(add-y (add dy)))
|
||||||
|
(if (aref *maze*
|
||||||
|
(+ add-x (to-pos *x*))
|
||||||
|
(to-pos *y*))
|
||||||
|
(setf *x* (normalize *x*))
|
||||||
|
(incf *x* dx))
|
||||||
|
(if (aref *maze*
|
||||||
|
(to-pos *x*)
|
||||||
|
(+ add-y (to-pos *y*)))
|
||||||
|
(setf *y* (normalize *y*))
|
||||||
|
(incf *y* dy))))
|
||||||
|
(move-ball)
|
||||||
|
(values))
|
||||||
|
|
||||||
|
(defun move-ball ()
|
||||||
|
(if (and (= *x* +w+)
|
||||||
|
(= *y* 0))
|
||||||
|
(new-game)
|
||||||
|
(let ((ball (find-quick-item ui:*ball*)))
|
||||||
|
;; 'qset' is faster than 'q>', but can't trigger animations
|
||||||
|
(qset ball |x| (- *x* 0.5))
|
||||||
|
(qset ball |y| (- *y* 0.5)))))
|
||||||
|
|
||||||
|
(defun start ()
|
||||||
|
(setf *x* (* +w+ (- *width* 1))
|
||||||
|
*y* (* +w+ (- *height* 2)))
|
||||||
|
(move-ball)
|
||||||
|
(q> |running| ui:*timer* t))
|
||||||
|
|
||||||
|
(defun stop ()
|
||||||
|
(q> |running| ui:*timer* nil))
|
||||||
|
|
||||||
|
(defun new-game ()
|
||||||
|
(new-maze)
|
||||||
|
(start))
|
||||||
|
|
||||||
|
(progn
|
||||||
|
(start)
|
||||||
|
(qlater 'ini))
|
||||||
61
examples/tilt-sensor/lisp/maze.lisp
Normal file
61
examples/tilt-sensor/lisp/maze.lisp
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
;;; original copyright: CL Maze 20030311 by Joe Wingbermuehle
|
||||||
|
;;;
|
||||||
|
;;; this is a reviewed version
|
||||||
|
|
||||||
|
(in-package :maze)
|
||||||
|
|
||||||
|
;; both must be odd
|
||||||
|
(defconstant *width* 25)
|
||||||
|
(defconstant *height* 39)
|
||||||
|
|
||||||
|
(defvar *maze*)
|
||||||
|
|
||||||
|
(defun carve-maze (x y)
|
||||||
|
(let ((d (random 4)))
|
||||||
|
(dotimes (c 4)
|
||||||
|
(let* ((cd (mod (+ c d) 4))
|
||||||
|
(dv (case cd
|
||||||
|
(0 (list 1 0))
|
||||||
|
(1 (list 0 1))
|
||||||
|
(2 (list -1 0))
|
||||||
|
(t (list 0 -1))))
|
||||||
|
(x1 (+ x (car dv)))
|
||||||
|
(y1 (+ y (cadr dv)))
|
||||||
|
(x2 (+ x1 (car dv)))
|
||||||
|
(y2 (+ y1 (cadr dv))))
|
||||||
|
(when (and (< 0 x2 *width*)
|
||||||
|
(< 0 y2 *height*)
|
||||||
|
(aref *maze* x1 y1)
|
||||||
|
(aref *maze* x2 y2))
|
||||||
|
(set-visible x1 y1 nil)
|
||||||
|
(set-visible x2 y2 nil)
|
||||||
|
(qsleep 0.001) ; slow down to make visible
|
||||||
|
(carve-maze x2 y2))))))
|
||||||
|
|
||||||
|
(defun generate-maze ()
|
||||||
|
(set-visible 1 1 nil)
|
||||||
|
(carve-maze 1 1)
|
||||||
|
(set-visible 1 0 nil)
|
||||||
|
(set-visible (- *width* 1) (- *height* 2) nil))
|
||||||
|
|
||||||
|
(defun set-visible (x y visible)
|
||||||
|
(setf (aref *maze* x y) visible)
|
||||||
|
;; |visible| doesn't work inside Repeater
|
||||||
|
(q> |opacity| (q! |itemAt| ui:*maze*
|
||||||
|
(+ x (* y *width*)))
|
||||||
|
(if visible 1 0)))
|
||||||
|
|
||||||
|
(defun display-maze ()
|
||||||
|
(dotimes (y *height*)
|
||||||
|
(dotimes (x *width*)
|
||||||
|
(set-visible x y (aref *maze* x y)))))
|
||||||
|
|
||||||
|
(defun new-maze ()
|
||||||
|
(setf *maze* (make-array (list *width* *height*)
|
||||||
|
:initial-element t))
|
||||||
|
(display-maze)
|
||||||
|
(qlater 'generate-maze))
|
||||||
|
|
||||||
|
(defun ini ()
|
||||||
|
(setf *random-state* (make-random-state t))
|
||||||
|
(new-maze))
|
||||||
7
examples/tilt-sensor/lisp/package.lisp
Normal file
7
examples/tilt-sensor/lisp/package.lisp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
(defpackage :maze
|
||||||
|
(:use :cl :qml)
|
||||||
|
(:export
|
||||||
|
#:*maze*
|
||||||
|
#:ini
|
||||||
|
#:new-maze))
|
||||||
|
|
||||||
13
examples/tilt-sensor/lisp/ui-vars.lisp
Normal file
13
examples/tilt-sensor/lisp/ui-vars.lisp
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
(defpackage ui
|
||||||
|
(:use :cl :qml)
|
||||||
|
(:export
|
||||||
|
#:*ball*
|
||||||
|
#:*maze*
|
||||||
|
#:*timer*))
|
||||||
|
|
||||||
|
(in-package :ui)
|
||||||
|
|
||||||
|
(defparameter *ball* "ball")
|
||||||
|
(defparameter *maze* "maze")
|
||||||
|
(defparameter *timer* "timer")
|
||||||
|
|
||||||
77
examples/tilt-sensor/platforms/android/AndroidManifest.xml
Normal file
77
examples/tilt-sensor/platforms/android/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<manifest package="org.lqml.example.maze" 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"/>
|
||||||
|
|
||||||
|
<!-- 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-sdk android:minSdkVersion="21" android:targetSdkVersion="31"/>
|
||||||
|
<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="Maze" 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="Maze" android:screenOrientation="portrait" 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/QtAndroidExtras.jar:jar/QtAndroidBearer.jar"/>
|
||||||
|
<meta-data android:name="android.app.static_init_classes" android:value=""/>
|
||||||
|
<!-- 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>
|
||||||
74
examples/tilt-sensor/qml/main.qml
Normal file
74
examples/tilt-sensor/qml/main.qml
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtSensors 5.15
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 400
|
||||||
|
height: 600
|
||||||
|
color: "#333"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -25
|
||||||
|
width: grid.width
|
||||||
|
height: grid.height
|
||||||
|
color: "white"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
objectName: "ball"
|
||||||
|
width: 13
|
||||||
|
height: width
|
||||||
|
radius: width / 2
|
||||||
|
color: "#c33"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
id: grid
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -25
|
||||||
|
columns: 25
|
||||||
|
rows: 39
|
||||||
|
columnSpacing: 1
|
||||||
|
rowSpacing: 1
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: maze
|
||||||
|
objectName: "maze"
|
||||||
|
model: parent.columns * parent.rows
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 12
|
||||||
|
height: width
|
||||||
|
color: "steelblue"
|
||||||
|
radius: width / 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundButton {
|
||||||
|
id: button
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 7
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: "Change Maze"
|
||||||
|
|
||||||
|
onClicked: Lisp.call("maze:new-game")
|
||||||
|
}
|
||||||
|
|
||||||
|
// sensor and timer
|
||||||
|
|
||||||
|
TiltSensor {
|
||||||
|
id: tilt
|
||||||
|
active: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
objectName: "timer"
|
||||||
|
interval: 30
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
// reversed: x axis changes y position, y axis changes x position
|
||||||
|
onTriggered: Lisp.call("maze:move", tilt.reading.yRotation, tilt.reading.xRotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
35
examples/tilt-sensor/readme.md
Normal file
35
examples/tilt-sensor/readme.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
Prepare
|
||||||
|
-------
|
||||||
|
|
||||||
|
Please copy the app template files first:
|
||||||
|
```
|
||||||
|
$ cd ..
|
||||||
|
$ ./copy.sh tilt-sensor
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Info
|
||||||
|
----
|
||||||
|
|
||||||
|
This shows how to read mobile device sensor data from QML, combined with a
|
||||||
|
`Timer`. Note also how a `Repeater` simplifies the UI.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)`.
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue