Lots of shit
This commit is contained in:
231
lib/basalt/objects/BaseFrame.lua
Normal file
231
lib/basalt/objects/BaseFrame.lua
Normal file
@@ -0,0 +1,231 @@
|
||||
local drawSystem = require("basaltDraw")
|
||||
local utils = require("utils")
|
||||
|
||||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Container")(name, basalt)
|
||||
local objectType = "BaseFrame"
|
||||
|
||||
local xOffset, yOffset = 0, 0
|
||||
|
||||
local colorTheme = {}
|
||||
|
||||
local updateRender = true
|
||||
|
||||
local termObject = basalt.getTerm()
|
||||
local basaltDraw = drawSystem(termObject)
|
||||
|
||||
local xCursor, yCursor, cursorBlink, cursorColor = 1, 1, false, colors.white
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
setOffset = function(self, xOff, yOff)
|
||||
xOffset = xOff or xOffset
|
||||
yOffset = yOff or yOffset
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
setXOffset = function(self, newXOffset)
|
||||
return self:setOffset(newXOffset, nil)
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
setYOffset = function(self, newYOffset)
|
||||
return self:setOffset(nil, newYOffset)
|
||||
end,
|
||||
|
||||
setPalette = function(self, col, ...)
|
||||
if(self==basalt.getActiveFrame())then
|
||||
if(type(col)=="string")then
|
||||
colorTheme[col] = ...
|
||||
termObject.setPaletteColor(type(col)=="number" and col or colors[col], ...)
|
||||
elseif(type(col)=="table")then
|
||||
for k,v in pairs(col)do
|
||||
colorTheme[k] = v
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], v)
|
||||
else
|
||||
local r,g,b = table.unpack(v)
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setSize = function(self, ...)
|
||||
base.setSize(self, ...)
|
||||
basaltDraw = drawSystem(termObject)
|
||||
return self
|
||||
end,
|
||||
|
||||
getSize = function()
|
||||
return termObject.getSize()
|
||||
end,
|
||||
|
||||
getWidth = function(self)
|
||||
return ({termObject.getSize()})[1]
|
||||
end,
|
||||
|
||||
getHeight = function(self)
|
||||
return ({termObject.getSize()})[2]
|
||||
end,
|
||||
|
||||
show = function(self)
|
||||
base.show(self)
|
||||
basalt.setActiveFrame(self)
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(v, colors.packRGB(term.nativePaletteColor((v))))
|
||||
end
|
||||
end
|
||||
for k,v in pairs(colorTheme)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], v)
|
||||
else
|
||||
local r,g,b = table.unpack(v)
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b)
|
||||
end
|
||||
end
|
||||
basalt.setMainFrame(self)
|
||||
return self
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if(base.render~=nil)then
|
||||
if(self:isVisible())then
|
||||
if(updateRender)then
|
||||
base.render(self)
|
||||
local children = self:getChildren()
|
||||
for _, child in ipairs(children) do
|
||||
if (child.element.render ~= nil) then
|
||||
child.element:render()
|
||||
end
|
||||
end
|
||||
updateRender = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
updateDraw = function(self)
|
||||
updateRender = true
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if(event=="term_resize")then
|
||||
self:setSize(termObject.getSize())
|
||||
end
|
||||
end,
|
||||
|
||||
updateTerm = function(self)
|
||||
if(basaltDraw~=nil)then
|
||||
basaltDraw.update()
|
||||
end
|
||||
end,
|
||||
|
||||
setTerm = function(self, newTerm)
|
||||
termObject = newTerm
|
||||
if(newTerm==nil)then
|
||||
basaltDraw = nil
|
||||
else
|
||||
basaltDraw = drawSystem(termObject)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getTerm = function()
|
||||
return termObject
|
||||
end,
|
||||
|
||||
blit = function (self, x, y, t, f, b)
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
if y >= 1 and y <= h then
|
||||
local t_visible = sub(t, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local f_visible = sub(f, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local b_visible = sub(b, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
basaltDraw.blit(max(x + (obx - 1), obx), oby + y - 1, t_visible, f_visible, b_visible)
|
||||
end
|
||||
end,
|
||||
|
||||
setCursor = function(self, _blink, _xCursor, _yCursor, color)
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local xO, yO = self:getOffset()
|
||||
cursorBlink = _blink or false
|
||||
if (_xCursor ~= nil) then
|
||||
xCursor = obx + _xCursor - 1 - xO
|
||||
end
|
||||
if (_yCursor ~= nil) then
|
||||
yCursor = oby + _yCursor - 1 - yO
|
||||
end
|
||||
cursorColor = color or cursorColor
|
||||
if (cursorBlink) then
|
||||
termObject.setTextColor(cursorColor)
|
||||
termObject.setCursorPos(xCursor, yCursor)
|
||||
termObject.setCursorBlink(cursorBlink)
|
||||
else
|
||||
termObject.setCursorBlink(false)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
for k,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do
|
||||
object[v[1]] = function(self, btn, x, y, ...)
|
||||
if(base[v[1]](self, btn, x, y, ...))then
|
||||
basalt.setActiveFrame(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do
|
||||
object[v] = function(self, x, y, width, height, symbol)
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
height = (y < 1 and (height + y > self:getHeight() and self:getHeight() or height + y - 1) or (height + y > self:getHeight() and self:getHeight() - y + 1 or height))
|
||||
width = (x < 1 and (width + x > self:getWidth() and self:getWidth() or width + x - 1) or (width + x > self:getWidth() and self:getWidth() - x + 1 or width))
|
||||
basaltDraw[v](max(x + (obx - 1), obx), max(y + (oby - 1), oby), width, height, symbol)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({"setBG", "setFG", "setText"}) do
|
||||
object[v] = function(self, x, y, str)
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
if (y >= 1) and (y <= h) then
|
||||
basaltDraw[v](max(x + (obx - 1), obx), oby + y - 1, sub(str, max(1 - x + 1, 1), max(w - x + 1,1)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
77
lib/basalt/objects/Button.lua
Normal file
77
lib/basalt/objects/Button.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Button
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Button"
|
||||
local textHorizontalAlign = "center"
|
||||
local textVerticalAlign = "center"
|
||||
|
||||
local text = "Button"
|
||||
|
||||
base:setSize(12, 3)
|
||||
base:setZIndex(5)
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getHorizontalAlign = function(self)
|
||||
return textHorizontalAlign
|
||||
end,
|
||||
|
||||
setHorizontalAlign = function(self, pos)
|
||||
textHorizontalAlign = pos
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getVerticalAlign = function(self)
|
||||
return textVerticalAlign
|
||||
end,
|
||||
|
||||
setVerticalAlign = function(self, pos)
|
||||
textVerticalAlign = pos
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
setText = function(self, newText)
|
||||
text = newText
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("button", function()
|
||||
local w,h = self:getSize()
|
||||
local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign)
|
||||
local xOffset
|
||||
if(textHorizontalAlign=="center")then
|
||||
xOffset = math.floor((w - text:len()) / 2)
|
||||
elseif(textHorizontalAlign=="right")then
|
||||
xOffset = w - text:len()
|
||||
end
|
||||
|
||||
self:addText(xOffset + 1, verticalAlign, text)
|
||||
self:addFG(xOffset + 1, verticalAlign, tHex[self:getForeground() or colors.white]:rep(text:len()))
|
||||
end)
|
||||
end,
|
||||
}
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
40
lib/basalt/objects/ChangeableObject.lua
Normal file
40
lib/basalt/objects/ChangeableObject.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
-- Base object
|
||||
local objectType = "ChangeableObject"
|
||||
|
||||
local value
|
||||
|
||||
local object = {
|
||||
setValue = function(self, _value, valueChangedHandler)
|
||||
if (value ~= _value) then
|
||||
value = _value
|
||||
self:updateDraw()
|
||||
if(valueChangedHandler~=false)then
|
||||
self:valueChangedHandler()
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getValue = function(self)
|
||||
return value
|
||||
end,
|
||||
|
||||
onChange = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("value_changed", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
valueChangedHandler = function(self)
|
||||
self:sendEvent("value_changed", value)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
114
lib/basalt/objects/Checkbox.lua
Normal file
114
lib/basalt/objects/Checkbox.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Checkbox
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Checkbox"
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setValue(false)
|
||||
base:setSize(1, 1)
|
||||
|
||||
local symbol,inactiveSymbol,text,textPos = "\42"," ","","right"
|
||||
|
||||
local object = {
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click", self)
|
||||
self:listenEvent("mouse_up", self)
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setSymbol = function(self, sym, inactive)
|
||||
symbol = sym or symbol
|
||||
inactiveSymbol = inactive or inactiveSymbol
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setActiveSymbol = function(self, sym)
|
||||
return self:setSymbol(sym, nil)
|
||||
end,
|
||||
|
||||
setInactiveSymbol = function(self, inactive)
|
||||
return self:setSymbol(nil, inactive)
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return symbol, inactiveSymbol
|
||||
end,
|
||||
|
||||
getActiveSymbol = function(self)
|
||||
return symbol
|
||||
end,
|
||||
|
||||
getInactiveSymbol = function(self)
|
||||
return inactiveSymbol
|
||||
end,
|
||||
|
||||
setText = function(self, _text)
|
||||
text = _text
|
||||
return self
|
||||
end,
|
||||
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
setTextPosition = function(self, pos)
|
||||
textPos = pos or textPos
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextPosition = function(self)
|
||||
return textPos
|
||||
end,
|
||||
|
||||
setChecked = base.setValue,
|
||||
|
||||
getChecked = base.getValue,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
if(button == 1)then
|
||||
if (self:getValue() ~= true) and (self:getValue() ~= false) then
|
||||
self:setValue(false)
|
||||
else
|
||||
self:setValue(not self:getValue())
|
||||
end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("checkbox", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local verticalAlign = utils.getTextVerticalAlign(h, "center")
|
||||
local bg,fg = self:getBackground(), self:getForeground()
|
||||
if (self:getValue()) then
|
||||
self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(symbol, w, "center"), tHex[fg], tHex[bg])
|
||||
else
|
||||
self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(inactiveSymbol, w, "center"), tHex[fg], tHex[bg])
|
||||
end
|
||||
if(text~="")then
|
||||
local align = textPos=="left" and -text:len() or 3
|
||||
self:addText(align, verticalAlign, text)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
429
lib/basalt/objects/Container.lua
Normal file
429
lib/basalt/objects/Container.lua
Normal file
@@ -0,0 +1,429 @@
|
||||
local utils = require("utils")
|
||||
local tableCount = utils.tableCount
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Container"
|
||||
|
||||
local children = {}
|
||||
|
||||
local events = {}
|
||||
|
||||
local container = {}
|
||||
|
||||
local focusedChild
|
||||
local sorted = true
|
||||
local objId, evId = 0, 0
|
||||
|
||||
local objSort = function(a, b)
|
||||
if a.zIndex == b.zIndex then
|
||||
return a.objId < b.objId
|
||||
else
|
||||
return a.zIndex < b.zIndex
|
||||
end
|
||||
end
|
||||
local evSort = function(a, b)
|
||||
if a.zIndex == b.zIndex then
|
||||
return a.evId > b.evId
|
||||
else
|
||||
return a.zIndex > b.zIndex
|
||||
end
|
||||
end
|
||||
|
||||
local function getChildren(self)
|
||||
self:sortChildren()
|
||||
return children
|
||||
end
|
||||
|
||||
local function getChild(self, name)
|
||||
if (type(name)=="table") then
|
||||
name = name:getName()
|
||||
end
|
||||
for _, v in ipairs(children) do
|
||||
if v.element:getName() == name then
|
||||
return v.element
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getDeepChild(self, name)
|
||||
local maybeChild = getChild(name)
|
||||
if (maybeChild ~= nil) then
|
||||
return maybeChild
|
||||
end
|
||||
for _, child in ipairs(children) do
|
||||
if (child:getType() == "Container") then
|
||||
local maybeDeepChild = child:getDeepChild(name)
|
||||
if (maybeDeepChild ~= nil) then
|
||||
return maybeDeepChild
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addChild(self, element)
|
||||
if (getChild(element:getName()) ~= nil) then
|
||||
return
|
||||
end
|
||||
objId = objId + 1
|
||||
local zIndex = element:getZIndex()
|
||||
table.insert(children, {element = element, zIndex = zIndex, objId = objId})
|
||||
sorted = false
|
||||
element:setParent(self, true)
|
||||
for event, _ in pairs(element:getRegisteredEvents()) do
|
||||
self:addEvent(event, element)
|
||||
end
|
||||
if (element.init~=nil) then
|
||||
element:init()
|
||||
end
|
||||
if (element.load~=nil) then
|
||||
element:load()
|
||||
end
|
||||
if (element.draw~=nil) then
|
||||
element:draw()
|
||||
end
|
||||
return element
|
||||
end
|
||||
|
||||
local function removeChild(self, element)
|
||||
if (type(element)=="string") then
|
||||
element = getChild(element:getName())
|
||||
end
|
||||
if (element==nil) then
|
||||
return
|
||||
end
|
||||
for i, v in ipairs(children) do
|
||||
if v.element == element then
|
||||
table.remove(children, i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
self:removeEvents(element)
|
||||
sorted = false
|
||||
end
|
||||
|
||||
local function removeChildren(self)
|
||||
local parent = self:getParent()
|
||||
children = {}
|
||||
events = {}
|
||||
sorted = false
|
||||
objId = 0
|
||||
evId = 0
|
||||
focusedChild = nil
|
||||
parent:removeEvents(self)
|
||||
end
|
||||
|
||||
local function updateZIndex(self, element, newZ)
|
||||
objId = objId + 1
|
||||
evId = evId + 1
|
||||
for _,v in pairs(children)do
|
||||
if(v.element==element)then
|
||||
v.zIndex = newZ
|
||||
v.objId = objId
|
||||
break
|
||||
end
|
||||
end
|
||||
for _,v in pairs(events)do
|
||||
for a,b in pairs(v)do
|
||||
if(b.element==element)then
|
||||
b.zIndex = newZ
|
||||
b.evId = evId
|
||||
end
|
||||
end
|
||||
end
|
||||
sorted = false
|
||||
self:updateDraw()
|
||||
end
|
||||
|
||||
local function removeEvents(self, element)
|
||||
local parent = self:getParent()
|
||||
for a, b in pairs(events) do
|
||||
for c, d in pairs(b) do
|
||||
if(d.element == element)then
|
||||
table.remove(events[a], c)
|
||||
end
|
||||
end
|
||||
if(tableCount(events[a])<=0)then
|
||||
if(parent~=nil)then
|
||||
parent:removeEvent(a, self)
|
||||
end
|
||||
end
|
||||
end
|
||||
sorted = false
|
||||
end
|
||||
|
||||
local function getEvent(self, event, name)
|
||||
if(type(name)=="table")then name = name:getName() end
|
||||
if(events[event]~=nil)then
|
||||
for _, obj in pairs(events[event]) do
|
||||
if (obj.element:getName() == name) then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addEvent(self, event, element)
|
||||
if (getEvent(self, event, element:getName()) ~= nil) then
|
||||
return
|
||||
end
|
||||
local zIndex = element:getZIndex()
|
||||
evId = evId + 1
|
||||
if(events[event]==nil)then events[event] = {} end
|
||||
table.insert(events[event], {element = element, zIndex = zIndex, evId = evId})
|
||||
sorted = false
|
||||
self:listenEvent(event)
|
||||
return element
|
||||
end
|
||||
|
||||
local function removeEvent(self, event, element)
|
||||
if(events[event]~=nil)then
|
||||
for a, b in pairs(events[event]) do
|
||||
if(b.element == element)then
|
||||
table.remove(events[event], a)
|
||||
end
|
||||
end
|
||||
if(tableCount(events[event])<=0)then
|
||||
self:listenEvent(event, false)
|
||||
end
|
||||
end
|
||||
sorted = false
|
||||
end
|
||||
|
||||
local function getEvents(self, event)
|
||||
return event~=nil and events[event] or events
|
||||
end
|
||||
|
||||
container = {
|
||||
getType = function()
|
||||
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,
|
||||
|
||||
setSize = function(self, ...)
|
||||
base.setSize(self, ...)
|
||||
self:customEventHandler("basalt_FrameResize")
|
||||
return self
|
||||
end,
|
||||
|
||||
setPosition = function(self, ...)
|
||||
base.setPosition(self, ...)
|
||||
self:customEventHandler("basalt_FrameReposition")
|
||||
return self
|
||||
end,
|
||||
|
||||
searchChildren = function(self, name)
|
||||
local results = {}
|
||||
for _, child in pairs(children) do
|
||||
if (string.find(child.element:getName(), name)) then
|
||||
table.insert(results, child)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end,
|
||||
|
||||
getChildrenByType = function(self, type)
|
||||
local results = {}
|
||||
for _, child in pairs(children) do
|
||||
if (child.element:isType(type)) then
|
||||
table.insert(results, child)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end,
|
||||
|
||||
setImportant = function(self, element)
|
||||
objId = objId + 1
|
||||
evId = evId + 1
|
||||
for a, b in pairs(events) do
|
||||
for c, d in pairs(b) do
|
||||
if(d.element == element)then
|
||||
d.evId = evId
|
||||
table.remove(events[a], c)
|
||||
table.insert(events[a], d)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
for i, v in ipairs(children) do
|
||||
if v.element == element then
|
||||
v.objId = objId
|
||||
table.remove(children, i)
|
||||
table.insert(children, v)
|
||||
break
|
||||
end
|
||||
end
|
||||
if(self.updateDraw~=nil)then
|
||||
self:updateDraw()
|
||||
end
|
||||
sorted = false
|
||||
end,
|
||||
|
||||
sortChildren = function(self)
|
||||
if (sorted) then
|
||||
return
|
||||
end
|
||||
table.sort(children, objSort)
|
||||
for event, _ in pairs(events) do
|
||||
table.sort(events[event], evSort)
|
||||
end
|
||||
sorted = true
|
||||
end,
|
||||
|
||||
clearFocusedChild = function(self)
|
||||
if(focusedChild~=nil)then
|
||||
if(getChild(self, focusedChild)~=nil)then
|
||||
focusedChild:loseFocusHandler()
|
||||
end
|
||||
end
|
||||
focusedChild = nil
|
||||
return self
|
||||
end,
|
||||
|
||||
setFocusedChild = function(self, obj)
|
||||
if(focusedChild~=obj)then
|
||||
if(focusedChild~=nil)then
|
||||
if(getChild(self, focusedChild)~=nil)then
|
||||
focusedChild:loseFocusHandler()
|
||||
end
|
||||
end
|
||||
if(obj~=nil)then
|
||||
if(getChild(self, obj)~=nil)then
|
||||
obj:getFocusHandler()
|
||||
end
|
||||
end
|
||||
focusedChild = obj
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
getFocused = function(self)
|
||||
return focusedChild
|
||||
end,
|
||||
|
||||
getChild = getChild,
|
||||
getChildren = getChildren,
|
||||
getDeepChildren = getDeepChild,
|
||||
addChild = addChild,
|
||||
removeChild = removeChild,
|
||||
removeChildren = removeChildren,
|
||||
getEvents = getEvents,
|
||||
getEvent = getEvent,
|
||||
addEvent = addEvent,
|
||||
removeEvent = removeEvent,
|
||||
removeEvents = removeEvents,
|
||||
updateZIndex = updateZIndex,
|
||||
|
||||
listenEvent = function(self, event, active)
|
||||
base.listenEvent(self, event, active)
|
||||
if(events[event]==nil)then events[event] = {} end
|
||||
return self
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, ...)
|
||||
base.customEventHandler(self, ...)
|
||||
for _, o in pairs(children) do
|
||||
if (o.element.customEventHandler ~= nil) then
|
||||
o.element:customEventHandler(...)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
if(focusedChild~=nil)then focusedChild:loseFocusHandler() focusedChild = nil end
|
||||
end,
|
||||
|
||||
getBasalt = function(self)
|
||||
return basalt
|
||||
end,
|
||||
|
||||
setPalette = function(self, col, ...)
|
||||
local parent = self:getParent()
|
||||
parent:setPalette(col, ...)
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, ...)
|
||||
if(base.eventHandler~=nil)then
|
||||
base.eventHandler(self, ...)
|
||||
if(events["other_event"]~=nil)then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(events["other_event"]) do
|
||||
if (obj.element.eventHandler ~= nil) then
|
||||
obj.element.eventHandler(obj.element, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
for k,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do
|
||||
container[v[1]] = function(self, btn, x, y, ...)
|
||||
if(base[v[1]]~=nil)then
|
||||
if(base[v[1]](self, btn, x, y, ...))then
|
||||
if(events[k]~=nil)then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(events[k]) do
|
||||
if (obj.element[v[1]] ~= nil) then
|
||||
local xO, yO = 0, 0
|
||||
if(self.getOffset~=nil)then
|
||||
xO, yO = self:getOffset()
|
||||
end
|
||||
if(obj.element.getIgnoreOffset~=nil)then
|
||||
if(obj.element.getIgnoreOffset())then
|
||||
xO, yO = 0, 0
|
||||
end
|
||||
end
|
||||
if (obj.element[v[1]](obj.element, btn, x+xO, y+yO, ...)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if(v[2])then
|
||||
self:clearFocusedChild()
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({key="keyHandler",key_up="keyUpHandler",char="charHandler"})do
|
||||
container[v] = function(self, ...)
|
||||
if(base[v]~=nil)then
|
||||
if(base[v](self, ...))then
|
||||
if(events[k]~=nil)then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(events[k]) do
|
||||
if (obj.element[v] ~= nil) then
|
||||
if (obj.element[v](obj.element, ...)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for objectName, _ in pairs(basalt.getObjects()) do
|
||||
container["add" .. objectName] = function(self, id)
|
||||
return self:addChild(basalt:createObject(objectName, id))
|
||||
end
|
||||
end
|
||||
|
||||
container.__index = container
|
||||
return setmetatable(container, base)
|
||||
end
|
||||
248
lib/basalt/objects/Dropdown.lua
Normal file
248
lib/basalt/objects/Dropdown.lua
Normal file
@@ -0,0 +1,248 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("List")(name, basalt)
|
||||
local objectType = "Dropdown"
|
||||
|
||||
base:setSize(12, 1)
|
||||
base:setZIndex(6)
|
||||
|
||||
local selectionColorActive = true
|
||||
local align = "left"
|
||||
local yOffset = 0
|
||||
|
||||
local dropdownW = 0
|
||||
local dropdownH = 0
|
||||
local autoSize = true
|
||||
local closedSymbol = "\16"
|
||||
local openedSymbol = "\31"
|
||||
local isOpened = false
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click", self)
|
||||
self:listenEvent("mouse_up", self)
|
||||
self:listenEvent("mouse_scroll", self)
|
||||
self:listenEvent("mouse_drag", self)
|
||||
end,
|
||||
|
||||
setOffset = function(self, yOff)
|
||||
yOffset = yOff
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
addItem = function(self, t, ...)
|
||||
base.addItem(self, t, ...)
|
||||
if(autoSize)then
|
||||
dropdownW = math.max(dropdownW, #t)
|
||||
dropdownH = dropdownH + 1
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
removeItem = function(self, index)
|
||||
base.removeItem(self, index)
|
||||
if(autoSize)then
|
||||
dropdownW = 0
|
||||
dropdownH = 0
|
||||
for n = 1, #list do
|
||||
dropdownW = math.max(dropdownW, #list[n].text)
|
||||
end
|
||||
dropdownH = #list
|
||||
end
|
||||
end,
|
||||
|
||||
isOpened = function(self)
|
||||
return isOpened
|
||||
end,
|
||||
|
||||
setOpened = function(self, open)
|
||||
isOpened = open
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setDropdownSize = function(self, width, height)
|
||||
dropdownW, dropdownH = width, height
|
||||
autoSize = false
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setDropdownWidth = function(self, width)
|
||||
return self:setDropdownSize(width, dropdownH)
|
||||
end,
|
||||
|
||||
setDropdownHeight = function(self, height)
|
||||
return self:setDropdownSize(dropdownW, height)
|
||||
end,
|
||||
|
||||
getDropdownSize = function(self)
|
||||
return dropdownW, dropdownH
|
||||
end,
|
||||
|
||||
getDropdownWidth = function(self)
|
||||
return dropdownW
|
||||
end,
|
||||
|
||||
getDropdownHeight = function(self)
|
||||
return dropdownH
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, isMon)
|
||||
if (isOpened) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
if(button==1)then
|
||||
local list = self:getAll()
|
||||
if (#list > 0) then
|
||||
for n = 1, dropdownH do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then
|
||||
self:setValue(list[n + yOffset])
|
||||
self:updateDraw()
|
||||
local val = self:sendEvent("mouse_click", self, "mouse_click", button, x, y)
|
||||
if(val==false)then return val end
|
||||
if(isMon)then
|
||||
basalt.schedule(function()
|
||||
sleep(0.1)
|
||||
self:mouseUpHandler(button, x, y)
|
||||
end)()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local base = base:getBase()
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
isOpened = not isOpened
|
||||
self:getParent():setImportant(self)
|
||||
self:updateDraw()
|
||||
return true
|
||||
else
|
||||
if(isOpened)then
|
||||
self:updateDraw()
|
||||
isOpened = false
|
||||
end
|
||||
return false
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
if (isOpened) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
if(button==1)then
|
||||
local list = self:getAll()
|
||||
if (#list > 0) then
|
||||
for n = 1, dropdownH do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then
|
||||
isOpened = false
|
||||
self:updateDraw()
|
||||
local val = self:sendEvent("mouse_up", self, "mouse_up", button, x, y)
|
||||
if(val==false)then return val end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, btn, x, y)
|
||||
if(base.dragHandler(self, btn, x, y))then
|
||||
isOpened = true
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(isOpened)then
|
||||
local xPos, yPos = self:getAbsolutePosition()
|
||||
if(x >= xPos)and(x <= xPos + dropdownW)and(y >= yPos)and(y <= yPos + dropdownH)then
|
||||
self:setFocus()
|
||||
end
|
||||
end
|
||||
if (isOpened)and(self:isFocused()) then
|
||||
local xPos, yPos = self:getAbsolutePosition()
|
||||
if(x < xPos)or(x > xPos + dropdownW)or(y < yPos)or(y > yPos + dropdownH)then
|
||||
return false
|
||||
end
|
||||
if(#self:getAll() <= dropdownH)then return false end
|
||||
|
||||
local list = self:getAll()
|
||||
yOffset = yOffset + dir
|
||||
if (yOffset < 0) then
|
||||
yOffset = 0
|
||||
end
|
||||
if (dir == 1) then
|
||||
if (#list > dropdownH) then
|
||||
if (yOffset > #list - dropdownH) then
|
||||
yOffset = #list - dropdownH
|
||||
end
|
||||
else
|
||||
yOffset = math.min(#list - 1, 0)
|
||||
end
|
||||
end
|
||||
local val = self:sendEvent("mouse_scroll", self, "mouse_scroll", dir, x, y)
|
||||
if(val==false)then return val end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:setDrawState("list", false)
|
||||
self:addDraw("dropdown", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local val = self:getValue()
|
||||
local list = self:getAll()
|
||||
local bgCol, fgCol = self:getBackground(), self:getForeground()
|
||||
local text = utils.getTextHorizontalAlign((val~=nil and val.text or ""), w, align):sub(1, w - 1) .. (isOpened and openedSymbol or closedSymbol)
|
||||
self:addBlit(1, 1, text, tHex[fgCol]:rep(#text), tHex[bgCol]:rep(#text))
|
||||
|
||||
if (isOpened) then
|
||||
self:addTextBox(1, 2, dropdownW, dropdownH, " ")
|
||||
self:addBackgroundBox(1, 2, dropdownW, dropdownH, bgCol)
|
||||
self:addForegroundBox(1, 2, dropdownW, dropdownH, fgCol)
|
||||
for n = 1, dropdownH do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
local t =utils.getTextHorizontalAlign(list[n + yOffset].text, dropdownW, align)
|
||||
if (list[n + yOffset] == val) then
|
||||
if (selectionColorActive) then
|
||||
local itemSelectedBG, itemSelectedFG = self:getSelectionColor()
|
||||
self:addBlit(1, n+1, t, tHex[itemSelectedFG]:rep(#t), tHex[itemSelectedBG]:rep(#t))
|
||||
else
|
||||
self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t))
|
||||
end
|
||||
else
|
||||
self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
433
lib/basalt/objects/Flexbox.lua
Normal file
433
lib/basalt/objects/Flexbox.lua
Normal file
@@ -0,0 +1,433 @@
|
||||
|
||||
local function flexObjectPlugin(base, basalt)
|
||||
local flexGrow = 0
|
||||
local flexShrink = 0
|
||||
local flexBasis = 0
|
||||
|
||||
local baseWidth, baseHeight = base:getSize()
|
||||
|
||||
local object = {
|
||||
getFlexGrow = function(self)
|
||||
return flexGrow
|
||||
end,
|
||||
|
||||
setFlexGrow = function(self, value)
|
||||
flexGrow = value
|
||||
return self
|
||||
end,
|
||||
|
||||
getFlexShrink = function(self)
|
||||
return flexShrink
|
||||
end,
|
||||
|
||||
setFlexShrink = function(self, value)
|
||||
flexShrink = value
|
||||
return self
|
||||
end,
|
||||
|
||||
getFlexBasis = function(self)
|
||||
return flexBasis
|
||||
end,
|
||||
|
||||
setFlexBasis = function(self, value)
|
||||
flexBasis = value
|
||||
return self
|
||||
end,
|
||||
|
||||
getSize = function(self)
|
||||
return baseWidth, baseHeight
|
||||
end,
|
||||
|
||||
getWidth = function(self)
|
||||
return baseWidth
|
||||
end,
|
||||
|
||||
getHeight = function(self)
|
||||
return baseHeight
|
||||
end,
|
||||
|
||||
setSize = function(self, width, height, rel, internalCall)
|
||||
base.setSize(self, width, height, rel)
|
||||
if not internalCall then
|
||||
baseWidth, baseHeight = base:getSize()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ScrollableFrame")(name, basalt)
|
||||
local objectType = "Flexbox"
|
||||
|
||||
local direction = "row"
|
||||
local spacing = 1
|
||||
local justifyContent = "flex-start"
|
||||
local wrap = "nowrap"
|
||||
local children = {}
|
||||
local sortedChildren = {}
|
||||
local updateLayout = false
|
||||
local lineBreakFakeObject = flexObjectPlugin({
|
||||
getHeight = function(self) return 0 end,
|
||||
getWidth = function(self) return 0 end,
|
||||
getPosition = function(self) return 0, 0 end,
|
||||
getSize = function(self) return 0, 0 end,
|
||||
isType = function(self) return false end,
|
||||
getType = function(self) return "lineBreakFakeObject" end,
|
||||
setPosition = function(self) end,
|
||||
setSize = function(self) end,
|
||||
})
|
||||
lineBreakFakeObject:setFlexBasis(0):setFlexGrow(0):setFlexShrink(0)
|
||||
|
||||
local function sortChildren(self)
|
||||
if(wrap=="nowrap")then
|
||||
sortedChildren = {}
|
||||
local index = 1
|
||||
local lineSize = 1
|
||||
local lineOffset = 1
|
||||
for _,v in pairs(children)do
|
||||
if(sortedChildren[index]==nil)then sortedChildren[index]={offset=1} end
|
||||
|
||||
local childHeight = direction == "row" and v:getHeight() or v:getWidth()
|
||||
if childHeight > lineSize then
|
||||
lineSize = childHeight
|
||||
end
|
||||
if(v == lineBreakFakeObject)then
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
lineSize = 1
|
||||
index = index + 1
|
||||
sortedChildren[index] = {offset=lineOffset}
|
||||
else
|
||||
table.insert(sortedChildren[index], v)
|
||||
end
|
||||
end
|
||||
elseif(wrap=="wrap")then
|
||||
sortedChildren = {}
|
||||
local lineSize = 1
|
||||
local lineOffset = 1
|
||||
|
||||
local maxSize = direction == "row" and self:getWidth() or self:getHeight()
|
||||
local usedSize = 0
|
||||
local index = 1
|
||||
|
||||
for _,v in pairs(children) do
|
||||
if(sortedChildren[index]==nil) then sortedChildren[index]={offset=1} end
|
||||
|
||||
if v == lineBreakFakeObject then
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
usedSize = 0
|
||||
lineSize = 1
|
||||
index = index + 1
|
||||
sortedChildren[index] = {offset=lineOffset}
|
||||
else
|
||||
local objSize = direction == "row" and v:getWidth() or v:getHeight()
|
||||
if(objSize+usedSize<=maxSize) then
|
||||
table.insert(sortedChildren[index], v)
|
||||
usedSize = usedSize + objSize + spacing
|
||||
else
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
lineSize = direction == "row" and v:getHeight() or v:getWidth()
|
||||
index = index + 1
|
||||
usedSize = objSize + spacing
|
||||
sortedChildren[index] = {offset=lineOffset, v}
|
||||
end
|
||||
|
||||
local childHeight = direction == "row" and v:getHeight() or v:getWidth()
|
||||
if childHeight > lineSize then
|
||||
lineSize = childHeight
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function calculateRow(self, children)
|
||||
local containerWidth, containerHeight = self:getSize()
|
||||
local totalFlexGrow = 0
|
||||
local totalFlexShrink = 0
|
||||
local totalFlexBasis = 0
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
totalFlexGrow = totalFlexGrow + child:getFlexGrow()
|
||||
totalFlexShrink = totalFlexShrink + child:getFlexShrink()
|
||||
totalFlexBasis = totalFlexBasis + child:getFlexBasis()
|
||||
end
|
||||
|
||||
local remainingSpace = containerWidth - totalFlexBasis - (spacing * (#children - 1))
|
||||
|
||||
local currentX = 1
|
||||
for _, child in ipairs(children) do
|
||||
if(child~=lineBreakFakeObject)then
|
||||
local childWidth
|
||||
|
||||
local flexGrow = child:getFlexGrow()
|
||||
local flexShrink = child:getFlexShrink()
|
||||
|
||||
local baseWidth = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getWidth()
|
||||
if totalFlexGrow > 0 then
|
||||
childWidth = baseWidth + flexGrow / totalFlexGrow * remainingSpace
|
||||
else
|
||||
childWidth = baseWidth
|
||||
end
|
||||
|
||||
if remainingSpace < 0 and totalFlexShrink > 0 then
|
||||
childWidth = baseWidth + flexShrink / totalFlexShrink * remainingSpace
|
||||
end
|
||||
|
||||
child:setPosition(currentX, children.offset or 1)
|
||||
child:setSize(childWidth, child:getHeight(), false, true)
|
||||
currentX = currentX + childWidth + spacing
|
||||
end
|
||||
end
|
||||
|
||||
if justifyContent == "flex-end" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = containerWidth - totalWidth + 1
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset, y)
|
||||
end
|
||||
elseif justifyContent == "center" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = (containerWidth - totalWidth) / 2 + 1
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset, y)
|
||||
end
|
||||
elseif justifyContent == "space-between" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = (containerWidth - totalWidth) / (#children - 1) + 1
|
||||
for i, child in ipairs(children) do
|
||||
if i > 1 then
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset * (i - 1), y)
|
||||
end
|
||||
end
|
||||
elseif justifyContent == "space-around" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = (containerWidth - totalWidth) / #children
|
||||
for i, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset * i - offset / 2, y)
|
||||
end
|
||||
elseif justifyContent == "space-evenly" then
|
||||
local numSpaces = #children + 1
|
||||
local totalChildWidth = 0
|
||||
for _, child in ipairs(children) do
|
||||
totalChildWidth = totalChildWidth + child:getWidth()
|
||||
end
|
||||
local totalSpace = containerWidth - totalChildWidth
|
||||
local offset = math.floor(totalSpace / numSpaces)
|
||||
local remaining = totalSpace - offset * numSpaces
|
||||
currentX = offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
for _, child in ipairs(children) do
|
||||
child:setPosition(currentX, 1)
|
||||
currentX = currentX + child:getWidth() + offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function calculateColumn(self, children)
|
||||
local containerWidth, containerHeight = self:getSize()
|
||||
local totalFlexGrow = 0
|
||||
local totalFlexShrink = 0
|
||||
local totalFlexBasis = 0
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
totalFlexGrow = totalFlexGrow + child:getFlexGrow()
|
||||
totalFlexShrink = totalFlexShrink + child:getFlexShrink()
|
||||
totalFlexBasis = totalFlexBasis + child:getFlexBasis()
|
||||
end
|
||||
|
||||
local remainingSpace = containerHeight - totalFlexBasis - (spacing * (#children - 1))
|
||||
|
||||
local currentY = 1
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
if(child~=lineBreakFakeObject)then
|
||||
local childHeight
|
||||
|
||||
local flexGrow = child:getFlexGrow()
|
||||
local flexShrink = child:getFlexShrink()
|
||||
|
||||
local baseHeight = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getHeight()
|
||||
if totalFlexGrow > 0 then
|
||||
childHeight = baseHeight + flexGrow / totalFlexGrow * remainingSpace
|
||||
else
|
||||
childHeight = baseHeight
|
||||
end
|
||||
|
||||
if remainingSpace < 0 and totalFlexShrink > 0 then
|
||||
childHeight = baseHeight + flexShrink / totalFlexShrink * remainingSpace
|
||||
end
|
||||
|
||||
child:setPosition(children.offset, currentY)
|
||||
child:setSize(child:getWidth(), childHeight, false, true)
|
||||
currentY = currentY + childHeight + spacing
|
||||
end
|
||||
end
|
||||
|
||||
if justifyContent == "flex-end" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = containerHeight - totalHeight + 1
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset)
|
||||
end
|
||||
elseif justifyContent == "center" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = (containerHeight - totalHeight) / 2
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset)
|
||||
end
|
||||
elseif justifyContent == "space-between" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = (containerHeight - totalHeight) / (#children - 1) + 1
|
||||
for i, child in ipairs(children) do
|
||||
if i > 1 then
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset * (i - 1))
|
||||
end
|
||||
end
|
||||
elseif justifyContent == "space-around" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = (containerHeight - totalHeight) / #children
|
||||
for i, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset * i - offset / 2)
|
||||
end
|
||||
elseif justifyContent == "space-evenly" then
|
||||
local numSpaces = #children + 1
|
||||
local totalChildHeight = 0
|
||||
for _, child in ipairs(children) do
|
||||
totalChildHeight = totalChildHeight + child:getHeight()
|
||||
end
|
||||
local totalSpace = containerHeight - totalChildHeight
|
||||
local offset = math.floor(totalSpace / numSpaces)
|
||||
local remaining = totalSpace - offset * numSpaces
|
||||
currentY = offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, currentY)
|
||||
currentY = currentY + child:getHeight() + offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function applyLayout(self)
|
||||
sortChildren(self)
|
||||
if direction == "row" then
|
||||
for _,v in pairs(sortedChildren)do
|
||||
calculateRow(self, v)
|
||||
end
|
||||
else
|
||||
for _,v in pairs(sortedChildren)do
|
||||
calculateColumn(self, v)
|
||||
end
|
||||
end
|
||||
updateLayout = false
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType == t or base.isType ~= nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setJustifyContent = function(self, value)
|
||||
justifyContent = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getJustifyContent = function(self)
|
||||
return justifyContent
|
||||
end,
|
||||
|
||||
setDirection = function(self, value)
|
||||
direction = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDirection = function(self)
|
||||
return direction
|
||||
end,
|
||||
|
||||
setSpacing = function(self, value)
|
||||
spacing = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSpacing = function(self)
|
||||
return spacing
|
||||
end,
|
||||
|
||||
setWrap = function(self, value)
|
||||
wrap = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getWrap = function(self)
|
||||
return wrap
|
||||
end,
|
||||
|
||||
updateLayout = function(self)
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
end,
|
||||
|
||||
addBreak = function(self)
|
||||
table.insert(children, lineBreakFakeObject)
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
base.customEventHandler(self, event, ...)
|
||||
if event == "basalt_FrameResize" then
|
||||
updateLayout = true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("flexboxDraw", function()
|
||||
if updateLayout then
|
||||
applyLayout(self)
|
||||
end
|
||||
end, 1)
|
||||
end
|
||||
}
|
||||
|
||||
for k, _ in pairs(basalt.getObjects()) do
|
||||
object["add" .. k] = function(self, name)
|
||||
local baseChild = base["add" .. k](self, name)
|
||||
local child = flexObjectPlugin(baseChild, basalt)
|
||||
table.insert(children, child)
|
||||
updateLayout = true
|
||||
return child
|
||||
end
|
||||
end
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
133
lib/basalt/objects/Frame.lua
Normal file
133
lib/basalt/objects/Frame.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local utils = require("utils")
|
||||
|
||||
local max,min,sub,rep,len = math.max,math.min,string.sub,string.rep,string.len
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Container")(name, basalt)
|
||||
local objectType = "Frame"
|
||||
local parent
|
||||
|
||||
local updateRender = true
|
||||
|
||||
local xOffset, yOffset = 0, 0
|
||||
|
||||
base:setSize(30, 10)
|
||||
base:setZIndex(10)
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
setOffset = function(self, xOff, yOff)
|
||||
xOffset = xOff or xOffset
|
||||
yOffset = yOff or yOffset
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
setXOffset = function(self, newXOffset)
|
||||
return self:setOffset(newXOffset, nil)
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
setYOffset = function(self, newYOffset)
|
||||
return self:setOffset(nil, newYOffset)
|
||||
end,
|
||||
|
||||
setParent = function(self, p, ...)
|
||||
base.setParent(self, p, ...)
|
||||
parent = p
|
||||
return self
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if(base.render~=nil)then
|
||||
if(self:isVisible())then
|
||||
base.render(self)
|
||||
local children = self:getChildren()
|
||||
for _, child in ipairs(children) do
|
||||
if (child.element.render ~= nil) then
|
||||
child.element:render()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
updateDraw = function(self)
|
||||
if(parent~=nil)then
|
||||
parent:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
blit = function (self, x, y, t, f, b)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = parent:getOffset()
|
||||
obx = obx - xO
|
||||
oby = oby - yO
|
||||
local w, h = self:getSize()
|
||||
if y >= 1 and y <= h then
|
||||
local t_visible = sub(t, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local f_visible = sub(f, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local b_visible = sub(b, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
parent:blit(max(x + (obx - 1), obx), oby + y - 1, t_visible, f_visible, b_visible)
|
||||
end
|
||||
end,
|
||||
|
||||
setCursor = function(self, blink, x, y, color)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = self:getOffset()
|
||||
parent:setCursor(blink or false, (x or 0)+obx-1 - xO, (y or 0)+oby-1 - yO, color or colors.white)
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
for k,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do
|
||||
object[v] = function(self, x, y, width, height, symbol)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = parent:getOffset()
|
||||
obx = obx - xO
|
||||
oby = oby - yO
|
||||
height = (y < 1 and (height + y > self:getHeight() and self:getHeight() or height + y - 1) or (height + y > self:getHeight() and self:getHeight() - y + 1 or height))
|
||||
width = (x < 1 and (width + x > self:getWidth() and self:getWidth() or width + x - 1) or (width + x > self:getWidth() and self:getWidth() - x + 1 or width))
|
||||
parent[v](parent, max(x + (obx - 1), obx), max(y + (oby - 1), oby), width, height, symbol)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({"setBG", "setFG", "setText"})do
|
||||
object[v] = function(self, x, y, str)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = parent:getOffset()
|
||||
obx = obx - xO
|
||||
oby = oby - yO
|
||||
local w, h = self:getSize()
|
||||
if (y >= 1) and (y <= h) then
|
||||
parent[v](parent, max(x + (obx - 1), obx), oby + y - 1, sub(str, max(1 - x + 1, 1), max(w - x + 1,1)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
171
lib/basalt/objects/Graph.lua
Normal file
171
lib/basalt/objects/Graph.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Graph"
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setSize(30, 10)
|
||||
|
||||
local graphData = {}
|
||||
local graphColor = colors.gray
|
||||
local graphSymbol = "\7"
|
||||
local graphSymbolCol = colors.black
|
||||
local maxValue = 100
|
||||
local minValue = 0
|
||||
local graphType = "line"
|
||||
local maxEntries = 10
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setGraphColor = function(self, color)
|
||||
graphColor = color or graphColor
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setGraphSymbol = function(self, symbol, symbolcolor)
|
||||
graphSymbol = symbol or graphSymbol
|
||||
graphSymbolCol = symbolcolor or graphSymbolCol
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setGraphSymbolColor = function(self, symbolColor)
|
||||
return self:setGraphSymbolColor(nil, symbolColor)
|
||||
end,
|
||||
|
||||
getGraphSymbol = function(self)
|
||||
return graphSymbol, graphSymbolCol
|
||||
end,
|
||||
|
||||
getGraphSymbolColor = function(self)
|
||||
return graphSymbolCol
|
||||
end,
|
||||
|
||||
addDataPoint = function(self, value)
|
||||
if value >= minValue and value <= maxValue then
|
||||
table.insert(graphData, value)
|
||||
self:updateDraw()
|
||||
end
|
||||
if(#graphData>100)then -- 100 is hard capped to prevent memory leaks
|
||||
table.remove(graphData,1)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setMaxValue = function(self, value)
|
||||
maxValue = value
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getMaxValue = function(self)
|
||||
return maxValue
|
||||
end,
|
||||
|
||||
setMinValue = function(self, value)
|
||||
minValue = value
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getMinValue = function(self)
|
||||
return minValue
|
||||
end,
|
||||
|
||||
setGraphType = function(self, graph_type)
|
||||
if graph_type == "scatter" or graph_type == "line" or graph_type == "bar" then
|
||||
graphType = graph_type
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getGraphType = function(self)
|
||||
return graphType
|
||||
end,
|
||||
|
||||
setMaxEntries = function(self, value)
|
||||
maxEntries = value
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getMaxEntries = function(self)
|
||||
return maxEntries
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
graphData = {}
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("graph", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
local bgCol, fgCol = self:getBackground(), self:getForeground()
|
||||
|
||||
local range = maxValue - minValue
|
||||
local prev_x, prev_y
|
||||
|
||||
local startIndex = #graphData - maxEntries + 1
|
||||
if startIndex < 1 then startIndex = 1 end
|
||||
|
||||
for i = startIndex, #graphData do
|
||||
local data = graphData[i]
|
||||
local x = math.floor(((w - 1) / (maxEntries - 1)) * (i - startIndex) + 1.5)
|
||||
local y = math.floor((h - 1) - ((h - 1) / range) * (data - minValue) + 1.5)
|
||||
|
||||
|
||||
if graphType == "scatter" then
|
||||
self:addBackgroundBox(x, y, 1, 1, graphColor)
|
||||
self:addForegroundBox(x, y, 1, 1, graphSymbolCol)
|
||||
self:addTextBox(x, y, 1, 1, graphSymbol)
|
||||
elseif graphType == "line" then
|
||||
if prev_x and prev_y then
|
||||
local dx = math.abs(x - prev_x)
|
||||
local dy = math.abs(y - prev_y)
|
||||
local sx = prev_x < x and 1 or -1
|
||||
local sy = prev_y < y and 1 or -1
|
||||
local err = dx - dy
|
||||
|
||||
while true do
|
||||
self:addBackgroundBox(prev_x, prev_y, 1, 1, graphColor)
|
||||
self:addForegroundBox(prev_x, prev_y, 1, 1, graphSymbolCol)
|
||||
self:addTextBox(prev_x, prev_y, 1, 1, graphSymbol)
|
||||
|
||||
if prev_x == x and prev_y == y then
|
||||
break
|
||||
end
|
||||
|
||||
local e2 = 2 * err
|
||||
|
||||
if e2 > -dy then
|
||||
err = err - dy
|
||||
prev_x = prev_x + sx
|
||||
end
|
||||
|
||||
if e2 < dx then
|
||||
err = err + dx
|
||||
prev_y = prev_y + sy
|
||||
end
|
||||
end
|
||||
end
|
||||
prev_x, prev_y = x, y
|
||||
elseif graphType == "bar" then
|
||||
self:addBackgroundBox(x - 1, y, 1, h - y, graphColor)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
363
lib/basalt/objects/Image.lua
Normal file
363
lib/basalt/objects/Image.lua
Normal file
@@ -0,0 +1,363 @@
|
||||
local images = require("images")
|
||||
local bimg = require("bimg")
|
||||
local unpack,sub,max,min = table.unpack,string.sub,math.max,math.min
|
||||
return function(name, basalt)
|
||||
-- Image
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Image"
|
||||
|
||||
local bimgLibrary = bimg()
|
||||
local bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
local originalImage
|
||||
local image
|
||||
local activeFrame = 1
|
||||
|
||||
local infinitePlay = false
|
||||
local animTimer
|
||||
local usePalette = false
|
||||
local autoSize = true
|
||||
|
||||
local xOffset, yOffset = 0, 0
|
||||
|
||||
base:setSize(24, 8)
|
||||
base:setZIndex(2)
|
||||
|
||||
local function getPalette(id)
|
||||
local p = {}
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
p[k] = {term.nativePaletteColor(v)}
|
||||
end
|
||||
end
|
||||
local globalPalette = bimgLibrary.getMetadata("palette")
|
||||
if(globalPalette~=nil)then
|
||||
for k,v in pairs(globalPalette)do
|
||||
p[k] = tonumber(v)
|
||||
end
|
||||
end
|
||||
local localPalette = bimgLibrary.getFrameData("palette")
|
||||
basalt.log(localPalette)
|
||||
if(localPalette~=nil)then
|
||||
for k,v in pairs(localPalette)do
|
||||
p[k] = tonumber(v)
|
||||
end
|
||||
end
|
||||
return p
|
||||
end
|
||||
|
||||
local function checkAutoSize()
|
||||
if(autoSize)then
|
||||
if(bimgLibrary~=nil)then
|
||||
base:setSize(bimgLibrary.getSize())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setOffset = function(self, _x, _y, rel)
|
||||
if(rel)then
|
||||
xOffset = xOffset + _x or 0
|
||||
yOffset = yOffset + _y or 0
|
||||
else
|
||||
xOffset = _x or xOffset
|
||||
yOffset = _y or yOffset
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setXOffset = function(self, _x)
|
||||
return self:setOffset(self, _x, nil)
|
||||
end,
|
||||
|
||||
setYOffset = function(self, _y)
|
||||
return self:setOffset(self, nil, _y)
|
||||
end,
|
||||
|
||||
setSize = function(self, _x, _y)
|
||||
base:setSize(_x, _y)
|
||||
autoSize = false
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
selectFrame = function(self, id)
|
||||
if(bimgLibrary.getFrameObject(id)==nil)then
|
||||
bimgLibrary.addFrame(id)
|
||||
end
|
||||
bimgFrame = bimgLibrary.getFrameObject(id)
|
||||
image = bimgFrame.getImage(id)
|
||||
activeFrame = id
|
||||
self:updateDraw()
|
||||
end,
|
||||
|
||||
addFrame = function(self, id)
|
||||
bimgLibrary.addFrame(id)
|
||||
return self
|
||||
end,
|
||||
|
||||
getFrame = function(self, id)
|
||||
return bimgLibrary.getFrame(id)
|
||||
end,
|
||||
|
||||
getFrameObject = function(self, id)
|
||||
return bimgLibrary.getFrameObject(id)
|
||||
end,
|
||||
|
||||
removeFrame = function(self, id)
|
||||
bimgLibrary.removeFrame(id)
|
||||
return self
|
||||
end,
|
||||
|
||||
moveFrame = function(self, id, dir)
|
||||
bimgLibrary.moveFrame(id, dir)
|
||||
return self
|
||||
end,
|
||||
|
||||
getFrames = function(self)
|
||||
return bimgLibrary.getFrames()
|
||||
end,
|
||||
|
||||
getFrameCount = function(self)
|
||||
return #bimgLibrary.getFrames()
|
||||
end,
|
||||
|
||||
getActiveFrame = function(self)
|
||||
return activeFrame
|
||||
end,
|
||||
|
||||
loadImage = function(self, path)
|
||||
if(fs.exists(path))then
|
||||
local newBimg = images.loadBIMG(path)
|
||||
bimgLibrary = bimg(newBimg)
|
||||
activeFrame = 1
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
originalImage = bimgLibrary.createBimg()
|
||||
image = bimgFrame.getImage()
|
||||
checkAutoSize()
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setPath = function(self, path)
|
||||
return self:loadImage(path)
|
||||
end,
|
||||
|
||||
setImage = function(self, t)
|
||||
if(type(t)=="table")then
|
||||
bimgLibrary = bimg(t)
|
||||
activeFrame = 1
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
originalImage = bimgLibrary.createBimg()
|
||||
image = bimgFrame.getImage()
|
||||
checkAutoSize()
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
bimgLibrary = bimg()
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
image = nil
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getImage = function(self)
|
||||
return bimgLibrary.createBimg()
|
||||
end,
|
||||
|
||||
getImageFrame = function(self, id)
|
||||
return bimgFrame.getImage(id)
|
||||
end,
|
||||
|
||||
usePalette = function(self, use)
|
||||
usePalette = use~=nil and use or true
|
||||
return self
|
||||
end,
|
||||
|
||||
getUsePalette = function(self)
|
||||
return usePalette
|
||||
end,
|
||||
|
||||
setUsePalette = function(self, use)
|
||||
return self:usePalette(use)
|
||||
end,
|
||||
|
||||
play = function(self, inf)
|
||||
if(bimgLibrary.getMetadata("animated"))then
|
||||
local t = bimgLibrary.getMetadata("duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2
|
||||
self:listenEvent("other_event")
|
||||
animTimer = os.startTimer(t)
|
||||
infinitePlay = inf or false
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setPlay = function(self, inf)
|
||||
return self:play(inf)
|
||||
end,
|
||||
|
||||
stop = function(self)
|
||||
os.cancelTimer(animTimer)
|
||||
animTimer = nil
|
||||
infinitePlay = false
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, timerId, ...)
|
||||
base.eventHandler(self, event, timerId, ...)
|
||||
if(event=="timer")then
|
||||
if(timerId==animTimer)then
|
||||
if(bimgLibrary.getFrame(activeFrame+1)~=nil)then
|
||||
activeFrame = activeFrame + 1
|
||||
self:selectFrame(activeFrame)
|
||||
local t = bimgLibrary.getFrameData(activeFrame, "duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2
|
||||
animTimer = os.startTimer(t)
|
||||
else
|
||||
if(infinitePlay)then
|
||||
activeFrame = 1
|
||||
self:selectFrame(activeFrame)
|
||||
local t = bimgLibrary.getFrameData(activeFrame, "duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2
|
||||
animTimer = os.startTimer(t)
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
setMetadata = function(self, key, value)
|
||||
bimgLibrary.setMetadata(key, value)
|
||||
return self
|
||||
end,
|
||||
|
||||
getMetadata = function(self, key)
|
||||
return bimgLibrary.getMetadata(key)
|
||||
end,
|
||||
|
||||
getFrameMetadata = function(self, id, key)
|
||||
return bimgLibrary.getFrameData(id, key)
|
||||
end,
|
||||
|
||||
setFrameMetadata = function(self, id, key, value)
|
||||
bimgLibrary.setFrameData(id, key, value)
|
||||
return self
|
||||
end,
|
||||
|
||||
blit = function(self, text, fg, bg, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.blit(text, fg, bg, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setText = function(self, text, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.text(text, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setBg = function(self, bg, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.bg(bg, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setFg = function(self, fg, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.fg(fg, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getImageSize = function(self)
|
||||
return bimgLibrary.getSize()
|
||||
end,
|
||||
|
||||
setImageSize = function(self, w, h)
|
||||
bimgLibrary.setSize(w, h)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
resizeImage = function(self, w, h)
|
||||
local newBimg = images.resizeBIMG(originalImage, w, h)
|
||||
bimgLibrary = bimg(newBimg)
|
||||
activeFrame = 1
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("image", function()
|
||||
local w,h = self:getSize()
|
||||
local x, y = self:getPosition()
|
||||
local wParent, hParent = self:getParent():getSize()
|
||||
local parentXOffset, parentYOffset = self:getParent():getOffset()
|
||||
|
||||
if(x - parentXOffset > wParent)or(y - parentYOffset > hParent)or(x - parentXOffset + w < 1)or(y - parentYOffset + h < 1)then
|
||||
return
|
||||
end
|
||||
|
||||
if(usePalette)then
|
||||
self:getParent():setPalette(getPalette(activeFrame))
|
||||
end
|
||||
|
||||
if(image~=nil)then
|
||||
for k,v in pairs(image)do
|
||||
if(k+yOffset<=h)and(k+yOffset>=1)then
|
||||
local t,f,b = v[1],v[2],v[3]
|
||||
|
||||
local startIdx = max(1 - xOffset, 1)
|
||||
local endIdx = min(w - xOffset, #t)
|
||||
|
||||
t = sub(t, startIdx, endIdx)
|
||||
f = sub(f, startIdx, endIdx)
|
||||
b = sub(b, startIdx, endIdx)
|
||||
|
||||
self:addBlit(max(1 + xOffset, 1), k + yOffset, t, f, b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
312
lib/basalt/objects/Input.lua
Normal file
312
lib/basalt/objects/Input.lua
Normal file
@@ -0,0 +1,312 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Input
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Input"
|
||||
|
||||
local inputType = "text"
|
||||
local inputLimit = 0
|
||||
base:setZIndex(5)
|
||||
base:setValue("")
|
||||
base:setSize(12, 1)
|
||||
|
||||
local textX = 1
|
||||
local wIndex = 1
|
||||
|
||||
local defaultText = ""
|
||||
local defaultBGCol = colors.black
|
||||
local defaultFGCol = colors.lightGray
|
||||
local showingText = defaultText
|
||||
local internalValueChange = false
|
||||
|
||||
local object = {
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("key")
|
||||
self:listenEvent("char")
|
||||
self:listenEvent("other_event")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setDefaultFG = function(self, fCol)
|
||||
return self:setDefaultText(self, defaultText, fCol, nil)
|
||||
end,
|
||||
|
||||
setDefaultBG = function(self, bCol)
|
||||
return self:setDefaultText(self, defaultText, nil, bCol)
|
||||
end,
|
||||
|
||||
setDefaultText = function(self, text, fCol, bCol)
|
||||
defaultText = text
|
||||
defaultFGCol = fCol or defaultFGCol
|
||||
defaultBGCol = bCol or defaultBGCol
|
||||
if (self:isFocused()) then
|
||||
showingText = ""
|
||||
else
|
||||
showingText = defaultText
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDefaultText = function(self)
|
||||
return defaultText, defaultFGCol, defaultBGCol
|
||||
end,
|
||||
|
||||
setOffset = function(self, x)
|
||||
wIndex = x
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return wIndex
|
||||
end,
|
||||
|
||||
setTextOffset = function(self, x)
|
||||
textX = x
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextOffset = function(self)
|
||||
return textX
|
||||
end,
|
||||
|
||||
setInputType = function(self, t)
|
||||
inputType = t
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getInputType = function(self)
|
||||
return inputType
|
||||
end,
|
||||
|
||||
setValue = function(self, val)
|
||||
base.setValue(self, tostring(val))
|
||||
if not (internalValueChange) then
|
||||
textX = tostring(val):len() + 1
|
||||
wIndex = math.max(1, textX-self:getWidth()+1)
|
||||
if(self:isFocused())then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self:getForeground())
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getValue = function(self)
|
||||
local val = base.getValue(self)
|
||||
return inputType == "number" and tonumber(val) or val
|
||||
end,
|
||||
|
||||
setInputLimit = function(self, limit)
|
||||
inputLimit = tonumber(limit) or inputLimit
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getInputLimit = function(self)
|
||||
return inputLimit
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
base.getFocusHandler(self)
|
||||
local parent = self:getParent()
|
||||
if (parent ~= nil) then
|
||||
local obx, oby = self:getPosition()
|
||||
showingText = ""
|
||||
if(defaultText~="")then
|
||||
self:updateDraw()
|
||||
end
|
||||
parent:setCursor(true, obx + textX - wIndex, oby+math.max(math.ceil(self:getHeight()/2-1, 1)), self:getForeground())
|
||||
end
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
local parent = self:getParent()
|
||||
showingText = defaultText
|
||||
if(defaultText~="")then
|
||||
self:updateDraw()
|
||||
end
|
||||
parent:setCursor(false)
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key)
|
||||
if (base.keyHandler(self, key)) then
|
||||
local w,h = self:getSize()
|
||||
local parent = self:getParent()
|
||||
internalValueChange = true
|
||||
if (key == keys.backspace) then
|
||||
-- on backspace
|
||||
local text = tostring(base.getValue())
|
||||
if (textX > 1) then
|
||||
self:setValue(text:sub(1, textX - 2) .. text:sub(textX, text:len()))
|
||||
textX = math.max(textX - 1, 1)
|
||||
if (textX < wIndex) then
|
||||
wIndex = math.max(wIndex - 1, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (key == keys.enter) then
|
||||
parent:clearFocusedChild(self)
|
||||
end
|
||||
if (key == keys.right) then
|
||||
local tLength = tostring(base.getValue()):len()
|
||||
textX = textX + 1
|
||||
|
||||
if (textX > tLength) then
|
||||
textX = tLength + 1
|
||||
end
|
||||
textX = math.max(textX, 1)
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
end
|
||||
wIndex = math.max(wIndex, 1)
|
||||
end
|
||||
|
||||
if (key == keys.left) then
|
||||
-- left arrow
|
||||
textX = textX - 1
|
||||
if (textX >= 1) then
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX
|
||||
end
|
||||
end
|
||||
textX = math.max(textX, 1)
|
||||
wIndex = math.max(wIndex, 1)
|
||||
end
|
||||
local obx, oby = self:getPosition()
|
||||
local val = tostring(base.getValue())
|
||||
|
||||
self:updateDraw()
|
||||
internalValueChange = false
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if (base.charHandler(self, char)) then
|
||||
internalValueChange = true
|
||||
local w,h = self:getSize()
|
||||
local text = base.getValue()
|
||||
if (text:len() < inputLimit or inputLimit <= 0) then
|
||||
if (inputType == "number") then
|
||||
local cache = text
|
||||
if (textX==1 and char == "-") or (char == ".") or (tonumber(char) ~= nil) then
|
||||
self:setValue(text:sub(1, textX - 1) .. char .. text:sub(textX, text:len()))
|
||||
textX = textX + 1
|
||||
if(char==".")or(char=="-")and(#text>0)then
|
||||
if (tonumber(base.getValue()) == nil) then
|
||||
self:setValue(cache)
|
||||
textX = textX - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
self:setValue(text:sub(1, textX - 1) .. char .. text:sub(textX, text:len()))
|
||||
textX = textX + 1
|
||||
end
|
||||
if (textX >= w + wIndex) then
|
||||
wIndex = wIndex + 1
|
||||
end
|
||||
end
|
||||
local obx, oby = self:getPosition()
|
||||
local val = tostring(base.getValue())
|
||||
|
||||
internalValueChange = false
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if(base.mouseHandler(self, button, x, y))then
|
||||
local parent = self:getParent()
|
||||
local ax, ay = self:getPosition()
|
||||
local obx, oby = self:getAbsolutePosition(ax, ay)
|
||||
local w, h = self:getSize()
|
||||
textX = x - obx + wIndex
|
||||
local text = base.getValue()
|
||||
if (textX > text:len()) then
|
||||
textX = text:len() + 1
|
||||
end
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
parent:setCursor(true, ax + textX - wIndex, ay+math.max(math.ceil(h/2-1, 1)), self:getForeground())
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, btn, x, y, xOffset, yOffset)
|
||||
if(self:isFocused())then
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
if(base.dragHandler(self, btn, x, y, xOffset, yOffset))then
|
||||
return true
|
||||
end
|
||||
end
|
||||
local parent = self:getParent()
|
||||
parent:clearFocusedChild()
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("input", function()
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign)
|
||||
|
||||
local val = tostring(base.getValue())
|
||||
local bCol = self:getBackground()
|
||||
local fCol = self:getForeground()
|
||||
local text
|
||||
if (val:len() <= 0) then
|
||||
text = showingText
|
||||
bCol = defaultBGCol or bCol
|
||||
fCol = defaultFGCol or fCol
|
||||
end
|
||||
|
||||
text = showingText
|
||||
if (val ~= "") then
|
||||
text = val
|
||||
end
|
||||
text = text:sub(wIndex, w + wIndex - 1)
|
||||
local space = w - text:len()
|
||||
if (space < 0) then
|
||||
space = 0
|
||||
end
|
||||
if (inputType == "password") and (val ~= "") then
|
||||
text = string.rep("*", text:len())
|
||||
end
|
||||
text = text .. string.rep(" ", space)
|
||||
self:addBlit(1, verticalAlign, text, tHex[fCol]:rep(text:len()), tHex[bCol]:rep(text:len()))
|
||||
|
||||
if(self:isFocused())then
|
||||
parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self:getForeground())
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
115
lib/basalt/objects/Label.lua
Normal file
115
lib/basalt/objects/Label.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
local utils = require("utils")
|
||||
local wrapText = utils.wrapText
|
||||
local writeWrappedText = utils.writeWrappedText
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Label
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Label"
|
||||
|
||||
base:setZIndex(3)
|
||||
base:setSize(5, 1)
|
||||
base:setBackground(false)
|
||||
|
||||
local autoSize = true
|
||||
local text, textAlign = "Label", "left"
|
||||
|
||||
local object = {
|
||||
--- Returns the object type.
|
||||
--- @return string
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
--- Returns the label's base object.
|
||||
--- @return object
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
--- Changes the label's text.
|
||||
--- @param newText string The new text of the label.
|
||||
--- @return object
|
||||
setText = function(self, newText)
|
||||
text = tostring(newText)
|
||||
if(autoSize)then
|
||||
local t = wrapText(text, #text)
|
||||
local newW, newH = 1,1
|
||||
for k,v in pairs(t)do
|
||||
newH = newH+1
|
||||
newW = math.max(newW, v:len())
|
||||
end
|
||||
self:setSize(newW, newH)
|
||||
autoSize = true
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
--- Returns the label's autoSize property.
|
||||
--- @return boolean
|
||||
getAutoSize = function(self)
|
||||
return autoSize
|
||||
end,
|
||||
|
||||
--- Sets the label's autoSize property.
|
||||
--- @param bool boolean The new value of the autoSize property.
|
||||
--- @return object
|
||||
setAutoSize = function(self, bool)
|
||||
autoSize = bool
|
||||
return self
|
||||
end,
|
||||
|
||||
--- Returns the label's text.
|
||||
--- @return string
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
--- Sets the size of the label.
|
||||
--- @param width number The width of the label.
|
||||
--- @param height number The height of the label.
|
||||
--- @return object
|
||||
setSize = function(self, width, height)
|
||||
base.setSize(self, width, height)
|
||||
autoSize = false
|
||||
return self
|
||||
end,
|
||||
|
||||
--- Gets the text alignment of the label.
|
||||
--- @return string
|
||||
getTextAlign = function(self)
|
||||
return textAlign
|
||||
end,
|
||||
|
||||
--- Sets the text alignment of the label.
|
||||
--- @param align string The alignment of the text. Can be "left", "center", or "right".
|
||||
--- @return object
|
||||
setTextAlign = function(self, align)
|
||||
textAlign = align or textAlign
|
||||
return self;
|
||||
end,
|
||||
|
||||
--- Queues a new draw function to be called when the object is drawn.
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("label", function()
|
||||
local w, h = self:getSize()
|
||||
local align = textAlign=="center" and math.floor(w/2-text:len()/2+0.5) or textAlign=="right" and w-(text:len()-1) or 1
|
||||
writeWrappedText(self, align, 1, text, w+1, h)
|
||||
end)
|
||||
end,
|
||||
|
||||
--- Initializes the label.
|
||||
init = function(self)
|
||||
base.init(self)
|
||||
local parent = self:getParent()
|
||||
self:setForeground(parent:getForeground())
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
279
lib/basalt/objects/List.lua
Normal file
279
lib/basalt/objects/List.lua
Normal file
@@ -0,0 +1,279 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "List"
|
||||
|
||||
local list = {}
|
||||
local itemSelectedBG = colors.black
|
||||
local itemSelectedFG = colors.lightGray
|
||||
local selectionColorActive = true
|
||||
local textAlign = "left"
|
||||
local yOffset = 0
|
||||
local scrollable = true
|
||||
|
||||
base:setSize(16, 8)
|
||||
base:setZIndex(5)
|
||||
|
||||
local object = {
|
||||
init = function(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("mouse_scroll")
|
||||
return base.init(self)
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
setTextAlign = function(self, align)
|
||||
textAlign = align
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextAlign = function(self)
|
||||
return textAlign
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
addItem = function(self, text, bgCol, fgCol, ...)
|
||||
table.insert(list, { text = text, bgCol = bgCol or self:getBackground(), fgCol = fgCol or self:getForeground(), args = { ... } })
|
||||
if (#list <= 1) then
|
||||
self:setValue(list[1], false)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setOptions = function(self, ...)
|
||||
list = {}
|
||||
for k,v in pairs(...)do
|
||||
if(type(v)=="string")then
|
||||
table.insert(list, { text = v, bgCol = self:getBackground(), fgCol = self:getForeground(), args = {} })
|
||||
else
|
||||
table.insert(list, { text = v[1], bgCol = v[2] or self:getBackground(), fgCol = v[3] or self:getForeground(), args = v[4] or {} })
|
||||
end
|
||||
end
|
||||
self:setValue(list[1], false)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setOffset = function(self, yOff)
|
||||
yOffset = yOff
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
removeItem = function(self, index)
|
||||
if(type(index)=="number")then
|
||||
table.remove(list, index)
|
||||
elseif(type(index)=="table")then
|
||||
for k,v in pairs(list)do
|
||||
if(v==index)then
|
||||
table.remove(list, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getItem = function(self, index)
|
||||
return list[index]
|
||||
end,
|
||||
|
||||
getAll = function(self)
|
||||
return list
|
||||
end,
|
||||
|
||||
getOptions = function(self)
|
||||
return list
|
||||
end,
|
||||
|
||||
getItemIndex = function(self)
|
||||
local selected = self:getValue()
|
||||
for key, value in pairs(list) do
|
||||
if (value == selected) then
|
||||
return key
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
list = {}
|
||||
self:setValue({}, false)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getItemCount = function(self)
|
||||
return #list
|
||||
end,
|
||||
|
||||
editItem = function(self, index, text, bgCol, fgCol, ...)
|
||||
table.remove(list, index)
|
||||
table.insert(list, index, { text = text, bgCol = bgCol or self:getBackground(), fgCol = fgCol or self:getForeground(), args = { ... } })
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
selectItem = function(self, index)
|
||||
self:setValue(list[index] or {}, false)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionColor = function(self, bgCol, fgCol, active)
|
||||
itemSelectedBG = bgCol or self:getBackground()
|
||||
itemSelectedFG = fgCol or self:getForeground()
|
||||
selectionColorActive = active~=nil and active or true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionBG = function(self, bgCol)
|
||||
return self:setSelectionColor(bgCol, nil, selectionColorActive)
|
||||
end,
|
||||
|
||||
setSelectionFG = function(self, fgCol)
|
||||
return self:setSelectionColor(nil, fgCol, selectionColorActive)
|
||||
end,
|
||||
|
||||
getSelectionColor = function(self)
|
||||
return itemSelectedBG, itemSelectedFG
|
||||
end,
|
||||
|
||||
getSelectionBG = function(self)
|
||||
return itemSelectedBG
|
||||
end,
|
||||
|
||||
getSelectionFG = function(self)
|
||||
return itemSelectedFG
|
||||
end,
|
||||
|
||||
isSelectionColorActive = function(self)
|
||||
return selectionColorActive
|
||||
end,
|
||||
|
||||
setScrollable = function(self, scroll)
|
||||
scrollable = scroll
|
||||
if(scroll==nil)then scrollable = true end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollable = function(self)
|
||||
return scrollable
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base.scrollHandler(self, dir, x, y))then
|
||||
if(scrollable)then
|
||||
local w,h = self:getSize()
|
||||
yOffset = yOffset + dir
|
||||
if (yOffset < 0) then
|
||||
yOffset = 0
|
||||
end
|
||||
if (dir >= 1) then
|
||||
if (#list > h) then
|
||||
if (yOffset > #list - h) then
|
||||
yOffset = #list - h
|
||||
end
|
||||
if (yOffset >= #list) then
|
||||
yOffset = #list - 1
|
||||
end
|
||||
else
|
||||
yOffset = yOffset - 1
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if(base.mouseHandler(self, button, x, y))then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local w,h = self:getSize()
|
||||
if (#list > 0) then
|
||||
for n = 1, h do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
if (obx <= x) and (obx + w > x) and (oby + n - 1 == y) then
|
||||
self:setValue(list[n + yOffset])
|
||||
self:selectHandler()
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
return self:mouseHandler(button, x, y)
|
||||
end,
|
||||
|
||||
touchHandler = function(self, x, y)
|
||||
return self:mouseHandler(1, x, y)
|
||||
end,
|
||||
|
||||
onSelect = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("select_item", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
selectHandler = function(self)
|
||||
self:sendEvent("select_item", self:getValue())
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("list", function()
|
||||
local w, h = self:getSize()
|
||||
for n = 1, h do
|
||||
if list[n + yOffset] then
|
||||
local t = list[n + yOffset].text
|
||||
local fg, bg = list[n + yOffset].fgCol, list[n + yOffset].bgCol
|
||||
if list[n + yOffset] == self:getValue() and selectionColorActive then
|
||||
fg, bg = itemSelectedFG, itemSelectedBG
|
||||
end
|
||||
self:addText(1, n, t:sub(1,w))
|
||||
self:addBG(1, n, tHex[bg]:rep(w))
|
||||
self:addFG(1, n, tHex[fg]:rep(w))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
131
lib/basalt/objects/Menubar.lua
Normal file
131
lib/basalt/objects/Menubar.lua
Normal file
@@ -0,0 +1,131 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("List")(name, basalt)
|
||||
local objectType = "Menubar"
|
||||
local object = {}
|
||||
|
||||
base:setSize(30, 1)
|
||||
base:setZIndex(5)
|
||||
|
||||
local itemOffset = 0
|
||||
local space, outerSpace = 1, 1
|
||||
local scrollable = true
|
||||
|
||||
local function maxScroll()
|
||||
local mScroll = 0
|
||||
local w = base:getWidth()
|
||||
local list = base:getAll()
|
||||
for n = 1, #list do
|
||||
mScroll = mScroll + list[n].text:len() + space * 2
|
||||
end
|
||||
return math.max(mScroll - w, 0)
|
||||
end
|
||||
|
||||
object = {
|
||||
init = function(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("mouse_scroll")
|
||||
return base.init(self)
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
setSpace = function(self, _space)
|
||||
space = _space or space
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSpace = function(self)
|
||||
return space
|
||||
end,
|
||||
|
||||
setScrollable = function(self, scroll)
|
||||
scrollable = scroll
|
||||
if(scroll==nil)then scrollable = true end
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollable = function(self)
|
||||
return scrollable
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if(base:getBase().mouseHandler(self, button, x, y))then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local w,h = self:getSize()
|
||||
local xPos = 0
|
||||
local list = self:getAll()
|
||||
for n = 1, #list do
|
||||
if (list[n] ~= nil) then
|
||||
if (objX + xPos <= x + itemOffset) and (objX + xPos + list[n].text:len() + (space*2) > x + itemOffset) and (objY == y) then
|
||||
self:setValue(list[n])
|
||||
self:sendEvent(event, self, event, 0, x, y, list[n])
|
||||
end
|
||||
xPos = xPos + list[n].text:len() + space * 2
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base:getBase().scrollHandler(self, dir, x, y))then
|
||||
if(scrollable)then
|
||||
itemOffset = itemOffset + dir
|
||||
if (itemOffset < 0) then
|
||||
itemOffset = 0
|
||||
end
|
||||
|
||||
local mScroll = maxScroll()
|
||||
|
||||
if (itemOffset > mScroll) then
|
||||
itemOffset = mScroll
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("list", function()
|
||||
local parent = self:getParent()
|
||||
local w,h = self:getSize()
|
||||
local text = ""
|
||||
local textBGCol = ""
|
||||
local textFGCol = ""
|
||||
local itemSelectedBG, itemSelectedFG = self:getSelectionColor()
|
||||
for _, v in pairs(self:getAll()) do
|
||||
local newItem = (" "):rep(space) .. v.text .. (" "):rep(space)
|
||||
text = text .. newItem
|
||||
if(v == self:getValue())then
|
||||
textBGCol = textBGCol .. tHex[itemSelectedBG or v.bgCol or self:getBackground()]:rep(newItem:len())
|
||||
textFGCol = textFGCol .. tHex[itemSelectedFG or v.FgCol or self:getForeground()]:rep(newItem:len())
|
||||
else
|
||||
textBGCol = textBGCol .. tHex[v.bgCol or self:getBackground()]:rep(newItem:len())
|
||||
textFGCol = textFGCol .. tHex[v.FgCol or self:getForeground()]:rep(newItem:len())
|
||||
end
|
||||
end
|
||||
|
||||
self:addBlit(1, 1, text:sub(itemOffset+1, w+itemOffset), textFGCol:sub(itemOffset+1, w+itemOffset), textBGCol:sub(itemOffset+1, w+itemOffset))
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
81
lib/basalt/objects/MonitorFrame.lua
Normal file
81
lib/basalt/objects/MonitorFrame.lua
Normal file
@@ -0,0 +1,81 @@
|
||||
local basaltMon = require("basaltMon")
|
||||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("BaseFrame")(name, basalt)
|
||||
local objectType = "MonitorFrame"
|
||||
|
||||
base:setTerm(nil)
|
||||
local isMonitorGroup = false
|
||||
local monGroup
|
||||
|
||||
local object = {
|
||||
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
setMonitor = function(self, newMon)
|
||||
if(type(newMon)=="string")then
|
||||
local mon = peripheral.wrap(newMon)
|
||||
if(mon~=nil)then
|
||||
self:setTerm(mon)
|
||||
end
|
||||
elseif(type(newMon)=="table")then
|
||||
self:setTerm(newMon)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setMonitorGroup = function(self, monGrp)
|
||||
monGroup = basaltMon(monGrp)
|
||||
self:setTerm(monGroup)
|
||||
isMonitorGroup = true
|
||||
return self
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if(self:getTerm()~=nil)then
|
||||
base.render(self)
|
||||
end
|
||||
end,
|
||||
|
||||
show = function(self)
|
||||
base:getBase().show(self)
|
||||
basalt.setActiveFrame(self)
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(v, colors.packRGB(term.nativePaletteColor((v))))
|
||||
end
|
||||
end
|
||||
for k,v in pairs(colorTheme)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], v)
|
||||
else
|
||||
local r,g,b = table.unpack(v)
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.mouseHandler = function(self, btn, x, y, isMon, monitor, ...)
|
||||
if(isMonitorGroup)then
|
||||
x, y = monGroup.calculateClick(monitor, x, y)
|
||||
end
|
||||
base.mouseHandler(self, btn, x, y, isMon, monitor, ...)
|
||||
end
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
99
lib/basalt/objects/MovableFrame.lua
Normal file
99
lib/basalt/objects/MovableFrame.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Frame")(name, basalt)
|
||||
local objectType = "MovableFrame"
|
||||
local parent
|
||||
|
||||
local dragXOffset, dragYOffset, isDragging = 0, 0, false
|
||||
|
||||
local dragMap = {
|
||||
{x1 = 1, x2 = "width", y1 = 1, y2 = 1}
|
||||
}
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setDraggingMap = function(self, t)
|
||||
dragMap = t
|
||||
return self
|
||||
end,
|
||||
|
||||
getDraggingMap = function(self)
|
||||
return dragMap
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or (base.isType~=nil and base.isType(t)) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
base.load(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
removeChildren = function(self)
|
||||
base.removeChildren(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
dragHandler = function(self, btn, x, y)
|
||||
if(base.dragHandler(self, btn, x, y))then
|
||||
if (isDragging) then
|
||||
local xO, yO = parent:getOffset()
|
||||
xO = xO < 0 and math.abs(xO) or -xO
|
||||
yO = yO < 0 and math.abs(yO) or -yO
|
||||
local parentX = 1
|
||||
local parentY = 1
|
||||
parentX, parentY = parent:getAbsolutePosition()
|
||||
self:setPosition(x + dragXOffset - (parentX - 1) + xO, y + dragYOffset - (parentY - 1) + yO)
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, btn, x, y, ...)
|
||||
if(base.mouseHandler(self, btn, x, y, ...))then
|
||||
parent:setImportant(self)
|
||||
local fx, fy = self:getAbsolutePosition()
|
||||
local w, h = self:getSize()
|
||||
for k,v in pairs(dragMap)do
|
||||
local x1, x2 = v.x1=="width" and w or v.x1, v.x2=="width" and w or v.x2
|
||||
local y1, y2= v.y1=="height" and h or v.y1, v.y2=="height" and h or v.y2
|
||||
if(x>=fx+x1-1)and(x<=fx+x2-1)and(y>=fy+y1-1)and(y<=fy+y2-1)then
|
||||
isDragging = true
|
||||
dragXOffset = fx - x
|
||||
dragYOffset = fy - y
|
||||
return true
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, ...)
|
||||
isDragging = false
|
||||
return base.mouseUpHandler(self, ...)
|
||||
end,
|
||||
|
||||
setParent = function(self, p, ...)
|
||||
base.setParent(self, p, ...)
|
||||
parent = p
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
283
lib/basalt/objects/Object.lua
Normal file
283
lib/basalt/objects/Object.lua
Normal file
@@ -0,0 +1,283 @@
|
||||
local basaltEvent = require("basaltEvent")
|
||||
local utils = require("utils")
|
||||
local uuid = utils.uuid
|
||||
|
||||
local unpack,sub = table.unpack,string.sub
|
||||
|
||||
return function(name, basalt)
|
||||
name = name or uuid()
|
||||
assert(basalt~=nil, "Unable to find basalt instance! ID: "..name)
|
||||
|
||||
-- Base object
|
||||
local objectType = "Object" -- not changeable
|
||||
local isEnabled,initialized = true,false
|
||||
|
||||
local eventSystem = basaltEvent()
|
||||
local registeredEvents = {}
|
||||
local activeEvents = {}
|
||||
|
||||
local parent
|
||||
|
||||
local object = {
|
||||
init = function(self)
|
||||
if(initialized)then return false end
|
||||
initialized = true
|
||||
return true
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t
|
||||
end,
|
||||
|
||||
getProperty = function(self, name)
|
||||
local get = self["get" .. name:gsub("^%l", string.upper)]
|
||||
if (get ~= nil) then
|
||||
return get(self)
|
||||
end
|
||||
end,
|
||||
|
||||
setProperty = function(self, name, ...)
|
||||
local set = self["set" .. name:gsub("^%l", string.upper)]
|
||||
if (set ~= nil) then
|
||||
return set(self, ...)
|
||||
end
|
||||
end,
|
||||
|
||||
getName = function(self)
|
||||
return name
|
||||
end,
|
||||
|
||||
getParent = function(self)
|
||||
return parent
|
||||
end,
|
||||
|
||||
setParent = function(self, newParent, noRemove)
|
||||
if(noRemove)then parent = newParent return self end
|
||||
if (newParent.getType ~= nil and newParent:isType("Container")) then
|
||||
self:remove()
|
||||
newParent:addChild(self)
|
||||
if (self.show) then
|
||||
self:show()
|
||||
end
|
||||
parent = newParent
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
updateEvents = function(self)
|
||||
for k,v in pairs(activeEvents)do
|
||||
parent:removeEvent(k, self)
|
||||
if(v)then
|
||||
parent:addEvent(k, self)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
listenEvent = function(self, event, active)
|
||||
if(parent~=nil)then
|
||||
if(active)or(active==nil)then
|
||||
activeEvents[event] = true
|
||||
parent:addEvent(event, self)
|
||||
elseif(active==false)then
|
||||
activeEvents[event] = false
|
||||
parent:removeEvent(event, self)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getZIndex = function(self)
|
||||
return 1
|
||||
end,
|
||||
|
||||
enable = function(self)
|
||||
isEnabled = true
|
||||
return self
|
||||
end,
|
||||
|
||||
disable = function(self)
|
||||
isEnabled = false
|
||||
return self
|
||||
end,
|
||||
|
||||
isEnabled = function(self)
|
||||
return isEnabled
|
||||
end,
|
||||
|
||||
remove = function(self)
|
||||
if (parent ~= nil) then
|
||||
parent:removeChild(self)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBaseFrame = function(self)
|
||||
if(parent~=nil)then
|
||||
return parent:getBaseFrame()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onEvent = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("other_event", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getEventSystem = function(self)
|
||||
return eventSystem
|
||||
end,
|
||||
|
||||
getRegisteredEvents = function(self)
|
||||
return registeredEvents
|
||||
end,
|
||||
|
||||
registerEvent = function(self, event, func)
|
||||
if(parent~=nil)then
|
||||
parent:addEvent(event, self)
|
||||
end
|
||||
eventSystem:registerEvent(event, func)
|
||||
if (registeredEvents[event] == nil) then
|
||||
registeredEvents[event] = {}
|
||||
end
|
||||
table.insert(registeredEvents[event], func)
|
||||
end,
|
||||
|
||||
removeEvent = function(self, event, index)
|
||||
if(eventSystem:getEventCount(event)<1)then
|
||||
if(parent~=nil)then
|
||||
parent:removeEvent(event, self)
|
||||
end
|
||||
end
|
||||
eventSystem:removeEvent(event, index)
|
||||
if (registeredEvents[event] ~= nil) then
|
||||
table.remove(registeredEvents[event], index)
|
||||
if (#registeredEvents[event] == 0) then
|
||||
registeredEvents[event] = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
local val = self:sendEvent("other_event", event, ...)
|
||||
if(val~=nil)then return val end
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
local val = self:sendEvent("custom_event", event, ...)
|
||||
if(val~=nil)then return val end
|
||||
return true
|
||||
end,
|
||||
|
||||
sendEvent = function(self, event, ...)
|
||||
if(event=="other_event")or(event=="custom_event")then
|
||||
return eventSystem:sendEvent(event, self, ...)
|
||||
end
|
||||
return eventSystem:sendEvent(event, self, event, ...)
|
||||
end,
|
||||
|
||||
onClick = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_click", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onClickUp = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_up", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onRelease = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_release", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onScroll = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_scroll", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onHover = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_hover", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onLeave = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_leave", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onDrag = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_drag", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onKey = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("key", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onChar = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("char", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onKeyUp = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("key_up", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return object
|
||||
end
|
||||
16
lib/basalt/objects/Pane.lua
Normal file
16
lib/basalt/objects/Pane.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
return function(name, basalt)
|
||||
-- Pane
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Pane"
|
||||
|
||||
base:setSize(25, 10)
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
721
lib/basalt/objects/Program.lua
Normal file
721
lib/basalt/objects/Program.lua
Normal file
@@ -0,0 +1,721 @@
|
||||
local tHex = require("tHex")
|
||||
local process = require("process")
|
||||
|
||||
local sub = string.sub
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Program"
|
||||
local object
|
||||
local cachedPath
|
||||
local enviroment = {}
|
||||
|
||||
local function createBasaltWindow(x, y, width, height)
|
||||
local xCursor, yCursor = 1, 1
|
||||
local bgColor, fgColor = colors.black, colors.white
|
||||
local cursorBlink = false
|
||||
local visible = false
|
||||
|
||||
local cacheT = {}
|
||||
local cacheBG = {}
|
||||
local cacheFG = {}
|
||||
|
||||
local tPalette = {}
|
||||
|
||||
local emptySpaceLine
|
||||
local emptyColorLines = {}
|
||||
|
||||
for i = 0, 15 do
|
||||
local c = 2 ^ i
|
||||
tPalette[c] = { basalt.getTerm().getPaletteColour(c) }
|
||||
end
|
||||
|
||||
local function createEmptyLines()
|
||||
emptySpaceLine = (" "):rep(width)
|
||||
for n = 0, 15 do
|
||||
local nColor = 2 ^ n
|
||||
local sHex = tHex[nColor]
|
||||
emptyColorLines[nColor] = sHex:rep(width)
|
||||
end
|
||||
end
|
||||
|
||||
local function recreateWindowArray()
|
||||
createEmptyLines()
|
||||
local emptyText = emptySpaceLine
|
||||
local emptyFG = emptyColorLines[colors.white]
|
||||
local emptyBG = emptyColorLines[colors.black]
|
||||
for n = 1, height do
|
||||
cacheT[n] = sub(cacheT[n] == nil and emptyText or cacheT[n] .. emptyText:sub(1, width - cacheT[n]:len()), 1, width)
|
||||
cacheFG[n] = sub(cacheFG[n] == nil and emptyFG or cacheFG[n] .. emptyFG:sub(1, width - cacheFG[n]:len()), 1, width)
|
||||
cacheBG[n] = sub(cacheBG[n] == nil and emptyBG or cacheBG[n] .. emptyBG:sub(1, width - cacheBG[n]:len()), 1, width)
|
||||
end
|
||||
base.updateDraw(base)
|
||||
end
|
||||
recreateWindowArray()
|
||||
|
||||
local function updateCursor()
|
||||
if xCursor >= 1 and yCursor >= 1 and xCursor <= width and yCursor <= height then
|
||||
--parentTerminal.setCursorPos(xCursor + x - 1, yCursor + y - 1)
|
||||
else
|
||||
--parentTerminal.setCursorPos(0, 0)
|
||||
end
|
||||
--parentTerminal.setTextColor(fgColor)
|
||||
end
|
||||
|
||||
local function internalBlit(sText, sTextColor, sBackgroundColor)
|
||||
if yCursor < 1 or yCursor > height or xCursor < 1 or xCursor + #sText - 1 > width then
|
||||
return
|
||||
end
|
||||
cacheT[yCursor] = sub(cacheT[yCursor], 1, xCursor - 1) .. sText .. sub(cacheT[yCursor], xCursor + #sText, width)
|
||||
cacheFG[yCursor] = sub(cacheFG[yCursor], 1, xCursor - 1) .. sTextColor .. sub(cacheFG[yCursor], xCursor + #sText, width)
|
||||
cacheBG[yCursor] = sub(cacheBG[yCursor], 1, xCursor - 1) .. sBackgroundColor .. sub(cacheBG[yCursor], xCursor + #sText, width)
|
||||
xCursor = xCursor + #sText
|
||||
if visible then
|
||||
updateCursor()
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local function setText(_x, _y, text)
|
||||
if (text ~= nil) then
|
||||
local gText = cacheT[_y]
|
||||
if (gText ~= nil) then
|
||||
cacheT[_y] = sub(gText:sub(1, _x - 1) .. text .. gText:sub(_x + (text:len()), width), 1, width)
|
||||
end
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local function setBG(_x, _y, colorStr)
|
||||
if (colorStr ~= nil) then
|
||||
local gBG = cacheBG[_y]
|
||||
if (gBG ~= nil) then
|
||||
cacheBG[_y] = sub(gBG:sub(1, _x - 1) .. colorStr .. gBG:sub(_x + (colorStr:len()), width), 1, width)
|
||||
end
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local function setFG(_x, _y, colorStr)
|
||||
if (colorStr ~= nil) then
|
||||
local gFG = cacheFG[_y]
|
||||
if (gFG ~= nil) then
|
||||
cacheFG[_y] = sub(gFG:sub(1, _x - 1) .. colorStr .. gFG:sub(_x + (colorStr:len()), width), 1, width)
|
||||
end
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local setTextColor = function(color)
|
||||
if type(color) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(color) .. ")", 2)
|
||||
elseif tHex[color] == nil then
|
||||
error("Invalid color (got " .. color .. ")", 2)
|
||||
end
|
||||
fgColor = color
|
||||
end
|
||||
|
||||
local setBackgroundColor = function(color)
|
||||
if type(color) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(color) .. ")", 2)
|
||||
elseif tHex[color] == nil then
|
||||
error("Invalid color (got " .. color .. ")", 2)
|
||||
end
|
||||
bgColor = color
|
||||
end
|
||||
|
||||
local setPaletteColor = function(colour, r, g, b)
|
||||
-- have to work on
|
||||
if type(colour) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(colour) .. ")", 2)
|
||||
end
|
||||
|
||||
if tHex[colour] == nil then
|
||||
error("Invalid color (got " .. colour .. ")", 2)
|
||||
end
|
||||
|
||||
local tCol
|
||||
if type(r) == "number" and g == nil and b == nil then
|
||||
tCol = { colours.rgb8(r) }
|
||||
tPalette[colour] = tCol
|
||||
else
|
||||
if type(r) ~= "number" then
|
||||
error("bad argument #2 (expected number, got " .. type(r) .. ")", 2)
|
||||
end
|
||||
if type(g) ~= "number" then
|
||||
error("bad argument #3 (expected number, got " .. type(g) .. ")", 2)
|
||||
end
|
||||
if type(b) ~= "number" then
|
||||
error("bad argument #4 (expected number, got " .. type(b) .. ")", 2)
|
||||
end
|
||||
|
||||
tCol = tPalette[colour]
|
||||
tCol[1] = r
|
||||
tCol[2] = g
|
||||
tCol[3] = b
|
||||
end
|
||||
end
|
||||
|
||||
local getPaletteColor = function(colour)
|
||||
if type(colour) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(colour) .. ")", 2)
|
||||
end
|
||||
if tHex[colour] == nil then
|
||||
error("Invalid color (got " .. colour .. ")", 2)
|
||||
end
|
||||
local tCol = tPalette[colour]
|
||||
return tCol[1], tCol[2], tCol[3]
|
||||
end
|
||||
|
||||
local basaltwindow = {
|
||||
setCursorPos = function(_x, _y)
|
||||
if type(_x) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(_x) .. ")", 2)
|
||||
end
|
||||
if type(_y) ~= "number" then
|
||||
error("bad argument #2 (expected number, got " .. type(_y) .. ")", 2)
|
||||
end
|
||||
xCursor = math.floor(_x)
|
||||
yCursor = math.floor(_y)
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end,
|
||||
|
||||
getCursorPos = function()
|
||||
return xCursor, yCursor
|
||||
end;
|
||||
|
||||
setCursorBlink = function(blink)
|
||||
if type(blink) ~= "boolean" then
|
||||
error("bad argument #1 (expected boolean, got " .. type(blink) .. ")", 2)
|
||||
end
|
||||
cursorBlink = blink
|
||||
end;
|
||||
|
||||
getCursorBlink = function()
|
||||
return cursorBlink
|
||||
end;
|
||||
|
||||
|
||||
getPaletteColor = getPaletteColor,
|
||||
getPaletteColour = getPaletteColor,
|
||||
|
||||
setBackgroundColor = setBackgroundColor,
|
||||
setBackgroundColour = setBackgroundColor,
|
||||
|
||||
setTextColor = setTextColor,
|
||||
setTextColour = setTextColor,
|
||||
|
||||
setPaletteColor = setPaletteColor,
|
||||
setPaletteColour = setPaletteColor,
|
||||
|
||||
getBackgroundColor = function()
|
||||
return bgColor
|
||||
end;
|
||||
getBackgroundColour = function()
|
||||
return bgColor
|
||||
end;
|
||||
|
||||
getSize = function()
|
||||
return width, height
|
||||
end;
|
||||
|
||||
getTextColor = function()
|
||||
return fgColor
|
||||
end;
|
||||
getTextColour = function()
|
||||
return fgColor
|
||||
end;
|
||||
|
||||
basalt_resize = function(_width, _height)
|
||||
width, height = _width, _height
|
||||
recreateWindowArray()
|
||||
end;
|
||||
|
||||
basalt_reposition = function(_x, _y)
|
||||
x, y = _x, _y
|
||||
end;
|
||||
|
||||
basalt_setVisible = function(vis)
|
||||
visible = vis
|
||||
end;
|
||||
|
||||
drawBackgroundBox = function(_x, _y, _width, _height, bgCol)
|
||||
for n = 1, _height do
|
||||
setBG(_x, _y + (n - 1), tHex[bgCol]:rep(_width))
|
||||
end
|
||||
end;
|
||||
drawForegroundBox = function(_x, _y, _width, _height, fgCol)
|
||||
for n = 1, _height do
|
||||
setFG(_x, _y + (n - 1), tHex[fgCol]:rep(_width))
|
||||
end
|
||||
end;
|
||||
drawTextBox = function(_x, _y, _width, _height, symbol)
|
||||
for n = 1, _height do
|
||||
setText(_x, _y + (n - 1), symbol:rep(_width))
|
||||
end
|
||||
end;
|
||||
|
||||
basalt_update = function()
|
||||
for n = 1, height do
|
||||
object:addBlit(1, n, cacheT[n], cacheFG[n], cacheBG[n])
|
||||
end
|
||||
end,
|
||||
|
||||
scroll = function(offset)
|
||||
assert(type(offset) == "number", "bad argument #1 (expected number, got " .. type(offset) .. ")")
|
||||
if offset ~= 0 then
|
||||
for newY = 1, height do
|
||||
local y = newY + offset
|
||||
if y < 1 or y > height then
|
||||
cacheT[newY] = emptySpaceLine
|
||||
cacheFG[newY] = emptyColorLines[fgColor]
|
||||
cacheBG[newY] = emptyColorLines[bgColor]
|
||||
else
|
||||
cacheT[newY] = cacheT[y]
|
||||
cacheBG[newY] = cacheBG[y]
|
||||
cacheFG[newY] = cacheFG[y]
|
||||
end
|
||||
end
|
||||
end
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
isColor = function()
|
||||
return basalt.getTerm().isColor()
|
||||
end;
|
||||
|
||||
isColour = function()
|
||||
return basalt.getTerm().isColor()
|
||||
end;
|
||||
|
||||
write = function(text)
|
||||
text = tostring(text)
|
||||
if (visible) then
|
||||
internalBlit(text, tHex[fgColor]:rep(text:len()), tHex[bgColor]:rep(text:len()))
|
||||
end
|
||||
end;
|
||||
|
||||
clearLine = function()
|
||||
if (visible) then
|
||||
setText(1, yCursor, (" "):rep(width))
|
||||
setBG(1, yCursor, tHex[bgColor]:rep(width))
|
||||
setFG(1, yCursor, tHex[fgColor]:rep(width))
|
||||
end
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end;
|
||||
|
||||
clear = function()
|
||||
for n = 1, height do
|
||||
setText(1, n, (" "):rep(width))
|
||||
setBG(1, n, tHex[bgColor]:rep(width))
|
||||
setFG(1, n, tHex[fgColor]:rep(width))
|
||||
end
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end;
|
||||
|
||||
blit = function(text, fgcol, bgcol)
|
||||
if type(text) ~= "string" then
|
||||
error("bad argument #1 (expected string, got " .. type(text) .. ")", 2)
|
||||
end
|
||||
if type(fgcol) ~= "string" then
|
||||
error("bad argument #2 (expected string, got " .. type(fgcol) .. ")", 2)
|
||||
end
|
||||
if type(bgcol) ~= "string" then
|
||||
error("bad argument #3 (expected string, got " .. type(bgcol) .. ")", 2)
|
||||
end
|
||||
if #fgcol ~= #text or #bgcol ~= #text then
|
||||
error("Arguments must be the same length", 2)
|
||||
end
|
||||
if (visible) then
|
||||
internalBlit(text, fgcol, bgcol)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
}
|
||||
|
||||
return basaltwindow
|
||||
end
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setSize(30, 12)
|
||||
local pWindow = createBasaltWindow(1, 1, 30, 12)
|
||||
local curProcess
|
||||
local paused = false
|
||||
local queuedEvent = {}
|
||||
|
||||
local function updateCursor(self)
|
||||
local parent = self:getParent()
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then
|
||||
parent:setCursor(self:isFocused() and pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor())
|
||||
end
|
||||
end
|
||||
|
||||
local function resumeProcess(self, event, ...)
|
||||
local ok, result = curProcess:resume(event, ...)
|
||||
if (ok==false)and(result~=nil)and(result~="Terminated")then
|
||||
local val = self:sendEvent("program_error", result)
|
||||
if(val~=false)then
|
||||
error("Basalt Program - "..result)
|
||||
end
|
||||
end
|
||||
|
||||
if(curProcess:getStatus()=="dead")then
|
||||
self:sendEvent("program_done")
|
||||
end
|
||||
end
|
||||
|
||||
local function mouseEvent(self, event, p1, x, y)
|
||||
if (curProcess == nil) then
|
||||
return false
|
||||
end
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
local absX, absY = self:getAbsolutePosition()
|
||||
resumeProcess(self, event, p1, x-absX+1, y-absY+1)
|
||||
updateCursor(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function keyEvent(self, event, key, isHolding)
|
||||
if (curProcess == nil) then
|
||||
return false
|
||||
end
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
if (self.draw) then
|
||||
resumeProcess(self, event, key, isHolding)
|
||||
updateCursor(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end;
|
||||
|
||||
show = function(self)
|
||||
base.show(self)
|
||||
pWindow.setBackgroundColor(self:getBackground())
|
||||
pWindow.setTextColor(self:getForeground())
|
||||
pWindow.basalt_setVisible(true)
|
||||
return self
|
||||
end;
|
||||
|
||||
hide = function(self)
|
||||
base.hide(self)
|
||||
pWindow.basalt_setVisible(false)
|
||||
return self
|
||||
end;
|
||||
|
||||
setPosition = function(self, x, y, rel)
|
||||
base.setPosition(self, x, y, rel)
|
||||
pWindow.basalt_reposition(self:getPosition())
|
||||
return self
|
||||
end,
|
||||
|
||||
getBasaltWindow = function()
|
||||
return pWindow
|
||||
end;
|
||||
|
||||
getBasaltProcess = function()
|
||||
return curProcess
|
||||
end;
|
||||
|
||||
setSize = function(self, width, height, rel)
|
||||
base.setSize(self, width, height, rel)
|
||||
pWindow.basalt_resize(self:getWidth(), self:getHeight())
|
||||
return self
|
||||
end;
|
||||
|
||||
getStatus = function(self)
|
||||
if (curProcess ~= nil) then
|
||||
return curProcess:getStatus()
|
||||
end
|
||||
return "inactive"
|
||||
end;
|
||||
|
||||
setEnviroment = function(self, env)
|
||||
enviroment = env or {}
|
||||
return self
|
||||
end,
|
||||
|
||||
execute = function(self, path, ...)
|
||||
cachedPath = path or cachedPath
|
||||
curProcess = process:new(cachedPath, pWindow, enviroment, ...)
|
||||
pWindow.setBackgroundColor(colors.black)
|
||||
pWindow.setTextColor(colors.white)
|
||||
pWindow.clear()
|
||||
pWindow.setCursorPos(1, 1)
|
||||
pWindow.setBackgroundColor(self:getBackground())
|
||||
pWindow.setTextColor(self:getForeground() or colors.white)
|
||||
pWindow.basalt_setVisible(true)
|
||||
|
||||
resumeProcess(self)
|
||||
paused = false
|
||||
self:listenEvent("mouse_click", self)
|
||||
self:listenEvent("mouse_up", self)
|
||||
self:listenEvent("mouse_drag", self)
|
||||
self:listenEvent("mouse_scroll", self)
|
||||
self:listenEvent("key", self)
|
||||
self:listenEvent("key_up", self)
|
||||
self:listenEvent("char", self)
|
||||
self:listenEvent("other_event", self)
|
||||
return self
|
||||
end;
|
||||
|
||||
setExecute = function(self, path, ...)
|
||||
return self:execute(path, ...)
|
||||
end,
|
||||
|
||||
stop = function(self)
|
||||
local parent = self:getParent()
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
resumeProcess(self, "terminate")
|
||||
if (curProcess:isDead()) then
|
||||
parent:setCursor(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
parent:removeEvents(self)
|
||||
return self
|
||||
end;
|
||||
|
||||
pause = function(self, p)
|
||||
paused = p or (not paused)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
self:injectEvents(table.unpack(queuedEvent))
|
||||
queuedEvent = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end;
|
||||
|
||||
isPaused = function(self)
|
||||
return paused
|
||||
end;
|
||||
|
||||
injectEvent = function(self, event, ign, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if (paused == false) or (ign) then
|
||||
resumeProcess(self, event, ...)
|
||||
else
|
||||
table.insert(queuedEvent, { event = event, args = {...} })
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end;
|
||||
|
||||
getQueuedEvents = function(self)
|
||||
return queuedEvent
|
||||
end;
|
||||
|
||||
updateQueuedEvents = function(self, events)
|
||||
queuedEvent = events or queuedEvent
|
||||
return self
|
||||
end;
|
||||
|
||||
injectEvents = function(self, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
for _, value in pairs({...}) do
|
||||
resumeProcess(self, value.event, table.unpack(value.args))
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end;
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
mouseEvent(self, "mouse_click", button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
if (base.mouseUpHandler(self, button, x, y)) then
|
||||
mouseEvent(self, "mouse_up", button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if (base.scrollHandler(self, dir, x, y)) then
|
||||
mouseEvent(self, "mouse_scroll", dir, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
mouseEvent(self, "mouse_drag", button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key, isHolding)
|
||||
if(base.keyHandler(self, key, isHolding))then
|
||||
keyEvent(self, "key", key, isHolding)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
keyUpHandler = function(self, key)
|
||||
if(base.keyUpHandler(self, key))then
|
||||
keyEvent(self, "key_up", key)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if(base.charHandler(self, char))then
|
||||
keyEvent(self, "char", char)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
base.getFocusHandler(self)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
local parent = self:getParent()
|
||||
if (parent ~= nil) then
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then
|
||||
parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
local parent = self:getParent()
|
||||
if (parent ~= nil) then
|
||||
parent:setCursor(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if curProcess == nil then
|
||||
return
|
||||
end
|
||||
if not curProcess:isDead() then
|
||||
if not paused then
|
||||
resumeProcess(self, event, ...)
|
||||
if self:isFocused() then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local w,h = self:getSize()
|
||||
if obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1 then
|
||||
parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor())
|
||||
end
|
||||
end
|
||||
else
|
||||
table.insert(queuedEvent, { event = event, args = { ... } })
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
resizeHandler = function(self, ...)
|
||||
base.resizeHandler(self, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
pWindow.basalt_resize(self:getSize())
|
||||
resumeProcess(self, "term_resize", self:getSize())
|
||||
else
|
||||
pWindow.basalt_resize(self:getSize())
|
||||
table.insert(queuedEvent, { event = "term_resize", args = { self:getSize() } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
repositionHandler = function(self, ...)
|
||||
base.repositionHandler(self, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
pWindow.basalt_reposition(self:getPosition())
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("program", function()
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local w,h = self:getSize()
|
||||
pWindow.basalt_update()
|
||||
end)
|
||||
end,
|
||||
|
||||
onError = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("program_error", v)
|
||||
end
|
||||
end
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
onDone = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("program_done", v)
|
||||
end
|
||||
end
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
136
lib/basalt/objects/Progressbar.lua
Normal file
136
lib/basalt/objects/Progressbar.lua
Normal file
@@ -0,0 +1,136 @@
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Progressbar"
|
||||
|
||||
local progress = 0
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setValue(false)
|
||||
base:setSize(25, 3)
|
||||
|
||||
local activeBarColor = colors.black
|
||||
local activeBarSymbol = ""
|
||||
local activeBarSymbolCol = colors.white
|
||||
local bgBarSymbol = ""
|
||||
local direction = 0
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setDirection = function(self, dir)
|
||||
direction = dir
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDirection = function(self)
|
||||
return direction
|
||||
end,
|
||||
|
||||
setProgressBar = function(self, color, symbol, symbolcolor)
|
||||
activeBarColor = color or activeBarColor
|
||||
activeBarSymbol = symbol or activeBarSymbol
|
||||
activeBarSymbolCol = symbolcolor or activeBarSymbolCol
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getProgressBar = function(self)
|
||||
return activeBarColor, activeBarSymbol, activeBarSymbolCol
|
||||
end,
|
||||
|
||||
setActiveBarColor = function(self, color)
|
||||
return self:setProgressBar(color, nil, nil)
|
||||
end,
|
||||
|
||||
getActiveBarColor = function(self)
|
||||
return activeBarColor
|
||||
end,
|
||||
|
||||
setActiveBarSymbol = function(self, symbol)
|
||||
return self:setProgressBar(nil, symbol, nil)
|
||||
end,
|
||||
|
||||
getActiveBarSymbol = function(self)
|
||||
return activeBarSymbol
|
||||
end,
|
||||
|
||||
setActiveBarSymbolColor = function(self, symbolColor)
|
||||
return self:setProgressBar(nil, nil, symbolColor)
|
||||
end,
|
||||
|
||||
getActiveBarSymbolColor = function(self)
|
||||
return activeBarSymbolCol
|
||||
end,
|
||||
|
||||
setBackgroundSymbol = function(self, symbol)
|
||||
bgBarSymbol = symbol:sub(1, 1)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBackgroundSymbol = function(self)
|
||||
return bgBarSymbol
|
||||
end,
|
||||
|
||||
setProgress = function(self, value)
|
||||
if (value >= 0) and (value <= 100) and (progress ~= value) then
|
||||
progress = value
|
||||
self:setValue(progress)
|
||||
if (progress == 100) then
|
||||
self:progressDoneHandler()
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getProgress = function(self)
|
||||
return progress
|
||||
end,
|
||||
|
||||
onProgressDone = function(self, f)
|
||||
self:registerEvent("progress_done", f)
|
||||
return self
|
||||
end,
|
||||
|
||||
progressDoneHandler = function(self)
|
||||
self:sendEvent("progress_done")
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("progressbar", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
if(bgCol~=false)then self:addBackgroundBox(1, 1, w, h, bgCol) end
|
||||
if(bgBarSymbol~="")then self:addTextBox(1, 1, w, h, bgBarSymbol) end
|
||||
if(fgCol~=false)then self:addForegroundBox(1, 1, w, h, fgCol) end
|
||||
if (direction == 1) then
|
||||
self:addBackgroundBox(1, 1, w, h / 100 * progress, activeBarColor)
|
||||
self:addForegroundBox(1, 1, w, h / 100 * progress, activeBarSymbolCol)
|
||||
self:addTextBox(1, 1, w, h / 100 * progress, activeBarSymbol)
|
||||
elseif (direction == 3) then
|
||||
self:addBackgroundBox(1, 1 + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarColor)
|
||||
self:addForegroundBox(1, 1 + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbolCol)
|
||||
self:addTextBox(1, 1 + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbol)
|
||||
elseif (direction == 2) then
|
||||
self:addBackgroundBox(1 + math.ceil(w - w / 100 * progress), 1, w / 100 * progress, h, activeBarColor)
|
||||
self:addForegroundBox(1 + math.ceil(w - w / 100 * progress), 1, w / 100 * progress, h, activeBarSymbolCol)
|
||||
self:addTextBox(1 + math.ceil(w - w / 100 * progress), 1, w / 100 * progress, h, activeBarSymbol)
|
||||
else
|
||||
self:addBackgroundBox(1, 1, math.ceil( w / 100 * progress), h, activeBarColor)
|
||||
self:addForegroundBox(1, 1, math.ceil(w / 100 * progress), h, activeBarSymbolCol)
|
||||
self:addTextBox(1, 1, math.ceil(w / 100 * progress), h, activeBarSymbol)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
138
lib/basalt/objects/Radio.lua
Normal file
138
lib/basalt/objects/Radio.lua
Normal file
@@ -0,0 +1,138 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("List")(name, basalt)
|
||||
local objectType = "Radio"
|
||||
|
||||
base:setSize(1, 1)
|
||||
base:setZIndex(5)
|
||||
|
||||
local list = {}
|
||||
local boxSelectedBG = colors.black
|
||||
local boxSelectedFG = colors.green
|
||||
local boxNotSelectedBG = colors.black
|
||||
local boxNotSelectedFG = colors.red
|
||||
local selectionColorActive = true
|
||||
local symbol = "\7"
|
||||
local align = "left"
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
addItem = function(self, text, x, y, bgCol, fgCol, ...)
|
||||
base.addItem(self, text, bgCol, fgCol, ...)
|
||||
table.insert(list, { x = x or 1, y = y or #list * 2 })
|
||||
return self
|
||||
end,
|
||||
|
||||
removeItem = function(self, index)
|
||||
base.removeItem(self, index)
|
||||
table.remove(list, index)
|
||||
return self
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
base.clear(self)
|
||||
list = {}
|
||||
return self
|
||||
end,
|
||||
|
||||
editItem = function(self, index, text, x, y, bgCol, fgCol, ...)
|
||||
base.editItem(self, index, text, bgCol, fgCol, ...)
|
||||
table.remove(list, index)
|
||||
table.insert(list, index, { x = x or 1, y = y or 1 })
|
||||
return self
|
||||
end,
|
||||
|
||||
setBoxSelectionColor = function(self, bg, fg)
|
||||
boxSelectedBG = bg
|
||||
boxSelectedFG = fg
|
||||
return self
|
||||
end,
|
||||
|
||||
setBoxSelectionBG = function(self, bg)
|
||||
return self:setBoxSelectionColor(bg, boxSelectedFG)
|
||||
end,
|
||||
|
||||
setBoxSelectionFG = function(self, fg)
|
||||
return self:setBoxSelectionColor(boxSelectedBG, fg)
|
||||
end,
|
||||
|
||||
getBoxSelectionColor = function(self)
|
||||
return boxSelectedBG, boxSelectedFG
|
||||
end,
|
||||
|
||||
getBoxSelectionBG = function(self)
|
||||
return boxSelectedBG
|
||||
end,
|
||||
|
||||
getBoxSelectionFG = function(self)
|
||||
return boxSelectedFG
|
||||
end,
|
||||
|
||||
setBoxDefaultColor = function(self, bg, fg)
|
||||
boxNotSelectedBG = bg
|
||||
boxNotSelectedFG = fg
|
||||
return self
|
||||
end,
|
||||
|
||||
setBoxDefaultBG = function(self, bg)
|
||||
return self:setBoxDefaultColor(bg, boxNotSelectedFG)
|
||||
end,
|
||||
|
||||
setBoxDefaultFG = function(self, fg)
|
||||
return self:setBoxDefaultColor(boxNotSelectedBG, fg)
|
||||
end,
|
||||
|
||||
getBoxDefaultColor = function(self)
|
||||
return boxNotSelectedBG, boxNotSelectedFG
|
||||
end,
|
||||
|
||||
getBoxDefaultBG = function(self)
|
||||
return boxNotSelectedBG
|
||||
end,
|
||||
|
||||
getBoxDefaultFG = function(self)
|
||||
return boxNotSelectedFG
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, ...)
|
||||
if (#list > 0) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local baseList = self:getAll()
|
||||
for k, value in pairs(baseList) do
|
||||
if (obx + list[k].x - 1 <= x) and (obx + list[k].x - 1 + value.text:len() + 1 >= x) and (oby + list[k].y - 1 == y) then
|
||||
self:setValue(value)
|
||||
local val = self:sendEvent("mouse_click", self, "mouse_click", button, x, y, ...)
|
||||
self:updateDraw()
|
||||
if(val==false)then return val end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
self:addDraw("radio", function()
|
||||
local itemSelectedBG, itemSelectedFG = self:getSelectionColor()
|
||||
local baseList = self:getAll()
|
||||
for k, value in pairs(baseList) do
|
||||
if (value == self:getValue()) then
|
||||
self:addBlit(list[k].x, list[k].y, symbol, tHex[boxSelectedFG], tHex[boxSelectedBG])
|
||||
self:addBlit(list[k].x + 2, list[k].y, value.text, tHex[itemSelectedFG]:rep(#value.text), tHex[itemSelectedBG]:rep(#value.text))
|
||||
else
|
||||
self:addBackgroundBox(list[k].x, list[k].y, 1, 1, boxNotSelectedBG or colors.black)
|
||||
self:addBlit(list[k].x + 2, list[k].y, value.text, tHex[value.fgCol]:rep(#value.text), tHex[value.bgCol]:rep(#value.text))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
147
lib/basalt/objects/ScrollableFrame.lua
Normal file
147
lib/basalt/objects/ScrollableFrame.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Frame")(name, basalt)
|
||||
local objectType = "ScrollableFrame"
|
||||
local parent
|
||||
|
||||
local direction = 0
|
||||
local manualScrollAmount = 0
|
||||
local calculateScrollAmount = true
|
||||
|
||||
local function getHorizontalScrollAmount(self)
|
||||
local amount = 0
|
||||
local children = self:getChildren()
|
||||
for _, b in pairs(children) do
|
||||
if(b.element.getWidth~=nil)and(b.element.getX~=nil)then
|
||||
local w, x = b.element:getWidth(), b.element:getX()
|
||||
local width = self:getWidth()
|
||||
if(b.element:getType()=="Dropdown")then
|
||||
if(b.element:isOpened())then
|
||||
local dropdownW = b.element:getDropdownSize()
|
||||
if (dropdownW + x - width >= amount) then
|
||||
amount = max(dropdownW + x - width, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (w + x - width >= amount) then
|
||||
amount = max(w + x - width, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return amount
|
||||
end
|
||||
|
||||
local function getVerticalScrollAmount(self)
|
||||
local amount = 0
|
||||
local children = self:getChildren()
|
||||
for _, b in pairs(children) do
|
||||
if(b.element.getHeight~=nil)and(b.element.getY~=nil)then
|
||||
local h, y = b.element:getHeight(), b.element:getY()
|
||||
local height = self:getHeight()
|
||||
if(b.element:getType()=="Dropdown")then
|
||||
if(b.element:isOpened())then
|
||||
local _,dropdownH = b.element:getDropdownSize()
|
||||
if (dropdownH + y - height >= amount) then
|
||||
amount = max(dropdownH + y - height, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (h + y - height >= amount) then
|
||||
amount = max(h + y - height, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return amount
|
||||
end
|
||||
|
||||
local function scrollHandler(self, dir)
|
||||
local xO, yO = self:getOffset()
|
||||
local scrollAmn
|
||||
if(direction==1)then
|
||||
scrollAmn = calculateScrollAmount and getHorizontalScrollAmount(self) or manualScrollAmount
|
||||
self:setOffset(min(scrollAmn, max(0, xO + dir)), yO)
|
||||
elseif(direction==0)then
|
||||
scrollAmn = calculateScrollAmount and getVerticalScrollAmount(self) or manualScrollAmount
|
||||
self:setOffset(xO, min(scrollAmn, max(0, yO + dir)))
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setDirection = function(self, dir)
|
||||
direction = dir=="horizontal" and 1 or dir=="vertical" and 0 or direction
|
||||
return self
|
||||
end,
|
||||
|
||||
setScrollAmount = function(self, amount)
|
||||
manualScrollAmount = amount
|
||||
calculateScrollAmount = false
|
||||
return self
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
base.load(self)
|
||||
self:listenEvent("mouse_scroll")
|
||||
end,
|
||||
|
||||
removeChildren = function(self)
|
||||
base.removeChildren(self)
|
||||
self:listenEvent("mouse_scroll")
|
||||
end,
|
||||
|
||||
setParent = function(self, p, ...)
|
||||
base.setParent(self, p, ...)
|
||||
parent = p
|
||||
return self
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base:getBase().scrollHandler(self, dir, x, y))then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(self:getEvents("mouse_scroll")) do
|
||||
if (obj.element.scrollHandler ~= nil) then
|
||||
local xO, yO = 0, 0
|
||||
if(self.getOffset~=nil)then
|
||||
xO, yO = self:getOffset()
|
||||
end
|
||||
if(obj.element.getIgnoreOffset())then
|
||||
xO, yO = 0, 0
|
||||
end
|
||||
if (obj.element.scrollHandler(obj.element, dir, x+xO, y+yO)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
scrollHandler(self, dir, x, y)
|
||||
self:clearFocusedChild()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("scrollableFrame", function()
|
||||
if(calculateScrollAmount)then
|
||||
scrollHandler(self, 0)
|
||||
end
|
||||
end, 0)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
218
lib/basalt/objects/Scrollbar.lua
Normal file
218
lib/basalt/objects/Scrollbar.lua
Normal file
@@ -0,0 +1,218 @@
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Scrollbar"
|
||||
|
||||
base:setZIndex(2)
|
||||
base:setSize(1, 8)
|
||||
base:setBackground(colors.lightGray, "\127", colors.gray)
|
||||
|
||||
local barType = "vertical"
|
||||
local symbol = " "
|
||||
local symbolBG = colors.black
|
||||
local symbolFG = colors.black
|
||||
local scrollAmount = 3
|
||||
local index = 1
|
||||
local symbolSize = 1
|
||||
local symbolAutoSize = true
|
||||
|
||||
local function updateSymbolSize()
|
||||
local w,h = base:getSize()
|
||||
if(symbolAutoSize)then
|
||||
symbolSize = math.max((barType == "vertical" and h or w-(#symbol)) - (scrollAmount-1), 1)
|
||||
end
|
||||
end
|
||||
updateSymbolSize()
|
||||
|
||||
local function mouseEvent(self, button, x, y)
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local w,h = self:getSize()
|
||||
updateSymbolSize()
|
||||
local size = barType == "vertical" and h or w
|
||||
for i = 0, size do
|
||||
if ((barType == "vertical" and oby + i == y) or (barType == "horizontal" and obx + i == x)) and (obx <= x) and (obx + w > x) and (oby <= y) and (oby + h > y) then
|
||||
index = math.min(i + 1, size - (#symbol + symbolSize - 2))
|
||||
self:scrollbarMoveHandler()
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
base.load(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_scroll")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
setSymbol = function(self, _symbol, bg, fg)
|
||||
symbol = _symbol:sub(1,1)
|
||||
symbolBG = bg or symbolBG
|
||||
symbolFG = fg or symbolFG
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSymbolBG = function(self, bg)
|
||||
return self:setSymbol(symbol, bg, nil)
|
||||
end,
|
||||
|
||||
setSymbolFG = function(self, fg)
|
||||
return self:setSymbol(symbol, nil, fg)
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return symbol
|
||||
end,
|
||||
|
||||
getSymbolBG = function(self)
|
||||
return symbolBG
|
||||
end,
|
||||
|
||||
getSymbolFG = function(self)
|
||||
return symbolFG
|
||||
end,
|
||||
|
||||
setIndex = function(self, _index)
|
||||
index = _index
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
local w,h = self:getSize()
|
||||
--index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1))
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setScrollAmount = function(self, amount)
|
||||
scrollAmount = amount
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollAmount = function(self)
|
||||
return scrollAmount
|
||||
end,
|
||||
|
||||
getIndex = function(self)
|
||||
local w,h = self:getSize()
|
||||
return scrollAmount > (barType=="vertical" and h or w) and math.floor(scrollAmount/(barType=="vertical" and h or w) * index) or index
|
||||
end,
|
||||
|
||||
setSymbolSize = function(self, size)
|
||||
symbolSize = tonumber(size) or 1
|
||||
symbolAutoSize = size~=false and false or true
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbolSize = function(self)
|
||||
return symbolSize
|
||||
end,
|
||||
|
||||
setBarType = function(self, _typ)
|
||||
barType = _typ:lower()
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBarType = function(self)
|
||||
return barType
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, ...)
|
||||
if (base.mouseHandler(self, button, x, y, ...)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
setSize = function(self, ...)
|
||||
base.setSize(self, ...)
|
||||
updateSymbolSize()
|
||||
return self
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base.scrollHandler(self, dir, x, y))then
|
||||
local w,h = self:getSize()
|
||||
updateSymbolSize()
|
||||
index = index + dir
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
index = math.min(index, (barType == "vertical" and h or w) - (barType == "vertical" and symbolSize - 1 or #symbol+symbolSize-2))
|
||||
self:scrollbarMoveHandler()
|
||||
self:updateDraw()
|
||||
end
|
||||
end,
|
||||
|
||||
onChange = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("scrollbar_moved", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
|
||||
scrollbarMoveHandler = function(self)
|
||||
self:sendEvent("scrollbar_moved", self:getIndex())
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
base.customEventHandler(self, event, ...)
|
||||
if(event=="basalt_FrameResize")then
|
||||
updateSymbolSize()
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("scrollbar", function()
|
||||
local parent = self:getParent()
|
||||
local w,h = self:getSize()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
if (barType == "horizontal") then
|
||||
for n = 0, h - 1 do
|
||||
self:addBlit(index, 1 + n, symbol:rep(symbolSize), tHex[symbolFG]:rep(#symbol*symbolSize), tHex[symbolBG]:rep(#symbol*symbolSize))
|
||||
end
|
||||
elseif (barType == "vertical") then
|
||||
for n = 0, h - 1 do
|
||||
if (index == n + 1) then
|
||||
for curIndexOffset = 0, math.min(symbolSize - 1, h) do
|
||||
self:addBlit(1, index + curIndexOffset, symbol:rep(math.max(#symbol, w)), tHex[symbolFG]:rep(math.max(#symbol, w)), tHex[symbolBG]:rep(math.max(#symbol, w)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
159
lib/basalt/objects/Slider.lua
Normal file
159
lib/basalt/objects/Slider.lua
Normal file
@@ -0,0 +1,159 @@
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Slider"
|
||||
|
||||
base:setSize(12, 1)
|
||||
base:setValue(1)
|
||||
base:setBackground(false, "\140", colors.black)
|
||||
|
||||
local barType = "horizontal"
|
||||
local symbol = " "
|
||||
local symbolFG = colors.black
|
||||
local symbolBG = colors.gray
|
||||
local maxValue = 12
|
||||
local index = 1
|
||||
local symbolSize = 1
|
||||
|
||||
local function mouseEvent(self, button, x, y)
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local size = barType == "vertical" and h or w
|
||||
for i = 0, size do
|
||||
if ((barType == "vertical" and oby + i == y) or (barType == "horizontal" and obx + i == x)) and (obx <= x) and (obx + w > x) and (oby <= y) and (oby + h > y) then
|
||||
index = math.min(i + 1, size - (#symbol + symbolSize - 2))
|
||||
self:setValue(maxValue / size * index)
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("mouse_scroll")
|
||||
end,
|
||||
|
||||
setSymbol = function(self, _symbol)
|
||||
symbol = _symbol:sub(1, 1)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return symbol
|
||||
end,
|
||||
|
||||
setIndex = function(self, _index)
|
||||
index = _index
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
local w,h = self:getSize()
|
||||
index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1))
|
||||
self:setValue(maxValue / (barType == "vertical" and h or w) * index)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getIndex = function(self)
|
||||
return index
|
||||
end,
|
||||
|
||||
setMaxValue = function(self, val)
|
||||
maxValue = val
|
||||
return self
|
||||
end,
|
||||
|
||||
getMaxValue = function(self)
|
||||
return maxValue
|
||||
end,
|
||||
|
||||
setSymbolColor = function(self, col)
|
||||
symbolColor = col
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbolColor = function(self)
|
||||
return symbolColor
|
||||
end,
|
||||
|
||||
setBarType = function(self, _typ)
|
||||
barType = _typ:lower()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBarType = function(self)
|
||||
return barType
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base.scrollHandler(self, dir, x, y))then
|
||||
local w,h = self:getSize()
|
||||
index = index + dir
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1))
|
||||
self:setValue(maxValue / (barType == "vertical" and h or w) * index)
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("slider", function()
|
||||
local w,h = self:getSize()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
if (barType == "horizontal") then
|
||||
self:addText(index, oby, symbol:rep(symbolSize))
|
||||
if(symbolBG~=false)then self:addBG(index, 1, tHex[symbolBG]:rep(#symbol*symbolSize)) end
|
||||
if(symbolFG~=false)then self:addFG(index, 1, tHex[symbolFG]:rep(#symbol*symbolSize)) end
|
||||
end
|
||||
|
||||
if (barType == "vertical") then
|
||||
for n = 0, h - 1 do
|
||||
if (index == n + 1) then
|
||||
for curIndexOffset = 0, math.min(symbolSize - 1, h) do
|
||||
self:addBlit(1, 1+n+curIndexOffset, symbol, tHex[symbolColor], tHex[symbolColor])
|
||||
end
|
||||
else
|
||||
if (n + 1 < index) or (n + 1 > index - 1 + symbolSize) then
|
||||
self:addBlit(1, 1+n, bgSymbol, tHex[fgCol], tHex[bgCol])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
77
lib/basalt/objects/Switch.lua
Normal file
77
lib/basalt/objects/Switch.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Switch"
|
||||
|
||||
base:setSize(4, 1)
|
||||
base:setValue(false)
|
||||
base:setZIndex(5)
|
||||
|
||||
local bgSymbol = colors.black
|
||||
local inactiveBG = colors.red
|
||||
local activeBG = colors.green
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setSymbol = function(self, col)
|
||||
bgSymbol = col
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return bgSymbol
|
||||
end,
|
||||
|
||||
setActiveBackground = function(self, col)
|
||||
activeBG = col
|
||||
return self
|
||||
end,
|
||||
|
||||
getActiveBackground = function(self)
|
||||
return activeBG
|
||||
end,
|
||||
|
||||
setInactiveBackground = function(self, col)
|
||||
inactiveBG = col
|
||||
return self
|
||||
end,
|
||||
|
||||
getInactiveBackground = function(self)
|
||||
return inactiveBG
|
||||
end,
|
||||
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, ...)
|
||||
if (base.mouseHandler(self, ...)) then
|
||||
self:setValue(not self:getValue())
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("switch", function()
|
||||
local parent = self:getParent()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
local w,h = self:getSize()
|
||||
if(self:getValue())then
|
||||
self:addBackgroundBox(1, 1, w, h, activeBG)
|
||||
self:addBackgroundBox(w, 1, 1, h, bgSymbol)
|
||||
else
|
||||
self:addBackgroundBox(1, 1, w, h, inactiveBG)
|
||||
self:addBackgroundBox(1, 1, 1, h, bgSymbol)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
774
lib/basalt/objects/Textfield.lua
Normal file
774
lib/basalt/objects/Textfield.lua
Normal file
@@ -0,0 +1,774 @@
|
||||
local tHex = require("tHex")
|
||||
|
||||
local rep,find,gmatch,sub,len = string.rep,string.find,string.gmatch,string.sub,string.len
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Textfield"
|
||||
local hIndex, wIndex, textX, textY = 1, 1, 1, 1
|
||||
|
||||
local lines = { "" }
|
||||
local bgLines = { "" }
|
||||
local fgLines = { "" }
|
||||
local keyWords = { }
|
||||
local rules = { }
|
||||
|
||||
local startSelX,endSelX,startSelY,endSelY
|
||||
|
||||
local selectionBG,selectionFG = colors.lightBlue,colors.black
|
||||
|
||||
base:setSize(30, 12)
|
||||
base:setZIndex(5)
|
||||
|
||||
local function isSelected()
|
||||
if(startSelX~=nil)and(endSelX~=nil)and(startSelY~=nil)and(endSelY~=nil)then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function getSelectionCoordinates()
|
||||
local sx, ex, sy, ey = startSelX, endSelX, startSelY, endSelY
|
||||
if isSelected() then
|
||||
if startSelX < endSelX and startSelY <= endSelY then
|
||||
sx = startSelX
|
||||
ex = endSelX
|
||||
if startSelY < endSelY then
|
||||
sy = startSelY
|
||||
ey = endSelY
|
||||
else
|
||||
sy = endSelY
|
||||
ey = startSelY
|
||||
end
|
||||
elseif startSelX > endSelX and startSelY >= endSelY then
|
||||
sx = endSelX
|
||||
ex = startSelX
|
||||
if startSelY > endSelY then
|
||||
sy = endSelY
|
||||
ey = startSelY
|
||||
else
|
||||
sy = startSelY
|
||||
ey = endSelY
|
||||
end
|
||||
elseif startSelY > endSelY then
|
||||
sx = endSelX
|
||||
ex = startSelX
|
||||
sy = endSelY
|
||||
ey = startSelY
|
||||
end
|
||||
return sx, ex, sy, ey
|
||||
end
|
||||
end
|
||||
|
||||
local function removeSelection(self)
|
||||
local sx, ex, sy, ey = getSelectionCoordinates()
|
||||
local startLine = lines[sy]
|
||||
local endLine = lines[ey]
|
||||
lines[sy] = startLine:sub(1, sx - 1) .. endLine:sub(ex + 1, endLine:len())
|
||||
bgLines[sy] = bgLines[sy]:sub(1, sx - 1) .. bgLines[ey]:sub(ex + 1, bgLines[ey]:len())
|
||||
fgLines[sy] = fgLines[sy]:sub(1, sx - 1) .. fgLines[ey]:sub(ex + 1, fgLines[ey]:len())
|
||||
|
||||
for i = ey, sy + 1, -1 do
|
||||
if i ~= sy then
|
||||
table.remove(lines, i)
|
||||
table.remove(bgLines, i)
|
||||
table.remove(fgLines, i)
|
||||
end
|
||||
end
|
||||
|
||||
textX, textY = sx, sy
|
||||
startSelX, endSelX, startSelY, endSelY = nil, nil, nil, nil
|
||||
return self
|
||||
end
|
||||
|
||||
local function stringGetPositions(str, word)
|
||||
local pos = {}
|
||||
if(str:len()>0)then
|
||||
for w in gmatch(str, word)do
|
||||
local s, e = find(str, w)
|
||||
if(s~=nil)and(e~=nil)then
|
||||
table.insert(pos,s)
|
||||
table.insert(pos,e)
|
||||
local startL = sub(str, 1, (s-1))
|
||||
local endL = sub(str, e+1, str:len())
|
||||
str = startL..(":"):rep(w:len())..endL
|
||||
end
|
||||
end
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
local function updateColors(self, l)
|
||||
l = l or textY
|
||||
local fgLine = tHex[self:getForeground()]:rep(fgLines[l]:len())
|
||||
local bgLine = tHex[self:getBackground()]:rep(bgLines[l]:len())
|
||||
for k,v in pairs(rules)do
|
||||
local pos = stringGetPositions(lines[l], v[1])
|
||||
if(#pos>0)then
|
||||
for x=1,#pos/2 do
|
||||
local xP = x*2 - 1
|
||||
if(v[2]~=nil)then
|
||||
fgLine = fgLine:sub(1, pos[xP]-1)..tHex[v[2]]:rep(pos[xP+1]-(pos[xP]-1))..fgLine:sub(pos[xP+1]+1, fgLine:len())
|
||||
end
|
||||
if(v[3]~=nil)then
|
||||
bgLine = bgLine:sub(1, pos[xP]-1)..tHex[v[3]]:rep(pos[xP+1]-(pos[xP]-1))..bgLine:sub(pos[xP+1]+1, bgLine:len())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for k,v in pairs(keyWords)do
|
||||
for _,b in pairs(v)do
|
||||
local pos = stringGetPositions(lines[l], b)
|
||||
if(#pos>0)then
|
||||
for x=1,#pos/2 do
|
||||
local xP = x*2 - 1
|
||||
fgLine = fgLine:sub(1, pos[xP]-1)..tHex[k]:rep(pos[xP+1]-(pos[xP]-1))..fgLine:sub(pos[xP+1]+1, fgLine:len())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
fgLines[l] = fgLine
|
||||
bgLines[l] = bgLine
|
||||
self:updateDraw()
|
||||
end
|
||||
|
||||
local function updateAllColors(self)
|
||||
for n=1,#lines do
|
||||
updateColors(self, n)
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end;
|
||||
|
||||
setBackground = function(self, bg)
|
||||
base.setBackground(self, bg)
|
||||
updateAllColors(self)
|
||||
return self
|
||||
end,
|
||||
|
||||
setForeground = function(self, fg)
|
||||
base.setForeground(self, fg)
|
||||
updateAllColors(self)
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelection = function(self, fg, bg)
|
||||
selectionFG = fg or selectionFG
|
||||
selectionBG = bg or selectionBG
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionFG = function(self, fg)
|
||||
return self:setSelection(fg, nil)
|
||||
end,
|
||||
|
||||
setSelectionBG = function(self, bg)
|
||||
return self:setSelection(nil, bg)
|
||||
end,
|
||||
|
||||
getSelection = function(self)
|
||||
return selectionFG, selectionBG
|
||||
end,
|
||||
|
||||
getSelectionFG = function(self)
|
||||
return selectionFG
|
||||
end,
|
||||
|
||||
getSelectionBG = function(self)
|
||||
return selectionBG
|
||||
end,
|
||||
|
||||
getLines = function(self)
|
||||
return lines
|
||||
end,
|
||||
|
||||
getLine = function(self, index)
|
||||
return lines[index]
|
||||
end,
|
||||
|
||||
editLine = function(self, index, text)
|
||||
lines[index] = text or lines[index]
|
||||
updateColors(self, index)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
lines = {""}
|
||||
bgLines = {""}
|
||||
fgLines = {""}
|
||||
startSelX,endSelX,startSelY,endSelY = nil,nil,nil,nil
|
||||
hIndex, wIndex, textX, textY = 1, 1, 1, 1
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
addLine = function(self, text, index)
|
||||
if(text~=nil)then
|
||||
local bgColor = self:getBackground()
|
||||
local fgColor = self:getForeground()
|
||||
if(#lines==1)and(lines[1]=="")then
|
||||
lines[1] = text
|
||||
bgLines[1] = tHex[bgColor]:rep(text:len())
|
||||
fgLines[1] = tHex[fgColor]:rep(text:len())
|
||||
updateColors(self, 1)
|
||||
return self
|
||||
end
|
||||
if (index ~= nil) then
|
||||
table.insert(lines, index, text)
|
||||
table.insert(bgLines, index, tHex[bgColor]:rep(text:len()))
|
||||
table.insert(fgLines, index, tHex[fgColor]:rep(text:len()))
|
||||
else
|
||||
table.insert(lines, text)
|
||||
table.insert(bgLines, tHex[bgColor]:rep(text:len()))
|
||||
table.insert(fgLines, tHex[fgColor]:rep(text:len()))
|
||||
end
|
||||
end
|
||||
updateColors(self, index or #lines)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
addKeywords = function(self, color, tab)
|
||||
if(keyWords[color]==nil)then
|
||||
keyWords[color] = {}
|
||||
end
|
||||
for k,v in pairs(tab)do
|
||||
table.insert(keyWords[color], v)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
addRule = function(self, rule, fg, bg)
|
||||
table.insert(rules, {rule, fg, bg})
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
editRule = function(self, rule, fg, bg)
|
||||
for k,v in pairs(rules)do
|
||||
if(v[1]==rule)then
|
||||
rules[k][2] = fg
|
||||
rules[k][3] = bg
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
removeRule = function(self, rule)
|
||||
for k,v in pairs(rules)do
|
||||
if(v[1]==rule)then
|
||||
table.remove(rules, k)
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setKeywords = function(self, color, tab)
|
||||
keyWords[color] = tab
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
removeLine = function(self, index)
|
||||
if(#lines>1)then
|
||||
table.remove(lines, index or #lines)
|
||||
table.remove(bgLines, index or #bgLines)
|
||||
table.remove(fgLines, index or #fgLines)
|
||||
else
|
||||
lines = {""}
|
||||
bgLines = {""}
|
||||
fgLines = {""}
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextCursor = function(self)
|
||||
return textX, textY
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return wIndex, hIndex
|
||||
end,
|
||||
|
||||
setOffset = function(self, xOff, yOff)
|
||||
wIndex = xOff or wIndex
|
||||
hIndex = yOff or hIndex
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return wIndex
|
||||
end,
|
||||
|
||||
setXOffset = function(self, xOff)
|
||||
return self:setOffset(xOff, nil)
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return hIndex
|
||||
end,
|
||||
|
||||
setYOffset = function(self, yOff)
|
||||
return self:setOffset(nil, yOff)
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
base.getFocusHandler(self)
|
||||
local obx, oby = self:getPosition()
|
||||
self:getParent():setCursor(true, obx + textX - wIndex, oby + textY - hIndex, self:getForeground())
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
self:getParent():setCursor(false)
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key)
|
||||
if (base.keyHandler(self, key)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (key == keys.backspace) then
|
||||
-- on backspace
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
else
|
||||
if (lines[textY] == "") then
|
||||
if (textY > 1) then
|
||||
table.remove(lines, textY)
|
||||
table.remove(fgLines, textY)
|
||||
table.remove(bgLines, textY)
|
||||
textX = lines[textY - 1]:len() + 1
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
textY = textY - 1
|
||||
end
|
||||
elseif (textX <= 1) then
|
||||
if (textY > 1) then
|
||||
textX = lines[textY - 1]:len() + 1
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
lines[textY - 1] = lines[textY - 1] .. lines[textY]
|
||||
fgLines[textY - 1] = fgLines[textY - 1] .. fgLines[textY]
|
||||
bgLines[textY - 1] = bgLines[textY - 1] .. bgLines[textY]
|
||||
table.remove(lines, textY)
|
||||
table.remove(fgLines, textY)
|
||||
table.remove(bgLines, textY)
|
||||
textY = textY - 1
|
||||
end
|
||||
else
|
||||
lines[textY] = lines[textY]:sub(1, textX - 2) .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 2) .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 2) .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
if (textX > 1) then
|
||||
textX = textX - 1
|
||||
end
|
||||
if (wIndex > 1) then
|
||||
if (textX < wIndex) then
|
||||
wIndex = wIndex - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if (textY < hIndex) then
|
||||
hIndex = hIndex - 1
|
||||
end
|
||||
end
|
||||
updateColors(self)
|
||||
self:setValue("")
|
||||
elseif (key == keys.delete) then
|
||||
-- on delete
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
else
|
||||
if (textX > lines[textY]:len()) then
|
||||
if (lines[textY + 1] ~= nil) then
|
||||
lines[textY] = lines[textY] .. lines[textY + 1]
|
||||
table.remove(lines, textY + 1)
|
||||
table.remove(bgLines, textY + 1)
|
||||
table.remove(fgLines, textY + 1)
|
||||
end
|
||||
else
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. lines[textY]:sub(textX + 1, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. fgLines[textY]:sub(textX + 1, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. bgLines[textY]:sub(textX + 1, bgLines[textY]:len())
|
||||
end
|
||||
end
|
||||
updateColors(self)
|
||||
elseif (key == keys.enter) then
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
end
|
||||
-- on enter
|
||||
table.insert(lines, textY + 1, lines[textY]:sub(textX, lines[textY]:len()))
|
||||
table.insert(fgLines, textY + 1, fgLines[textY]:sub(textX, fgLines[textY]:len()))
|
||||
table.insert(bgLines, textY + 1, bgLines[textY]:sub(textX, bgLines[textY]:len()))
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1)
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1)
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1)
|
||||
textY = textY + 1
|
||||
textX = 1
|
||||
wIndex = 1
|
||||
if (textY - hIndex >= h) then
|
||||
hIndex = hIndex + 1
|
||||
end
|
||||
self:setValue("")
|
||||
elseif (key == keys.up) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow up
|
||||
if (textY > 1) then
|
||||
textY = textY - 1
|
||||
if (textX > lines[textY]:len() + 1) then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
if (wIndex > 1) then
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if (hIndex > 1) then
|
||||
if (textY < hIndex) then
|
||||
hIndex = hIndex - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif (key == keys.down) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow down
|
||||
if (textY < #lines) then
|
||||
textY = textY + 1
|
||||
if (textX > lines[textY]:len() + 1) then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
if (wIndex > 1) then
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if (textY >= hIndex + h) then
|
||||
hIndex = hIndex + 1
|
||||
end
|
||||
end
|
||||
elseif (key == keys.right) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow right
|
||||
textX = textX + 1
|
||||
if (textY < #lines) then
|
||||
if (textX > lines[textY]:len() + 1) then
|
||||
textX = 1
|
||||
textY = textY + 1
|
||||
end
|
||||
elseif (textX > lines[textY]:len()) then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
if (textX < 1) then
|
||||
textX = 1
|
||||
end
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
end
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
|
||||
elseif (key == keys.left) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow left
|
||||
textX = textX - 1
|
||||
if (textX >= 1) then
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX
|
||||
end
|
||||
end
|
||||
if (textY > 1) then
|
||||
if (textX < 1) then
|
||||
textY = textY - 1
|
||||
textX = lines[textY]:len() + 1
|
||||
wIndex = textX - w + 1
|
||||
end
|
||||
end
|
||||
if (textX < 1) then
|
||||
textX = 1
|
||||
end
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
elseif(key == keys.tab)then
|
||||
if(textX % 3 == 0 )then
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. " " .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + 1
|
||||
end
|
||||
while textX % 3 ~= 0 do
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. " " .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + 1
|
||||
end
|
||||
end
|
||||
|
||||
if not((obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (oby + textY - hIndex >= oby and oby + textY - hIndex < oby + h)) then
|
||||
wIndex = math.max(1, lines[textY]:len()-w+1)
|
||||
hIndex = math.max(1, textY - h + 1)
|
||||
end
|
||||
|
||||
local cursorX = (textX <= lines[textY]:len() and textX - 1 or lines[textY]:len()) - (wIndex - 1)
|
||||
if (cursorX > self:getX() + w - 1) then
|
||||
cursorX = self:getX() + w - 1
|
||||
end
|
||||
local cursorY = (textY - hIndex < h and textY - hIndex or textY - hIndex - 1)
|
||||
if (cursorX < 1) then
|
||||
cursorX = 0
|
||||
end
|
||||
parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground())
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if(base.charHandler(self, char))then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
end
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. char .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + 1
|
||||
if (textX >= w + wIndex) then
|
||||
wIndex = wIndex + 1
|
||||
end
|
||||
updateColors(self)
|
||||
self:setValue("")
|
||||
|
||||
if not((obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (oby + textY - hIndex >= oby and oby + textY - hIndex < oby + h)) then
|
||||
wIndex = math.max(1, lines[textY]:len()-w+1)
|
||||
hIndex = math.max(1, textY - h + 1)
|
||||
end
|
||||
|
||||
local cursorX = (textX <= lines[textY]:len() and textX - 1 or lines[textY]:len()) - (wIndex - 1)
|
||||
if (cursorX > self:getX() + w - 1) then
|
||||
cursorX = self:getX() + w - 1
|
||||
end
|
||||
local cursorY = (textY - hIndex < h and textY - hIndex or textY - hIndex - 1)
|
||||
if (cursorX < 1) then
|
||||
cursorX = 0
|
||||
end
|
||||
parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground())
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local ox, oy = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (lines[y - oby + hIndex] ~= nil) then
|
||||
if(x - obx + wIndex > 0)and(x - obx + wIndex <= w)then
|
||||
textX = x - obx + wIndex
|
||||
textY = y - oby + hIndex
|
||||
|
||||
if textX > lines[textY]:len() then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
endSelX = textX
|
||||
endSelY = textY
|
||||
|
||||
if textX < wIndex then
|
||||
wIndex = textX - 1
|
||||
if wIndex < 1 then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
parent:setCursor(not isSelected(), ox + textX - wIndex, oy + textY - hIndex, self:getForeground())
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if (base.scrollHandler(self, dir, x, y)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local anchx, anchy = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
hIndex = hIndex + dir
|
||||
if (hIndex > #lines - (h - 1)) then
|
||||
hIndex = #lines - (h - 1)
|
||||
end
|
||||
|
||||
if (hIndex < 1) then
|
||||
hIndex = 1
|
||||
end
|
||||
|
||||
if (obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (anchy + textY - hIndex >= anchy and anchy + textY - hIndex < anchy + h) then
|
||||
parent:setCursor(not isSelected(), anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground())
|
||||
else
|
||||
parent:setCursor(false)
|
||||
end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local anchx, anchy = self:getPosition()
|
||||
if (lines[y - oby + hIndex] ~= nil) then
|
||||
textX = x - obx + wIndex
|
||||
textY = y - oby + hIndex
|
||||
endSelX = nil
|
||||
endSelY = nil
|
||||
startSelX = textX
|
||||
startSelY = textY
|
||||
if (textX > lines[textY]:len()) then
|
||||
textX = lines[textY]:len() + 1
|
||||
startSelX = textX
|
||||
end
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground())
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
if (base.mouseUpHandler(self, button, x, y)) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
if (lines[y - oby + hIndex] ~= nil) then
|
||||
endSelX = x - obx + wIndex
|
||||
endSelY = y - oby + hIndex
|
||||
if (endSelX > lines[endSelY]:len()) then
|
||||
endSelX = lines[endSelY]:len() + 1
|
||||
end
|
||||
if(startSelX==endSelX)and(startSelY==endSelY)then
|
||||
startSelX, endSelX, startSelY, endSelY = nil, nil, nil, nil
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, paste, ...)
|
||||
base.eventHandler(self, event, paste, ...)
|
||||
if(event=="paste")then
|
||||
if(self:isFocused())then
|
||||
local parent = self:getParent()
|
||||
local fgColor, bgColor = self:getForeground(), self:getBackground()
|
||||
local w, h = self:getSize()
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. paste .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[fgColor]:rep(paste:len()) .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[bgColor]:rep(paste:len()) .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + paste:len()
|
||||
if (textX >= w + wIndex) then
|
||||
wIndex = (textX+1)-w
|
||||
end
|
||||
local anchx, anchy = self:getPosition()
|
||||
parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, fgColor)
|
||||
updateColors(self)
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("textfield", function()
|
||||
local w, h = self:getSize()
|
||||
local bgColor = tHex[self:getBackground()]
|
||||
local fgColor = tHex[self:getForeground()]
|
||||
|
||||
for n = 1, h do
|
||||
local text = ""
|
||||
local bg = ""
|
||||
local fg = ""
|
||||
if lines[n + hIndex - 1] then
|
||||
text = lines[n + hIndex - 1]
|
||||
fg = fgLines[n + hIndex - 1]
|
||||
bg = bgLines[n + hIndex - 1]
|
||||
end
|
||||
|
||||
text = sub(text, wIndex, w + wIndex - 1)
|
||||
bg = rep(bgColor, w)
|
||||
fg = rep(fgColor, w)
|
||||
|
||||
self:addText(1, n, text)
|
||||
self:addBG(1, n, bg)
|
||||
self:addFG(1, n, fg)
|
||||
self:addBlit(1, n, text, fg, bg)
|
||||
end
|
||||
|
||||
if startSelX and endSelX and startSelY and endSelY then
|
||||
local sx, ex, sy, ey = getSelectionCoordinates()
|
||||
for n = sy, ey do
|
||||
local line = #lines[n]
|
||||
local xOffset = 0
|
||||
if n == sy and n == ey then
|
||||
xOffset = sx - 1 - (wIndex - 1)
|
||||
line = line - (sx - 1 - (wIndex - 1)) - (line - ex + (wIndex - 1))
|
||||
elseif n == ey then
|
||||
line = line - (line - ex + (wIndex - 1))
|
||||
elseif n == sy then
|
||||
line = line - (sx - 1)
|
||||
xOffset = sx - 1 - (wIndex - 1)
|
||||
end
|
||||
|
||||
local visible_line_length = math.min(line, w - xOffset)
|
||||
|
||||
self:addBG(1 + xOffset, n, rep(tHex[selectionBG], visible_line_length))
|
||||
self:addFG(1 + xOffset, n, rep(tHex[selectionFG], visible_line_length))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_scroll")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("key")
|
||||
self:listenEvent("char")
|
||||
self:listenEvent("other_event")
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
112
lib/basalt/objects/Thread.lua
Normal file
112
lib/basalt/objects/Thread.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Object")(name, basalt)
|
||||
|
||||
local objectType = "Thread"
|
||||
|
||||
local func
|
||||
local cRoutine
|
||||
local isActive = false
|
||||
local filter
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
start = function(self, f)
|
||||
if (f == nil) then
|
||||
error("Function provided to thread is nil")
|
||||
end
|
||||
func = f
|
||||
cRoutine = coroutine.create(func)
|
||||
isActive = true
|
||||
filter=nil
|
||||
local ok, result = coroutine.resume(cRoutine)
|
||||
filter = result
|
||||
if not (ok) then
|
||||
if (result ~= "Terminated") then
|
||||
error("Thread Error Occurred - " .. result)
|
||||
end
|
||||
end
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_scroll")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("key")
|
||||
self:listenEvent("key_up")
|
||||
self:listenEvent("char")
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
getStatus = function(self, f)
|
||||
if (cRoutine ~= nil) then
|
||||
return coroutine.status(cRoutine)
|
||||
end
|
||||
return nil
|
||||
end,
|
||||
|
||||
stop = function(self, f)
|
||||
isActive = false
|
||||
self:listenEvent("mouse_click", false)
|
||||
self:listenEvent("mouse_up", false)
|
||||
self:listenEvent("mouse_scroll", false)
|
||||
self:listenEvent("mouse_drag", false)
|
||||
self:listenEvent("key", false)
|
||||
self:listenEvent("key_up", false)
|
||||
self:listenEvent("char", false)
|
||||
self:listenEvent("other_event", false)
|
||||
return self
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, ...)
|
||||
self:eventHandler("mouse_click", ...)
|
||||
end,
|
||||
mouseUpHandler = function(self, ...)
|
||||
self:eventHandler("mouse_up", ...)
|
||||
end,
|
||||
mouseScrollHandler = function(self, ...)
|
||||
self:eventHandler("mouse_scroll", ...)
|
||||
end,
|
||||
mouseDragHandler = function(self, ...)
|
||||
self:eventHandler("mouse_drag", ...)
|
||||
end,
|
||||
mouseMoveHandler = function(self, ...)
|
||||
self:eventHandler("mouse_move", ...)
|
||||
end,
|
||||
keyHandler = function(self, ...)
|
||||
self:eventHandler("key", ...)
|
||||
end,
|
||||
keyUpHandler = function(self, ...)
|
||||
self:eventHandler("key_up", ...)
|
||||
end,
|
||||
charHandler = function(self, ...)
|
||||
self:eventHandler("char", ...)
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if (isActive) then
|
||||
if (coroutine.status(cRoutine) == "suspended") then
|
||||
if(filter~=nil)then
|
||||
if(event~=filter)then return end
|
||||
filter=nil
|
||||
end
|
||||
local ok, result = coroutine.resume(cRoutine, event, ...)
|
||||
filter = result
|
||||
if not (ok) then
|
||||
if (result ~= "Terminated") then
|
||||
error("Thread Error Occurred - " .. result)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:stop()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
81
lib/basalt/objects/Timer.lua
Normal file
81
lib/basalt/objects/Timer.lua
Normal file
@@ -0,0 +1,81 @@
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Object")(name, basalt)
|
||||
local objectType = "Timer"
|
||||
|
||||
local timer = 0
|
||||
local savedRepeats = 0
|
||||
local repeats = 0
|
||||
local timerObj
|
||||
local timerIsActive = false
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setTime = function(self, _timer, _repeats)
|
||||
timer = _timer or 0
|
||||
savedRepeats = _repeats or 1
|
||||
return self
|
||||
end,
|
||||
|
||||
getTime = function(self)
|
||||
return timer
|
||||
end,
|
||||
|
||||
start = function(self)
|
||||
if(timerIsActive)then
|
||||
os.cancelTimer(timerObj)
|
||||
end
|
||||
repeats = savedRepeats
|
||||
timerObj = os.startTimer(timer)
|
||||
timerIsActive = true
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
isActive = function(self)
|
||||
return timerIsActive
|
||||
end,
|
||||
|
||||
cancel = function(self)
|
||||
if (timerObj ~= nil) then
|
||||
os.cancelTimer(timerObj)
|
||||
end
|
||||
timerIsActive = false
|
||||
self:removeEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
setStart = function(self, start)
|
||||
if (start == true) then
|
||||
return self:start()
|
||||
else
|
||||
return self:cancel()
|
||||
end
|
||||
end,
|
||||
|
||||
onCall = function(self, func)
|
||||
self:registerEvent("timed_event", func)
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if event == "timer" and tObj == timerObj and timerIsActive then
|
||||
self:sendEvent("timed_event")
|
||||
if (repeats >= 1) then
|
||||
repeats = repeats - 1
|
||||
if (repeats >= 1) then
|
||||
timerObj = os.startTimer(timer)
|
||||
end
|
||||
elseif (repeats == -1) then
|
||||
timerObj = os.startTimer(timer)
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
356
lib/basalt/objects/Treeview.lua
Normal file
356
lib/basalt/objects/Treeview.lua
Normal file
@@ -0,0 +1,356 @@
|
||||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Treeview"
|
||||
|
||||
local nodes = {}
|
||||
local itemSelectedBG = colors.black
|
||||
local itemSelectedFG = colors.lightGray
|
||||
local selectionColorActive = true
|
||||
local textAlign = "left"
|
||||
local xOffset, yOffset = 0, 0
|
||||
local scrollable = true
|
||||
|
||||
base:setSize(16, 8)
|
||||
base:setZIndex(5)
|
||||
|
||||
local function newNode(text, expandable)
|
||||
text = text or ""
|
||||
expandable = expandable or false
|
||||
local expanded = false
|
||||
local parent = nil
|
||||
local children = {}
|
||||
|
||||
local node = {}
|
||||
|
||||
local onSelect
|
||||
|
||||
node = {
|
||||
getChildren = function(self)
|
||||
return children
|
||||
end,
|
||||
|
||||
setParent = function(self, p)
|
||||
if(parent~=nil)then
|
||||
parent.removeChild(parent.findChildrenByText(node.getText()))
|
||||
end
|
||||
parent = p
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
getParent = function(self)
|
||||
return parent
|
||||
end,
|
||||
|
||||
addChild = function(self, text, expandable)
|
||||
local childNode = newNode(text, expandable)
|
||||
childNode.setParent(node)
|
||||
table.insert(children, childNode)
|
||||
base:updateDraw()
|
||||
return childNode
|
||||
end,
|
||||
|
||||
setExpanded = function(self, exp)
|
||||
if(expandable)then
|
||||
expanded = exp
|
||||
end
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
isExpanded = function(self)
|
||||
return expanded
|
||||
end,
|
||||
|
||||
onSelect = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
onSelect = v
|
||||
end
|
||||
end
|
||||
return node
|
||||
end,
|
||||
|
||||
callOnSelect = function(self)
|
||||
if(onSelect~=nil)then
|
||||
onSelect(node)
|
||||
end
|
||||
end,
|
||||
|
||||
setExpandable = function(self, expandable)
|
||||
expandable = expandable
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
isExpandable = function(self)
|
||||
return expandable
|
||||
end,
|
||||
|
||||
removeChild = function(self, index)
|
||||
if(type(index)=="table")then
|
||||
for k,v in pairs(index)do
|
||||
if(v==index)then
|
||||
index = k
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
table.remove(children, index)
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
findChildrenByText = function(self, searchText)
|
||||
local foundNodes = {}
|
||||
for _, child in ipairs(children) do
|
||||
if string.find(child.getText(), searchText) then
|
||||
table.insert(foundNodes, child)
|
||||
end
|
||||
end
|
||||
return foundNodes
|
||||
end,
|
||||
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
setText = function(self, t)
|
||||
text = t
|
||||
base:updateDraw()
|
||||
return node
|
||||
end
|
||||
}
|
||||
|
||||
return node
|
||||
end
|
||||
|
||||
local root = newNode("Root", true)
|
||||
root:setExpanded(true)
|
||||
|
||||
local object = {
|
||||
init = function(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_scroll")
|
||||
return base.init(self)
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType == t or base.isType ~= nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setOffset = function(self, x, y)
|
||||
xOffset = x
|
||||
yOffset = y
|
||||
return self
|
||||
end,
|
||||
|
||||
setXOffset = function(self, x)
|
||||
return self:setOffset(x, yOffset)
|
||||
end,
|
||||
|
||||
setYOffset = function(self, y)
|
||||
return self:setOffset(xOffset, y)
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
setScrollable = function(self, scroll)
|
||||
scrollable = scroll
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollable = function(self, scroll)
|
||||
return scrollable
|
||||
end,
|
||||
|
||||
setSelectionColor = function(self, bgCol, fgCol, active)
|
||||
itemSelectedBG = bgCol or self:getBackground()
|
||||
itemSelectedFG = fgCol or self:getForeground()
|
||||
selectionColorActive = active~=nil and active or true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionBG = function(self, bgCol)
|
||||
return self:setSelectionColor(bgCol, nil, selectionColorActive)
|
||||
end,
|
||||
|
||||
setSelectionFG = function(self, fgCol)
|
||||
return self:setSelectionColor(nil, fgCol, selectionColorActive)
|
||||
end,
|
||||
|
||||
getSelectionColor = function(self)
|
||||
return itemSelectedBG, itemSelectedFG
|
||||
end,
|
||||
|
||||
getSelectionBG = function(self)
|
||||
return itemSelectedBG
|
||||
end,
|
||||
|
||||
getSelectionFG = function(self)
|
||||
return itemSelectedFG
|
||||
end,
|
||||
|
||||
isSelectionColorActive = function(self)
|
||||
return selectionColorActive
|
||||
end,
|
||||
|
||||
getRoot = function(self)
|
||||
return root
|
||||
end,
|
||||
|
||||
setRoot = function(self, node)
|
||||
root = node
|
||||
node.setParent(nil)
|
||||
return self
|
||||
end,
|
||||
|
||||
onSelect = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("treeview_select", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
selectionHandler = function(self, node)
|
||||
node.callOnSelect(node)
|
||||
self:sendEvent("treeview_select", node)
|
||||
return self
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if base.mouseHandler(self, button, x, y) then
|
||||
local currentLine = 1 - yOffset
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local w, h = self:getSize()
|
||||
local function checkNodeClick(node, level)
|
||||
if y == oby+currentLine-1 then
|
||||
if x >= obx and x < obx + w then
|
||||
node:setExpanded(not node:isExpanded())
|
||||
self:selectionHandler(node)
|
||||
self:setValue(node)
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end
|
||||
currentLine = currentLine + 1
|
||||
if node:isExpanded() then
|
||||
for _, child in ipairs(node:getChildren()) do
|
||||
if checkNodeClick(child, level + 1) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
for _, item in ipairs(root:getChildren()) do
|
||||
if checkNodeClick(item, 1) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if base.scrollHandler(self, dir, x, y) then
|
||||
if scrollable then
|
||||
local _, h = self:getSize()
|
||||
yOffset = yOffset + dir
|
||||
|
||||
if yOffset < 0 then
|
||||
yOffset = 0
|
||||
end
|
||||
|
||||
if dir >= 1 then
|
||||
local visibleLines = 0
|
||||
local function countVisibleLines(node, level)
|
||||
visibleLines = visibleLines + 1
|
||||
if node:isExpanded() then
|
||||
for _, child in ipairs(node:getChildren()) do
|
||||
countVisibleLines(child, level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, item in ipairs(root:getChildren()) do
|
||||
countVisibleLines(item, 1)
|
||||
end
|
||||
|
||||
if visibleLines > h then
|
||||
if yOffset > visibleLines - h then
|
||||
yOffset = visibleLines - h
|
||||
end
|
||||
else
|
||||
yOffset = yOffset - 1
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("treeview", function()
|
||||
local currentLine = 1 - yOffset
|
||||
local lastClickedNode = self:getValue()
|
||||
local function drawNode(node, level)
|
||||
local w, h = self:getSize()
|
||||
|
||||
if currentLine >= 1 and currentLine <= h then
|
||||
local bg = (node == lastClickedNode) and itemSelectedBG or self:getBackground()
|
||||
local fg = (node == lastClickedNode) and itemSelectedFG or self:getForeground()
|
||||
|
||||
local text = node.getText()
|
||||
self:addBlit(1 + level + xOffset, currentLine, text, tHex[fg]:rep(#text), tHex[bg]:rep(#text))
|
||||
end
|
||||
|
||||
currentLine = currentLine + 1
|
||||
|
||||
if node:isExpanded() then
|
||||
for _, child in ipairs(node:getChildren()) do
|
||||
drawNode(child, level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, item in ipairs(root:getChildren()) do
|
||||
drawNode(item, 1)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
646
lib/basalt/objects/VisualObject.lua
Normal file
646
lib/basalt/objects/VisualObject.lua
Normal file
@@ -0,0 +1,646 @@
|
||||
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
|
||||
Reference in New Issue
Block a user