;;;; 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 :gesture-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" const screen-width = 800 const screen-height = 450 const max-gesture-strings = 20 once gesture-log: [max-gesture-strings str] once gestures-count: i32 once current-gesture: rl/Gesture once 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. fn gesture-name(g: rl/Gesture) -> str if g == :gesture-tap "GESTURE TAP" elif g == :gesture-double-tap "GESTURE DOUBLETAP" elif g == :gesture-hold "GESTURE HOLD" elif g == :gesture-drag "GESTURE DRAG" elif g == :gesture-swipe-right "GESTURE SWIPE RIGHT" elif g == :gesture-swipe-left "GESTURE SWIPE LEFT" elif g == :gesture-swipe-up "GESTURE SWIPE UP" elif g == :gesture-swipe-down "GESTURE SWIPE DOWN" elif g == :gesture-pinch-in "GESTURE PINCH IN" elif g == :gesture-pinch-out "GESTURE PINCH OUT" else "" fn 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 last-gesture = current-gesture current-gesture = rl/get-gesture-detected() let touch = rl/get-touch-position(0) if rl/check-collision-point-rec(touch, touch-area) and not current-gesture == :gesture-none and not current-gesture == last-gesture gesture-log[gestures-count] = gesture-name(current-gesture) 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. if gestures-count >= max-gesture-strings 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)) for i in range(gestures-count) if 0 == i % 2 rl/draw-rectangle(10, 30 + 20 * i, 200, 20, rl/fade(rl/lightgray, 0.5)) else 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(gesture-log[i], 35, 36 + 20 * i, 10, if i < gestures-count - 1 then rl/darkgray else 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 == :gesture-none): rl/draw-circle-v(touch, 30.0, rl/maroon)