64 lines
2.7 KiB
Lua
64 lines
2.7 KiB
Lua
|
|
-- A dead-simple layout helper for the editor sidebar. Everything works in the
|
||
|
|
-- sidebar's local coordinate space (0,0 = top-left of sideBarCanvas) — the same
|
||
|
|
-- space editorDraw / editorMouseHandler already use — so section rects double as
|
||
|
|
-- love.graphics.setScissor rects and as hit boxes. No dependencies, no state of
|
||
|
|
-- its own beyond the scroll table the caller hands in.
|
||
|
|
|
||
|
|
Layout = {}
|
||
|
|
|
||
|
|
-- point-in-rect
|
||
|
|
function Layout.hit(r, x, y)
|
||
|
|
return x >= r.x and x < r.x + r.w and y >= r.y and y < r.y + r.h
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Clip drawing to a section. setScissor ignores the active graphics transform,
|
||
|
|
-- so multiply the virtual-space rect by editorRenderScale to hit real canvas
|
||
|
|
-- pixels. Clamp to non-negative: a too-narrow/short sidebar (e.g. a square
|
||
|
|
-- window with no room for it) would otherwise hand setScissor a negative size.
|
||
|
|
function Layout.clip(r)
|
||
|
|
local s = editorRenderScale or 1
|
||
|
|
love.graphics.setScissor(r.x * s, r.y * s, math.max(0, r.w * s), math.max(0, r.h * s))
|
||
|
|
end
|
||
|
|
function Layout.unclip() love.graphics.setScissor() end
|
||
|
|
|
||
|
|
-- A vertical scrolling list confined to rect `r`. `state` is any table the
|
||
|
|
-- caller keeps between frames to hold `state.scroll`; it is clamped here.
|
||
|
|
-- Returns helpers to place / cull / hit-test `count` items of height `itemH`.
|
||
|
|
function Layout.list(state, r, itemH, count, gap)
|
||
|
|
gap = gap or 6
|
||
|
|
local step = itemH + gap
|
||
|
|
local content = count * step
|
||
|
|
local maxScroll = math.max(0, content - r.h)
|
||
|
|
state.scroll = math.max(0, math.min(state.scroll or 0, maxScroll))
|
||
|
|
local scroll = state.scroll
|
||
|
|
return {
|
||
|
|
rect = r, itemH = itemH, step = step, count = count, maxScroll = maxScroll, scroll = scroll,
|
||
|
|
-- top-left corner of item i (1-based), in sidebar space
|
||
|
|
pos = function(i) return r.x, r.y + (i - 1) * step - scroll end,
|
||
|
|
-- is item i at all inside the visible window? (cheap cull)
|
||
|
|
visible = function(i)
|
||
|
|
local y = r.y + (i - 1) * step - scroll
|
||
|
|
return y + itemH > r.y and y < r.y + r.h
|
||
|
|
end,
|
||
|
|
-- index at a sidebar-space point, or nil if outside the list / no item
|
||
|
|
at = function(x, y)
|
||
|
|
if not Layout.hit(r, x, y) then return nil end
|
||
|
|
local i = math.floor((y - r.y + scroll) / step) + 1
|
||
|
|
if i >= 1 and i <= count then return i end
|
||
|
|
return nil
|
||
|
|
end,
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Thin scrollbar thumb on the right edge of a list, drawn only when it scrolls.
|
||
|
|
function Layout.scrollbar(list)
|
||
|
|
if list.maxScroll <= 0 then return end
|
||
|
|
local r = list.rect
|
||
|
|
local thumb = math.max(16, r.h * (r.h / (r.h + list.maxScroll)))
|
||
|
|
local ty = r.y + (r.h - thumb) * (list.scroll / list.maxScroll)
|
||
|
|
local pr, pg, pb, pa = love.graphics.getColor()
|
||
|
|
love.graphics.setColor(255, 255, 255, 90)
|
||
|
|
love.graphics.rectangle("fill", r.x + r.w - 4, ty, 3, thumb)
|
||
|
|
love.graphics.setColor(pr, pg, pb, pa)
|
||
|
|
end
|