- flex-shrink: a line whose children want more room than it has takes it back from those that shrink, in proportion to shrink times size and never below a min size, a fixed size or the content. A scroll box shrinks (and scrolls), and a box in a column shrinks as far as the scroll boxes inside it let it, so a list in a column takes the room its siblings leave with no height. `flex: grow shrink`, and `flex-shrink` by name. - A row wider than its room measures its texts (and boxes without a width) again in the room the rest leave them, so a line wraps beside an icon. - calc() with + - * / and brackets over px, %, em, rem, vw, vh, plain numbers and var(); a width or height keeps its percentage, taken of the room it is given. Lengths lists (padding, margin) keep a calc()'s spaces. - `order` places a box's children without touching the tree. - width: 0 and height: 0 are 0: an unset size is UI_AUTO now, not 0. - A component root that is itself a component takes each user's class, style and id in turn (the outermost's id wins), and the rules of all their sheets are weighed by specificity together; a user's rule wins a tie. The parent's sheet used to override the child's whatever its specificity, and a middle component's sheet was lost. - The default sheet lays .ui-track out as a row, so a range's fill is as tall as its track and a checked box's knob goes right; a range's thumb is centred on the fill's end. - ui_boxes.ludic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.9 KiB
Text
75 lines
2.9 KiB
Text
# layout_shrink.ludic - flex-shrink: when a line's children want more room than it has, those that
|
|
# shrink give it up, each in proportion to its shrink times its size, and none below what it must
|
|
# keep (its min size, a fixed size, its content's). A scroll box keeps nothing - it scrolls - so a
|
|
# list in a column takes the room its siblings leave; a box in a column shrinks as far as the scroll
|
|
# boxes inside it let it, and anything else shrinks only when flex-shrink says so.
|
|
function ly_shrink(dir: int, c: UiNode) -> float {
|
|
if c.ex != null and c.ex.shrink >= 0.0 { return c.ex.shrink }
|
|
if c.kind == UI_SCROLL { return 1.0 }
|
|
if dir == UI_COL and c.kind == UI_BOX { return 1.0 }
|
|
return 0.0
|
|
}
|
|
# how small a child may be pressed along the run, margins included
|
|
function ly_floor(dir: int, c: UiNode) -> float {
|
|
if dir == UI_ROW {
|
|
var w = c.min_w
|
|
if c.w >= 0.0 { w = Math.max(w, c.w) }
|
|
return w + c.ml + c.mr
|
|
}
|
|
return Math.max(ly_min_h(c), c.min_h) + c.mt + c.mb
|
|
}
|
|
function ly_min_h(c: UiNode) -> float {
|
|
if c.ex != null and c.ex.has_min { return c.ex.mh_min }
|
|
return c.mh
|
|
}
|
|
# `sizes` (the children from..to) shrunk by `over` in all
|
|
function ly_shrink_line(n: UiNode, from: int, sizes: []float, over0: float) -> void {
|
|
var over = over0
|
|
let frozen = new []bool
|
|
for k in 0 .. len(sizes) { push(frozen, n.children[from + k].pos >= 2) }
|
|
for pass in 0 .. 8 {
|
|
var wsum = 0.0
|
|
for k in 0 .. len(sizes) {
|
|
if not frozen[k] { wsum = wsum + ly_shrink(n.dir, n.children[from + k]) * sizes[k] }
|
|
}
|
|
if wsum <= 0.0 or over <= 0.01 { return }
|
|
var taken = 0.0
|
|
for k in 0 .. len(sizes) {
|
|
let c = n.children[from + k]
|
|
let wk = ly_shrink(n.dir, c) * sizes[k]
|
|
if frozen[k] or wk <= 0.0 { continue }
|
|
let floor = Math.min(ly_floor(n.dir, c), sizes[k])
|
|
var want = sizes[k] - over * wk / wsum
|
|
if want <= floor {
|
|
want = floor
|
|
frozen[k] = true
|
|
}
|
|
taken = taken + sizes[k] - want
|
|
sizes[k] = want
|
|
}
|
|
over = over - taken
|
|
}
|
|
}
|
|
# how short the box can be pressed: a scroll box to its padding, a column to what its children can
|
|
# be, a row to its tallest child's least; kept only when it is less than the box's own height
|
|
function ly_min_note(n: UiNode) -> void {
|
|
var m = n.mh
|
|
if n.h < 0.0 and n.kind == UI_SCROLL { m = ly_vin(n) } else if n.h < 0.0 and n.kind == UI_BOX and n.children != null and not n.wrap {
|
|
var sum = 0.0
|
|
var count = 0
|
|
for i in 0 .. len(n.children) {
|
|
let c = n.children[i]
|
|
if c.pos >= 2 { continue }
|
|
let cm = ly_min_h(c) + c.mt + c.mb
|
|
if n.dir == UI_ROW { sum = Math.max(sum, cm) } else { sum = sum + cm }
|
|
if n.dir == UI_COL and count > 0 { sum = sum + n.gap }
|
|
count += 1
|
|
}
|
|
m = ly_vin(n) + sum
|
|
}
|
|
m = ly_clamp(m, n.min_h, n.max_h)
|
|
if m < n.mh - 0.01 {
|
|
nx(n).mh_min = m
|
|
n.ex.has_min = true
|
|
} else if n.ex != null { n.ex.has_min = false }
|
|
}
|