Rebuild level editor sidebar with a fixed virtual-space layout
Replace the fraction-of-window positioning (which overlapped and didn't scale) with a small layout system: the sidebar is authored in one fixed virtual coordinate space and rendered at native panel resolution, so element sizes stay constant relative to the panel at any window size and fonts scale with it. - level_editor/layout.lua: sections, scrolling list (with clip + hit-test by point), scrollbar. Clip rects are scaled to real canvas pixels. - Room view split into non-overlapping divs: search/back header, a scrollable asset list (replaces the old row-paging + forward buttons), a status strip, and a compact bottom control cluster. - Mouse wheel scrolls the list; clicks map from window coords into the virtual space via the same transform used to render. - Sidebar canvas is panel-sized and blitted 1:1 (nearest filter, never averaged) to stay crisp; editorDraw runs under a scale transform. - Center text-only fields (level name) in their rect. Also carried in main.lua (share the file, can't split cleanly here): narrator require path fixed via love.filesystem.setRequirePath; sfxr static uses waveform=NOISE again after the field rename; low-pass + lower volume on the static loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
03532d29e4
commit
5b7ea9ec20
4 changed files with 336 additions and 144 deletions
63
level_editor/layout.lua
Normal file
63
level_editor/layout.lua
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
-- 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue