646 lines
20 KiB
Lua
646 lines
20 KiB
Lua
local utils = require("utils")
|
|
local tHex = require("tHex")
|
|
|
|
local sub, find, insert = string.sub, string.find, table.insert
|
|
|
|
return function(name, basalt)
|
|
local base = basalt.getObject("Object")(name, basalt)
|
|
-- Base object
|
|
local objectType = "VisualObject" -- not changeable
|
|
|
|
local isVisible,ignOffset,isHovered,isClicked,isDragging = true,false,false,false,false
|
|
local zIndex = 1
|
|
|
|
local x, y, width, height = 1,1,1,1
|
|
local dragStartX, dragStartY, dragXOffset, dragYOffset = 0, 0, 0, 0
|
|
|
|
local bgColor,fgColor, transparency = colors.black, colors.white, false
|
|
local parent
|
|
|
|
local preDrawQueue = {}
|
|
local drawQueue = {}
|
|
local postDrawQueue = {}
|
|
|
|
local renderObject = {}
|
|
|
|
local function split(str, d)
|
|
local result = {}
|
|
if str == "" then
|
|
return result
|
|
end
|
|
d = d or " "
|
|
local start = 1
|
|
local delim_start, delim_end = find(str, d, start)
|
|
while delim_start do
|
|
insert(result, {x=start, value=sub(str, start, delim_start - 1)})
|
|
start = delim_end + 1
|
|
delim_start, delim_end = find(str, d, start)
|
|
end
|
|
insert(result, {x=start, value=sub(str, start)})
|
|
return result
|
|
end
|
|
|
|
|
|
local object = {
|
|
getType = function(self)
|
|
return objectType
|
|
end,
|
|
|
|
getBase = function(self)
|
|
return base
|
|
end,
|
|
|
|
isType = function(self, t)
|
|
return objectType==t or base.isType~=nil and base.isType(t) or false
|
|
end,
|
|
|
|
getBasalt = function(self)
|
|
return basalt
|
|
end,
|
|
|
|
show = function(self)
|
|
isVisible = true
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
hide = function(self)
|
|
isVisible = false
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
isVisible = function(self)
|
|
return isVisible
|
|
end,
|
|
|
|
setVisible = function(self, _isVisible)
|
|
isVisible = _isVisible or not isVisible
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
setTransparency = function(self, _transparency)
|
|
transparency = _transparency~= nil and _transparency or true
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
setParent = function(self, newParent, noRemove)
|
|
base.setParent(self, newParent, noRemove)
|
|
parent = newParent
|
|
return self
|
|
end,
|
|
|
|
setFocus = function(self)
|
|
if (parent ~= nil) then
|
|
parent:setFocusedChild(self)
|
|
end
|
|
return self
|
|
end,
|
|
|
|
setZIndex = function(self, index)
|
|
zIndex = index
|
|
if (parent ~= nil) then
|
|
parent:updateZIndex(self, zIndex)
|
|
self:updateDraw()
|
|
end
|
|
return self
|
|
end,
|
|
|
|
getZIndex = function(self)
|
|
return zIndex
|
|
end,
|
|
|
|
updateDraw = function(self)
|
|
if (parent ~= nil) then
|
|
parent:updateDraw()
|
|
end
|
|
return self
|
|
end,
|
|
|
|
setPosition = function(self, xPos, yPos, rel)
|
|
local curX, curY = x, y
|
|
if(type(xPos)=="number")then
|
|
x = rel and x+xPos or xPos
|
|
end
|
|
if(type(yPos)=="number")then
|
|
y = rel and y+yPos or yPos
|
|
end
|
|
if(parent~=nil)then parent:customEventHandler("basalt_FrameReposition", self) end
|
|
if(self:getType()=="Container")then parent:customEventHandler("basalt_FrameReposition", self) end
|
|
self:updateDraw()
|
|
self:repositionHandler(curX, curY)
|
|
return self
|
|
end,
|
|
|
|
getX = function(self)
|
|
return x
|
|
end,
|
|
|
|
setX = function(self, newX)
|
|
return self:setPosition(newX, y)
|
|
end,
|
|
|
|
getY = function(self)
|
|
return y
|
|
end,
|
|
|
|
setY = function(self, newY)
|
|
return self:setPosition(x, newY)
|
|
end,
|
|
|
|
getPosition = function(self)
|
|
return x, y
|
|
end,
|
|
|
|
setSize = function(self, newWidth, newHeight, rel)
|
|
local oldW, oldH = width, height
|
|
if(type(newWidth)=="number")then
|
|
width = rel and width+newWidth or newWidth
|
|
end
|
|
if(type(newHeight)=="number")then
|
|
height = rel and height+newHeight or newHeight
|
|
end
|
|
if(parent~=nil)then
|
|
parent:customEventHandler("basalt_FrameResize", self)
|
|
if(self:getType()=="Container")then parent:customEventHandler("basalt_FrameResize", self) end
|
|
end
|
|
self:resizeHandler(oldW, oldH)
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
getHeight = function(self)
|
|
return height
|
|
end,
|
|
|
|
setHeight = function(self, newHeight)
|
|
return self:setSize(width, newHeight)
|
|
end,
|
|
|
|
getWidth = function(self)
|
|
return width
|
|
end,
|
|
|
|
setWidth = function(self, newWidth)
|
|
return self:setSize(newWidth, height)
|
|
end,
|
|
|
|
getSize = function(self)
|
|
return width, height
|
|
end,
|
|
|
|
setBackground = function(self, color)
|
|
bgColor = color
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
getBackground = function(self)
|
|
return bgColor
|
|
end,
|
|
|
|
setForeground = function(self, color)
|
|
fgColor = color or false
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
getForeground = function(self)
|
|
return fgColor
|
|
end,
|
|
|
|
getAbsolutePosition = function(self, x, y)
|
|
-- relative position to absolute position
|
|
if (x == nil) or (y == nil) then
|
|
x, y = self:getPosition()
|
|
end
|
|
|
|
if (parent ~= nil) then
|
|
local fx, fy = parent:getAbsolutePosition()
|
|
x = fx + x - 1
|
|
y = fy + y - 1
|
|
end
|
|
return x, y
|
|
end,
|
|
|
|
ignoreOffset = function(self, ignore)
|
|
ignOffset = ignore
|
|
if(ignore==nil)then ignOffset = true end
|
|
return self
|
|
end,
|
|
|
|
getIgnoreOffset = function(self)
|
|
return ignOffset
|
|
end,
|
|
|
|
isCoordsInObject = function(self, x, y)
|
|
if(isVisible)and(self:isEnabled())then
|
|
if(x==nil)or(y==nil)then return false end
|
|
local objX, objY = self:getAbsolutePosition()
|
|
local w, h = self:getSize()
|
|
if (objX <= x) and (objX + w > x) and (objY <= y) and (objY + h > y) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end,
|
|
|
|
onGetFocus = function(self, ...)
|
|
for _,v in pairs(table.pack(...))do
|
|
if(type(v)=="function")then
|
|
self:registerEvent("get_focus", v)
|
|
end
|
|
end
|
|
return self
|
|
end,
|
|
|
|
onLoseFocus = function(self, ...)
|
|
for _,v in pairs(table.pack(...))do
|
|
if(type(v)=="function")then
|
|
self:registerEvent("lose_focus", v)
|
|
end
|
|
end
|
|
return self
|
|
end,
|
|
|
|
isFocused = function(self)
|
|
if (parent ~= nil) then
|
|
return parent:getFocused() == self
|
|
end
|
|
return true
|
|
end,
|
|
|
|
resizeHandler = function(self, ...)
|
|
if(self:isEnabled())then
|
|
local val = self:sendEvent("basalt_resize", ...)
|
|
if(val==false)then return false end
|
|
end
|
|
return true
|
|
end,
|
|
|
|
repositionHandler = function(self, ...)
|
|
if(self:isEnabled())then
|
|
local val = self:sendEvent("basalt_reposition", ...)
|
|
if(val==false)then return false end
|
|
end
|
|
return true
|
|
end,
|
|
|
|
onResize = function(self, ...)
|
|
for _,v in pairs(table.pack(...))do
|
|
if(type(v)=="function")then
|
|
self:registerEvent("basalt_resize", v)
|
|
end
|
|
end
|
|
return self
|
|
end,
|
|
|
|
onReposition = function(self, ...)
|
|
for _,v in pairs(table.pack(...))do
|
|
if(type(v)=="function")then
|
|
self:registerEvent("basalt_reposition", v)
|
|
end
|
|
end
|
|
return self
|
|
end,
|
|
|
|
mouseHandler = function(self, button, x, y, isMon)
|
|
if(self:isCoordsInObject(x, y))then
|
|
local objX, objY = self:getAbsolutePosition()
|
|
local val = self:sendEvent("mouse_click", button, x - (objX-1), y - (objY-1), x, y, isMon)
|
|
if(val==false)then return false end
|
|
if(parent~=nil)then
|
|
parent:setFocusedChild(self)
|
|
end
|
|
isClicked = true
|
|
isDragging = true
|
|
dragStartX, dragStartY = x, y
|
|
return true
|
|
end
|
|
end,
|
|
|
|
mouseUpHandler = function(self, button, x, y)
|
|
isDragging = false
|
|
if(isClicked)then
|
|
local objX, objY = self:getAbsolutePosition()
|
|
local val = self:sendEvent("mouse_release", button, x - (objX-1), y - (objY-1), x, y)
|
|
isClicked = false
|
|
end
|
|
if(self:isCoordsInObject(x, y))then
|
|
local objX, objY = self:getAbsolutePosition()
|
|
local val = self:sendEvent("mouse_up", button, x - (objX-1), y - (objY-1), x, y)
|
|
if(val==false)then return false end
|
|
return true
|
|
end
|
|
end,
|
|
|
|
dragHandler = function(self, button, x, y)
|
|
if(isDragging)then
|
|
local objX, objY = self:getAbsolutePosition()
|
|
local val = self:sendEvent("mouse_drag", button, x - (objX-1), y - (objY-1), dragStartX-x, dragStartY-y, x, y)
|
|
dragStartX, dragStartY = x, y
|
|
if(val~=nil)then return val end
|
|
if(parent~=nil)then
|
|
parent:setFocusedChild(self)
|
|
end
|
|
return true
|
|
end
|
|
|
|
if(self:isCoordsInObject(x, y))then
|
|
local objX, objY = self:getAbsolutePosition()
|
|
dragStartX, dragStartY = x, y
|
|
dragXOffset, dragYOffset = objX - x, objY - y
|
|
end
|
|
end,
|
|
|
|
scrollHandler = function(self, dir, x, y)
|
|
if(self:isCoordsInObject(x, y))then
|
|
local objX, objY = self:getAbsolutePosition()
|
|
local val = self:sendEvent("mouse_scroll", dir, x - (objX-1), y - (objY-1))
|
|
if(val==false)then return false end
|
|
if(parent~=nil)then
|
|
parent:setFocusedChild(self)
|
|
end
|
|
return true
|
|
end
|
|
end,
|
|
|
|
hoverHandler = function(self, x, y, stopped)
|
|
if(self:isCoordsInObject(x, y))then
|
|
local val = self:sendEvent("mouse_hover", x, y, stopped)
|
|
if(val==false)then return false end
|
|
isHovered = true
|
|
return true
|
|
end
|
|
if(isHovered)then
|
|
local val = self:sendEvent("mouse_leave", x, y, stopped)
|
|
if(val==false)then return false end
|
|
isHovered = false
|
|
end
|
|
end,
|
|
|
|
keyHandler = function(self, key, isHolding)
|
|
if(self:isEnabled())and(isVisible)then
|
|
if (self:isFocused()) then
|
|
local val = self:sendEvent("key", key, isHolding)
|
|
if(val==false)then return false end
|
|
return true
|
|
end
|
|
end
|
|
end,
|
|
|
|
keyUpHandler = function(self, key)
|
|
if(self:isEnabled())and(isVisible)then
|
|
if (self:isFocused()) then
|
|
local val = self:sendEvent("key_up", key)
|
|
if(val==false)then return false end
|
|
return true
|
|
end
|
|
end
|
|
end,
|
|
|
|
charHandler = function(self, char)
|
|
if(self:isEnabled())and(isVisible)then
|
|
if(self:isFocused())then
|
|
local val = self:sendEvent("char", char)
|
|
if(val==false)then return false end
|
|
return true
|
|
end
|
|
end
|
|
end,
|
|
|
|
getFocusHandler = function(self)
|
|
local val = self:sendEvent("get_focus")
|
|
if(val~=nil)then return val end
|
|
return true
|
|
end,
|
|
|
|
loseFocusHandler = function(self)
|
|
isDragging = false
|
|
local val = self:sendEvent("lose_focus")
|
|
if(val~=nil)then return val end
|
|
return true
|
|
end,
|
|
|
|
addDraw = function(self, name, f, pos, typ, active)
|
|
local queue = (typ==nil or typ==1) and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue
|
|
pos = pos or #queue+1
|
|
if(name~=nil)then
|
|
for k,v in pairs(queue)do
|
|
if(v.name==name)then
|
|
table.remove(queue, k)
|
|
break
|
|
end
|
|
end
|
|
local t = {name=name, f=f, pos=pos, active=active~=nil and active or true}
|
|
table.insert(queue, pos, t)
|
|
end
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
addPreDraw = function(self, name, f, pos, typ)
|
|
self:addDraw(name, f, pos, 2)
|
|
return self
|
|
end,
|
|
|
|
addPostDraw = function(self, name, f, pos, typ)
|
|
self:addDraw(name, f, pos, 3)
|
|
return self
|
|
end,
|
|
|
|
setDrawState = function(self, name, state, typ)
|
|
local queue = (typ==nil or typ==1) and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue
|
|
for k,v in pairs(queue)do
|
|
if(v.name==name)then
|
|
v.active = state
|
|
break
|
|
end
|
|
end
|
|
self:updateDraw()
|
|
return self
|
|
end,
|
|
|
|
getDrawId = function(self, name, typ)
|
|
local queue = typ==1 and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue or drawQueue
|
|
for k,v in pairs(queue)do
|
|
if(v.name==name)then
|
|
return k
|
|
end
|
|
end
|
|
end,
|
|
|
|
addText = function(self, x, y, text)
|
|
local obj = self:getParent() or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
if not(transparency)then
|
|
obj:setText(x+xPos-1, y+yPos-1, text)
|
|
return
|
|
end
|
|
local t = split(text, "\0")
|
|
for k,v in pairs(t)do
|
|
if(v.value~="")and(v.value~="\0")then
|
|
obj:setText(x+v.x+xPos-2, y+yPos-1, v.value)
|
|
end
|
|
end
|
|
end,
|
|
|
|
addBG = function(self, x, y, bg, noText)
|
|
local obj = parent or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
if not(transparency)then
|
|
obj:setBG(x+xPos-1, y+yPos-1, bg)
|
|
return
|
|
end
|
|
local t = split(bg)
|
|
for k,v in pairs(t)do
|
|
if(v.value~="")and(v.value~=" ")then
|
|
if(noText~=true)then
|
|
obj:setText(x+v.x+xPos-2, y+yPos-1, (" "):rep(#v.value))
|
|
obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value)
|
|
else
|
|
table.insert(renderObject, {x=x+v.x-1,y=y,bg=v.value})
|
|
obj:setBG(x+xPos-1, y+yPos-1, fg)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
addFG = function(self, x, y, fg)
|
|
local obj = parent or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
if not(transparency)then
|
|
obj:setFG(x+xPos-1, y+yPos-1, fg)
|
|
return
|
|
end
|
|
local t = split(fg)
|
|
for k,v in pairs(t)do
|
|
if(v.value~="")and(v.value~=" ")then
|
|
obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value)
|
|
end
|
|
end
|
|
end,
|
|
|
|
addBlit = function(self, x, y, t, fg, bg)
|
|
local obj = parent or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
if not(transparency)then
|
|
obj:blit(x+xPos-1, y+yPos-1, t, fg, bg)
|
|
return
|
|
end
|
|
local _text = split(t, "\0")
|
|
local _fg = split(fg)
|
|
local _bg = split(bg)
|
|
for k,v in pairs(_text)do
|
|
if(v.value~="")or(v.value~="\0")then
|
|
obj:setText(x+v.x+xPos-2, y+yPos-1, v.value)
|
|
end
|
|
end
|
|
for k,v in pairs(_bg)do
|
|
if(v.value~="")or(v.value~=" ")then
|
|
obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value)
|
|
end
|
|
end
|
|
for k,v in pairs(_fg)do
|
|
if(v.value~="")or(v.value~=" ")then
|
|
obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value)
|
|
end
|
|
end
|
|
end,
|
|
|
|
addTextBox = function(self, x, y, w, h, text)
|
|
local obj = parent or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
obj:drawTextBox(x+xPos-1, y+yPos-1, w, h, text)
|
|
end,
|
|
|
|
addForegroundBox = function(self, x, y, w, h, col)
|
|
local obj = parent or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
obj:drawForegroundBox(x+xPos-1, y+yPos-1, w, h, col)
|
|
end,
|
|
|
|
addBackgroundBox = function(self, x, y, w, h, col)
|
|
local obj = parent or self
|
|
local xPos,yPos = self:getPosition()
|
|
if(parent~=nil)then
|
|
local xO, yO = parent:getOffset()
|
|
xPos = ignOffset and xPos or xPos - xO
|
|
yPos = ignOffset and yPos or yPos - yO
|
|
end
|
|
obj:drawBackgroundBox(x+xPos-1, y+yPos-1, w, h, col)
|
|
end,
|
|
|
|
render = function(self)
|
|
if (isVisible)then
|
|
self:redraw()
|
|
end
|
|
end,
|
|
|
|
redraw = function(self)
|
|
for k,v in pairs(preDrawQueue)do
|
|
if (v.active)then
|
|
v.f(self)
|
|
end
|
|
end
|
|
for k,v in pairs(drawQueue)do
|
|
if (v.active)then
|
|
v.f(self)
|
|
end
|
|
end
|
|
for k,v in pairs(postDrawQueue)do
|
|
if (v.active)then
|
|
v.f(self)
|
|
end
|
|
end
|
|
return true
|
|
end,
|
|
|
|
draw = function(self)
|
|
self:addDraw("base", function()
|
|
local w,h = self:getSize()
|
|
if(bgColor~=false)then
|
|
self:addTextBox(1, 1, w, h, " ")
|
|
self:addBackgroundBox(1, 1, w, h, bgColor)
|
|
end
|
|
if(fgColor~=false)then
|
|
self:addForegroundBox(1, 1, w, h, fgColor)
|
|
end
|
|
end, 1)
|
|
end,
|
|
}
|
|
object.__index = object
|
|
return setmetatable(object, base)
|
|
end |