Elemental handling -> master

pr #11
This commit is contained in:
Fox 2016-04-04 21:33:51 -07:00
commit 6a42bde50f
40 changed files with 2220 additions and 103 deletions

21
LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-2016 Paul Liverman III
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

52
README.md Normal file
View File

@ -0,0 +1,52 @@
# Pop.Box
*Do not mix with [Cola][1].*
Pop.Box is a GUI library for use in the [LÖVE][2] engine, designed to be easy to
use and require as little code as possible to set up. It is primarily designed
to make it easy to experiment with GUIs during development.
Supports LÖVE versions 0.9.1 and higher.
## Features
- Quickly set up and align GUI elements.
- Fully customizable alignment / styling.
- Moving/resizing elements takes alignment into account.
- Mouse and key input handling. (**Note**: Work in progress.)
- Extensible: Make your own elements, skins, extensions, and everything is
automatically loaded.
## Usage
The basics:
```lua
local pop = require "pop"
-- define LÖVE callbacks here (update, draw, textinput, mouse/key events)
local window = pop.window():align("center"):setTitle("Welcome!")
window:addChild(pop.text("Welcome to Pop.Box()!"))
```
**Note**: Due to this being so early in development...the above example doesn't
actually work as expected. `window` is a very new element.
For more examples, see the code in `demo`. For documentation, see `docs`.
# Documentation
**Note**: Docs not written just yet. Will be soon.
- [Pop Module][3] (The main module/interface.)
- [Elements][4] (Basic features of elements/types of elements.)
- [Skins][5] (A basic system for quickly applying settings to many elements.)
- [Extensions][7] (A way to load custom code in.)
- [Drawables][6] (Reference for what can be used as a background/color.)
[1]: https://en.wikipedia.org/wiki/Cola_(programming_language)
[2]: https://love2d.org/
[3]: ./docs/Pop.md
[4]: ./docs/Elements.md
[5]: ./docs/Skins.md
[6]: ./docs/Drawables.md
[7]: ./docs/Extensions.md

