# controls_parts.ludic - what a control shows besides its own parts: its label, with a `note` (a line # of help under it) in .ui-labels > .ui-label + .ui-note, and a range's or a number's value as text: # `decimals="1"` places, `format="percent"` its place between min and max, and a `unit` after it function ct_label(ui_st: mut UiState, n: UiNode) -> void { let label = ui_attr_text(n, "label") let note = ui_attr_text(n, "note") if note == "" { if label != "" { ui_kept(n.children, ct_part(ui_st, n, "ui-label", ui_tr(ui_st, label))) } return } let both = ct_part(ui_st, n, "ui-labels", "") if label != "" { ui_kept(both.children, ct_part(ui_st, n, "ui-label", ui_tr(ui_st, label))) } ui_kept(both.children, ct_part(ui_st, n, "ui-note", ui_tr(ui_st, note))) ui_kept(n.children, both) } @alloc_ok("a memo miss: once per value a range shows (memo_more.ludic)") function ct_value_text(n: UiNode) -> string { let v = ui_attr(n, "value") if Value.kind(v) == 0 { return "" } var f = Value.as_float(v) let fmt = ui_attr_text(n, "format") if fmt == "percent" { let lo = Value.as_float(ui_attr(n, "min")) var hi = Value.as_float(ui_attr(n, "max")) if hi <= lo { hi = lo + 1.0 } f = (f - lo) / (hi - lo) * 100.0 } var s = "" if Value.kind(ui_attr(n, "decimals")) != 0 { s = ct_fixed(f, Value.as_int(ui_attr(n, "decimals"))) } else if fmt == "percent" { s = string(int(Math.round(f))) } else { s = vl_text(v) } if fmt == "percent" { s = s + "%" } return s + ui_attr_text(n, "unit") } # a number with `places` digits after the point, rounded @alloc_ok("a memo miss (ct_value_shown): once per value a range shows") function ct_fixed(f: float, places: int) -> string { var k = 1 for i in 0 .. Math.max(places, 0) { k = k * 10 } let neg = f < 0.0 let whole = int(Math.round(Math.abs(f) * float(k))) var s = string(whole / k) if places > 0 { var frac = string(whole % k) while len(frac) < places { frac = "0" + frac } s = s + "." + frac } if neg and whole != 0 { s = "-" + s } return s } # Enter (or A) on a text field: on-submit with what it holds; the focus stays, and the text too # unless it says clear-on-submit function ct_submit(ui_st: mut UiState, n: UiNode) -> void { ui_fire(ui_st, n, "submit", ui_attr(n, "value")) if ui_attr_on(n, "clear-on-submit") { ui_fire(ui_st, n, "change", Value.str("")) } } # the text is exactly i's digits, compared without writing i out function ct_is_int(s: string, i: int) -> bool { if i < 0 or len(s) == 0 { return false } var n = i var at = len(s) - 1 while at >= 0 { if s[at] != 48 + n % 10 { return false } n = n / 10 at -= 1 if n == 0 { return at < 0 } } return false } # a press let go over a control: on a select's < it steps back, anywhere else on it forward (the < # stepped forward too, so a cycler's left arrow did the right one's job) function ct_activate_at(ui_st: mut UiState, n: UiNode, x: float, y: float) -> void { if ct_type(n) == "select" and ct_over_part(n, "ui-prev", x, y) { ct_step(ui_st, n, -1) return } ct_activate(ui_st, n) } function ct_over_part(n: UiNode, cls: string, x: float, y: float) -> bool { for i in 0 .. len(n.children) { let c = n.children[i] if sel_has(c.classes, cls) and x >= c.x and y >= c.y and x < c.x + c.cw and y < c.y + c.ch { return true } } return false }