flan/examples/core-window-flags.flan
Joseph Ferano 1df6f7a642 Five more core examples, and the 3D half of the bindings they wanted
core-2d-camera, core-scissor-test, core-window-flags, core-world-screen
and core-window-should-close, ported from raylib 5.5's examples/core.

What each one asked of vendor/raylib:

  2d-camera        nothing. A whole Camera2D by value, per frame, into the
                   call that actually draws with it — the layout the
                   acceptance table pins through arithmetic, now going
                   through the path it was bound for.
  scissor-test     begin-scissor-mode / end-scissor-mode, hand-written.
  window-flags     twelve more ConfigFlags constants; raylib.flan carried
                   the four sand.flan sets and this reads eleven.
  world-screen     the 3D surface did not exist: no Vector3, no Camera3D,
                   and the importer refused every 3D function in raylib.h
                   by name for want of them. Two defstructs, two defenums,
                   begin/end-mode-3d, update-camera, get-world-to-screen,
                   draw-cube, draw-cube-wires, draw-grid — and 24 more 3D
                   lines the importer can generate now that the types are
                   described.
  window-should-close  set-exit-key, and Key/null to pass it.

The hand-written/generated line, written down in vendor/raylib/bindings:
a drawing pair inside a frame is hand-written, and so is anything whose
Flan face is not the C signature — set-exit-key takes a Key, update-camera
takes a (Ptr Camera3D) and a CameraMode. The window-state family and
get-mouse-x/y stay generated: plain scalars in and bool out, with nothing
for a hand-written line to add.

Camera3D's projection field stays i32, because the header says int and the
layout check holds this file to that; rl/camera-projection is the
conversion, and still takes a keyword.
2026-09-13 12:51:19 +07:00

180 lines
8.2 KiB
Plaintext

