ludic/packages/ludic.ui/layout_fit.ludic
Orkuncakilkaya a299117858 frame keeps: a model's records filled in place, kept event numbers, list spares, Json.read_file
From the fence's kept frames in 22 minutes of play:

- A component field that is a record or a list of records was `value_put(o, k, view_val_T(x))`,
  a whole new tree every frame (HudPrompt's notifications). view_fill.ludic generates view_set_T /
  view_set_list_T / view_fill_T that fill the object and list under the key in place.
- value_list_fit dropped the items it cut off and value_item made new ones as the list grew back,
  a Value per item per regrowth (value_item / value_set_strs); the cut-off items are now the
  list's spares (Val.spare), and an item of another kind is turned rather than replaced.
- ludic.ui: a scroll box's "scroll" and a slider's "change" fired a fresh Value.float a frame
  (sc_walk, scroll.ludic:36); ui_fire_float takes one from a ring kept with the state (fired.ludic).
  ui_object_fit_into is exported, for a draw that keeps its list.
- Json.read_file(path): read, parsed, and the file's text given back - Json.parse(Fs.read_text())
  kept the whole file on every read (Maroon Lake's settings peeks).

Golden value_list_regrow: a list alternating 6 and 2 items every frame keeps nothing (the toolchain
before this fails it: +128 B new Val from value_item). Game compiles; ludic.i18n/settings/hints/
base tests pass (ludic.ui has none); arena and fence goldens unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:22:13 +03:00

40 lines
1.6 KiB
Text

# layout_fit.ludic - aspect-ratio in layout: a width (fixed, a share, or fill) makes the height, a
# height the width, and neither the height from the content's width; object-fit in drawing: where a
# picture (or a native's content) of a natural size goes in the element's content box
function ly_ratio(n: UiNode, fixed_w: float, avail: float) -> void {
if n.ex == null or n.ex.ratio <= 0.0 { return }
let r = n.ex.ratio
if n.h < 0.0 and n.h_pct <= 0.0 {
var w = n.mw
if fixed_w >= 0.0 { w = fixed_w } else if n.w == UI_FILL { w = avail - n.ml - n.mr }
n.mw = w
n.mh = w / r
} else if fixed_w < 0.0 and n.w != UI_FILL and n.h >= 0.0 { n.mw = n.h * r }
}
# x, y, w, h: a `nat_w` x `nat_h` picture in the node's content box by its object-fit
export function ui_object_fit(n: UiNode, nat_w: float, nat_h: float) -> []float { return ui_object_fit_into(new []float, n, nat_w, nat_h) }
# ... into the caller's kept list (a draw every frame should: ui_object_fit makes one a call)
export function ui_object_fit_into(out: []float, n: UiNode, nat_w: float, nat_h: float) -> []float {
let bx = n.x + n.pl + n.bl
let by = n.y + n.pt + n.bt
let bw = n.cw - ly_hin(n)
let bh = n.ch - ly_vin(n)
var k = 0
if n.ex != null { k = n.ex.fit_obj }
var w = bw
var h = bh
if k != 0 and nat_w > 0.0 and nat_h > 0.0 {
var s = Math.min(bw / nat_w, bh / nat_h)
if k == 2 { s = Math.max(bw / nat_w, bh / nat_h) }
if k == 3 { s = 1.0 }
if k == 4 { s = Math.min(s, 1.0) }
w = nat_w * s
h = nat_h * s
}
List.clear(out)
ui_kept(out, bx + (bw - w) / 2.0)
ui_kept(out, by + (bh - h) / 2.0)
ui_kept(out, w)
ui_kept(out, h)
return out
}