Files
love-luigi/luigi/layout.lua
2015-10-28 05:37:42 -04:00

160 lines
4.1 KiB
Lua

local ROOT = (...):gsub('[^.]*$', '')
local Base = require(ROOT .. 'base')
local Event = require(ROOT .. 'event')
local Widget = require(ROOT .. 'widget')
local Input = require(ROOT .. 'input')
local Style = require(ROOT .. 'style')
local Hooker = require(ROOT .. 'hooker')
local Layout = Base:extend()
local weakValueMeta = { __mode = 'v' }
function Layout:constructor (data)
self.widgets = setmetatable({}, weakValueMeta)
self.root = Widget(self, data or {})
self:setStyle()
self:setTheme()
self.isMousePressed = false
self.isManagingInput = false
self.hooks = {}
end
function Layout:setStyle (rules)
if type(rules) == 'function' then
rules = rules()
end
self.style = Style(rules or {}, 'id', 'style')
end
function Layout:setTheme (rules)
if type(rules) == 'function' then
rules = rules()
end
self.theme = Style(rules or {}, 'type')
end
function Layout:show ()
local root = self.root
local width = root.width
local height = root.height
local title = root.title
if not self.input then
self.input = Input(self)
end
local currentWidth, currentHeight, flags = love.window.getMode()
love.window.setMode(width or currentWidth, height or currentHeight, flags)
if title then
love.window.setTitle(title)
end
self:manageInput(self.input)
root:reflow()
end
function Layout:hide ()
if not self.isManagingInput then
return
end
self.isManagingInput = false
self:unhook()
end
-- Get the innermost widget at a position, within a root widget.
-- Should always return a widget since all positions are within
-- the layout's root widget.
function Layout:getWidgetAt (x, y, root)
local widget = root or self.root
local children = widget.children
local childCount = #children
-- Loop through in reverse, because siblings defined later in the tree
-- will overdraw earlier siblings.
for i = childCount, 1, -1 do
local child = children[i]
local inner = self:getWidgetAt(x, y, child)
if inner then return inner end
end
if widget:isAt(x, y) then return widget end
if widget == self.root then return widget end
end
-- Internal, called from Widget:new
function Layout:addWidget (widget)
if widget.id then
self[widget.id] = widget
end
table.insert(self.widgets, widget)
end
-- event stuff
function Layout:hook (key, method)
self.hooks[#self.hooks + 1] = Hooker.hook(love, key, method)
end
function Layout:unhook ()
for _, item in ipairs(self.hooks) do
Hooker.unhook(item)
end
self.hooks = {}
end
local getMouseButtonId
local major, minor, revision, codename = love.getVersion()
if minor < 10 then
getMouseButtonId = function (value)
return value == 'l' and 1
or value == 'r' and 2
or value == 'm' and 3
end
else
getMouseButtonId = function (value)
return value
end
end
function Layout:manageInput (input)
if self.isManagingInput then
return
end
self.isManagingInput = true
self:hook('draw', function ()
input:handleDisplay()
end)
self:hook('resize', function (width, height)
return input:handleReshape(width, height)
end)
self:hook('mousepressed', function (x, y, button)
self.isMousePressed = true
return input:handlePressStart(getMouseButtonId(button), x, y)
end)
self:hook('mousereleased', function (x, y, button)
self.isMousePressed = false
return input:handlePressEnd(getMouseButtonId(button), x, y)
end)
self:hook('mousemoved', function (x, y, dx, dy)
if self.isMousePressed then
return input:handlePressedMotion(x, y)
else
return input:handleMotion(x, y)
end
end)
self:hook('keypressed', function (key, isRepeat)
return input:handleKeyboard(key, love.mouse.getX(), love.mouse.getY())
end)
self:hook('textinput', function (text)
return input:handleTextInput(text, love.mouse.getX(), love.mouse.getY())
end)
end
-- event binders
Event.injectBinders(Layout)
return Layout