;;;; raylib [core] example - window flags
;;;;
;;;; examples/core/core_window_flags.c. The reason to port this one is the
;;;; flags themselves: raylib.flan carried four of ConfigFlags' sixteen
;;;; members — the four sand.flan sets before the window exists — and this
;;;; example reads and writes eleven of them after it exists. All sixteen are
;;;; in raylib.flan now, read off raylib.h 5.5, in the header's order and not
;;;; in bit order (FLAG_VSYNC_HINT is 0x40 and FLAG_FULLSCREEN_MODE is 0x02,
;;;; which is the kind of thing nobody remembers correctly).
;;;;
;;;; They are `defconst u32`s and not a `defenum` for the reason the file
;;;; already gives about gestures: raylib wants the OR of several and a
;;;; keyword can only ever name one member.
;;;;
;;;; window-state?, set-window-state, clear-window-state, toggle-fullscreen,
;;;; minimize-window, maximize-window and restore-window all come from the
;;;; generated half. That is the line drawn in vendor/raylib/bindings and it
;;;; is worth saying why it falls here: the rule in PORTING.md §1 exists so
;;;; that a build with no header set can still draw, and generated.flan is
;;;; committed, so it can. What a hand-written line adds on top of that is a
;;;; Flan face the C signature does not have — a Key instead of an int, a
;;;; (Ptr Camera3D) instead of a raw pointer — and these seven have no such
;;;; face to add. They are u32 in and bool out in both languages.
;;;;
;;;; Not faithful in one place, deliberately: the C draws twelve lines of
;;;; on/off state through TextFormat and a two-branch if each time. Flan has
;;;; no TextFormat, so the pair is one helper here — which also removes the
;;;; C's own copy-paste bug, where the UNFOCUSED line says "[G]" when it is on
;;;; and "[U]" when it is off.
(import rl "vendor:raylib")
(import d "digits.flan")
(defconst screen-width 800)
(defconst screen-height 450)
;; Frames the window has been hidden or minimized for. H and N both put the
;; window somewhere it cannot be typed at, so the only way back is a count.
(defconst restore-after 240)
(defvar ball-pos rl/Vector2)
(defvar ball-speed rl/Vector2)
(defvar frames i32)
(defconst ball-radius f32 20.0)
;; One line of the state list: the label, then "on" or "off" in lime or
;; maroon, at the x the label ended. The C writes two whole DrawText calls per
;; flag with the text repeated; this says it once.
(defn draw-flag [label string flag u32 y i32] ()
(rl/draw-text label 10 y 10 rl/gray)
(let [x (+ 10 (rl/measure-text label 10))]
(if (rl/window-state? flag)
(rl/draw-text " on" x y 10 rl/lime)
(rl/draw-text " off" x y 10 rl/maroon))))
;; A flag the program owns: pressing the key turns it off if it is on and on
;; if it is off. Nine of the C's eleven key handlers are exactly this.
(defn toggle-flag [flag u32] ()
(if (rl/window-state? flag)
(rl/clear-window-state flag)
(rl/set-window-state flag)))
(defn main [] ()
;; The C leaves its SetConfigFlags call commented out, so that every flag
;; the list shows starts off. Kept that way: the point of the example is
;; which of them can be changed afterwards.
(rl/init-window screen-width screen-height
"raylib [core] example - window flags")
(defer (rl/close-window))
(set ball-pos (rl/Vector2 {.x (/ (f32 (rl/get-screen-width)) 2.0)
.y (/ (f32 (rl/get-screen-height)) 2.0)}))
(set ball-speed (rl/Vector2 {.x 5.0 .y 4.0}))
;; No set-target-fps, as in the C: with FLAG_VSYNC_HINT among the flags the
;; example toggles, a frame limiter on top of it would hide what V-Sync
;; does to the number draw-fps reports.
(until (rl/window-should-close?)
;; Update
(when (rl/key-pressed? :f) (rl/toggle-fullscreen))
(when (rl/key-pressed? :r) (toggle-flag rl/flag-window-resizable))
(when (rl/key-pressed? :d) (toggle-flag rl/flag-window-undecorated))
(when (rl/key-pressed? :u) (toggle-flag rl/flag-window-unfocused))
(when (rl/key-pressed? :t) (toggle-flag rl/flag-window-topmost))
(when (rl/key-pressed? :a) (toggle-flag rl/flag-window-always-run))
(when (rl/key-pressed? :v) (toggle-flag rl/flag-vsync-hint))
;; Hidden and minimized are not toggles: the window they hide is also the
;; window the key would have to be pressed in, so each comes back on a
;; timer instead.
(when (rl/key-pressed? :h)
(unless (rl/window-state? rl/flag-window-hidden)
(rl/set-window-state rl/flag-window-hidden))
(set frames 0))
(when (rl/window-state? rl/flag-window-hidden)
(set frames (+ frames 1))
(when (>= frames restore-after)
(rl/clear-window-state rl/flag-window-hidden)))
(when (rl/key-pressed? :n)
(unless (rl/window-state? rl/flag-window-minimized)
(rl/minimize-window))
(set frames 0))
(when (rl/window-state? rl/flag-window-minimized)
(set frames (+ frames 1))
(when (>= frames restore-after) (rl/restore-window)))
;; Maximize needs FLAG_WINDOW_RESIZABLE first, which is what R is for.
(when (rl/key-pressed? :m)
(if (rl/window-state? rl/flag-window-maximized)
(rl/restore-window)
(rl/maximize-window)))
;; The ball bounces off whatever the window is right now, so resizing,
;; maximizing and going fullscreen all show up in its path.
(set (.x ball-pos) (+ (.x ball-pos) (.x ball-speed)))
(set (.y ball-pos) (+ (.y ball-pos) (.y ball-speed)))
(when (or (>= (.x ball-pos) (- (f32 (rl/get-screen-width)) ball-radius))
(<= (.x ball-pos) ball-radius))
(set (.x ball-speed) (* (.x ball-speed) -1.0)))
(when (or (>= (.y ball-pos) (- (f32 (rl/get-screen-height)) ball-radius))
(<= (.y ball-pos) ball-radius))
(set (.y ball-speed) (* (.y ball-speed) -1.0)))
;; Draw
(rl/begin-drawing)
;; A transparent framebuffer wants a transparent clear; anything else
;; paints over the desktop the flag exists to show.
(if (rl/window-state? rl/flag-window-transparent)
(rl/clear-background rl/blank)
(rl/clear-background rl/raywhite))
(rl/draw-circle-v ball-pos ball-radius rl/maroon)
(rl/draw-rectangle-lines-ex
(rl/Rectangle {.x 0.0 .y 0.0
.width (f32 (rl/get-screen-width))
.height (f32 (rl/get-screen-height))})
4.0 rl/raywhite)
(rl/draw-circle-v (rl/get-mouse-position) 10.0 rl/darkblue)
(rl/draw-fps 10 10)
;; The C's TextFormat("Screen Size: [%i, %i]", ...), reassembled out of
;; literals and examples/digits.flan the way the other ports do it: `x`
;; walks along the line, and draw-int hands back the width it drew.
(let [x 10]
(rl/draw-text "Screen Size: [" x 40 10 rl/green)
(set x (+ x (rl/measure-text "Screen Size: [" 10)))
(set x (+ x (d/draw-int (rl/get-screen-width) x 40 10 rl/green)))
(rl/draw-text ", " x 40 10 rl/green)
(set x (+ x (rl/measure-text ", " 10)))
(set x (+ x (d/draw-int (rl/get-screen-height) x 40 10 rl/green)))
(rl/draw-text "]" x 40 10 rl/green))
(rl/draw-text "Following flags can be set after window creation:"
10 60 10 rl/gray)
(draw-flag "[F] FLAG_FULLSCREEN_MODE:" rl/flag-fullscreen-mode 80)
(draw-flag "[R] FLAG_WINDOW_RESIZABLE:" rl/flag-window-resizable 100)
(draw-flag "[D] FLAG_WINDOW_UNDECORATED:" rl/flag-window-undecorated 120)
(draw-flag "[H] FLAG_WINDOW_HIDDEN:" rl/flag-window-hidden 140)
(draw-flag "[N] FLAG_WINDOW_MINIMIZED:" rl/flag-window-minimized 160)
(draw-flag "[M] FLAG_WINDOW_MAXIMIZED:" rl/flag-window-maximized 180)
(draw-flag "[U] FLAG_WINDOW_UNFOCUSED:" rl/flag-window-unfocused 200)
(draw-flag "[T] FLAG_WINDOW_TOPMOST:" rl/flag-window-topmost 220)
(draw-flag "[A] FLAG_WINDOW_ALWAYS_RUN:" rl/flag-window-always-run 240)
(draw-flag "[V] FLAG_VSYNC_HINT:" rl/flag-vsync-hint 260)
(rl/draw-text "Following flags can only be set before window creation:"
10 300 10 rl/gray)
(draw-flag "FLAG_WINDOW_HIGHDPI:" rl/flag-window-highdpi 320)
(draw-flag "FLAG_WINDOW_TRANSPARENT:" rl/flag-window-transparent 340)
(draw-flag "FLAG_MSAA_4X_HINT:" rl/flag-msaa-4x-hint 360)
(rl/end-drawing)))