Love Loader v2.0

This commit is contained in:
Er2 2022-05-30 10:33:56 +03:00
parent 9513a5c471
commit f562b23197
16 changed files with 933 additions and 207 deletions

190
skins/base.lua Normal file
View file

@ -0,0 +1,190 @@
return function(ll)
-- Basic cmd-like style UI
-- FIXME: Console scrolling
local cw, ch, ctw, cth
local ct = 'Love Loader v2.0\n(c) Er2 2022\tZlib License\n\n'
local cce = false
local buf = ''
local mb, mpb, mt = 0, 0, 0
local function ccp()
local argv = {}
for v in buf:gmatch '%S+'
do table.insert(argv, v)
end
local cmd = (argv[1] or ''):lower()
if cmd == '' then return '' -- nothing
elseif cmd == 'help' then return 'Available commands:'
.. '\nhelp\t\tThis command'
.. '\nls\t\tList of games'
.. '\ndir\t\tSame as ls'
.. '\ncat\t<path>\tInformation about game'
.. '\ninfo\t<path>\tSame as cat'
.. '\nrun\t<path>\tStart game'
.. '\nmount\t<path>\tSame as run'
.. '\nchroot\t<path>\tSame as run'
.. '\nclear\t\tClear screen'
.. '\neval\t<code>\tExecute code'
elseif cmd == 'clear' then
ct = ''
return ''
elseif cmd == 'eval' then
local code = buf:match '^%S+%s+(.*)'
local f, err = load(code, 'test.lua')
if not f then return err
else return tostring(f() or 'nil')
end
elseif cmd == 'ls'
or cmd == 'dir' then
local r = ''
if #ll.games == 0 then
return ('%s: No games found. Add some to the library.'):format(argv[1])
end
for i = 1, #ll.games do
local v = ll.games[i]
r = r .. ('%s\t(%s)\t - %s\n'):format(v.dir, v.name, v.desc)
end
return r .. ('\nTotal: %3d games\n'):format(#ll.games)
elseif cmd == 'cat'
or cmd == 'info' then
if not argv[2]
then return ('%s: Game directory missing'):format(argv[1])
end
local r = ''
for _, v in pairs(ll.games) do
if argv[2] == v.dir
or argv[2] == v.base .. v.dir
then r = r..
( '\nFriendly name:\t%s'
..'\nDescription:\t%s'
..'\nLocation:\t%s%s'
..'\nMain file:\t%s'
..'\n\n\t\tScreenshots are not supported yet.'
..'\n'):format(v.name, v.desc, v.base, v.dir, v.main)
end
end
if r == '' then r = 'Not found' end
return r
elseif cmd == 'run'
or cmd == 'mount'
or cmd == 'chroot' then
local gme
for _, v in pairs(ll.games) do
if argv[2] == v.dir
or argv[2] == v.base .. v.dir
then if gme then
return 'Error: multiple paths found, use full location'
end
gme = v end
end
if gme
then ll.mount(gme)
love.keyboard.setTextInput(false)
return ''
else return 'Not found'
end
else return 'Unknown command "'.. cmd .. '"'
end
end
local function update()
mpb = mb
if love.mouse.isDown(1) then mb = 1
if mpb ~= 1
then mt = os.time()
end
else mb = 0
end
if mb == 0 and mpb == 1
and os.time() - mt <= 1 then
if love.system.getOS() == 'Android' then
love.keyboard.setTextInput(
not love.keyboard.hasTextInput(),
0, H, W, ch)
end
end
if not cce then
cce = true
local r = ccp()
if #r ~= 0 then ct = ct.. '\n'.. r end
ct = ct.. '\n> '
buf = ''
end
end
local utf8 = require 'utf8'
local function draw()
love.graphics.setColor(255, 255, 255)
local x, y = 0, 0
for p, cde in utf8.codes(ct) do
local chr = utf8.char(cde)
if chr == '\n'
then x, y = 0, y + 1
elseif chr == '\r'
then x = 0
elseif chr == '\t'
then x = x + 8 - (x % 8)
elseif chr == '\v'
then y = y + 1
else love.graphics.print(chr, x * cw, y * ch)
if x >= ctw
then x, y = x - ctw, y + 1
else x = x + 1
end
end
end
if os.time() % 2 == 0
then love.graphics.rectangle('fill', x * cw, y * ch, cw, ch)
end
end
function resize()
local f = love.graphics.newFont(math.min(W, H) / 32)
love.graphics.setFont(f)
cw, ch = f:getWidth 'm', f:getHeight 'A'
ctw, cth =
math.floor(W / cw) - 1,
math.floor(H / ch) - 1
love.keyboard.setTextInput(true, 0, H, W, ch)
end
function love.textinput(txt)
ct = ct.. txt
buf = buf.. txt
end
function love.keypressed(k)
if k == 'backspace' then
local off = utf8.offset(buf, -1)
if off then
buf = buf:sub(1, off - 1)
off = utf8.offset(ct, -1)
if off
then ct = ct:sub(1, off - 1)
end
end
elseif k == 'return'
then cce = false
end
end
love.keyboard.setKeyRepeat(true)
love.window.setMode(800, 600, {resizable = true})
return {
update = update,
draw = draw,
lovecb = {
'textinput',
'keypressed',
},
}
end

220
skins/gui.lua Normal file
View file

@ -0,0 +1,220 @@
return function(ll)
-- Classic UI from Love Loader v1
ll.cfg.pcht = ll.cfg.pcht or 60 * 5
local pikchv, pikcha = 0, 0
local pikchao = math.floor(1 / ll.cfg.pcht * 2 * 255 + 0.5)
local cx, cy, cw, ch
local f, bf
local mx, mb, mpb = 0, 0, 0
local cdir, sel = 0, 1
function resize()
cw = W / 1.25
ch = H / 1.25
cx = (W - cw) / 2
cy = (H - ch) / 2
local th = math.min(W, H) / 8
f = love.graphics.newFont(th / 3)
bf = love.graphics.newFont(th / 2)
end
local function update()
mx = love.mouse.getX()
mpb = mb
if love.mouse.isDown(1) then mb = 1
else mb = 0 end
local sdi = 0
if mpb == 1 and mb == 0 then
if mx <= cx
then sdi = 1
elseif mx >= cx + cw
then sdi = 2
else sdi = 3
end
end
if love.keyboard.isScancodeDown('left', 'a')
then sdi = 1
elseif love.keyboard.isScancodeDown('right', 'd')
then sdi = 2
elseif love.keyboard.isScancodeDown('return', 'space')
then sdi = 3
end
if cdir ~= sdi then
cdir = sdi
if sdi == 1
then sel = sel - 1
elseif sdi == 2
then sel = sel + 1
elseif sdi == 3 and ll.games[sel]
then ll.mount(ll.games[sel])
end
if sel < 1 then sel = #ll.games end
if sel > #ll.games then sel = 1 end
end
pikchv = pikchv + 1
if pikchv >= ll.cfg.pcht then
pikchv = 0
pikcha = 0
for _, v in pairs(ll.games) do
if v.dat.scr then
v.scrprv = v.scrcur
v.scrcur = v.scrcur + 1
if v.scrcur > #v.dat.scr
then v.scrcur = 1
end
end
end
else pikcha = math.min(255, pikcha + pikchao)
end
if love.keyboard.isDown 'menu'
and mx >= W - 8
then pcall(select(2, pcall(require, 'dev.devtools')), ll)
end
end
local tm = 0
local function draw()
love.graphics.setColor(0 / COLDIV, 50 / COLDIV, 75 / COLDIV)
love.graphics.rectangle('fill', 0, 0, W, H)
love.graphics.setColor(255, 255, 255, 100 / COLDIV)
love.graphics.setLineWidth(8)
love.graphics.setFont(bf)
local t = 'Love Loader'
local tw, th = bf:getWidth(t), bf:getHeight(t)
love.graphics.print(t, W - tw - 8, H - th)
tm = (tm + 0.02) % 6.28
local c, pc, ps = tm, math.cos(tm), math.sin(tm)
local oy = H / 2
for x = 0, W + 8, 8 do
c = c + 0.1
local c, s = math.cos(c), math.sin(c)
local cy, ncy, sy, nsy =
pc * H / 12,
c * H / 12,
ps * H / 12,
s * H / 12
love.graphics.line(x - 8, sy + oy, x-1, nsy + oy)
love.graphics.line(x - 8, sy/2 + oy, x-1, nsy/2 + oy)
love.graphics.line(x - 8, cy/1.5 + oy, x-1, ncy/1.5 + oy)
love.graphics.line(x - 8, cy*1.5 + oy, x-1, ncy*1.5 + oy)
pc, ps = c, s
end
love.graphics.setColor(255, 255, 255, 255)
love.graphics.setLineWidth(1)
local oy, t = 0, ''
local gme = ll.games[sel]
if gme then
love.graphics.polygon('fill',
8, H / 2,
32, H / 2 - 32,
32, H / 2 + 32)
love.graphics.polygon('fill',
W - 8, H / 2,
W - 32, H / 2 - 32,
W - 32, H / 2 + 32)
love.graphics.stencil(function()
love.graphics.rectangle('fill', cx, cy, cw, ch, 16)
end)
love.graphics.setStencilTest('greater', 0)
love.graphics.setColor(50 / COLDIV, 50 / COLDIV, 50 / COLDIV, 100 / COLDIV)
love.graphics.rectangle('fill', cx, cy, cw, ch)
love.graphics.setColor(255, 255, 255, 255)
if gme.dat.scr then
local p, n = gme.dat.scr[gme.scrprv], gme.dat.scr[gme.scrcur]
love.graphics.draw(p, cx, cy, 0, cw / p:getWidth(), ch / p:getHeight())
love.graphics.setColor(255, 255, 255, pikcha / COLDIV)
love.graphics.draw(n, cx, cy, 0, cw / n:getWidth(), ch / n:getHeight())
love.graphics.setColor(0, 0, 0, 150 / COLDIV)
love.graphics.rectangle('fill', cx, cy, cw, ch)
love.graphics.setColor(255, 255, 255, 255)
end
oy = cy + ch / 1.25
love.graphics.setFont(bf)
love.graphics.print(gme.name, cx + 16, oy)
oy = oy + bf:getHeight(gme.name)
love.graphics.setFont(f)
love.graphics.print(gme.desc, cx + 16, oy)
love.graphics.setStencilTest()
love.graphics.rectangle('line', cx, cy, cw, ch, 16)
elseif ll.games[1] then
sel = 1
love.graphics.setColor(255, 255, 255, 255)
love.graphics.print('Sorry :)', W / 2, H / 2)
else love.graphics.setColor(255, 255, 255, 255)
oy = H / 2.5
t = 'No games'
love.graphics.setFont(bf)
love.graphics.print(t, (W - bf:getWidth(t)) / 2, oy)
oy = oy + bf:getHeight(t)
love.graphics.setFont(f)
t = 'There are no projects/games to run'
love.graphics.print(t, (W - f:getWidth(t)) / 2, oy)
end
end
function error(msg)
msg = tostring(msg)
love.graphics.reset()
love.graphics.origin()
local bf = love.graphics.newFont(64)
local f = love.graphics.setNewFont(16)
local perc = 0
local q
repeat
perc = math.min(100, perc + 0.1 * math.random(50))
love.graphics.clear(17/COLDIV, 113/COLDIV, 172/COLDIV)
love.graphics.setColor(255, 255, 255)
love.graphics.setFont(bf)
love.graphics.print(':(', 64, 16)
love.graphics.setFont(f)
love.graphics.print(('%d%% complete'):format(perc), 64, 100)
love.graphics.printf(msg, 64, 132, W - 64)
love.graphics.print('(c) Love Loader and Er2', 8, H - 16 - 8)
love.graphics.present()
love.event.pump()
for n, a,b,c in love.event.poll() do
if n == 'quit'
or n == 'mousereleased'
or (n == 'keypressed' and a == 'escape')
then q = true end
end
love.timer.sleep(0.5)
until q or perc == 100
-- Unfortunately, we can't restart Love in error handler
llHome() -- but can outside of love.errorhandler
return function() return 1 end
end
return {
update = update,
draw = draw,
}
end

175
skins/psp.lua Normal file
View file

@ -0,0 +1,175 @@
return function(ll)
-- New UI from Sony PSP
local sel = 1
local psel
local cx, cy, cw, ch, cg
local css, rcss = 2, 0
local f, bf
ll.cfg.pcht = ll.cfg.pcht or 60 * 5
local pikchv, pikcha = 0, 0
local pikchao = math.floor(1 / ll.cfg.pcht * 2 * 255 + 0.5)
function resize()
r = math.min(W, H) / 30
cg = H / 64
cw = W / 5
ch = (H - cg) / 6
cx = W / 10
cy = -H / 2
f = love.graphics.setNewFont(math.min(W, H) / 30)
bf = love.graphics.newFont(math.min(W, H) / 20)
end
love.window.setMode(800, 600, {resizable = true})
local my, mb, mpb
local sdir = 0
local function update()
local ty = H / 2 - (ch + cg) * sel
cy = cy + (ty - cy) * 0.1
css = css + (2 - css) * 0.2
rcss = 2 - css + 1
local sdi
my = love.mouse.getY()
mpb = mb
if love.mouse.isDown(1) then mb = 1
else mb = 0
end
if mb == 0 and mpb == 1 then
if my <= H / 2 - ch
then sdi = 1
elseif my >= H / 2 + ch + cg
then sdi = 2
else sdi = 3
end
elseif love.keyboard.isScancodeDown('up', 'w')
then sdi = 1
elseif love.keyboard.isScancodeDown('down', 's')
then sdi = 2
elseif love.keyboard.isScancodeDown('return', 'space')
then sdi = 3
else sdi = 0
end
if sdi ~= sdir then
if sdi ~= 0
then rcss = css
css = 1
if sdi == 3
then css = 1.5
end
psel = sel
end
sdir = sdi
if sdi == 1
then sel = sel - 1
elseif sdi == 2
then sel = sel + 1
elseif sdi == 3 and ll.games[sel]
then ll.mount(ll.games[sel])
end
if sel < 1 then sel = #ll.games end
if sel > #ll.games then sel = 1 end
end
pikchv = pikchv + 1
if pikchv >= ll.cfg.pcht then
pikchv = 0
pikcha = 0
for _, v in pairs(ll.games) do
if v.dat.scr then
v.scrprv = v.scrcur
v.scrcur = v.scrcur + 1
if v.scrcur > #v.dat.scr
then v.scrcur = 1
end
end
end
else pikcha = math.min(255, pikcha + pikchao)
end
end
local function scrCard(gme, x, y, w, h, a)
if not gme.dat.scr then return end
love.graphics.setColor(255, 255, 255, a / COLDIV)
local p, n = gme.dat.scr[gme.scrprv], gme.dat.scr[gme.scrcur]
love.graphics.draw(p, x, y, 0, w / p:getWidth(), h / p:getHeight())
love.graphics.setColor(255, 255, 255, math.min(a, pikcha) / COLDIV)
love.graphics.draw(n, x, y, 0, w / n:getWidth(), h / n:getHeight())
love.graphics.setColor(0, 0, 0, 150 / COLDIV)
love.graphics.rectangle('fill', x, y, w, h)
end
local function draw()
love.graphics.setColor(0 / COLDIV, 50 / COLDIV, 75 / COLDIV)
love.graphics.rectangle('fill', 0, 0, W, H)
if ll.games[sel] then
local cur = ll.games[sel]
scrCard(cur, 0, 0, W, H, (css - 1) * 255)
love.graphics.setColor(255, 255, 255, 255)
love.graphics.setFont(bf)
love.graphics.printf(cur.desc, cx + cw * 2, cx, W - (cx + cw * 2))
else love.graphics.setColor(255, 255, 255, 255)
sel = #ll.games
end
love.graphics.setFont(f)
local oy = 0
for k, v in pairs(ll.games) do
local x, w, h, g = cx, cw, ch, cg
if k == sel then
x = cx / css
w = cw * css
h = ch * css
g = cg * 3
oy = oy + cg * css
elseif k == psel then
x = cx / rcss
w = cw * rcss
h = ch * rcss
oy = oy + cg * rcss
end
love.graphics.stencil(function()
love.graphics.rectangle('fill', x, cy + oy, w, h, r)
end)
love.graphics.setStencilTest('greater', 0)
love.graphics.setColor(50 / COLDIV, 50 / COLDIV, 50 / COLDIV, 100 / COLDIV)
love.graphics.rectangle('fill', x, cy + oy, w, h)
love.graphics.setColor(255, 255, 255, 255)
scrCard(v, x, cy + oy, w, h, 255)
love.graphics.setColor(255, 255, 255, 255)
local th = f:getHeight(v.name)
love.graphics.print(v.name, x + cg, cy + oy + h - th - cg)
love.graphics.setStencilTest()
love.graphics.rectangle('line', x, cy + oy, w, h, r)
oy = oy + h + g
end
if #ll.games == 0 then
love.graphics.print('No games', cx, cy - ch)
love.graphics.setFont(bf)
love.graphics.print('Add some to the library', cx, cy)
end
end
return {
update = update,
draw = draw,
}
end