5
build.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
cd src
moonc -t ../lib .
cd ..
cp -rf ./lib/pop/* ./demo/pop/

344
demo/debug-lib/inspect.lua Normal file
View File

@ -0,0 +1,344 @@
local inspect ={
_VERSION = 'inspect.lua 3.0.3',
_URL = 'http://github.com/kikito/inspect.lua',
_DESCRIPTION = 'human-readable representations of tables',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2013 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end})
inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end})
-- Apostrophizes the string if it has quotes, but not aphostrophes
-- Otherwise, it returns a regular quoted string
local function smartQuote(str)
if str:match('"') and not str:match("'") then
return "'" .. str .. "'"
end
return '"' .. str:gsub('"', '\\"') .. '"'
end
local controlCharsTranslation = {
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v"
}
local function escape(str)
local result = str:gsub("\\", "\\\\"):gsub("(%c)", controlCharsTranslation)
return result
end
local function isIdentifier(str)
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
end
local function isSequenceKey(k, sequenceLength)
return type(k) == 'number'
and 1 <= k
and k <= sequenceLength
and math.floor(k) == k
end
local defaultTypeOrders = {
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
['function'] = 5, ['userdata'] = 6, ['thread'] = 7
}
local function sortKeys(a, b)
local ta, tb = type(a), type(b)
-- strings and numbers are sorted numerically/alphabetically
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
-- Two default types are compared according to the defaultTypeOrders table
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
elseif dta then return true -- default types before custom ones
elseif dtb then return false -- custom types after default ones
end
-- custom types are sorted out alphabetically
return ta < tb
end
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
-- tables aren't pure sequences. So we implement our own # operator.
local function getSequenceLength(t)
local len = 1
local v = rawget(t,len)
while v ~= nil do
len = len + 1
v = rawget(t,len)
end
return len - 1
end
local function getNonSequentialKeys(t)
local keys = {}
local sequenceLength = getSequenceLength(t)
for k,_ in pairs(t) do
if not isSequenceKey(k, sequenceLength) then table.insert(keys, k) end
end
table.sort(keys, sortKeys)
return keys, sequenceLength
end
local function getToStringResultSafely(t, mt)
local __tostring = type(mt) == 'table' and rawget(mt, '__tostring')
local str, ok
if type(__tostring) == 'function' then
ok, str = pcall(__tostring, t)
str = ok and str or 'error: ' .. tostring(str)
end
if type(str) == 'string' and #str > 0 then return str end
end
local maxIdsMetaTable = {
__index = function(self, typeName)
rawset(self, typeName, 0)
return 0
end
}
local idsMetaTable = {
__index = function (self, typeName)
local col = {}
rawset(self, typeName, col)
return col
end
}
local function countTableAppearances(t, tableAppearances)
tableAppearances = tableAppearances or {}
if type(t) == 'table' then
if not tableAppearances[t] then
tableAppearances[t] = 1
for k,v in pairs(t) do
countTableAppearances(k, tableAppearances)
countTableAppearances(v, tableAppearances)
end
countTableAppearances(getmetatable(t), tableAppearances)
else
tableAppearances[t] = tableAppearances[t] + 1
end
end
return tableAppearances
end
local copySequence = function(s)
local copy, len = {}, #s
for i=1, len do copy[i] = s[i] end
return copy, len
end
local function makePath(path, ...)
local keys = {...}
local newPath, len = copySequence(path)
for i=1, #keys do
newPath[len + i] = keys[i]
end
return newPath
end
local function processRecursive(process, item, path, visited)
if item == nil then return nil end
if visited[item] then return visited[item] end
local processed = process(item, path)
if type(processed) == 'table' then
local processedCopy = {}
visited[item] = processedCopy
local processedKey
for k,v in pairs(processed) do
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
if processedKey ~= nil then
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
end
end
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
setmetatable(processedCopy, mt)
processed = processedCopy
end
return processed
end
-------------------------------------------------------------------
local Inspector = {}
local Inspector_mt = {__index = Inspector}
function Inspector:puts(...)
local args = {...}
local buffer = self.buffer
local len = #buffer
for i=1, #args do
len = len + 1
buffer[len] = tostring(args[i])
end
end
function Inspector:down(f)
self.level = self.level + 1
f()
self.level = self.level - 1
end
function Inspector:tabify()
self:puts(self.newline, string.rep(self.indent, self.level))
end
function Inspector:alreadyVisited(v)
return self.ids[type(v)][v] ~= nil
end
function Inspector:getId(v)
local tv = type(v)
local id = self.ids[tv][v]
if not id then
id = self.maxIds[tv] + 1
self.maxIds[tv] = id
self.ids[tv][v] = id
end
return id
end
function Inspector:putKey(k)
if isIdentifier(k) then return self:puts(k) end
self:puts("[")
self:putValue(k)
self:puts("]")
end
function Inspector:putTable(t)
if t == inspect.KEY or t == inspect.METATABLE then
self:puts(tostring(t))
elseif self:alreadyVisited(t) then
self:puts('<table ', self:getId(t), '>')
elseif self.level >= self.depth then
self:puts('{...}')
else
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
local nonSequentialKeys, sequenceLength = getNonSequentialKeys(t)
local mt = getmetatable(t)
local toStringResult = getToStringResultSafely(t, mt)
self:puts('{')
self:down(function()
if toStringResult then
self:puts(' -- ', escape(toStringResult))
if sequenceLength >= 1 then self:tabify() end
end
local count = 0
for i=1, sequenceLength do
if count > 0 then self:puts(',') end
self:puts(' ')
self:putValue(t[i])
count = count + 1
end
for _,k in ipairs(nonSequentialKeys) do
if count > 0 then self:puts(',') end
self:tabify()
self:putKey(k)
self:puts(' = ')
self:putValue(t[k])
count = count + 1
end
if mt then
if count > 0 then self:puts(',') end
self:tabify()
self:puts('<metatable> = ')
self:putValue(mt)
end
end)
if #nonSequentialKeys > 0 or mt then -- result is multi-lined. Justify closing }
self:tabify()
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
self:puts(' ')
end
self:puts('}')
end
end
function Inspector:putValue(v)
local tv = type(v)
if tv == 'string' then
self:puts(smartQuote(escape(v)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then
self:puts(tostring(v))
elseif tv == 'table' then
self:putTable(v)
else
self:puts('<',tv,' ',self:getId(v),'>')
end
end
-------------------------------------------------------------------
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or math.huge
local newline = options.newline or '\n'
local indent = options.indent or ' '
local process = options.process
if process then
root = processRecursive(process, root, {}, {})
end
local inspector = setmetatable({
depth = depth,
buffer = {},
level = 0,
ids = setmetatable({}, idsMetaTable),
maxIds = setmetatable({}, maxIdsMetaTable),
newline = newline,
indent = indent,
tableAppearances = countTableAppearances(root)
}, Inspector_mt)
inspector:putValue(root)
return table.concat(inspector.buffer)
end
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
return inspect

View File

@ -1,8 +1,14 @@
local lg = love.graphics
local pop
local pop, inspect
local debugDraw = false
function love.load()
print(love.getVersion())
inspect = require "debug-lib/inspect"
pop = require "pop"
---[[
local c = pop.box():align("center", "center"):setSize(300, 300)
pop.box(c, {255, 0, 0, 255}):setSize(100, 50)
pop.box(c, {0, 255, 0, 255}):align("center"):setSize(100, 100)
@ -17,6 +23,45 @@ function love.load()
pop.skin(pop.text("Here's easier-to-code test text in the center!"):align("center", "center", true)) -- 'true' means align to pixel!
w = pop.box(nil, {255, 255, 255, 255}):align(false, "bottom"):setSize(150, 150)
b = pop.box(w, {0, 0, 0, 255}):setMargin(5):setSize(100, 100)
--]]
--c:move(100)
pop.box({255, 0, 0, 255}):position(50, 500) -- testing streamlined_get_set extension & optional parents
--b:margin(2) -- testing streamlined_get_set extension
b:fill() -- testing fill!
---[[
w2 = pop.window(nil, "Window")
w2:move(100, 100)
w2:setWidth(500)
w2:move(-50, 80)
w2:setHeight(500)
w2:move(0, -175)
w2.title:align("center")
w2:position(0, 0)
--w2:setAlignment("right")
w2:size(200, 120):position(90, 70)
--w2:align("center")
--w2:setAlignment("center"):align("center")
--w2.child[1]:setBackground {100, 100, 100, 255}
--w2.child[3]:setBackground {160, 140, 40, 255}
--]]
local test = lg.newImage("test.png")
G = pop.element():align("right"):move(-2, 2)
a = pop.box(G, test):align("right")
b = pop.box(G, test):align("right"):move(-25):setWidth(40)
c = pop.box(G, test):align("right"):move(0, 25):setHeight(40)
print(a.horizontal, a.vertical)
print(b.horizontal, b.vertical)
print(c.horizontal, c.vertical)
local window = pop.window():align("center", "center"):setTitle("Welcome!")
--window:addChild(pop.text("Welcome to Pop.Box()!"))
--TODO make debugDraw better
end
function love.update(dt)
@ -25,7 +70,15 @@ end
function love.draw()
pop.draw()
--pop.debugDraw()
if debugDraw then
pop.debugDraw()
--w2:debugDraw()
end
end
function love.mousemoved(x, y, dx, dy)
pop.mousemoved(x, y, dx, dy)
end
function love.mousepressed(x, y, button)
@ -39,6 +92,10 @@ end
function love.keypressed(key)
local handled = pop.keypressed(key)
if (key == "d") and (not handled) then
debugDraw = not debugDraw
end
if (key == "escape") and (not handled) then
love.event.quit()
end

View File

@ -21,6 +21,7 @@ do
local w, h = self.background:getDimensions()
w = self.w / w
h = self.h / h
graphics.setColor(255, 255, 255, 255)
graphics.draw(self.background, self.x, self.y, 0, w, h)
end
end
@ -70,11 +71,13 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, pop, parent, background)
__init = function(self, parent, background)
if background == nil then
background = false
end
_class_0.__parent.__init(self, pop, parent)
_class_0.__parent.__init(self, parent)
self.w = 20
self.h = 20
self.background = background
end,
__base = _base_0,

View File

@ -16,6 +16,14 @@ do
graphics.print("e", self.x, self.y)
return self
end,
addChild = function(self, child)
self.child[#self.child + 1] = child
child.parent = self
return self
end,
getChildren = function(self)
return self.child
end,
move = function(self, x, y)
if x then
self.x = self.x + x
@ -105,6 +113,32 @@ do
getSize = function(self)
return self.w, self.h
end,
setWidth = function(self, w)
local _exp_0 = self.horizontal
if "center" == _exp_0 then
self.x = self.x - ((w - self.w) / 2)
elseif "right" == _exp_0 then
self.x = self.x - (w - self.w)
end
self.w = w
return self
end,
getWidth = function(self)
return self.w
end,
setHeight = function(self, h)
local _exp_0 = self.vertical
if "center" == _exp_0 then
self.y = self.y - ((h - self.h) / 2)
elseif "bottom" == _exp_0 then
self.y = self.y - (h - self.h)
end
self.h = h
return self
end,
getHeight = function(self)
return self.h
end,
adjustSize = function(self, w, h)
local W, H = self:getSize()
if w then
@ -136,7 +170,7 @@ do
elseif "bottom" == _exp_1 then
self.y = self.y + (self.parent.h - self.h - self.margin)
end
if toPixel then
if toPixel or (toPixel == nil) then
self.x = floor(self.x)
self.y = floor(self.y)
end
@ -158,6 +192,9 @@ do
end
return self
end,
getAlignment = function(self)
return self.horizontal, self.vertical
end,
setMargin = function(self, margin)
self.margin = margin
self:align()
@ -165,25 +202,31 @@ do
end,
getMargin = function(self)
return self.margin
end,
fill = function(self)
self.x = self.parent.x + self.margin
self.y = self.parent.y + self.margin
self.w = self.parent.w - self.margin * 2
self.h = self.parent.h - self.margin * 2
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, pop, parent)
__init = function(self, parent)
self.parent = parent
self.child = { }
self.w = 0
self.h = 0
self.margin = 0
if parent then
self.x = parent.x or 0
self.y = parent.y or 0
self.x = parent.x
self.y = parent.y
else
self.x = 0
self.y = 0
end
self.w = 10
self.h = 10
self.horizontal = "left"
self.vertical = "top"
self.margin = 0
end,
__base = _base_0,
__name = "element"

View File

@ -12,19 +12,10 @@ do
local _class_0
local _parent_0 = element
local _base_0 = {
wrap = function(pop)
return function(parent, ...)
if type(parent) == "string" then
return pop.create("text", nil, parent, ...)
else
return pop.create("text", parent, ...)
end
end
end,
draw = function(self)
graphics.setColor(self.color)
graphics.setFont(self.font)
graphics.print(self.text, self.x, self.y)
graphics.print(self.txt, self.x, self.y)
return self
end,
debugDraw = function(self)
@ -38,8 +29,8 @@ do
return self
end,
setSize = function(self)
local w = self.font:getWidth(self.text)
local h = self.font:getHeight() * (select(2, self.text:gsub("\n", "\n")) + 1)
local w = self.font:getWidth(self.txt)
local h = self.font:getHeight() * (select(2, self.txt:gsub("\n", "\n")) + 1)
local _exp_0 = self.horizontal
if "center" == _exp_0 then
self.x = self.x - ((w - self.w) / 2)
@ -56,16 +47,24 @@ do
self.h = h
return self
end,
setWidth = function(self)
self:setSize()
return self
end,
setHeight = function(self)
self:setSize()
return self
end,
setText = function(self, text)
if text == nil then
text = ""
end
self.text = text
self.txt = text
self:setSize()
return self
end,
getText = function(self)
return self.text
return self.txt
end,
setFont = function(self, font)
self.font = font
@ -98,7 +97,7 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, pop, parent, text, color)
__init = function(self, parent, text, color)
if text == nil then
text = ""
end
@ -110,7 +109,7 @@ do
255
}
end
_class_0.__parent.__init(self, pop, parent)
_class_0.__parent.__init(self, parent)
self.font = graphics.newFont(14)
self:setText(text)
self.color = color
@ -137,6 +136,16 @@ do
end
})
_base_0.__class = _class_0
local self = _class_0
self.wrap = function(pop)
return function(parent, ...)
if type(parent) == "string" then
return pop.create("text", nil, parent, ...)
else
return pop.create("text", parent, ...)
end
end
end
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end

View File

@ -0,0 +1,251 @@
local graphics
graphics = love.graphics
local sub, len
do
local _obj_0 = string
sub, len = _obj_0.sub, _obj_0.len
end
local path = sub(..., 1, len(...) - len("/window"))
local element = require(tostring(path) .. "/element")
local box = require(tostring(path) .. "/box")
local text = require(tostring(path) .. "/text")
local left = 1
local mousemoved_event = true
do
local major, minor, revision = love.getVersion()
if (major == 0) and (minor == 10) and ((revision == 0) or (revision == 1)) then
left = 1
elseif (major == 0) and (minor == 9) then
left = "l"
if revision == 1 then
mousemoved_event = false
end
else
print("elements/window: unrecognized LÖVE version: " .. tostring(major) .. "." .. tostring(minor) .. "." .. tostring(revision))
print(" assuming LÖVE version > 0.10.1 (there may be bugs)")
end
end
local pop_ref = false
local window
do
local _class_0
local _parent_0 = element
local _base_0 = {
load = function(pop)
pop_ref = pop
end,
debugDraw = function(self)
graphics.setLineWidth(0.5)
graphics.setColor(0, 0, 0, 100)
graphics.rectangle("fill", self.x, self.y, self.w, self.h)
graphics.setColor(200, 0, 200, 200)
graphics.rectangle("line", self.x, self.y, self.w, self.h)
graphics.setColor(255, 200, 255, 255)
graphics.print("w", self.x, self.y)
return self
end,
addChild = function(self, child)
self.window.child[#self.window.child + 1] = child
child.parent = self.window
return self
end,
getChildren = function(self)
return self.window.child
end,
align = function(self, horizontal, vertical, toPixel)
_class_0.__parent.__base.align(self, horizontal, vertical, toPixel)
for i = 1, #self.child do
self.child[i]:align()
end
self.window:move(nil, self.head:getHeight())
return self
end,
setSize = function(self, w, h)
local x = 0
local y = 0
if w then
local _exp_0 = self.horizontal
if "center" == _exp_0 then
x = x - ((w - self.w) / 2)
elseif "right" == _exp_0 then
x = x - (w - self.w)
end
self.head:setWidth(w)
self.window:setWidth(w)
self.w = w
self.x = self.x + x
self.title:align()
end
if h then
h = h - self.head:getHeight()
local _exp_0 = self.vertical
if "center" == _exp_0 then
y = y - ((h - self.h) / 2)
elseif "right" == _exp_0 then
y = y - (h - self.h)
end
self.window:setHeight(h)
self.h = h + self.head:getHeight()
self.y = self.y + y
end
self.head:move(x, y)
self.window:move(x, y)
return self
end,
setWidth = function(self, w)
local x = 0
local _exp_0 = self.horizontal
if "center" == _exp_0 then
x = x - ((w - self.w) / 2)
elseif "right" == _exp_0 then
x = x - (w - self.w)
end
self.head:setWidth(w)
self.window:setWidth(w)
self.w = w
self.x = self.x + x
self.title:align()
self.head:move(x)
self.window:move(x)
return self
end,
setHeight = function(self, h)
local y = 0
h = h - self.head:getHeight()
local _exp_0 = self.vertical
if "center" == _exp_0 then
y = y - ((h - self.h) / 2)
elseif "right" == _exp_0 then
y = y - (h - self.h)
end
self.window:setHeight(h)
self.h = h + self.head:getHeight()
self.y = self.y + y
self.head:move(nil, y)
self.title:move(nil, y)
self.window:move(nil, y)
return self
end,
setTitle = function(self, title)
self.title:setText(title)
return self
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, parent, title, tBackground, tColor, wBackground)
if title == nil then
title = "window"
end
if tBackground == nil then
tBackground = {
25,
180,
230,
255
}
end
if tColor == nil then
tColor = {
255,
255,
255,
255
}
end
if wBackground == nil then
wBackground = {
200,
200,
210,
255
}
end
_class_0.__parent.__init(self, parent)
self.head = box(self, tBackground)
self.title = text(self, title, tColor)
self.window = box(self, wBackground)
local height = self.title:getHeight()
self.head:setSize(self.w, height)
self.window:move(nil, height)
self:setSize(100, 80)
self.child = {
self.head,
self.title,
self.window
}
self.head.selected = false
if mousemoved_event then
self.head.mousemoved = function(self, x, y, dx, dy)
if self.selected then
self.parent:move(y, dx)
return true
end
return false
end
self.head.mousepressed = function(self, x, y, button)
if button == left then
self.selected = true
return true
end
return false
end
self.head.mousereleased = function(self, x, y, button)
if button == left then
self.selected = false
pop_ref.focused = false
return true
end
return false
end
else
self.head.mx = 0
self.head.my = 0
self.head.update = function(self)
return false
end
self.head.mousepressed = function(self, x, y, button)
if button == left then
self.selected = true
self.mx = x
self.my = y
end
end
self.head.mousereleased = function(self, x, y, button)
if button == left then
self.selected = false
return true
end
return false
end
end
end,
__base = _base_0,
__name = "window",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
window = _class_0
return _class_0
end

View File

@ -0,0 +1,51 @@
local graphics
graphics = love.graphics
local sub, len
do
local _obj_0 = string
sub, len = _obj_0.sub, _obj_0.len
end
local path = sub(..., 1, len(...) - len("/extensions/streamlined_get_set"))
local element = require(tostring(path) .. "/elements/element")
element.__base.position = function(self, x, y)
if x or y then
return self:setPosition(x, y)
else
return self:getPosition()
end
end
element.__base.size = function(self, w, h)
if w or h then
return self:setSize(w, h)
else
return self:getSize()
end
end
element.__base.width = function(self, w)
if w then
return self:setWidth(w)
else
return self:getWidth()
end
end
element.__base.height = function(self, h)
if h then
return self:setHeight(h)
else
return self:getHeight()
end
end
element.__base.alignment = function(self, horizontal, vertical)
if horizontal or vertical then
return self:setAlignment(horizontal, vertical)
else
return self:getAlignment()
end
end
element.__base.margin = function(self, m)
if m then
return self:setMargin(m)
else
return self:getMargin()
end
end

View File

@ -1,3 +1,6 @@
if not (love.getVersion) then
error("Pop.Box only supports LÖVE versions >= 0.9.1")
end
local filesystem, graphics
do
local _obj_0 = love
@ -5,11 +8,15 @@ do
end
local insert
insert = table.insert
local inheritsFromElement
inheritsFromElement = require(tostring(...) .. "/util").inheritsFromElement
local path = ...
local pop = { }
pop.elements = { }
pop.skins = { }
pop.events = { }
pop.screen = false
pop.focused = false
pop.load = function()
local elements = filesystem.getDirectoryItems(tostring(path) .. "/elements")
for i = 1, #elements do
@ -21,6 +28,9 @@ pop.load = function()
end
local name = elements[i]:sub(1, -5)
pop.elements[name] = require(tostring(path) .. "/elements/" .. tostring(name))
if pop.elements[name].load then
pop.elements[name].load(pop)
end
print("element loaded: \"" .. tostring(name) .. "\"")
if not (pop[name]) then
if pop.elements[name].wrap then
@ -55,6 +65,23 @@ pop.load = function()
break
end
end
local extensions = filesystem.getDirectoryItems(tostring(path) .. "/extensions")
for i = 1, #extensions do
local _continue_0 = false
repeat
if not (extensions[i]:sub(-4) == ".lua") then
_continue_0 = true
break
end
local name = extensions[i]:sub(1, -5)
require(tostring(path) .. "/extensions/" .. tostring(name))
print("extension loaded: \"" .. tostring(name) .. "\"")
_continue_0 = true
until true
if not _continue_0 then
break
end
end
pop.screen = pop.create("element", false):setSize(graphics.getWidth(), graphics.getHeight())
return print("created \"pop.screen\"")
end
@ -62,9 +89,14 @@ pop.create = function(element, parent, ...)
if parent == nil then
parent = pop.screen
end
element = pop.elements[element](pop, parent, ...)
if parent then
if inheritsFromElement(parent) then
element = pop.elements[element](parent, ...)
insert(parent.child, element)
elseif parent == false then
element = pop.elements[element](false, ...)
else
element = pop.elements[element](pop.screen, parent, ...)
insert(pop.screen.child, element)
end
return element
end
@ -94,19 +126,62 @@ pop.draw = function(element)
end
end
end
pop.mousepressed = function(x, y, button, element)
if element == nil then
element = pop.screen
pop.mousemoved = function(self, x, y, dx, dy)
if pop.focused and pop.focused.mousemoved then
return pop.focused:mousemoved(x, y, dx, dy)
end
print("mousepressed", x, y, button, element)
return false
end
pop.mousereleased = function(x, y, button, element)
if element == nil then
pop.mousepressed = function(x, y, button, element)
if not (element) then
print("mousepressed", x, y, button)
element = pop.screen
end
print("mousereleased", x, y, button, element)
return false
local handled = false
if (x >= element.x) and (x <= element.x + element.w) and (y >= element.y) and (y <= element.y + element.h) then
if element.mousepressed then
handled = element:mousepressed(x - element.x, y - element.y, button)
end
if handled then
pop.focused = element
pop.events[button] = element
else
for i = 1, #element.child do
handled = pop.mousepressed(x, y, button, element.child[i])
if handled then
break
end
end
end
end
return handled
end
pop.mousereleased = function(x, y, button)
print("mousereleased", x, y, button)
local clickedHandled = false
local mousereleasedHandled = false
do
local element = pop.events[button]
if element then
if element.clicked and (x >= element.x) and (x <= element.x + element.w) and (y >= element.y) and (y <= element.y + element.h) then
do
clickedHandled = element:clicked(x - element.x, y - element.y, button)
if clickedHandled then
pop.events[button] = nil
end
end
end
if element.mousereleased then
do
mousereleasedHandled = element:mousereleased(x - element.x, y - element.y, button)
if mousereleasedHandled then
pop.events[button] = nil
end
end
end
end
end
return clickedHandled, mousereleasedHandled
end
pop.keypressed = function(key)
print("keypressed", key)

19
demo/pop/util.lua Normal file
View File

@ -0,0 +1,19 @@
local inheritsFromElement
inheritsFromElement = function(object)
if object and object.__class then
local cls = object.__class
if cls.__name == "element" then
return true
end
while cls.__parent do
cls = cls.__parent
if cls.__name == "element" then
return true
end
end
end
return false
end
return {
inheritsFromElement = inheritsFromElement
}

BIN
demo/test.ogv Normal file

Binary file not shown.

BIN
demo/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

15
docs/Drawables.md Normal file
View File

@ -0,0 +1,15 @@
# Supported Drawables
Pop.Box supports three [Drawables][1]: Canvas, Image, and Video.
**Note**: Video and Canvas support are untested.
Additionally, in the place of a Drawable, you can use `false` to not render
anything, or a table of color values. The color values should be in the format
LÖVE uses (`{red, green, blue, alpha}`, see [love.graphics.setColor][2]).
(The alpha value is optional and will default to `255`, but not using an alpha
is likely to mess up your rendering if an alpha value is used *anywhere else*.)
[1]: https://love2d.org/wiki/Drawable
[2]: https://love2d.org/wiki/love.graphics.setColor

31
docs/Elements.md Normal file
View File

@ -0,0 +1,31 @@
# Elements
Elements are the core of Pop.Box.
Once `pop` has been required, you can create Elements and interact with them.
Most elements can be created like this: `local box = pop.box(...)`
However, if an element's name clashes with a function name used in Pop.Box, you
will have to use `pop.create(type, ...)` where `type` is a string naming the
element type. (No standard elements do this.)
When creating an element, the first argument is its parent element. If the first
argument is not an element, it will be treated as the second argument. If it is
`false`, then an element with no parent will be created.
When no parent is specified, an element's parent is `pop.screen`, which is the
top-level element of Pop.Box. (This behavior can be modified by custom elements,
so check their documentation.)
## Available Elements
- [Element][1] (The base of all elements, and useful for alignment.)
- [Box][2] (A box, can be colored, or display a [supported Drawable][3].)
- [Text][4] (Plain text, no special features. Useful for basic labels and such.)
- [Window][5] (A moveable window. Has a title and area for other elements.)
[1]: ./elements/element.md
[2]: ./elements/box.md
[3]: ./Drawables.md
[4]: ./elements/text.md
[5]: ./elements/window.md

14
docs/Extensions.md Normal file
View File

@ -0,0 +1,14 @@
# Extensions
Extensions are simply a way for custom code to be run after loading elements and
skins. Simply place a `.lua` file in the `extensions` directory, and it will be
required.
## Standard Extensions
There is only one standard extension, which modifies element classes to add a
more convenient getter/setter method to most get/set methods. For example,
instead of `element:getSize()`, just call `element:size()`. Instead of
`element:setSize(w, h)`, call `element:size(w, h)`.
This is mostly for a demo of what can be possible, but also might be useful.

54
docs/Pop.md Normal file
View File

@ -0,0 +1,54 @@
# Pop Module
This is the main module that allows you to access everything else in Pop.Box.
Simply require it (`local pop = require "pop"`) and define LÖVE callbacks for:
- `pop.update(dt)`
- `pop.draw()`
- `pop.mousemoved(x, y, dx, dy)` (when using LÖVE 0.10.0 or later)
- `pop.mousepressed(x, y, button)`
- `pop.mousereleased(x, y, button)`
- `pop.keypressed(key)`
- `pop.keyreleased(key)`
- `pop.textinput(text)`
Every callback returns `true`/`false` for whether or not the event was handled.
For example, using the `mousepressed` event handler:
```lua
function love.mousepressed(x, y, button)
local handled = pop.mousepressed(x, y, button)
if not handled then
-- do something useful
end
end
```
## Creating Elements
Once `pop` has been required, you can create [Elements][1] and interact with
them. Most elements can be created like this: `local box = pop.box(...)`
For more information, see the [Elements documentation][1].
## Skinning Elements
See the [Skins][2] documentation.
## Custom Elements/Skins/Extensions
Any `.lua` file placed in the `elements`, `skins`, and `extensions` directories
within the module will be loaded and available as appropriate. See the
documentation on each for how to make them:
- [Elements][1]
- [Skins][2]
- [Extensions][3]
Also of use, there is a separate set of docs about how Pop.Box works under the
surface: [Pop Module (dev)][4]
[1]: ./Elements.md
[2]: ./Skins.md
[3]: ./Extensions.md
[4]: ./dev/Pop.md

19
docs/Skins.md Normal file
View File

@ -0,0 +1,19 @@
# Skins
**Note**: This system is mostly an after-thought right now, and will probably
be replaced with something else entirely.
Skins are simple tables containing information to style a variety of elements.
Use `pop.skin()` to apply a skin to an element and its children (see
[Pop Module][3] documentation). Skins are loaded from the `skins` directory.
- `color` - A table of RGBA values (see [love.graphics.setColor][2]), used as a
foreground color (currently for `text` elements only).
- `background` - A [supported Drawable][4], used for backgrounds (currently
used on `box` elements only).
- `font` - A [Font][5].
[2]: https://love2d.org/wiki/love.graphics.setColor
[3]: ./Pop.md
[4]: ./Drawables.md
[5]: https://love2d.org/wiki/Font

8
docs/dev/Pop.md Normal file
View File

@ -0,0 +1,8 @@
# Pop Module (dev)
(This document focuses on the structure and code of Pop.Box, not how to use it.
See the [regular documentation][1] for that.)
TODO: Write me.
[1]: ../Pop.md

17
docs/elements/box.md Normal file
View File

@ -0,0 +1,17 @@
# box
The box element is a rectangle that has a [supported Drawable][1] as its
background.
## Methods
- `setBackground(background)` Using a supported Drawable (see above), set the
background.
- `getBackground()` Returns the background in use.
- `setColor(red, green, blue, alpha)` Sets the background to the specified
color. `alpha` is optional and defaults to `255`. Alternately, pass a table of
color values (ex: `{red, green, blue, alpha}`).
- `getColor()` Returns red, green, blue, and alpha color values of background.
Errors if the background is not a color.
[1]: ../Drawables.md

53
docs/elements/element.md Normal file
View File

@ -0,0 +1,53 @@
# element
This is the base of all elements, and useful for alignment purposes. It is also
the element type used for `pop.screen` (the top-level element of Pop.Box). All
methods here are available on all other elements (any differences are noted on
their documentation pages).
## Alignment
All elements have a `horizontal` and `vertical` alignment property. These modify
how elements are aligned and how positions are handled. For example, an element
aligned to the top-right will return the position of the top-right corner when
calling `getPosition()`.
- `horizontal` can be `left`, `center`, or `right`. Defaults to `left`.
- `vertical` can be `top`, `center`, or `bottom`. Defaults to `top`.
## Methods
- `addChild(child)` Adds a child element.
- `getChildren()` Returns a numerically indexed table of child elements.
- `move(x, y)` Moves the element (and its children) by specified values.
Parameters optional.
- `setPosition(x, y)` Sets position of the element (and its children) based on
the alignment of the element. Parameters optional.
- `getPosition()` Returns x/y position of the element based on its alignment.
- `setSize(w, h)` Sets the width/height of the element, element keeps "in-place"
based on its alignment. (For example, a right-aligned element will grow to the
left.) Parameters optional.
- `getSize()` Returns the width/height of the element.
- `setWidth(w)` Sets the width of the element. Element stays "in-place" based on
its alignment.
- `getWidth()` Returns the width of the element.
- `setHeight(h)` Sets the height of the element. Element stays "in-place" based
on its alignment.
- `getHeight()` Returns the height of the element.
- `adjustSize(w, h)` Grows the element by a relative width/height. Element stays
"in-place" based on its alignment.
- `align(horizontal, vertical, toPixel)` Aligns the element based on its margin
and parent. `toPixel` is a boolean for pixel-perfect alignment, defaulting to
true. See above section about alignment for valid values of `horizontal` and
`vertical`. A parent element is required for this method.
- `alignTo(element, horizontal, vertical, toPixel)` Works just like `align()`,
except that alignment is based on a specific element instead of the parent.
Does not require a parent element.
- `setAlignment(horizontal, vertical)` Sets alignment values on the element
*without* moving the element.
- `getAlignment()` Returns the `horizontal` and `vertical` alignment of the
element.
- `setMargin(m)` Sets a margin to be used when aligning the element.
- `getMargin()` Returns the current margin value.
- `fill()` Resizes and aligns the element to fill its parent's area, with the
element's margin taken into account on all sides.

22
docs/elements/text.md Normal file
View File

@ -0,0 +1,22 @@
# text
The text element is plain text in one color. Nothing special.
(**Note**: Other, more advanced text elements are planned, with support for
things like line-wrapping and custom coloring and formatting of text.)
## Methods
- `setSize()` Unlike other elements, a size cannot be set. If this is called, it
will fix the size of the text if it somehow was modified incorrectly.
- `setWidth()` Width cannot be set. If called, will fix the size of the text.
- `setHeight()` Height cannot be set. If called, will fix the size of the text.
- `setText(text)` Sets the text of the element. Will resize element to fit text.
Newlines are supported. Defaults to an empty string.
- `getText()` Returns the text of the element.
- `setFont()` Sets the font to be used on this element. Will resize to fit the
text and font.
- `setColor(red, green, blue, alpha)` Sets color of text. `alpha` is optional
and defaults to `255`. Alternately, pass a table of color values (ex: `{red,
green, blue, alpha}`).
- `getColor()` Returns red, green, blue, and alpha values of color.

4
docs/elements/window.md Normal file
View File

@ -0,0 +1,4 @@
# window
Documentation has not been written yet, as this element is still under heavy
development.

34
dummy/main.lua Normal file
View File

@ -0,0 +1,34 @@
local lg = love.graphics
local pop, parts
-- pretend parts has been defined
function love.load()
pop = require "lib.pop"
local width4 = lg.getWidth()/4
local height2 = lg.getHeight()/2
local PartList = pop.scrollbox():setSize(width4, height2)--:setSizeControl(true) --defaults to true
local PartInfo = pop.scrollbox():setSize(width4, height2):move(nil, height2)
local CraftInfo = pop.box():setSize(width4, height2):move(lg.getWidth()*3/4)
local columns = math.floor(PartList:getWidth()/128)
local rows = math.floor(#parts/columns)
local grid = pop.grid(PartList, columns, rows)
for i = 1, #parts do
-- pretend that parts.gui is a box designed to fix in here properly
grid:add(parts[i].gui) -- pretend by default, adding something to a grid like this adds it to first available spot
-- also, grids auto-resize their children
end
PartList:add(grid) -- BULLSHIT ?!
end
-- parts.gui is something like this:
gui = pop.box(newImage()) -- assumes a box can take 'userdata' as first arg and know it is an image
gui.clicked = function(x, y, button)
-- don't care about x/y
if button == "l" then --left
selected = gui.partReference -- or something
elseif button == "r" then --right
displayPartInfo() -- something happens to display it in the proper spot
end
end

View File

@ -21,6 +21,7 @@ do
local w, h = self.background:getDimensions()
w = self.w / w
h = self.h / h
graphics.setColor(255, 255, 255, 255)
graphics.draw(self.background, self.x, self.y, 0, w, h)
end
end
@ -70,11 +71,13 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, pop, parent, background)
__init = function(self, parent, background)
if background == nil then
background = false
end
_class_0.__parent.__init(self, pop, parent)
_class_0.__parent.__init(self, parent)
self.w = 20
self.h = 20
self.background = background
end,
__base = _base_0,

View File

@ -16,6 +16,14 @@ do
graphics.print("e", self.x, self.y)
return self
end,
addChild = function(self, child)
self.child[#self.child + 1] = child
child.parent = self
return self
end,
getChildren = function(self)
return self.child
end,
move = function(self, x, y)
if x then
self.x = self.x + x
@ -105,6 +113,32 @@ do
getSize = function(self)
return self.w, self.h
end,
setWidth = function(self, w)
local _exp_0 = self.horizontal
if "center" == _exp_0 then
self.x = self.x - ((w - self.w) / 2)
elseif "right" == _exp_0 then
self.x = self.x - (w - self.w)
end
self.w = w
return self
end,
getWidth = function(self)
return self.w
end,
setHeight = function(self, h)
local _exp_0 = self.vertical
if "center" == _exp_0 then
self.y = self.y - ((h - self.h) / 2)
elseif "bottom" == _exp_0 then
self.y = self.y - (h - self.h)
end
self.h = h
return self
end,
getHeight = function(self)
return self.h
end,
adjustSize = function(self, w, h)
local W, H = self:getSize()
if w then
@ -136,7 +170,7 @@ do
elseif "bottom" == _exp_1 then
self.y = self.y + (self.parent.h - self.h - self.margin)
end
if toPixel then
if toPixel or (toPixel == nil) then
self.x = floor(self.x)
self.y = floor(self.y)
end
@ -158,6 +192,9 @@ do
end
return self
end,
getAlignment = function(self)
return self.horizontal, self.vertical
end,
setMargin = function(self, margin)
self.margin = margin
self:align()
@ -165,25 +202,31 @@ do
end,
getMargin = function(self)
return self.margin
end,
fill = function(self)
self.x = self.parent.x + self.margin
self.y = self.parent.y + self.margin
self.w = self.parent.w - self.margin * 2
self.h = self.parent.h - self.margin * 2
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, pop, parent)
__init = function(self, parent)
self.parent = parent
self.child = { }
self.w = 0
self.h = 0
self.margin = 0
if parent then
self.x = parent.x or 0
self.y = parent.y or 0
self.x = parent.x
self.y = parent.y
else
self.x = 0
self.y = 0
end
self.w = 10
self.h = 10
self.horizontal = "left"
self.vertical = "top"
self.margin = 0
end,
__base = _base_0,
__name = "element"

View File

@ -12,19 +12,10 @@ do
local _class_0
local _parent_0 = element
local _base_0 = {
wrap = function(pop)
return function(parent, ...)
if type(parent) == "string" then
return pop.create("text", nil, parent, ...)
else
return pop.create("text", parent, ...)
end
end
end,
draw = function(self)
graphics.setColor(self.color)
graphics.setFont(self.font)
graphics.print(self.text, self.x, self.y)
graphics.print(self.txt, self.x, self.y)
return self
end,
debugDraw = function(self)
@ -38,8 +29,8 @@ do
return self
end,
setSize = function(self)
local w = self.font:getWidth(self.text)
local h = self.font:getHeight() * (select(2, self.text:gsub("\n", "\n")) + 1)
local w = self.font:getWidth(self.txt)
local h = self.font:getHeight() * (select(2, self.txt:gsub("\n", "\n")) + 1)
local _exp_0 = self.horizontal
if "center" == _exp_0 then
self.x = self.x - ((w - self.w) / 2)
@ -56,16 +47,24 @@ do
self.h = h
return self
end,
setWidth = function(self)
self:setSize()
return self
end,
setHeight = function(self)
self:setSize()
return self
end,
setText = function(self, text)
if text == nil then
text = ""
end
self.text = text
self.txt = text
self:setSize()
return self
end,
getText = function(self)
return self.text
return self.txt
end,
setFont = function(self, font)
self.font = font
@ -98,7 +97,7 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, pop, parent, text, color)
__init = function(self, parent, text, color)
if text == nil then
text = ""
end
@ -110,7 +109,7 @@ do
255
}
end
_class_0.__parent.__init(self, pop, parent)
_class_0.__parent.__init(self, parent)
self.font = graphics.newFont(14)
self:setText(text)
self.color = color
@ -137,6 +136,16 @@ do
end
})
_base_0.__class = _class_0
local self = _class_0
self.wrap = function(pop)
return function(parent, ...)
if type(parent) == "string" then
return pop.create("text", nil, parent, ...)
else
return pop.create("text", parent, ...)
end
end
end
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end

251
lib/pop/elements/window.lua Normal file
View File

@ -0,0 +1,251 @@
local graphics
graphics = love.graphics
local sub, len
do
local _obj_0 = string
sub, len = _obj_0.sub, _obj_0.len
end
local path = sub(..., 1, len(...) - len("/window"))
local element = require(tostring(path) .. "/element")
local box = require(tostring(path) .. "/box")
local text = require(tostring(path) .. "/text")
local left = 1
local mousemoved_event = true
do
local major, minor, revision = love.getVersion()
if (major == 0) and (minor == 10) and ((revision == 0) or (revision == 1)) then
left = 1
elseif (major == 0) and (minor == 9) then
left = "l"
if revision == 1 then
mousemoved_event = false
end
else
print("elements/window: unrecognized LÖVE version: " .. tostring(major) .. "." .. tostring(minor) .. "." .. tostring(revision))
print(" assuming LÖVE version > 0.10.1 (there may be bugs)")
end
end
local pop_ref = false
local window
do
local _class_0
local _parent_0 = element
local _base_0 = {
load = function(pop)
pop_ref = pop
end,
debugDraw = function(self)
graphics.setLineWidth(0.5)
graphics.setColor(0, 0, 0, 100)
graphics.rectangle("fill", self.x, self.y, self.w, self.h)
graphics.setColor(200, 0, 200, 200)
graphics.rectangle("line", self.x, self.y, self.w, self.h)
graphics.setColor(255, 200, 255, 255)
graphics.print("w", self.x, self.y)
return self
end,
addChild = function(self, child)
self.window.child[#self.window.child + 1] = child
child.parent = self.window
return self
end,
getChildren = function(self)
return self.window.child
end,
align = function(self, horizontal, vertical, toPixel)
_class_0.__parent.__base.align(self, horizontal, vertical, toPixel)
for i = 1, #self.child do
self.child[i]:align()
end
self.window:move(nil, self.head:getHeight())
return self
end,
setSize = function(self, w, h)
local x = 0
local y = 0
if w then
local _exp_0 = self.horizontal
if "center" == _exp_0 then
x = x - ((w - self.w) / 2)
elseif "right" == _exp_0 then
x = x - (w - self.w)
end
self.head:setWidth(w)
self.window:setWidth(w)
self.w = w
self.x = self.x + x
self.title:align()
end
if h then
h = h - self.head:getHeight()
local _exp_0 = self.vertical
if "center" == _exp_0 then
y = y - ((h - self.h) / 2)
elseif "right" == _exp_0 then
y = y - (h - self.h)
end
self.window:setHeight(h)
self.h = h + self.head:getHeight()
self.y = self.y + y
end
self.head:move(x, y)
self.window:move(x, y)
return self
end,
setWidth = function(self, w)
local x = 0
local _exp_0 = self.horizontal
if "center" == _exp_0 then
x = x - ((w - self.w) / 2)
elseif "right" == _exp_0 then
x = x - (w - self.w)
end
self.head:setWidth(w)
self.window:setWidth(w)
self.w = w
self.x = self.x + x
self.title:align()
self.head:move(x)
self.window:move(x)
return self
end,
setHeight = function(self, h)
local y = 0
h = h - self.head:getHeight()
local _exp_0 = self.vertical
if "center" == _exp_0 then
y = y - ((h - self.h) / 2)
elseif "right" == _exp_0 then
y = y - (h - self.h)
end
self.window:setHeight(h)
self.h = h + self.head:getHeight()
self.y = self.y + y
self.head:move(nil, y)
self.title:move(nil, y)
self.window:move(nil, y)
return self
end,
setTitle = function(self, title)
self.title:setText(title)
return self
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, parent, title, tBackground, tColor, wBackground)
if title == nil then
title = "window"
end
if tBackground == nil then
tBackground = {
25,
180,
230,
255
}
end
if tColor == nil then
tColor = {
255,
255,
255,
255
}
end
if wBackground == nil then
wBackground = {
200,
200,
210,
255
}
end
_class_0.__parent.__init(self, parent)
self.head = box(self, tBackground)
self.title = text(self, title, tColor)
self.window = box(self, wBackground)
local height = self.title:getHeight()
self.head:setSize(self.w, height)
self.window:move(nil, height)
self:setSize(100, 80)
self.child = {
self.head,
self.title,
self.window
}
self.head.selected = false
if mousemoved_event then
self.head.mousemoved = function(self, x, y, dx, dy)
if self.selected then
self.parent:move(y, dx)
return true
end
return false
end
self.head.mousepressed = function(self, x, y, button)
if button == left then
self.selected = true
return true
end
return false
end
self.head.mousereleased = function(self, x, y, button)
if button == left then
self.selected = false
pop_ref.focused = false
return true
end
return false
end
else
self.head.mx = 0
self.head.my = 0
self.head.update = function(self)
return false
end
self.head.mousepressed = function(self, x, y, button)
if button == left then
self.selected = true
self.mx = x
self.my = y
end
end
self.head.mousereleased = function(self, x, y, button)
if button == left then
self.selected = false
return true
end
return false
end
end
end,
__base = _base_0,
__name = "window",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
window = _class_0
return _class_0
end

View File

@ -0,0 +1,51 @@
local graphics
graphics = love.graphics
local sub, len
do
local _obj_0 = string
sub, len = _obj_0.sub, _obj_0.len
end
local path = sub(..., 1, len(...) - len("/extensions/streamlined_get_set"))
local element = require(tostring(path) .. "/elements/element")
element.__base.position = function(self, x, y)
if x or y then
return self:setPosition(x, y)
else
return self:getPosition()
end
end
element.__base.size = function(self, w, h)
if w or h then
return self:setSize(w, h)
else
return self:getSize()
end
end
element.__base.width = function(self, w)
if w then
return self:setWidth(w)
else
return self:getWidth()
end
end
element.__base.height = function(self, h)
if h then
return self:setHeight(h)
else
return self:getHeight()
end
end
element.__base.alignment = function(self, horizontal, vertical)
if horizontal or vertical then
return self:setAlignment(horizontal, vertical)
else
return self:getAlignment()
end
end
element.__base.margin = function(self, m)
if m then
return self:setMargin(m)
else
return self:getMargin()
end
end

View File

@ -1,3 +1,6 @@
if not (love.getVersion) then
error("Pop.Box only supports LÖVE versions >= 0.9.1")
end
local filesystem, graphics
do
local _obj_0 = love
@ -5,11 +8,15 @@ do
end
local insert
insert = table.insert
local inheritsFromElement
inheritsFromElement = require(tostring(...) .. "/util").inheritsFromElement
local path = ...
local pop = { }
pop.elements = { }
pop.skins = { }
pop.events = { }
pop.screen = false
pop.focused = false
pop.load = function()
local elements = filesystem.getDirectoryItems(tostring(path) .. "/elements")
for i = 1, #elements do
@ -21,6 +28,9 @@ pop.load = function()
end
local name = elements[i]:sub(1, -5)
pop.elements[name] = require(tostring(path) .. "/elements/" .. tostring(name))
if pop.elements[name].load then
pop.elements[name].load(pop)
end
print("element loaded: \"" .. tostring(name) .. "\"")
if not (pop[name]) then
if pop.elements[name].wrap then
@ -55,6 +65,23 @@ pop.load = function()
break
end
end
local extensions = filesystem.getDirectoryItems(tostring(path) .. "/extensions")
for i = 1, #extensions do
local _continue_0 = false
repeat
if not (extensions[i]:sub(-4) == ".lua") then
_continue_0 = true
break
end
local name = extensions[i]:sub(1, -5)
require(tostring(path) .. "/extensions/" .. tostring(name))
print("extension loaded: \"" .. tostring(name) .. "\"")
_continue_0 = true
until true
if not _continue_0 then
break
end
end
pop.screen = pop.create("element", false):setSize(graphics.getWidth(), graphics.getHeight())
return print("created \"pop.screen\"")
end
@ -62,9 +89,14 @@ pop.create = function(element, parent, ...)
if parent == nil then
parent = pop.screen
end
element = pop.elements[element](pop, parent, ...)
if parent then
if inheritsFromElement(parent) then
element = pop.elements[element](parent, ...)
insert(parent.child, element)
elseif parent == false then
element = pop.elements[element](false, ...)
else
element = pop.elements[element](pop.screen, parent, ...)
insert(pop.screen.child, element)
end
return element
end
@ -94,19 +126,62 @@ pop.draw = function(element)
end
end
end
pop.mousepressed = function(x, y, button, element)
if element == nil then
element = pop.screen
pop.mousemoved = function(self, x, y, dx, dy)
if pop.focused and pop.focused.mousemoved then
return pop.focused:mousemoved(x, y, dx, dy)
end
print("mousepressed", x, y, button, element)
return false
end
pop.mousereleased = function(x, y, button, element)
if element == nil then
pop.mousepressed = function(x, y, button, element)
if not (element) then
print("mousepressed", x, y, button)
element = pop.screen
end
print("mousereleased", x, y, button, element)
return false
local handled = false
if (x >= element.x) and (x <= element.x + element.w) and (y >= element.y) and (y <= element.y + element.h) then
if element.mousepressed then
handled = element:mousepressed(x - element.x, y - element.y, button)
end
if handled then
pop.focused = element
pop.events[button] = element
else
for i = 1, #element.child do
handled = pop.mousepressed(x, y, button, element.child[i])
if handled then
break
end
end
end
end
return handled
end
pop.mousereleased = function(x, y, button)
print("mousereleased", x, y, button)
local clickedHandled = false
local mousereleasedHandled = false
do
local element = pop.events[button]
if element then
if element.clicked and (x >= element.x) and (x <= element.x + element.w) and (y >= element.y) and (y <= element.y + element.h) then
do
clickedHandled = element:clicked(x - element.x, y - element.y, button)
if clickedHandled then
pop.events[button] = nil
end
end
end
if element.mousereleased then
do
mousereleasedHandled = element:mousereleased(x - element.x, y - element.y, button)
if mousereleasedHandled then
pop.events[button] = nil
end
end
end
end
end
return clickedHandled, mousereleasedHandled
end
pop.keypressed = function(key)
print("keypressed", key)

19
lib/pop/util.lua Normal file
View File

@ -0,0 +1,19 @@
local inheritsFromElement
inheritsFromElement = function(object)
if object and object.__class then
local cls = object.__class
if cls.__name == "element" then
return true
end
while cls.__parent do
cls = cls.__parent
if cls.__name == "element" then
return true
end
end
end
return false
end
return {
inheritsFromElement = inheritsFromElement
}

View File

@ -5,8 +5,11 @@ path = sub ..., 1, len(...) - len "/box"
element = require "#{path}/element"
class box extends element
new: (pop, parent, background=false) =>
super pop, parent
new: (parent, background=false) =>
super parent
@w = 20
@h = 20
@background = background
@ -19,6 +22,7 @@ class box extends element
w, h = @background\getDimensions!
w = @w / w
h = @h / h
graphics.setColor 255, 255, 255, 255
graphics.draw @background, @x, @y, 0, w, h
return @

View File

@ -2,23 +2,29 @@ import graphics from love
import floor from math
class element
new: (pop, parent) =>
new: (parent) =>
@parent = parent
@child = {}
@w = 0
@h = 0
@margin = 0
if parent
@x = parent.x or 0
@y = parent.y or 0
@x = parent.x
@y = parent.y
--@horizontal = parent.horizontal
--@vertical = parent.vertical
--@align!
else
@x = 0
@y = 0
@w = 10
@h = 10
--@horizontal = "left"
--@vertical = "top"
@horizontal = "left"
@vertical = "top"
@margin = 0
debugDraw: =>
graphics.setLineWidth 0.5
@ -31,6 +37,15 @@ class element
return @
addChild: (child) =>
@child[#@child+1] = child
child.parent = @
return @
getChildren: =>
return @child
move: (x, y) =>
if x
@x = @x + x
@ -117,6 +132,34 @@ class element
getSize: =>
return @w, @h
setWidth: (w) =>
switch @horizontal
when "center"
@x -= (w - @w)/2
when "right"
@x -= w - @w
@w = w
return @
getWidth: =>
return @w
setHeight: (h) =>
switch @vertical
when "center"
@y -= (h - @h)/2
when "bottom"
@y -= h - @h
@h = h
return @
getHeight: =>
return @h
adjustSize: (w, h) =>
W, H = @getSize!
@ -130,7 +173,7 @@ class element
return @
--TODO note that align requires a parent!
align: (horizontal, vertical, toPixel) =>
align: (horizontal, vertical, toPixel=true) =>
@setAlignment horizontal, vertical
@x = @parent.x
@ -158,11 +201,11 @@ class element
return @
alignTo: (element, horizontal, vertical) =>
alignTo: (element, horizontal, vertical, toPixel=true) =>
parent = @parent
@parent = element
@align horizontal, vertical
@align horizontal, vertical, toPixel
@parent = parent
@ -176,6 +219,9 @@ class element
return @
getAlignment: =>
return @horizontal, @vertical
setMargin: (margin) =>
@margin = margin
@align!
@ -183,3 +229,9 @@ class element
getMargin: =>
return @margin
fill: =>
@x = @parent.x + @margin
@y = @parent.y + @margin
@w = @parent.w - @margin*2
@h = @parent.h - @margin*2

View File

@ -5,15 +5,16 @@ path = sub ..., 1, len(...) - len "/box"
element = require "#{path}/element"
class text extends element
wrap: (pop) ->
-- this should be completely unneccessary, but I'm keeping it just in case
@wrap = (pop) ->
return (parent, ...) ->
if type(parent) == "string"
return pop.create("text", nil, parent, ...)
else
return pop.create("text", parent, ...)
new: (pop, parent, text="", color={255,255,255,255}) =>
super pop, parent
new: (parent, text="", color={255,255,255,255}) =>
super parent
@font = graphics.newFont 14
@setText text
@ -22,7 +23,7 @@ class text extends element
draw: =>
graphics.setColor @color
graphics.setFont @font
graphics.print @text, @x, @y
graphics.print @txt, @x, @y
return @
@ -39,8 +40,8 @@ class text extends element
-- unlike most elements, you cannot set a size for text elements
setSize: =>
w = @font\getWidth @text
h = @font\getHeight! * (select(2, @text\gsub("\n", "\n")) + 1) --hack to get height of multiple lines
w = @font\getWidth @txt
h = @font\getHeight! * (select(2, @txt\gsub("\n", "\n")) + 1) --hack to get height of multiple lines
switch @horizontal
when "center"
@ -59,13 +60,23 @@ class text extends element
return @
-- cannot set width!
setWidth: =>
@setSize!
return @
-- cannot set height!
setHeight: =>
@setSize!
return @
setText: (text="") =>
@text = text
@txt = text
@setSize!
return @
getText: =>
return @text
return @txt
setFont: (font) =>
@font = font

View File

@ -0,0 +1,223 @@
import graphics from love
import sub, len from string
path = sub ..., 1, len(...) - len "/window"
element = require "#{path}/element"
box = require "#{path}/box"
text = require "#{path}/text"
-- version compatibility
left = 1 -- what is the left mouse button?
mousemoved_event = true -- is the mousemoved event available?
do
major, minor, revision = love.getVersion!
if (major == 0) and (minor == 10) and ((revision == 0) or (revision == 1))
left = 1 -- redundant, but whatever
elseif (major == 0) and (minor == 9)
left = "l"
if revision == 1
mousemoved_event = false
else
print "elements/window: unrecognized LOVE version: #{major}.#{minor}.#{revision}"
print " assuming LOVE version > 0.10.1 (there may be bugs)"
pop_ref = false -- reference to pop, loaded by pop.load!
class window extends element
load: (pop) ->
pop_ref = pop
--wrap: (pop) ->
-- pop_ref = pop -- set our reference to pop (needed for mouse handling)
-- return (...) -> -- standard wrapper, nothing special needed
-- return pop.create("window", ...)
new: (parent, title="window", tBackground={25, 180, 230, 255}, tColor={255, 255, 255, 255}, wBackground={200, 200, 210, 255}) =>
super parent
@head = box @, tBackground -- title box at top
@title = text @, title, tColor -- text at top
@window = box @, wBackground -- main window area
-- correct placement / sizes of elements
height = @title\getHeight!
@head\setSize @w, height
@window\move nil, height
@setSize 100, 80
-- our child elements are still child elements
--TODO change title to be a child of head ?
@child = {
@head, @title, @window
}
--@selected = false -- whether or not the window title (and thus, the window) has been selected
--NOTE all of these commented out, because I realized these event handlers should be attached to the title element
@head.selected = false -- whether or not the window title (and thus, the window) has been selected
if mousemoved_event
@head.mousemoved = (x, y, dx, dy) =>
if @selected
-- for some reason, y and dx are actually dx and dy...what the fuck? (note: in version 0.10.0)
@parent\move y, dx --dx, dy
return true
return false
@head.mousepressed = (x, y, button) =>
if button == left
@selected = true
return true
return false
@head.mousereleased = (x, y, button) =>
if button == left
@selected = false
pop_ref.focused = false -- clear our focus
return true
return false
else
@head.mx = 0 -- local mouse coordinates when selected
@head.my = 0
@head.update = =>
--TODO write me!
return false
@head.mousepressed = (x, y, button) =>
if button == left
@selected = true
@mx = x
@my = y
@head.mousereleased = (x, y, button) => -- this is actually the same for both versions...
if button == left
@selected = false
return true
return false
debugDraw: =>
graphics.setLineWidth 0.5
graphics.setColor 0, 0, 0, 100
graphics.rectangle "fill", @x, @y, @w, @h
graphics.setColor 200, 0, 200, 200
graphics.rectangle "line", @x, @y, @w, @h
graphics.setColor 255, 200, 255, 255
graphics.print "w", @x, @y
return @
addChild: (child) =>
@window.child[#@window.child+1] = child
child.parent = @window
return @
getChildren: =>
return @window.child
align: (horizontal, vertical, toPixel) =>
super horizontal, vertical, toPixel
for i = 1, #@child
@child[i]\align!
@window\move nil, @head\getHeight!
return @
--update: =>
-- if selected, set position based on current mouse position relative to position it was when mousepressed
--mousemoved: (x, y, dx, dy) =>
-- if selected, set position based on new mouse position relative to position it was when mousepressed
--mousepressed: (x, y, button) =>
-- if button == "l" -> selected = true, mouse position saved
--mousereleased: (x, y, button) =>
-- if button == "l" -> set position based on position relative to when mousepressed, selected == false
setSize: (w, h) =>
x = 0
y = 0
if w
switch @horizontal
when "center"
x -= (w - @w)/2
when "right"
x -= w - @w
@head\setWidth w
@window\setWidth w
@w = w
@x += x
@title\align!
if h
h = h - @head\getHeight!
switch @vertical
when "center"
y -= (h - @h)/2
when "right"
y -= h - @h
@window\setHeight h
@h = h + @head\getHeight!
@y += y
@head\move x, y
--@title\move x, y
@window\move x, y
return @
setWidth: (w) =>
x = 0
switch @horizontal
when "center"
x -= (w - @w)/2
when "right"
x -= w - @w
@head\setWidth w
@window\setWidth w
@w = w
@x += x
@title\align!
@head\move x
--@title\move x
@window\move x
return @
setHeight: (h) =>
y = 0
h = h - @head\getHeight!
switch @vertical
when "center"
y -= (h - @h)/2
when "right"
y -= h - @h
@window\setHeight h
@h = h + @head\getHeight!
@y += y
@head\move nil, y
@title\move nil, y
@window\move nil, y
return @
setTitle: (title) =>
@title\setText title
return @

View File

@ -0,0 +1,86 @@
-- adds methods to elements using a single function for get and set operations
-- ex: instead of getWidth() and setWidth(val), use width() and width(val)
import graphics from love
import sub, len from string
path = sub ..., 1, len(...) - len "/extensions/streamlined_get_set"
element = require "#{path}/elements/element"
box = require "#{path}/elements/box"
text = require "#{path}/elements/text"
element.__base.position = (x, y) =>
if x or y
return @setPosition x, y
else
return @getPosition!
element.__base.size = (w, h) =>
if w or h
return @setSize w, h
else
return @getSize!
element.__base.width = (w) =>
if w
return @setWidth w
else
return @getWidth!
element.__base.height = (h) =>
if h
return @setHeight h
else
return @getHeight!
element.__base.alignment = (horizontal, vertical) =>
if horizontal or vertical
return @setAlignment horizontal, vertical
else
return @getAlignment!
-- why is this bit here? Oo
element.__base.margin = (m) =>
if m
return @setMargin m
else
return @getMargin!
--oldinit = element.__init
--
--element.__init = (...) ->
-- object = oldinit ...
-- value = object.margin
--
-- object.margin = setmetatable {:value}, {
-- __call: (...) ->
-- print ...
-- }
element.__base.resize = element.__base.adjustSize
-- box.__base.background -- can't be done!
box.__base.color = (r, g, b, a) =>
if r or g or b or a
return @setColor r, g, b, a
else
return @getColor!
text.__base.text = (text) =>
if text
return @setText text
else
return @getText!
text.__base.font = (font) =>
if font
return @setFont font
else
return @getFont!
text.__base.color = (r, g, b, a) =>
if r or g or b or a
return @setColor r, g, b, a
else
return @getColor!

View File

@ -1,5 +1,9 @@
unless love.getVersion
error "Pop.Box only supports LOVE versions >= 0.9.1"
import filesystem, graphics from love
import insert from table
import inheritsFromElement from require "#{...}/util"
path = ...
@ -7,13 +11,15 @@ pop = {}
pop.elements = {}
pop.skins = {}
pop.events = {}
pop.screen = false -- initialized in pop.load()
--pop.focused ?
pop.focused = false
-- loads elements and skins, creates pop.screen (intended to only be called once at the beginning)
pop.load = ->
elements = filesystem.getDirectoryItems "#{path}/elements"
for i = 1, #elements
-- only attempt to load lua files
unless elements[i]\sub(-4) == ".lua"
@ -22,6 +28,10 @@ pop.load = ->
-- load into pop.elements table
name = elements[i]\sub 1, -5
pop.elements[name] = require "#{path}/elements/#{name}"
if pop.elements[name].load
pop.elements[name].load pop
print "element loaded: \"#{name}\""
-- create pop.element() wrapper if possible
@ -36,27 +46,47 @@ pop.load = ->
-- works just like above, except no wrappers
skins = filesystem.getDirectoryItems "#{path}/skins"
for i = 1, #skins
unless skins[i]\sub(-4) == ".lua"
continue
name = skins[i]\sub 1, -5
pop.skins[name] = require "#{path}/skins/#{name}"
print "skin loaded: \"#{name}\""
-- load extensions by just running them via require
extensions = filesystem.getDirectoryItems "#{path}/extensions"
for i = 1, #extensions
unless extensions[i]\sub(-4) == ".lua"
continue
name = extensions[i]\sub 1, -5
require "#{path}/extensions/#{name}"
print "extension loaded: \"#{name}\""
-- main window (called screen because there will be a window element class)
pop.screen = pop.create("element", false)\setSize(graphics.getWidth!, graphics.getHeight!)
print "created \"pop.screen\""
-- creates an element with specified parent (parent can be false)
-- creates an element with specified parent (parent can be false or non-existent)
pop.create = (element, parent=pop.screen, ...) ->
element = pop.elements[element](pop, parent, ...)
if parent
if inheritsFromElement parent
element = pop.elements[element](parent, ...)
insert parent.child, element
elseif parent == false
element = pop.elements[element](false, ...)
else
element = pop.elements[element](pop.screen, parent, ...)
insert pop.screen.child, element
return element
pop.update = (dt, element=pop.screen) ->
--pop.screen\update dt
unless element.excludeUpdate
if element.update
element\update dt
@ -64,19 +94,56 @@ pop.update = (dt, element=pop.screen) ->
pop.update dt, element.child[i]
pop.draw = (element=pop.screen) ->
--pop.screen\draw!
unless element.excludeDraw
if element.draw
element\draw!
for i = 1, #element.child
pop.draw element.child[i]
pop.mousepressed = (x, y, button, element=pop.screen) ->
print "mousepressed", x, y, button, element
return false --TODO event handlers return if they have handled the event!
pop.mousemoved = (x, y, dx, dy) =>
if pop.focused and pop.focused.mousemoved
return pop.focused\mousemoved x, y, dx, dy
pop.mousereleased = (x, y, button, element=pop.screen) ->
print "mousereleased", x, y, button, element
return false --TODO event handlers return if they have handled the event!
return false
pop.mousepressed = (x, y, button, element) ->
unless element
print "mousepressed", x, y, button
element = pop.screen
handled = false
if (x >= element.x) and (x <= element.x + element.w) and (y >= element.y) and (y <= element.y + element.h)
if element.mousepressed
handled = element\mousepressed x - element.x, y - element.y, button
if handled
pop.focused = element
pop.events[button] = element
else
for i = 1, #element.child
handled = pop.mousepressed x, y, button, element.child[i]
if handled
break
return handled
pop.mousereleased = (x, y, button) ->
print "mousereleased", x, y, button
clickedHandled = false
mousereleasedHandled = false
if element = pop.events[button]
if element.clicked and (x >= element.x) and (x <= element.x + element.w) and (y >= element.y) and (y <= element.y + element.h)
if clickedHandled = element\clicked x - element.x, y - element.y, button
pop.events[button] = nil
if element.mousereleased
if mousereleasedHandled = element\mousereleased x - element.x, y - element.y, button
pop.events[button] = nil
return clickedHandled, mousereleasedHandled
pop.keypressed = (key) ->
print "keypressed", key
@ -90,6 +157,8 @@ pop.textinput = (text) ->
print "textinput", text
return false --TODO event handlers return if they have handled the event!
--TODO rewrite skin system to not rely on knowing internals of elements,
-- instead call functions like setColor and setBackground
-- skins an element (and its children unless depth == true or 0)
-- depth can be an integer for how many levels to go down when skinning
-- defaults to pop.screen and the default skin

View File

@ -1,3 +1,6 @@
-- Note that the "default" name is a bit of a misnomer, as this does not
-- specify the defaults used in Pop.Box elements (they define their own)
import graphics from love
return {

17
src/pop/util.moon Normal file
View File

@ -0,0 +1,17 @@
inheritsFromElement = (object) ->
if object and object.__class
cls = object.__class
if cls.__name == "element"
return true
while cls.__parent
cls = cls.__parent
if cls.__name == "element"
return true
return false
return {
:inheritsFromElement
}