xurfer/src/lovr/lib/iui/widgets/split-view.lua
2026-06-06 12:35:31 +02:00

167 lines
4.3 KiB
Lua

local currentPath = (...):match('(.-)[^%./]+$')
local parentPath = currentPath:match('(.-)[^%./]+%.$')
--- @class IUILib
local iui = require(parentPath .. "iui")
--- @alias IUISplitViewDirection "horiz" | "vert"
--- @alias IUISplitViewSide "min" | "max"
--- @class (exact) IUISplitStackItem
--- @field direction IUISplitViewDirection
--- @field current number
--- @field x number
--- @field y number
--- @field w number
--- @field h number
--- @type IUISplitStackItem[]
local splitStack = {}
--- @param name string
--- @param direction IUISplitViewDirection
--- @param current number
--- @return number
function iui.splitView(name, direction, current)
local id = iui.beginID(name, false)
local state = iui.state(id)
local x, y, w, h = iui.layout.getPanelBounds()
local mx = iui.input.mouse.x
local my = iui.input.mouse.y
local spacing = iui.style["spacing"]
local splitMinEdge = iui.style["splitMinEdge"] or 8
local splitMaxEdge = iui.style["splitMaxEdge"] or 8
local splitSide = iui.style["splitSide"] or "min" --- @type IUISplitViewSide
if splitSide == "max" then
current = w - current
end
local handleWidth = math.ceil(spacing * 0.75)
local handleMin = current - handleWidth
local handleMax = current + handleWidth + 1
if direction == "horiz" then
if mx >= x + handleMin and mx <= x + handleMax then
if my >= y and my < y + h then
iui.becomeHover()
end
end
if iui.hoverID == id then
if iui.input.mouse.pressed:has(1) then
iui.becomeActive()
state.offset = (mx - x) - current
end
end
if iui.activeID == id then
current = (mx - x) - state.offset
if not iui.input.mouse.down:has(1) then
iui.activeID = nil
end
end
if iui.hoverID == id or iui.activeID == id then
iui.cursor = "sizewe"
end
elseif direction == "vert" then
if my >= y + handleMin and my <= y + handleMax then
if mx >= x and mx < x + w then
iui.becomeHover()
end
end
if iui.hoverID == id then
if iui.input.mouse.pressed:has(1) then
iui.becomeActive()
state.offset = (mx - x) - current
end
end
if iui.activeID == id then
current = (my - y) - state.offset
if not iui.input.mouse.down:has(1) then
iui.activeID = nil
end
end
if iui.hoverID == id or iui.activeID == id then
iui.cursor = "sizens"
end
end
current = iui.utils.round(current)
if current < splitMinEdge then
current = splitMinEdge
end
if direction == "horiz" then
if current > w - (splitMaxEdge + 1) then
current = w - (splitMaxEdge + 1)
end
elseif direction == "vert" then
if current > h - (splitMaxEdge + 1) then
current = h - (splitMaxEdge + 1)
end
end
iui.panelBackground()
local pos = current
iui.colors.sysGray0:set()
if direction == "horiz" then
iui.graphics.rectangle(x + pos, y, 1, h)
elseif direction == "vert" then
iui.graphics.rectangle(x, y + pos, w, 1)
end
if direction == "horiz" then
iui.layout.beginPanel(x, y, current, h)
elseif direction == "vert" then
iui.layout.beginPanel(x, y, w, current)
end
--- @type IUISplitStackItem
local item = iui.pool.get("split_view_stack_item")
item.direction = direction
item.current = current
item.x, item.y, item.w, item.h = x, y, w, h
table.insert(splitStack, item)
if splitSide == "max" then
current = w - current
end
return current
end
function iui.splitViewDivider()
--- @type IUISplitStackItem
local item = table.remove(splitStack)
local direction = item.direction
local x, y, w, h = item.x, item.y, item.w, item.h
local current = item.current
iui.layout.endPanel()
if direction == "horiz" then
iui.layout.beginPanel(x + current + 1, y, w - (current + 1), h)
elseif direction == "vert" then
iui.layout.beginPanel(x, y + current + 1, w, h - (current + 1))
end
iui.pool.put(item)
end
function iui.endSplitView()
iui.layout.endPanel()
iui.endID()
end