
if not is_client then
    return
end

function scroll_by(node, diff)
    local thumb = node:query():name("scroll_thumb"):matches()(nil, nil)
    local old_offset = thumb:get_property_float("offset") or 0.0
    local _, pos, _, bar_height = node:render_position()


    local content = node:query()
        :name('scroll_panel'):child()
        :name('content'):matches()(nil, nil)
    local _, _, _, limit = content:raw_position()

    local height = limit - bar_height
    if height <= 0 then
        return
    end

    warp_to(node, {
        y = (old_offset * (bar_height - 16)) + 8 + pos + diff * (30/height) * bar_height,
    })
end

function warp_to(node, evt)
    local content = node:query()
        :name('scroll_panel'):child()
        :name('content'):matches()(nil, nil)

    local _, _, _, limit = content:raw_position()
    local thumb = node:query():name("scroll_thumb"):matches()(nil, nil)
    local _, pos, _, bar_height = node:render_position()

    local height = limit - bar_height
    if height < 0 then
        height = 0
    end

    local offset = (evt.y - 8 - pos) / (bar_height - 16)
    if offset > 1 then
        offset = 1
    end
    if offset < 0 or height == 0 then
        offset = 0
    end
    thumb:set_property_float("offset", offset)
    content:set_property_int('scroll_y', -height * offset)
end

function start_scroll(node, evt)
    warp_to(node, evt)
    local catcher = ui.new("scroll_catcher")
    catcher:set_property_table("$scroll", {
        scroll = node,
    })
    ui.add_node(catcher)
end

function close_scroll()
    local dc = ui.query():name("scroll_catcher"):matches()(nil, nil)
    if dc == nil then
        return
    end
    ui.remove_node(dc)
end