diff --git a/NyoUI.lua b/NyoUI.lua deleted file mode 100644 index ac141de..0000000 --- a/NyoUI.lua +++ /dev/null @@ -1,2592 +0,0 @@ -animation = {__type = "Animation", name = ""} -animation.__index = animation - -local NyoUI = {debugger=true,updater=false} - -local object = {} -- Base class for all UI elements - -local activeFrame -local _frames = {} -local animationQueue = {} -local keyModifier = {} -local parentTerminal = term.current() - - ---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 copyVar(orig) - local orig_type = type(orig) - local copy - if orig_type == 'table' then - copy = {} - for orig_key, orig_value in next, orig, nil do - copy[copyVar(orig_key)] = copyVar(orig_value) - end - setmetatable(copy, copyVar(getmetatable(orig))) - else -- number, string, boolean, etc - copy = orig - end - return copy -end - -local function callAll(tab,...) - if(tab~=nil)then - if(#tab>0)then - for k,v in pairs(tab)do - v(...) - end - end - end -end - -local function sign(v) - return (v >= 0 and 1) or -1 -end - -local function round(v, bracket) - bracket = bracket or 1 - return math.floor(v/bracket + sign(v) * 0.5) * bracket -end - ---Object Constructors: ---(base class for every element/object even frames) -function object:new() - local newElement = {__type = "Object",name="",links={},zIndex=1,drawCalls=0,x=1,y=1,xOriginal=1,yOriginal=1,w=1,h=1,draw=false,bgcolor=colors.black,fgcolor=colors.white,hanchor="left",vanchor="top",ignYOffset=false,ignXOffset=false} - setmetatable(newElement, {__index = self}) - return newElement -end - -function object:copy(obj) -local newElement = {} - for k,v in pairs(obj)do - newElement[k] = v - end - 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="\42",zIndex=5,bgcolor=colors.lightBlue,fgcolor=colors.black, value = false} - setmetatable(newElement, {__index = self}) - return newElement -end - -radio = object:new() -function radio:new() - local newElement = {__type = "Radio",symbol="\7",symbolFGColor=colors.black,symbolBGColor=colors.gray,zIndex=5,bgcolor=colors.gray,fgcolor=colors.black, value = "", items={}} - setmetatable(newElement, {__index = self}) - return newElement -end - -label = object:new() -function label:new() - local newElement = {__type = "Label", value=""} - setmetatable(newElement, {__index = self}) - return newElement -end - -input = object:new() -function input:new() - local newElement = {__type = "Input",zIndex=5,bgcolor=colors.gray,fgcolor=colors.black,w=10, value = "", iType = "text"} - setmetatable(newElement, {__index = self}) - return newElement -end - -button = object:new() -function button:new() - local newElement = {__type = "Button",zIndex=5,bgcolor=colors.gray,fgcolor=colors.black,w=8,horizontalTextAlign="center",verticalTextAlign="center",value=""} - setmetatable(newElement, {__index = self}) - return newElement -end - -dropdown = object:new() -function dropdown:new() - local newElement = {__type = "Dropdown",zIndex=9,bgcolor=colors.gray,fgcolor=colors.black,w=10,horizontalTextAlign="center",items={},value={text="",fgcolor=colors.black,bgcolor=colors.lightBlue}} - setmetatable(newElement, {__index = self}) - return newElement -end - -list = object:new() -function list:new() - local newElement = {__type = "List",index=1,colorIndex=1,textColorIndex=1,zIndex=5,activeItemBackground=colors.black,activeItemForeground=colors.lightGray,itemColors={colors.gray},itemTextColors={colors.black},symbol="",bgcolor=colors.gray,fgcolor=colors.black,w=15,h=6,horizontalTextAlign="center",items={},value={text=""}} - setmetatable(newElement, {__index = self}) - return newElement -end - -textfield = object:new() -function textfield:new() - local newElement = {__type = "Textfield",hIndex=1,wIndex=1,textX=1,textY=1,zIndex=5,bgcolor=colors.gray,fgcolor=colors.black,w=20,h=6,value="",lines={""}} - setmetatable(newElement, {__index = self}) - return newElement -end - -scrollbar = object:new() -function scrollbar:new() - local newElement = {__type = "Scrollbar",index=1,value=1,zIndex=10,bgcolor=colors.gray,fgcolor=colors.black,w=8,h=1,barType="vertical", symbolColor=colors.black, symbol = " ", symbolSize = 1, bgSymbol = "\127"} - setmetatable(newElement, {__index = self}) - return newElement -end - -slider = object:new() -function slider:new() - local newElement = {__type = "Slider",value=1,zIndex=5,bgcolor=colors.lightGray,fgcolor=colors.gray,w=5,h=1,barType="horizontal", symbolColor=colors.black, symbol = " ", bgSymbol = "\140"} - setmetatable(newElement, {__index = self}) - return newElement -end - -program = object:new() -function program:new() - local newElement = {__type = "Program",value="",zIndex=5,bgcolor=colors.black,fgcolor=colors.white,w=12,h=6} - setmetatable(newElement, {__index = self}) - return newElement -end - -animation = object:new() -function animation:new() - local newElement = {__type = "Animation",animations={},nextWaitTimer=0,index=1,infiniteloop=false} - setmetatable(newElement, {__index = self}) - return newElement -end - -frame = object:new() -function frame:new(name,scrn,frameObj) - local parent = scrn~=nil and scrn or term.current() - local w, h = parent.getSize() - local newElement = {} - if(frameObj~=nil)then - newElement = object:copy(frameObj) - newElement.fWindow = window.create(parent,1,1,frameObj.w,frameObj.h) - else - newElement = {__type = "Frame",name=name, parent = parent,zIndex=10, xOffset=0, yOffset=0, fWindow = window.create(parent,1,1,w,h),x=1,y=1,w=w,h=h, objects={},objZKeys={},bgcolor = colors.lightGray, fgcolor=colors.black,barActive = false, title="New Frame", titlebgcolor = colors.gray, titlefgcolor = colors.black, horizontalTextAlign="left",focusedObject={}, isMoveable = false,cursorBlink=false} - end - setmetatable(newElement, {__index = self}) - return newElement -end --------- - ---object methods -function object:show() - self.draw = true - self:updateVisuals() - return self -end - -function object:hide() - self.draw = false - self:updateVisuals() - return self -end - -function object:changeVisibility() - if(self.draw)then - self:hide() - else - self:show() - end - return self -end - -function object:isVisible() - return self.draw -end - -function object:getName() - return self.name -end - -function object:setPosition(x,y,typ) - if(typ=="r")or(typ=="relative")then - self.x = self.xOriginal+tonumber(x) - self.y = self.yOriginal+tonumber(y) - self.xOriginal = self.xOriginal+tonumber(x) - self.yOriginal = self.yOriginal+tonumber(y) - else - self.x = tonumber(x) - self.y = tonumber(y) - self.xOriginal = tonumber(x) - self.yOriginal = tonumber(y) - end - self:updateVisuals() - return self -end - -function object:setBackground(color) - self.bgcolor = color - self:updateVisuals() - return self -end - -function object:setForeground(color) - self.fgcolor = color - self:updateVisuals() - return self -end - ---Object Events:----- -function object:onClick(func) - if(self.clickFunc==nil)then self.clickFunc = {} end - table.insert(self.clickFunc,func) - return self -end - -function object:onClickUp(func) - if(self.upFunc==nil)then self.upFunc = {} end - table.insert(self.upFunc,func) - return self -end - -function object:onMouseDrag(func) - if(self.dragFunc==nil)then self.dragFunc = {} end - table.insert(self.dragFunc,func) - return self -end - -function object:onChange(func) - if(self.changeFunc==nil)then self.changeFunc = {} end - table.insert(self.changeFunc,func) - return self -end - -function object:onKey(func) - if(self.keyEventFunc==nil)then self.keyEventFunc = {} end - table.insert(self.keyEventFunc,func) - return self -end - -function object:onLoseFocus(func) - if(self.loseFocusEventFunc==nil)then self.loseFocusEventFunc = {} end - table.insert(self.loseFocusEventFunc,func) - return self -end - -function object:onGetFocus(func) - if(self.getFocusEventFunc==nil)then self.getFocusEventFunc = {} end - table.insert(self.getFocusEventFunc,func) - return self -end --------------------- - -function object:setSize(w,h) - self.w = tonumber(w) - self.h = tonumber(h) - self:updateVisuals() - return self -end - -function object:getHeight() - return self.h -end - -function object:getWidth() - return self.w -end - -function object:linkTo(obj) - obj:link(self) - return self -end - -function object:link(obj) -- does not work correctly needs a fix dsfgsdfgfsdg - if(obj.__type==self.__type)then - self.links[obj.name] = obj - end - return self -end - -function object:isLinkedTo(obj) - return (obj[self.name] ~= nil) -end - -function object:isLinked(obj) - return (self[obj.name] ~= nil) -end - -function object:setValue(val) - self.value = val - self:updateVisuals() - for _,v in pairs(self.links)do - v.value = val - v:updateVisuals() - end - - callAll(self.changeFunc,self,self.args) - return self -end - -function object:getValue() - return self.value; -end - -function object:setCustomArgs(args) - self.args = args - return self; -end - -function object:setTextAlign(halign,valign) - self.horizontalTextAlign = halign - if(valign~=nil)then self.verticalTextAlign = valign end - self:updateVisuals() - return self -end - -function object:updateVisuals() - if(self.frame~=nil)then - self.frame:updateVisuals() - end - self.changed = true -end - -function object:drawObject() - if(self.draw)then - self.drawCalls = self.drawCalls + 1 - if(self.frame~=nil)then - if not(self.ignXOffset)then - if(self.hanchor=="right")then - self.x = self.xOriginal + self.frame.xOffset - else - self.x = self.xOriginal - self.frame.xOffset - end - end - if not(self.ignYOffset)then - if(self.vanchor=="bottom")then - self.y = self.yOriginal + self.frame.yOffset - else - self.y = self.yOriginal - self.frame.yOffset - end - end - if(self.__type=="Frame")then - self.fWindow.reposition(self.x,self.y) - end - end - return true - end - return false -end - -function object:ignoreScroll(vertical,horizontal) - self.ignYOffset = vertical - self.ignXOffset = horizontal - return self -end - -function object:setAnchor(...) - if(type(...)=="string")then - if(...=="right")or(...=="left")then - self.hanchor = ... - end - if(...=="top")or(...=="bottom")then - self.vanchor = ... - end - end - if(type(...)=="table")then - for _,v in pairs(...)do - if(v=="right")or(v=="left")then - self.hanchor = v - end - if(v=="top")or(v=="bottom")then - self.vanchor = v - end - end -end - return self -end - -function object:relativeToAbsolutePosition(x,y) -- relative position - if(x==nil)then x = self.x end - if(y==nil)then y = self.y end - - if(self.frame~=nil)then - local fx,fy = self.frame:relativeToAbsolutePosition() - x=fx+x-1 - y=fy+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-self.w+2 - end - if(self.vanchor=="bottom")then - y = self.frame.h-y-self.h+2 - end - return x, y -end - -function object:isFocusedObject() - if(self.frame~=nil)then - return self == self.frame.focusedObject - end - return false -end - -function object:mouseEvent(event,typ,x,y) -- internal class, dont use unless you know what you do -local vx,vy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(vx<=x)and(vx+self.w>x)and(vy<=y)and(vy+self.h>y)then - if(self.frame~=nil)then self.frame:setFocusedElement(self) end - if(event=="mouse_click")then - if(self.clickFunc~=nil)then - callAll(self.clickFunc,self,event,typ,x,y) - end - elseif(event=="mouse_up")then - if(self.upFunc~=nil)then - callAll(self.upFunc,self,event,typ,x,y) - end - elseif(event=="mouse_drag")then - if(self.dragFunc~=nil)then - callAll(self.dragFunc,self,event,typ,x,y) - end - end - return true - end - return false -end - -function object:eventListener(event,p1,p2,p3,p4) - -end - -function object:keyEvent(event,typ) -- internal class, dont use unless you know what you do - if(self.keyEventFunc~=nil)then - callAll(self.keyEventFunc,self,typ) - end -end - -function object:setFocus() - if(self.frame~=nil)then - self.frame:setFocusedElement(self) - end - return self -end - -function object:loseFocusEvent() - if(self.loseFocusEventFunc~=nil)then - callAll(self.loseFocusEventFunc,self) - end -end - -function object:getFocusEvent() - if(self.getFocusEventFunc~=nil)then - callAll(self.getFocusEventFunc,self) - end -end - -function object:setZIndex(index) - self.frame:changeZIndexOfObject(self,index) - return self -end - - -function object:setParent(frame) - if(frame.__type=="Frame")then - if(self.frame~=nil)then - self.frame:removeObject(self) - end - self.frame = frame - self.frame:addObject(self) - if(self.draw)then - self:show() - end - end - return self -end ---object end - ---Frame object -NyoUI.createFrame = function(name, scrn) -- this is also just a frame, but its a level 0 frame -local obj = frame:new(name,scrn or parentTerminal) - if(_frames[name] == nil)then - _frames[name] = obj - obj.fWindow.setVisible(false) - return obj; - else - return _frames[name]; - end -end - -NyoUI.removeFrame = function(name) - _frames[name].fWindow.setVisible(false) - _frames[name] = nil -end - -function frame:addFrame(frameObj) -- with this you also create frames, but it needs to have a parent frame (level 1 or more frame) - if(self:getObject(frameObj) == nil)then - local obj - if(type(frameObj)=="string")then - obj = frame:new(frameObj,self.fWindow) - elseif(type(frameObj)=="table")and(frameObj.__type=="Frame")then - obj = frame:new(frameObj.name,self.fWindow,frameObj) - end - obj.frame=self; - self:addObject(obj) - return obj; - else - return nil, "id "..frameObj.." already exists"; - end -end - -function frame:setParentFrame(parent) -- if you want to change the parent of a frame. even level 0 frames can have a parent (they will be 'converted' *habschi*) - if(parent.__type=="Frame")and(parent~=self.frame)then - if(self.frame~=nil)then - self.frame:removeObject(self) - end - self.parent = parent.fWindow - self.frame = parent - self.fWindow.setVisible(false) - self.fWindow = window.create(parent.fWindow,self.x,self.y,self.w,self.h) - self.frame:addObject(self) - if(self.draw)then - self:show() - end - end - return self -end - -function frame:showBar(active) -- shows the top bar - self.barActive = active ~= nil and active or true - self:updateVisuals() - return self -end - -function frame:isModifierActive(key) - if(key==340)or(key=="shift")then - return keyModifier[340] - end - if(key==341)or(key=="ctrl")then - return keyModifier[341] - end - if(key==342)or(key=="alt")then - return keyModifier[342] - end - return keyModifier[key] -end - -function frame:setTitle(title,fgcolor,bgcolor) -- changed the title in your top bar - self.title=title - if(fgcolor~=nil)then self.titlefgcolor = fgcolor end - if(bgcolor~=nil)then self.titlebgcolor = bgcolor end - self:updateVisuals() - return self -end - -function frame:setTitleAlign(align) -- changes title align - self.horizontalTextAlign = align - self:updateVisuals() - return self -end - -function frame:setSize(width, height) -- frame size - object.setSize(self,width,height) - self.fWindow.reposition(self.x,self.y,width,height) - return self -end - -function frame:setXOffset(offset) -- frame x offset - self.xOffset = offset - self:updateVisuals() - return self -end - -function frame:setYOffset(offset) -- frame y offset - self.yOffset = offset - self:updateVisuals() - return self -end - -function frame:setPosition(x,y,typ) -- pos - object.setPosition(self,x,y,typ) - self.fWindow.reposition(self.x,self.y) - return self -end - -function frame:show() -- you need to call to be able to see the frame - object.show(self) - self.fWindow.setBackgroundColor(self.bgcolor) - self.fWindow.setTextColor(self.fgcolor) - self.fWindow.setVisible(true) - self.fWindow.redraw() - if(self.frame == nil)then - activeFrame = self - end - return self -end - -function frame:hide() -- hides the frame (does not remove setted values) - object.hide(self) - self.fWindow.setVisible(false) - self.fWindow.redraw() - self.parent.clear() - return self -end - -function frame:remove() -- removes the frame completly - if(self.frame~=nil)then - object.hide(self) - end - self:updateVisuals() - self.draw = false - self.fWindow.setVisible(false) - _frames[self.name] = nil - self.parent.clear() -end - -function frame:getObject(name) -- you can find objects by their name - if(self.objects~=nil)then - for _,b in pairs(self.objects)do - for _,v in pairs(b)do - if(v.name==name)then - return v - end - end - end - end -end - -function frame:removeObject(obj) -- you can remove objects - if(self.objects~=nil)then - for a,b in pairs(self.objects)do - for k,v in pairs(b)do - if(v==obj)then - table.remove(self.objects[a],k) - return; - end - end - end - end -end - -function frame:addObject(obj) -- you can add a object manually, normaly you shouldn't use this function, it gets called internally - if(self.objects[obj.zIndex]==nil)then - for x=0,#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 - self.objects[obj.zIndex] = {} - end - table.insert(self.objects[obj.zIndex],obj) -end - -function frame:drawObject() -- this draws the frame, you dont need that function, it gets called internally - if(object.drawObject(self))then - if(self.draw)then - if(self.drag)and(self.frame==nil)then - self.parent.clear() - end - self.fWindow.clear() - if(self.barActive)then - self.fWindow.setBackgroundColor(self.titlebgcolor) - self.fWindow.setTextColor(self.titlefgcolor) - self.fWindow.setCursorPos(1,1) - self.fWindow.write(getTextHorizontalAlign(self.title,self.w,self.horizontalTextAlign)) - end - - for _,b in rpairs(self.objZKeys)do - for k,v in pairs(self.objects[b])do - if(v.draw~=nil)then - v:drawObject() - end - end - end - - --term.redirect(self.fWindow) - self.fWindow.setBackgroundColor(self.bgcolor) - self.fWindow.setTextColor(self.cursorColor or self.fgcolor) - self.fWindow.setVisible(true) - self.fWindow.redraw() - - if(self.focusedObject.cursorX~=nil)and(self.focusedObject.cursorY~=nil)then - self.fWindow.setCursorPos(self.focusedObject.cursorX, self.focusedObject.cursorY) - end - - if(self.focusedObject.__type=="Program")then - if not(self.focusedObject.process:isDead())then - self.cursorColor = self.focusedObject.pWindow.getTextColor() - term.redirect(self.focusedObject.pWindow) - self.focusedObject.pWindow.restoreCursor() - end - else - self.fWindow.setCursorBlink(self.cursorBlink) - end - if(self.focusedObject.__type=="Frame")then - term.redirect(self.focusedObject.fWindow) - self.focusedObject.fWindow.restoreCursor() - end - end - end -end - -function frame:mouseEvent(event,typ,x,y) -- internal mouse event, should make it local but as lazy as i am.. - local fx,fy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.drag)and(self.draw)then - if(event=="mouse_drag")then - local parentX=1;local parentY=1 - if(self.frame~=nil)then - parentX,parentY = self.frame:relativeToAbsolutePosition(self.frame:getAnchorPosition()) - end - self:setPosition(x+self.xToRem-(parentX-1)+self.frame.xOffset,y-(parentY-1)+self.frame.yOffset) - end - if(event=="mouse_up")then - self.drag = false - end - return true - end - - if(object.mouseEvent(self,event,typ,x,y))then - - if(x>fx+self.w-1)or(y>fy+self.h-1)then return end - - for _,b in pairs(self.objZKeys)do - for _,v in rpairs(self.objects[b])do - if(v.draw~=false)then - if(v.__type=="Frame")then - v:removeFocusedElement() - end - end - end - end - - for _,b in pairs(self.objZKeys)do - for _,v in rpairs(self.objects[b])do - if(v.draw~=false)then - if(v:mouseEvent(event,typ,x,y))then - return true - end - end - end - end - if(self.isMoveable)then - 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 - end - if(fx<=x)and(fx+self.w>x)and(fy<=y)and(fy+self.h>y)then - self:removeFocusedElement() - return true - end - return false -end - -function frame:eventListener(event,p1,p2,p3,p4) - local keys = {} - local terminatingprogram = false - for k in pairs(self.objects)do - table.insert(keys,k) - end - for _,b in pairs(keys)do - for _,v in rpairs(self.objects[b])do - if(v.draw~=false)then - v:eventListener(event,p1,p2,p3,p4) - - if(v:isFocusedObject()and(v.__type=="Program"))then - terminatingprogram = true - end - end - end - end - --if(event=="terminate")then NyoUI.debug(terminatingprogram) end -- kack buggy - if(event=="terminate")and(terminatingprogram == false)then - if(self.terminatedTime==nil)then self.terminatedTime = 0 end - if(self.terminatedTime+5<=os.clock())then - --if("asd"=="b")then - NyoUI.stopUpdate() - for k,v in pairs(_frames)do - v:hide() - end - term.redirect(parentTerminal) - term.setCursorPos(1,1) - term.clear() - --end - end - end -end - -function frame:keyEvent(event,key)-- internal key event, should make it local but as lazy i am.. - for _,b in pairs(self.objects)do - for _,v in pairs(b)do - if(v.draw~=false)then - if(v:keyEvent(event,key))then - return true - end - end - end - end - return false -end - -function frame:onScrollEvent(scrollbar) - if(scrollbar.name == self.name.."__generatedVScrollbar")then - self.yOffset = round((scrollbar.index-1) * scrollbar:getLowestValue()) - if(self.yOffset<0)then self.yOffset = 0 end - end - if(scrollbar.name == self.name.."__generatedHScrollbar")then - self.xOffset = round((scrollbar.index-1) * scrollbar:getLowestValue()) - if(self.xOffset<0)then self.xOffset = 0 end - end -end - -function frame:createScrollbar(typ, val) - if(typ=="horizontal")then - if(self.horizontalScrollbar==nil)then - self.horizontalScrollbar = self:addScrollbar(self.name.."__generatedHScrollbar"):setAnchor("bottom"):setSize(self.w,1):setBarType("horizontal") - self.horizontalScrollbar:onChange(function(self) self.frame.onScrollEvent(self.frame,self.frame.horizontalScrollbar) end) - self.horizontalScrollbar:setZIndex(15) - self.maxXOffset = val or 10 - self.horizontalScrollbar:ignoreScroll(true,true):setSymbolSize(self.w-self.maxXOffset >= 1 and self.w-self.maxXOffset or 1 ) - if(self.verticalScrollBar~=nil)and(self.verticalScrollBar.name==self.name.."__generatedVScrollbar")then - self.horizontalScrollbar:setSize(self.w-1,1) - end - end - else - if(self.verticalScrollBar==nil)then - self.verticalScrollBar = self:addScrollbar(self.name.."__generatedVScrollbar"):setAnchor("right"):setSize(1,self.h) - self.verticalScrollBar:onChange(function(self) self.frame.onScrollEvent(self.frame,self.frame.verticalScrollBar) end) - self.verticalScrollBar:setZIndex(15) - self.maxYOffset = val or 10 - self.verticalScrollBar:setMaxValue(self.maxYOffset) - self.verticalScrollBar:ignoreScroll(true,true):setSymbolSize(self.h-self.maxYOffset >= 1 and self.h-self.maxYOffset or 1 ) - if(self.horizontalScrollbar~=nil)and(self.horizontalScrollbar.name==self.name.."__generatedHScrollbar")then - self.horizontalScrollbar:setSize(self.w-1,1) - end - end - end - return self -end - -function frame:setMaxOffset(typ, val) - if(typ=="horizontal")then - if(self.horizontalScrollbar==nil)then - self.maxXOffset = val or 10 - self.horizontalScrollbar:setSymbolSize(self.w-self.maxXOffset >= 1 and self.w-self.maxXOffset or 1 ) - end - end - if(typ=="vertical")then - if(self.verticalScrollBar==nil)then - self.maxYOffset = val or 10 - self.verticalScrollBar:setSymbolSize(self.h-self.maxYOffset >= 1 and self.h-self.maxYOffset or 1 ) - end - end - return self -end - -function frame:showScrollbar(typ) - if(typ=="horizontal")then - self.horizontalScrollbar:show() - else - self.verticalScrollBar:show() - end - return self -end - -function frame:setCustomScrollbar(typ,bar) - if(bar~=nil)then - if(typ=="horizontal")then - if(self.horizontalScrollbar~=nil)and(self.horizontalScrollbar.name==self.name.."__generatedHScrollbar")then - self:removeObject(self.horizontalScrollbar) - end - self.horizontalScrollbar = bar - else - if(self.verticalScrollBar~=nil)and(self.verticalScrollBar.name==self.name.."__generatedVScrollbar")then - self:removeObject(self.verticalScrollBar) - end - self.verticalScrollBar = bar - end - end - return self -end - -function frame:getScrollbar(typ) - if(typ=="horizontal")then - return self.horizontalScrollbar - else - return self.verticalScrollBar - end -end - -function frame:hideScrollbar(typ) - if(typ=="horizontal")then - if(self.horizontalScrollbar~=nil)then - self.horizontalScrollbar:hide() - end - else - if(self.verticalScrollBar~=nil)then - self.verticalScrollBar:hide() - end - end - return self -end - -function frame:setCursorBlink(bool,color) - if(self.frame~=nil)then - --self.frame:setCursorBlink(bool) - end - self.cursorBlink = bool - self.cursorColor = color or self.fgcolor - return self -end - -function frame:changeZIndexOfObject(obj, zindex) - self:removeObject(obj) - obj.zIndex = zindex - self:addObject(obj) -end - -function frame:setFocusedElement(obj)-- you can set the focus of an element in a frame - 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 - return self -end - -function frame:removeFocusedElement()-- and here you can remove the focus - if(self.focusedObject.name~=nil)then - self.focusedObject:loseFocusEvent() - end - self.focusedObject = {} -end - -function frame:getFocusedElement()--gets the current focused element - return self.focusedObject -end - -function frame:loseFocusEvent()--event which gets fired when the frame lost the focus in this case i remove the cursor blink from the active input object - object.loseFocusEvent(self) - self.cursorBlink = false - self.fWindow.setCursorBlink(false) -end - -function frame:getFocusEvent()--event which gets fired when the frame gets the focus -local frameList = {} - for k,v in pairs(self.frame.objects[self.zIndex])do - if(self~=v)then - table.insert(frameList,v) - end - end - table.insert(frameList,self) - self.frame.objects[self.zIndex] = frameList -end - - -function frame:setMoveable(mv)--you can make the frame moveable (Todo: i want to make all objects moveable, so i can create a ingame gui editor MUHUHHUH) - self.isMoveable = mv - return self; -end ---Frames end - - ---Timer object -function frame:addTimer(name)--adds the timer object - 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)--tobecontinued - self.timer = timer - if(repeats==nil)then repeats = -1 end - 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:updateVisuals() - 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.value)then - self.frame.fWindow.write(self.symbol) - else - self.frame.fWindow.write(" ") - end - end -end - -function checkbox:mouseEvent(event,typ,x,y) -- we have to switch the order of object.mouseEvent with checkbox:mouseEvent, because the value should be changed before we call user click events - local vx,vy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(vx<=x)and(vx+self.w>x)and(vy<=y)and(vy+self.h>y)then - if(event=="mouse_click")then - self:setValue(not self.value) - end - end - if(object.mouseEvent(self,event,typ,x,y))then return true end - return false -end ---Checkbox end - ---Radio object -function frame:addRadio(name) - if(self:getObject(name) == nil)then - local obj = radio:new() - obj.name = name;obj.frame=self; - obj.bgcolor = self.bgcolor - obj.fgcolor = self.fgcolor - obj.symbolBGColor = self.bgcolor - obj.symbolFGColor = self.fgcolor - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function radio:setSymbol(symbol) - self.symbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function radio:setSymbolForegroundColor(color) - self.symbolFGColor = color - self:updateVisuals() - return self -end - -function radio:setSymbolBackgroundColor(color) - self.symbolBGColor = color - self:updateVisuals() - return self -end - -function radio:addItem(text,x,y,bgcolor,fgcolor,...) - if(x==nil)or(y==nil)then - table.insert(self.items,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor),x=0,y=#self.items,vars=table.pack(...)}) - else - table.insert(self.items,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor),x=x,y=y,vars=table.pack(...)}) - end - if(#self.items==1)then - self:setValue(self.items[1]) - end - return self -end - -function radio:removeItem(item) - if(type(item)=="table")then - for k,v in pairs(self.items)do - if(v==item)then - table.remove(self.items,k) - break; - end - end - elseif(type(item)=="number")then - if(self.items[item]~=nil)then - table.remove(self.items,item) - end - end - return self -end - -function radio:mouseEvent(event,typ,x,y) - if(#self.items>0)then - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - for _,v in pairs(self.items)do - if(dx<=x)and(dx+v.x+string.len(v.text)+1>x)and(dy+v.y==y)then - if(event=="mouse_click")and(typ==1)then self:setValue(v) end - if(self.frame~=nil)then self.frame:setFocusedElement(self) end - if(event=="mouse_click")then - if(self.clickFunc~=nil)then - callAll(self.clickFunc,self,event,typ,x,y) - end - elseif(event=="mouse_up")then - if(self.upFunc~=nil)then - callAll(self.upFunc,self,event,typ,x,y) - end - elseif(event=="mouse_drag")then - if(self.dragFunc~=nil)then - callAll(self.dragFunc,self,event,typ,x,y) - end - end - return true - end - end - end - return false -end - -function radio:drawObject() - object.drawObject(self) -- Base class - if(self.draw)then - if(#self.items>0)then - for _,v in ipairs(self.items)do - local objx, objy = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(v.bgcolor) - self.frame.fWindow.setTextColor(v.fgcolor) - self.frame.fWindow.setCursorPos(objx+v.x,objy+v.y) - if(v==self.value)then - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(self.symbolBGColor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(self.symbolFGColor) end - self.frame.fWindow.write(self.symbol) - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(v.bgcolor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(v.fgcolor) end - self.frame.fWindow.write(v.text) - else - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(self.symbolBGColor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(self.symbolFGColor) end - self.frame.fWindow.write(" ") - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(v.bgcolor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(v.fgcolor) end - self.frame.fWindow.write(v.text) - end - end - end - end -end ---Radio 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) - self:setValue(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(tostring(self.value):sub(1,self.w)) - 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:setInputType(typ) - self.iType = typ - self:updateVisuals() - return self -end - -function input:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - local anchX,anchY = self:getAnchorPosition() - self.frame.fWindow.setCursorPos(anchX+(string.len(self.value) < self.w-1 and string.len(self.value) or self.w-1),anchY) - self.cursorX = anchX+(string.len(self.value) < self.w-1 and string.len(self.value) or self.w-1) - self.cursorY = anchY - self.frame.fWindow.setCursorBlink(true) - return true - end - return false -end - -function input:getValue() - if(self.iType=="number")then - if(tonumber(self.value)~=nil)then - return tonumber(self.value) - else - self:setValue(0) - return 0 - end - end - return self.value -end - -function input:keyEvent(event,key) - if(self:isFocusedObject())then - if(self.draw)then - if(event=="key")then - if(key==259)then - self:setValue(string.sub(self.value,1,string.len(self.value)-1)) - end - if(key==257)then -- on enter - if(self.inputActive)then - self.inputActive = false - self.fWindow.setCursorBlink(false) - end - end - end - if(event=="char")then - if(self.iType=="number")then - local cache = self.value - if (key==".")or(tonumber(key)~=nil)then - self:setValue(self.value..key) - end - if(tonumber(self.value)==nil)then - self:setValue(cache) - end - else - self:setValue(self.value..key) - end - end - local anchX,anchY = self:getAnchorPosition() - self.cursorX = anchX+(string.len(self.value) < self.w and string.len(self.value) or self.w-1) - self.cursorY = anchY - if(self.changeFunc~=nil)then - self.changeFunc(self.acveInput) - end - end - end -end - -function input:drawObject() - object.drawObject(self) -- Base class - local text = "" - if(self.draw)then - if(string.len(self.value)>=self.w)then - text = string.sub(self.value, string.len(self.value)-self.w+2, string.len(self.value)) - if(self.iType=="password")then - text = string.sub(string.rep("*",self.value:len()), string.len(self.value)-self.w+2, string.len(self.value)) - else - text = string.sub(self.value, string.len(self.value)-self.w+2, string.len(self.value)) - end - else - if(self.iType=="password")then - text = string.rep("*",self.value:len()) - else - text = self.value - end - - 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) - end -end - -function input:getFocusEvent() - object.getFocusEvent(self) - self.frame:setCursorBlink(true,self.fgcolor) -end - -function input:loseFocusEvent() - object.loseFocusEvent(self) - if(self.iType=="number")then - if(tonumber(self.value)==nil)then - self:setValue(0) - end - end - self.frame: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.value, self.w, self.horizontalTextAlign)) - else - self.frame.fWindow.write(string.rep(" ", self.w)) - end - end - end -end - -function button:setText(text) - return self:setValue(text) -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:addItem(text,bgcolor,fgcolor,...) - table.insert(self.items,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor),vars=...}) - if(#self.items==1)then - self:setValue(self.items[1]) - end - return self -end - -function dropdown:removeItem(item) - if(type(item)=="table")then - for k,v in pairs(self.items)do - if(v==item)then - table.remove(self.items,k) - break; - end - end - elseif(type(item)=="number")then - if(self.items[item]~=nil)then - table.remove(self.items,item) - end - end - return self -end - -function dropdown:setActiveItemBackground(color) - self.activeItemBackground = color - self:updateVisuals() - return self -end - -function dropdown:setActiveItemForeground(color) - self.activeItemForeground = color - self:updateVisuals() - return self -end - -function dropdown:setItemColors(...) - self.itemColors = table.pack(...) - self.itemColorIndex = 1 - self:updateVisuals() - return self -end - -function dropdown:setItemTextColors(...) - self.itemTextColors = table.pack(...) - self.itemTextColorIndex = 1 - self:updateVisuals() - 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.value.bgcolor) - self.frame.fWindow.setTextColor(self.value.fgcolor) - self.frame.fWindow.write(getTextHorizontalAlign(self.value.text, self.w, self.horizontalTextAlign)) - - if(self:isFocusedObject())then - if(#self.items>0)then - self.itemColorIndex = 1 - self.itemTextColorIndex = 1 - local index = 1 - for _,v in ipairs(self.items)do - local objx, objy = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(v.bgcolor) - if(self.itemColors~=nil)then - if(#self.itemColors>0)then - self.frame.fWindow.setBackgroundColor(self.itemColors[self.itemColorIndex]) - self.itemColorIndex = self.itemColorIndex + 1 - if(self.itemColorIndex>#self.itemColors)then - self.itemColorIndex = 1 - end - end - end - if(self.itemTextColors~=nil)then - if(#self.itemTextColors>0)then - self.frame.fWindow.setTextColor(self.itemTextColors[self.itemTextColorIndex]) - self.itemTextColorIndex = self.itemTextColorIndex + 1 - if(self.itemTextColorIndex>#self.itemTextColors)then - self.itemTextColorIndex = 1 - end - end - end - if(v==self.value)then - if(self.activeItemBackground~=nil)then - self.frame.fWindow.setBackgroundColor(self.activeItemBackground) - end - if(self.activeItemForeground~=nil)then - self.frame.fWindow.setTextColor(self.activeItemForeground) - end - end - 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 - end -end - -function dropdown:mouseEvent(event,typ,x,y) - object.mouseEvent(self,event,typ,x,y) - if(self:isFocusedObject())then - if(#self.items>0)then - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - local index = 1 - for _,b in pairs(self.items)do - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - if(event=="mouse_click")and(typ==1)then self:setValue(b) end - if(self.changeFunc~=nil)then - self.changeFunc(self) - end - self.frame:removeFocusedElement() - 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 - self.frame:removeFocusedElement() - 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.colorIndex = 1 - self.textColorIndex = 1 - for index=0,self.h-1 do - self.frame.fWindow.setCursorPos(self:getAnchorPosition(self.x,self.y+index)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - - if(self.items[index+self.index]~=nil)then - local bgCol = self.items[index+self.index].bgcolor or self.itemColors[self.colorIndex] - local fgCol = self.items[index+self.index].fgcolor or self.itemTextColors[self.textColorIndex] - if(self.items[index+self.index].bgcolor == nil)then self.colorIndex = self.colorIndex+1 end - if(self.items[index+self.index].fgcolor == nil)then self.textColorIndex = self.textColorIndex+1 end - if(self.colorIndex>#self.itemColors)then self.colorIndex = 1 end - if(self.textColorIndex>#self.itemTextColors)then self.textColorIndex = 1 end - self.frame.fWindow.setBackgroundColor(bgCol) - self.frame.fWindow.setTextColor(fgCol) - if(self.items[index+self.index]==self.value)then - if(self.activeItemBackground~=nil)then self.frame.fWindow.setBackgroundColor(self.activeItemBackground) end - if(self.activeItemForeground~=nil)then self.frame.fWindow.setTextColor(self.activeItemForeground) end - self.frame.fWindow.write(self.symbol..getTextHorizontalAlign(self.items[index+self.index].text, self.w-string.len(self.symbol), self.horizontalTextAlign)) - else - self.frame.fWindow.write(string.rep(" ", string.len(self.symbol))..getTextHorizontalAlign(self.items[index+self.index].text, self.w-string.len(self.symbol), self.horizontalTextAlign)) - end - else - self.frame.fWindow.write(getTextHorizontalAlign(" ", self.w, self.horizontalTextAlign)) - end - end - end -end - -function list:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw - if(typ==1)then - if(#self.items>0)then - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - for index=0,self.h do - if(self.items[index+self.index]~=nil)then - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - self:setValue(self.items[index+self.index]) - self:updateVisuals() - return true - end - end - end - end - end - end - if(event=="mouse_scroll")then - self.index = self.index+typ - if(self.index<1)then self.index = 1 end - if(typ==1)then - if(#self.items>self.h)then - if(self.index>#self.items+1-self.h)then - self.index = #self.items+1-self.h - end - else - self.index = self.index-1 - end - end - self:updateVisuals() - return true - end - end - return false -end - -function list:onScrollbarChangeEvent(scrollbar) - --self.index = (scrollbar.value/(scrollbar.maxValue/(scrollbar.barType=="vertical" and scrollbar.h or scrollbar.w))) - self.index = math.floor(scrollbar.value) - if(self.index<1)then self.index = 1 end - if(self.index>#self.items+1-self.h)then self.index = #self.items+1-self.h end -end - -function list:addScrollbar(obj) - if(obj.__type=="Scrollbar")then - self.scrollbar = obj - self.scrollbar:setMaxValue(#self.items+1-self.h) - self.scrollbar.args = self - self.scrollbar:onChange(function(scrlb,lst) lst:onScrollbarChangeEvent(scrlb) end) - end - return self -end - -function list:addItem(text,bgcolor,fgcolor,...) - table.insert(self.items,{text=text,bgcolor=bgcolor,fgcolor=fgcolor,vars=...}) - if(#self.items==1)then - self:setValue(self.items[1]) - end - if(self.scrollbar~=nil)then - self.scrollbar:setMaxValue(#self.items-self.h) - end - return self -end - -function list:setItemColors(...) - self.itemColors = table.pack(...) - self:updateVisuals() - return self -end - -function list:setItemTextColors(...) - self.itemTextColors = table.pack(...) - self:updateVisuals() - return self -end - -function list:setIndex(index) - self.index = index - self:updateVisuals() - return self -end - -function list:removeItem(item) - if(type(item)=="table")then - for k,v in pairs(self.items)do - if(v==item)then - table.remove(self.items,k) - break; - end - end - elseif(type(item)=="number")then - if(self.items[item]~=nil)then - table.remove(self.items,item) - end - end - - if(self.scrollbar~=nil)then - self.scrollbar:setMaxValue(#self.items-self.h) - end - return self -end - -function list:setSymbol(symbol) - self.symbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function list:setActiveItemBackground(color) - self.activeItemBackground = color - self:updateVisuals() - return self -end - -function list:setActiveItemForeground(color) - self.activeItemForeground = color - self:updateVisuals() - return self -end - -function frame:addTextfield(name) - if(self:getObject(name) == nil)then - local obj = textfield:new() - obj.name = name;obj.frame=self; - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function textfield:keyEvent(event,key) - if(self:isFocusedObject())then - if(self.draw)then - local anchX,anchY = self:getAnchorPosition() - if(event=="key")then - if(key==259)then -- on backspace - if(self.lines[self.textY]=="")then - if(self.textY>1)then - table.remove(self.lines,self.textY) - self.textX = self.lines[self.textY-1]:len()+1 - self.wIndex = self.textX-self.w+1 - if(self.wIndex<1)then self.wIndex = 1 end - self.textY = self.textY-1 - end - elseif(self.textX<=1)then - if(self.textY>1)then - self.textX = self.lines[self.textY-1]:len()+1 - self.wIndex = self.textX-self.w+1 - if(self.wIndex<1)then self.wIndex = 1 end - self.lines[self.textY-1] = self.lines[self.textY-1]..self.lines[self.textY] - table.remove(self.lines,self.textY) - self.textY = self.textY-1 - end - else - self.lines[self.textY] = self.lines[self.textY]:sub(1,self.textX-2)..self.lines[self.textY]:sub(self.textX,self.lines[self.textY]:len()) - if(self.textX>1)then self.textX = self.textX-1 end - if(self.wIndex>1)then - if(self.textX=self.h)then - self.hIndex = self.hIndex+1 - end - end - if(key==258)then -- on tab - - --self.lines[self.textY] = self.lines[self.textY]..string.rep(" ",self.w-(self.w-self.lines[self.textY]:len())) - end - if(key==265)then -- arrow up - if(self.textY>1)then - self.textY = self.textY-1 - if(self.textX>self.lines[self.textY]:len()+1)then self.textX = self.lines[self.textY]:len()+1 end - if(self.wIndex>1)then - if(self.textX1)then - if(self.textYself.lines[self.textY]:len()+1)then self.textX = self.lines[self.textY]:len()+1 end - - if(self.textY>=self.hIndex+self.h)then - self.hIndex = self.hIndex+1 - end - end - end - if(key==262)then -- arrow right - self.textX = self.textX+1 - if(self.textY<#self.lines)then - if(self.textX>self.lines[self.textY]:len()+1)then - self.textX = 1 - self.textY = self.textY+1 - end - elseif(self.textX > self.lines[self.textY]:len())then - self.textX = self.lines[self.textY]:len()+1 - end - if(self.textX<1)then self.textX = 1 end - if(self.textX=self.w+self.wIndex)then - self.wIndex = self.textX-self.w+1 - end - if(self.wIndex<1)then self.wIndex = 1 end - - end - if(key==263)then -- arrow left - self.textX = self.textX-1 - if(self.textX>=1)then - if(self.textX=self.w+self.wIndex)then - self.wIndex = self.textX+1 - end - end - if(self.textY>1)then - if(self.textX<1)then - self.textY = self.textY-1 - self.textX = self.lines[self.textY]:len()+1 - self.wIndex = self.textX-self.w+1 - end - end - if(self.textX<1)then self.textX = 1 end - if(self.wIndex<1)then self.wIndex = 1 end - end - end - if(event=="char")then - self.lines[self.textY] = self.lines[self.textY]:sub(1,self.textX-1)..key..self.lines[self.textY]:sub(self.textX,self.lines[self.textY]:len()) - self.textX = self.textX+1 - if(self.textX>=self.w+self.wIndex)then self.wIndex = self.wIndex+1 end - end - self.cursorX = anchX+(self.textX <= self.lines[self.textY]:len() and self.textX-1 or self.lines[self.textY]:len())-(self.wIndex-1) - if(self.cursorX>self.x+self.w-1)then self.cursorX = self.x+self.w-1 end - self.cursorY = anchY+(self.textY-self.hIndex < self.h and self.textY-self.hIndex or self.textY-self.hIndex-1) - if(self.changeFunc~=nil)then - callAll(self.changeFunc) - end - end - end -end - -function textfield:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")then - local anchX,anchY = self:getAnchorPosition() - local absX,absY = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.lines[y-absY+self.hIndex]~=nil)then - self.textX = x-absX+self.wIndex - self.textY = y-absY+self.hIndex - if(self.textX>self.lines[self.textY]:len())then - self.textX = self.lines[self.textY]:len()+1 - end - if(self.textX=#self.lines-self.h)then self.hIndex = #self.lines-self.h end - self:updateVisuals() - end - return true - end - return false -end - -function textfield:drawObject() - object.drawObject(self) -- Base class - if(self.draw)then - for index=0,self.h-1 do - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.setTextColor(self.fgcolor) - local text = "" - if(self.lines[index+self.hIndex]~=nil)then - text = self.lines[index+self.hIndex] - end - text = text:sub(self.wIndex, self.w+self.wIndex-1) - local n = self.w-text:len() - if(n<0)then n = 0 end - text = text..string.rep(" ", n) - - self.frame.fWindow.setCursorPos(self:getAnchorPosition(self.x,self.y+index)) - self.frame.fWindow.write(text) - end - if(self.cursorX==nil)or(self.cursorXself.x+self.w)then self.cursorX = self.x end - if(self.cursorY==nil)or(self.cursorYself.y+self.h)then self.cursorY = self.y end - self.frame.fWindow.setCursorPos(self.cursorX,self.cursorY) - end -end - - -function textfield:getFocusEvent() - object.getFocusEvent(self) - self.frame:setCursorBlink(true) -end - -function textfield:loseFocusEvent() - object.loseFocusEvent(self) - self.frame:setCursorBlink(false) -end - - - - -function frame:addScrollbar(name) - if(self:getObject(name) == nil)then - local obj = scrollbar:new() - obj.name = name;obj.frame=self; - obj.maxValue = obj.h - obj.value = obj.maxValue/obj.h - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function scrollbar:setSize(w,h) - object.setSize(self,w,h) - if(self.barType=="vertical")then - self.maxValue = self.h - self.value = self.maxValue/self.h - elseif(self.barType=="horizontal")then - self.maxValue = self.w - self.value = self.maxValue/self.w - end - return self -end - -function scrollbar:getIndex() - return self.index -end - -function scrollbar:setIndex(index) - self.index = index - if(self.index<1)then self.index = 1 end - if(self.index>(self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1))then self.index = (self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1) end - self:setValue(self.index-1 * (self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))-(self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))) - return self -end - -function scrollbar:drawObject() - object.drawObject(self) -- Base class - if(self.draw)then - local x,y = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.setTextColor(self.fgcolor) - if(self.barType=="vertical")then - for curIndex=1,self.h do - self.frame.fWindow.setCursorPos(x,y+curIndex-1) - if(self.index==curIndex)then - for curIndexOffset=0,self.symbolSize-1 do - self.frame.fWindow.setCursorPos(x,y+curIndex-1+curIndexOffset) - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(string.rep(self.symbol,self.w)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - end - else - if(curIndexself.index-1+self.symbolSize)then - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w)) - end - end - end - end - if(self.barType=="horizontal")then - for curIndex=1,self.h do - self.frame.fWindow.setCursorPos(x,y+curIndex-1) - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w-(self.w-(self.index-1)))) - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(string.rep(self.symbol,self.symbolSize)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w-(self.index+(self.symbolSize-1)))) - end - end - end -end - -function scrollbar:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.barType=="vertical")then - for index=0,self.h-1 do - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - if(index <= self.h-self.symbolSize)then - self.index = index+1 - else - self.index = self.h-(self.symbolSize-1) - end - self:setValue(self.index-1 * (self.maxValue/(self.h-(self.symbolSize-1)))-(self.maxValue/(self.h-(self.symbolSize-1)))) - self:updateVisuals() - end - end - end - if(self.barType=="horizontal")then - for index=0,self.w-1 do - if(dx+index==x)and(dy<=y)and(dy+self.y>y)then - if(index <= self.w-self.symbolSize)then - self.index = index+1 - else - self.index = self.w-(self.symbolSize-1) - end - self:setValue(self.index-1 * (self.maxValue/(self.w-(self.symbolSize-1)))-(self.maxValue/(self.w-(self.symbolSize-1)))) - self:updateVisuals() - end - end - end - end - if(event=="mouse_scroll")then - self.index = self.index+typ - if(self.index<1)then self.index = 1 end - if(self.index>(self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1))then self.index = (self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1) end - - self:setValue(self.index-1 * (self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))-(self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))) - self:updateVisuals() - end - return true - end -end - -function scrollbar:setSymbol(symbol) - self.symbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function scrollbar:setSymbolSize(size) - self.symbolSize = tonumber(size) or 1 - if(self.barType=="vertical")then - self:setValue(self.index-1 * (self.maxValue/(self.h-(self.symbolSize-1)))-(self.maxValue/(self.h-(self.symbolSize-1)))) - elseif(self.barType=="horizontal")then - self:setValue(self.index-1 * (self.maxValue/(self.w-(self.symbolSize-1)))-(self.maxValue/(self.w-(self.symbolSize-1)))) - end - self:updateVisuals() - return self -end - -function scrollbar:setBackgroundSymbol(symbol) - self.bgSymbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function scrollbar:setMaxValue(val) - self.maxValue = val - if(self.barType=="vertical")then - self:setValue(self.index-1 * (self.maxValue/(self.h-(self.symbolSize-1)))-(self.maxValue/(self.h-(self.symbolSize-1)))) - elseif(self.barType=="horizontal")then - self:setValue(self.index-1 * (self.maxValue/(self.w-(self.symbolSize-1)))-(self.maxValue/(self.w-(self.symbolSize-1)))) - end - self:updateVisuals() - return self -end - -function scrollbar:getLowestValue() - if(self.barType=="vertical")then - return self.maxValue/(self.h-(self.symbolSize-1)) - elseif(self.barType=="horizontal")then - return self.maxValue/(self.w-(self.symbolSize-1)) - end - return self -end - -function scrollbar:setSymbolColor(color) - self.symbolColor = color - self:updateVisuals() - return self -end - -function scrollbar:setBarType(typ) - self.barType = typ:lower() - self:updateVisuals() - return self -end - -function scrollbar:setBarSize(typ) - self.barSize = typ:lower() - self:updateVisuals() - return self -end - -function frame:addSlider(name) - if(self:getObject(name) == nil)then - local obj = slider:new() - obj.name = name;obj.frame=self; - obj.maxValue = obj.h - obj.value = obj.maxValue/obj.h - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function slider:setSize(w,h) - object.setSize(self,w,h) - if(self.barType=="vertical")then - self.maxValue = self.h - self.value = self.maxValue/self.h - elseif(self.barType=="horizontal")then - self.maxValue = self.w - self.value = self.maxValue/self.w - end - return self -end - -function slider:drawObject() - object.drawObject(self) -- Base class - if(self.draw)then - local x,y = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.setTextColor(self.fgcolor) - if(self.barType=="vertical")then - for curPos=0,self.h-1 do - self.frame.fWindow.setCursorPos(x,y+curPos) - if(tostring(self.maxValue/self.h*(curPos+1))==tostring(self.value))then - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(string.rep(self.symbol,self.w)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - else - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w)) - end - end - end - if(self.barType=="horizontal")then - for curPos=0,self.h-1 do - self.frame.fWindow.setCursorPos(x,y+curPos) - self.frame.fWindow.write(string.rep(self.bgSymbol,(self.value/(self.maxValue/self.w))-1)) - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(self.symbol) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.write(string.rep(self.bgSymbol,self.maxValue/(self.maxValue/self.w)-(self.value/(self.maxValue/self.w)))) - end - end - end -end - -function slider:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.barType=="vertical")then - for index=0,self.h-1 do - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - self:setValue(self.maxValue/self.h*(index+1)) - self:updateVisuals() - end - end - end - if(self.barType=="horizontal")then - for index=0,self.w-1 do - if(dx+index==x)and(dy<=y)and(dy+self.y>y)then - self:setValue(self.maxValue/self.w*(index+1)) - self:updateVisuals() - end - end - end - end - if(event=="mouse_scroll")then - self:setValue(self.value + (self.maxValue/(self.barType=="vertical" and self.h or self.w))*typ) - self:updateVisuals() - end - if(self.value>self.maxValue)then self:setValue(self.maxValue) end - if(self.value0)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 - else - self.playing = false - self.index = 1 - end - end - end -end - -function animation:play(infiniteloop) - if(infiniteloop~=nil)then self.infiniteloop=infiniteloop end - self.playing = true - 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 - end - return self -end - -function animation:cancel() - os.cancelTimer(self.timeObj) - self.playing = false - self.infiniteloop = false - self.index = 1 - return self -end ------------ - - -local function checkTimer(timeObject) - for a,b in pairs(activeFrame.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 - if(v.__type=="Animation")and(v.playing)then - if(v.timeObj == timeObject)then - v:onPlay() - end - end - end - end -end - - -local function handleObjectDrawing() -local changed = false - for k,v in pairs(activeFrame.objects)do - for a,b in pairs(v)do - if(b.changed)then - changed = true - end - end - end - if(changed)then - activeFrame:drawObject() - end -end - -if(NyoUI.debugger)then - NyoUI.debugFrame = NyoUI.createFrame("NyoUIDebuggingFrame"):showBar():setBackground(colors.lightGray):setTitle("Debug",colors.black,colors.gray) - NyoUI.debugList = NyoUI.debugFrame:addList("debugList"):setSize(NyoUI.debugFrame.w - 2, NyoUI.debugFrame.h - 3):setPosition(2,3):setSymbol(""):setBackground(colors.gray):setItemColors(colors.gray):setTextAlign("left"):show() - NyoUI.debugFrame:addButton("back"):setAnchor("right"):setSize(1,1):setText("\22"):onClick(function() NyoUI.oldFrame:show() end):setBackground(colors.red):show() - NyoUI.debugLabel = NyoUI.debugFrame:addLabel("debugLabel"):onClick(function() NyoUI.oldFrame = activeFrame NyoUI.debugFrame:show() end):setBackground(colors.black):setForeground(colors.white):setAnchor("bottom"):ignoreScroll(true,true):show() -end - -function NyoUI.startUpdate() - if not(NyoUI.updater)then - handleObjectDrawing() - NyoUI.updater = true - while NyoUI.updater do - local event, p1,p2,p3,p4 = os.pullEventRaw() - activeFrame:eventListener(event,p1,p2,p3,p4) - if(event=="mouse_click")then - activeFrame:mouseEvent(event,p1,p2,p3) - end - if(event=="mouse_scroll")then - activeFrame:mouseEvent(event,p1,p2,p3) - end - if(event=="mouse_drag")then - activeFrame:mouseEvent(event,p1,p2,p3) - end - if(event=="mouse_up")then - activeFrame:mouseEvent(event,p1,p2,p3) - end - if(event=="timer")then - checkTimer(p1) - end - if(event=="char")or(event=="key")then - activeFrame:keyEvent(event,p1) - keyModifier[p1] = true - end - if(event=="key_up")then - keyModifier[p1] = false - end - handleObjectDrawing() - end - end -end - -function NyoUI.stopUpdate() - NyoUI.updater = false -end - -if(NyoUI.debugger)then - function NyoUI.debug(...) - local args = {...} - if(activeFrame.name~="NyoUIDebuggingFrame")then - if(activeFrame~=NyoUI.debugLabel.frame)then - NyoUI.debugLabel:setParent(activeFrame) - end - end - local str = "" - for k,v in pairs(args)do - str = str..tostring(v)..(#args~=k and ", " or "") - end - NyoUI.debugLabel:setText("[Debug] "..str) - NyoUI.debugList:addItem(str) - if(#NyoUI.debugList.items>NyoUI.debugList.h)then NyoUI.debugList:removeItem(1) end - - NyoUI.debugLabel:show() - end - -end - -function NyoUI.getFrame(name) - return _frames[name]; -end - -function NyoUI.getActiveFrame() - if(activeFrame.name=="NyoUIDebuggingFrame")then - return oldFrame - end - return activeFrame -end - -return NyoUI; \ No newline at end of file diff --git a/basalt.lua b/basalt.lua deleted file mode 100644 index 72871a8..0000000 --- a/basalt.lua +++ /dev/null @@ -1,2600 +0,0 @@ -animation = {__type = "Animation", name = ""} -animation.__index = animation - -local Basalt = {debugger=true,updater=false} - -local object = {} -- Base class for all UI elements - -local activeFrame -local _frames = {} -local animationQueue = {} -local keyModifier = {} -local parentTerminal = term.current() - - ---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 copyVar(orig) - local orig_type = type(orig) - local copy - if orig_type == 'table' then - copy = {} - for orig_key, orig_value in next, orig, nil do - copy[copyVar(orig_key)] = copyVar(orig_value) - end - setmetatable(copy, copyVar(getmetatable(orig))) - else -- number, string, boolean, etc - copy = orig - end - return copy -end - -local function callAll(tab,...) - if(tab~=nil)then - if(#tab>0)then - for k,v in pairs(tab)do - v(...) - end - end - end -end - -local function sign(v) - return (v >= 0 and 1) or -1 -end - -local function round(v, bracket) - bracket = bracket or 1 - return math.floor(v/bracket + sign(v) * 0.5) * bracket -end - ---Object Constructors: ---(base class for every element/object even frames) -function object:new() - local newElement = {__type = "Object",name="",links={},zIndex=1,drawCalls=0,x=1,y=1,xOriginal=1,yOriginal=1,w=1,h=1,draw=false,bgcolor=colors.black,fgcolor=colors.white,hanchor="left",vanchor="top",ignYOffset=false,ignXOffset=false} - setmetatable(newElement, {__index = self}) - return newElement -end - -function object:copy(obj) -local newElement = {} - for k,v in pairs(obj)do - newElement[k] = v - end - 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="\42",zIndex=5,bgcolor=colors.gray,fgcolor=colors.black, value = false} - setmetatable(newElement, {__index = self}) - return newElement -end - -radio = object:new() -function radio:new() - local newElement = {__type = "Radio",symbol="\7",symbolFGColor=colors.black,symbolBGColor=colors.gray,zIndex=5,bgcolor=colors.gray,fgcolor=colors.black, value = "", items={}} - setmetatable(newElement, {__index = self}) - return newElement -end - -label = object:new() -function label:new() - local newElement = {__type = "Label", value=""} - setmetatable(newElement, {__index = self}) - return newElement -end - -input = object:new() -function input:new() - local newElement = {__type = "Input",zIndex=5,bgcolor=colors.gray,fgcolor=colors.black,w=10, value = "", iType = "text"} - setmetatable(newElement, {__index = self}) - return newElement -end - -button = object:new() -function button:new() - local newElement = {__type = "Button",zIndex=5,bgcolor=colors.gray,fgcolor=colors.black,w=8,horizontalTextAlign="center",verticalTextAlign="center",value=""} - setmetatable(newElement, {__index = self}) - return newElement -end - -dropdown = object:new() -function dropdown:new() - local newElement = {__type = "Dropdown",zIndex=9,bgcolor=colors.gray,fgcolor=colors.black,w=10,horizontalTextAlign="center",items={},value={text="",fgcolor=colors.black,bgcolor=colors.lightBlue}} - setmetatable(newElement, {__index = self}) - return newElement -end - -list = object:new() -function list:new() - local newElement = {__type = "List",index=1,colorIndex=1,textColorIndex=1,zIndex=5,activeItemBackground=colors.black,activeItemForeground=colors.lightGray,itemColors={colors.gray},itemTextColors={colors.black},symbol="",bgcolor=colors.gray,fgcolor=colors.black,w=15,h=6,horizontalTextAlign="center",items={},value={text=""}} - setmetatable(newElement, {__index = self}) - return newElement -end - -textfield = object:new() -function textfield:new() - local newElement = {__type = "Textfield",hIndex=1,wIndex=1,textX=1,textY=1,zIndex=5,bgcolor=colors.gray,fgcolor=colors.black,w=20,h=6,value="",lines={""}} - setmetatable(newElement, {__index = self}) - return newElement -end - -scrollbar = object:new() -function scrollbar:new() - local newElement = {__type = "Scrollbar",index=1,value=1,zIndex=10,bgcolor=colors.gray,fgcolor=colors.black,w=8,h=1,barType="vertical", symbolColor=colors.black, symbol = " ", symbolSize = 1, bgSymbol = "\127"} - setmetatable(newElement, {__index = self}) - return newElement -end - -slider = object:new() -function slider:new() - local newElement = {__type = "Slider",value=1,zIndex=5,bgcolor=colors.lightGray,fgcolor=colors.gray,w=5,h=1,barType="horizontal", symbolColor=colors.black, symbol = " ", bgSymbol = "\140"} - setmetatable(newElement, {__index = self}) - return newElement -end - -program = object:new() -function program:new() - local newElement = {__type = "Program",value="",zIndex=5,bgcolor=colors.black,fgcolor=colors.white,w=12,h=6} - setmetatable(newElement, {__index = self}) - return newElement -end - -animation = object:new() -function animation:new() - local newElement = {__type = "Animation",animations={},nextWaitTimer=0,index=1,infiniteloop=false} - setmetatable(newElement, {__index = self}) - return newElement -end - -frame = object:new() -function frame:new(name,scrn,frameObj) - local parent = scrn~=nil and scrn or term.current() - local w, h = parent.getSize() - local newElement = {} - if(frameObj~=nil)then - newElement = object:copy(frameObj) - newElement.fWindow = window.create(parent,1,1,frameObj.w,frameObj.h) - else - newElement = {__type = "Frame",name=name, parent = parent,zIndex=10, xOffset=0, yOffset=0, fWindow = window.create(parent,1,1,w,h),x=1,y=1,w=w,h=h, objects={},objZKeys={},bgcolor = colors.lightGray, fgcolor=colors.black,barActive = false, title="New Frame", titlebgcolor = colors.gray, titlefgcolor = colors.black, horizontalTextAlign="left",focusedObject={}, isMoveable = false,cursorBlink=false} - end - setmetatable(newElement, {__index = self}) - return newElement -end --------- - ---object methods -function object:show() - self.draw = true - self:updateVisuals() - return self -end - -function object:hide() - self.draw = false - self:updateVisuals() - return self -end - -function object:changeVisibility() - if(self.draw)then - self:hide() - else - self:show() - end - return self -end - -function object:isVisible() - return self.draw -end - -function object:getName() - return self.name -end - -function object:setPosition(x,y,typ) - if(typ=="r")or(typ=="relative")then - self.x = self.xOriginal+tonumber(x) - self.y = self.yOriginal+tonumber(y) - self.xOriginal = self.xOriginal+tonumber(x) - self.yOriginal = self.yOriginal+tonumber(y) - else - self.x = tonumber(x) - self.y = tonumber(y) - self.xOriginal = tonumber(x) - self.yOriginal = tonumber(y) - end - self:updateVisuals() - return self -end - -function object:setBackground(color) - self.bgcolor = color - self:updateVisuals() - return self -end - -function object:setForeground(color) - self.fgcolor = color - self:updateVisuals() - return self -end - ---Object Events:----- -function object:onClick(func) - if(self.clickFunc==nil)then self.clickFunc = {} end - table.insert(self.clickFunc,func) - return self -end - -function object:onClickUp(func) - if(self.upFunc==nil)then self.upFunc = {} end - table.insert(self.upFunc,func) - return self -end - -function object:onMouseDrag(func) - if(self.dragFunc==nil)then self.dragFunc = {} end - table.insert(self.dragFunc,func) - return self -end - -function object:onChange(func) - if(self.changeFunc==nil)then self.changeFunc = {} end - table.insert(self.changeFunc,func) - return self -end - -function object:onKey(func) - if(self.keyEventFunc==nil)then self.keyEventFunc = {} end - table.insert(self.keyEventFunc,func) - return self -end - -function object:onLoseFocus(func) - if(self.loseFocusEventFunc==nil)then self.loseFocusEventFunc = {} end - table.insert(self.loseFocusEventFunc,func) - return self -end - -function object:onGetFocus(func) - if(self.getFocusEventFunc==nil)then self.getFocusEventFunc = {} end - table.insert(self.getFocusEventFunc,func) - return self -end --------------------- - -function object:setSize(w,h) - self.w = tonumber(w) - self.h = tonumber(h) - self:updateVisuals() - return self -end - -function object:getHeight() - return self.h -end - -function object:getWidth() - return self.w -end - -function object:linkTo(obj) - obj:link(self) - return self -end - -function object:link(obj) -- does not work correctly needs a fix dsfgsdfgfsdg - if(obj.__type==self.__type)then - self.links[obj.name] = obj - end - return self -end - -function object:isLinkedTo(obj) - return (obj[self.name] ~= nil) -end - -function object:isLinked(obj) - return (self[obj.name] ~= nil) -end - -function object:setValue(val) - if(self.value~=val)then - self.value = val - self:updateVisuals() - end - for _,v in pairs(self.links)do - if(v.value~=val)then - v.value = val - v:updateVisuals() - end - end - - callAll(self.changeFunc,self,self.args) - return self -end - -function object:getValue() - return self.value; -end - -function object:setCustomArgs(args) - self.args = args - return self; -end - -function object:setTextAlign(halign,valign) - self.horizontalTextAlign = halign - if(valign~=nil)then self.verticalTextAlign = valign end - self:updateVisuals() - return self -end - -function object:updateVisuals() - self.changed = true -end - -function object:drawObject() - if(self.draw)then - self.drawCalls = self.drawCalls + 1 - if(self.frame~=nil)then - if not(self.ignXOffset)then - if(self.hanchor=="right")then - self.x = self.xOriginal + self.frame.xOffset - else - self.x = self.xOriginal - self.frame.xOffset - end - end - if not(self.ignYOffset)then - if(self.vanchor=="bottom")then - self.y = self.yOriginal + self.frame.yOffset - else - self.y = self.yOriginal - self.frame.yOffset - end - end - if(self.__type=="Frame")then - self.fWindow.reposition(self.x,self.y) - end - end - self.changed=false - return true - end - return false -end - -function object:ignoreScroll(vertical,horizontal) - self.ignYOffset = vertical - self.ignXOffset = horizontal - return self -end - -function object:setAnchor(...) - if(type(...)=="string")then - if(...=="right")or(...=="left")then - self.hanchor = ... - end - if(...=="top")or(...=="bottom")then - self.vanchor = ... - end - end - if(type(...)=="table")then - for _,v in pairs(...)do - if(v=="right")or(v=="left")then - self.hanchor = v - end - if(v=="top")or(v=="bottom")then - self.vanchor = v - end - end -end - return self -end - -function object:relativeToAbsolutePosition(x,y) -- relative position - if(x==nil)then x = self.x end - if(y==nil)then y = self.y end - - if(self.frame~=nil)then - local fx,fy = self.frame:relativeToAbsolutePosition() - x=fx+x-1 - y=fy+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-self.w+2 - end - if(self.vanchor=="bottom")then - y = self.frame.h-y-self.h+2 - end - return x, y -end - -function object:isFocusedObject() - if(self.frame~=nil)then - return self == self.frame.focusedObject - end - return false -end - -function object:mouseEvent(event,typ,x,y) -- internal class, dont use unless you know what you do -local vx,vy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(vx<=x)and(vx+self.w>x)and(vy<=y)and(vy+self.h>y)then - if(self.frame~=nil)then self.frame:setFocusedElement(self) end - if(event=="mouse_click")then - if(self.clickFunc~=nil)then - callAll(self.clickFunc,self,event,typ,x,y) - end - elseif(event=="mouse_up")then - if(self.upFunc~=nil)then - callAll(self.upFunc,self,event,typ,x,y) - end - elseif(event=="mouse_drag")then - if(self.dragFunc~=nil)then - callAll(self.dragFunc,self,event,typ,x,y) - end - end - return true - end - return false -end - -function object:eventListener(event,p1,p2,p3,p4) - -end - -function object:keyEvent(event,typ) -- internal class, dont use unless you know what you do - if(self.keyEventFunc~=nil)then - callAll(self.keyEventFunc,self,typ) - end -end - -function object:setFocus() - if(self.frame~=nil)then - self.frame:setFocusedElement(self) - end - return self -end - -function object:loseFocusEvent() - if(self:isFocusedObject())then - if(self.loseFocusEventFunc~=nil)then - callAll(self.loseFocusEventFunc,self) - end - return true - end - return false -end - -function object:getFocusEvent() - if not(self:isFocusedObject())then - if(self.getFocusEventFunc~=nil)then - callAll(self.getFocusEventFunc,self) - end - return true - end - return false -end - -function object:setZIndex(index) - self.frame:changeZIndexOfObject(self,index) - return self -end - - -function object:setParent(frame) - if(frame.__type=="Frame")then - if(self.frame~=nil)then - self.frame:removeObject(self) - end - self.frame = frame - self.frame:addObject(self) - if(self.draw)then - self:show() - end - end - return self -end ---object end - ---Frame object -Basalt.createFrame = function(name, scrn) -- this is also just a frame, but its a level 0 frame -local obj = frame:new(name,scrn or parentTerminal) - if(_frames[name] == nil)then - _frames[name] = obj - obj.fWindow.setVisible(false) - return obj; - else - return _frames[name]; - end -end - -Basalt.removeFrame = function(name) - _frames[name].fWindow.setVisible(false) - _frames[name] = nil -end - -function frame:addFrame(frameObj) -- with this you also create frames, but it needs to have a parent frame (level 1 or more frame) - if(self:getObject(frameObj) == nil)then - local obj - if(type(frameObj)=="string")then - obj = frame:new(frameObj,self.fWindow) - elseif(type(frameObj)=="table")and(frameObj.__type=="Frame")then - obj = frame:new(frameObj.name,self.fWindow,frameObj) - end - obj.frame=self; - self:addObject(obj) - return obj; - else - return nil, "id "..frameObj.." already exists"; - end -end - -function frame:setParentFrame(parent) -- if you want to change the parent of a frame. even level 0 frames can have a parent (they will be 'converted' *habschi*) - if(parent.__type=="Frame")and(parent~=self.frame)then - if(self.frame~=nil)then - self.frame:removeObject(self) - end - self.parent = parent.fWindow - self.frame = parent - self.fWindow.setVisible(false) - self.fWindow = window.create(parent.fWindow,self.x,self.y,self.w,self.h) - self.frame:addObject(self) - if(self.draw)then - self:show() - end - end - return self -end - -function frame:showBar(active) -- shows the top bar - self.barActive = active ~= nil and active or true - self:updateVisuals() - return self -end - -function frame:isModifierActive(key) - if(key==340)or(key=="shift")then - return keyModifier[340] - end - if(key==341)or(key=="ctrl")then - return keyModifier[341] - end - if(key==342)or(key=="alt")then - return keyModifier[342] - end - return keyModifier[key] -end - -function frame:setTitle(title,fgcolor,bgcolor) -- changed the title in your top bar - self.title=title - if(fgcolor~=nil)then self.titlefgcolor = fgcolor end - if(bgcolor~=nil)then self.titlebgcolor = bgcolor end - self:updateVisuals() - return self -end - -function frame:setTitleAlign(align) -- changes title align - self.horizontalTextAlign = align - self:updateVisuals() - return self -end - -function frame:setSize(width, height) -- frame size - object.setSize(self,width,height) - self.fWindow.reposition(self.x,self.y,width,height) - return self -end - -function frame:setXOffset(offset) -- frame x offset - self.xOffset = offset - self:updateVisuals() - return self -end - -function frame:setYOffset(offset) -- frame y offset - self.yOffset = offset - self:updateVisuals() - return self -end - -function frame:setPosition(x,y,typ) -- pos - object.setPosition(self,x,y,typ) - self.fWindow.reposition(self.x,self.y) - return self -end - -function frame:show() -- you need to call to be able to see the frame - object.show(self) - self.fWindow.setBackgroundColor(self.bgcolor) - self.fWindow.setTextColor(self.fgcolor) - self.fWindow.setVisible(true) - self.fWindow.redraw() - if(self.frame == nil)then - activeFrame = self - end - return self -end - -function frame:hide() -- hides the frame (does not remove setted values) - object.hide(self) - self.fWindow.setVisible(false) - self.fWindow.redraw() - self.parent.clear() - return self -end - -function frame:remove() -- removes the frame completly - if(self.frame~=nil)then - object.hide(self) - end - self:updateVisuals() - self.draw = false - self.fWindow.setVisible(false) - _frames[self.name] = nil - self.parent.clear() -end - -function frame:getObject(name) -- you can find objects by their name - if(self.objects~=nil)then - for _,b in pairs(self.objects)do - for _,v in pairs(b)do - if(v.name==name)then - return v - end - end - end - end -end - -function frame:removeObject(obj) -- you can remove objects - if(self.objects~=nil)then - for a,b in pairs(self.objects)do - for k,v in pairs(b)do - if(v==obj)then - table.remove(self.objects[a],k) - return; - end - end - end - end -end - -function frame:addObject(obj) -- you can add a object manually, normaly you shouldn't use this function, it gets called internally - if(self.objects[obj.zIndex]==nil)then - for x=0,#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 - self.objects[obj.zIndex] = {} - end - table.insert(self.objects[obj.zIndex],obj) -end - -function frame:drawObject() -- this draws the frame, you dont need that function, it gets called internally - if(object.drawObject(self))then - if(self.draw)then - if(self.drag)and(self.frame==nil)then - self.parent.clear() - end - self.fWindow.clear() - if(self.barActive)then - self.fWindow.setBackgroundColor(self.titlebgcolor) - self.fWindow.setTextColor(self.titlefgcolor) - self.fWindow.setCursorPos(1,1) - self.fWindow.write(getTextHorizontalAlign(self.title,self.w,self.horizontalTextAlign)) - end - - for _,b in rpairs(self.objZKeys)do - for k,v in pairs(self.objects[b])do - if(v.draw~=nil)then - v:drawObject() - end - end - end - - --term.redirect(self.fWindow) - self.fWindow.setBackgroundColor(self.bgcolor) - self.fWindow.setTextColor(self.cursorColor or self.fgcolor) - self.fWindow.setVisible(true) - self.fWindow.redraw() - - if(self.focusedObject.cursorX~=nil)and(self.focusedObject.cursorY~=nil)then - self.fWindow.setCursorPos(self.focusedObject.cursorX, self.focusedObject.cursorY) - end - - if(self.focusedObject.__type=="Program")then - if not(self.focusedObject.process:isDead())then - self.cursorColor = self.focusedObject.pWindow.getTextColor() - term.redirect(self.focusedObject.pWindow) - self.focusedObject.pWindow.restoreCursor() - end - else - self.fWindow.setCursorBlink(self.cursorBlink) - end - if(self.focusedObject.__type=="Frame")then - term.redirect(self.focusedObject.fWindow) - self.focusedObject.fWindow.restoreCursor() - end - end - end -end - -function frame:mouseEvent(event,typ,x,y) -- internal mouse event, should make it local but as lazy as i am.. - local fx,fy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.drag)and(self.draw)then - if(event=="mouse_drag")then - local parentX=1;local parentY=1 - if(self.frame~=nil)then - parentX,parentY = self.frame:relativeToAbsolutePosition(self.frame:getAnchorPosition()) - end - self:setPosition(x+self.xToRem-(parentX-1)+self.frame.xOffset,y-(parentY-1)+self.frame.yOffset) - end - if(event=="mouse_up")then - self.drag = false - end - return true - end - - if(object.mouseEvent(self,event,typ,x,y))then - - if(x>fx+self.w-1)or(y>fy+self.h-1)then return end - - for _,b in pairs(self.objZKeys)do - for _,v in rpairs(self.objects[b])do - if(v.draw~=false)then - if(v.__type=="Frame")then - v:removeFocusedElement() - end - end - end - end - - for _,b in pairs(self.objZKeys)do - for _,v in rpairs(self.objects[b])do - if(v.draw~=false)then - if(v:mouseEvent(event,typ,x,y))then - return true - end - end - end - end - if(self.isMoveable)then - 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 - end - if(fx<=x)and(fx+self.w>x)and(fy<=y)and(fy+self.h>y)then - self:removeFocusedElement() - return true - end - return false -end - -function frame:eventListener(event,p1,p2,p3,p4) - local keys = {} - local terminatingprogram = false - for k in pairs(self.objects)do - table.insert(keys,k) - end - for _,b in pairs(keys)do - for _,v in rpairs(self.objects[b])do - if(v.draw~=false)then - v:eventListener(event,p1,p2,p3,p4) - - if(v:isFocusedObject()and(v.__type=="Program"))then - terminatingprogram = true - end - end - end - end - --if(event=="terminate")then Basalt.debug(terminatingprogram) end -- kack buggy - if(event=="terminate")and(terminatingprogram == false)then - if(self.terminatedTime==nil)then self.terminatedTime = 0 end - if(self.terminatedTime+5<=os.clock())then - --if("asd"=="b")then - Basalt.stopUpdate() - for k,v in pairs(_frames)do - v:hide() - end - term.redirect(parentTerminal) - term.setCursorPos(1,1) - term.clear() - --end - end - end -end - -function frame:keyEvent(event,key)-- internal key event, should make it local but as lazy i am.. - for _,b in pairs(self.objects)do - for _,v in pairs(b)do - if(v.draw~=false)then - if(v:keyEvent(event,key))then - return true - end - end - end - end - return false -end - -function frame:onScrollEvent(scrollbar) - if(scrollbar.name == self.name.."__generatedVScrollbar")then - self.yOffset = round((scrollbar.index-1) * scrollbar:getLowestValue()) - if(self.yOffset<0)then self.yOffset = 0 end - end - if(scrollbar.name == self.name.."__generatedHScrollbar")then - self.xOffset = round((scrollbar.index-1) * scrollbar:getLowestValue()) - if(self.xOffset<0)then self.xOffset = 0 end - end -end - -function frame:createScrollbar(typ, val) - if(typ=="horizontal")then - if(self.horizontalScrollbar==nil)then - self.horizontalScrollbar = self:addScrollbar(self.name.."__generatedHScrollbar"):setAnchor("bottom"):setSize(self.w,1):setBarType("horizontal") - self.horizontalScrollbar:onChange(function(self) self.frame.onScrollEvent(self.frame,self.frame.horizontalScrollbar) end) - self.horizontalScrollbar:setZIndex(15) - self.maxXOffset = val or 10 - self.horizontalScrollbar:ignoreScroll(true,true):setSymbolSize(self.w-self.maxXOffset >= 1 and self.w-self.maxXOffset or 1 ) - if(self.verticalScrollBar~=nil)and(self.verticalScrollBar.name==self.name.."__generatedVScrollbar")then - self.horizontalScrollbar:setSize(self.w-1,1) - end - end - else - if(self.verticalScrollBar==nil)then - self.verticalScrollBar = self:addScrollbar(self.name.."__generatedVScrollbar"):setAnchor("right"):setSize(1,self.h) - self.verticalScrollBar:onChange(function(self) self.frame.onScrollEvent(self.frame,self.frame.verticalScrollBar) end) - self.verticalScrollBar:setZIndex(15) - self.maxYOffset = val or 10 - self.verticalScrollBar:setMaxValue(self.maxYOffset) - self.verticalScrollBar:ignoreScroll(true,true):setSymbolSize(self.h-self.maxYOffset >= 1 and self.h-self.maxYOffset or 1 ) - if(self.horizontalScrollbar~=nil)and(self.horizontalScrollbar.name==self.name.."__generatedHScrollbar")then - self.horizontalScrollbar:setSize(self.w-1,1) - end - end - end - return self -end - -function frame:setMaxOffset(typ, val) - if(typ=="horizontal")then - if(self.horizontalScrollbar==nil)then - self.maxXOffset = val or 10 - self.horizontalScrollbar:setSymbolSize(self.w-self.maxXOffset >= 1 and self.w-self.maxXOffset or 1 ) - end - end - if(typ=="vertical")then - if(self.verticalScrollBar==nil)then - self.maxYOffset = val or 10 - self.verticalScrollBar:setSymbolSize(self.h-self.maxYOffset >= 1 and self.h-self.maxYOffset or 1 ) - end - end - return self -end - -function frame:showScrollbar(typ) - if(typ=="horizontal")then - self.horizontalScrollbar:show() - else - self.verticalScrollBar:show() - end - return self -end - -function frame:setCustomScrollbar(typ,bar) - if(bar~=nil)then - if(typ=="horizontal")then - if(self.horizontalScrollbar~=nil)and(self.horizontalScrollbar.name==self.name.."__generatedHScrollbar")then - self:removeObject(self.horizontalScrollbar) - end - self.horizontalScrollbar = bar - else - if(self.verticalScrollBar~=nil)and(self.verticalScrollBar.name==self.name.."__generatedVScrollbar")then - self:removeObject(self.verticalScrollBar) - end - self.verticalScrollBar = bar - end - end - return self -end - -function frame:getScrollbar(typ) - if(typ=="horizontal")then - return self.horizontalScrollbar - else - return self.verticalScrollBar - end -end - -function frame:hideScrollbar(typ) - if(typ=="horizontal")then - if(self.horizontalScrollbar~=nil)then - self.horizontalScrollbar:hide() - end - else - if(self.verticalScrollBar~=nil)then - self.verticalScrollBar:hide() - end - end - return self -end - -function frame:setCursorBlink(bool,color) - if(self.frame~=nil)then - --self.frame:setCursorBlink(bool) - end - self.cursorBlink = bool - self.cursorColor = color or self.fgcolor - return self -end - -function frame:changeZIndexOfObject(obj, zindex) - self:removeObject(obj) - obj.zIndex = zindex - self:addObject(obj) -end - -function frame:setFocusedElement(obj)-- you can set the focus of an element in a frame - 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 - return self -end - -function frame:removeFocusedElement()-- and here you can remove the focus - if(self.focusedObject.name~=nil)then - self.focusedObject:loseFocusEvent() - end - self.focusedObject = {} -end - -function frame:getFocusedElement()--gets the current focused element - return self.focusedObject -end - -function frame:loseFocusEvent()--event which gets fired when the frame lost the focus in this case i remove the cursor blink from the active input object - object.loseFocusEvent(self) - self.cursorBlink = false - self.fWindow.setCursorBlink(false) -end - -function frame:getFocusEvent()--event which gets fired when the frame gets the focus -local frameList = {} - for k,v in pairs(self.frame.objects[self.zIndex])do - if(self~=v)then - table.insert(frameList,v) - end - end - table.insert(frameList,self) - self.frame.objects[self.zIndex] = frameList -end - - -function frame:setMoveable(mv)--you can make the frame moveable (Todo: i want to make all objects moveable, so i can create a ingame gui editor MUHUHHUH) - self.isMoveable = mv - return self; -end ---Frames end - - ---Timer object -function frame:addTimer(name)--adds the timer object - 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)--tobecontinued - self.timer = timer - if(repeats==nil)then repeats = -1 end - 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:updateVisuals() - 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.value)then - self.frame.fWindow.write(self.symbol) - else - self.frame.fWindow.write(" ") - end - end -end - -function checkbox:mouseEvent(event,typ,x,y) -- we have to switch the order of object.mouseEvent with checkbox:mouseEvent, because the value should be changed before we call user click events - local vx,vy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(vx<=x)and(vx+self.w>x)and(vy<=y)and(vy+self.h>y)then - if(event=="mouse_click")then - self:setValue(not self.value) - end - end - if(object.mouseEvent(self,event,typ,x,y))then return true end - return false -end ---Checkbox end - ---Radio object -function frame:addRadio(name) - if(self:getObject(name) == nil)then - local obj = radio:new() - obj.name = name;obj.frame=self; - obj.bgcolor = self.bgcolor - obj.fgcolor = self.fgcolor - obj.symbolBGColor = self.bgcolor - obj.symbolFGColor = self.fgcolor - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function radio:setSymbol(symbol) - self.symbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function radio:setSymbolForegroundColor(color) - self.symbolFGColor = color - self:updateVisuals() - return self -end - -function radio:setSymbolBackgroundColor(color) - self.symbolBGColor = color - self:updateVisuals() - return self -end - -function radio:addItem(text,x,y,bgcolor,fgcolor,...) - if(x==nil)or(y==nil)then - table.insert(self.items,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor),x=0,y=#self.items,vars=table.pack(...)}) - else - table.insert(self.items,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor),x=x,y=y,vars=table.pack(...)}) - end - if(#self.items==1)then - self:setValue(self.items[1]) - end - return self -end - -function radio:removeItem(item) - if(type(item)=="table")then - for k,v in pairs(self.items)do - if(v==item)then - table.remove(self.items,k) - break; - end - end - elseif(type(item)=="number")then - if(self.items[item]~=nil)then - table.remove(self.items,item) - end - end - return self -end - -function radio:mouseEvent(event,typ,x,y) - if(#self.items>0)then - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - for _,v in pairs(self.items)do - if(dx<=x)and(dx+v.x+string.len(v.text)+1>x)and(dy+v.y==y)then - if(event=="mouse_click")and(typ==1)then self:setValue(v) end - if(self.frame~=nil)then self.frame:setFocusedElement(self) end - if(event=="mouse_click")then - if(self.clickFunc~=nil)then - callAll(self.clickFunc,self,event,typ,x,y) - end - elseif(event=="mouse_up")then - if(self.upFunc~=nil)then - callAll(self.upFunc,self,event,typ,x,y) - end - elseif(event=="mouse_drag")then - if(self.dragFunc~=nil)then - callAll(self.dragFunc,self,event,typ,x,y) - end - end - return true - end - end - end - return false -end - -function radio:drawObject() - object.drawObject(self) -- Base class - if(self.draw)then - if(#self.items>0)then - for _,v in ipairs(self.items)do - local objx, objy = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(v.bgcolor) - self.frame.fWindow.setTextColor(v.fgcolor) - self.frame.fWindow.setCursorPos(objx+v.x,objy+v.y) - if(v==self.value)then - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(self.symbolBGColor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(self.symbolFGColor) end - self.frame.fWindow.write(self.symbol) - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(v.bgcolor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(v.fgcolor) end - self.frame.fWindow.write(v.text) - else - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(self.symbolBGColor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(self.symbolFGColor) end - self.frame.fWindow.write(" ") - if(self.symbolBGColor~=nil)then self.frame.fWindow.setBackgroundColor(v.bgcolor) end - if(self.symbolFGColor~=nil)then self.frame.fWindow.setTextColor(v.fgcolor) end - self.frame.fWindow.write(v.text) - end - end - end - end -end ---Radio 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) - self:setValue(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(tostring(self.value):sub(1,self.w)) - 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:setInputType(typ) - self.iType = typ - self:updateVisuals() - return self -end - -function input:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - local anchX,anchY = self:getAnchorPosition() - self.frame.fWindow.setCursorPos(anchX+(string.len(self.value) < self.w-1 and string.len(self.value) or self.w-1),anchY) - self.cursorX = anchX+(string.len(self.value) < self.w-1 and string.len(self.value) or self.w-1) - self.cursorY = anchY - self.frame.fWindow.setCursorBlink(true) - return true - end - return false -end - -function input:getValue() - if(self.iType=="number")then - if(tonumber(self.value)~=nil)then - return tonumber(self.value) - else - self:setValue(0) - return 0 - end - end - return self.value -end - -function input:keyEvent(event,key) - if(self:isFocusedObject())then - if(self.draw)then - if(event=="key")then - if(key==259)then - self:setValue(string.sub(self.value,1,string.len(self.value)-1)) - end - if(key==257)then -- on enter - if(self.inputActive)then - self.inputActive = false - self.fWindow.setCursorBlink(false) - end - end - end - if(event=="char")then - if(self.iType=="number")then - local cache = self.value - if (key==".")or(tonumber(key)~=nil)then - self:setValue(self.value..key) - end - if(tonumber(self.value)==nil)then - self:setValue(cache) - end - else - self:setValue(self.value..key) - end - end - local anchX,anchY = self:getAnchorPosition() - self.cursorX = anchX+(string.len(self.value) < self.w and string.len(self.value) or self.w-1) - self.cursorY = anchY - if(self.changeFunc~=nil)then - self.changeFunc(self.acveInput) - end - end - end -end - -function input:drawObject() - object.drawObject(self) -- Base class - local text = "" - if(self.draw)then - if(string.len(self.value)>=self.w)then - text = string.sub(self.value, string.len(self.value)-self.w+2, string.len(self.value)) - if(self.iType=="password")then - text = string.sub(string.rep("*",self.value:len()), string.len(self.value)-self.w+2, string.len(self.value)) - else - text = string.sub(self.value, string.len(self.value)-self.w+2, string.len(self.value)) - end - else - if(self.iType=="password")then - text = string.rep("*",self.value:len()) - else - text = self.value - end - - 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) - end -end - -function input:getFocusEvent() - if(object.getFocusEvent(self))then - self.frame:setCursorBlink(true,self.fgcolor) - self:updateVisuals() - end -end - -function input:loseFocusEvent() - if(object.loseFocusEvent(self))then - if(self.iType=="number")then - if(tonumber(self.value)==nil)then - self:setValue(0) - end - end - self.frame:setCursorBlink(false) - self:updateVisuals() - end -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.value, self.w, self.horizontalTextAlign)) - else - self.frame.fWindow.write(string.rep(" ", self.w)) - end - end - end -end - -function button:setText(text) - return self:setValue(text) -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:addItem(text,bgcolor,fgcolor,...) - table.insert(self.items,{text=text,bgcolor=(bgcolor ~= nil and bgcolor or self.bgcolor),fgcolor=(fgcolor ~= nil and fgcolor or self.fgcolor),vars=...}) - if(#self.items==1)then - self:setValue(self.items[1]) - end - return self -end - -function dropdown:removeItem(item) - if(type(item)=="table")then - for k,v in pairs(self.items)do - if(v==item)then - table.remove(self.items,k) - break; - end - end - elseif(type(item)=="number")then - if(self.items[item]~=nil)then - table.remove(self.items,item) - end - end - return self -end - -function dropdown:setActiveItemBackground(color) - self.activeItemBackground = color - self:updateVisuals() - return self -end - -function dropdown:setActiveItemForeground(color) - self.activeItemForeground = color - self:updateVisuals() - return self -end - -function dropdown:setItemColors(...) - self.itemColors = table.pack(...) - self.itemColorIndex = 1 - self:updateVisuals() - return self -end - -function dropdown:setItemTextColors(...) - self.itemTextColors = table.pack(...) - self.itemTextColorIndex = 1 - self:updateVisuals() - 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.value.bgcolor) - self.frame.fWindow.setTextColor(self.value.fgcolor) - self.frame.fWindow.write(getTextHorizontalAlign(self.value.text, self.w, self.horizontalTextAlign)) - - if(self:isFocusedObject())then - if(#self.items>0)then - self.itemColorIndex = 1 - self.itemTextColorIndex = 1 - local index = 1 - for _,v in ipairs(self.items)do - local objx, objy = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(v.bgcolor) - if(self.itemColors~=nil)then - if(#self.itemColors>0)then - self.frame.fWindow.setBackgroundColor(self.itemColors[self.itemColorIndex]) - self.itemColorIndex = self.itemColorIndex + 1 - if(self.itemColorIndex>#self.itemColors)then - self.itemColorIndex = 1 - end - end - end - if(self.itemTextColors~=nil)then - if(#self.itemTextColors>0)then - self.frame.fWindow.setTextColor(self.itemTextColors[self.itemTextColorIndex]) - self.itemTextColorIndex = self.itemTextColorIndex + 1 - if(self.itemTextColorIndex>#self.itemTextColors)then - self.itemTextColorIndex = 1 - end - end - end - if(v==self.value)then - if(self.activeItemBackground~=nil)then - self.frame.fWindow.setBackgroundColor(self.activeItemBackground) - end - if(self.activeItemForeground~=nil)then - self.frame.fWindow.setTextColor(self.activeItemForeground) - end - end - 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 - end -end - -function dropdown:mouseEvent(event,typ,x,y) - object.mouseEvent(self,event,typ,x,y) - if(self:isFocusedObject())then - if(#self.items>0)then - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - local index = 1 - for _,b in pairs(self.items)do - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - if(event=="mouse_click")and(typ==1)then self:setValue(b) end - if(self.changeFunc~=nil)then - self.changeFunc(self) - end - self.frame:removeFocusedElement() - 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 - self.frame:removeFocusedElement() - 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.colorIndex = 1 - self.textColorIndex = 1 - for index=0,self.h-1 do - self.frame.fWindow.setCursorPos(self:getAnchorPosition(self.x,self.y+index)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - - if(self.items[index+self.index]~=nil)then - local bgCol = self.items[index+self.index].bgcolor or self.itemColors[self.colorIndex] - local fgCol = self.items[index+self.index].fgcolor or self.itemTextColors[self.textColorIndex] - if(self.items[index+self.index].bgcolor == nil)then self.colorIndex = self.colorIndex+1 end - if(self.items[index+self.index].fgcolor == nil)then self.textColorIndex = self.textColorIndex+1 end - if(self.colorIndex>#self.itemColors)then self.colorIndex = 1 end - if(self.textColorIndex>#self.itemTextColors)then self.textColorIndex = 1 end - self.frame.fWindow.setBackgroundColor(bgCol) - self.frame.fWindow.setTextColor(fgCol) - if(self.items[index+self.index]==self.value)then - if(self.activeItemBackground~=nil)then self.frame.fWindow.setBackgroundColor(self.activeItemBackground) end - if(self.activeItemForeground~=nil)then self.frame.fWindow.setTextColor(self.activeItemForeground) end - self.frame.fWindow.write(self.symbol..getTextHorizontalAlign(self.items[index+self.index].text, self.w-string.len(self.symbol), self.horizontalTextAlign)) - else - self.frame.fWindow.write(string.rep(" ", string.len(self.symbol))..getTextHorizontalAlign(self.items[index+self.index].text, self.w-string.len(self.symbol), self.horizontalTextAlign)) - end - else - self.frame.fWindow.write(getTextHorizontalAlign(" ", self.w, self.horizontalTextAlign)) - end - end - end -end - -function list:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw - if(typ==1)then - if(#self.items>0)then - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - for index=0,self.h do - if(self.items[index+self.index]~=nil)then - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - self:setValue(self.items[index+self.index]) - self:updateVisuals() - return true - end - end - end - end - end - end - if(event=="mouse_scroll")then - self.index = self.index+typ - if(self.index<1)then self.index = 1 end - if(typ==1)then - if(#self.items>self.h)then - if(self.index>#self.items+1-self.h)then - self.index = #self.items+1-self.h - end - else - self.index = self.index-1 - end - end - self:updateVisuals() - return true - end - end - return false -end - -function list:onScrollbarChangeEvent(scrollbar) - --self.index = (scrollbar.value/(scrollbar.maxValue/(scrollbar.barType=="vertical" and scrollbar.h or scrollbar.w))) - self.index = math.floor(scrollbar.value) - if(self.index<1)then self.index = 1 end - if(self.index>#self.items+1-self.h)then self.index = #self.items+1-self.h end -end - -function list:addScrollbar(obj) - if(obj.__type=="Scrollbar")then - self.scrollbar = obj - self.scrollbar:setMaxValue(#self.items+1-self.h) - self.scrollbar.args = self - self.scrollbar:onChange(function(scrlb,lst) lst:onScrollbarChangeEvent(scrlb) end) - end - return self -end - -function list:addItem(text,bgcolor,fgcolor,...) - table.insert(self.items,{text=text,bgcolor=bgcolor,fgcolor=fgcolor,vars=...}) - if(#self.items==1)then - self:setValue(self.items[1]) - end - if(self.scrollbar~=nil)then - self.scrollbar:setMaxValue(#self.items-self.h) - end - return self -end - -function list:setItemColors(...) - self.itemColors = table.pack(...) - self:updateVisuals() - return self -end - -function list:setItemTextColors(...) - self.itemTextColors = table.pack(...) - self:updateVisuals() - return self -end - -function list:setIndex(index) - self.index = index - self:updateVisuals() - return self -end - -function list:removeItem(item) - if(type(item)=="table")then - for k,v in pairs(self.items)do - if(v==item)then - table.remove(self.items,k) - break; - end - end - elseif(type(item)=="number")then - if(self.items[item]~=nil)then - table.remove(self.items,item) - end - end - - if(self.scrollbar~=nil)then - self.scrollbar:setMaxValue(#self.items-self.h) - end - return self -end - -function list:setSymbol(symbol) - self.symbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function list:setActiveItemBackground(color) - self.activeItemBackground = color - self:updateVisuals() - return self -end - -function list:setActiveItemForeground(color) - self.activeItemForeground = color - self:updateVisuals() - return self -end - -function frame:addTextfield(name) - if(self:getObject(name) == nil)then - local obj = textfield:new() - obj.name = name;obj.frame=self; - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function textfield:keyEvent(event,key) - if(self:isFocusedObject())then - if(self.draw)then - local anchX,anchY = self:getAnchorPosition() - if(event=="key")then - if(key==259)then -- on backspace - if(self.lines[self.textY]=="")then - if(self.textY>1)then - table.remove(self.lines,self.textY) - self.textX = self.lines[self.textY-1]:len()+1 - self.wIndex = self.textX-self.w+1 - if(self.wIndex<1)then self.wIndex = 1 end - self.textY = self.textY-1 - end - elseif(self.textX<=1)then - if(self.textY>1)then - self.textX = self.lines[self.textY-1]:len()+1 - self.wIndex = self.textX-self.w+1 - if(self.wIndex<1)then self.wIndex = 1 end - self.lines[self.textY-1] = self.lines[self.textY-1]..self.lines[self.textY] - table.remove(self.lines,self.textY) - self.textY = self.textY-1 - end - else - self.lines[self.textY] = self.lines[self.textY]:sub(1,self.textX-2)..self.lines[self.textY]:sub(self.textX,self.lines[self.textY]:len()) - if(self.textX>1)then self.textX = self.textX-1 end - if(self.wIndex>1)then - if(self.textX=self.h)then - self.hIndex = self.hIndex+1 - end - end - if(key==258)then -- on tab - - --self.lines[self.textY] = self.lines[self.textY]..string.rep(" ",self.w-(self.w-self.lines[self.textY]:len())) - end - if(key==265)then -- arrow up - if(self.textY>1)then - self.textY = self.textY-1 - if(self.textX>self.lines[self.textY]:len()+1)then self.textX = self.lines[self.textY]:len()+1 end - if(self.wIndex>1)then - if(self.textX1)then - if(self.textYself.lines[self.textY]:len()+1)then self.textX = self.lines[self.textY]:len()+1 end - - if(self.textY>=self.hIndex+self.h)then - self.hIndex = self.hIndex+1 - end - end - end - if(key==262)then -- arrow right - self.textX = self.textX+1 - if(self.textY<#self.lines)then - if(self.textX>self.lines[self.textY]:len()+1)then - self.textX = 1 - self.textY = self.textY+1 - end - elseif(self.textX > self.lines[self.textY]:len())then - self.textX = self.lines[self.textY]:len()+1 - end - if(self.textX<1)then self.textX = 1 end - if(self.textX=self.w+self.wIndex)then - self.wIndex = self.textX-self.w+1 - end - if(self.wIndex<1)then self.wIndex = 1 end - - end - if(key==263)then -- arrow left - self.textX = self.textX-1 - if(self.textX>=1)then - if(self.textX=self.w+self.wIndex)then - self.wIndex = self.textX+1 - end - end - if(self.textY>1)then - if(self.textX<1)then - self.textY = self.textY-1 - self.textX = self.lines[self.textY]:len()+1 - self.wIndex = self.textX-self.w+1 - end - end - if(self.textX<1)then self.textX = 1 end - if(self.wIndex<1)then self.wIndex = 1 end - end - end - if(event=="char")then - self.lines[self.textY] = self.lines[self.textY]:sub(1,self.textX-1)..key..self.lines[self.textY]:sub(self.textX,self.lines[self.textY]:len()) - self.textX = self.textX+1 - if(self.textX>=self.w+self.wIndex)then self.wIndex = self.wIndex+1 end - end - self.cursorX = anchX+(self.textX <= self.lines[self.textY]:len() and self.textX-1 or self.lines[self.textY]:len())-(self.wIndex-1) - if(self.cursorX>self.x+self.w-1)then self.cursorX = self.x+self.w-1 end - self.cursorY = anchY+(self.textY-self.hIndex < self.h and self.textY-self.hIndex or self.textY-self.hIndex-1) - self:updateVisuals() - if(self.changeFunc~=nil)then - callAll(self.changeFunc) - end - end - end -end - -function textfield:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")then - local anchX,anchY = self:getAnchorPosition() - local absX,absY = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.lines[y-absY+self.hIndex]~=nil)then - self.textX = x-absX+self.wIndex - self.textY = y-absY+self.hIndex - if(self.textX>self.lines[self.textY]:len())then - self.textX = self.lines[self.textY]:len()+1 - end - if(self.textX=#self.lines-self.h)then self.hIndex = #self.lines-self.h end - self:updateVisuals() - end - return true - end - return false -end - -function textfield:drawObject() - if(object.drawObject(self))then - for index=0,self.h-1 do - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.setTextColor(self.fgcolor) - local text = "" - if(self.lines[index+self.hIndex]~=nil)then - text = self.lines[index+self.hIndex] - end - text = text:sub(self.wIndex, self.w+self.wIndex-1) - local n = self.w-text:len() - if(n<0)then n = 0 end - text = text..string.rep(" ", n) - - self.frame.fWindow.setCursorPos(self:getAnchorPosition(self.x,self.y+index)) - self.frame.fWindow.write(text) - end - if(self.cursorX==nil)or(self.cursorXself.x+self.w)then self.cursorX = self.x end - if(self.cursorY==nil)or(self.cursorYself.y+self.h)then self.cursorY = self.y end - self.frame.fWindow.setCursorPos(self.cursorX,self.cursorY) - end -end - - -function textfield:getFocusEvent() - if(object.getFocusEvent(self))then - self.frame:setCursorBlink(true) - self:updateVisuals() - end -end - -function textfield:loseFocusEvent() - if(object.loseFocusEvent(self))then - self.frame:setCursorBlink(false) - self:updateVisuals() - end -end - - - - -function frame:addScrollbar(name) - if(self:getObject(name) == nil)then - local obj = scrollbar:new() - obj.name = name;obj.frame=self; - obj.maxValue = obj.h - obj.value = obj.maxValue/obj.h - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function scrollbar:setSize(w,h) - object.setSize(self,w,h) - if(self.barType=="vertical")then - self.maxValue = self.h - self.value = self.maxValue/self.h - elseif(self.barType=="horizontal")then - self.maxValue = self.w - self.value = self.maxValue/self.w - end - return self -end - -function scrollbar:getIndex() - return self.index -end - -function scrollbar:setIndex(index) - self.index = index - if(self.index<1)then self.index = 1 end - if(self.index>(self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1))then self.index = (self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1) end - self:setValue(self.index-1 * (self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))-(self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))) - return self -end - -function scrollbar:drawObject() - if(object.drawObject(self))then - local x,y = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.setTextColor(self.fgcolor) - if(self.barType=="vertical")then - for curIndex=1,self.h do - self.frame.fWindow.setCursorPos(x,y+curIndex-1) - if(self.index==curIndex)then - for curIndexOffset=0,self.symbolSize-1 do - self.frame.fWindow.setCursorPos(x,y+curIndex-1+curIndexOffset) - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(string.rep(self.symbol,self.w)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - end - else - if(curIndexself.index-1+self.symbolSize)then - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w)) - end - end - end - end - if(self.barType=="horizontal")then - for curIndex=1,self.h do - self.frame.fWindow.setCursorPos(x,y+curIndex-1) - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w-(self.w-(self.index-1)))) - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(string.rep(self.symbol,self.symbolSize)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w-(self.index+(self.symbolSize-1)))) - end - end - end -end - -function scrollbar:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.barType=="vertical")then - for index=0,self.h-1 do - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - if(index <= self.h-self.symbolSize)then - self.index = index+1 - else - self.index = self.h-(self.symbolSize-1) - end - self:setValue(self.index-1 * (self.maxValue/(self.h-(self.symbolSize-1)))-(self.maxValue/(self.h-(self.symbolSize-1)))) - self:updateVisuals() - end - end - end - if(self.barType=="horizontal")then - for index=0,self.w-1 do - if(dx+index==x)and(dy<=y)and(dy+self.y>y)then - if(index <= self.w-self.symbolSize)then - self.index = index+1 - else - self.index = self.w-(self.symbolSize-1) - end - self:setValue(self.index-1 * (self.maxValue/(self.w-(self.symbolSize-1)))-(self.maxValue/(self.w-(self.symbolSize-1)))) - self:updateVisuals() - end - end - end - end - if(event=="mouse_scroll")then - self.index = self.index+typ - if(self.index<1)then self.index = 1 end - if(self.index>(self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1))then self.index = (self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1) end - - self:setValue(self.index-1 * (self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))-(self.maxValue/((self.barType=="vertical" and self.h or self.w)-(self.symbolSize-1)))) - self:updateVisuals() - end - return true - end -end - -function scrollbar:setSymbol(symbol) - self.symbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function scrollbar:setSymbolSize(size) - self.symbolSize = tonumber(size) or 1 - if(self.barType=="vertical")then - self:setValue(self.index-1 * (self.maxValue/(self.h-(self.symbolSize-1)))-(self.maxValue/(self.h-(self.symbolSize-1)))) - elseif(self.barType=="horizontal")then - self:setValue(self.index-1 * (self.maxValue/(self.w-(self.symbolSize-1)))-(self.maxValue/(self.w-(self.symbolSize-1)))) - end - self:updateVisuals() - return self -end - -function scrollbar:setBackgroundSymbol(symbol) - self.bgSymbol = string.sub(symbol,1,1) - self:updateVisuals() - return self -end - -function scrollbar:setMaxValue(val) - self.maxValue = val - if(self.barType=="vertical")then - self:setValue(self.index-1 * (self.maxValue/(self.h-(self.symbolSize-1)))-(self.maxValue/(self.h-(self.symbolSize-1)))) - elseif(self.barType=="horizontal")then - self:setValue(self.index-1 * (self.maxValue/(self.w-(self.symbolSize-1)))-(self.maxValue/(self.w-(self.symbolSize-1)))) - end - self:updateVisuals() - return self -end - -function scrollbar:getLowestValue() - if(self.barType=="vertical")then - return self.maxValue/(self.h-(self.symbolSize-1)) - elseif(self.barType=="horizontal")then - return self.maxValue/(self.w-(self.symbolSize-1)) - end - return self -end - -function scrollbar:setSymbolColor(color) - self.symbolColor = color - self:updateVisuals() - return self -end - -function scrollbar:setBarType(typ) - self.barType = typ:lower() - self:updateVisuals() - return self -end - -function scrollbar:setBarSize(typ) - self.barSize = typ:lower() - self:updateVisuals() - return self -end - -function frame:addSlider(name) - if(self:getObject(name) == nil)then - local obj = slider:new() - obj.name = name;obj.frame=self; - obj.maxValue = obj.h - obj.value = obj.maxValue/obj.h - self:addObject(obj) - return obj; - else - return nil, "id "..name.." already exists"; - end -end - -function slider:setSize(w,h) - object.setSize(self,w,h) - if(self.barType=="vertical")then - self.maxValue = self.h - self.value = self.maxValue/self.h - elseif(self.barType=="horizontal")then - self.maxValue = self.w - self.value = self.maxValue/self.w - end - return self -end - -function slider:drawObject() - if(object.drawObject(self))then -- Base class - local x,y = self:getAnchorPosition() - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.setTextColor(self.fgcolor) - if(self.barType=="vertical")then - for curPos=0,self.h-1 do - self.frame.fWindow.setCursorPos(x,y+curPos) - if(tostring(self.maxValue/self.h*(curPos+1))==tostring(self.value))then - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(string.rep(self.symbol,self.w)) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - else - self.frame.fWindow.write(string.rep(self.bgSymbol,self.w)) - end - end - end - if(self.barType=="horizontal")then - for curPos=0,self.h-1 do - self.frame.fWindow.setCursorPos(x,y+curPos) - self.frame.fWindow.write(string.rep(self.bgSymbol,(self.value/(self.maxValue/self.w))-1)) - self.frame.fWindow.setBackgroundColor(self.symbolColor) - self.frame.fWindow.write(self.symbol) - self.frame.fWindow.setBackgroundColor(self.bgcolor) - self.frame.fWindow.write(string.rep(self.bgSymbol,self.maxValue/(self.maxValue/self.w)-(self.value/(self.maxValue/self.w)))) - end - end - end -end - -function slider:mouseEvent(event,typ,x,y) - if(object.mouseEvent(self,event,typ,x,y))then - if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw - local dx,dy = self:relativeToAbsolutePosition(self:getAnchorPosition()) - if(self.barType=="vertical")then - for index=0,self.h-1 do - if(dx<=x)and(dx+self.w>x)and(dy+index==y)then - self:setValue(self.maxValue/self.h*(index+1)) - self:updateVisuals() - end - end - end - if(self.barType=="horizontal")then - for index=0,self.w-1 do - if(dx+index==x)and(dy<=y)and(dy+self.y>y)then - self:setValue(self.maxValue/self.w*(index+1)) - self:updateVisuals() - end - end - end - end - if(event=="mouse_scroll")then - self:setValue(self.value + (self.maxValue/(self.barType=="vertical" and self.h or self.w))*typ) - self:updateVisuals() - end - if(self.value>self.maxValue)then self:setValue(self.maxValue) end - if(self.value0)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 - else - self.playing = false - self.index = 1 - end - end - end -end - -function animation:play(infiniteloop) - if(infiniteloop~=nil)then self.infiniteloop=infiniteloop end - self.playing = true - 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 - end - return self -end - -function animation:cancel() - os.cancelTimer(self.timeObj) - self.playing = false - self.infiniteloop = false - self.index = 1 - return self -end ------------ - - -local function checkTimer(timeObject) - for a,b in pairs(activeFrame.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 - if(v.__type=="Animation")and(v.playing)then - if(v.timeObj == timeObject)then - v:onPlay() - end - end - end - end -end - - -local function handleObjectDrawing() -local changed = false - for k,v in pairs(activeFrame.objects)do - for a,b in pairs(v)do - if(b.changed)then - changed = true - end - end - end - if(changed)then - activeFrame:drawObject() - end -end - -if(Basalt.debugger)then - Basalt.debugFrame = Basalt.createFrame("BasaltDebuggingFrame"):showBar():setBackground(colors.lightGray):setTitle("Debug",colors.black,colors.gray) - Basalt.debugList = Basalt.debugFrame:addList("debugList"):setSize(Basalt.debugFrame.w - 2, Basalt.debugFrame.h - 3):setPosition(2,3):setSymbol(""):setBackground(colors.gray):setItemColors(colors.gray):setTextAlign("left"):show() - Basalt.debugFrame:addButton("back"):setAnchor("right"):setSize(1,1):setText("\22"):onClick(function() Basalt.oldFrame:show() end):setBackground(colors.red):show() - Basalt.debugLabel = Basalt.debugFrame:addLabel("debugLabel"):onClick(function() Basalt.oldFrame = activeFrame Basalt.debugFrame:show() end):setBackground(colors.black):setForeground(colors.white):setAnchor("bottom"):ignoreScroll(true,true):show() -end - -function Basalt.startUpdate() - if not(Basalt.updater)then - handleObjectDrawing() - Basalt.updater = true - while Basalt.updater do - local event, p1,p2,p3,p4 = os.pullEventRaw() - activeFrame:eventListener(event,p1,p2,p3,p4) - if(event=="mouse_click")or(event=="mouse_scroll")or(event=="mouse_drag")or(event=="mouse_up")then - activeFrame:mouseEvent(event,p1,p2,p3) - end - if(event=="timer")then - checkTimer(p1) - end - if(event=="char")or(event=="key")then - activeFrame:keyEvent(event,p1) - keyModifier[p1] = true - end - if(event=="key_up")then - activeFrame:keyEvent(event,p1) - keyModifier[p1] = false - end - handleObjectDrawing() - end - end -end - -function Basalt.stopUpdate() - Basalt.updater = false -end - -if(Basalt.debugger)then - function Basalt.debug(...) - local args = {...} - if(activeFrame.name~="BasaltDebuggingFrame")then - if(activeFrame~=Basalt.debugLabel.frame)then - Basalt.debugLabel:setParent(activeFrame) - end - end - local str = "" - for k,v in pairs(args)do - str = str..tostring(v)..(#args~=k and ", " or "") - end - Basalt.debugLabel:setText("[Debug] "..str) - Basalt.debugList:addItem(str) - if(#Basalt.debugList.items>Basalt.debugList.h)then Basalt.debugList:removeItem(1) end - - Basalt.debugLabel:show() - end - -end - -function Basalt.getFrame(name) - return _frames[name]; -end - -function Basalt.getActiveFrame() - if(activeFrame.name=="BasaltDebuggingFrame")then - return oldFrame - end - return activeFrame -end - -return Basalt; \ No newline at end of file diff --git a/basalt_full.lua b/basalt_full.lua new file mode 100644 index 0000000..402204c --- /dev/null +++ b/basalt_full.lua @@ -0,0 +1,3008 @@ +local theme = { + basaltBG = colors.lightGray, + basaltFG = colors.black, + FrameBG = colors.gray, + FrameFG = colors.black, + ButtonBG = colors.gray, + ButtonFG = colors.black, + CheckboxBG = colors.gray, + CheckboxFG = colors.black, + InputBG = colors.gray, + InputFG = colors.black, + textfieldBG = colors.gray, + textfieldFG = colors.black, + listBG = colors.gray, + listFG = colors.black, + dropdownBG = colors.gray, + dropdownFG = colors.black, + radioBG = colors.gray, + radioFG = colors.black, + selectionBG = colors.black, + selectionFG = colors.lightGray, +} + +local basalt = {debugger=true} +local activeFrame + +local animationQueue = {} +local keyModifier = {} +local parentTerminal = term.current() + +local sub = string.sub + +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 = math.ceil(h / 2) + if(offset<1)then offset = 1 end + 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 tHex = { -- copy paste is a very important feature everyone should make use of + [ colors.white ] = "0", + [ colors.orange ] = "1", + [ colors.magenta ] = "2", + [ colors.lightBlue ] = "3", + [ colors.yellow ] = "4", + [ colors.lime ] = "5", + [ colors.pink ] = "6", + [ colors.gray ] = "7", + [ colors.lightGray ] = "8", + [ colors.cyan ] = "9", + [ colors.purple ] = "a", + [ colors.blue ] = "b", + [ colors.brown ] = "c", + [ colors.green ] = "d", + [ colors.red ] = "e", + [ colors.black ] = "f", +} + +local function basaltDrawHelper() + local terminal = parentTerminal + local w,h = terminal.getSize() + local cacheT = {} + local cacheBG = {} + local cacheFG = {} + + local _cacheT = {} + local _cacheBG = {} + local _cacheFG = {} + + local emptySpaceLine + local emptyColorLines = {} + + local function createEmptyLines() + emptySpaceLine = (" "):rep(w) + for n=0,15 do + local nColor = 2^n + local sHex = tHex[nColor] + emptyColorLines[nColor] = sHex:rep(w) + end + end + ---- + createEmptyLines() + + local function recreateWindowArray() + local emptyText = emptySpaceLine + local emptyFG = emptyColorLines[colors.white] + local emptyBG = emptyColorLines[colors.black] + for n=1,h do + cacheT[n] = sub(cacheT[n] == nil and emptyText or cacheT[n]..emptyText:sub(1,w-cacheT[n]:len()),1,w) + cacheFG[n] = sub(cacheFG[n] == nil and emptyFG or cacheFG[n]..emptyFG:sub(1,w-cacheFG[n]:len()),1,w) + cacheBG[n] = sub(cacheBG[n] == nil and emptyBG or cacheBG[n]..emptyBG:sub(1,w-cacheBG[n]:len()),1,w) + end + end + recreateWindowArray() + + local function setText(x,y,text) + local gText = cacheT[y] + if(y>=1)and(y<=h)then + if(x>=1)then + cacheT[y] = sub(gText:sub(1,x-1)..text..gText:sub(x+(text:len()),w),1, w) + else + cacheT[y] = sub(text:sub(math.abs(x) + 2, text:len())..gText:sub((text:len() - (math.abs(x))),w),1, w) + end + end + end + + local function setBG(x,y,colorStr) + local gBG = cacheBG[y] + if(y>=1)and(y<=h)then + if(x>=1)then + cacheBG[y] = sub(gBG:sub(1,x-1)..colorStr..gBG:sub(x+(colorStr:len()),w),1,w) + else + cacheBG[y] = sub(colorStr:sub(math.abs(x) + 2, colorStr:len())..gBG:sub((colorStr:len() - (math.abs(x))),w),1,w) + end + end + end + + local function setFG(x,y,colorStr) + local gFG = cacheFG[y] + if(y>=1)and(y<=h)then + if(x>=1)then + cacheFG[y] = sub(gFG:sub(1,x-1)..colorStr..gFG:sub(x+(colorStr:len()),w),1,w) + else + cacheFG[y] = sub(colorStr:sub(math.abs(x) + 2, colorStr:len())..gFG:sub((colorStr:len() - (math.abs(x))),w),1,w) + end + end + end + + local drawHelper = { + setBG = function(x,y,colorStr) + setBG(x,y,colorStr) + end; + + setText = function(x,y,text) + setText(x,y,text) + end; + + setFG = function(x,y,colorStr) + setFG(x,y,colorStr) + end; + + drawBackgroundBox = function (x, y, w, h, bgCol) + for n = 1, h do + setBG(x, y + (n-1), tHex[bgCol]:rep(w)) + end + end; + drawForegroundBox = function (x, y, w, h, fgCol) + for n = 1, h do + setFG(x, y + (n-1), tHex[fgCol]:rep(w)) + end + end; + drawTextBox = function (x, y, w, h, symbol) + for n = 1, h do + setText(x, y + (n-1), symbol:rep(w)) + end + end; + writeText = function (x, y, text, bgCol, fgCol) + bgCol = bgCol or terminal.getBackgroundColor() + fgCol = fgCol or terminal.getTextColor() + setText(x, y, text) + setBG(x, y, tHex[bgCol]:rep(text:len())) + setFG(x, y, tHex[fgCol]:rep(text:len())) + end; + + update = function () + local xC, yC = terminal.getCursorPos() + local isBlinking = terminal.getCursorBlink() + terminal.setCursorBlink(false) + for n=1, h do + terminal.setCursorPos(1, n) + terminal.blit(cacheT[n], cacheFG[n], cacheBG[n]) + end + terminal.setCursorBlink(isBlinking) + terminal.setCursorPos(xC, yC) + end; + + setTerm = function (newTerm) + terminal = newTerm; + end; + } + return drawHelper +end +local drawHelper = basaltDrawHelper() + +local function BasaltEvents() + + local events = {} + local index = {} + + local event = { + registerEvent = function(self,_event,func) + if( events[_event] == nil)then events[_event] = {} index[_event] = 1 end + events[_event][index[_event]] = func + index[_event] = index[_event] + 1 + return index[_event] - 1 + end; + + removeEvent = function(self,_event,index) + events[_event][index[_event]] = nil + end; + + sendEvent = function(self,_event,...) + if(events[_event]~=nil)then + for k,v in pairs(events[_event])do + v(...) + end + end + end; + } + event.__index = event + return event +end + +local processes = {} +local process = {} +local processId = 0 + +function process:new(path,window,...) + local args = table.pack( ... ) + local newP = setmetatable({path=path},{__index = self}) + newP.window = window + newP.processId = processId + newP.coroutine = coroutine.create(function() + os.run({basalt=basalt}, path, table.unpack(args)) + end) + processes[processId] = newP + processId = processId + 1 + return newP +end + +function process:resume(event, ...) + term.redirect(self.window) + local ok, result = coroutine.resume( self.coroutine, event, ... ) + self.window = term.current() + if ok then + self.filter = result + else + basalt.debug( result ) + end +end + +function process:isDead() + if(self.coroutine~=nil)then + if(coroutine.status(self.coroutine)=="dead")then + table.remove(processes, self.processId) + return true + end + else + return true + end + return false +end + +function process:getStatus() + if(self.coroutine~=nil)then + return coroutine.status(self.coroutine) + end + return nil +end + +function process:start() + coroutine.resume(self.coroutine) +end + +local function Object(name) -- Base object + local typ = "Object" -- not changeable + --[[ + local horizontalAnchor = "left" + local verticalAnchor = "top" + local ignYOffset = false + local ignXOffset = false ]] + local value = nil + local zIndex = 1 + local hanchor = "left" + local vanchor = "top" + local ignOffset = false + + local visualsChanged = true + + local eventSystem = BasaltEvents() + + local object = { + x = 1, + y = 1, + w = 1, + h = 1, + visible = false, + bgcolor = colors.black, + fgcolor = colors.white, + name = name or "Object", + parent = nil, + + show = function(self) + self.visible = true + visualsChanged = true + return self + end; + + getZIndex = function(self) + return zIndex; + end; + + setZIndex = function(self, index) + zIndex = index + return self + end; + + getType = function(self) + return typ + end; + + hide = function(self) + self.visible = false + visualsChanged = true + return self + end; + + setParent = function(self, frame) + if(frame.getType~=nil and frame:getType()=="Frame")then + if(self.parent~=nil)then + self.parent:removeObject(self) + end + frame:addObject(self) + if(self.draw)then + self:show() + end + end + return self + end; + + setValue = function(self, _value) + value = _value + visualsChanged = true + self:valueChangedHandler() + return self + end; + + getValue = function(self) + return value + end; + + getVisualChanged = function(self) + return visualsChanged + end; + + setVisualChanged = function(self, change) + visualsChanged = change or true + return self + end; + + + getEventSystem = function(self) + return eventSystem + end; + + + getParent = function(self) + return self.parent + end; + + setPosition = function(self, xPos, yPos, rel) + if(rel)then + self.x, self.y = self.x + xPos, self.y + yPos + else + self.x, self.y = xPos, yPos + end + visualsChanged = true + return self + end; + + getPosition = function(self) + return self.x,self.y + end; + + getVisibility = function(self) + return self.visible + end; + + setVisibility = function(self, isVisible) + self.visible = isVisible or not self.visible + visualsChanged = true + return self + end; + + setSize = function(self, w, h) + self.w, self.h = w, h + visualsChanged = true + return self + end; + + getHeight = function(self) + return self.h + end; + + getWidth = function(self) + return self.w + end; + + setBackground = function(self, color) + self.bgcolor = color + visualsChanged = true + return self + end; + + getBackground = function(self) + return self.bgcolor + end; + + setForeground = function(self, color) + self.fgcolor = color + visualsChanged = true + return self + end; + + getForeground = function(self) + return self.fgcolor + end; + + draw = function(self) + if(self.visible)then + return true + end + return false + end; + + + calcRelToAbsPosition = function(self, x,y) -- relative position + if(x==nil)then x = self.x end + if(y==nil)then y = self.y end + + if(self.parent~=nil)then + local fx,fy = self.parent:calcRelToAbsPosition() + x=fx+x-1 + y=fy+y-1 + end + return x, y + end; + + getOffset = function(self, x, y) + if(self.parent~=nil)and(ignOffset==false)then + return self.parent:getFrameOffset() + end + return 0, 0 + end; + + ignoreOffset = function(self, ignore) + ignOffset = ignore or true + return self + end; + + getAnchorPosition = function(self,x, y, ignOff) + if(x==nil)then x = self.x end + if(y==nil)then y = self.y end + if(hanchor=="right")then + x = self.parent.w-x-self.w+2 + end + if(vanchor=="bottom")then + y = self.parent.h-y-self.h+2 + end + local xO, yO = self:getOffset() + if(ignOffset or ignOff)then + return x, y + end + return x+xO, y+yO + end; + + setAnchor = function(self,...) + for _,v in pairs(table.pack(...))do + if(v=="right")or(v=="left")then + hanchor = v + end + if(v=="top")or(v=="bottom")then + vanchor = v + end + end + visualsChanged = true + return self + end; + + getAnchor = function(self) + return hanchor, vanchor + end; + + onChange = function(self, func) + self:registerEvent("value_changed", func) + return self + end; + + onClick = function(self, func) + self:registerEvent("mouse_click", func) + return self + end; + + onEvent = function(self, func) + self:registerEvent("custom_event_handler", func) + return self + end; + + onClickUp = function(self, func) + self:registerEvent("mouse_up", func) + return self + end; + + onKey = function(self, func) + self:registerEvent("key", func) + self:registerEvent("char", func) + return self + end; + + onKeyUp = function(self, func) + self:registerEvent("key_up", func) + return self + end; + + isFocused = function(self) + if(self.parent~=nil)then + return self.parent:getFocus()==self + end + return false + end; + + onGetFocus = function(self, func) + self:registerEvent("get_focus", func) + return self + end; + + onLoseFocus = function(self, func) + self:registerEvent("lose_focus", func) + return self + end; + + registerEvent = function(self,event, func) + return eventSystem:registerEvent(event, func) + end; + + removeEvent = function(self,event, index) + return eventSystem:removeEvent(event, index) + end; + + mouseHandler = function(self, event, button, x, y) + local objX,objY = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(objX<=x)and(objX+self.w>x)and(objY<=y)and(objY+self.h>y)then + if(self.parent~=nil)then self.parent:setFocus(self) end + eventSystem:sendEvent(event, self, event, button, x, y) + return true + end + return false + end; + + keyHandler = function(self, event, key) + if(self:isFocused())then + eventSystem:sendEvent(event, self, event, key) + return true + end + return false + end; + + valueChangedHandler = function(self) + eventSystem:sendEvent("value_changed", self) + end; + + eventHandler = function(self, event, p1, p2, p3, p4) + eventSystem:sendEvent("custom_event_handler", self, event, p1, p2, p3, p4) + end; + + getFocusHandler = function(self) + eventSystem:sendEvent("get_focus", self) + end; + + loseFocusHandler = function(self) + eventSystem:sendEvent("lose_focus", self) + end; + + + } + + object.__index = object + return object +end + +local function Button(name) -- Button + local base = Object(name) + local typ = "Button" + + base:setValue("Button") + base:setZIndex(5) + base.w = 8 + base.bgcolor = theme.ButtonBG + base.fgcolor = theme.ButtonFG + + local textHorizontalAlign = "center" + local textVerticalAlign = "center" + + local object = { + getType = function(self) + return typ + end; + setHorizontalAlign = function (self, pos) + textHorizontalAlign = pos + end; + + setVerticalAlign = function (self, pos) + textVerticalAlign = pos + end; + + setText = function(self,text) + base:setValue(text) + return self + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition(self.x,self.y) + local verticalAlign = getTextVerticalAlign(self.h, textVerticalAlign) + + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + self.parent:drawTextBox(obx, oby, self.w, self.h, " ") + for n=1,self.h do + if(n==verticalAlign)then + self.parent:writeText(obx, oby+(n-1), getTextHorizontalAlign(self:getValue(), self.w, textHorizontalAlign), self.bgcolor, self.fgcolor) + end + end + end + end + end; + + } + return setmetatable(object, base) +end + +local function Program(name) + local base = Object(name) + local typ = "Program" + base:setZIndex(5) + local object + + local function basaltWindow(x, y, w, h) + 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] = { parentTerminal.getPaletteColour( c ) } + end + + local function createEmptyLines() + emptySpaceLine = (" "):rep(w) + for n=0,15 do + local nColor = 2^n + local sHex = tHex[nColor] + emptyColorLines[nColor] = sHex:rep(w) + end + end + ---- + createEmptyLines() + + local function recreateWindowArray() + local emptyText = emptySpaceLine + local emptyFG = emptyColorLines[colors.white] + local emptyBG = emptyColorLines[colors.black] + for n=1,h do + cacheT[n] = sub(cacheT[n] == nil and emptyText or cacheT[n]..emptyText:sub(1,w-cacheT[n]:len()),1,w) + cacheFG[n] = sub(cacheFG[n] == nil and emptyFG or cacheFG[n]..emptyFG:sub(1,w-cacheFG[n]:len()),1,w) + cacheBG[n] = sub(cacheBG[n] == nil and emptyBG or cacheBG[n]..emptyBG:sub(1,w-cacheBG[n]:len()),1,w) + end + end + recreateWindowArray() + + local function updateCursor() + if xCursor >= 1 and yCursor >= 1 and xCursor <= w and yCursor <= h 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 ) -- copy pasti strikes again (cc: window.lua) + local nStart = xCursor + local nEnd = nStart + #sText - 1 + if yCursor >= 1 and yCursor <= h then + if nStart <= w and nEnd >= 1 then + -- Modify line + if nStart == 1 and nEnd == w then + cacheT[yCursor] = sText + cacheFG[yCursor] = sTextColor + cacheBG[yCursor] = sBackgroundColor + else + local sClippedText, sClippedTextColor, sClippedBackgroundColor + if nStart < 1 then + local nClipStart = 1 - nStart + 1 + local nClipEnd = w - nStart + 1 + sClippedText = sub( sText, nClipStart, nClipEnd ) + sClippedTextColor = sub( sTextColor, nClipStart, nClipEnd ) + sClippedBackgroundColor = sub( sBackgroundColor, nClipStart, nClipEnd ) + elseif nEnd > w then + local nClipEnd = w - nStart + 1 + sClippedText = sub( sText, 1, nClipEnd ) + sClippedTextColor = sub( sTextColor, 1, nClipEnd ) + sClippedBackgroundColor = sub( sBackgroundColor, 1, nClipEnd ) + else + sClippedText = sText + sClippedTextColor = sTextColor + sClippedBackgroundColor = sBackgroundColor + end + + local sOldText = cacheT[yCursor] + local sOldTextColor = cacheFG[yCursor] + local sOldBackgroundColor = cacheBG[yCursor] + local sNewText, sNewTextColor, sNewBackgroundColor + if nStart > 1 then + local nOldEnd = nStart - 1 + sNewText = sub( sOldText, 1, nOldEnd ) .. sClippedText + sNewTextColor = sub( sOldTextColor, 1, nOldEnd ) .. sClippedTextColor + sNewBackgroundColor = sub( sOldBackgroundColor, 1, nOldEnd ) .. sClippedBackgroundColor + else + sNewText = sClippedText + sNewTextColor = sClippedTextColor + sNewBackgroundColor = sClippedBackgroundColor + end + if nEnd < w then + local nOldStart = nEnd + 1 + sNewText = sNewText .. sub( sOldText, nOldStart, w ) + sNewTextColor = sNewTextColor .. sub( sOldTextColor, nOldStart, w ) + sNewBackgroundColor = sNewBackgroundColor .. sub( sOldBackgroundColor, nOldStart, w ) + end + + cacheT[yCursor] = sNewText + cacheFG[yCursor] = sNewTextColor + cacheBG[yCursor] = sNewBackgroundColor + end + end + xCursor = nEnd + 1 + if(visible)then + updateCursor() + end + end + 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()),w),1,w) + end + end + 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()),w),1,w) + end + end + 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()),w),1,w) + end + end + 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 w, h + end; + + getTextColor = function() + return fgcolor + end; + getTextColour = function() + return fgcolor + end; + + basalt_resize = function(_w, _h) + w, h = _w, _h + recreateWindowArray() + end; + + basalt_reposition = function(_x, _y) + x, y = _x, _y + end; + + basalt_setVisible = function(vis) + visible = vis + end; + + drawBackgroundBox = function (_x, _y, _w, _h, bgCol) + for n = 1, _h do + setBG(_x, _y + (n-1), tHex[bgCol]:rep(_w)) + end + end; + drawForegroundBox = function (_x, _y, _w, _h, fgCol) + for n = 1, _h do + setFG(_x, _y + (n-1), tHex[fgCol]:rep(_w)) + end + end; + drawTextBox = function (_x, _y, _w, _h, symbol) + for n = 1, _h do + setText(_x, _y + (n-1), symbol:rep(_w)) + end + end; + writeText = function (_x, _y, text, bgCol, fgCol) + bgCol = bgCol or bgcolor + fgCol = fgCol or fgcolor + setText(x, _y, text) + setBG(_x, _y, tHex[bgCol]:rep(text:len())) + setFG(_x, _y, tHex[fgCol]:rep(text:len())) + end; + + basalt_update = function() + if(object.parent~=nil)then + for n=1, h do + object.parent:setText(x, y + (n-1), cacheT[n]) + object.parent:setBG(x, y + (n-1), cacheBG[n]) + object.parent:setFG(x, y + (n-1), cacheFG[n]) + end + end + end; + + scroll = function (offset) + if type( offset ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( offset ) .. ")", 2 ) end + if offset ~= 0 then + local sEmptyText = emptySpaceLine + local sEmptyTextColor = emptyColorLines[ fgcolor ] + local sEmptyBackgroundColor = emptyColorLines[ bgcolor ] + for newY=1,h do + local y = newY + offset + if y >= 1 and y <= h then + cacheT[newY] = cacheT[y] + cacheBG[newY] = cacheBG[y] + cacheFG[newY] = cacheFG[y] + else + cacheT[newY] = sEmptyText + cacheFG[newY] = sEmptyTextColor + cacheBG[newY] = sEmptyBackgroundColor + end + end + end + if(visible)then + updateCursor() + end + end; + + + isColor = function() + return parentTerminal.isColor() + end; + + isColour = function() + return parentTerminal.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(w)) + setBG(1, yCursor, tHex[bgcolor]:rep(w)) + setFG(1, yCursor, tHex[fgcolor]:rep(w)) + end + if(visible)then + updateCursor() + end + end; + + clear = function() + for n=1,h do + setText(1, n, (" "):rep(w)) + setBG(1, n, tHex[bgcolor]:rep(w)) + setFG(1, n, tHex[fgcolor]:rep(w)) + 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 + --setText(xCursor, yCursor, text) + --setBG(xCursor, yCursor, bgcol) + --setFG(xCursor, yCursor, fgcol) + --xCursor = xCursor+text:len() + internalBlit(text, fgcol, bgcol) + end + end + + + } + + return basaltwindow + end + + base.w = 30 + base.h = 12 + local pWindow = basaltWindow(1, 1, base.w, base.h) + local curProcess + local paused = false + local queuedEvent = {} + + object = { + getType = function(self) + return typ + end; + + show = function(self) + base.show(self) + pWindow.setBackgroundColor(self.bgcolor) + pWindow.setTextColor(self.fgcolor) + 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:getAnchorPosition()) + return self + end; + + getBasaltWindow = function() + return pWindow + end; + + getBasaltProcess = function() + return curProcess + end; + + setSize = function(self, w, h) + base.setSize(self,w,h) + pWindow.basalt_resize(self.w, self.h) + return self + end; + + getStatus = function(self) + if(curProcess~=nil)then + return curProcess:getStatus() + end + return "inactive" + end; + + execute = function(self, path, ...) + curProcess = process:new(path, pWindow, ...) + pWindow.setBackgroundColor(colors.black) + pWindow.setTextColor(colors.white) + pWindow.clear() + pWindow.setCursorPos(1, 1) + curProcess:resume() + paused = false + return self + end; + + stop = function(self) + if(curProcess~=nil)then + if not(curProcess:isDead())then + curProcess:resume("terminate") + if(curProcess:isDead())then + if(self.parent~=nil)then + self.parent:setCursor(false) + end + end + end + end + 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 + for _,v in pairs(queuedEvent)do + curProcess:resume(v.event, table.unpack(v.args)) + end + queuedEvent = {} + end + end + end + return self + end; + + isPaused = function(self) + return paused + end; + + injectEvent = function(self, event, ign, p1, p2, p3, p4) + if(curProcess~=nil)then + if not(curProcess:isDead())then + if not(paused)or(ign)then + curProcess:resume(event,p1,p2,p3,p4) + else + table.insert(queuedEvent, {event=event, args = {p1,p2,p3,p4}}) + end + end + end + return self + end; + + mouseHandler = function(self, event, button, x, y) + if(base.mouseHandler(self,event,button,x,y))then + if(curProcess==nil)then return false end + if not(curProcess:isDead())then + if not(paused)then + local absX,absY = self:calcRelToAbsPosition(self:getAnchorPosition()) + curProcess:resume(event, button, x-absX+1, y-absY+1) + end + end + return true + end + end; + + keyHandler = function(self, event, key) + if(self:isFocused())then + if(curProcess==nil)then return false end + if not(curProcess:isDead())then + if not(paused)then + base.keyHandler(self, event, key) + if(self.draw)then + curProcess:resume(event, key) + end + end + end + end + end; + + getFocusHandler = function(self) + base.getFocusHandler(self) + if(curProcess~=nil)then + if not(curProcess:isDead())then + if not(paused)then + if(self.parent~=nil)then + local xCur, yCur = pWindow.getCursorPos() + local obx, oby = self:getAnchorPosition() + if(self.parent~=nil)then + if(obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + self.w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + self.h - 1)then + self.parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) + end + end + end + end + end + end + end; + + loseFocusHandler = function(self) + base.loseFocusHandler(self) + if(curProcess~=nil)then + if not(curProcess:isDead())then + if(self.parent~=nil)then + self.parent:setCursor(false) + end + end + end + end; + + eventHandler = function(self, event, p1, p2, p3, p4) + if(curProcess==nil)then return end + if not(curProcess:isDead())then + if not(paused)then + if(event~="mouse_click")and(event~="mouse_up")and(event~="mouse_scroll")and(event~="mouse_drag")and(event~="key_up")and(event~="key")and(event~="char")and(event~="terminate")then + curProcess:resume(event,p1,p2,p3,p4) + end + if(self:isFocused())then + local obx, oby = self:getAnchorPosition() + local xCur, yCur = pWindow.getCursorPos() + if(self.parent~=nil)then + if(obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + self.w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + self.h - 1)then + self.parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) + end + end + + if(event=="terminate")and(self:isFocused())then + self:stop() + end + end + else + if(event~="mouse_click")and(event~="mouse_up")and(event~="mouse_scroll")and(event~="mouse_drag")and(event~="key_up")and(event~="key")and(event~="char")and(event~="terminate")then + table.insert(queuedEvent, {event=event, args = {p1,p2,p3,p4}}) + end + end + end + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + pWindow.basalt_reposition(obx,oby) + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + pWindow.basalt_update() + end + end + end; + + } + + return setmetatable(object, base) +end + +local function Label(name) -- Label + local base = Object(name) + local typ = "Label" + + local autoWidth = true + base:setValue("") + + local object = { + getType = function(self) + return typ + end; + setText = function(self,text) + base:setValue(text) + if(autoWidth)then + self.w = text:len() + end + return self + end; + + setSize = function(self,w,h) + self.w, self.h = w, h + autoWidth = false + return self + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + self.parent:writeText(obx, oby, self:getValue(), self.bgcolor, self.fgcolor) + end + end + end; + + } + + return setmetatable(object, base) +end + +local function Checkbox(name) -- Checkbox + local base = Object(name) + local typ = "Checkbox" + + base:setZIndex(5) + base:setValue(false) + base.w = 1 + base.h = 1 + base.bgcolor = theme.CheckboxBG + base.fgcolor = theme.CheckboxFG + + local object = { + symbol = "\42", + + getType = function(self) + return typ + end; + + mouseHandler = function(self, event, button, x, y) + if(base.mouseHandler(self, event, button, x, y))then + if(event == "mouse_click")and(button == 1)then + if(self:getValue()~=true)and(self:getValue()~=false)then + self:setValue(false) + else + self:setValue(not self:getValue()) + end + end + return true + end + return false + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + local verticalAlign = getTextVerticalAlign(self.h, "center") + + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + for n=1,self.h do + if(n==verticalAlign)then + if(self:getValue()==true)then + self.parent:writeText(obx, oby+(n-1), getTextHorizontalAlign(self.symbol, self.w, "center"), self.bgcolor, self.fgcolor) + else + self.parent:writeText(obx, oby+(n-1), getTextHorizontalAlign(" ", self.w, "center"), self.bgcolor, self.fgcolor) + end + end + end + end + end + end; + + } + + return setmetatable(object, base) +end + +local function Input(name) -- Input + local base = Object(name) + local typ = "Input" + + local inputType = "text" + local inputLimit = 0 + base:setZIndex(5) + base:setValue("") + base.w = 10 + base.h = 1 + base.bgcolor = theme.InputBG + base.fgcolor = theme.InputFG + + local object = { + + getType = function(self) + return typ + end; + + setInputType = function(self, iType) + if(iType=="password")or(iType=="number")or(iType=="text")then + inputType = iType + end + return self + end; + + getInputType = function(self) + return inputType + end; + + setInputLimit = function(self, limit) + inputLimit = tonumber(limit) or inputLimit + return self + end; + + getInputLimit = function(self) + return inputLimit + end; + + getFocusHandler = function(self) + base.getFocusHandler(self) + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + local cursorX = obx+(self:getValue():len() < self.w and self:getValue():len() or self.w-1) + local cursorY = oby + if(self.parent~=nil)then + self.parent:setCursor(true, cursorX, cursorY, self.fgcolor) + end + end + end; + + loseFocusHandler = function(self) + base.loseFocusHandler(self) + if(self.parent~=nil)then + self.parent:setCursor(false) + end + end; + + keyHandler = function(self, event, key) + if(base.keyHandler(self, event, key))then + if(event=="key")then + if(key==259)then + self:setValue(self:getValue():sub(1,self:getValue():len()-1)) + end + if(key==257)then -- on enter + if(self.parent~=nil)then + --self.parent:removeFocus(self) + end + end + end + + if(event=="char")then + if(self:getValue():len() < inputLimit or inputLimit <= 0)then + if(inputType=="number")then + local cache = self:getValue() + if (key==".")or(tonumber(key)~=nil)then + self:setValue(self:getValue()..key) + end + if(tonumber(self:getValue())==nil)then + self:setValue(cache) + end + else + self:setValue(self:getValue()..key) + end + end + end + local obx,oby = self:getAnchorPosition() + local cursorX = obx+(self:getValue():len() < self.w and self:getValue():len() or self.w-1) + local cursorY = oby + if(self.parent~=nil)then + self.parent:setCursor(true, cursorX, cursorY, self.fgcolor) + end + end + end; + + mouseHandler = function(self, event, button, x, y) + if(base.mouseHandler(self, event, button, x, y))then + if(event == "mouse_click")and(button == 1)then + + end + return true + end + return false + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + local verticalAlign = getTextVerticalAlign(self.h, "center") + + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + for n=1,self.h do + if(n==verticalAlign)then + local text = inputType == "password" and ("*"):rep(self:getValue():len()) or self:getValue() + if(text:len()>=self.w)then + if(inputType=="password")then + text = ("*"):rep(text:len()):sub(text:len()-self.w+2, text:len()) + else + text = text:sub(text:len()-self.w+2, text:len()) + end + end + self.parent:writeText(obx, oby+(n-1), text, self.bgcolor, self.fgcolor) + end + end + end + end + end; + } + + return setmetatable(object, base) +end + +local function Textfield(name) + local base = Object(name) + local typ = "Textfield" + local hIndex, wIndex, textX, textY = 1, 1, 1, 1 + + local lines = {""} + local selection = {} + local selectionColor = colors.lightBlue + + base.w = 20 + base.h = 8 + base.bgcolor = theme.textfieldBG + base.fgcolor = theme.textfieldFG + base:setZIndex(5) + + local object = { + getType = function(self) + return typ + end; + + getLines = function (self) + return lines + end; + + getLine = function (self, index) + return lines[index] or "" + end; + + editLine = function (self, index, text) + lines[index] = text or lines[index] + return self + end; + + addLine = function (self, text, index) + if(index~=nil)then + table.insert(lines, index, text) + else + table.insert(lines, text) + end + return self + end; + + removeLine = function(self, index) + table.remove(lines, index or #lines) + if(#lines <= 0)then + table.insert(lines, "") + end + return self + end; + + getTextCursor = function (self) + return textX, textY + end; + + getFocusHandler = function(self) + base.getFocusHandler(self) + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + if(self.parent~=nil)then + self.parent:setCursor(true, obx+textX-wIndex, oby+textY-hIndex, self.fgcolor) + end + end + end; + + loseFocusHandler = function(self) + base.loseFocusHandler(self) + if(self.parent~=nil)then + self.parent:setCursor(false) + end + end; + + keyHandler = function(self, event, key) + if(base.keyHandler(self, event, key))then + local obx,oby = self:getAnchorPosition() + if(event=="key")then + if(key==259)then -- on backspace + if(lines[textY]=="")then + if(textY>1)then + table.remove(lines,textY) + textX = lines[textY-1]:len()+1 + wIndex = textX-self.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-self.w+1 + if(wIndex<1)then wIndex = 1 end + lines[textY-1] = lines[textY-1]..lines[textY] + table.remove(lines,textY) + textY = textY-1 + end + else + lines[textY] = lines[textY]:sub(1,textX-2)..lines[textY]:sub(textX,lines[textY]:len()) + if(textX>1)then textX = textX-1 end + if(wIndex>1)then + if(textX=self.h)then + hIndex = hIndex+1 + end + self:setValue("") + end + + if(key==265)then -- 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(textX1)then + if(textYlines[textY]:len()+1)then textX = lines[textY]:len()+1 end + + if(textY>=hIndex+self.h)then + hIndex = hIndex+1 + end + end + end + if(key==262)then -- 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=self.w+wIndex)then + wIndex = textX-self.w+1 + end + if(wIndex<1)then wIndex = 1 end + + end + if(key==263)then -- arrow left + textX = textX-1 + if(textX>=1)then + if(textX=self.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-self.w+1 + end + end + if(textX<1)then textX = 1 end + if(wIndex<1)then wIndex = 1 end + end + end + + if(event=="char")then + lines[textY] = lines[textY]:sub(1,textX-1)..key..lines[textY]:sub(textX,lines[textY]:len()) + textX = textX+1 + if(textX>=self.w+wIndex)then wIndex = wIndex+1 end + self:setValue("") + end + + local cursorX = (textX <= lines[textY]:len() and textX-1 or lines[textY]:len())-(wIndex-1) + if(cursorX>self.x+self.w-1)then cursorX = self.x+self.w-1 end + local cursorY = (textY-hIndex < self.h and textY-hIndex or textY-hIndex-1) + if(cursorX<1)then cursorX = 0 end + self.parent:setCursor(true, obx+cursorX, oby+cursorY, self.fgcolor) + return true + end + end; + + mouseHandler = function(self, event, button, x, y) + if(base.mouseHandler(self, event, button, x, y))then + local obx,oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + local anchx,anchy = self:getAnchorPosition() + if(event=="mouse_click")then + if(lines[y-oby+hIndex]~=nil)then + textX = x-obx+wIndex + textY = y-oby+hIndex + if(textX>lines[textY]:len())then + textX = lines[textY]:len()+1 + end + if(textX#lines-(self.h-1))then hIndex = #lines-(self.h-1) end + + if(hIndex<1)then hIndex = 1 end + + if(self.parent~=nil)then + if(obx+textX-wIndex>=obx and obx+textX-wIndex <= obx+self.w)and(oby+textY-hIndex >= oby and oby+textY-hIndex <= oby+self.h)then + self.parent:setCursor(true, anchx+textX-wIndex, anchy+textY-hIndex) + else + self.parent:setCursor(false) + end + end + end + self:setVisualChanged() + return true + end + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + for n=1, self.h do + local text = "" + if(lines[n+hIndex-1]~=nil)then + text = lines[n+hIndex-1] + end + text = text:sub(wIndex, self.w+wIndex-1) + local space = self.w-text:len() + if(space<0)then space = 0 end + text = text..string.rep(" ", space) + self.parent:setText(obx, oby+n-1, text) + end + end + end + end; + } + + return setmetatable(object, base) +end + +local function List(name) + local base = Object(name) + local typ = "List" + base.w = 16 + base.h = 6 + base.bgcolor = theme.listBG + base.fgcolor = theme.listFG + base:setZIndex(5) + + local list = {} + local itemSelectedBG = theme.selectionBG + local itemSelectedFG = theme.selectionFG + local selectionColorActive = true + local align = "left" + local yOffset = 0 + + local object = { + getType = function(self) + return typ + end; + + addItem = function(self, text, bgCol, fgCol) + table.insert(list, {text=text, bgCol = bgCol or self.bgcolor, fgCol = fgCol or self.fgcolor}) + if(#list==1)then + self:setValue(list[1]) + end + return self + end; + + removeItem = function(self, index) + table.remove(list, index) + return self + end; + + getItem = function(self, index) + return list[index] + end; + + editItem = function(self, index, text, bgCol, fgCol) + table.remove(list, index) + table.insert(list, index, {text=text, bgCol = bgCol or self.bgcolor, fgCol = fgCol or self.fgcolor}) + return self + end; + + selectItem = function(self, index) + self:setValue(list[index] or {}) + return self + end; + + selectedItem = function(self, bgCol, fgCol, active) + itemSelectedBG = bgCol or self.bgcolor + itemSelectedFG = fgCol or self.fgcolor + selectionColorActive = active + return self + end; + + mouseHandler = function(self, event, button, x, y) + if(base.mouseHandler(self, event, button, x, y))then + local obx,oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(event=="mouse_click")or(event=="mouse_drag")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw + if(button==1)then + if(#list>0)then + for n=1,self.h do + if(list[n+yOffset]~=nil)then + if(obx<=x)and(obx+self.w>x)and(oby+n-1==y)then + self:setValue(list[n+yOffset]) + end + end + end + end + end + end + + if(event=="mouse_scroll")then + yOffset = yOffset+button + if(yOffset<0)then yOffset = 0 end + if(button==1)then + if(#list>self.h)then + if(yOffset>#list-self.h)then + yOffset = #list-self.h + end + else + yOffset = list-1 + end + end + end + self:setVisualChanged() + return true + end + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + for n=1, self.h do + if(list[n+yOffset]~=nil)then + if(list[n+yOffset]==self:getValue())then + if(selectionColorActive)then + self.parent:writeText(obx, oby+n-1, getTextHorizontalAlign(list[n+yOffset].text, self.w, align), itemSelectedBG, itemSelectedFG) + else + self.parent:writeText(obx, oby+n-1, getTextHorizontalAlign(list[n+yOffset].text, self.w, align), list[n+yOffset].bgCol, list[n+yOffset].fgCol) + end + else + self.parent:writeText(obx, oby+n-1, getTextHorizontalAlign(list[n+yOffset].text, self.w, align), list[n+yOffset].bgCol,list[n+yOffset].fgCol) + end + end + end + end + end + end; + } + + return setmetatable(object, base) +end + +local function Dropdown(name) + local base = Object(name) + local typ = "Dropdown" + base.w = 12 + base.h = 1 + base.bgcolor = theme.dropdownBG + base.fgcolor = theme.dropdownFG + base:setZIndex(6) + + local list = {} + local itemSelectedBG = theme.selectionBG + local itemSelectedFG = theme.selectionFG + local selectionColorActive = true + local align = "left" + local yOffset = 0 + + local dropdownW = 16 + local dropdownH = 6 + local closedSymbol = "\16" + local openedSymbol = "\31" + local state = 1 + + local object = { + getType = function(self) + return typ + end; + + addItem = function(self, text, bgCol, fgCol) + table.insert(list, {text=text, bgCol = bgCol or self.bgcolor, fgCol = fgCol or self.fgcolor}) + if(#list==1)then + self:setValue(list[1]) + end + return self + end; + + removeItem = function(self, index) + table.remove(list, index) + return self + end; + + getItem = function(self, index) + return list[index] + end; + + editItem = function(self, index, text, bgCol, fgCol) + table.remove(list, index) + table.insert(list, index, {text=text, bgCol = bgCol or self.bgcolor, fgCol = fgCol or self.fgcolor}) + return self + end; + + selectItem = function(self, index) + self:setValue(list[index] or {}) + return self + end; + + selectedItem = function(self, bgCol, fgCol, active) + itemSelectedBG = bgCol or self.bgcolor + itemSelectedFG = fgCol or self.fgcolor + selectionColorActive = active + return self + end; + + setDropdownSize = function(self, w, h) + dropdownW, dropdownH = w, h + return self + end; + + mouseHandler = function(self, event, button, x, y) + if(state == 2)then + local obx,oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(event=="mouse_click")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw + if(button==1)then + 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]) + return true + end + end + end + end + end + end + + if(event=="mouse_scroll")then + yOffset = yOffset+button + if(yOffset<0)then yOffset = 0 end + if(button==1)then + if(#list>dropdownH)then + if(yOffset>#list-dropdownH)then + yOffset = #list-dropdownH + end + else + yOffset = list-1 + end + end + return true + end + self:setVisualChanged() + end + if(base.mouseHandler(self, event, button, x, y))then + state = 2 + else + state = 1 + end + end; + + draw = function(self) + if(base.draw(self))then + local obx, oby = self:getAnchorPosition() + if(self.parent~=nil)then + self.parent:drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + if(#list>=1)then + if(self:getValue().text~=nil)then + if(state==1)then + self.parent:writeText(obx, oby, getTextHorizontalAlign(self:getValue().text, self.w, align):sub(1,self.w-1)..closedSymbol, self.bgcolor, self.fgcolor) + else + self.parent:writeText(obx, oby, getTextHorizontalAlign(self:getValue().text, self.w, align):sub(1,self.w-1)..openedSymbol, self.bgcolor, self.fgcolor) + end + end + if(state==2)then + for n=1, dropdownH do + if(list[n+yOffset]~=nil)then + if(list[n+yOffset]==self:getValue())then + if(selectionColorActive)then + self.parent:writeText(obx, oby+n, getTextHorizontalAlign(list[n+yOffset].text, dropdownW, align), itemSelectedBG, itemSelectedFG) + else + self.parent:writeText(obx, oby+n, getTextHorizontalAlign(list[n+yOffset].text, dropdownW, align), list[n+yOffset].bgCol, list[n+yOffset].fgCol) + end + else + self.parent:writeText(obx, oby+n, getTextHorizontalAlign(list[n+yOffset].text, dropdownW, align), list[n+yOffset].bgCol,list[n+yOffset].fgCol) + end + end + end + end + end + end + end + end; + } + + return setmetatable(object, base) +end + +local function Radio(name) + local base = Object(name) + local typ = "Radio" + base.w = 8 + base.bgcolor = theme.listBG + base.fgcolor = theme.listFG + base:setZIndex(5) + + local list = {} + local itemSelectedBG = theme.selectionBG + local itemSelectedFG = theme.selectionFG + local boxSelectedBG = base.bgcolor + local boxSelectedFG = base.fgcolor + local selectionColorActive = true + local symbol = "\7" + local align = "left" + + local object = { + getType = function(self) + return typ + end; + + addItem = function(self,text, x, y, bgCol, fgCol) + table.insert(list, {x=x or 1, y=y or 1, text=text, bgCol = bgCol or self.bgcolor, fgCol = fgCol or self.fgcolor}) + if(#list==1)then + self:setValue(list[1]) + end + return self + end; + + removeItem = function(self, index) + table.remove(list, index) + return self + end; + + getItem = function(self, index) + return list[index] + end; + + editItem = function(self, index, text, x, y, bgCol, fgCol) + table.remove(list, index) + table.insert(list, index, {x=x or 1, y=y or 1, text=text, bgCol = bgCol or self.bgcolor, fgCol = fgCol or self.fgcolor}) + return self + end; + + selectItem = function(self, index) + self:setValue(list[index] or {}) + return self + end; + + selectedItem = function(self, bgCol, fgCol, boxBG, boxFG, active) + itemSelectedBG = bgCol or itemSelectedBG + itemSelectedFG = fgCol or itemSelectedFG + boxSelectedBG = boxBG or boxSelectedBG + boxSelectedFG = boxFG or boxSelectedFG + selectionColorActive = active + return self + end; + + mouseHandler = function(self, event, button, x, y) + local obx,oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(event=="mouse_click")then -- remove mouse_drag if i want to make objects moveable uwuwuwuw + if(button==1)then + if(#list>0)then + for _,v in pairs(list)do + if(obx+v.x-1<=x)and(obx+v.x-1+v.text:len()+2>=x)and(oby+v.y-1==y)then + self:setValue(v) + if(self.parent~=nil)then self.parent:setFocus(self) end + --eventSystem:sendEvent(event, self, event, button, x, y) + self:setVisualChanged() + return true + end + end + end + end + end + return false + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + for _,v in pairs(list)do + if(v==self:getValue())then + if(align=="left")then + self.parent:writeText(v.x+obx-1,v.y+oby-1,symbol,boxSelectedBG,boxSelectedFG) + self.parent:writeText(v.x+2+obx-1,v.y+oby-1,v.text,itemSelectedBG,itemSelectedFG) + end + else + self.parent:drawBackgroundBox(v.x+obx-1, v.y+oby-1,1,1,self.bgcolor) + self.parent:writeText(v.x+2+obx-1,v.y+oby-1,v.text,v.bgCol,v.fgCol) + end + end + end + end + end; + } + + return setmetatable(object, base) +end + +local function Timer(name) + local typ = "Timer" + + local timer = 0 + local savedRepeats = 0 + local repeats = 0 + local timerObj + local eventSystem = BasaltEvents() + + local object = { + name = name, + getType = function(self) + return typ + end; + + getZIndex = function(self) + return 1 + end; + + getName = function(self) + return self.name + end; + + setTime = function(self, _timer, _repeats) + timer = _timer or 0 + savedRepeats = _repeats or 1 + return self + end; + + start = function(self) + repeats = savedRepeats + timerObj = os.startTimer(timer) + return self + end; + + cancel = function(self) + os.cancelTimer(timerObj) + return self + end; + + onCall = function(self, func) + eventSystem:registerEvent("timed_event", func) + return self + end; + + eventHandler = function(self, event, tObj) + if(event=="timer")and(tObj==timerObj)then + eventSystem:sendEvent("timed_event",self) + 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 object +end + +local function Animation(name) + local object = {} + local typ = "Animation" + + local timerObj + + local animations = {} + local index = 1 + + local nextWaitTimer = 0 + local lastFunc + + local function onPlay() + if(animations[index]~=nil)then + animations[index].f(object, index) + end + index = index+1 + if(animations[index]~=nil)then + if(animations[index].t>0)then + timerObj = os.startTimer(animations[index].t) + else + onPlay() + end + end + end + + object = { + name = name, + getType = function(self) + return typ + end; + + getZIndex = function(self) + return 1 + end; + + getName = function(self) + return self.name + end; + + add = function(self, func, wait) + lastFunc = func + table.insert(animations, {f=func,t = wait or nextWaitTimer}) + return self + end; + + wait = function(self, wait) + nextWaitTimer = wait + return self + end; + + rep = function(self, reps) + for x=1,reps do + table.insert(animations, {f=lastFunc,t = nextWaitTimer}) + end + return self + end; + + clear = function(self) + animations = {} + lastFunc = nil + nextWaitTimer = 0 + index = 1 + return self + end; + + play = function(self) + index = 1 + if(animations[index]~=nil)then + if(animations[index].t>0)then + timerObj = os.startTimer(animations[index].t) + else + onPlay() + end + end + return self + end; + + cancel = function(self) + os.cancelTimer(timerObj) + return self + end; + + eventHandler = function(self, event, tObj) + if(event=="timer")and(tObj==timerObj)then + if(animations[index]~=nil)then + onPlay() + end + end + end; + } + object.__index = object + + return object +end + +local function Slider(name) + local base = Object(name) + local typ = "Slider" + + base.w = 8 + base.bgcolor = colors.lightGray + base.fgcolor = colors.gray + base:setValue(1) + + local barType = "horizontal" + local symbol = " " + local symbolColor=colors.black + local bgSymbol = "\140" + local maxValue = base.w + local index = 1 + + + + local object = { + getType = function(self) + return typ + end; + + setSymbol = function(self, _symbol) + symbol = _symbol:sub(1,1) + self:setVisualChanged() + return self + end; + + setBackgroundSymbol = function(self, _bgSymbol) + bgSymbol = string.sub(_bgSymbol,1,1) + self:setVisualChanged() + return self + end; + + setSymbolColor = function(self, col) + symbolColor = col + self:setVisualChanged() + return self + end; + + setBarType = function(self, _typ) + barType = _typ:lower() + return self + end; + + mouseHandler = function(self, event, button, x, y) + if(base.mouseHandler(self,event,button,x,y))then + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(barType=="horizontal")then + for _index=0,self.w-1 do + if(obx+_index==x)and(oby<=y)and(oby+self.h>y)then + index = _index+1 + self:setValue(maxValue/self.w*(index)) + self:setVisualChanged() + end + end + end + if(barType=="vertical")then + for _index=0,self.h-1 do + if(oby+_index==y)and(obx<=x)and(obx+self.w>x)then + index = _index+1 + self:setValue(maxValue/self.h*(index)) + self:setVisualChanged() + end + end + end + --[[if(event=="mouse_scroll")then + self:setValue(self:getValue() + (maxValue/(barType=="vertical" and self.h or self.w))*typ) + self:setVisualChanged() + end + if(self:getValue()>maxValue)then self:setValue(maxValue) end + if(self:getValue()y)then + index = math.min(_index+1, self.w-(symbolSize-1)) + self:setValue(maxValue/self.w*(index)) + self:setVisualChanged() + end + end + end + if(barType=="vertical")then + for _index=0,self.h do + if(oby+_index==y)and(obx<=x)and(obx+self.w>x)then + index = math.min(_index+1, self.h-(symbolSize-1)) + self:setValue(maxValue/self.h*(index)) + self:setVisualChanged() + end + end + end + end + if(event=="mouse_scroll")then + index = index+button + if(index<1)then index = 1 end + index = math.min(index, (barType=="vertical" and self.h or self.w)-(symbolSize-1)) + self:setValue(maxValue/(barType=="vertical" and self.h or self.w)*index) + end + end + end; + + draw = function(self) + if(base.draw(self))then + if(self.parent~=nil)then + local obx, oby = self:getAnchorPosition() + if(barType=="horizontal")then + self.parent:writeText(obx, oby, bgSymbol:rep(index-1), self.bgcolor, self.fgcolor) + self.parent:writeText(obx + index - 1, oby, symbol:rep(symbolSize), symbolColor, symbolColor) + self.parent:writeText(obx + index+symbolSize-1, oby, bgSymbol:rep(self.w - (index+symbolSize-1)), self.bgcolor, self.fgcolor) + end + + if(barType=="vertical")then + for n = 0, self.h-1 do + + if(index==n+1)then + for curIndexOffset=0,math.min(symbolSize-1,self.h) do + self.parent:writeText(obx, oby+n+curIndexOffset, symbol, symbolColor, symbolColor) + end + else + if(n+1index-1+symbolSize)then + self.parent:writeText(obx, oby+n, bgSymbol, self.bgcolor, self.fgcolor) + end + end + end + end + end + end + end; + + } + + return setmetatable(object, base) +end + + + + +local function Frame(name,parent) -- Frame + local base = Object(name) + local typ = "Frame" + local objects = {} + local objZIndex = {} + local object = {} + local focusedObject + base:setZIndex(10) + + local cursorBlink = false + local xCursor = 1 + local yCursor = 1 + local cursorColor = colors.white + + local xOffset, yOffset = 0, 0 + + if(parent~=nil)then + base.parent = parent + base.w, base.h = parent.w, parent.h + base.bgcolor = theme.FrameBG + base.fgcolor = theme.FrameFG + else + local termW, termH = parentTerminal.getSize() + base.w, base.h = termW, termH + base.bgcolor = theme.basaltBG + base.fgcolor = theme.basaltFG + base:ignoreOffset(true) + end + + + local function addObject(obj) + local index = obj:getZIndex() + if(objects[index]==nil)then + for x=0,#objZIndex+1 do + if(objZIndex[x]~=nil)then + if(index > objZIndex[x])then + table.insert(objZIndex,x,index) + end + else + table.insert(objZIndex,x,index) + end + end + if(#objZIndex<=0)then + table.insert(objZIndex,index) + end + objects[index] = {} + end + obj.parent = object + table.insert(objects[index],obj) + return obj + end + + local function removeObject(obj) + if(objects~=nil)then + for a,b in pairs(objects)do + for k,v in pairs(b)do + if(v==obj)then + table.remove(objects[a],k) + return; + end + end + end + end + end + + object = { + barActive = false, + barBackground = colors.gray, + barTextcolor = colors.black, + barText = "New Frame", + barTextAlign = "left", + isMoveable = false, + + getType = function(self) + return typ + end; + + setFocus = function(self, obj) + for _,index in pairs(objZIndex)do + for _,v in pairs(objects[index])do + if(v == obj)then + if(focusedObject~=nil)then focusedObject:loseFocusHandler() end + focusedObject = obj + focusedObject:getFocusHandler() + end + end + end + return self + end; + + setOffset = function(self, xO, yO) + xOffset = xO ~= nil and math.floor(xO < 0 and math.abs(xO) or -xO) or xOffset + yOffset = yO ~= nil and math.floor(yO < 0 and math.abs(yO) or -yO) or yOffset + return self + end; + + getFrameOffset = function(self) + return xOffset, yOffset + end; + + removeFocus = function(self) + if(focusedObject~=nil)then focusedObject:loseFocusHandler() end + focusedObject = nil + return self + end; + + getFocus = function(self) + return focusedObject + end; + + show = function(self) + base:show() + if(self.parent==nil)then + activeFrame = self + end + return self + end; + + setCursor = function(self, _blink, _xCursor, _yCursor, color) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + cursorBlink = _blink or false + if(_xCursor~=nil)then xCursor = obx+_xCursor-1 end + if(_yCursor~=nil)then yCursor = oby+_yCursor-1 end + cursorColor = color or cursorColor + self:setVisualChanged() + return self + end; + + setMoveable = function(self, moveable) + self.isMoveable = moveable or not self.isMoveable + self:setVisualChanged() + return self; + end; + + + showBar = function(self, showIt) + self.barActive = showIt or not self.barActive + self:setVisualChanged() + return self + end; + + setBar = function(self, text, bgCol, fgCol) + self.barText = text or "" + self.barBackground = bgCol or self.barBackground + self.barTextcolor = fgCol or self.barTextcolor + self:setVisualChanged() + return self + end; + + setBarTextAlign = function(self, align) + self.barTextAlign = align or "left" + self:setVisualChanged() + return self + end; + + getVisualChanged = function(self) + local changed = base.getVisualChanged(self) + for _,index in pairs(objZIndex)do + for _,v in pairs(objects[index])do + if(v.getVisualChanged~=nil and v:getVisualChanged())then + changed = true + end + end + end + return changed + end; + + getFocusHandler = function(self) + base.getFocusHandler(self) + if(self.parent~=nil)then + self.parent:removeObject(self) + self.parent:addObject(self) + end + end; + + keyHandler = function(self, event, key) + if(focusedObject~=nil)then + if(focusedObject.keyHandler~=nil)then + if(focusedObject:keyHandler(event,key))then + return true + end + end + end + return false + end; + + eventHandler = function(self, event, p1, p2, p3, p4) + base.eventHandler(self, event, p1, p2, p3, p4) + for _,index in pairs(objZIndex)do + for _,v in pairs(objects[index])do + if(v.eventHandler~=nil)then + v:eventHandler(event,p1, p2, p3, p4) + end + end + end + if(event=="terminate")then + parentTerminal.clear() + parentTerminal.setCursorPos(1,1) + basalt.stop() + end + end; + + mouseHandler = function(self, event, button, x, y) + local xO, yO = self:getOffset() + xO = xO < 0 and math.abs(xO) or -xO + yO = yO < 0 and math.abs(yO) or -yO + if(self.drag)and(self.visible)then + if(event=="mouse_drag")then + local parentX=1;local parentY=1 + if(self.parent~=nil)then + parentX,parentY = self.parent:calcRelToAbsPosition(self.parent:getAnchorPosition()) + end + self:setPosition(x+self.xToRem-(parentX-1) + xO,y-(parentY-1) + yO) + end + if(event=="mouse_up")then + self.drag = false + end + return true + end + + if(base.mouseHandler(self,event,button,x,y))then + local fx,fy = self:calcRelToAbsPosition(self:getAnchorPosition()) + for _,index in pairs(objZIndex)do + for _,v in rpairs(objects[index])do + if(v.mouseHandler~=nil)then + if(v:mouseHandler(event,button,x+xO,y+yO))then + return true + end + end + end + end + + if(self.isMoveable)then + if(x>=fx)and(x<=fx+self.w-1)and(y==fy)and(event=="mouse_click")then + self.drag = true + self.xToRem = fx-x + end + end + if(focusedObject~=nil)then focusedObject:loseFocusHandler() focusedObject = nil end + return true + end + return false + end; + + setText = function(self, x, y, text) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(y>=1)and(y<=self.h)then + drawHelper.setText(math.max(x+(obx-1),obx), oby+y-1, sub( text, math.max(1 - x + 1, 1), self.w - x + 1 )) + end + end; + + setBG = function(self, x, y, bgCol) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(y>=1)and(y<=self.h)then + drawHelper.setBG(math.max(x+(obx-1),obx), oby+y-1, sub( bgCol, math.max(1 - x + 1, 1), self.w - x + 1 )) + end + end; + + setFG = function(self, x, y, fgCol) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(y>=1)and(y<=self.h)then + drawHelper.setFG(math.max(x+(obx-1),obx), oby+y-1, sub( fgCol, math.max(1 - x + 1, 1), self.w - x + 1 )) + end + end; + + writeText = function(self, x, y, text, bgCol, fgCol) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + if(y>=1)and(y<=self.h)then + drawHelper.writeText(math.max(x+(obx-1),obx), oby+y-1, sub( text, math.max(1 - x + 1, 1), self.w - x + 1 ), bgCol, fgCol) + end + end; + + drawBackgroundBox = function(self, x, y, w, h, bgCol) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + h = (y < 1 and (h+y > self.h and self.h or h+y-1) or (h+y > self.h and self.h-y+1 or h)) + w = (x < 1 and (w+x > self.w and self.w or w+x-1) or (w+x > self.w and self.w-x+1 or w)) + drawHelper.drawBackgroundBox(math.max(x+(obx-1),obx), math.max(y+(oby-1),oby), w, h, bgCol) + end; + + drawTextBox = function(self, x, y, w, h, symbol) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + h = (y < 1 and (h+y > self.h and self.h or h+y-1) or (h+y > self.h and self.h-y+1 or h)) + w = (x < 1 and (w+x > self.w and self.w or w+x-1) or (w+x > self.w and self.w-x+1 or w)) + drawHelper.drawTextBox(math.max(x+(obx-1),obx), math.max(y+(oby-1),oby), w, h, symbol:sub(1,1)) + end; + + drawForegroundBox = function(self, x, y, w, h, fgCol) + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + h = (y < 1 and (h+y > self.h and self.h or h+y-1) or (h+y > self.h and self.h-y+1 or h)) + w = (x < 1 and (w+x > self.w and self.w or w+x-1) or (w+x > self.w and self.w-x+1 or w)) + drawHelper.drawForegroundBox(math.max(x+(obx-1),obx), math.max(y+(oby-1),oby), w, h, fgCol) + end; + + draw = function(self) + if(self:getVisualChanged())then + if(base.draw(self))then + local obx, oby = self:calcRelToAbsPosition(self:getAnchorPosition()) + drawHelper.drawBackgroundBox(obx, oby, self.w, self.h, self.bgcolor) + drawHelper.drawForegroundBox(obx, oby, self.w, self.h, self.fgcolor) + drawHelper.drawTextBox(obx, oby, self.w, self.h, " ") + parentTerminal.setCursorBlink(false) + if(self.barActive)then + drawHelper.writeText(obx, oby, getTextHorizontalAlign(self.barText, self.w, self.barTextAlign), self.barBackground, self.barTextcolor) + end + + for _,index in rpairs(objZIndex)do + for _,v in pairs(objects[index])do + if(v.draw~=nil)then + v:draw() + end + end + end + if(cursorBlink)then + parentTerminal.setTextColor(cursorColor) + parentTerminal.setCursorPos(xCursor, yCursor) + if(self.parent~=nil)then + parentTerminal.setCursorBlink(self:isFocused()) + else + parentTerminal.setCursorBlink(cursorBlink) + end + end + end + self:setVisualChanged(false) + end + end; + + addObject = function(self, obj) + return addObject(obj) + end; + + removeObject = function(self, obj) + return removeObject(obj) + end; + + addButton = function(self, name) + local obj = Button(name) + obj.name = name + return addObject(obj) + end; + + addLabel = function(self, name) + local obj = Label(name) + obj.name = name + obj.bgcolor = self.bgcolor + obj.fgcolor = self.fgcolor + return addObject(obj) + end; + + addCheckbox = function(self, name) + local obj = Checkbox(name) + obj.name = name + return addObject(obj) + end; + + addInput = function(self, name) + local obj = Input(name) + obj.name = name + return addObject(obj) + end; + + addProgram = function(self, name) + local obj = Program(name) + obj.name = name + return addObject(obj) + end; + + addTextfield = function(self, name) + local obj = Textfield(name) + obj.name = name + return addObject(obj) + end; + + addList = function(self, name) + local obj = List(name) + obj.name = name + return addObject(obj) + end; + + addDropdown = function(self, name) + local obj = Dropdown(name) + obj.name = name + return addObject(obj) + end; + + addRadio = function(self, name) + local obj = Radio(name) + obj.name = name + return addObject(obj) + end; + + addTimer = function(self, name) + local obj = Timer(name) + obj.name = name + return addObject(obj) + end; + + addAnimation = function(self, name) + local obj = Animation(name) + obj.name = name + return addObject(obj) + end; + + addSlider = function(self, name) + local obj = Slider(name) + obj.name = name + return addObject(obj) + end; + + addScrollbar = function(self, name) + local obj = Scrollbar(name) + obj.name = name + return addObject(obj) + end; + + addFrame = function(self, name) + local obj = Frame(name, self) + obj.name = name + return addObject(obj) + end; + } + setmetatable(object, base) + + return object +end + +local updaterActive = false +function basalt.update(isActive) + parentTerminal.clear() + updaterActive = isActive or true + activeFrame:draw() + drawHelper.update() + while updaterActive do + local event, p1,p2,p3,p4 = os.pullEventRaw() -- change to raw later + if(event=="mouse_click")then activeFrame:mouseHandler(event,p1,p2,p3,p4) end + if(event=="mouse_drag")then activeFrame:mouseHandler(event,p1,p2,p3,p4) end + if(event=="mouse_up")then activeFrame:mouseHandler(event,p1,p2,p3,p4) end + if(event=="mouse_scroll")then activeFrame:mouseHandler(event,p1,p2,p3,p4) end + if(event=="key")or(event=="char")then activeFrame:keyHandler(event,p1,p2,p3,p4) end + activeFrame:eventHandler(event, p1, p2, p3, p4) + if(updaterActive)then + activeFrame:draw() + drawHelper.update() + end + end +end + +function basalt.stop() + updaterActive = false +end + +function basalt.getFrame(name) + +end + +function basalt.getActiveFrame() + return activeFrame +end + +function basalt.setActiveFrame(frame) + if(frame:getType()=="Frame")then + activeFrame = frame + return true + end + return false +end + +function basalt.createFrame(name) + local frame = Frame(name) + return frame +end + +function basalt.removeFrame() + +end + +if(basalt.debugger)then + basalt.debugFrame = basalt.createFrame("basaltDebuggingFrame"):showBar():setBackground(colors.lightGray):setBar("Debug",colors.black,colors.gray) + --basalt.debugList = basalt.debugFrame:addList("debugList"):setSize(basalt.debugFrame.w - 2, basalt.debugFrame.h - 3):setPosition(2,3):setSymbol(""):setTextAlign("left"):show() + --basalt.debugFrame:addButton("back"):setAnchor("right"):setSize(1,1):setText("\22"):onClick(function() basalt.oldFrame:show() end):setBackground(colors.red):show() + basalt.debugLabel = basalt.debugFrame:addLabel("debugLabel"):onClick(function() --[[basalt.oldFrame = activeFrame basalt.debugFrame:show()]] end):setBackground(colors.black):setForeground(colors.white):setAnchor("bottom"):show() +end + + +if(basalt.debugger)then + function basalt.debug(...) + local args = {...} + if(activeFrame.name~="basaltDebuggingFrame")then + if(activeFrame~=basalt.debugLabel.frame)then + basalt.debugLabel:setParent(activeFrame) + end + end + local str = "" + for k,v in pairs(args)do + str = str..tostring(v)..(#args~=k and ", " or "") + end + basalt.debugLabel:setText("[Debug] "..str) + -- basalt.debugList:addItem(str) + --if(#basalt.debugList.items>basalt.debugList.h)then basalt.debugList:removeItem(1) end + + basalt.debugLabel:show() + end +end + +return basalt \ No newline at end of file