poppy-client/lua/layout.lua

420 lines
12 KiB
Lua

local layout = {}
layout.uiState = {}
layout.uiState.Menu = {}
layout.uiState.GameUI = {}
layout.uiState.MainMenu = {}
local fonts = require("shared.fonts")
local utils = require("shared.utils")
local asserts = require("shared.asserts")
local catalog = require("shared.catalog")
function layout.debugPrint(string)
--print(string)
end
function layout.canvasAndColor(container, x, y, simulate)
asserts.number("layout.canvasAndColor", 2, x, y)
if simulate then return layout.handle(container[1], x, y, simulate) end
utils.color_push()
love.graphics.setCanvas(container.canvas)
x, y = layout.handle(container[1], x, y, simulate)
love.graphics.setCanvas()
utils.color_pop()
return x, y
end
function layout.rotate(container, x, y, simulate)
asserts.number("layout.rotate", 2, x, y)
asserts.number("layout.rotate (container)", container.rotation)
local transform = love.math.newTransform(0, 0, container.rotation)
local noTransform = love.math.newTransform(0, 0, 0)
love.graphics.replaceTransform(transform)
local x, y = layout.handle(container[1], x, y, simulate)
love.graphics.replaceTransform(noTransform)
return x, y
end
function layout.frame(container, x, y, simulate)
asserts.number("layout.frame", 2, x, y)
x2, y2 = layout.handle(container[1], x +1, y +1, simulate)
if not simulate then
love.graphics.rectangle("line", x, y, x2 -x, y2 -y)
end
return x2+1, y2+1
end
function layout.cursorSelect(container, x, y, simulate)
x2, y2 = layout.handle(container[1], x, y, simulate)
assert(container.uiSelect)
if not simulate then
table.insert(layout.uiState[container.uiSelect], { identifier = container.identifier, kind=container.kind,
x=x, x2=x2, y=y, y2=y2 })
end
return x2, y2
end
function layout.spacer(container, x, y, simulate)
assert(container.width or container.height, "No arguments for layout.spacer!")
assert(container.width == container.width,
"Argument container.width to layout.spacer must not be NaN!")
assert(container.height == container.height,
"Argument container.height to layout.spacer must not be NaN!")
local width = container.width or 0
local height = container.height or 0
if container[1] then
return layout.handle(container[1], x + width, y + height, simulate)
else
return x + width, y + height
end
end
function layout.drawTexture(container, x, y, simulate)
local texture = container.texture
local scale = container.scale or 1
if not simulate then
love.graphics.draw(texture, x, y, 0, scale, scale)
end
return x + (texture:getWidth() * scale), y + texture:getHeight() * scale
end
function layout.drawHash(container, x, y, simulate)
local texture = levelloop.textures[container.hash]
local scale = container.scale or 1
if not texture.image then
texture.image = love.graphics.newImage(texture.data)
end
if not simulate then
love.graphics.draw(texture.image, x, y, 0, scale, scale)
end
return x + texture.image:getWidth() * scale, y + texture.image:getHeight() * scale
end
function layout.bwColorPicker(container, x, y, simulate)
asserts.number("layout.bwColorPicker", 2, x, y)
local startx, starty = x, y
granularity = container.granularity or 0.04
local points = {}
local myx = x
local endx = 0
local pointSize = container.pointSize or 8
if not simulate then
utils.color_push()
love.graphics.setPointSize(pointSize)
for c=0, 1.0, granularity do
love.graphics.setColor(c, c, c, 1)
love.graphics.points(myx+(pointSize/2), y +(pointSize/2))
myx = myx + pointSize
end
utils.color_pop()
local iterationCount = (1.0 / granularity)
maxx = x + pointSize * iterationCount
table.insert(layout.uiState.GameUI, { granularity = granularity, pointSize = pointSize,
kind=container.kind,
x=x, x2=maxx, y=y, y2=y + pointSize })
else
local iterationCount = (1.0 / granularity)
maxx = x + pointSize * iterationCount
maxy = y + pointSize
return maxx, maxy
end
return maxx, y + pointSize
end
function layout.colorPicker(container, x, y, simulate)
asserts.number("layout.colorPicker", 2, x, y)
local startx, starty = x, y
granularity = container.granularity or 0.2
local points = {}
local myx, myy = x, y
local endx = 0
local pointSize = container.pointSize or 8
if not simulate then
utils.color_push()
love.graphics.setPointSize(pointSize)
for r=0, 1.0, granularity do
for g=0, 1.0, granularity do
for b=0, 1.0, granularity do
love.graphics.setColor(r, g, b, 1)
myx=myx+pointSize
love.graphics.points(myx-(pointSize/2) -.5, myy +(pointSize/2))
end
end
myy = myy + pointSize
if myx > endx then endx = myx end
myx = x
end
utils.color_pop()
local iterationCount = (1.0 / granularity) + 1
maxx = x + pointSize * iterationCount * iterationCount
table.insert(layout.uiState.GameUI, { granularity = granularity, pointSize = pointSize,
kind=container.kind,
x=x, x2=maxx, y=y, y2=myy })
else
local iterationCount = (1.0 / granularity) + 1
maxx = x + pointSize * iterationCount * iterationCount
maxy = y + pointSize * iterationCount
return maxx, maxy
end
return maxx, myy
end
function layout.color(container, x, y, simulate)
if simulate then return layout.handle(container[1], x, y, simulate) end
assert(container.color, "layout.color Color!")
assert(#container.color == 3 or #container.color == 4)
utils.color_push()
love.graphics.setColor(container.color)
x, y = layout.handle(container[1], x, y, simulate)
utils.color_pop()
return x, y
end
function layout.rect(container, x, y, simulate)
asserts.number("layout.rect", 2, x, y)
asserts.number("layout.rect (container)", 2, container.width, container.height)
if simulate then return x + container.width, y + container.height end
if container.color then
utils.color_push()
love.graphics.setColor(container.color.r, container.color.g, container.color.b, container.color.a or 1)
love.graphics.rectangle(container.fill or "fill", x, y, container.width, container.height)
utils.color_pop()
else
love.graphics.rectangle(container.fill or "fill", x, y, container.width, container.height)
end
return x + container.width, y + container.height
end
function layout.button(container, x, y, simulate)
local textObject = love.graphics.newText(fonts.headerFont, container.text)
local uiSelect = layout.uiState[container.uiSelect] or error("layout.button passed invalid uiSelect!" .. container.uiSelect or "no value!")
assert(container.identifier, "layout.button no identifier passed!")
local buttonColor = catalog.buttonColors[container.buttonColor or "blue"]
local width = textObject:getWidth()
local height = textObject:getHeight()
local factor = 1.15
if not simulate then
utils.color_push()
love.graphics.setColor(buttonColor[1])
love.graphics.rectangle("fill", x, y, width* factor, height* factor,
height* factor/4, height* factor/4)
love.graphics.setColor(buttonColor[2])
love.graphics.rectangle("line", x, y, width* factor, height* factor,
height* factor/4, height* factor/4)
love.graphics.setColor(buttonColor[3])
love.graphics.draw(textObject, x + width * 0.075 , y + height * 0.075)
utils.color_pop()
end
table.insert(uiSelect, { identifier = container.identifier, kind="button",
x=x, x2=x+(width *factor), y=y, y2=y + (height * factor) })
return x+ (width *factor), y + (height * factor)
end
function layout.overlayRect(container, x, y, simulate)
asserts.number("layout.overlayRect", 2, x, y)
winx, winy = layout.handle(container[1], x, y, simulate)
width = winx -x
height = winy -y
if not simulate then
love.graphics.rectangle(container.fill or "fill", x, y, width, height)
end
return x + width, y + height
end
function layout.labelWShadow(container, x, y, simulate)
-- TODO: Replace this with a text shadow shader FFS
if not container.font then container.font = fonts.normalFont end
local text = love.graphics.newText( container.font, container.text )
if not text then text = love.graphics.newText( container.font, "Unset text!!") end
if not simulate then
utils.color_push()
love.graphics.setColor(0,0,0)
love.graphics.draw(text, x, y +4)
love.graphics.draw(text, x, y +2)
love.graphics.draw(text, x, y +0)
love.graphics.draw(text, x +2, y +2)
love.graphics.draw(text, x +2, y +0)
love.graphics.draw(text, x +4, y +4)
love.graphics.draw(text, x +4, y +2)
love.graphics.draw(text, x +4, y +0)
utils.color_pop()
love.graphics.draw(text, x +2, y +2)
end
return x + text:getWidth() + 2, y + text:getHeight() +2
end
function layout.label(container, x, y, simulate)
if not container.font then container.font = fonts.normalFont end
local text = love.graphics.newText( container.font, container.text )
if not text then text = love.graphics.newText( container.font, "Unset text!!") end
if not simulate then
love.graphics.draw(text, x, y)
end
return x + text:getWidth(), y + text:getHeight()
end
function layout.layer(container, x, y, simulate)
local ret1 = {}
local ret2 = {}
ret1.x, ret1.y = layout.handle(container[1], x, y, simulate)
ret2.x, ret2.y = layout.handle(container[2], x, y, simulate)
return math.max(ret1.x,ret2.x), math.max(ret1.y, ret2.y)
end
function layout.horizontal(container, x, y, simulate)
local bigy = y
if not simulate then
assert(container[1], "horizontal called without arguments!")
else
if not container[1] then return x, y end
end
for i, v in ipairs(container) do
local ret = {}
ret.x, ret.y = layout.handle(v,x,y, simulate)
if ret.y > bigy then bigy = ret.y end
x = ret.x
end
return x, bigy
end
function layout.naiveGrid(container, startX, startY, simulate)
-- This is naiveGrid and not grid because the splitting alghorythm splits
-- *after* the threshold is reached, thus individual lines can be quite a bit longer
-- depending on the passed content.
-- todo: rewrite this with a (possibly) more expensive grid function that
-- simulates everything before doing it
local maxX, maxY = startX, startY
local workX, workY = startX, startY -- The current "pointer" for where to draw
local retX, retY = startX, startY -- the values returned by the newly drawn shape
local width = container.width
if not simulate then
assert(container[1], "naiveGrid called without arguments!")
else
if not container[1] then return startX, startY end
end
for i, v in ipairs(container) do
retX, retY = layout.handle(v, workX, workY, simulate)
if retY > maxY then maxY = retY end
if retX > startX + width then
workY = maxY
workX = startX
if retX > maxX then maxX = retX end
else
workX = retX
end
end
return maxX, maxY
end
function layout.copySize(container, x, y, simulate)
local bigx, bigy = layout.handle(container[2], x, y, true)
container[1].width = bigx -x
container[1].height = bigy -y
assert(container[1])
assert(container[2])
layout.handle(container[1], x, y, simulate)
layout.handle(container[2], x, y, simulate)
return bigx, bigy
end
function layout.vertical(container, x, y, simulate)
local bigx = x
if not simulate then
assert(container[1], "vertical called without arguments!")
else
if not container[1] then return x, y end
end
for i, v in ipairs(container) do
local ret = {}
ret.x, ret.y = layout.handle(v,x,y, simulate)
if ret.x > bigx then bigx = ret.x end
y = ret.y
end
return bigx,y
end
function layout.skip(container, x, y, simulate)
return x, y
end
local depth = -1
function layout.handle(container, x, y, simulate)
asserts.number("layout.handle", 2, x, y)
assert(container, "layout.handle called without container")
local name = container["name"]
if not name then return end
assert(name, "layout.handle container without name")
assert(layout[name], "Unknown layout function " .. name .. " called")
depth = depth +1
local depthCursor = ""
for i=0, depth do
depthCursor = depthCursor .. ".."
end
if depth == 0 then
if simulate then
layout.debugPrint("Starting simulation")
else
layout.debugPrint("Starting rendering")
end
end
layout.debugPrint(depthCursor.. ">" .. container.name)
x, y = layout[name](container, x, y, simulate)
asserts.number("layout.handle" .. container.name .. " is not returning properly!", 2, x, y)
layout.debugPrint(depthCursor.."<" .. container.name)
depth = depth -1
if depth == -1 then
if simulate then
layout.debugPrint("simulation ended\n")
else
layout.debugPrint("rendering ended\n")
end
end
return x, y
end
return layout