- the scrollbar is .ui-scrollbar with a .ui-thumb, styled by the default sheet or a theme; a press on the thumb holds it at the point it was taken and the pointer moves it in proportion, a press on the track jumps the thumb's middle there and holds it, and neither presses what is under the bar (it used to centre the thumb on the pointer and press the row beneath as well); - while a popover is up only scroll boxes inside it take the pointer, and a press outside it that closes it forgets any press in progress; - a transition ends exactly on its value (it stopped a rounding error short, at every frame rate). Tests: ui_popover_mouse, ui_scrollbar, ui_ease (60/120/180/240 Hz). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
2.6 KiB
Text
63 lines
2.6 KiB
Text
# scroll_bar.ludic - a scroll box's bar: .ui-scrollbar, the track down its right edge, and its
|
|
# .ui-thumb, styled by the default sheet or a theme as the box's own parts. A press on the thumb holds
|
|
# it where it was taken; a press on the track jumps the thumb's middle to the pointer and holds it there.
|
|
var sb_x: float = 0.0
|
|
var sb_w: float = 0.0
|
|
var sb_ty: float = 0.0
|
|
var sb_th: float = 0.0
|
|
var sb_bar: UiNode = null
|
|
var sc_grab: float = 0.0 # how far below the thumb's top the pointer holds it
|
|
# the bar's parts, styled as descendants of the box, and where they are at this offset
|
|
function sb_geo(n: UiNode, off: float, room: float, most: float) -> void {
|
|
let bar = ct_part(n, "ui-scrollbar", "")
|
|
bar.tag = "div"
|
|
bar.parent = n
|
|
push(bar.children, ct_part(n, "ui-thumb", ""))
|
|
cs_tree(bar)
|
|
sb_bar = bar
|
|
sb_w = ui_px(6.0)
|
|
if bar.w >= 0.0 { sb_w = bar.w }
|
|
sb_x = n.x + n.cw - sb_w - bar.mr
|
|
var least = ui_px(24.0)
|
|
if len(bar.children) > 0 and bar.children[0].min_h > 0.0 { least = bar.children[0].min_h }
|
|
sb_th = Math.min(Math.max(n.ch * room / (room + most), least), n.ch)
|
|
sb_ty = n.y
|
|
if most > 0.0 { sb_ty = n.y + (n.ch - sb_th) * Math.clamp(off, 0.0, most) / most }
|
|
}
|
|
# the pointer on the bar: taken on a press over it, moved while held, let go on release
|
|
function sb_input(n: UiNode, off: float, room: float, most: float) -> float {
|
|
let i = in_now
|
|
if most <= 0.0 or room <= 0.0 { return off }
|
|
if i.down and not in_was_down and sc_drag == "" {
|
|
sb_geo(n, off, room, most)
|
|
let reach = Math.min(sb_x, n.x + n.cw - ui_px(14.0))
|
|
let over = i.x >= reach and i.y >= n.y and i.x < n.x + n.cw and i.y < n.y + n.ch
|
|
if over and not sb_bar.hidden {
|
|
sc_drag = n.key
|
|
sc_grab = sb_th / 2.0
|
|
if i.y >= sb_ty and i.y < sb_ty + sb_th { sc_grab = i.y - sb_ty }
|
|
}
|
|
}
|
|
if sc_drag != n.key { return off }
|
|
sb_geo(n, off, room, most)
|
|
let span = n.ch - sb_th
|
|
if span <= 0.0 { return off }
|
|
return (i.y - sc_grab - n.y) / span * most
|
|
}
|
|
# the track, then the thumb over it; scrollbar-color on the box wins over the parts' backgrounds
|
|
function sc_bar(n: UiNode) -> void {
|
|
let room = n.ch - ly_vin(n)
|
|
let most = n.content_h - ly_vin(n) - room
|
|
if most <= 0.0 or ui_be.rect == null { return }
|
|
sb_geo(n, n.scroll_y, room, most)
|
|
let bar = sb_bar
|
|
if bar.hidden { return }
|
|
var track = bar.bg
|
|
if n.bar_track != -2 { track = n.bar_track }
|
|
if track >= 0 { fr_box(sb_x, n.y, sb_w, n.ch, bar.radius, track, bar.bg_a * fr_ga) }
|
|
if len(bar.children) == 0 { return }
|
|
let t = bar.children[0]
|
|
var thumb = t.bg
|
|
if n.bar_c >= 0 { thumb = n.bar_c }
|
|
if thumb >= 0 { fr_box(sb_x, sb_ty, sb_w, sb_th, t.radius, thumb, t.bg_a * fr_ga) }
|
|
}
|