flan/examples/core-input-gestures.flan
Joseph Ferano 9a820d86cd Sweep every field label from the colon spelling to the dot
The script is in tools/ rather than thrown away, because two lanes are
writing Flan in the old spelling right now and their files need the same
pass at merge.

It works on forms, not on text: a keyword becomes a dot only where it sits
in a field-label position inside a brace, so an enum member in value
position, a map key inside an EDN string and a type-position {K V} are all
left alone. :keys keeps its colon -- it names no field.
2026-09-12 14:47:54 +07:00

111 lines
4.6 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
;;;; `defvar` 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)
(defvar gesture-log [max-gesture-strings string])
(defvar gestures-count i32)
(defvar current-gesture rl/Gesture)
(defvar 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/begin-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))
(rl/end-drawing)))))