Pop.Box/init.lua
2017-08-28 01:17:54 -07:00

487 lines
15 KiB
Lua

local pop = {
_VERSION = '0.0.0',
_DESCRIPTION = 'GUI library for LOVE, designed for ease of use',
_URL = 'http://github.com/Guard13007/Pop.Box',
_LICENSE = 'The MIT License (MIT)',
_AUTHOR = 'Paul Liverman III'
}
local log
log = function(...)
return print("[Pop.Box]", ...)
end
if not (love.getVersion) then
error("Pop.Box only supports LOVE versions >= 0.9.1")
end
local path = (...):gsub("%.", "/")
if (...):sub(-4) == "init" then
path = (...):sub(1, -5)
if not (path) then
path = "."
end
end
log("Require path detected: \"" .. tostring(path) .. "\"")
local filesystem, graphics
do
local _obj_0 = love
filesystem, graphics = _obj_0.filesystem, _obj_0.graphics
end
local insert
insert = table.insert
local inheritsFromElement
inheritsFromElement = require(tostring(path) .. "/util").inheritsFromElement
local dumps, loads
do
local _obj_0 = require(tostring(path) .. "/lib/bitser/bitser")
dumps, loads = _obj_0.dumps, _obj_0.loads
end
local major, minor, revision = love.getVersion()
if major == 0 and minor == 9 then
pop.constants = {
left_mouse = "l",
middle_mouse = "m",
right_mouse = "r",
button_4 = "x1",
button_5 = "x2",
mouse_wheel_down = "wd",
mouse_wheel_up = "wu"
}
elseif major == 0 and minor == 10 then
pop.constants = {
left_mouse = 1,
middle_mouse = 3,
right_mouse = 2,
button_4 = 4,
button_5 = 5
}
else
pop.constants = { }
end
pop.elements = { }
pop.skins = { }
pop.extensions = { }
pop.states = { }
pop.state = false
pop.screen = false
pop.focused = false
pop.hovered = false
pop.log = log
pop.load = function(load_path)
if load_path == nil then
load_path = path
end
log("Loading elements from \"" .. tostring(load_path) .. "/elements\"")
local elements = filesystem.getDirectoryItems(tostring(load_path) .. "/elements")
for i = 1, #elements do
local _continue_0 = false
repeat
if not (elements[i]:sub(-4) == ".lua") then
log("Ignored non-Lua file \"" .. tostring(load_path) .. "/elements/" .. tostring(elements[i]) .. "\"")
_continue_0 = true
break
end
local name = elements[i]:sub(1, -5)
log("Requiring \"" .. tostring(name) .. "\" from \"" .. tostring(load_path) .. "/elements/" .. tostring(name) .. "\"")
pop.elements[name] = require(tostring(load_path) .. "/elements/" .. tostring(name))
if pop.elements[name].load then
pop.elements[name].load(pop)
end
log("Element loaded: \"" .. tostring(name) .. "\"")
if not (pop[name]) then
if pop.elements[name].wrap then
pop[name] = pop.elements[name].wrap(pop)
else
pop[name] = function(...)
return pop.create(name, ...)
end
end
log("Wrapper created: \"pop." .. tostring(name) .. "()\"")
end
_continue_0 = true
until true
if not _continue_0 then
break
end
end
local skins = filesystem.getDirectoryItems(tostring(load_path) .. "/skins")
for i = 1, #skins do
local _continue_0 = false
repeat
if not (skins[i]:sub(-4) == ".lua") then
log("Ignored non-Lua file \"" .. tostring(load_path) .. "/skins/" .. tostring(skins[i]) .. "\"")
_continue_0 = true
break
end
local name = skins[i]:sub(1, -5)
log("Requiring \"" .. tostring(name) .. "\" from \"" .. tostring(load_path) .. "/skins/" .. tostring(name) .. "\"")
pop.skins[name] = require(tostring(load_path) .. "/skins/" .. tostring(name))
if pop.skins[name].load then
pop.skins[name].load(pop)
end
log("Skin loaded: \"" .. tostring(name) .. "\"")
_continue_0 = true
until true
if not _continue_0 then
break
end
end
local extensions = filesystem.getDirectoryItems(tostring(load_path) .. "/extensions")
for i = 1, #extensions do
local _continue_0 = false
repeat
if not (extensions[i]:sub(-4) == ".lua") then
log("Ignored non-Lua file \"" .. tostring(load_path) .. "/extensions/" .. tostring(extensions[i]) .. "\"")
_continue_0 = true
break
end
local name = extensions[i]:sub(1, -5)
log("Requiring \"" .. tostring(name) .. "\" from \"" .. tostring(load_path) .. "/extensions/" .. tostring(name) .. "\"")
pop.extensions[name] = require(tostring(load_path) .. "/extensions/" .. tostring(name))
if type(pop.extensions[name]) == "table" and pop.extensions[name].load then
pop.extensions[name].load(pop)
end
log("Extension loaded: \"" .. tostring(name) .. "\"")
_continue_0 = true
until true
if not _continue_0 then
break
end
end
if not (pop.screen) then
return pop.setState(pop.newState())
end
end
pop.newState = function(name)
local screen = pop.create("element", false):setSize(graphics.getWidth(), graphics.getHeight())
screen.data.update = true
if not (name) then
if pop.states.default then
name = #pop.states + 1
else
name = "default"
end
end
pop.states[name] = {
screen = screen,
focused = false,
hovered = false
}
log("Created state: \"" .. tostring(name) .. "\"")
return name
end
pop.setState = function(name)
if name == nil then
name = default
end
do
local state = pop.states[name]
if state then
pop.state = name
pop.screen = state.screen
pop.focused = state.focused
pop.hovered = state.hovered
return true
else
return error("Invalid state: \"" .. tostring(name) .. "\"")
end
end
end
pop.create = function(element, parent, data, ...)
if parent == nil then
parent = pop.screen
end
if inheritsFromElement(parent) then
if type(data) == "table" then
element = pop.elements[element](parent, data, ...)
else
element = pop.elements[element](parent, { }, data, ...)
end
insert(parent.child, element)
insert(parent.data.child, element.data)
element.parent = parent
element.data.parent = parent.data
elseif parent == false then
if type(data) == "table" then
element = pop.elements[element](false, data, ...)
else
element = pop.elements[element](false, { }, data, ...)
end
element.parent = false
element.data.parent = false
else
if type(parent) == "table" then
element = pop.elements[element](pop.screen, parent, data, ...)
else
element = pop.elements[element](pop.screen, { }, parent, data, ...)
end
insert(pop.screen.child, element)
insert(pop.screen.data.child, element.data)
element.parent = pop.screen
element.data.parent = pop.screen.data
if element.parent and element.parent.childAdded then
print("working?")
element.parent:childAdded(element)
end
end
return element
end
pop.update = function(dt, element)
if element == nil then
element = pop.screen
end
if element.data.update then
if element.update then
element:update(dt)
end
for i = 1, #element.child do
pop.update(dt, element.child[i])
end
end
end
pop.draw = function(element)
if element == nil then
element = pop.screen
end
if element.data.draw then
local drawChildren
if element.draw then
drawChildren = element:draw()
end
if drawChildren ~= false then
for i = 1, #element.child do
pop.draw(element.child[i])
end
end
end
end
pop.mousemoved = function(x, y, dx, dy, element)
if element == nil then
element = pop.screen
end
local previously_hovered
if element == pop.screen then
previously_hovered = pop.hovered
end
if element.data.draw and element.data.hoverable and (x >= element.data.x) and (x <= element.data.x + element.data.w) and (y >= element.data.y) and (y <= element.data.y + element.data.h) then
pop.hovered = element
for i = 1, #element.child do
pop.mousemoved(x, y, dx, dy, element.child[i])
end
end
if element == pop.screen then
if pop.hovered ~= previously_hovered then
log(" pop.hovered: " .. tostring(pop.hovered) .. " (" .. tostring(pop.hovered.data.type) .. ")")
if previously_hovered and previously_hovered.hovered then
previously_hovered:hovered(false)
end
if pop.hovered.hovered then
pop.hovered:hovered(true)
end
end
if pop.focused and pop.focused.mousemoved then
return pop.focused:mousemoved(x - pop.focused.data.x, y - pop.focused.data.y, dx, dy)
end
end
return false
end
pop.mousepressed = function(x, y, button, element)
if not (element) then
if button == pop.constants.mouse_wheel_down then
pop.wheelmoved(0, -1)
return true
elseif button == pop.constants.mouse_wheel_up then
pop.wheelmoved(0, 1)
return true
end
log("mousepressed", x, y, button)
element = pop.screen
end
local handled = false
if element.data.draw and (x >= element.data.x) and (x <= element.data.x + element.data.w) and (y >= element.data.y) and (y <= element.data.y + element.data.h) then
for i = #element.child, 1, -1 do
handled = pop.mousepressed(x, y, button, element.child[i])
if handled ~= false then
return handled
end
end
if element.mousepressed then
handled = element:mousepressed(x - element.data.x, y - element.data.y, button)
if handled ~= false then
log(" " .. tostring(handled) .. " (handled)", tostring(element) .. " (" .. tostring(element.data.type) .. ")")
end
if handled then
log(" ^ focused")
pop.focused = element
end
end
end
return handled
end
pop.mousereleased = function(x, y, button, element)
local clickedHandled = false
local mousereleasedHandled = false
if element then
if element.data.draw and (x >= element.data.x) and (x <= element.data.x + element.data.w) and (y >= element.data.y) and (y <= element.data.y + element.data.h) then
for i = #element.child, 1, -1 do
clickedHandled, mousereleasedHandled = pop.mousereleased(x, y, button, element.child[i])
if clickedHandled ~= false or mousereleasedHandled ~= false then
return clickedHandled, mousereleasedHandled
end
end
if element.clicked then
clickedHandled = element:clicked(x - element.data.x, y - element.data.y, button)
end
if element.mousereleased then
mousereleasedHandled = element:mousereleased(x - element.data.x, y - element.data.y, button)
end
if clickedHandled ~= false then
log(" " .. tostring(clickedHandled) .. " (click handled)", tostring(element) .. " (" .. tostring(element.data.type) .. ")")
end
if clickedHandled then
log(" ^ focused")
pop.focused = element
end
if mousereleasedHandled ~= false then
log(" " .. tostring(mousereleasedHandled) .. " (release handled)", tostring(element) .. " (" .. tostring(element.data.type) .. ")")
end
end
else
log("mousereleased", x, y, button)
do
element = pop.focused
if element then
if element.data.draw and (x >= element.data.x) and (x <= element.data.x + element.data.w) and (y >= element.data.y) and (y <= element.data.y + element.data.h) then
if element.clicked then
clickedHandled = element:clicked(x - element.data.x, y - element.data.y, button)
if clickedHandled ~= false then
log(" " .. tostring(clickedHandled) .. " (click handled)", tostring(element) .. " (" .. tostring(element.data.type) .. ")")
end
end
end
if element.mousereleased then
mousereleasedHandled = element:mousereleased(x - element.data.x, y - element.data.y, button)
if mousereleasedHandled ~= false then
log(" " .. tostring(mousereleasedHandled) .. " (release handled)", tostring(element) .. " (" .. tostring(element.data.type) .. ")")
end
end
if clickedHandled ~= false or mousereleasedHandled ~= false then
return clickedHandled, mousereleasedHandled
end
end
end
pop.mousereleased(x, y, button, pop.screen)
end
return clickedHandled, mousereleasedHandled
end
pop.wheelmoved = function(x, y)
log("wheelmoved", x, y)
if pop.hovered and pop.hovered.wheelmoved then
return pop.hovered:wheelmoved(x, y)
end
return false
end
pop.keypressed = function(key)
log("keypressed", key)
local element = pop.focused
if element and element.keypressed and element.data.draw then
return element.keypressed(key)
end
return false
end
pop.keyreleased = function(key)
log("keyreleased", key)
local element = pop.focused
if element and element.keyreleased then
return element.keyreleased(key)
end
return false
end
pop.textinput = function(text)
log("textinput", text)
local element = pop.focused
if element and element.textinput and element.data.draw then
return element.textinput(text)
end
return false
end
pop.import = function(data, parent)
if parent == nil then
parent = pop.screen
end
local element
if type(data) == "string" then
data = loads(data)
element = pop.create(data.type, parent, data)
else
element = pop.elements[data.type](parent, data)
insert(parent.child, element)
end
for i = 1, #data.child do
pop.import(data.child[i], element)
end
end
pop.export = function(element)
if element == nil then
element = pop.screen
end
return dumps(element.data)
end
pop.debugDraw = function(element)
if element == nil then
element = pop.screen
end
if element.debugDraw then
element:debugDraw()
end
graphics.setLineWidth(1)
graphics.setColor(0, 0, 0, 100)
graphics.rectangle("fill", element.data.x, element.data.y, element.data.w, element.data.h)
graphics.setColor(150, 150, 150, 150)
graphics.rectangle("line", element.data.x, element.data.y, element.data.w, element.data.h)
graphics.setColor(200, 200, 200, 255)
if element.debugInfo then
graphics.print(tostring(element.__class.__name:sub(1, 1)) .. " (" .. tostring(element:debugInfo()) .. ")", element.data.x, element.data.y)
else
graphics.print(tostring(element.__class.__name:sub(1, 1)), element.data.x, element.data.y)
end
for i = 1, #element.child do
pop.debugDraw(element.child[i])
end
end
pop.printElementTree = function(element, fn, depth)
if element == nil then
element = pop.screen
end
if depth == nil then
depth = 0
end
if "table" ~= type(element) then
depth = fn
fn = element
element = pop.screen
end
if "number" == type(fn) then
depth = fn
fn = nil
end
if not (depth) then
depth = 0
end
local cls = element.__class.__name
if element.debugInfo then
cls = cls .. " (" .. tostring(element:debugInfo()) .. ")"
end
if fn then
cls = cls .. " " .. tostring(fn(element))
end
if depth > 0 then
log(string.rep("-", depth) .. " " .. tostring(cls))
else
log(cls)
end
for i = 1, #element.child do
pop.printElementTree(element.child[i], fn, depth + 1)
end
end
pop.load()
return pop