Ktlo

Computer Craft Object API v3.0

Jul 13th, 2015
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 48.30 KB | None | 0 0
  1. --v3.0
  2. --Setup
  3. local List = { }
  4. Button = { }
  5. CheckBox = { }
  6. Label = { }
  7. Image = { }
  8. Process = { }
  9. Registry = { }
  10. TextBox = { }
  11. Graph = { }
  12. New = { }
  13. --Helper functions
  14. local copyTable
  15. copyTable = function(orig, boolean) --Function for coping table
  16.     local copy
  17.     if type(orig) == "table" then
  18.         copy = { }
  19.         for key, value in pairs(orig) do
  20.             if boolean then
  21.                 copy[key] = copyTable(value, true)
  22.             else
  23.                 copy[key] = orig[key]
  24.             end
  25.         end
  26.     else
  27.         copy = orig
  28.     end
  29.     return copy
  30. end
  31. local function tolines(text, w, boolean)
  32.     local lines = { }
  33.     if boolean then
  34.         local i = 1
  35.         lines[i] = ""
  36.         for value in text:gmatch("%a+") do
  37.             if #(lines[i]..value.." ") > w then
  38.                 i = i+1
  39.                 lines[i] = value.." "
  40.             else
  41.                 lines[i] = lines[i]..value.." "
  42.             end
  43.         end
  44.     else
  45.         for i=1, math.ceil(#text/w) do
  46.             lines[i] = text:sub((i-1)*w+1, i*w)
  47.         end
  48.     end
  49.     return lines
  50. end
  51. local function getColourOf(hex)
  52.     local value = tonumber(hex, 16)
  53.     if not value then return nil end
  54.     value = math.pow(2,value)
  55.     return value
  56. end
  57. function Image.LoadNFT(path) --Loads NFT files
  58.     local sFrame = 1
  59.     local frames = { }
  60.     frames[sFrame] = { }
  61.     frames[sFrame].backcol = { }
  62.     frames[sFrame].text = { }
  63.     frames[sFrame].textcol = { }
  64.     if fs.exists(path) then
  65.         local file = io.open(path, "r")
  66.         local sLine = file:read()
  67.         local num = 1
  68.         while sLine do
  69.             table.insert(frames[sFrame].backcol, num, {})
  70.             table.insert(frames[sFrame].text, num, {})
  71.             table.insert(frames[sFrame].textcol, num, {})
  72.             local writeIndex = 1
  73.             local bgNext, fgNext = false, false
  74.             local currBG, currFG = nil,nil
  75.             for i=1,#sLine do
  76.                 local nextChar = string.sub(sLine, i, i)
  77.                 if nextChar:byte() == 30 then
  78.                     bgNext = true
  79.                 elseif nextChar:byte() == 31 then
  80.                     fgNext = true
  81.                 elseif bgNext then
  82.                     currBG = getColourOf(nextChar)
  83.                     bgNext = false
  84.                 elseif fgNext then
  85.                     currFG = getColourOf(nextChar)
  86.                     fgNext = false
  87.                 else
  88.                     if nextChar ~= " " and currFG == nil then
  89.                         currFG = colours.white
  90.                     end
  91.                     frames[sFrame].backcol[num][writeIndex] = currBG
  92.                     frames[sFrame].textcol[num][writeIndex] = currFG
  93.                     frames[sFrame].text[num][writeIndex] = nextChar
  94.                     writeIndex = writeIndex + 1
  95.                 end
  96.             end
  97.             num = num+1
  98.             sLine = file:read()
  99.         end
  100.         file:close()
  101.         return frames[sFrame]
  102.     end
  103. end
  104. local function colorText(x, y, color, backColor, value) --The easy way to make colour text
  105.     local xs, ys = term.getCursorPos()
  106.     term.setCursorPos(x, y)
  107.     term.setTextColor(color)
  108.     term.setBackgroundColor(backColor)
  109.     term.write(value)
  110.     term.setCursorPos(xs, ys)
  111. end
  112. local function check(str, form) --Checks the format
  113.     local result = false
  114.     for i=1, #str do
  115.         local n, n2 = str:find("\."..form)
  116.         if n2 == str:len() then
  117.             result = true
  118.             break
  119.         else
  120.             str = str:sub(1, n2)
  121.         end
  122.     end
  123.     return result
  124. end
  125. --Object
  126. local function object_set(meta, self, Error, key, value)
  127.     if type(value) == "function" and not self[key] then
  128.         rawset(self, key, value)
  129.     else
  130.         meta.__index[key] = value
  131.     end
  132.     local err = Error(meta.__index, self)
  133.     if err then error(err, 3) end
  134.     if meta.__index.Visible and meta.__index.Object ~= "process" then
  135.         if meta.__index.Object == "check_box" then
  136.             if meta.__index.State then self.Draw("active") else self.Draw() end
  137.         else
  138.             self.Draw()
  139.         end
  140.     end
  141. end
  142. local function object_detect(object, action, list)
  143.     if type(list) ~= "table" and list ~= nil then
  144.         error("Bad argument #2: event table expected, got "..type(list), 3)
  145.     end
  146.     if action ~= "mouse_click" and action ~= "mouse_scroll" and action ~= "mouse_drag" and action ~= "monitor_touch" and action ~= "monitor_up" and action ~= "key" then
  147.         local var
  148.         if type(action) == "string" then
  149.             var = '"'..action..'"'
  150.         else
  151.             var = tostring(action)
  152.         end
  153.         error('Unregistered '..object.Object..' event: '..var, 3)
  154.     end
  155.     if not list then
  156.         list = { os.pullEvent(action) }
  157.     end
  158.     local result = false
  159.     local w = object.Width or 1
  160.     local h = object.Height or 1
  161.     if action == "key" and list[1] == "key" then
  162.         if list[2] == object.Key then
  163.             return true
  164.         else
  165.             return false
  166.         end
  167.     end
  168.     local button = list.Button or 0
  169.     if action == list[1]
  170.     and (button == list[2] or button == 0)
  171.     and list[3] >= object.xPos
  172.     and list[3] <= object.xPos+w-1
  173.     and list[4] >= object.yPos
  174.     and list[4] <= object.yPos+h-1 then
  175.         return true, list
  176.     else
  177.         return false, list
  178.     end
  179. end
  180. do --Button
  181. local function button_error(object, self) --Checks errors in button
  182.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  183.     object.Draw = nil
  184.     object.Set = nil
  185.     object.Detect = nil
  186.     object.Term = object.Term or term.current()
  187.     object.Width = object.Width or 9
  188.     object.Height = object.Height or 3
  189.     object.Text = tostring(object.Text or "")
  190.     object.TextColor = object.TextColor or colors.white
  191.     object.BackgroundColor = object.BackgroundColor or colors.blue
  192.     object.ActiveColor = object.ActiveColor or colors.lime
  193.     object.InactiveColor = object.InactiveColor or colors.gray
  194.     object.Time = object.Time or 0.3
  195.     if object.Visible == nil then object.Visible = true end
  196.     object.Object = "button"
  197.     for key, value in ipairs{"xPos", "yPos", "Width", "Height", "TextColor", "BackgroundColor", "ActiveColor", "InactiveColor", "Time"} do
  198.         if type(object[value]) ~= "number" then
  199.             local var = type(object[value])
  200.             object[value] = tonumber(object[value])
  201.             if not object[value] then
  202.                 return 'Bad argument "'..value..'": number expected, got '..var
  203.             end
  204.             if value ~= "Time" then
  205.                 object[value] = math.floor(object[value])
  206.             end
  207.         end
  208.     end
  209.     if type(object.Term) ~= "table" then
  210.         return 'Bad argument "Term": term object expected, got '..type(object.Term)
  211.     else
  212.         for key, value in pairs(term.native()) do
  213.             if not object.Term[key] then
  214.                 return 'Bad argument "Term": term object expected, got '..type(object.Term)
  215.             end
  216.         end
  217.     end
  218.     if type(object.Visible) ~= "boolean" then
  219.         return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
  220.     end
  221. end
  222. local function button_draw(object, state) --Draws button
  223.     local Term = term.current()
  224.     local color
  225.     if Term ~= object.Term then
  226.         term.redirect(object.Term)
  227.     end
  228.     local a, b = term.getTextColor(), term.getBackgroundColor()
  229.     local x, y = term.getCursorPos()
  230.     if state == "active" then
  231.         color = object.ActiveColor
  232.     elseif state == "inactive" then
  233.         color = object.InactiveColor
  234.     else
  235.         color = object.BackgroundColor
  236.     end
  237.     if object.Width >= 1 or object.Height >= 1 then
  238.         paintutils.drawFilledBox(object.xPos, object.yPos, object.xPos+object.Width-1, object.yPos+object.Height-1, color)
  239.         local text = tolines(object.Text, object.Width)
  240.         local h = #text
  241.         if #text > object.Height then
  242.             h = object.Height
  243.         end
  244.         for i=1, h do
  245.             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])
  246.         end
  247.     end
  248.     term.setCursorPos(x, y)
  249.     term.setBackgroundColor(b)
  250.     term.setTextColor(a)
  251.     if Term ~= object.Term then
  252.         term.redirect(Term)
  253.     end
  254. end
  255. local function button_detect(object, self, action, t)
  256.     local boolean, var = object_detect(object, action, t)
  257.     if boolean and object.Visible then
  258.         self.Draw("active")
  259.         os.sleep(object.Time)
  260.         self.Draw()
  261.     end
  262.     return boolean, var
  263. end
  264. function New.Button(self, object) --Button class
  265.     local object = copyTable(object)
  266.     do
  267.         local ok = button_error(object)
  268.         if ok then error(ok ,2) end
  269.     end
  270.     local self, meta
  271.     self = {
  272.         Draw = function(state)
  273.             button_draw(object, state)
  274.         end;
  275.         Detect = function(action, t)
  276.             return button_detect(object, self, action, t)
  277.         end
  278.     }
  279.     meta = {
  280.         __index = object;
  281.         __metatable = false;
  282.         __private = {
  283.             name = string.gsub(tostring(self), type(self), object.Object)
  284.         };
  285.         __tostring = function()
  286.             return meta.__private.name
  287.         end;
  288.         __newindex = function(self, key, value)
  289.             object_set(meta, self, button_error, key, value)
  290.         end;
  291.         __pairs = object_pairs;
  292.     }
  293.     setmetatable(self, meta)
  294.     if object.Visible then self.Draw() end
  295.     return self, object
  296. end
  297. end
  298. do --Check Box
  299. local function checkbox_error(object, self)
  300.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  301.     object.Draw = nil
  302.     object.Set = nil
  303.     object.Detect = nil
  304.     object.ChangeState = nil
  305.     object.Term = object.Term or term.current()
  306.     object.Text = tostring(object.Text or "")
  307.     object.Width = #object.Text+2
  308.     object.TextColor = object.TextColor or colors.white
  309.     object.BackgroundColor = object.BackgroundColor or colors.black
  310.     object.BoxColor = object.BoxColor or colors.blue
  311.     object.ActiveColor = object.ActiveColor or colors.lime
  312.     object.InactiveColor = object.InactiveColor or colors.gray
  313.     if object.State == nil then object.State = false end
  314.     if object.Visible == nil then object.Visible = true end
  315.     object.Object = "check_box"
  316.     for key, value in ipairs{"xPos", "yPos", "Width", "TextColor", "BackgroundColor", "BoxColor", "ActiveColor", "InactiveColor"} do
  317.         if type(object[value]) ~= "number" then
  318.             local var = type(object[value])
  319.             object[value] = tonumber(object[value])
  320.             if not object[value] then
  321.                 return 'Bad argument "'..value..'": number expected, got '..var
  322.             end
  323.             object[value] = math.floor(object[value])
  324.         end
  325.     end
  326.     for key, value in ipairs{"Visible", "State"} do
  327.         if type(object[value]) ~= "boolean" then
  328.             return 'Bad argument "'..value..'": boolean expected, got '..type(object[value])
  329.         end
  330.     end
  331.     if type(object.Term) ~= "table" then
  332.         return 'Bad argument "Term": term object expected, got '..type(object.Term)
  333.     else
  334.         for key, value in pairs(term.native()) do
  335.             if not object.Term[key] then
  336.                 return 'Bad argument "Term": term object expected, got '..type(object.Term)
  337.             end
  338.         end
  339.     end
  340. end
  341. local function checkbox_draw(object, state)
  342.     local Term = term.current()
  343.     if Term ~= object.Term then term.redirect(object.Term) end
  344.     local a, b = term.getTextColor(), term.getBackgroundColor()
  345.     local x, y = term.getCursorPos()
  346.     if state == "active" then
  347.         textcol = object.TextColor
  348.         backcol = object.ActiveColor
  349.     elseif state == "inactive" then
  350.         textcol = object.InactiveColor
  351.         backcol = object.InactiveColor
  352.     else
  353.         textcol = object.TextColor
  354.         backcol = object.BoxColor
  355.     end
  356.     paintutils.drawPixel(object.xPos, object.yPos, backcol)
  357.     colorText(object.xPos+2, object.yPos, textcol, object.BackgroundColor, object.Text)
  358.     term.setCursorPos(x, y)
  359.     term.setTextColor(a)
  360.     term.setBackgroundColor(b)
  361.     if Term ~= object.Term then term.redirect(Term) end
  362. end
  363. local function checkbox_changeState(object, self, state)
  364.     if state == nil then
  365.         object.State = not object.State
  366.     elseif type(state) ~= "boolean" then
  367.         object.State = state
  368.     else
  369.         error("Bad argument: boolean expected, got "..type(state), 3)
  370.     end
  371.     if object.Visible then
  372.         if object.State then
  373.             self.Draw"active"
  374.         else
  375.             self.Draw()
  376.         end
  377.     end
  378.     return object.State
  379. end
  380. local function checkbox_detect(object, self, action, t)
  381.     local boolean, var = object_detect(object, action, t)
  382.     if boolean then self.ChangeState() end
  383.     return boolean, var
  384. end
  385. function New.CheckBox(self, object) --CheckBox class
  386.     local object = copyTable(object)
  387.     do
  388.         local ok = checkbox_error(object)
  389.         if ok then error(ok ,2) end
  390.     end
  391.     local self, meta
  392.     self = {
  393.         Draw = function(state)
  394.             checkbox_draw(object, state)
  395.         end;
  396.         Detect = function(action, t)
  397.             return checkbox_detect(object, self, action, t)
  398.         end;
  399.         ChangeState = function(state)
  400.             return checkbox_changeState(object, self, state)
  401.         end;
  402.     }
  403.     meta = {
  404.         __index = object;
  405.         __metatable = false;
  406.         __private = {
  407.             name = string.gsub(tostring(self), type(self), object.Object)
  408.         };
  409.         __tostring = function()
  410.             return meta.__private.name
  411.         end;
  412.         __newindex = function(self, key, value)
  413.             object_set(meta, self, checkbox_error, key, value)
  414.         end;
  415.     }
  416.     setmetatable(self, meta)
  417.     if object.Visible then if object.State then self.Draw("active") else self.Draw() end end
  418.     return self, meta
  419. end
  420. end
  421. do --Label
  422. local function label_error(object) -- Error handing
  423.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  424.     object.Draw = nil
  425.     object.Set = nil
  426.     object.Detect = nil
  427.     object.Term = object.Term or term.current()
  428.     object.Text = tostring(object.Text or "")
  429.     object.TextColor = object.TextColor or colors.white
  430.     object.BackgroundColor = object.BackgroundColor or colors.black
  431.     object.Position = object.Position or "middle"
  432.     if object.Visible == nil then object.Visible = true end
  433.     object.Object = "label"
  434.     for key, value in ipairs{"xPos", "yPos", "TextColor", "BackgroundColor"} do
  435.         if type(object[value]) ~= "number" then
  436.             local var = type(object[value])
  437.             object[value] = tonumber(object[value])
  438.             if not object[value] then
  439.                 return 'Bad argument "'..value..'": number expected, got '..var
  440.             end
  441.             object[value] = math.floor(object[value])
  442.         end
  443.     end
  444.     if type(object.Term) ~= "table" then
  445.         return 'Bad argument "Term": term object expected, got '..type(object.Term)
  446.     else
  447.         for key, value in pairs(term.native()) do
  448.             if not object.Term[key] then
  449.                 return 'Bad argument "Term": term object expected, got '..type(object.Term)
  450.             end
  451.         end
  452.     end
  453.     if type(object.Visible) ~= "boolean" then
  454.         return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
  455.     end
  456.     if object.Position ~= "right" and object.Position ~= "left" and object.Position ~= "middle" then
  457.         return 'Argument "Position" must be "right", "left" or "middle"'
  458.     end
  459. end
  460. local function label_draw(object) --Draws label
  461.     local Term = term.current()
  462.     if Term ~= object.Term then term.redirect(object.Term) end
  463.     local a, b = term.getTextColor(), term.getBackgroundColor()
  464.     local x, y = term.getCursorPos()
  465.     local xPos
  466.     if object.Position == "middle" then
  467.         xPos = object.xPos-math.floor(#object.Text/2)
  468.     elseif object.Position == "right" then
  469.         xPos = object.xPos
  470.     elseif object.Position == "left" then
  471.         xPos = object.xPos-#object.Text+1
  472.     end
  473.     colorText(xPos, object.yPos, object.TextColor, object.BackgroundColor, object.Text)
  474.     term.setCursorPos(x, y)
  475.     term.setTextColor(a)
  476.     term.setBackgroundColor(b)
  477.     if Term ~= object.Term then term.redirect(Term) end
  478. end
  479. local function label_detect(object, self, action, t)
  480.     local xPos, Width = object.xPos, object.Width
  481.     object.Width = #object.Text
  482.     if object.Position == "middle" then
  483.         object.xPos = xPos-math.floor(#object.Text/2)
  484.     elseif object.Position == "left" then
  485.         object.xPos = object.xPos-#object.Text+1
  486.     end
  487.     local ok, boolean, n = pcall(object_detect, object, action, t)
  488.     object.xPos, object.Width = xPos, Width
  489.     if not ok then error(boolean, 3) end
  490.     if object.Visible then self.Draw() end
  491.     return boolean, n
  492. end
  493. function New.Label(self, object) --Label class
  494.     local object = copyTable(object)
  495.     do
  496.         local ok = label_error(object)
  497.         if ok then error(ok ,2) end
  498.     end
  499.     local self, meta
  500.     self = {
  501.         Draw = function(state)
  502.             label_draw(object, state)
  503.         end;
  504.         Detect = function(action, t)
  505.             return label_detect(object, self, t)
  506.         end;
  507.     }
  508.     meta = {
  509.         __index = object;
  510.         __metatable = false;
  511.         __private = {
  512.             name = tostring(self):gsub(type(self), object.Object)
  513.         };
  514.         __tostring = function()
  515.             return meta.__private.name
  516.         end;
  517.         __newindex = function(self, key, value)
  518.             object_set(meta, self, label_error, key, value)
  519.         end;
  520.     }
  521.     setmetatable(self, meta)
  522.     if object.Visible then self.Draw() end
  523.     return self, meta
  524. end
  525. end
  526. do --Registry
  527. local function registry_error(object) -- Error handing
  528.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  529.     if not object.Path or not object.Path:find("%a") then return "Not correct path" end
  530.     if not fs.exists(fs.getDir(object.Path)) then
  531.         fs.makeDir(fs.getDir(object.Path))
  532.     end
  533.     object.Object = "registry"
  534.     if not object.Table then
  535.         local file = io.open(object.Path, "r")
  536.         if file then
  537.             local text = file:read("*a")
  538.             if text == "" then
  539.                 object.Table = { }
  540.             else
  541.                 object.Table = textutils.unserialize(text)
  542.                 if not object.Table then return "Not a registry file" end
  543.                 file:close()
  544.             end
  545.         else
  546.             object.Table = { }
  547.         end
  548.     end
  549.     if type(object.Table) ~= "table" then
  550.         return 'Bad argument "Table": table expected, got '..type(object.Table)
  551.     end
  552.     if type(object.Path) ~= "string" then
  553.         return 'Bad argument "Path": string expected, got '..type(object.Path)
  554.     end
  555. end
  556. local function registry_save(object)
  557.     if not fs.exists(fs.getDir(object.Path)) then
  558.         fs.makeDir(fs.getDir(object.Path))
  559.     end
  560.     local file = io.open(object.Path, "w")
  561.     if not file then error("Have not access to the registry file", 3) end
  562.     local ok, text = pcall(textutils.serialize, object.Table)
  563.     if not ok then error(text, 3) end
  564.     file:write("--Registry file\n"..text)
  565.     file:close()
  566. end
  567. local function registry_amount(object)
  568.     local result = 0
  569.     for var in pairs(object.Table) do
  570.         result = result+1
  571.     end
  572.     return result
  573. end
  574. local function registry_insert(object, key, value)
  575.     if type(key) == "function" or type(value) == "function" then
  576.         error('The type of a value can\'t be number, got '..type(key), 3)
  577.     end
  578.     return table.insert(object.Table, key, value)
  579. end
  580. local function registry_remove(object, key, value)
  581.     if type(key) ~= "number" then
  582.         error('The type of a key must be number, got '..type(key), 3)
  583.     end
  584.     return table.remove(object.Table, key, value)
  585. end
  586. function New.Registry(self, object) --Registry class
  587.     local object = copyTable(object)
  588.     if type(object) == "string" then
  589.         object = {Path = object}
  590.     else
  591.         object = copyTable(object)
  592.     end
  593.     do
  594.         local ok = registry_error(object)
  595.         if ok then error(ok, 2) end
  596.     end
  597.     local self, meta, meta_reg = {
  598.         ["Save"] = function()
  599.             registry_save(object)
  600.         end;
  601.         ["Amount"] = function()
  602.             return registry_amount(object)
  603.         end;
  604.         ["Insert"] = function(key, value)
  605.             return registry_insert(object, key, value)
  606.         end;
  607.         ["Remove"] = function(object, key, value)
  608.             return registry_remove(object, key, value)
  609.         end;
  610.     }
  611.     meta = {
  612.         __index = object;
  613.         __private = {
  614.             name = tostring(self):gsub(type(self), object.Object)
  615.         };
  616.         __tostring = function()
  617.             return meta.__private.name
  618.         end;
  619.         __newindex = function()
  620.             error("Attempt to index a registry object", 2)
  621.         end;
  622.         __metatable = false;
  623.         __len = function()
  624.             return registry_amount(object)
  625.         end;
  626.     }
  627.     meta_reg = {
  628.         __newindex = function(t, key, value)
  629.             if type(value) == "function" then error("Couldn't serialize function", 2) end
  630.             local save = meta_reg.__newindex
  631.             meta_reg.__newindex = nil
  632.             meta.__index.Table[key] = value
  633.             meta_reg.__newindex = save
  634.         end;
  635.         __metatable = false
  636.     }
  637.     setmetatable(meta.__index.Table, meta_reg)
  638.     setmetatable(self, meta)
  639.     return self, meta
  640. end
  641. end
  642. do --Image
  643. local function image_error(object) --Checks errors in image
  644.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  645.     object.Draw = nil
  646.     object.Set = nil
  647.     object.Detect = nil
  648.     object.Term = object.Term or term.current()
  649.     object.Width = object.Width or 10
  650.     object.Height = object.Height or 5
  651.     object.xOffset = object.xOffset or 0
  652.     object.yOffset = object.yOffset or 0
  653.     object.Image = object.Image or { }
  654.     object.BackgroundColor = object.BackgroundColor or 0
  655.     object.BorderColor = object.BorderColor or colors.blue
  656.     object.LinesColor = object.LinesColor or colors.white
  657.     object.BorderStyle = object.BorderStyle or "none"
  658.     if object.Visible == nil then object.Visible = true end
  659.     object.Object = "image"
  660.     for key, value in ipairs{"xPos", "yPos", "Width", "Height", "xOffset", "yOffset", "BackgroundColor", "BorderColor", "LinesColor"} do
  661.         if type(object[value]) ~= "number" then
  662.             local var = type(object[value])
  663.             object[value] = tonumber(object[value])
  664.             if not object[value] then
  665.                 return 'Bad argument "'..value..'": number expected, got '..var
  666.             end
  667.             object[value] = math.floor(object[value])
  668.         end
  669.     end
  670.     if type(object.Image) == "string" then
  671.         local ok
  672.         object.Path = object.Image
  673.         if check(object.Path, "nft") then
  674.             ok, object.Image = pcall(Image.LoadNFT, object.Path)
  675.         else
  676.             object.Image = { }
  677.             ok, object.Image.backcol = pcall(paintutils.loadImage, object.Path)
  678.         end
  679.         if not ok then
  680.             return 'Couldn\'t find an image file by the path'
  681.         end
  682.     elseif type(object.Image) == "table" then
  683.         if not object.Image.backcol then
  684.             object.Image = {backcol = object.Image}
  685.         end
  686.     else
  687.         return 'Bad argument "Image": table or string expected, got '..type(object.Image)
  688.     end
  689.     if object.BorderStyle ~= "none" and object.BorderStyle ~= "box" and object.BorderStyle ~= "lines" then
  690.         return 'The argument "BorderStyle" must be "none", "box" or "lines", got "'..object.BorderStyle..'"'
  691.     end
  692.     if type(object.Term) ~= "table" then
  693.         return 'Bad argument "Term": term object expected, got '..type(object.Term)
  694.     else
  695.         for key, value in pairs(term.native()) do
  696.             if not object.Term[key] then
  697.                 return 'Bad argument "Term": term object expected, got '..type(object.Term)
  698.             end
  699.         end
  700.     end
  701.     if type(object.Visible) ~= "boolean" then
  702.         return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
  703.     end
  704.     for key, value in pairs(object.Image) do
  705.         for i=1, #object.Image[key] do
  706.             local var = table.maxn(object.Image[key][i]) or 0
  707.             for k=1, tonumber(var) do
  708.                 if key == "backcol" then
  709.                     object.Image[key][i][k] = object.Image[key][i][k] or 0
  710.                 elseif key == "text" then
  711.                     object.Image[key][i][k] = object.Image[key][i][k] or " "
  712.                 elseif key == "textcol" then
  713.                     object.Image[key][i][k] = object.Image[key][i][k] or colors.white
  714.                 end
  715.             end
  716.         end
  717.     end
  718. end
  719. local function image_draw(object) --Draw image
  720.     if object.Width < 1 or object.Height < 1 then
  721.         return
  722.     end
  723.     local Term = term.current()
  724.     local color
  725.     if Term ~= object.Term then
  726.         term.redirect(object.Term)
  727.     end
  728.     local a, b = term.getTextColor(), term.getBackgroundColor()
  729.     local x, y = term.getCursorPos()
  730.     if object.BackgroundColor ~= 0 then
  731.         paintutils.drawFilledBox(object.xPos, object.yPos, object.xPos+object.Width-1, object.yPos+object.Height-1, object.BackgroundColor)
  732.     end
  733.     for i=object.yOffset, object.Height do
  734.         if object.Image.backcol[i] then
  735.             for k=object.xOffset, object.Width do
  736.                 if object.Image.backcol[i][k] and object.Image.backcol[i][k] ~= 0 then
  737.                     local xPos, yPos = object.xPos+k-object.xOffset-1, object.yPos+i-object.yOffset-1
  738.                     if xPos >= object.xPos
  739.                     and xPos <= object.xPos+object.Width-1
  740.                     and yPos >= object.yPos
  741.                     and yPos <= object.yPos+object.Height-1 then
  742.                         term.setCursorPos(xPos, yPos)
  743.                         term.setBackgroundColor(object.Image.backcol[i][k])
  744.                         if object.Image.text and object.Image.text[i] and object.Image.text[i][k] then
  745.                             term.setTextColor(object.Image.textcol[i][k])
  746.                             term.write(object.Image.text[i][k])
  747.                         else
  748.                             term.write(" ")
  749.                         end
  750.                     end
  751.                 end
  752.             end
  753.         end
  754.     end
  755.     if object.BorderStyle == "box" then
  756.         paintutils.drawBox(object.xPos-1, object.yPos-1, object.xPos+object.Width, object.yPos+object.Height, object.BorderColor)
  757.     elseif object.BorderStyle == "lines" then
  758.         term.setBackgroundColor(object.BorderColor)
  759.         term.setTextColor(object.LinesColor)
  760.         for i=0, object.Width-1 do
  761.             term.setCursorPos(object.xPos+i, object.yPos-1)
  762.             term.write("-")
  763.             term.setCursorPos(object.xPos+i, object.yPos+object.Height)
  764.             term.write("-")
  765.         end
  766.         for i=0, object.Height-1 do
  767.             term.setCursorPos(object.xPos-1, object.yPos+i)
  768.             term.write("|")
  769.             term.setCursorPos(object.xPos+object.Width, object.yPos+i)
  770.             term.write("|")
  771.         end
  772.         term.setCursorPos(object.xPos-1, object.yPos-1)
  773.         term.write("+")
  774.         term.setCursorPos(object.xPos+object.Width, object.yPos-1)
  775.         term.write("+")
  776.         term.setCursorPos(object.xPos-1, object.yPos+object.Height)
  777.         term.write("+")
  778.         term.setCursorPos(object.xPos+object.Width, object.yPos+object.Height)
  779.         term.write("+")
  780.     end
  781.     term.setCursorPos(x, y)
  782.     term.setBackgroundColor(b)
  783.     term.setTextColor(a)
  784.     if Term ~= object.Term then
  785.         term.redirect(Term)
  786.     end
  787. end
  788. local function image_detect(object, self, action, t) --Detects events
  789.     local boolean, var = object_detect(action, object, t)
  790.     if object.Visible and boolean then
  791.         self.Draw()
  792.     end
  793.     return boolean, var
  794. end
  795. function New.Image(self, object) --Image class
  796.     local object = copyTable(object)
  797.     do
  798.         local ok = image_error(object)
  799.         if ok then error(ok, 2) end
  800.     end
  801.     local self, meta = {
  802.         ["Draw"] = function()
  803.             image_draw(object)
  804.         end;
  805.         ["Detect"] = function(action, t)
  806.             return image_detect(object, self, action, t)
  807.         end;
  808.     }
  809.     meta = {
  810.         __index = object;
  811.         __metatable = false;
  812.         __private = {
  813.             name = tostring(self):gsub(type(self), object.Object)
  814.         };
  815.         __tostring = function()
  816.             return meta.__private.name
  817.         end;
  818.         __newindex = function(self, key, value)
  819.             object_set(meta, self, image_error, key, value)
  820.         end;
  821.     }
  822.     setmetatable(self, meta)
  823.     if object.Visible then self.Draw() end
  824.     return self, meta
  825. end
  826. end
  827. do --Process
  828. local function process_switch( ... )
  829.     local n = ...
  830.     if type(n) ~= "number" then
  831.         error("Bad argument: number expected, got "..type(n), 2)
  832.     end
  833.     return coroutine.yield("switch", ... )
  834. end
  835. local function process_exit( ... )
  836.     return coroutine.yield("stop", ... )
  837. end
  838. local function process_kill( ... )
  839.     local n = ...
  840.     if type(n) ~= "number" then
  841.         error("Bad argument: number expected, got "..type(n), 2)
  842.     end
  843.     return coroutine.yield("kill", ... )
  844. end
  845. local function process_add(object)
  846.     if Type(object) ~= "process" then
  847.         error("Bad argument: process expected, got "..Type(object), 2)
  848.     end
  849.     return coroutine.yield("add", object)
  850. end
  851. local function process_amount()
  852.     return coroutine.yield "amount"
  853. end
  854. local function process_status(n)
  855.     if type(n) ~= "number" then
  856.         error("Bad argument: number expected, got "..type(n), 2)
  857.     end
  858.     return coroutine.yield("status", n)
  859. end
  860. local function process_call()
  861.     error("You can't do it inside the process!", 2)
  862. end
  863. local function process_error(object, self, b) --Checks errors in button
  864.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  865.     local function process_coroutine(args)
  866.         if not args[1] then args = object.Args end
  867.         object.Env.shell = shell
  868.         object.Env.multishell = multishell
  869.         object.Env.term = term
  870.         object.Env.term.native = term.current
  871.         object.Env.Process.SetWindow = self.SetWindow
  872.         setmetatable(object.Env.Process, {
  873.             __index = self;
  874.             __newindex = process_call;
  875.             __tostring = function()
  876.                 return tostring(self)
  877.             end;
  878.             __metatable = false;
  879.         })
  880.         setmetatable(object.Env, {__index = _G})
  881.         local foo
  882.         do local err
  883.         if type(object.Process) == "function" then
  884.             foo = object.Process
  885.         else
  886.             local file = io.open(object.Process)
  887.             if file then
  888.                 foo, err = load(file:read "*a", fs.getName(object.Process), "t", object.Env)
  889.             else
  890.                 err = "file not found"
  891.             end
  892.             if not foo then error('Error in program file: '..err, 0) end
  893.         end end
  894.         object.State = true
  895.         local var = { pcall(foo, unpack(args)) }
  896.         object.State = false
  897.         if not var[1] then error("Error in the running process: "..var[2], 0) end
  898.         return select(2, unpack(var))
  899.     end
  900.     object.Term = object.Term or term.current()
  901.     if type(object.Term) ~= "table" then
  902.         return 'Bad argument "Term": term object expected, got '..type(object.Term)
  903.     else
  904.         for key, value in pairs(term.native()) do
  905.             if not object.Term[key] then
  906.                 return 'Bad argument "Term": term object expected, got '..type(object.Term)
  907.             end
  908.         end
  909.     end
  910.     object.Env = {Process = {
  911.         Exit = process_exit;
  912.         Switch = process_switch;
  913.         Kill = process_kill;
  914.         Run = process_call;
  915.         Rebuild = process_call;
  916.         Add = process_add;
  917.         Amount = process_amount;
  918.         Status = process_status;
  919.         Current = 1;
  920.     }}
  921.     object.Resume = nil
  922.     object.Set = nil
  923.     object.Run = nil
  924.     local w, h = object.Term.getSize()
  925.     object.xPos = object.xPos or 1
  926.     object.yPos = object.yPos or 1
  927.     object.Width = object.Width or w
  928.     object.Height = object.Height or h
  929.     object.Visible = object.Visible or true
  930.     object.Args = object.Args or { }
  931.     object.Object = "process"
  932.     object.State = false
  933.     object.UseWindow = object.UseWindow or false
  934.     object.Coroutine = coroutine.create(process_coroutine)
  935.     for key, value in ipairs{"xPos", "yPos", "Width", "Height"} do
  936.         if type(object[value]) ~= "number" then
  937.             local var = type(object[value])
  938.             object[value] = tonumber(object[value])
  939.             if not object[value] then
  940.                 return 'Bad argument "'..value..'": number expected, got '..var
  941.             end
  942.             if value ~= "Time" then
  943.                 object[value] = math.floor(object[value])
  944.             end
  945.         end
  946.     end
  947.     for key, value in ipairs{"UseWindow", "Visible"} do
  948.         if type(object[value]) ~= "boolean" then
  949.             return 'Bad argument "'..value..'": boolean expected, got '..type(object[value])
  950.         end
  951.     end
  952.     if type(object.Process) == "string" then
  953.         local file = io.open(object.Process)
  954.         if not file then return "Couldn't find a file by the path" end
  955.         file:close()
  956.     elseif type(object.Process) == "function" then
  957.     else
  958.         return 'Bad argument "Process": path or function expected, got '..type(object.Process)
  959.     end
  960.     if object.UseWindow then
  961.         if not b and object.Window then
  962.             object.Window.reposition(object.xPos, object.yPos, object.Width, object.Height)
  963.             object.Term = object.Window.parent
  964.         else
  965.             object.Window = window.create(object.Term, object.xPos, object.yPos, object.Width, object.Height, false)
  966.             object.Window.parent = object.Term
  967.         end
  968.     end
  969. end
  970. local process_dead = coroutine.create(function() end)
  971. coroutine.resume(process_dead)
  972. local function process_run(object, args)
  973.     local x, y, Term
  974.     if object.UseWindow then
  975.         Term = term.current()
  976.         x, y = term.getCursorPos()
  977.         term.redirect(object.Window)
  978.         if object.Visible then
  979.             object.Window.setVisible(object.Visible)
  980.             object.Window.redraw()
  981.             object.Window.restoreCursor()
  982.         end
  983.     end
  984.     local var = { coroutine.resume(object.Coroutine, args) }
  985.     while coroutine.status(object.Coroutine) == "suspended" do
  986.         if var[2] == "stop" then
  987.             var = { select(3, unpack(var)) }
  988.             table.insert(var, 1, true)
  989.             break
  990.         elseif var[2] == "switch" then
  991.             var[2] = false
  992.             table.remove(var, 3)
  993.         elseif var[2] == "add" then
  994.             var[2] = false
  995.         elseif var[2] == "kill" then
  996.             if var[3] == 1 then
  997.                 var = { }
  998.                 object.Coroutine = process_dead
  999.                 break
  1000.             else
  1001.                 var[2] = false
  1002.                 table.remove(var, 3)
  1003.             end
  1004.         else
  1005.             var = { coroutine.yield(var[2]) }
  1006.             table.insert(var, 1, true)
  1007.         end
  1008.         if object.UseWindow and (var[2] == "mouse_click" or var[2] == "mouse_drag" or var[2] == "mouse_scroll" or var[2] == "mouse_up") then
  1009.             var[4], var[5] = var[4]-object.xPos+1, var[5]-object.yPos+1
  1010.         end
  1011.         var = { coroutine.resume(object.Coroutine, select(2, unpack(var))) } --unload"object"Object=require"object3"Process=Object.Process{Process="prog",Visible=false}
  1012.     end
  1013.     if object.UseWindow then
  1014.         term.redirect(Term)
  1015.         term.setCursorPos(x, y)
  1016.     end
  1017.     return unpack(var)
  1018. end
  1019. local function process_setWindow(object, new)
  1020.     if type(new) ~= "table" then
  1021.         error('This method must be called with table argument!', 3)
  1022.     end
  1023.     if new.Visible ~= nil then object.Visible = new.Visible end
  1024.     if new.UseWindow ~= nil then object.UseWindow = new.UseWindow end
  1025.     for key, value in ipairs{"xPos", "yPos", "Width", "Height"} do
  1026.         object[value] = new[value] or object[value]
  1027.         if type(object[value]) ~= "number" then
  1028.             local var = type(object[value])
  1029.             object[value] = tonumber(object[value])
  1030.             if not object[value] then
  1031.                 error('Bad argument "'..value..'": number expected, got '..var, 3)
  1032.             end
  1033.             if value ~= "Time" then
  1034.                 object[value] = math.floor(object[value])
  1035.             end
  1036.         end
  1037.     end
  1038.     for key, value in ipairs{"UseWindow", "Visible"} do
  1039.         if type(object[value]) ~= "boolean" then
  1040.             error('Bad argument "'..value..'": boolean expected, got '..type(object[value]), 3)
  1041.         end
  1042.     end
  1043.     object.Window.reposition(object.xPos, object.yPos, object.Width, object.Height)
  1044. end
  1045. function New.Process(self, object) --Process class
  1046.     local object = copyTable(object)
  1047.     local self, meta = {
  1048.         ["Run"] = function( ... )
  1049.             return process_run(object, { ... })
  1050.         end;
  1051.         ["SetWindow"] = function(t)
  1052.             process_setWindow(object, t)
  1053.         end;
  1054.         ["SetArgs"] = function( ... )
  1055.             object.Args = { ... }
  1056.         end;
  1057.         ["Rebuild"] = function()
  1058.             process_error(object, self)
  1059.         end;
  1060.     }
  1061.     do
  1062.         local ok = process_error(object, self, true)
  1063.         if ok then error(ok, 2) end
  1064.     end
  1065.     meta = {
  1066.         __index = object;
  1067.         __metatable = false;
  1068.         __private = {
  1069.             name = tostring(self):gsub(type(self), object.Object)
  1070.         };
  1071.         __tostring = function()
  1072.             return meta.__private.name
  1073.         end;
  1074.         __newindex = function(self, key, value)
  1075.             if key == "Coroutine" then
  1076.                 object.Coroutine = value
  1077.             else
  1078.                 object_set(meta, self, process_error, key, value)
  1079.             end
  1080.         end;
  1081.     }
  1082.     setmetatable(self, meta)
  1083.     return self, meta
  1084. end
  1085. function Process.Multithread(processes) --Parallel controller
  1086.     processes = copyTable(processes)
  1087.     if type(processes.Parallel) ~= 'boolean' and processes.Parallel ~= nil then
  1088.         error("Bad argument \"Parallel\": boolean expected, got "..type(processes.Parallel), 2)
  1089.     end
  1090.     processes.Parallel = processes.Parallel == true
  1091.     for key, value in ipairs(processes) do
  1092.         if not (type(value) == "table" and value.Object == "process") then
  1093.             error("Bad argument #"..key..": process expected, got "..type(value), 2)
  1094.         end
  1095.         if coroutine.status(value.Coroutine) == "dead" then
  1096.             error("Cannot resume dead process #"..key, 2)
  1097.         end
  1098.         value.Env.Process.Current = key
  1099.     end
  1100.     local result = {}
  1101.     local process = processes[1]
  1102.     local Term = term.current()
  1103.     local cx, cy = term.getCursorPos()
  1104.     local n, var = 1, { }
  1105.     while true do
  1106.         if process.UseWindow then
  1107.             term.redirect(process.Window)
  1108.             if process.Visible then
  1109.                 term.setVisible(true)
  1110.                 term.redraw()
  1111.                 term.restoreCursor()
  1112.             end
  1113.         else
  1114.             term.redirect(Term)
  1115.             if term.redraw then term.redraw() end
  1116.         end
  1117.         while coroutine.status(process.Coroutine) == "suspended" do
  1118.             if not process.State then
  1119.                 var = { coroutine.resume(process.Coroutine, { }) }
  1120.             end
  1121.             if var[2] == "stop" then
  1122.                 result[n] = { table.unpack(var, 3) }
  1123.                 process.Coroutine = process_dead
  1124.                 var[2] = "stopped"
  1125.                 table.insert(var, 3, n)
  1126.                 n=n+1
  1127.                 break
  1128.             elseif var[2] == "kill" then
  1129.                 result[var[3]] = { }
  1130.                 processes[var[3]].Coroutine = process_dead
  1131.                 var = {true, "killed", var[3]}
  1132.                 if n == var[3] then break end
  1133.             elseif var[2] == "switch" then
  1134.                 var[2] = "switched"
  1135.                 n, var[3] = var[3], n
  1136.                 break
  1137.             elseif var[2] == "add" then
  1138.                 var[2] = "added"
  1139.                 table.insert(processes, var[3])
  1140.                 var[3].Env.Process.Current = #processes
  1141.                 var[3] = nil
  1142.             elseif var[2] == "amount" then
  1143.                 var[2] = #processes
  1144.             elseif var[2] == "status" then
  1145.                 if processes[var[3]] then
  1146.                     if n == var[3] then
  1147.                         var[2] = "running"
  1148.                     else
  1149.                         var[2] = coroutine.status(processes[var[3]].Coroutine)
  1150.                     end
  1151.                 else
  1152.                     var[2] = false
  1153.                 end
  1154.                 var[3] = nil
  1155.             elseif var[2] == 'stopped' or var[2] == 'killed' or var[2] == 'switched' then
  1156.             else
  1157.                 var = { coroutine.yield(var[2]) }
  1158.                 table.insert(var, 1, true)
  1159.                 if process.UseWindow and var[2]:find("mouse") then
  1160.                     var[4], var[5] = var[4]-process.xPos+1, var[5]-process.yPos+1
  1161.                 end
  1162.             end
  1163.             table.insert(var, 2, process.Coroutine)
  1164.             var = { coroutine.resume(table.unpack(var, 2)) }
  1165.             if coroutine.status(process.Coroutine) == "dead" then
  1166.                 result[n] = { table.unpack(var, 2) }
  1167.                 table.insert(var, 2, "stopped")
  1168.                 table.insert(var, 3, n)
  1169.                 n=n+1
  1170.                 break
  1171.             end
  1172.         end
  1173.         if process.UseWindow then
  1174.             term.setVisible(true)
  1175.             term.redirect(Term)
  1176.             if term.redraw then term.redraw() end
  1177.         end
  1178.         if n > #processes then
  1179.             n = 1
  1180.         end
  1181.         if coroutine.status(processes[n].Coroutine) == "dead" then
  1182.             local a = true
  1183.             n=0
  1184.             repeat
  1185.                 n=n+1
  1186.                 if n > #processes then
  1187.                     a = false
  1188.                     break
  1189.                 end
  1190.             until coroutine.status(processes[n].Coroutine) == "suspended"
  1191.             if not a then break end
  1192.         end
  1193.         process = processes[n]
  1194.     end
  1195.     return table.unpack(result)
  1196. end
  1197. function Process.Run(process, ... )
  1198.     return Process{Process = process, Args = { ... }}.Run()
  1199. end
  1200. end
  1201. do --Text Box
  1202. local function textbox_error(object, self) --Checks errors in text box
  1203.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  1204.     object.Draw = nil
  1205.     object.Set = nil
  1206.     object.Detect = nil
  1207.     object.Term = object.Term or term.current()
  1208.     object.Width = object.Width or 9
  1209.     object.Height = object.Height or 1
  1210.     object.Text = tostring(object.Text or "")
  1211.     object.TextColor = object.TextColor or colors.black
  1212.     object.BackgroundColor = object.BackgroundColor or colors.white
  1213.     if object.Visible == nil then object.Visible = true end
  1214.     if object.Words == nil then object.Words = true end
  1215.     object.Object = "text_box"
  1216.     for key, value in ipairs{"xPos", "yPos", "Width", "TextColor", "BackgroundColor"} do
  1217.         if type(object[value]) ~= "number" then
  1218.             local var = type(object[value])
  1219.             object[value] = tonumber(object[value])
  1220.             if not object[value] then
  1221.                 return 'Bad argument "'..value..'": number expected, got '..var
  1222.             end
  1223.             object[value] = math.floor(object[value])
  1224.         end
  1225.     end
  1226.     if type(object.Term) ~= "table" then
  1227.         return 'Bad argument "Term": term object expected, got '..type(object.Term)
  1228.     else
  1229.         for key, value in pairs(term.native()) do
  1230.             if not object.Term[key] then
  1231.                 return 'Bad argument "Term": term object expected, got '..type(object.Term)
  1232.             end
  1233.         end
  1234.     end
  1235.     if type(object.Visible) ~= "boolean" then
  1236.         return 'Bad argument "Visible": boolean expected, got '..type(object.Visible)
  1237.     end
  1238. end
  1239. local function count(object, mode)
  1240.     local tText, sText = {""}, object.Text
  1241.     while sText:len() > 0 and #tText <= object.Height do
  1242.         local whitespace = sText:match("^[ \t]+")
  1243.         if whitespace then
  1244.             tText[#tText] = tText[#tText]..whitespace
  1245.             sText = sText:sub(string.len(whitespace)+1)
  1246.         end
  1247.         local newline = sText:match("^\n")
  1248.         if newline then
  1249.             tText[#tText+1] = ""
  1250.             sText = sText:sub(2)
  1251.         end
  1252.         local text = sText:match("^[^ \t\n]+")
  1253.         if text then
  1254.             sText = sText:sub(text:len()+1)
  1255.             if text:len() > object.Width and not mode then
  1256.                 local n = #tText
  1257.                 local text = tText[n]..text
  1258.                 tText[n] = nil
  1259.                 for i=1, math.ceil(#text/object.Width+1) do
  1260.                     if #tText > object.Height then break end
  1261.                     tText[#tText+1] = text:sub((i-1)*object.Width+1, i*object.Width)
  1262.                 end
  1263.                 if tText[#tText] == "" then tText[#tText] = nil end
  1264.             else
  1265.                 tText[#tText] = tText[#tText]..text
  1266.             end
  1267.         end
  1268.     end
  1269.     for i=object.Height+1, #tText do
  1270.         tText[i] = nil
  1271.     end
  1272.     return tText
  1273. end
  1274. local function textbox_draw(object) --Draws text box
  1275.     local Term = term.current()
  1276.     if Term ~= object.Term then
  1277.         term.redirect(object.Term)
  1278.     end
  1279.     local a, b = term.getTextColor(), term.getBackgroundColor()
  1280.     local cx, cy = term.getCursorPos()
  1281.     --
  1282.     term.setTextColor(object.TextColor)
  1283.     paintutils.drawFilledBox(object.xPos, object.yPos, object.xPos+object.Width-1, object.yPos+object.Height-1, object.BackgroundColor)
  1284.     for key, value in next, count(object) do
  1285.         term.setCursorPos(object.xPos, object.yPos-1+key)
  1286.         term.write(value)
  1287.     end
  1288.     --
  1289.     term.setCursorPos(cx, cy)
  1290.     term.setBackgroundColor(b)
  1291.     term.setTextColor(a)
  1292.     if Term ~= object.Term then
  1293.         term.redirect(Term)
  1294.     end
  1295. end
  1296. local function textbox_detect(object, action, event)
  1297. --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)
  1298.     local result, n = object_detect(object, action, event)
  1299.     local cx, cy = term.getCursorPos()
  1300.     local x, y
  1301.     local text, posit, totext
  1302.     if result then
  1303.         if event.TextBox and action ~= "key" then
  1304.             text = count(object)
  1305.             function posit(x, y, b)
  1306.                 local a
  1307.                 while not text[y-object.yPos+1] do
  1308.                     y = y-1
  1309.                     a = true
  1310.                 end
  1311.                 local w = #(text[y-object.yPos+1] or "")+1
  1312.                 if b and x-object.xPos+1 > w then
  1313.                     y = y+1
  1314.                     if not text[y-object.yPos+1] then
  1315.                         y = object.yPos
  1316.                     end
  1317.                     x = object.xPos
  1318.                 elseif b and x < object.xPos then
  1319.                     y = y-1
  1320.                     if not text[y-object.yPos+1] then
  1321.                         y = #text+object.yPos-1
  1322.                     end
  1323.                     local w = #(text[y-object.yPos+1] or "")+5
  1324.                     if w == object.xPos+object.Width then
  1325.                         x = w-1
  1326.                     else
  1327.                         x = w
  1328.                     end
  1329.                 elseif x == object.xPos+object.Width then
  1330.                     y = y+1
  1331.                     x = object.xPos
  1332.                 elseif x-object.xPos+1 > w or a then
  1333.                     x = w+object.xPos-1
  1334.                 end
  1335.                 term.setCursorPos(x, y)
  1336.                 return x-object.xPos+1, y-object.yPos+1
  1337.             end
  1338.             function totext(tText)
  1339.                 local text = ""
  1340.                 for _, value in next, tText do
  1341.                     text = text.."\n"..value
  1342.                 end
  1343.                 return text
  1344.             end
  1345.             x, y = posit(t[3], t[4])
  1346.         else
  1347.             if object.Visible then textbox_draw(object) end
  1348.             return result, n
  1349.         end
  1350.     else
  1351.         return result, n
  1352.     end
  1353.     local color = term.getTextColor()
  1354.     term.setCursorBlink(true)
  1355.     term.setTextColor(object.TextColor)
  1356.     while true do
  1357.         event = { os.pullEvent() }
  1358.         if event[1] == "mouse_click" then
  1359.             local ok, n = object_detect(object, event)
  1360.             if ok then
  1361.                 if n == 1 then
  1362.                     x, y = posit(event[3], event[4])
  1363.                 end
  1364.             else
  1365.                 break
  1366.             end
  1367.         end
  1368.         if event[1] == "char" then
  1369.             local text2 = count(object, true)
  1370.             local x,y = term.getCursorPos()
  1371.             term.setCursorPos(1,object.yPos+2)
  1372.            
  1373.             term.setCursorPos(x,y)
  1374.             textbox_draw(object)
  1375.         end
  1376.         if event[1] == "key" then
  1377.             local x, y = term.getCursorPos()
  1378.             if event[2] == 200 then
  1379.                 if select(2, term.getCursorPos()) == object.yPos then
  1380.                     posit(x, object.yPos+object.Height-1)
  1381.                 else
  1382.                     posit(x, y-1)
  1383.                 end
  1384.             elseif event[2] == 208 then
  1385.                 if select(2, term.getCursorPos()) == object.yPos+object.Height-1 then
  1386.                     posit(x, object.yPos)
  1387.                 elseif not text[y-object.yPos+2] then
  1388.                     posit(x, object.yPos)
  1389.                 else
  1390.                     posit(x, y+1)
  1391.                 end
  1392.             elseif event[2] == 205 then
  1393.                 posit(x+1, y, 1)
  1394.             elseif event[2] == 203 then
  1395.                 posit(x-1, y, 1)
  1396.             end
  1397.         end
  1398.     end
  1399.     term.setTextColor(color)
  1400.     term.setCursorBlink(false)
  1401.     term.setCursorPos(cx,cy)
  1402. end
  1403. function New.TextBox(self, object) --Text box class
  1404.     local object = copyTable(object)
  1405.     do
  1406.         local err = textbox_error(object)
  1407.         if err then error(err, 2) end
  1408.     end
  1409.     local self, meta = {
  1410.         ["Draw"] = function()
  1411.             textbox_draw(object)
  1412.         end;
  1413.         ["Detect"] = function(t)
  1414.             return textbox_detect(object, action, t)
  1415.         end;
  1416.     }
  1417.     meta = {
  1418.         __index = object;
  1419.         __newindex = function(self, key, value)
  1420.             object_set(meta, self, process_error, key, value)
  1421.         end;
  1422.         __private = {
  1423.             name = tostring(self):gsub(type(self), object.Object)
  1424.         };
  1425.         __metatable = false;
  1426.         __tostring = function()
  1427.             return meta.__private.name
  1428.         end;
  1429.     }
  1430.     setmetatable(self, meta)
  1431.     if object.Visible then textbox_draw(object) end
  1432.     return self, meta
  1433. end
  1434. end
  1435. do --Graph
  1436. local function graph_error(object) --Graph
  1437.     if type(object) ~= "table" then return 'Class must be called with table argument!' end
  1438.     object.Object = "graph"
  1439.     object.Factor = object.Factor or 20
  1440.     object.Size = object.Size or 9
  1441.     object.Color = object.Color or colors.white
  1442.     object.AxisColor = object.AxisColor or colors.gray
  1443.     object.BackgroundColor = object.BackgroundColor or colors.black
  1444.     if object.Axis == nil then object.Axis = true end
  1445.     if type(object.Function) ~= "function" then
  1446.         return 'Bad argument "Function": function expected, got '..type(object.Function)
  1447.     end
  1448.     for key, value in ipairs{"Factor", "Size", "Color", "AxisColor", "BackgroundColor"} do
  1449.         if type(object[value]) ~= "number" then
  1450.             local var = type(object[value])
  1451.             object[value] = tonumber(object[value])
  1452.             if not object[value] then
  1453.                 return 'Bad argument "'..value..'": number expected, got '..var
  1454.             end
  1455.             object[value] = math.floor(object[value])
  1456.         end
  1457.     end
  1458.     if type(object.Axis) ~= "boolean" then
  1459.         return 'Bad argument "Axis": boolean expected, got '..type(object.Axis)
  1460.     end
  1461. end
  1462. local function graph_getImage(object, self)
  1463.     local image = { }
  1464.     for y=1, 2*object.Size+1 do
  1465.         image[y] = { }
  1466.     end
  1467.     for x=-math.modf(object.Size*object.Factor), math.modf(object.Size*object.Factor) do
  1468.         ok, y = pcall(object.Function, x/object.Factor, self)
  1469.         if not ok or type(y) ~= "number" then
  1470.             error("Error in graph function: "..y, 2)
  1471.         end
  1472.         y = math.floor(object.Size-math.modf(y))+1
  1473.         x2 = math.modf(x/object.Factor)+object.Size+1
  1474.         if y >= 1 and y <= 2*object.Size+1 then
  1475.             image[y][x2] = object.Color
  1476.         end
  1477.     end
  1478.     if object.Axis then
  1479.         image = {
  1480.             backcol = image;
  1481.             text = { };
  1482.             textcol = { };
  1483.         }
  1484.         for y=1, object.Size*2+1 do
  1485.             image.textcol[y] = { }
  1486.             image.text[y] = { }
  1487.             image.textcol[y][object.Size+1] = object.AxisColor
  1488.             image.text[y][object.Size+1] = "|"
  1489.             image.backcol[y][object.Size+1] = image.backcol[y][object.Size+1] or object.BackgroundColor
  1490.         end
  1491.         for x=1, object.Size*2+1 do
  1492.             image.textcol[object.Size+1][x] = object.AxisColor
  1493.             image.text[object.Size+1][x] = "-"
  1494.             image.backcol[object.Size+1][x] = image.backcol[object.Size+1][x] or object.BackgroundColor
  1495.         end
  1496.         image.text[object.Size+1][object.Size+1] = "+"
  1497.     else
  1498.         for y=1, table.maxn(image) do
  1499.             image[y] = image[y] or { }
  1500.             for x=1, table.maxn(image[y]) do
  1501.                 image[y][x] = image[y][x] or 0
  1502.             end
  1503.         end
  1504.     end
  1505.     return image
  1506. end
  1507. function New.Graph(self, object) --Graph class
  1508.     local object = copyTable(object)
  1509.     do
  1510.         local err = graph_error(object)
  1511.         if err then error(err, 2) end
  1512.     end
  1513.     local self, meta
  1514.     self = {
  1515.         GetImage = function()
  1516.             return graph_getImage(object, self)
  1517.         end;
  1518.     }
  1519.     meta = {
  1520.         __index = object;
  1521.         __metatable = false;
  1522.         __call = self.GetImage;
  1523.         __private = {
  1524.             name = tostring(self):gsub(type(self), object.Object)
  1525.         };
  1526.         __tostring = function()
  1527.             return meta.__private.name
  1528.         end;
  1529.         __newindex = function(self, key, value)
  1530.             object_set(meta, self, process_error, key, value)
  1531.         end;
  1532.     }
  1533.     setmetatable(self, meta)
  1534.     return self, meta
  1535. end
  1536. end
  1537.  
  1538. do
  1539. local function __newindex(self, key, value)
  1540.     error("index expected, got class", 2)
  1541. end
  1542. local button_meta
  1543. button_meta = {
  1544.     __call = New.Button;
  1545.     name = tostring(Button):gsub(type(Button), "class");
  1546.     __tostring = function()
  1547.         return button_meta.name
  1548.     end;
  1549.     __metatable = false;
  1550.     __newindex = __newindex;
  1551. }
  1552. setmetatable(Button, button_meta)
  1553. local checkbox_meta
  1554. checkbox_meta = {
  1555.     __call = New.CheckBox;
  1556.     name = tostring(CheckBox):gsub(type(CheckBox), "class");
  1557.     __tostring = function()
  1558.         return checkbox_meta.name
  1559.     end;
  1560.     __metatable = false;
  1561.     __newindex = __newindex;
  1562. }
  1563. setmetatable(CheckBox, checkbox_meta)
  1564. local label_meta
  1565. label_meta = {
  1566.     __call = New.Label;
  1567.     name = tostring(Label):gsub(type(Label), "class");
  1568.     __tostring = function()
  1569.         return label_meta.name
  1570.     end;
  1571.     __metatable = false;
  1572.     __newindex = __newindex;
  1573. }
  1574. setmetatable(Label, label_meta)
  1575. local image_meta
  1576. image_meta = {
  1577.     __call = New.Image;
  1578.     name = tostring(Image):gsub(type(Image), "class");
  1579.     __tostring = function()
  1580.         return image_meta.name
  1581.     end;
  1582.     __metatable = false;
  1583.     __newindex = __newindex;
  1584. }
  1585. setmetatable(Image, image_meta)
  1586. local registry_meta
  1587. registry_meta = {
  1588.     __call = New.Registry;
  1589.     name = tostring(Registry):gsub(type(Registry), "class");
  1590.     __tostring = function()
  1591.         return registry_meta.name
  1592.     end;
  1593.     __metatable = false;
  1594.     __newindex = __newindex;
  1595. }
  1596. setmetatable(Registry, registry_meta)
  1597. local textbox_meta
  1598. textbox_meta = {
  1599.     __call = New.TextBox;
  1600.     name = tostring(TextBox):gsub(type(TextBox), "class");
  1601.     __tostring = function()
  1602.         return textbox_meta.name
  1603.     end;
  1604.     __metatable = false;
  1605.     __newindex = __newindex;
  1606. }
  1607. setmetatable(TextBox, textbox_meta)
  1608. local graph_meta
  1609. graph_meta = {
  1610.     __call = New.Graph;
  1611.     name = tostring(Graph):gsub(type(Graph), "class");
  1612.     __tostring = function()
  1613.         return graph_meta.name
  1614.     end;
  1615.     __metatable = false;
  1616.     __newindex = __newindex;
  1617. }
  1618. setmetatable(Graph, graph_meta)
  1619. local process_meta
  1620. process_meta = {
  1621.     __call = New.Process;
  1622.     name = tostring(Process):gsub(type(Process), "class");
  1623.     __tostring = function()
  1624.         return process_meta.name
  1625.     end;
  1626.     __metatable = false;
  1627.     __newindex = __newindex;
  1628. }
  1629. setmetatable(Process, process_meta)
  1630. end
  1631.  
  1632. Type = function(object)
  1633.     if type(object) == "table" and object.Object then
  1634.         return object.Object
  1635.     else
  1636.         return type(object)
  1637.     end
  1638. end
  1639.  
  1640. New = nil
  1641. local meta
  1642. meta = {
  1643.     __metatable = false;
  1644.     name = tostring(getfenv()):gsub("table", "module");
  1645.     __tostring = function()
  1646.         return meta.name
  1647.     end;
  1648.     __index = _G;
  1649.     __newindex = function()
  1650.         error("You haven't access for this!", 2)
  1651.     end;
  1652. }
  1653. setmetatable(getfenv(), meta)
Advertisement
Add Comment
Please, Sign In to add comment