Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --v3.0
- --Setup
- local List = { }
- Button = { }
- CheckBox = { }
- Label = { }
- Image = { }
- Process = { }
- Registry = { }
- TextBox = { }
- Graph = { }
- New = { }
- --Helper functions
- local copyTable
- copyTable = function(orig, boolean) --Function for coping table
- local copy
- if type(orig) == "table" then
- copy = { }
- for key, value in pairs(orig) do
- if boolean then
- copy[key] = copyTable(value, true)
- else
- copy[key] = orig[key]
- end
- end
- else
- copy = orig
- end
- return copy
- end
- local function tolines(text, w, boolean)
- local lines = { }
- if boolean then
- local i = 1
- lines[i] = ""
- for value in text:gmatch("%a+") do
- if #(lines[i]..value.." ") > w then
- i = i+1
- lines[i] = value.." "
- else
- lines[i] = lines[i]..value.." "
- end
- end
- else
- for i=1, math.ceil(#text/w) do
- lines[i] = text:sub((i-1)*w+1, i*w)
- end
- end
- return lines
- end
- local function getColourOf(hex)
- local value = tonumber(hex, 16)
- if not value then return nil end
- value = math.pow(2,value)
- return value
- end
- function Image.LoadNFT(path) --Loads NFT files
- local sFrame = 1
- local frames = { }
- frames[sFrame] = { }
- frames[sFrame].backcol = { }
- frames[sFrame].text = { }
- frames[sFrame].textcol = { }
- if fs.exists(path) then
- local file = io.open(path, "r")
- local sLine = file:read()
- local num = 1
- while sLine do
- table.insert(frames[sFrame].backcol, num, {})
- table.insert(frames[sFrame].text, num, {})
- table.insert(frames[sFrame].textcol, num, {})
- local writeIndex = 1
- local bgNext, fgNext = false, false
- local currBG, currFG = nil,nil
- for i=1,#sLine do
- local nextChar = string.sub(sLine, i, i)
- if nextChar:byte() == 30 then
- bgNext = true
- elseif nextChar:byte() == 31 then
- fgNext = true
- elseif bgNext then
- currBG = getColourOf(nextChar)
- bgNext = false
- elseif fgNext then
- currFG = getColourOf(nextChar)
- fgNext = false
- else
- if nextChar ~= " " and currFG == nil then
- currFG = colours.white
- end
- frames[sFrame].backcol[num][writeIndex] = currBG
- frames[sFrame].textcol[num][writeIndex] = currFG
- frames[sFrame].text[num][writeIndex] = nextChar
- writeIndex = writeIndex + 1
- end
- end
- num = num+1
- sLine = file:read()
- end
- file:close()
- return frames[sFrame]
- end
- end
- local function colorText(x, y, color, backColor, value) --The easy way to make colour text
- local xs, ys = term.getCursorPos()
- term.setCursorPos(x, y)
- term.setTextColor(color)
- term.setBackgroundColor(backColor)
- term.write(value)
- term.setCursorPos(xs, ys)
- end
- local function check(str, form) --Checks the format
- local result = false
- for i=1, #str do
- local n, n2 = str:find("\."..form)
- if n2 == str:len() then
- result = true
- break
- else
- str = str:sub(1, n2)
- end
- end
- return result
- end
- --Object
- local function object_set(meta, self, Error, key, value)
- if type(value) == "function" and not self[key] then
- rawset(self, key, value)
- else
- meta.__index[key] = value
- end
- local err = Error(meta.__index, self)
- if err then error(err, 3) end
- if meta.__index.Visible and meta.__index.Object ~= "process" then
- if meta.__index.Object == "check_box" then
- if meta.__index.State then self.Draw("active") else self.Draw() end
- else
- self.Draw()
- end
- end
- end
- local function object_detect(object, action, list)
- if type(list) ~= "table" and list ~= nil then
- error("Bad argument #2: event table expected, got "..type(list), 3)
- end
- if action ~= "mouse_click" and action ~= "mouse_scroll" and action ~= "mouse_drag" and action ~= "monitor_touch" and action ~= "monitor_up" and action ~= "key" then
- local var
- if type(action) == "string" then
- var = '"'..action..'"'
- else
- var = tostring(action)
- end
- error('Unregistered '..object.Object..' event: '..var, 3)
- end
- if not list then
- list = { os.pullEvent(action) }
- end
- local result = false
- local w = object.Width or 1
- local h = object.Height or 1
- if action == "key" and list[1] == "key" then
- if list[2] == object.Key then
- return true
- else
- return false
- end
- end
- local button = list.Button or 0
- if action == list[1]
- and (button == list[2] or button == 0)
- and list[3] >= object.xPos
- and list[3] <= object.xPos+w-1
- and list[4] >= object.yPos
- and list[4] <= object.yPos+h-1 then
- return true, list
- else
- return false, list
- end
- end
- do --Button
- local function button_error(object, self) --Checks errors in button
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- object.Draw = nil
- object.Set = nil
- object.Detect = nil
- object.Term = object.Term or term.current()
- object.Width = object.Width or 9
- object.Height = object.Height or 3
- object.Text = tostring(object.Text or "")
- object.TextColor = object.TextColor or colors.white
- object.BackgroundColor = object.BackgroundColor or colors.blue
- object.ActiveColor = object.ActiveColor or colors.lime
- object.InactiveColor = object.InactiveColor or colors.gray
- object.Time = object.Time or 0.3
- if object.Visible == nil then object.Visible = true end
- object.Object = "button"
- for key, value in ipairs{"xPos", "yPos", "Width", "Height", "TextColor", "BackgroundColor", "ActiveColor", "InactiveColor", "Time"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- if value ~= "Time" then
- object[value] = math.floor(object[value])
- end
- end
- end
- if type(object.Term) ~= "table" then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- else
- for key, value in pairs(term.native()) do
- if not object.Term[key] then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- end
- end
- end
- if type(object.Visible) ~= "boolean" then
- return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
- end
- end
- local function button_draw(object, state) --Draws button
- local Term = term.current()
- local color
- if Term ~= object.Term then
- term.redirect(object.Term)
- end
- local a, b = term.getTextColor(), term.getBackgroundColor()
- local x, y = term.getCursorPos()
- if state == "active" then
- color = object.ActiveColor
- elseif state == "inactive" then
- color = object.InactiveColor
- else
- color = object.BackgroundColor
- end
- if object.Width >= 1 or object.Height >= 1 then
- paintutils.drawFilledBox(object.xPos, object.yPos, object.xPos+object.Width-1, object.yPos+object.Height-1, color)
- local text = tolines(object.Text, object.Width)
- local h = #text
- if #text > object.Height then
- h = object.Height
- end
- for i=1, h do
- colorText(object.xPos+math.ceil((object.Width-1)/2-#text[i]/2), object.yPos+math.floor((object.Height-1)/2-h/2)+i, object.TextColor, color, text[i])
- end
- end
- term.setCursorPos(x, y)
- term.setBackgroundColor(b)
- term.setTextColor(a)
- if Term ~= object.Term then
- term.redirect(Term)
- end
- end
- local function button_detect(object, self, action, t)
- local boolean, var = object_detect(object, action, t)
- if boolean and object.Visible then
- self.Draw("active")
- os.sleep(object.Time)
- self.Draw()
- end
- return boolean, var
- end
- function New.Button(self, object) --Button class
- local object = copyTable(object)
- do
- local ok = button_error(object)
- if ok then error(ok ,2) end
- end
- local self, meta
- self = {
- Draw = function(state)
- button_draw(object, state)
- end;
- Detect = function(action, t)
- return button_detect(object, self, action, t)
- end
- }
- meta = {
- __index = object;
- __metatable = false;
- __private = {
- name = string.gsub(tostring(self), type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function(self, key, value)
- object_set(meta, self, button_error, key, value)
- end;
- __pairs = object_pairs;
- }
- setmetatable(self, meta)
- if object.Visible then self.Draw() end
- return self, object
- end
- end
- do --Check Box
- local function checkbox_error(object, self)
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- object.Draw = nil
- object.Set = nil
- object.Detect = nil
- object.ChangeState = nil
- object.Term = object.Term or term.current()
- object.Text = tostring(object.Text or "")
- object.Width = #object.Text+2
- object.TextColor = object.TextColor or colors.white
- object.BackgroundColor = object.BackgroundColor or colors.black
- object.BoxColor = object.BoxColor or colors.blue
- object.ActiveColor = object.ActiveColor or colors.lime
- object.InactiveColor = object.InactiveColor or colors.gray
- if object.State == nil then object.State = false end
- if object.Visible == nil then object.Visible = true end
- object.Object = "check_box"
- for key, value in ipairs{"xPos", "yPos", "Width", "TextColor", "BackgroundColor", "BoxColor", "ActiveColor", "InactiveColor"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- object[value] = math.floor(object[value])
- end
- end
- for key, value in ipairs{"Visible", "State"} do
- if type(object[value]) ~= "boolean" then
- return 'Bad argument "'..value..'": boolean expected, got '..type(object[value])
- end
- end
- if type(object.Term) ~= "table" then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- else
- for key, value in pairs(term.native()) do
- if not object.Term[key] then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- end
- end
- end
- end
- local function checkbox_draw(object, state)
- local Term = term.current()
- if Term ~= object.Term then term.redirect(object.Term) end
- local a, b = term.getTextColor(), term.getBackgroundColor()
- local x, y = term.getCursorPos()
- if state == "active" then
- textcol = object.TextColor
- backcol = object.ActiveColor
- elseif state == "inactive" then
- textcol = object.InactiveColor
- backcol = object.InactiveColor
- else
- textcol = object.TextColor
- backcol = object.BoxColor
- end
- paintutils.drawPixel(object.xPos, object.yPos, backcol)
- colorText(object.xPos+2, object.yPos, textcol, object.BackgroundColor, object.Text)
- term.setCursorPos(x, y)
- term.setTextColor(a)
- term.setBackgroundColor(b)
- if Term ~= object.Term then term.redirect(Term) end
- end
- local function checkbox_changeState(object, self, state)
- if state == nil then
- object.State = not object.State
- elseif type(state) ~= "boolean" then
- object.State = state
- else
- error("Bad argument: boolean expected, got "..type(state), 3)
- end
- if object.Visible then
- if object.State then
- self.Draw"active"
- else
- self.Draw()
- end
- end
- return object.State
- end
- local function checkbox_detect(object, self, action, t)
- local boolean, var = object_detect(object, action, t)
- if boolean then self.ChangeState() end
- return boolean, var
- end
- function New.CheckBox(self, object) --CheckBox class
- local object = copyTable(object)
- do
- local ok = checkbox_error(object)
- if ok then error(ok ,2) end
- end
- local self, meta
- self = {
- Draw = function(state)
- checkbox_draw(object, state)
- end;
- Detect = function(action, t)
- return checkbox_detect(object, self, action, t)
- end;
- ChangeState = function(state)
- return checkbox_changeState(object, self, state)
- end;
- }
- meta = {
- __index = object;
- __metatable = false;
- __private = {
- name = string.gsub(tostring(self), type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function(self, key, value)
- object_set(meta, self, checkbox_error, key, value)
- end;
- }
- setmetatable(self, meta)
- if object.Visible then if object.State then self.Draw("active") else self.Draw() end end
- return self, meta
- end
- end
- do --Label
- local function label_error(object) -- Error handing
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- object.Draw = nil
- object.Set = nil
- object.Detect = nil
- object.Term = object.Term or term.current()
- object.Text = tostring(object.Text or "")
- object.TextColor = object.TextColor or colors.white
- object.BackgroundColor = object.BackgroundColor or colors.black
- object.Position = object.Position or "middle"
- if object.Visible == nil then object.Visible = true end
- object.Object = "label"
- for key, value in ipairs{"xPos", "yPos", "TextColor", "BackgroundColor"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- object[value] = math.floor(object[value])
- end
- end
- if type(object.Term) ~= "table" then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- else
- for key, value in pairs(term.native()) do
- if not object.Term[key] then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- end
- end
- end
- if type(object.Visible) ~= "boolean" then
- return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
- end
- if object.Position ~= "right" and object.Position ~= "left" and object.Position ~= "middle" then
- return 'Argument "Position" must be "right", "left" or "middle"'
- end
- end
- local function label_draw(object) --Draws label
- local Term = term.current()
- if Term ~= object.Term then term.redirect(object.Term) end
- local a, b = term.getTextColor(), term.getBackgroundColor()
- local x, y = term.getCursorPos()
- local xPos
- if object.Position == "middle" then
- xPos = object.xPos-math.floor(#object.Text/2)
- elseif object.Position == "right" then
- xPos = object.xPos
- elseif object.Position == "left" then
- xPos = object.xPos-#object.Text+1
- end
- colorText(xPos, object.yPos, object.TextColor, object.BackgroundColor, object.Text)
- term.setCursorPos(x, y)
- term.setTextColor(a)
- term.setBackgroundColor(b)
- if Term ~= object.Term then term.redirect(Term) end
- end
- local function label_detect(object, self, action, t)
- local xPos, Width = object.xPos, object.Width
- object.Width = #object.Text
- if object.Position == "middle" then
- object.xPos = xPos-math.floor(#object.Text/2)
- elseif object.Position == "left" then
- object.xPos = object.xPos-#object.Text+1
- end
- local ok, boolean, n = pcall(object_detect, object, action, t)
- object.xPos, object.Width = xPos, Width
- if not ok then error(boolean, 3) end
- if object.Visible then self.Draw() end
- return boolean, n
- end
- function New.Label(self, object) --Label class
- local object = copyTable(object)
- do
- local ok = label_error(object)
- if ok then error(ok ,2) end
- end
- local self, meta
- self = {
- Draw = function(state)
- label_draw(object, state)
- end;
- Detect = function(action, t)
- return label_detect(object, self, t)
- end;
- }
- meta = {
- __index = object;
- __metatable = false;
- __private = {
- name = tostring(self):gsub(type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function(self, key, value)
- object_set(meta, self, label_error, key, value)
- end;
- }
- setmetatable(self, meta)
- if object.Visible then self.Draw() end
- return self, meta
- end
- end
- do --Registry
- local function registry_error(object) -- Error handing
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- if not object.Path or not object.Path:find("%a") then return "Not correct path" end
- if not fs.exists(fs.getDir(object.Path)) then
- fs.makeDir(fs.getDir(object.Path))
- end
- object.Object = "registry"
- if not object.Table then
- local file = io.open(object.Path, "r")
- if file then
- local text = file:read("*a")
- if text == "" then
- object.Table = { }
- else
- object.Table = textutils.unserialize(text)
- if not object.Table then return "Not a registry file" end
- file:close()
- end
- else
- object.Table = { }
- end
- end
- if type(object.Table) ~= "table" then
- return 'Bad argument "Table": table expected, got '..type(object.Table)
- end
- if type(object.Path) ~= "string" then
- return 'Bad argument "Path": string expected, got '..type(object.Path)
- end
- end
- local function registry_save(object)
- if not fs.exists(fs.getDir(object.Path)) then
- fs.makeDir(fs.getDir(object.Path))
- end
- local file = io.open(object.Path, "w")
- if not file then error("Have not access to the registry file", 3) end
- local ok, text = pcall(textutils.serialize, object.Table)
- if not ok then error(text, 3) end
- file:write("--Registry file\n"..text)
- file:close()
- end
- local function registry_amount(object)
- local result = 0
- for var in pairs(object.Table) do
- result = result+1
- end
- return result
- end
- local function registry_insert(object, key, value)
- if type(key) == "function" or type(value) == "function" then
- error('The type of a value can\'t be number, got '..type(key), 3)
- end
- return table.insert(object.Table, key, value)
- end
- local function registry_remove(object, key, value)
- if type(key) ~= "number" then
- error('The type of a key must be number, got '..type(key), 3)
- end
- return table.remove(object.Table, key, value)
- end
- function New.Registry(self, object) --Registry class
- local object = copyTable(object)
- if type(object) == "string" then
- object = {Path = object}
- else
- object = copyTable(object)
- end
- do
- local ok = registry_error(object)
- if ok then error(ok, 2) end
- end
- local self, meta, meta_reg = {
- ["Save"] = function()
- registry_save(object)
- end;
- ["Amount"] = function()
- return registry_amount(object)
- end;
- ["Insert"] = function(key, value)
- return registry_insert(object, key, value)
- end;
- ["Remove"] = function(object, key, value)
- return registry_remove(object, key, value)
- end;
- }
- meta = {
- __index = object;
- __private = {
- name = tostring(self):gsub(type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function()
- error("Attempt to index a registry object", 2)
- end;
- __metatable = false;
- __len = function()
- return registry_amount(object)
- end;
- }
- meta_reg = {
- __newindex = function(t, key, value)
- if type(value) == "function" then error("Couldn't serialize function", 2) end
- local save = meta_reg.__newindex
- meta_reg.__newindex = nil
- meta.__index.Table[key] = value
- meta_reg.__newindex = save
- end;
- __metatable = false
- }
- setmetatable(meta.__index.Table, meta_reg)
- setmetatable(self, meta)
- return self, meta
- end
- end
- do --Image
- local function image_error(object) --Checks errors in image
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- object.Draw = nil
- object.Set = nil
- object.Detect = nil
- object.Term = object.Term or term.current()
- object.Width = object.Width or 10
- object.Height = object.Height or 5
- object.xOffset = object.xOffset or 0
- object.yOffset = object.yOffset or 0
- object.Image = object.Image or { }
- object.BackgroundColor = object.BackgroundColor or 0
- object.BorderColor = object.BorderColor or colors.blue
- object.LinesColor = object.LinesColor or colors.white
- object.BorderStyle = object.BorderStyle or "none"
- if object.Visible == nil then object.Visible = true end
- object.Object = "image"
- for key, value in ipairs{"xPos", "yPos", "Width", "Height", "xOffset", "yOffset", "BackgroundColor", "BorderColor", "LinesColor"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- object[value] = math.floor(object[value])
- end
- end
- if type(object.Image) == "string" then
- local ok
- object.Path = object.Image
- if check(object.Path, "nft") then
- ok, object.Image = pcall(Image.LoadNFT, object.Path)
- else
- object.Image = { }
- ok, object.Image.backcol = pcall(paintutils.loadImage, object.Path)
- end
- if not ok then
- return 'Couldn\'t find an image file by the path'
- end
- elseif type(object.Image) == "table" then
- if not object.Image.backcol then
- object.Image = {backcol = object.Image}
- end
- else
- return 'Bad argument "Image": table or string expected, got '..type(object.Image)
- end
- if object.BorderStyle ~= "none" and object.BorderStyle ~= "box" and object.BorderStyle ~= "lines" then
- return 'The argument "BorderStyle" must be "none", "box" or "lines", got "'..object.BorderStyle..'"'
- end
- if type(object.Term) ~= "table" then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- else
- for key, value in pairs(term.native()) do
- if not object.Term[key] then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- end
- end
- end
- if type(object.Visible) ~= "boolean" then
- return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
- end
- for key, value in pairs(object.Image) do
- for i=1, #object.Image[key] do
- local var = table.maxn(object.Image[key][i]) or 0
- for k=1, tonumber(var) do
- if key == "backcol" then
- object.Image[key][i][k] = object.Image[key][i][k] or 0
- elseif key == "text" then
- object.Image[key][i][k] = object.Image[key][i][k] or " "
- elseif key == "textcol" then
- object.Image[key][i][k] = object.Image[key][i][k] or colors.white
- end
- end
- end
- end
- end
- local function image_draw(object) --Draw image
- if object.Width < 1 or object.Height < 1 then
- return
- end
- local Term = term.current()
- local color
- if Term ~= object.Term then
- term.redirect(object.Term)
- end
- local a, b = term.getTextColor(), term.getBackgroundColor()
- local x, y = term.getCursorPos()
- if object.BackgroundColor ~= 0 then
- paintutils.drawFilledBox(object.xPos, object.yPos, object.xPos+object.Width-1, object.yPos+object.Height-1, object.BackgroundColor)
- end
- for i=object.yOffset, object.Height do
- if object.Image.backcol[i] then
- for k=object.xOffset, object.Width do
- if object.Image.backcol[i][k] and object.Image.backcol[i][k] ~= 0 then
- local xPos, yPos = object.xPos+k-object.xOffset-1, object.yPos+i-object.yOffset-1
- if xPos >= object.xPos
- and xPos <= object.xPos+object.Width-1
- and yPos >= object.yPos
- and yPos <= object.yPos+object.Height-1 then
- term.setCursorPos(xPos, yPos)
- term.setBackgroundColor(object.Image.backcol[i][k])
- if object.Image.text and object.Image.text[i] and object.Image.text[i][k] then
- term.setTextColor(object.Image.textcol[i][k])
- term.write(object.Image.text[i][k])
- else
- term.write(" ")
- end
- end
- end
- end
- end
- end
- if object.BorderStyle == "box" then
- paintutils.drawBox(object.xPos-1, object.yPos-1, object.xPos+object.Width, object.yPos+object.Height, object.BorderColor)
- elseif object.BorderStyle == "lines" then
- term.setBackgroundColor(object.BorderColor)
- term.setTextColor(object.LinesColor)
- for i=0, object.Width-1 do
- term.setCursorPos(object.xPos+i, object.yPos-1)
- term.write("-")
- term.setCursorPos(object.xPos+i, object.yPos+object.Height)
- term.write("-")
- end
- for i=0, object.Height-1 do
- term.setCursorPos(object.xPos-1, object.yPos+i)
- term.write("|")
- term.setCursorPos(object.xPos+object.Width, object.yPos+i)
- term.write("|")
- end
- term.setCursorPos(object.xPos-1, object.yPos-1)
- term.write("+")
- term.setCursorPos(object.xPos+object.Width, object.yPos-1)
- term.write("+")
- term.setCursorPos(object.xPos-1, object.yPos+object.Height)
- term.write("+")
- term.setCursorPos(object.xPos+object.Width, object.yPos+object.Height)
- term.write("+")
- end
- term.setCursorPos(x, y)
- term.setBackgroundColor(b)
- term.setTextColor(a)
- if Term ~= object.Term then
- term.redirect(Term)
- end
- end
- local function image_detect(object, self, action, t) --Detects events
- local boolean, var = object_detect(action, object, t)
- if object.Visible and boolean then
- self.Draw()
- end
- return boolean, var
- end
- function New.Image(self, object) --Image class
- local object = copyTable(object)
- do
- local ok = image_error(object)
- if ok then error(ok, 2) end
- end
- local self, meta = {
- ["Draw"] = function()
- image_draw(object)
- end;
- ["Detect"] = function(action, t)
- return image_detect(object, self, action, t)
- end;
- }
- meta = {
- __index = object;
- __metatable = false;
- __private = {
- name = tostring(self):gsub(type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function(self, key, value)
- object_set(meta, self, image_error, key, value)
- end;
- }
- setmetatable(self, meta)
- if object.Visible then self.Draw() end
- return self, meta
- end
- end
- do --Process
- local function process_switch( ... )
- local n = ...
- if type(n) ~= "number" then
- error("Bad argument: number expected, got "..type(n), 2)
- end
- return coroutine.yield("switch", ... )
- end
- local function process_exit( ... )
- return coroutine.yield("stop", ... )
- end
- local function process_kill( ... )
- local n = ...
- if type(n) ~= "number" then
- error("Bad argument: number expected, got "..type(n), 2)
- end
- return coroutine.yield("kill", ... )
- end
- local function process_add(object)
- if Type(object) ~= "process" then
- error("Bad argument: process expected, got "..Type(object), 2)
- end
- return coroutine.yield("add", object)
- end
- local function process_amount()
- return coroutine.yield "amount"
- end
- local function process_status(n)
- if type(n) ~= "number" then
- error("Bad argument: number expected, got "..type(n), 2)
- end
- return coroutine.yield("status", n)
- end
- local function process_call()
- error("You can't do it inside the process!", 2)
- end
- local function process_error(object, self, b) --Checks errors in button
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- local function process_coroutine(args)
- if not args[1] then args = object.Args end
- object.Env.shell = shell
- object.Env.multishell = multishell
- object.Env.term = term
- object.Env.term.native = term.current
- object.Env.Process.SetWindow = self.SetWindow
- setmetatable(object.Env.Process, {
- __index = self;
- __newindex = process_call;
- __tostring = function()
- return tostring(self)
- end;
- __metatable = false;
- })
- setmetatable(object.Env, {__index = _G})
- local foo
- do local err
- if type(object.Process) == "function" then
- foo = object.Process
- else
- local file = io.open(object.Process)
- if file then
- foo, err = load(file:read "*a", fs.getName(object.Process), "t", object.Env)
- else
- err = "file not found"
- end
- if not foo then error('Error in program file: '..err, 0) end
- end end
- object.State = true
- local var = { pcall(foo, unpack(args)) }
- object.State = false
- if not var[1] then error("Error in the running process: "..var[2], 0) end
- return select(2, unpack(var))
- end
- object.Term = object.Term or term.current()
- if type(object.Term) ~= "table" then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- else
- for key, value in pairs(term.native()) do
- if not object.Term[key] then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- end
- end
- end
- object.Env = {Process = {
- Exit = process_exit;
- Switch = process_switch;
- Kill = process_kill;
- Run = process_call;
- Rebuild = process_call;
- Add = process_add;
- Amount = process_amount;
- Status = process_status;
- Current = 1;
- }}
- object.Resume = nil
- object.Set = nil
- object.Run = nil
- local w, h = object.Term.getSize()
- object.xPos = object.xPos or 1
- object.yPos = object.yPos or 1
- object.Width = object.Width or w
- object.Height = object.Height or h
- object.Visible = object.Visible or true
- object.Args = object.Args or { }
- object.Object = "process"
- object.State = false
- object.UseWindow = object.UseWindow or false
- object.Coroutine = coroutine.create(process_coroutine)
- for key, value in ipairs{"xPos", "yPos", "Width", "Height"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- if value ~= "Time" then
- object[value] = math.floor(object[value])
- end
- end
- end
- for key, value in ipairs{"UseWindow", "Visible"} do
- if type(object[value]) ~= "boolean" then
- return 'Bad argument "'..value..'": boolean expected, got '..type(object[value])
- end
- end
- if type(object.Process) == "string" then
- local file = io.open(object.Process)
- if not file then return "Couldn't find a file by the path" end
- file:close()
- elseif type(object.Process) == "function" then
- else
- return 'Bad argument "Process": path or function expected, got '..type(object.Process)
- end
- if object.UseWindow then
- if not b and object.Window then
- object.Window.reposition(object.xPos, object.yPos, object.Width, object.Height)
- object.Term = object.Window.parent
- else
- object.Window = window.create(object.Term, object.xPos, object.yPos, object.Width, object.Height, false)
- object.Window.parent = object.Term
- end
- end
- end
- local process_dead = coroutine.create(function() end)
- coroutine.resume(process_dead)
- local function process_run(object, args)
- local x, y, Term
- if object.UseWindow then
- Term = term.current()
- x, y = term.getCursorPos()
- term.redirect(object.Window)
- if object.Visible then
- object.Window.setVisible(object.Visible)
- object.Window.redraw()
- object.Window.restoreCursor()
- end
- end
- local var = { coroutine.resume(object.Coroutine, args) }
- while coroutine.status(object.Coroutine) == "suspended" do
- if var[2] == "stop" then
- var = { select(3, unpack(var)) }
- table.insert(var, 1, true)
- break
- elseif var[2] == "switch" then
- var[2] = false
- table.remove(var, 3)
- elseif var[2] == "add" then
- var[2] = false
- elseif var[2] == "kill" then
- if var[3] == 1 then
- var = { }
- object.Coroutine = process_dead
- break
- else
- var[2] = false
- table.remove(var, 3)
- end
- else
- var = { coroutine.yield(var[2]) }
- table.insert(var, 1, true)
- end
- if object.UseWindow and (var[2] == "mouse_click" or var[2] == "mouse_drag" or var[2] == "mouse_scroll" or var[2] == "mouse_up") then
- var[4], var[5] = var[4]-object.xPos+1, var[5]-object.yPos+1
- end
- var = { coroutine.resume(object.Coroutine, select(2, unpack(var))) } --unload"object"Object=require"object3"Process=Object.Process{Process="prog",Visible=false}
- end
- if object.UseWindow then
- term.redirect(Term)
- term.setCursorPos(x, y)
- end
- return unpack(var)
- end
- local function process_setWindow(object, new)
- if type(new) ~= "table" then
- error('This method must be called with table argument!', 3)
- end
- if new.Visible ~= nil then object.Visible = new.Visible end
- if new.UseWindow ~= nil then object.UseWindow = new.UseWindow end
- for key, value in ipairs{"xPos", "yPos", "Width", "Height"} do
- object[value] = new[value] or object[value]
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- error('Bad argument "'..value..'": number expected, got '..var, 3)
- end
- if value ~= "Time" then
- object[value] = math.floor(object[value])
- end
- end
- end
- for key, value in ipairs{"UseWindow", "Visible"} do
- if type(object[value]) ~= "boolean" then
- error('Bad argument "'..value..'": boolean expected, got '..type(object[value]), 3)
- end
- end
- object.Window.reposition(object.xPos, object.yPos, object.Width, object.Height)
- end
- function New.Process(self, object) --Process class
- local object = copyTable(object)
- local self, meta = {
- ["Run"] = function( ... )
- return process_run(object, { ... })
- end;
- ["SetWindow"] = function(t)
- process_setWindow(object, t)
- end;
- ["SetArgs"] = function( ... )
- object.Args = { ... }
- end;
- ["Rebuild"] = function()
- process_error(object, self)
- end;
- }
- do
- local ok = process_error(object, self, true)
- if ok then error(ok, 2) end
- end
- meta = {
- __index = object;
- __metatable = false;
- __private = {
- name = tostring(self):gsub(type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function(self, key, value)
- if key == "Coroutine" then
- object.Coroutine = value
- else
- object_set(meta, self, process_error, key, value)
- end
- end;
- }
- setmetatable(self, meta)
- return self, meta
- end
- function Process.Multithread(processes) --Parallel controller
- processes = copyTable(processes)
- if type(processes.Parallel) ~= 'boolean' and processes.Parallel ~= nil then
- error("Bad argument \"Parallel\": boolean expected, got "..type(processes.Parallel), 2)
- end
- processes.Parallel = processes.Parallel == true
- for key, value in ipairs(processes) do
- if not (type(value) == "table" and value.Object == "process") then
- error("Bad argument #"..key..": process expected, got "..type(value), 2)
- end
- if coroutine.status(value.Coroutine) == "dead" then
- error("Cannot resume dead process #"..key, 2)
- end
- value.Env.Process.Current = key
- end
- local result = {}
- local process = processes[1]
- local Term = term.current()
- local cx, cy = term.getCursorPos()
- local n, var = 1, { }
- while true do
- if process.UseWindow then
- term.redirect(process.Window)
- if process.Visible then
- term.setVisible(true)
- term.redraw()
- term.restoreCursor()
- end
- else
- term.redirect(Term)
- if term.redraw then term.redraw() end
- end
- while coroutine.status(process.Coroutine) == "suspended" do
- if not process.State then
- var = { coroutine.resume(process.Coroutine, { }) }
- end
- if var[2] == "stop" then
- result[n] = { table.unpack(var, 3) }
- process.Coroutine = process_dead
- var[2] = "stopped"
- table.insert(var, 3, n)
- n=n+1
- break
- elseif var[2] == "kill" then
- result[var[3]] = { }
- processes[var[3]].Coroutine = process_dead
- var = {true, "killed", var[3]}
- if n == var[3] then break end
- elseif var[2] == "switch" then
- var[2] = "switched"
- n, var[3] = var[3], n
- break
- elseif var[2] == "add" then
- var[2] = "added"
- table.insert(processes, var[3])
- var[3].Env.Process.Current = #processes
- var[3] = nil
- elseif var[2] == "amount" then
- var[2] = #processes
- elseif var[2] == "status" then
- if processes[var[3]] then
- if n == var[3] then
- var[2] = "running"
- else
- var[2] = coroutine.status(processes[var[3]].Coroutine)
- end
- else
- var[2] = false
- end
- var[3] = nil
- elseif var[2] == 'stopped' or var[2] == 'killed' or var[2] == 'switched' then
- else
- var = { coroutine.yield(var[2]) }
- table.insert(var, 1, true)
- if process.UseWindow and var[2]:find("mouse") then
- var[4], var[5] = var[4]-process.xPos+1, var[5]-process.yPos+1
- end
- end
- table.insert(var, 2, process.Coroutine)
- var = { coroutine.resume(table.unpack(var, 2)) }
- if coroutine.status(process.Coroutine) == "dead" then
- result[n] = { table.unpack(var, 2) }
- table.insert(var, 2, "stopped")
- table.insert(var, 3, n)
- n=n+1
- break
- end
- end
- if process.UseWindow then
- term.setVisible(true)
- term.redirect(Term)
- if term.redraw then term.redraw() end
- end
- if n > #processes then
- n = 1
- end
- if coroutine.status(processes[n].Coroutine) == "dead" then
- local a = true
- n=0
- repeat
- n=n+1
- if n > #processes then
- a = false
- break
- end
- until coroutine.status(processes[n].Coroutine) == "suspended"
- if not a then break end
- end
- process = processes[n]
- end
- return table.unpack(result)
- end
- function Process.Run(process, ... )
- return Process{Process = process, Args = { ... }}.Run()
- end
- end
- do --Text Box
- local function textbox_error(object, self) --Checks errors in text box
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- object.Draw = nil
- object.Set = nil
- object.Detect = nil
- object.Term = object.Term or term.current()
- object.Width = object.Width or 9
- object.Height = object.Height or 1
- object.Text = tostring(object.Text or "")
- object.TextColor = object.TextColor or colors.black
- object.BackgroundColor = object.BackgroundColor or colors.white
- if object.Visible == nil then object.Visible = true end
- if object.Words == nil then object.Words = true end
- object.Object = "text_box"
- for key, value in ipairs{"xPos", "yPos", "Width", "TextColor", "BackgroundColor"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- object[value] = math.floor(object[value])
- end
- end
- if type(object.Term) ~= "table" then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- else
- for key, value in pairs(term.native()) do
- if not object.Term[key] then
- return 'Bad argument "Term": term object expected, got '..type(object.Term)
- end
- end
- end
- if type(object.Visible) ~= "boolean" then
- return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
- end
- end
- local function count(object, mode)
- local tText, sText = {""}, object.Text
- while sText:len() > 0 and #tText <= object.Height do
- local whitespace = sText:match("^[ \t]+")
- if whitespace then
- tText[#tText] = tText[#tText]..whitespace
- sText = sText:sub(string.len(whitespace)+1)
- end
- local newline = sText:match("^\n")
- if newline then
- tText[#tText+1] = ""
- sText = sText:sub(2)
- end
- local text = sText:match("^[^ \t\n]+")
- if text then
- sText = sText:sub(text:len()+1)
- if text:len() > object.Width and not mode then
- local n = #tText
- local text = tText[n]..text
- tText[n] = nil
- for i=1, math.ceil(#text/object.Width+1) do
- if #tText > object.Height then break end
- tText[#tText+1] = text:sub((i-1)*object.Width+1, i*object.Width)
- end
- if tText[#tText] == "" then tText[#tText] = nil end
- else
- tText[#tText] = tText[#tText]..text
- end
- end
- end
- for i=object.Height+1, #tText do
- tText[i] = nil
- end
- return tText
- end
- local function textbox_draw(object) --Draws text box
- local Term = term.current()
- if Term ~= object.Term then
- term.redirect(object.Term)
- end
- local a, b = term.getTextColor(), term.getBackgroundColor()
- local cx, cy = term.getCursorPos()
- --
- term.setTextColor(object.TextColor)
- paintutils.drawFilledBox(object.xPos, object.yPos, object.xPos+object.Width-1, object.yPos+object.Height-1, object.BackgroundColor)
- for key, value in next, count(object) do
- term.setCursorPos(object.xPos, object.yPos-1+key)
- term.write(value)
- end
- --
- term.setCursorPos(cx, cy)
- term.setBackgroundColor(b)
- term.setTextColor(a)
- if Term ~= object.Term then
- term.redirect(Term)
- end
- end
- local function textbox_detect(object, action, event)
- --unload"object"local t={os.pullEvent"mouse_click"}t.TextBox=true term.clear() require"object".New.TextBox{xPos=5,yPos=5,Width=13,Height=5,Text=text}.Detect("mouse_click",t)
- local result, n = object_detect(object, action, event)
- local cx, cy = term.getCursorPos()
- local x, y
- local text, posit, totext
- if result then
- if event.TextBox and action ~= "key" then
- text = count(object)
- function posit(x, y, b)
- local a
- while not text[y-object.yPos+1] do
- y = y-1
- a = true
- end
- local w = #(text[y-object.yPos+1] or "")+1
- if b and x-object.xPos+1 > w then
- y = y+1
- if not text[y-object.yPos+1] then
- y = object.yPos
- end
- x = object.xPos
- elseif b and x < object.xPos then
- y = y-1
- if not text[y-object.yPos+1] then
- y = #text+object.yPos-1
- end
- local w = #(text[y-object.yPos+1] or "")+5
- if w == object.xPos+object.Width then
- x = w-1
- else
- x = w
- end
- elseif x == object.xPos+object.Width then
- y = y+1
- x = object.xPos
- elseif x-object.xPos+1 > w or a then
- x = w+object.xPos-1
- end
- term.setCursorPos(x, y)
- return x-object.xPos+1, y-object.yPos+1
- end
- function totext(tText)
- local text = ""
- for _, value in next, tText do
- text = text.."\n"..value
- end
- return text
- end
- x, y = posit(t[3], t[4])
- else
- if object.Visible then textbox_draw(object) end
- return result, n
- end
- else
- return result, n
- end
- local color = term.getTextColor()
- term.setCursorBlink(true)
- term.setTextColor(object.TextColor)
- while true do
- event = { os.pullEvent() }
- if event[1] == "mouse_click" then
- local ok, n = object_detect(object, event)
- if ok then
- if n == 1 then
- x, y = posit(event[3], event[4])
- end
- else
- break
- end
- end
- if event[1] == "char" then
- local text2 = count(object, true)
- local x,y = term.getCursorPos()
- term.setCursorPos(1,object.yPos+2)
- term.setCursorPos(x,y)
- textbox_draw(object)
- end
- if event[1] == "key" then
- local x, y = term.getCursorPos()
- if event[2] == 200 then
- if select(2, term.getCursorPos()) == object.yPos then
- posit(x, object.yPos+object.Height-1)
- else
- posit(x, y-1)
- end
- elseif event[2] == 208 then
- if select(2, term.getCursorPos()) == object.yPos+object.Height-1 then
- posit(x, object.yPos)
- elseif not text[y-object.yPos+2] then
- posit(x, object.yPos)
- else
- posit(x, y+1)
- end
- elseif event[2] == 205 then
- posit(x+1, y, 1)
- elseif event[2] == 203 then
- posit(x-1, y, 1)
- end
- end
- end
- term.setTextColor(color)
- term.setCursorBlink(false)
- term.setCursorPos(cx,cy)
- end
- function New.TextBox(self, object) --Text box class
- local object = copyTable(object)
- do
- local err = textbox_error(object)
- if err then error(err, 2) end
- end
- local self, meta = {
- ["Draw"] = function()
- textbox_draw(object)
- end;
- ["Detect"] = function(t)
- return textbox_detect(object, action, t)
- end;
- }
- meta = {
- __index = object;
- __newindex = function(self, key, value)
- object_set(meta, self, process_error, key, value)
- end;
- __private = {
- name = tostring(self):gsub(type(self), object.Object)
- };
- __metatable = false;
- __tostring = function()
- return meta.__private.name
- end;
- }
- setmetatable(self, meta)
- if object.Visible then textbox_draw(object) end
- return self, meta
- end
- end
- do --Graph
- local function graph_error(object) --Graph
- if type(object) ~= "table" then return 'Class must be called with table argument!' end
- object.Object = "graph"
- object.Factor = object.Factor or 20
- object.Size = object.Size or 9
- object.Color = object.Color or colors.white
- object.AxisColor = object.AxisColor or colors.gray
- object.BackgroundColor = object.BackgroundColor or colors.black
- if object.Axis == nil then object.Axis = true end
- if type(object.Function) ~= "function" then
- return 'Bad argument "Function": function expected, got '..type(object.Function)
- end
- for key, value in ipairs{"Factor", "Size", "Color", "AxisColor", "BackgroundColor"} do
- if type(object[value]) ~= "number" then
- local var = type(object[value])
- object[value] = tonumber(object[value])
- if not object[value] then
- return 'Bad argument "'..value..'": number expected, got '..var
- end
- object[value] = math.floor(object[value])
- end
- end
- if type(object.Axis) ~= "boolean" then
- return 'Bad argument "Axis": boolean expected, got '..type(object.Axis)
- end
- end
- local function graph_getImage(object, self)
- local image = { }
- for y=1, 2*object.Size+1 do
- image[y] = { }
- end
- for x=-math.modf(object.Size*object.Factor), math.modf(object.Size*object.Factor) do
- ok, y = pcall(object.Function, x/object.Factor, self)
- if not ok or type(y) ~= "number" then
- error("Error in graph function: "..y, 2)
- end
- y = math.floor(object.Size-math.modf(y))+1
- x2 = math.modf(x/object.Factor)+object.Size+1
- if y >= 1 and y <= 2*object.Size+1 then
- image[y][x2] = object.Color
- end
- end
- if object.Axis then
- image = {
- backcol = image;
- text = { };
- textcol = { };
- }
- for y=1, object.Size*2+1 do
- image.textcol[y] = { }
- image.text[y] = { }
- image.textcol[y][object.Size+1] = object.AxisColor
- image.text[y][object.Size+1] = "|"
- image.backcol[y][object.Size+1] = image.backcol[y][object.Size+1] or object.BackgroundColor
- end
- for x=1, object.Size*2+1 do
- image.textcol[object.Size+1][x] = object.AxisColor
- image.text[object.Size+1][x] = "-"
- image.backcol[object.Size+1][x] = image.backcol[object.Size+1][x] or object.BackgroundColor
- end
- image.text[object.Size+1][object.Size+1] = "+"
- else
- for y=1, table.maxn(image) do
- image[y] = image[y] or { }
- for x=1, table.maxn(image[y]) do
- image[y][x] = image[y][x] or 0
- end
- end
- end
- return image
- end
- function New.Graph(self, object) --Graph class
- local object = copyTable(object)
- do
- local err = graph_error(object)
- if err then error(err, 2) end
- end
- local self, meta
- self = {
- GetImage = function()
- return graph_getImage(object, self)
- end;
- }
- meta = {
- __index = object;
- __metatable = false;
- __call = self.GetImage;
- __private = {
- name = tostring(self):gsub(type(self), object.Object)
- };
- __tostring = function()
- return meta.__private.name
- end;
- __newindex = function(self, key, value)
- object_set(meta, self, process_error, key, value)
- end;
- }
- setmetatable(self, meta)
- return self, meta
- end
- end
- do
- local function __newindex(self, key, value)
- error("index expected, got class", 2)
- end
- local button_meta
- button_meta = {
- __call = New.Button;
- name = tostring(Button):gsub(type(Button), "class");
- __tostring = function()
- return button_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(Button, button_meta)
- local checkbox_meta
- checkbox_meta = {
- __call = New.CheckBox;
- name = tostring(CheckBox):gsub(type(CheckBox), "class");
- __tostring = function()
- return checkbox_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(CheckBox, checkbox_meta)
- local label_meta
- label_meta = {
- __call = New.Label;
- name = tostring(Label):gsub(type(Label), "class");
- __tostring = function()
- return label_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(Label, label_meta)
- local image_meta
- image_meta = {
- __call = New.Image;
- name = tostring(Image):gsub(type(Image), "class");
- __tostring = function()
- return image_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(Image, image_meta)
- local registry_meta
- registry_meta = {
- __call = New.Registry;
- name = tostring(Registry):gsub(type(Registry), "class");
- __tostring = function()
- return registry_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(Registry, registry_meta)
- local textbox_meta
- textbox_meta = {
- __call = New.TextBox;
- name = tostring(TextBox):gsub(type(TextBox), "class");
- __tostring = function()
- return textbox_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(TextBox, textbox_meta)
- local graph_meta
- graph_meta = {
- __call = New.Graph;
- name = tostring(Graph):gsub(type(Graph), "class");
- __tostring = function()
- return graph_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(Graph, graph_meta)
- local process_meta
- process_meta = {
- __call = New.Process;
- name = tostring(Process):gsub(type(Process), "class");
- __tostring = function()
- return process_meta.name
- end;
- __metatable = false;
- __newindex = __newindex;
- }
- setmetatable(Process, process_meta)
- end
- Type = function(object)
- if type(object) == "table" and object.Object then
- return object.Object
- else
- return type(object)
- end
- end
- New = nil
- local meta
- meta = {
- __metatable = false;
- name = tostring(getfenv()):gsub("table", "module");
- __tostring = function()
- return meta.name
- end;
- __index = _G;
- __newindex = function()
- error("You haven't access for this!", 2)
- end;
- }
- setmetatable(getfenv(), meta)
Advertisement
Add Comment
Please, Sign In to add comment