add examples 'tilt-sensor' (sensor reading on mobile devices)

This commit is contained in:
pls.153 2022-04-15 10:32:22 +02:00
parent 834440953b
commit 15fc8c062a
9 changed files with 335 additions and 0 deletions

View 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")))

View 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

View 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))

View 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))

View file

@ -0,0 +1,7 @@
(defpackage :maze
(:use :cl :qml)
(:export
#:*maze*
#:ini
#:new-maze))

View 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")

View 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>

View 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)
}
}

View 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)`.