LoveFrames/objects/base.lua
2014-08-10 14:40:30 -04:00

1271 lines
28 KiB
Lua

--[[------------------------------------------------
-- Love Frames - A GUI library for LOVE --
-- Copyright (c) 2012-2014 Kenny Shields --
--]]------------------------------------------------
-- base object
local newobject = loveframes.NewObject("base", "loveframes_object_base")
--[[---------------------------------------------------------
- func: initialize()
- desc: initializes the element
--]]---------------------------------------------------------
function newobject:initialize()
-- width and height of the window
local w = love.graphics.getWidth()
local h = love.graphics.getHeight()
self.type = "base"
self.width = w
self.height = h
self.internal = true
self.children = {}
self.internals = {}
end
--[[---------------------------------------------------------
- func: update(deltatime)
- desc: updates the object
--]]---------------------------------------------------------
function newobject:update(dt)
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local width, height = love.graphics.getDimensions()
if self.width ~= width then
self.width = width
end
if self.height ~= height then
self.height = height
end
local children = self.children
local internals = self.internals
for k, v in ipairs(children) do
v:update(dt)
end
for k, v in ipairs(internals) do
v:update(dt)
end
end
--[[---------------------------------------------------------
- func: draw()
- desc: draws the object
--]]---------------------------------------------------------
function newobject:draw()
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local children = self.children
local internals = self.internals
-- set the object's draw order
self:SetDrawOrder()
for k, v in ipairs(children) do
v:draw()
end
for k, v in ipairs(internals) do
v:draw()
end
end
--[[---------------------------------------------------------
- func: mousepressed(x, y, button)
- desc: called when the player presses a mouse button
--]]---------------------------------------------------------
function newobject:mousepressed(x, y, button)
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local visible = self.visible
local children = self.children
local internals = self.internals
if not visible then
return
end
if children then
for k, v in ipairs(children) do
v:mousepressed(x, y, button)
end
end
if internals then
for k, v in ipairs(internals) do
v:mousepressed(x, y, button)
end
end
end
--[[---------------------------------------------------------
- func: mousereleased(x, y, button)
- desc: called when the player releases a mouse button
--]]---------------------------------------------------------
function newobject:mousereleased(x, y, button)
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local visible = self.visible
local children = self.children
local internals = self.internals
if not visible then
return
end
if children then
for k, v in ipairs(children) do
v:mousereleased(x, y, button)
end
end
if internals then
for k, v in ipairs(internals) do
v:mousereleased(x, y, button)
end
end
end
--[[---------------------------------------------------------
- func: keypressed(key, isrepeat)
- desc: called when the player presses a key
--]]---------------------------------------------------------
function newobject:keypressed(key, isrepeat)
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local visible = self.visible
local children = self.children
local internals = self.internals
if not visible then
return
end
if children then
for k, v in ipairs(children) do
v:keypressed(key, unicode)
end
end
if internals then
for k, v in ipairs(internals) do
v:keypressed(key, unicode)
end
end
end
--[[---------------------------------------------------------
- func: keyreleased(key)
- desc: called when the player releases a key
--]]---------------------------------------------------------
function newobject:keyreleased(key)
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local visible = self.visible
local children = self.children
local internals = self.internals
if not visible then
return
end
if children then
for k, v in ipairs(children) do
v:keyreleased(key)
end
end
if internals then
for k, v in ipairs(internals) do
v:keyreleased(key)
end
end
end
--[[---------------------------------------------------------
- func: textinput(text)
- desc: called when the user inputs text
--]]---------------------------------------------------------
function newobject:textinput(text)
local state = loveframes.state
local selfstate = self.state
if state ~= selfstate then
return
end
local visible = self.visible
local children = self.children
local internals = self.internals
if not visible then
return
end
if children then
for k, v in ipairs(children) do
v:textinput(text)
end
end
if internals then
for k, v in ipairs(internals) do
v:textinput(text)
end
end
end
--[[---------------------------------------------------------
- func: SetPos(x, y, center)
- desc: sets the object's position
--]]---------------------------------------------------------
function newobject:SetPos(x, y, center)
local base = loveframes.base
local parent = self.parent
if center then
local width = self.width
local height = self.height
x = x - width/2
y = y - height/2
end
if parent == base then
self.x = x
self.y = y
else
self.staticx = x
self.staticy = y
end
return self
end
--[[---------------------------------------------------------
- func: SetX(x, center)
- desc: sets the object's x position
--]]---------------------------------------------------------
function newobject:SetX(x, center)
local base = loveframes.base
local parent = self.parent
if center then
local width = self.width
x = x - width/2
end
if parent == base then
self.x = x
else
self.staticx = x
end
return self
end
--[[---------------------------------------------------------
- func: SetY(y, center)
- desc: sets the object's y position
--]]---------------------------------------------------------
function newobject:SetY(y, center)
local base = loveframes.base
local parent = self.parent
if center then
local height = self.height
y = y - height/2
end
if parent == base then
self.y = y
else
self.staticy = y
end
return self
end
--[[---------------------------------------------------------
- func: GetPos()
- desc: gets the object's position
--]]---------------------------------------------------------
function newobject:GetPos()
return self.x, self.y
end
--[[---------------------------------------------------------
- func: GetX()
- desc: gets the object's x position
--]]---------------------------------------------------------
function newobject:GetX()
return self.x
end
--[[---------------------------------------------------------
- func: GetY()
- desc: gets the object's y position
--]]---------------------------------------------------------
function newobject:GetY()
return self.y
end
--[[---------------------------------------------------------
- func: GetStaticPos()
- desc: gets the object's static position
--]]---------------------------------------------------------
function newobject:GetStaticPos()
return self.staticx, self.staticy
end
--[[---------------------------------------------------------
- func: GetStaticX()
- desc: gets the object's static x position
--]]---------------------------------------------------------
function newobject:GetStaticX()
return self.staticx
end
--[[---------------------------------------------------------
- func: GetStaticY()
- desc: gets the object's static y position
--]]---------------------------------------------------------
function newobject:GetStaticY()
return self.staticy
end
--[[---------------------------------------------------------
- func: Center()
- desc: centers the object in the game window or in
its parent if it has one
--]]---------------------------------------------------------
function newobject:Center()
local base = loveframes.base
local parent = self.parent
if parent == base then
local width = love.graphics.getWidth()
local height = love.graphics.getHeight()
self.x = width/2 - self.width/2
self.y = height/2 - self.height/2
else
local width = parent.width
local height = parent.height
self.staticx = width/2 - self.width/2
self.staticy = height/2 - self.height/2
end
return self
end
--[[---------------------------------------------------------
- func: CenterX()
- desc: centers the object by its x value
--]]---------------------------------------------------------
function newobject:CenterX()
local base = loveframes.base
local parent = self.parent
if parent == base then
local width = love.graphics.getWidth()
self.x = width/2 - self.width/2
else
local width = parent.width
self.staticx = width/2 - self.width/2
end
return self
end
--[[---------------------------------------------------------
- func: CenterY()
- desc: centers the object by its y value
--]]---------------------------------------------------------
function newobject:CenterY()
local base = loveframes.base
local parent = self.parent
if parent == base then
local height = love.graphics.getHeight()
self.y = height/2 - self.height/2
else
local height = parent.height
self.staticy = height/2 - self.height/2
end
return self
end
--[[---------------------------------------------------------
- func: CenterWithinArea()
- desc: centers the object within the given area
--]]---------------------------------------------------------
function newobject:CenterWithinArea(x, y, width, height)
local selfwidth = self.width
local selfheight = self.height
self.x = x + width/2 - selfwidth/2
self.y = y + height/2 - selfheight/2
return self
end
--[[---------------------------------------------------------
- func: SetSize(width, height, r1, r2)
- desc: sets the object's size
--]]---------------------------------------------------------
function newobject:SetSize(width, height, r1, r2)
if r1 then
self.width = self.parent.width * width
else
self.width = width
end
if r2 then
self.height = self.parent.height * height
else
self.height = height
end
return self
end
--[[---------------------------------------------------------
- func: SetWidth(width, relative)
- desc: sets the object's width
--]]---------------------------------------------------------
function newobject:SetWidth(width, relative)
if relative then
self.width = self.parent.width * width
else
self.width = width
end
return self
end
--[[---------------------------------------------------------
- func: SetHeight(height, relative)
- desc: sets the object's height
--]]---------------------------------------------------------
function newobject:SetHeight(height, relative)
if relative then
self.height = self.parent.height * height
else
self.height = height
end
return self
end
--[[---------------------------------------------------------
- func: GetSize()
- desc: gets the object's size
--]]---------------------------------------------------------
function newobject:GetSize()
return self.width, self.height
end
--[[---------------------------------------------------------
- func: GetWidth()
- desc: gets the object's width
--]]---------------------------------------------------------
function newobject:GetWidth()
return self.width
end
--[[---------------------------------------------------------
- func: GetHeight()
- desc: gets the object's height
--]]---------------------------------------------------------
function newobject:GetHeight()
return self.height
end
--[[---------------------------------------------------------
- func: SetVisible(bool)
- desc: sets the object's visibility
--]]---------------------------------------------------------
function newobject:SetVisible(bool)
local children = self.children
local internals = self.internals
self.visible = bool
if children then
for k, v in ipairs(children) do
v:SetVisible(bool)
end
end
if internals then
for k, v in ipairs(internals) do
v:SetVisible(bool)
end
end
return self
end
--[[---------------------------------------------------------
- func: GetVisible()
- desc: gets the object's visibility
--]]---------------------------------------------------------
function newobject:GetVisible()
return self.visible
end
--[[---------------------------------------------------------
- func: SetParent(parent)
- desc: sets the object's parent
--]]---------------------------------------------------------
function newobject:SetParent(parent)
local tparent = parent
local cparent = self.parent
local ptype = tparent.type
local stype = self.type
if ptype ~= "frame" and ptype ~= "panel" and ptype ~= "list" then
return
end
self:Remove()
self.parent = tparent
self:SetState(tparent.state)
table.insert(tparent.children, self)
return self
end
--[[---------------------------------------------------------
- func: GetParent()
- desc: gets the object's parent
--]]---------------------------------------------------------
function newobject:GetParent()
local parent = self.parent
return parent
end
--[[---------------------------------------------------------
- func: Remove()
- desc: removes the object
--]]---------------------------------------------------------
function newobject:Remove()
local pinternals = self.parent.internals
local pchildren = self.parent.children
if pinternals then
for k, v in ipairs(pinternals) do
if v == self then
table.remove(pinternals, k)
end
end
end
if pchildren then
for k, v in ipairs(pchildren) do
if v == self then
table.remove(pchildren, k)
end
end
end
return self
end
--[[---------------------------------------------------------
- func: SetClickBounds(x, y, width, height)
- desc: sets a boundary box for the object's collision
detection
--]]---------------------------------------------------------
function newobject:SetClickBounds(x, y, width, height)
local internals = self.internals
local children = self.children
self.clickbounds = {x = x, y = y, width = width, height = height}
if internals then
for k, v in ipairs(internals) do
v:SetClickBounds(x, y, width, height)
end
end
if children then
for k, v in ipairs(children) do
v:SetClickBounds(x, y, width, height)
end
end
return self
end
--[[---------------------------------------------------------
- func: GetClickBounds()
- desc: gets the boundary box for the object's collision
detection
--]]---------------------------------------------------------
function newobject:GetClickBounds()
return self.clickbounds
end
--[[---------------------------------------------------------
- func: RemoveClickBounds()
- desc: removes the collision detection boundary for the
object
--]]---------------------------------------------------------
function newobject:RemoveClickBounds()
local internals = self.internals
local children = self.children
self.clickbounds = nil
if internals then
for k, v in ipairs(internals) do
v:RemoveClickBounds()
end
end
if children then
for k, v in ipairs(children) do
v:RemoveClickBounds()
end
end
return self
end
--[[---------------------------------------------------------
- func: InClickBounds()
- desc: checks if the mouse is inside the object's
collision detection boundaries
--]]---------------------------------------------------------
function newobject:InClickBounds()
local x, y = love.mouse.getPosition()
local bounds = self.clickbounds
if bounds then
local col = loveframes.util.BoundingBox(x, bounds.x, y, bounds.y, 1, bounds.width, 1, bounds.height)
return col
else
return false
end
return self
end
--[[---------------------------------------------------------
- func: GetBaseParent(object, t)
- desc: finds the object's base parent
--]]---------------------------------------------------------
function newobject:GetBaseParent(t)
local t = t or {}
local base = loveframes.base
local parent = self.parent
if parent ~= base then
table.insert(t, parent)
parent:GetBaseParent(t)
end
return t[#t]
end
--[[---------------------------------------------------------
- func: CheckHover()
- desc: checks to see if the object should be in a
hover state
--]]---------------------------------------------------------
function newobject:CheckHover()
local x = self.x
local y = self.y
local width = self.width
local height = self.height
local mx, my = love.mouse.getPosition()
local selfcol = loveframes.util.BoundingBox(mx, x, my, y, 1, width, 1, height)
local collisioncount = loveframes.collisioncount
local curstate = loveframes.state
local state = self.state
local visible = self.visible
local type = self.type
local hoverobject = loveframes.hoverobject
-- check if the mouse is colliding with the object
if state == curstate and visible then
local collide = self.collide
if selfcol and collide then
loveframes.collisioncount = collisioncount + 1
local clickbounds = self.clickbounds
if clickbounds then
local cx = clickbounds.x
local cy = clickbounds.y
local cwidth = clickbounds.width
local cheight = clickbounds.height
local clickcol = loveframes.util.BoundingBox(mx, cx, my, cy, 1, cwidth, 1, cheight)
if clickcol then
table.insert(loveframes.collisions, self)
end
else
table.insert(loveframes.collisions, self)
end
end
end
-- check if the object is being hovered
if hoverobject == self and type ~= "base" then
self.hover = true
else
self.hover = false
end
local hover = self.hover
local calledmousefunc = self.calledmousefunc
-- check for mouse enter and exit events
if hover then
loveframes.hover = true
if not calledmousefunc then
local on_mouse_enter = self.OnMouseEnter
if on_mouse_enter then
on_mouse_enter(self)
self.calledmousefunc = true
else
self.calledmousefunc = true
end
end
else
if calledmousefunc then
local on_mouse_exit = self.OnMouseExit
if on_mouse_exit then
on_mouse_exit(self)
self.calledmousefunc = false
else
self.calledmousefunc = false
end
end
end
end
--[[---------------------------------------------------------
- func: GetHover()
- desc: return if the object is in a hover state or not
--]]---------------------------------------------------------
function newobject:GetHover()
return self.hover
end
--[[---------------------------------------------------------
- func: GetChildren()
- desc: returns the object's children
--]]---------------------------------------------------------
function newobject:GetChildren()
local children = self.children
if children then
return children
end
end
--[[---------------------------------------------------------
- func: GetInternals()
- desc: returns the object's internals
--]]---------------------------------------------------------
function newobject:GetInternals()
local internals = self.internals
if internals then
return internals
end
end
--[[---------------------------------------------------------
- func: IsTopList()
- desc: returns true if the object is the top most list
object or false if not
--]]---------------------------------------------------------
function newobject:IsTopList()
local cols = loveframes.util.GetCollisions()
local children = self:GetChildren()
local order = self.draworder
local top = true
local found = false
local function IsChild(object)
local parents = object:GetParents()
for k, v in ipairs(parents) do
if v == self then
return true
end
end
return false
end
for k, v in ipairs(cols) do
if v == self then
found = true
else
if v.draworder > order then
if IsChild(v) ~= true then
top = false
break
end
end
end
end
if found == false then
top = false
end
return top
end
--[[---------------------------------------------------------
- func: IsTopChild()
- desc: returns true if the object is the top most child
in its parent's children table or false if not
--]]---------------------------------------------------------
function newobject:IsTopChild()
local children = self.parent.children
local num = #children
if children[num] == self then
return true
else
return false
end
end
--[[---------------------------------------------------------
- func: MoveToTop()
- desc: moves the object to the top of its parent's
children table
--]]---------------------------------------------------------
function newobject:MoveToTop()
local pchildren = self.parent.children
local pinternals = self.parent.internals
local internal = false
if pinternals then
for k, v in ipairs(pinternals) do
if v == self then
internal = true
end
end
end
self:Remove()
if internal then
table.insert(pinternals, self)
else
table.insert(pchildren, self)
end
return self
end
--[[---------------------------------------------------------
- func: SetSkin(name)
- desc: sets the object's skin
--]]---------------------------------------------------------
function newobject:SetSkin(name)
local children = self.children
local internals = self.internals
self.skin = name
if children then
for k, v in ipairs(children) do
v:SetSkin(name)
end
end
if internals then
for k, v in ipairs(internals) do
v:SetSkin(name)
end
end
return self
end
--[[---------------------------------------------------------
- func: GetSkin()
- desc: gets the object's skin
--]]---------------------------------------------------------
function newobject:GetSkin()
local skins = loveframes.skins.available
local skinindex = loveframes.config["ACTIVESKIN"]
local defaultskin = loveframes.config["DEFAULTSKIN"]
local selfskin = self.skin
local skin = skins[selfskin] or skins[skinindex]
return skin
end
--[[---------------------------------------------------------
- func: GetSkinName()
- desc: gets the name of the object's skin
--]]---------------------------------------------------------
function newobject:GetSkinName()
return self.skin
end
--[[---------------------------------------------------------
- func: SetAlwaysUpdate(bool)
- desc: sets the object's skin
--]]---------------------------------------------------------
function newobject:SetAlwaysUpdate(bool)
self.alwaysupdate = bool
return self
end
--[[---------------------------------------------------------
- func: GetAlwaysUpdate()
- desc: gets whether or not the object will always update
--]]---------------------------------------------------------
function newobject:GetAlwaysUpdate()
return self.alwaysupdate
end
--[[---------------------------------------------------------
- func: SetRetainSize(bool)
- desc: sets whether or not the object should retain its
size when another object tries to resize it
--]]---------------------------------------------------------
function newobject:SetRetainSize(bool)
self.retainsize = bool
return self
end
--[[---------------------------------------------------------
- func: GetRetainSize()
- desc: gets whether or not the object should retain its
size when another object tries to resize it
--]]---------------------------------------------------------
function newobject:GetRetainSize()
return self.retainsize
end
--[[---------------------------------------------------------
- func: IsActive()
- desc: gets whether or not the object is active within
its parent's child table
--]]---------------------------------------------------------
function newobject:IsActive()
local parent = self.parent
local pchildren = parent.children
local valid = false
for k, v in ipairs(pchildren) do
if v == self then
valid = true
end
end
return valid
end
--[[---------------------------------------------------------
- func: GetParents()
- desc: returns a table of the object's parents and its
sub-parents
--]]---------------------------------------------------------
function newobject:GetParents()
local function GetParents(object, t)
local t = t or {}
local type = object.type
local parent = object.parent
if type ~= "base" then
table.insert(t, parent)
GetParents(parent, t)
end
return t
end
local parents = GetParents(self)
return parents
end
--[[---------------------------------------------------------
- func: IsTopInternal()
- desc: returns true if the object is the top most
internal in its parent's internals table or
false if not
--]]---------------------------------------------------------
function newobject:IsTopInternal()
local parent = self.parent
local internals = parent.internals
local topitem = internals[#internals]
if topitem ~= self then
return false
else
return true
end
end
--[[---------------------------------------------------------
- func: IsInternal()
- desc: returns true if the object is internal or
false if not
--]]---------------------------------------------------------
function newobject:IsInternal()
return self.internal
end
--[[---------------------------------------------------------
- func: GetType()
- desc: gets the type of the object
--]]---------------------------------------------------------
function newobject:GetType()
return self.type
end
--[[---------------------------------------------------------
- func: SetDrawOrder()
- desc: sets the object's draw order
--]]---------------------------------------------------------
function newobject:SetDrawOrder()
loveframes.drawcount = loveframes.drawcount + 1
self.draworder = loveframes.drawcount
return self
end
--[[---------------------------------------------------------
- func: GetDrawOrder()
- desc: sets the object's draw order
--]]---------------------------------------------------------
function newobject:GetDrawOrder()
return self.draworder
end
--[[---------------------------------------------------------
- func: SetProperty(name, value)
- desc: sets a property on the object
--]]---------------------------------------------------------
function newobject:SetProperty(name, value)
self[name] = value
return self
end
--[[---------------------------------------------------------
- func: GetProperty(name)
- desc: gets the value of an object's property
--]]---------------------------------------------------------
function newobject:GetProperty(name)
return self[name]
end
--[[---------------------------------------------------------
- func: IsInList()
- desc: checks to see if an object is in a list
--]]---------------------------------------------------------
function newobject:IsInList()
local parents = self:GetParents()
for k, v in ipairs(parents) do
if v.type == "list" then
return true, v
end
end
return false, false
end
--[[---------------------------------------------------------
- func: SetState(name)
- desc: sets the object's state
--]]---------------------------------------------------------
function newobject:SetState(name)
local children = self.children
local internals = self.internals
self.state = name
if children then
for k, v in ipairs(children) do
v:SetState(name)
end
end
if internals then
for k, v in ipairs(internals) do
v:SetState(name)
end
end
return self
end
--[[---------------------------------------------------------
- func: GetState()
- desc: gets the object's state
--]]---------------------------------------------------------
function newobject:GetState()
return self.state
end