1084 lines
30 KiB
Lua
1084 lines
30 KiB
Lua
-- Shad's GUI free for everyone to use
|
|
|
|
|
|
animation = {__type = "Animation", name = ""}
|
|
animation.__index = animation
|
|
|
|
local object = {} -- Base class for all UI elements
|
|
|
|
local activeScreen
|
|
local screen = {}
|
|
local screens = {}
|
|
local animations = {}
|
|
|
|
--Utility Functions:
|
|
local function getTextHorizontalAlign(text, w, textAlign)
|
|
local text = string.sub(text, 1, w)
|
|
local n = w-string.len(text)
|
|
if(textAlign=="right")then
|
|
text = string.rep(" ", n)..text
|
|
elseif(textAlign=="center")then
|
|
text = string.rep(" ", math.floor(n/2))..text..string.rep(" ", math.floor(n/2))
|
|
text = text..(string.len(text) < w and " " or "")
|
|
else
|
|
text = text..string.rep(" ", n)
|
|
end
|
|
return text
|
|
end
|
|
|
|
local function getTextVerticalAlign(h,textAlign)
|
|
local offset = 0
|
|
if(textAlign=="center")then
|
|
offset = h%2 == 0 and math.floor(h / 2)-1 or math.floor(h / 2)
|
|
end
|
|
if(textAlign=="bottom")then
|
|
offset = h
|
|
end
|
|
return offset
|
|
end
|
|
|
|
local function rpairs(t)
|
|
return function(t, i)
|
|
i = i - 1
|
|
if i ~= 0 then
|
|
return i, t[i]
|
|
end
|
|
end, t, #t + 1
|
|
end
|
|
|
|
local function reverseTable(t)
|
|
local newT = {}
|
|
local keys = {}
|
|
|
|
for k,v in pairs(t)do
|
|
table.insert(keys,k)
|
|
end
|
|
for k,v in rpairs(keys)do
|
|
newT[v] = t[v]
|
|
end
|
|
return newT
|
|
end
|
|
|
|
--------------
|
|
--Animation System
|
|
animation.new = function(name)
|
|
local newElement = {name=name,animations={},nextWaitTimer=0,index=1,infiniteloop=false}
|
|
setmetatable(newElement, animation)
|
|
table.insert(animations, newElement)
|
|
return newElement
|
|
end
|
|
|
|
function animation:addAnimation(func)
|
|
table.insert(self.animations, {f=func,t=self.nextWaitTimer})
|
|
self.nextWaitTimer = 0
|
|
return self
|
|
end
|
|
|
|
function animation:wait(timer)
|
|
self.nextWaitTimer = timer
|
|
return self
|
|
end
|
|
|
|
function animation:onPlay() -- internal function, don't use it unless you know what you do!
|
|
if(self.playing)then
|
|
self.animations[self.index].f(self)
|
|
self.index = self.index+1
|
|
|
|
if(self.animations[self.index]~=nil)then
|
|
if(self.animations[self.index].t>0)then
|
|
self.timeObj = os.startTimer(self.animations[self.index].t)
|
|
else
|
|
self:onPlay()
|
|
end
|
|
else
|
|
if(self.infiniteloop)then
|
|
self.index = 1
|
|
if(self.animations[self.index].t>0)then
|
|
self.timeObj = os.startTimer(self.animations[self.index].t)
|
|
else
|
|
self:onPlay()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function animation:play(infiniteloop)
|
|
if(infiniteloop~=nil)then self.infiniteloop=infiniteloop end
|
|
self.playing = true
|
|
if(self.animations[self.index]~=nil)then
|
|
if(self.animations[self.index].t>0)then
|
|
self.timeObj = os.startTimer(self.animations[self.index].t)
|
|
else
|
|
self:onPlay()
|
|
end
|
|
end
|
|
return self
|
|
end
|
|
|
|
function animation:cancel()
|
|
os.cancelTimer(self.timeObj)
|
|
self.playing = false
|
|
self.infiniteloop = false
|
|
self.index = 0
|
|
return self
|
|
end
|
|
-----------
|
|
|
|
|
|
|
|
|
|
|
|
--Object Constructors:
|
|
--(base class for every element/object even frames)
|
|
function object:new()
|
|
local newElement = {__type = "Object",name="",zIndex=1,drawCalls=0,x=1,y=1,w=1,h=1,textAlign="left",draw=false,changed=true,bgcolor=colors.black,fgcolor=colors.white,text="",hanchor="left",vanchor="top"}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
timer = object:new()
|
|
function timer:new()
|
|
local newElement = {__type = "Timer"}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
checkbox = object:new()
|
|
function checkbox:new()
|
|
local newElement = {__type = "Checkbox",symbol="x",zIndex=5,bgcolor=colors.lightBlue,fgcolor=colors.black}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
label = object:new()
|
|
function label:new()
|
|
local newElement = {__type = "Label"}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
input = object:new()
|
|
function input:new()
|
|
local newElement = {__type = "Input",zIndex=5,bgcolor=colors.lightBlue,fgcolor=colors.black,w=5}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
button = object:new()
|
|
function button:new()
|
|
local newElement = {__type = "Button",zIndex=5,bgcolor=colors.lightBlue,fgcolor=colors.black,w=5,horizontalTextAlign="center",verticalTextAlign="center"}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
dropdown = object:new()
|
|
function dropdown:new()
|
|
local newElement = {__type = "Dropdown",zIndex=10,bgcolor=colors.lightBlue,fgcolor=colors.black,w=5,horizontalTextAlign="center",elements={},selected={text="",fgcolor=colors.black,bgcolor=colors.lightBlue}}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
list = object:new()
|
|
function list:new()
|
|
local newElement = {__type = "List",zIndex=5,bgcolor=colors.lightBlue,fgcolor=colors.black,w=5,horizontalTextAlign="center",elements={},selected={text="",fgcolor=colors.black,bgcolor=colors.lightBlue}}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
|
|
frame = object:new()
|
|
function frame:new(name,scrn)
|
|
local parent = scrn~=nil and scrn or term.native()
|
|
local w, h = parent.getSize()
|
|
local newElement = {name=name, parent = parent,zIndex=20, fWindow = window.create(parent,1,1,w,h),x=1,y=1,w=w,h=h, objects={},objZKeys={},bgcolor = colors.black, fgcolor=colors.white,barActive = false, title="New Frame", titlebgcolor = colors.lightBlue, titlefgcolor = colors.black, horizontalTextAlign="left",focusedObject={}, isMoveable = true}
|
|
setmetatable(newElement, {__index = self})
|
|
return newElement
|
|
end
|
|
--------
|
|
|
|
--object methods
|
|
function object:show()
|
|
if not(self.draw)then
|
|
self.draw = true
|
|
self.changed = true
|
|
end
|
|
return self
|
|
end
|
|
|
|
function object:hide()
|
|
if(self.draw)then
|
|
self.draw = false
|
|
self.changed = true
|
|
end
|
|
return self
|
|
end
|
|
|
|
function object:getName()
|
|
return self.name
|
|
end
|
|
|
|
function object:setPosition(x,y)
|
|
self.x = tonumber(x)
|
|
self.y = tonumber(y)
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function object:setBackground(color)
|
|
self.bgcolor = color
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function object:setForeground(color)
|
|
self.fgcolor = color
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function object:onClick(func)
|
|
self.clickFunc = func
|
|
return self
|
|
end
|
|
|
|
function object:onMouseUp(func)
|
|
self.upFunc = func
|
|
return self
|
|
end
|
|
|
|
function object:onMouseDrag(func)
|
|
self.dragFunc = func
|
|
return self
|
|
end
|
|
|
|
function object:setText(text)
|
|
self.text = text
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function object:onChange(func)
|
|
self.changeFunc = func
|
|
return self
|
|
end
|
|
|
|
function object:setSize(w,h)
|
|
self.w = tonumber(w)
|
|
self.h = tonumber(h)
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function object:setTextAlign(halign,valign)
|
|
self.horizontalTextAlign = halign
|
|
if(valign~=nil)then self.verticalTextAlign = valign end
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function object:drawObject()
|
|
if(self.draw)then
|
|
self.drawCalls = self.drawCalls + 1
|
|
end
|
|
end
|
|
|
|
function object:setAnchor(ank1,ank2)
|
|
if(ank1=="right")or(ank1=="left")then
|
|
self.hanchor = ank1
|
|
end
|
|
if(ank2=="top")or(ank2=="bottom")then
|
|
self.vanchor = ank2
|
|
end
|
|
if(ank1=="top")or(ank1=="bottom")then
|
|
self.vanchor = ank1
|
|
end
|
|
if(ank2=="right")or(ank2=="left")then
|
|
self.hanchor = ank2
|
|
end
|
|
return self
|
|
end
|
|
|
|
function object:relativeToAbsolutePosition(x,y) -- relative position
|
|
if(x==nil)then x = 0 end
|
|
if(y==nil)then y = 0 end
|
|
|
|
x = x+self.x;y=y+self.y
|
|
if(self.frame~=nil)then
|
|
x,y = self.frame:relativeToAbsolutePosition(x,y)
|
|
x = x-1; y = y-1
|
|
end
|
|
return x, y
|
|
end
|
|
|
|
function object:getAnchorPosition(x,y)
|
|
if(x==nil)then x = self.x end
|
|
if(y==nil)then y = self.y end
|
|
if(self.hanchor=="right")then
|
|
x = self.frame.w-x+1
|
|
end
|
|
if(self.vanchor=="bottom")then
|
|
y = self.frame.h-y
|
|
end
|
|
return x, y
|
|
end
|
|
|
|
function object:isFocusedElement()
|
|
return self == self.frame.focusedObject
|
|
end
|
|
|
|
function object:clickEvent(event,typ,x,y) -- internal class, dont use unless you know what you do
|
|
local vx,vy = self:getAnchorPosition(self:relativeToAbsolutePosition())
|
|
if(vx<=x)and(vx+self.w>x)and(vy<=y)and(vy+self.h>y)then
|
|
if(event=="mouse_click")then
|
|
if(self.clickFunc~=nil)then
|
|
self.clickFunc(self,typ,x,y)
|
|
end
|
|
elseif(event=="mouse_up")then
|
|
if(self.upFunc~=nil)then
|
|
self.upFunc(self,typ,x,y)
|
|
end
|
|
elseif(event=="mouse_drag")then
|
|
if(self.dragFunc~=nil)then
|
|
self.dragFunc(self,typ,x,y)
|
|
end
|
|
end
|
|
if(self.frame~=nil)then self.frame:setFocusedElement(self) end
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function object:loseFocusEvent()
|
|
|
|
end
|
|
|
|
function object:getFocusEvent()
|
|
end
|
|
|
|
function object:setZIndex(index)
|
|
self.frame:changeZIndexOfObj(self,index)
|
|
return self
|
|
end
|
|
--object end
|
|
|
|
--Frame object
|
|
screen.new = function(name, scrn)
|
|
local obj = frame:new(name,scrn)
|
|
if(screens[name] == nil)then
|
|
screens[name] = obj
|
|
obj.fWindow.setVisible(false)
|
|
obj.debugLabel=obj:addLabel("DebugLabel")
|
|
return obj;
|
|
else
|
|
return screens[name];
|
|
end
|
|
end
|
|
|
|
screen.remove = function(name)
|
|
screens[name].fWindow.setVisible(false)
|
|
screens[name] = nil
|
|
end
|
|
|
|
function frame:addFrame(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = frame:new(name,self.fWindow)
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function frame:showBar()
|
|
self.barActive = true
|
|
return self
|
|
end
|
|
|
|
function frame:hideBar()
|
|
self.barActive = false
|
|
return self
|
|
end
|
|
|
|
function frame:setTitle(title,fgcolor,bgcolor)
|
|
self.title=title
|
|
if(fgcolor~=nil)then self.titlefgcolor = fgcolor end
|
|
if(bgcolor~=nil)then self.titlebgcolor = bgcolor end
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function frame:setTextAlign(align)
|
|
self.horizontalTextAlign = align
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function frame:setSize(width, height)
|
|
object.setSize(self,width,height)
|
|
self.fWindow.reposition(self.x,self.y,width,height)
|
|
return self
|
|
end
|
|
|
|
function frame:setPosition(x,y)
|
|
object.setPosition(self,x,y)
|
|
self.fWindow.reposition(x,y)
|
|
return self
|
|
end
|
|
|
|
function frame:show()
|
|
object.show(self)
|
|
self.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.fWindow.setTextColor(self.fgcolor)
|
|
self.fWindow.setVisible(true)
|
|
if(self.frame == nil)then
|
|
activeScreen = self
|
|
end
|
|
return self
|
|
end
|
|
|
|
function frame:hide()
|
|
object.hide(self)
|
|
self.fWindow.setVisible(false)
|
|
self.fWindow.redraw()
|
|
self.parent.clear()
|
|
return self
|
|
end
|
|
|
|
function frame:close()
|
|
if(self.frame~=nil)then
|
|
object.hide(self)
|
|
end
|
|
self.changed = true
|
|
self.draw = false
|
|
self.fWindow.setVisible(false)
|
|
screens[self.name] = nil
|
|
self.parent.clear()
|
|
end
|
|
|
|
function frame:getObject(name)
|
|
if(self.objects~=nil)then
|
|
for k,v in pairs(self.objects)do
|
|
if(v[name]~=nil)then
|
|
return v[name]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function frame:getFocusedObject()
|
|
return self.focusedObject
|
|
end
|
|
|
|
function frame:addObject(obj) --Z index not working need bugfix
|
|
if(self.objects[obj.zIndex]==nil)then
|
|
for x=1,#self.objZKeys+1 do
|
|
if(self.objZKeys[x]~=nil)then
|
|
if(obj.zIndex >self.objZKeys[x])then
|
|
table.insert(self.objZKeys,x,obj.zIndex)
|
|
end
|
|
else
|
|
table.insert(self.objZKeys,x,obj.zIndex)
|
|
end
|
|
end
|
|
if(#self.objZKeys<=0)then
|
|
table.insert(self.objZKeys,obj.zIndex)
|
|
end
|
|
local cache = {}
|
|
for k,v in pairs(self.objZKeys)do
|
|
if(self.objects[v]~=nil)then
|
|
cache[v] = self.objects[v]
|
|
else
|
|
cache[v] = {}
|
|
end
|
|
end
|
|
self.objects = cache
|
|
end
|
|
self.objects[obj.zIndex][obj.name] = obj
|
|
end
|
|
|
|
function frame:drawObject()
|
|
if(self.draw)then
|
|
if(self.drag)and(self.frame==nil)then
|
|
self.parent.clear()
|
|
end
|
|
object.drawObject(self)
|
|
self.fWindow.clear()
|
|
if(self.barActive)then
|
|
local text = string.sub(self.title, 1, self.w)
|
|
local n = self.w-string.len(text)
|
|
if(self.horizontalTextAlign=="left")then
|
|
text = text..string.rep(" ", n)
|
|
end
|
|
if(self.horizontalTextAlign=="right")then
|
|
text = string.rep(" ", n)..text
|
|
end
|
|
if(self.horizontalTextAlign=="center")then
|
|
text = string.rep(" ", math.floor(n/2))..text..string.rep(" ", math.floor(n/2))
|
|
text = text..(string.len(text) < self.w and " " or "")
|
|
end
|
|
self.fWindow.setBackgroundColor(self.titlebgcolor)
|
|
self.fWindow.setTextColor(self.titlefgcolor)
|
|
self.fWindow.setCursorPos(1,1)
|
|
self.fWindow.write(text)
|
|
end
|
|
|
|
for a,b in pairs(self.objects)do
|
|
for k,v in pairs(b)do
|
|
if(v.draw~=nil)then
|
|
v:drawObject()
|
|
end
|
|
end
|
|
end
|
|
|
|
if(self.inputActive)then
|
|
self.fWindow.setCursorPos(self.cursorX, self.cursorY)
|
|
end
|
|
self.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.fWindow.setTextColor(self.fgcolor)
|
|
self.fWindow.setVisible(true)
|
|
self.fWindow.redraw()
|
|
end
|
|
end
|
|
|
|
function frame:clickEvent(event,typ,x,y)
|
|
local fx,fy = self:getAnchorPosition(self:relativeToAbsolutePosition())
|
|
if(self.drag)and(self.draw)then
|
|
if(event=="mouse_drag")then
|
|
local parentX=1;parentY=1
|
|
if(self.frame~=nil)then
|
|
parentX,parentY = self.frame:getAnchorPosition(self.frame:relativeToAbsolutePosition())
|
|
end
|
|
self:setPosition(x+self.xToRem-(parentX-1),y-(parentY-1))
|
|
end
|
|
if(event=="mouse_up")then
|
|
self.drag = false
|
|
end
|
|
return true
|
|
end
|
|
if(object.clickEvent(self,event,typ,x,y))then
|
|
if(x>fx+self.w-1)or(y>fy+self.h-1)then return end
|
|
local keys = {}
|
|
for k in pairs(self.objects)do
|
|
table.insert(keys,k)
|
|
end
|
|
for _,b in rpairs(keys)do
|
|
for _,v in pairs(self.objects[b])do
|
|
if(v.draw~=false)then
|
|
if(v:clickEvent(event,typ,x,y))then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
self:loseFocusedElement()
|
|
if(x>=fx)and(x<=fx+self.w)and(y==fy)and(event=="mouse_click")then
|
|
self.drag = true
|
|
self.xToRem = fx-x
|
|
end
|
|
end
|
|
if(fx<=x)and(fx+self.w>x)and(fy<=y)and(fy+self.h>y)then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function frame:changeZIndexOfObj(obj, zindex)
|
|
self.objects[obj.zIndex][obj.name] = nil
|
|
obj.zIndex = zindex
|
|
self:addObject(obj)
|
|
end
|
|
|
|
function frame:setFocusedElement(obj)
|
|
if(self:getObject(obj.name)~=nil)then
|
|
if(self.focusedObject~=obj)then
|
|
if(self.focusedObject.name~=nil)then
|
|
self.focusedObject:loseFocusEvent()
|
|
end
|
|
obj:getFocusEvent()
|
|
self.focusedObject = obj
|
|
end
|
|
end
|
|
end
|
|
|
|
function frame:loseFocusedElement()
|
|
if(self.focusedObject.name~=nil)then
|
|
self.focusedObject:loseFocusEvent()
|
|
end
|
|
self.focusedObject = {}
|
|
end
|
|
|
|
function frame:setMoveable(mv)
|
|
self.isMoveable = mv
|
|
return self;
|
|
end
|
|
--Frames end
|
|
|
|
|
|
--Timer object
|
|
function frame:addTimer(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = timer:new()
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function timer:setTime(timer, repeats)
|
|
self.timer = timer
|
|
if(repeats>0)then
|
|
self.repeats = repeats
|
|
else
|
|
self.repeats = -1
|
|
end
|
|
return self
|
|
end
|
|
|
|
function timer:start(timer, repeats)
|
|
self.active = true
|
|
if(timer~=nil)then self.timer = timer end
|
|
if(repeats~=nil)then self.repeats = repeats end
|
|
self.timeObj = os.startTimer(self.timer)
|
|
return self
|
|
end
|
|
|
|
function timer:cancel()
|
|
self.active = false
|
|
os.cancelTimer(self.timeObj)
|
|
return self
|
|
end
|
|
|
|
function timer:onCall(func)
|
|
self.call = func
|
|
return self
|
|
end
|
|
--Timer end
|
|
|
|
|
|
--Checkbox object
|
|
function frame:addCheckbox(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = checkbox:new()
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function checkbox:setSymbol(symbol)
|
|
self.symbol = string.sub(symbol,1,1)
|
|
self.changed = true
|
|
return self
|
|
end
|
|
|
|
function checkbox:drawObject()
|
|
object.drawObject(self) -- Base class
|
|
if(self.draw)then
|
|
self.frame.fWindow.setCursorPos(self:getAnchorPosition())
|
|
self.frame.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.frame.fWindow.setTextColor(self.fgcolor)
|
|
if(self.checked)then
|
|
self.frame.fWindow.write(self.symbol)
|
|
else
|
|
self.frame.fWindow.write(" ")
|
|
end
|
|
self.changed = false
|
|
end
|
|
end
|
|
|
|
function checkbox:clickEvent(event,typ,x,y)
|
|
if(object.clickEvent(self,event,typ,x,y))then
|
|
self.checked = not self.checked
|
|
self.changed = true
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
--Checkbox end
|
|
|
|
--Label object
|
|
function frame:addLabel(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = label:new()
|
|
obj.bgcolor = self.bgcolor
|
|
obj.fgcolor = self.fgcolor
|
|
obj.name=name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function label:setText(text)
|
|
object.setText(self,text)
|
|
self.w = string.len(text)
|
|
return self
|
|
end
|
|
|
|
function label:drawObject()
|
|
object.drawObject(self) -- Base class
|
|
if(self.draw)then
|
|
self.frame.fWindow.setCursorPos(self:getAnchorPosition())
|
|
self.frame.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.frame.fWindow.setTextColor(self.fgcolor)
|
|
self.frame.fWindow.write(self.text)
|
|
self.changed = false
|
|
end
|
|
end
|
|
--Label end
|
|
|
|
function frame:addInput(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = input:new()
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function input:clickEvent(event,typ,x,y)
|
|
if(object.clickEvent(self,event,typ,x,y))then
|
|
local vx,vy = self:getAnchorPosition(self:relativeToAbsolutePosition())
|
|
self.frame.inputActive = true
|
|
self.frame.activeInput = self
|
|
self.frame.fWindow.setCursorPos(vx+(string.len(self.text) < self.w and string.len(self.text) or self.w),vy)
|
|
self.frame.cursorX = vx+(string.len(self.text) < self.w and string.len(self.text) or self.w)
|
|
self.frame.cursorY = vy
|
|
self.frame.fWindow.setCursorBlink(true)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function input:drawObject()
|
|
object.drawObject(self) -- Base class
|
|
local text = ""
|
|
if(self.draw)then
|
|
if(string.len(self.text)>=self.w)then
|
|
text = string.sub(self.text, string.len(self.text)-self.w+2, string.len(self.text))
|
|
else
|
|
text = self.text
|
|
end
|
|
local n = self.w-string.len(text)
|
|
text = text..string.rep(" ", n)
|
|
self.frame.fWindow.setCursorPos(self:getAnchorPosition())
|
|
self.frame.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.frame.fWindow.setTextColor(self.fgcolor)
|
|
self.frame.fWindow.write(text)
|
|
self.changed = false
|
|
end
|
|
end
|
|
|
|
|
|
function input:getFocusEvent()
|
|
object.getFocusEvent(self)
|
|
self.frame.fWindow.setCursorPos(self:getAnchorPosition())
|
|
self.frame.fWindow.setCursorBlink(true)
|
|
end
|
|
|
|
function input:loseFocusEvent()
|
|
object.loseFocusEvent(self)
|
|
self.frame.inputActive = false
|
|
self.frame.fWindow.setCursorBlink(false)
|
|
end
|
|
|
|
function frame:addButton(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = button:new()
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function button:drawObject()
|
|
object.drawObject(self) -- Base class
|
|
if(self.draw)then
|
|
local x,y = self:getAnchorPosition()
|
|
local yOffset = getTextVerticalAlign(self.h,self.verticalTextAlign)
|
|
self.frame.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.frame.fWindow.setTextColor(self.fgcolor)
|
|
for line=0,self.h-1 do
|
|
self.frame.fWindow.setCursorPos(x,y+line)
|
|
if(line==yOffset)then
|
|
self.frame.fWindow.write(getTextHorizontalAlign(self.text, self.w, self.horizontalTextAlign))
|
|
else
|
|
self.frame.fWindow.write(string.rep(" ", self.w))
|
|
end
|
|
end
|
|
self.changed = false
|
|
end
|
|
end
|
|
|
|
function frame:addDropdown(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = dropdown:new()
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function dropdown:addElement(text,bgcolor,fgcolor)
|
|
table.insert(self.elements,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor)})
|
|
if(#self.elements==1)then
|
|
self.selected = self.elements[1]
|
|
end
|
|
return self
|
|
end
|
|
|
|
function dropdown:drawObject()
|
|
object.drawObject(self) -- Base class
|
|
if(self.draw)then
|
|
self.frame.fWindow.setCursorPos(self:getAnchorPosition())
|
|
self.frame.fWindow.setBackgroundColor(self.selected.bgcolor)
|
|
self.frame.fWindow.setTextColor(self.selected.fgcolor)
|
|
self.frame.fWindow.write(getTextHorizontalAlign(self.selected.text, self.w, self.horizontalTextAlign))
|
|
|
|
if(self:isFocusedElement())then
|
|
if(#self.elements>0)then
|
|
local index = 1
|
|
for _,v in ipairs(self.elements)do
|
|
local objx, objy = self:getAnchorPosition()
|
|
self.frame.fWindow.setBackgroundColor(v.bgcolor)
|
|
self.frame.fWindow.setTextColor(v.fgcolor)
|
|
self.frame.fWindow.setCursorPos(objx,objy+index)
|
|
self.frame.fWindow.write(getTextHorizontalAlign(v.text, self.w, self.horizontalTextAlign))
|
|
index = index+1
|
|
end
|
|
end
|
|
end
|
|
self.changed = false
|
|
end
|
|
end
|
|
|
|
function dropdown:getSelection()
|
|
return self.selected
|
|
end
|
|
|
|
function dropdown:clickEvent(event,typ,x,y)
|
|
object.clickEvent(self,event,typ,x,y)
|
|
if(self:isFocusedElement())then
|
|
if(#self.elements>0)then
|
|
local dx,dy = self:getAnchorPosition(self:relativeToAbsolutePosition())
|
|
local index = 1
|
|
for _,b in pairs(self.elements)do
|
|
if(dx<=x)and(dx+self.w>x)and(dy+index==y)then
|
|
self.selected = b
|
|
if(self.changeFunc~=nil)then
|
|
self.changeFunc(self)
|
|
end
|
|
activeScreen:loseFocusedElement()
|
|
return true
|
|
end
|
|
index = index+1
|
|
end
|
|
if not((dx<=x)and(dx+self.w>x)and(dy<=y)and(dy+self.h>y))then
|
|
activeScreen:loseFocusedElement()
|
|
end
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
|
|
function frame:addList(name)
|
|
if(self:getObject(name) == nil)then
|
|
local obj = list:new()
|
|
obj.name = name;obj.frame=self;
|
|
self:addObject(obj)
|
|
return obj;
|
|
else
|
|
return nil, "id "..name.." already exists";
|
|
end
|
|
end
|
|
|
|
function list:drawObject()
|
|
object.drawObject(self) -- Base class
|
|
if(self.draw)then
|
|
self.frame.fWindow.setCursorPos(self:getAnchorPosition())
|
|
self.frame.fWindow.setBackgroundColor(self.bgcolor)
|
|
self.frame.fWindow.setTextColor(self.fgcolor)
|
|
self.frame.fWindow.write(getTextHorizontalAlign(self.selected.text, self.w, self.horizontalTextAlign))
|
|
|
|
if(#self.elements>0)then
|
|
local index = 0
|
|
for _,v in ipairs(self.elements)do
|
|
local objx, objy = self:getAnchorPosition()
|
|
self.frame.fWindow.setBackgroundColor(v.bgcolor)
|
|
self.frame.fWindow.setTextColor(v.fgcolor)
|
|
self.frame.fWindow.setCursorPos(objx,objy+index)
|
|
if(v==self.selected)then
|
|
self.frame.fWindow.write(">"..getTextHorizontalAlign(v.text, self.w, self.horizontalTextAlign))
|
|
else
|
|
self.frame.fWindow.write(" "..getTextHorizontalAlign(v.text, self.w, self.horizontalTextAlign))
|
|
end
|
|
index = index+1
|
|
end
|
|
end
|
|
self.changed = false
|
|
end
|
|
end
|
|
|
|
function list:clickEvent(event,typ,x,y)
|
|
object.clickEvent(self,event,typ,x,y)
|
|
if(#self.elements>0)then
|
|
local dx,dy = self:getAnchorPosition(self:relativeToAbsolutePosition())
|
|
local index = 0
|
|
for _,v in pairs(self.elements)do
|
|
if(dx<=x)and(dx+self.w>x)and(dy+index==y)then
|
|
self.selected = v
|
|
self.changed = true
|
|
if(self.changeFunc~=nil)then
|
|
self.changeFunc(self)
|
|
end
|
|
return true
|
|
end
|
|
index = index+1
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function list:getSelection()
|
|
return self.selected
|
|
end
|
|
|
|
function list:addElement(text,bgcolor,fgcolor)
|
|
table.insert(self.elements,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor)})
|
|
if(#self.elements==1)then
|
|
self.selected = self.elements[1]
|
|
end
|
|
return self
|
|
end
|
|
|
|
local function handleKeyboardEvent(event, key)
|
|
if(activeScreen.inputActive)then
|
|
if(activeScreen.activeInput.draw)then
|
|
if(event=="key")then
|
|
if(key==259)then
|
|
activeScreen.activeInput:setText(string.sub(activeScreen.activeInput.text,1,string.len(activeScreen.activeInput.text)-1))
|
|
end
|
|
if(key==257)then
|
|
if(activeScreen.inputActive)then
|
|
activeScreen.inputActive = false
|
|
activeScreen.fWindow.setCursorBlink(false)
|
|
end
|
|
end
|
|
end
|
|
if(event=="char")then
|
|
activeScreen.activeInput:setText(activeScreen.activeInput.text..key)
|
|
end
|
|
activeScreen.cursorX = activeScreen.activeInput.x+(string.len(activeScreen.activeInput.text) < activeScreen.activeInput.w and string.len(activeScreen.activeInput.text) or activeScreen.activeInput.w-1)
|
|
activeScreen.cursorY = activeScreen.activeInput.y
|
|
if(activeScreen.activeInput.changeFunc~=nil)then
|
|
activeScreen.activeInput.changeFunc(activeScreen.activeInput)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function checkTimer(timeObject)
|
|
for a,b in pairs(activeScreen.objects)do
|
|
for k,v in pairs(b)do
|
|
if(v.__type=="Timer")and(v.active)then
|
|
if(v.timeObj == timeObject)then
|
|
v.call(v)
|
|
if(v.repeats~=0)then
|
|
v.timeObj = os.startTimer(v.timer)
|
|
v.repeats = (v.repeats > 0 and v.repeats-1 or v.repeats)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if(#animations>0)then
|
|
for k,v in pairs(animations)do
|
|
if(v.timeObj==timeObject)then
|
|
v:onPlay()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function handleChangedObjectsEvent()
|
|
local changed = activeScreen.changed
|
|
for a,b in pairs(activeScreen.objects)do
|
|
for k,v in pairs(b)do
|
|
if(v.changed)then
|
|
changed = true
|
|
end
|
|
end
|
|
end
|
|
if(changed)then
|
|
if(activeScreen.draw)then
|
|
activeScreen:drawObject()
|
|
end
|
|
end
|
|
end
|
|
|
|
function screen.startUpdate()
|
|
handleChangedObjectsEvent()
|
|
screen.updater = true
|
|
while screen.updater do
|
|
local event, p1,p2,p3 = os.pullEvent()
|
|
if(event=="mouse_click")then
|
|
activeScreen:clickEvent(event,p1,p2,p3)
|
|
end
|
|
if(event=="mouse_drag")then
|
|
activeScreen:clickEvent(event,p1,p2,p3)
|
|
end
|
|
if(event=="mouse_up")then
|
|
activeScreen:clickEvent(event,p1,p2,p3)
|
|
end
|
|
if(event=="timer")then
|
|
checkTimer(p1)
|
|
end
|
|
if(event=="char")or(event=="key")then
|
|
handleKeyboardEvent(event,p1)
|
|
end
|
|
handleChangedObjectsEvent()
|
|
end
|
|
end
|
|
|
|
function screen.stopUpdate()
|
|
screen.updater = false
|
|
end
|
|
|
|
|
|
function debug(...)
|
|
local args = {...}
|
|
activeScreen.debugLabel:setPosition(1,activeScreen.h)
|
|
local str = "[Debug] "
|
|
for k,v in pairs(args)do
|
|
str = str..tostring(v)..(#args~=k and ", " or "")
|
|
end
|
|
activeScreen.debugLabel:setText(str)
|
|
activeScreen.debugLabel:show()
|
|
end
|
|
|
|
screen.debug = debug
|
|
|
|
function screen.get(name)
|
|
return screens[name];
|
|
end
|
|
|
|
function screen.getActiveScreen()
|
|
return activeScreen
|
|
end
|
|
|
|
return screen;
|