The trio the author decided on 2026-09-20 is now all built: def is CL's defparameter — its initialiser runs on every daemon re-run, unguarded, so an edited initialiser repaints the same storage on C-c C-c plus re-run — defonce (Clojure's name for CL's defvar, per the author) initialises once behind the .init~once. flag, and defconst stays the image. One parse arm reads both forms; the difference is Ast.reinit, carried to Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and Check.check_global lifts every def initialiser — zero and literal included — into global/<n>, so the host's startup reaches it through the function cell and a re-evaluated def swaps it (Session's def_inits; Emit.redefinition declares the cell for a non-sibling target). The old defvar spelling is refused with the rename and both compiling spellings, and every program, test, doc and editor list is swept — except sand.flan, the author's live WIP, whose seven defvar lines are flagged in FIX.org and keep its three dependent tests red on this branch.
109 lines
4.7 KiB
Plaintext
109 lines
4.7 KiB
Plaintext
;;;; raylib [core] example - input gestures
|
|
;;;;
|
|
;;;; examples/core/core_input_gestures.c. Needed `fade`, now bound.
|
|
;;;;
|
|
;;;; The C keeps `char gestureStrings[20][32]` and TextCopy's a name into the
|
|
;;;; next slot. Flan has no mutable character buffer and no way to copy into
|
|
;;;; one, but it does not need either: the names are compile-time literals, so
|
|
;;;; the log is a `[20 string]` and a slot holds the literal itself. That is
|
|
;;;; strictly better than the C — no truncation at 32 bytes, no copy — and it
|
|
;;;; is only possible because every string that ever goes into the log is
|
|
;;;; known at compile time. A log of strings the program had BUILT could not be
|
|
;;;; written at all.
|
|
;;;;
|
|
;;;; The C's `switch (currentGesture)` over the ten gesture values is a `cond`
|
|
;;;; of keyword equalities. `get-gesture-detected` answers an `rl/Gesture` and
|
|
;;;; `(= g :tap)` compares against a member by name, checked at compile time —
|
|
;;;; so a typo here is an error and the C's `default: break` has nothing to
|
|
;;;; catch.
|
|
;;;;
|
|
;;;; A slot that has not been written yet holds a zero-length string, because a
|
|
;;;; `defonce` with no initialiser is all-bytes-zero and a string is ptr+len —
|
|
;;;; a null pointer with a length of 0. draw-text draws nothing for it. That is
|
|
;;;; the C's `{ "" }` initialiser arriving by a different route, and it is why
|
|
;;;; resetting the log below only has to reset the counter.
|
|
|
|
(import rl "vendor:raylib")
|
|
|
|
(defconst screen-width 800)
|
|
(defconst screen-height 450)
|
|
|
|
(defconst max-gesture-strings 20)
|
|
|
|
(defonce gesture-log [max-gesture-strings string])
|
|
(defonce gestures-count i32)
|
|
(defonce current-gesture rl/Gesture)
|
|
(defonce last-gesture rl/Gesture)
|
|
|
|
;; The C's switch, as a function. `:else` is its `default:` — an unnamed
|
|
;; gesture logs the empty string, which draws nothing, which is what falling
|
|
;; through the C's switch without a TextCopy leaves in the slot.
|
|
(defn gesture-name [g rl/Gesture] string
|
|
(cond
|
|
(= g :tap) "GESTURE TAP"
|
|
(= g :double-tap) "GESTURE DOUBLETAP"
|
|
(= g :hold) "GESTURE HOLD"
|
|
(= g :drag) "GESTURE DRAG"
|
|
(= g :swipe-right) "GESTURE SWIPE RIGHT"
|
|
(= g :swipe-left) "GESTURE SWIPE LEFT"
|
|
(= g :swipe-up) "GESTURE SWIPE UP"
|
|
(= g :swipe-down) "GESTURE SWIPE DOWN"
|
|
(= g :pinch-in) "GESTURE PINCH IN"
|
|
(= g :pinch-out) "GESTURE PINCH OUT"
|
|
:else ""))
|
|
|
|
(defn main [] ()
|
|
(rl/init-window screen-width screen-height
|
|
"raylib [core] example - input gestures")
|
|
(defer (rl/close-window))
|
|
|
|
(rl/set-target-fps 60)
|
|
|
|
(let [touch-area (rl/Rectangle {.x 220.0 .y 10.0
|
|
.width (- (f32 screen-width) 230.0)
|
|
.height (- (f32 screen-height) 20.0)})]
|
|
(until (rl/window-should-close?)
|
|
;; Update
|
|
(set last-gesture current-gesture)
|
|
(set current-gesture (rl/get-gesture-detected))
|
|
(let [touch (rl/get-touch-position 0)]
|
|
|
|
(when (and (rl/collision-point-rec? touch touch-area)
|
|
(not (= current-gesture :none))
|
|
(not (= current-gesture last-gesture)))
|
|
(set (at gesture-log gestures-count) (gesture-name current-gesture))
|
|
(set gestures-count (+ gestures-count 1))
|
|
;; Full: start over. The stale slots below the counter are never
|
|
;; drawn, so they do not have to be cleared the way the C clears
|
|
;; them — the loop below is bounded by gestures-count.
|
|
(when (>= gestures-count max-gesture-strings)
|
|
(set gestures-count 0)))
|
|
|
|
;; Draw
|
|
(rl/with-drawing
|
|
(rl/clear-background rl/raywhite)
|
|
|
|
(rl/draw-rectangle-rec touch-area rl/gray)
|
|
(rl/draw-rectangle 225 15 (- screen-width 240) (- screen-height 30)
|
|
rl/raywhite)
|
|
|
|
(rl/draw-text "GESTURES TEST AREA" (- screen-width 270)
|
|
(- screen-height 40) 20 (rl/fade rl/gray 0.5))
|
|
|
|
(dotimes [i gestures-count]
|
|
(if (= 0 (% i 2))
|
|
(rl/draw-rectangle 10 (+ 30 (* 20 i)) 200 20
|
|
(rl/fade rl/lightgray 0.5))
|
|
(rl/draw-rectangle 10 (+ 30 (* 20 i)) 200 20
|
|
(rl/fade rl/lightgray 0.3)))
|
|
;; The newest entry in maroon and the rest in dark grey, as the C
|
|
;; has it.
|
|
(rl/draw-text (at gesture-log i) 35 (+ 36 (* 20 i)) 10
|
|
(if (< i (- gestures-count 1)) rl/darkgray rl/maroon)))
|
|
|
|
(rl/draw-rectangle-lines 10 29 200 (- screen-height 50) rl/gray)
|
|
(rl/draw-text "DETECTED GESTURES" 50 15 10 rl/gray)
|
|
|
|
(unless (= current-gesture :none)
|
|
(rl/draw-circle-v touch 30.0 rl/maroon)))))))
|