Created
April 28, 2013 19:06
-
-
Save sk89q/5478026 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Node Panel Display | |
by sk89q | |
]]-- | |
dofile("npanel_conf.lua") | |
dofile("serpent.lua") | |
dofile("util.lua") | |
local function validateColor(allowNone) | |
return function(input) | |
if allowNone and input == "" then return nil end | |
if not colors[input] then | |
return "Invalid color! Examples: red, blue, black, lightBlue, etc." | |
end | |
end | |
end | |
local Block = prototype({ | |
__construct = function(self, x, y, text, color) | |
self.x = x | |
self.y = y | |
self.text = text | |
self.color = color or colors.lightBlue | |
self.conn = {} | |
self.cable = nil | |
self.state = nil | |
self:setText(text) | |
end, | |
setText = function(self, text) | |
self.text = text | |
-- calculate width of the block | |
self._width = #self.text + 1 | |
if self._width % 2 ~= 0 then | |
self._width = self._width + 1 | |
end | |
end, | |
onClick = function(self) | |
if self.cable then -- bundled cable | |
-- toggle the latch (external to the system) | |
self.state = not self.state | |
redstone.setBundledOutput(bundledSide, self.cable) | |
os.sleep(0.2) | |
redstone.setBundledOutput(bundledSide, 0) | |
return "Toggled " .. self.text .. " to " .. (self.state and "ON" or "OFF") | |
else | |
return false | |
end | |
end, | |
contains = function(self, x, y) | |
return x >= -self._width / 2 + self.x and x <= self._width / 2 + self.x and | |
y >= self.y - 1 and y <= self.y + 1 | |
end, | |
connect = function(self, to, color) | |
local color = color or colors.white | |
table.insert(self.conn, {to = to, color = color}) | |
table.insert(to.conn, {to = self, color = color}) | |
end, | |
disconnect = function(self, to) | |
for k, other in ipairs(self.conn) do | |
if other.to == to then | |
-- remove own connection | |
table.remove(self.conn, k) | |
-- remove the other's reference too | |
for k, other in ipairs(to.conn) do | |
if other.to == self then | |
table.remove(to.conn, k) | |
break | |
end | |
end | |
return -- exit | |
end | |
end | |
end, | |
disconnectAll = function(self) | |
for _, other in ipairs(self.conn) do | |
-- remove the other's reference | |
for k, o in ipairs(other.to.conn) do | |
if o.to == self then | |
table.remove(other.to.conn, k) | |
break | |
end | |
end | |
end | |
self.conn = {} | |
end, | |
isConnected = function(self, to) | |
for k, other in ipairs(self.conn) do | |
if other.to == to then return true end | |
end | |
return false | |
end, | |
setCable = function(self, color) | |
self.cable = color | |
-- set the state field if only we have a color set | |
if color then | |
self.state = self.state or false | |
else | |
self.state = nil | |
end | |
return self | |
end, | |
apply = function(self, object) | |
prototyptify(self, object) | |
end, | |
draw = function(self) | |
term.setBackgroundColor(self._selected and colors.blue or self.color) | |
term.setTextColor(colors.white) | |
drawLine(-self._width / 2 + self.x + 1, self.y - 1, self._width / 2 + self.x - 1, self.y - 1, "-") | |
drawLine(-self._width / 2 + self.x + 1, self.y + 1, self._width / 2 + self.x - 1, self.y + 1, "-") | |
drawPixel(-self._width / 2 + self.x, self.y - 1, "+") | |
drawPixel(self._width / 2 + self.x, self.y - 1, "+") | |
drawPixel(-self._width / 2 + self.x, self.y + 1, "+") | |
drawPixel(self._width / 2 + self.x, self.y + 1, "+") | |
drawPixel(-self._width / 2 + self.x, self.y, "|") | |
drawPixel(self._width / 2 + self.x, self.y, "|") | |
term.setCursorPos(-self._width / 2 + self.x + 1, self.y) | |
term.write(self.text) | |
for i = 0, self._width - #self.text - 2 do | |
term.write(" ") | |
end | |
-- draw state | |
if self.state ~= nil then | |
term.setCursorPos(-self._width / 2 + self.x + 1, self.y - 1) | |
if self.state then | |
term.setBackgroundColor(colors.green) | |
term.setTextColor(colors.yellow) | |
term.write("ON") | |
else | |
term.setBackgroundColor(colors.red) | |
term.setTextColor(colors.yellow) | |
term.write("OFF") | |
end | |
end | |
end | |
}) | |
local Diagram = prototype({ | |
__construct = function(self) | |
self.blocks = {} | |
self.seen = {} | |
end, | |
add = function(self, block) | |
-- only add if we haven't seen this block | |
if not self.seen[block] then | |
self.seen[block] = true | |
table.insert(self.blocks, block) | |
for _, c in ipairs(block.conn) do | |
self:add(c.to) -- add this block too | |
end | |
end | |
end, | |
remove = function(self, block) | |
self.seen[block] = nil | |
-- remove from self.blocks | |
for k, v in ipairs(self.blocks) do | |
if v == block then | |
table.remove(self.blocks, k) | |
return | |
end | |
end | |
end, | |
save = function(self, path) | |
local data = serpent.dump(self.blocks, { | |
valtypeignore = {["function"] = true}, | |
compact = true | |
}) | |
-- save to file | |
local f = fs.open(path, "w") | |
f.write(data) | |
f.close() | |
end, | |
load = function(self, path) | |
-- save to file | |
local f = fs.open(path, "r") | |
if f then | |
local data = f.readAll() | |
f.close() | |
self.blocks = loadstring(data)() | |
-- need to re-initialize | |
for _, block in ipairs(self.blocks) do | |
Block:apply(block) | |
end | |
else -- no data to load then | |
self.blocks = {} | |
end | |
end, | |
intersect = function(self, x, y, seen, block) | |
for _, block in ipairs(self.blocks) do | |
if block:contains(x, y) then | |
return block | |
end | |
end | |
end | |
}) | |
local BasePane = prototype({ | |
titleColor = colors.cyan, | |
__construct = function(self, app) | |
self.app = app | |
end, | |
readInput = function(self, name, validate) | |
local input | |
self:drawHint("Please type the input above") | |
while true do | |
self:drawStatus(name) | |
redstone.setOutput(enableSide, true) | |
input = trim(read()) | |
redstone.setOutput(enableSide, false) | |
if type(validate) == 'function' then | |
local msg = validate(input) | |
if msg then -- uh oh, error! | |
self:drawHint(msg) | |
else | |
break -- ok | |
end | |
elseif validate then -- just verify non-blank | |
if msg == "" then | |
self:drawHint("Non-empty string required") | |
else | |
break -- ok | |
end | |
else | |
break -- no validation needed | |
end | |
end | |
-- ok! | |
self:drawHint("") | |
return input | |
end, | |
drawStatus = function(self, status) | |
local w, h = term.getSize() | |
drawLine(1, h - 1, w, h - 1, " ", colors.black) | |
drawText(2, h - 1, status, colors.black, colors.yellow) | |
end, | |
drawHint = function(self, status) | |
local w, h = term.getSize() | |
drawLine(1, h, w, h, " ", self.titleColor) | |
drawText(2, h, status, self.titleColor, colors.white) | |
end, | |
drawTitle = function(self, title) | |
drawText(2, 1, " " .. title .. " ", self.titleColor, colors.white) | |
end, | |
drawDiagram = function(self) | |
self:drawConnections() | |
self:drawBlocks() | |
end, | |
drawBlocks = function(self) | |
for _, block in ipairs(self.app.diagram.blocks) do | |
block:draw() | |
end | |
end, | |
drawConnection = function(self, x1, y1, x2, y2, color) | |
drawLine(x1, y1, x2, y2, x1 == x2 and "|" or "-", color, colors.black) | |
end, | |
drawConnections = function(self) | |
for _, block in ipairs(self.app.diagram.blocks) do | |
for k, v in ipairs(block.conn) do | |
self:drawConnection(block.x, block.y, v.to.x, v.to.y, v.color) | |
end | |
end | |
end, | |
draw = function(self) | |
-- do nothing | |
end, | |
onPress = function(self, key) | |
-- do nothing | |
end, | |
onClick = function(self, button, x, y) | |
-- do nothing | |
end, | |
onDrag = function(self, button, x, y) | |
-- do nothing | |
end, | |
}) | |
local Display = prototype(BasePane, { | |
draw = function(self) | |
self.app:drawAll(function() | |
local w, h = term.getSize() | |
term.setBackgroundColor(colors.black) | |
term.clear() | |
self:drawTitle("SYSTEM OVERVIEW") | |
self:drawStatus("Touch elements to toggle them off and on") | |
self:drawHint("[E]dit Mode") | |
self:drawDiagram() | |
end) | |
end, | |
onPress = function(self, key) | |
if key:lower() == "e" then | |
self.app:show(self.app.editor) | |
end | |
end, | |
onClick = function(self, button, x, y) | |
local clicked = self.app.diagram:intersect(x, y) | |
if clicked then | |
local status = clicked:onClick() | |
if status then | |
self.app:drawAll(function() | |
clicked:draw() | |
self:drawStatus(status) | |
self.app:save() -- better save state | |
end) | |
self.app.notebox.playNote(3, 24) | |
end | |
end | |
end, | |
}) | |
local Editor = prototype(BasePane, { | |
titleColor = colors.red, | |
selected = nil, | |
lastSelected = nil, | |
draw = function(self) | |
self.app:drawAll(function() | |
local w, h = term.getSize() | |
term.setBackgroundColor(colors.black) | |
term.clear() | |
self:drawTitle("BLOCK EDITOR") | |
self:drawStatusBar() | |
self:drawDiagram() | |
end) | |
end, | |
drawStatusBar = function(self) | |
if self.selected then | |
self:drawHint("[I]nsert [D]elete [M]odify [C]onnect [S]ave") | |
else | |
self:drawHint("[I]nsert [S]ave") | |
end | |
end, | |
select = function(self, block) | |
-- swap selection | |
local last = nil | |
if self.selected then | |
self.selected._selected = false | |
last = self.selected | |
end | |
self.selected = block | |
if block then | |
block._selected = true | |
end | |
self.lastSelected = last | |
return last | |
end, | |
onClick = function(self, button, x, y) | |
local clicked = self.app.diagram:intersect(x, y) | |
if clicked then | |
local last = self:select(clicked) | |
-- redraw | |
self.app:drawAll(function() | |
clicked:draw() | |
if last then | |
last:draw() -- unselected the last one, so redraw | |
end | |
self:drawStatus(clicked.text .. " selected" .. | |
(clicked.cable and (" [color: " .. getColor(clicked.cable) .. "]") or "")) | |
self:drawStatusBar() | |
end) | |
end | |
end, | |
onDrag = function(self, button, x, y) | |
if self.selected then | |
if x ~= self.selected.x or y ~= self.selected.y then | |
self.selected.x = x | |
self.selected.y = y | |
self:draw() | |
end | |
end | |
end, | |
onPress = function(self, key) | |
local lkey = key:lower() | |
-- save/quit | |
if lkey == "s" then | |
self:select(nil) | |
self.app:show(self.app.display) | |
self.app:save() | |
-- insert | |
elseif lkey == "i" then | |
local x, y = 2, 2 | |
local name = self:readInput("Name: ", true) -- just non-blank | |
local block = Block(x, y, name) | |
self.app.diagram:add(block) | |
self:select(block) | |
self:draw() -- redraw all | |
-- connect | |
elseif lkey == "c" and self.selected then -- only if selected | |
if self.lastSelected == self.selected then | |
self:drawHint("Can't connect to itself, silly") | |
elseif self.lastSelected then | |
if self.selected:isConnected(self.lastSelected) then -- disconnect | |
self.selected:disconnect(self.lastSelected, color) | |
else -- connect | |
local color = colors[self:readInput("Color: ", validateColor())] | |
self.selected:connect(self.lastSelected, color) | |
end | |
self:draw() -- redraw all | |
else | |
self:drawHint("Select two blocks in sequence first") | |
end | |
-- delete | |
elseif lkey == "d" and self.selected then -- only if selected | |
local confirm = self:readInput("Are you sure? [y/n] ") | |
if confirm:lower() == "y" then | |
self.selected:disconnectAll() | |
self.app.diagram:remove(self.selected) | |
self:select(nil) | |
end | |
self:draw() | |
-- modify | |
elseif lkey == "m" and self.selected then -- only if selected | |
-- set name | |
local name = self:readInput("Name [blank for no change]: ") | |
if name ~= "" then | |
self.selected:setText(name) | |
end | |
-- bundled cable | |
local color = colors[self:readInput( | |
"Bundled cable [blank for none] color: ", | |
validateColor(true))] -- allow none | |
self.selected:setCable(color) | |
self:draw() -- redraw all | |
end | |
end, | |
}) | |
local Application = prototype({ | |
__construct = function(self) | |
self.diagram = Diagram() | |
self.notebox = peripheral.wrap(noteboxSide) | |
self.terminals = { peripheral.wrap("top"), term.native } | |
self:load() | |
self.display = Display(self) | |
self.editor = Editor(self) | |
end, | |
load = function(self) | |
self.diagram:load(diagramFile) | |
end, | |
save = function(self) | |
self.diagram:save(diagramFile) | |
end, | |
drawExternal = function(self, func) | |
for _, m in ipairs(self.terminals) do | |
if m ~= term.native then -- ignore native | |
term.redirect(m) | |
func() | |
end | |
end | |
term.redirect(term.native) | |
end, | |
drawAll = function(self, func) | |
local enabled = self:isEnabled() -- only draw if enabled | |
for _, m in ipairs(self.terminals) do | |
if m == term.native or enabled then | |
term.redirect(m) | |
func() | |
end | |
end | |
term.redirect(term.native) | |
end, | |
show = function(self, view) | |
self.view = view | |
self.view:draw() | |
end, | |
isEnabled = function(self) | |
return redstone.getInput(enableSide) | |
end, | |
processEvents = function(self) | |
local active = true | |
local wasOn = self:isEnabled() | |
self:show(self.display) | |
-- clear on start if needed | |
if not wasOn then | |
self:drawExternal(function() | |
term.setBackgroundColor(colors.black) | |
term.clear() | |
end) | |
end | |
while active do | |
local id, p1, p2, p3 = os.pullEvent() | |
local on = self:isEnabled() | |
if id == "redstone" then | |
if wasOn ~= on then | |
wasOn = on | |
self:drawExternal(function() | |
-- redraw if turned on | |
if on then | |
self.view:draw() | |
else | |
-- clear when off | |
term.setBackgroundColor(colors.black) | |
term.clear() | |
end | |
end) | |
end | |
elseif id == "key" then | |
local key = p1 | |
if key == 221 then | |
active = false | |
end | |
elseif id == "char" then | |
local ch = p1 | |
self.view:onPress(ch) | |
elseif id == "mouse_click" then | |
local button, x, y = p1, p2, p3 | |
self.view:onClick(button, x, y) | |
elseif id == "mouse_drag" then | |
local button, x, y = p1, p2, p3 | |
self.view:onDrag(button, x, y) | |
elseif id == "monitor_touch" and on then -- only if on! | |
local side, x, y = p1, p2, p3 | |
self.view:onClick(0, x, y) | |
end | |
end | |
self:drawAll(function() | |
term.setBackgroundColor(colors.black) | |
term.setTextColor(colors.white) | |
term.clear() | |
term.setCursorPos(1, 1) | |
print("Node Panel exited") | |
end) | |
end, | |
loadExample = function(self) | |
local boiler = Block(25, 14, "Boiler"):setCable(colors.red) | |
local engines = Block(10, 6, "Engines"):setCable(colors.white) | |
local refinery = Block(10, 14, "Refinery"):setCable(colors.black) | |
local mjStore = Block(25, 6, "MJ Store") | |
local euStore = Block(40, 6, "EU Store") | |
local factory = Block(40, 14, "Factory") | |
boiler:connect(mjStore, colors.orange) | |
engines:connect(mjStore, colors.orange) | |
refinery:connect(engines, colors.yellow) | |
mjStore:connect(euStore, colors.purple) | |
euStore:connect(factory, colors.purple) | |
self.diagram:add(boiler) | |
end | |
}) | |
local app = Application() | |
app:processEvents() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bundledSide = "bottom" | |
noteboxSide = "right" | |
diagramFile = "layout.txt" | |
enableSide = "back" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local n, v = "serpent", 0.22 -- (C) 2012 Paul Kulchenko; MIT License | |
local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types" | |
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} | |
local badtype = {thread = true, userdata = true} | |
local keyword, globals, G = {}, {}, (_G or _ENV) | |
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', | |
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', | |
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end | |
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping | |
for _,g in ipairs({'coroutine', 'io', 'math', 'string', 'table', 'os'}) do | |
for k,v in pairs(G[g]) do globals[v] = g..'.'..k end end | |
local function s(t, opts) | |
local name, indent, fatal = opts.name, opts.indent, opts.fatal | |
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge | |
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) | |
local comm = opts.comment and (tonumber(opts.comment) or math.huge) | |
local seen, sref, syms, symn = {}, {}, {}, 0 | |
local function gensym(val) return (tostring(val):gsub("[^%w]",""):gsub("(%d%w+)", | |
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end)) end | |
local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s) | |
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 | |
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end | |
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end | |
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal | |
and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end | |
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] | |
local n = name == nil and '' or name | |
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] | |
local safe = plain and n or '['..safestr(n)..']' | |
return (path or '')..(plain and path and '.' or '')..safe, safe end | |
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(o, n) | |
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} | |
local function padnum(d) return ("%0"..maxn.."d"):format(d) end | |
table.sort(o, function(a,b) | |
return (o[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) | |
< (o[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end | |
local function val2str(t, name, indent, insref, path, plainindex, level) | |
local ttype, level = type(t), (level or 0) | |
local spath, sname = safename(path, name) | |
local tag = plainindex and | |
((type(name) == "number") and '' or name..space..'='..space) or | |
(name ~= nil and sname..space..'='..space or '') | |
if seen[t] then -- if already seen and in sref processing, | |
if insref then return tag..seen[t] end -- then emit right away | |
table.insert(sref, spath..space..'='..space..seen[t]) | |
return tag..'nil'..comment('ref', level) | |
elseif badtype[ttype] then | |
seen[t] = spath | |
return tag..globerr(t, level) | |
elseif ttype == 'function' then | |
seen[t] = insref or spath | |
local ok, res = pcall(string.dump, t) | |
local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or | |
"loadstring("..safestr(res)..",'@serialized')")..comment(t, level)) | |
return tag..(func or globerr(t, level)) | |
elseif ttype == "table" then | |
if level >= maxl then return tag..'{}'..comment('max', level) end | |
seen[t] = insref or spath -- set path to use as reference | |
if getmetatable(t) and getmetatable(t).__tostring | |
then return tag..val2str(tostring(t),nil,indent,false,nil,nil,level+1)..comment("meta", level) end | |
if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty | |
local maxn, o, out = #t, {}, {} | |
for key = 1, maxn do table.insert(o, key) end | |
for key in pairs(t) do if not o[key] then table.insert(o, key) end end | |
if opts.sortkeys then alphanumsort(o, opts.sortkeys) end | |
for n, key in ipairs(o) do | |
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse | |
if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing | |
or opts.keyallow and not opts.keyallow[key] | |
or opts.keynounderscore and type(key) == "string" and string.sub(key, 1, 1) == "_" | |
or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types | |
or sparse and value == nil then -- skipping nils; do nothing | |
elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then | |
if not seen[key] and not globals[key] then | |
table.insert(sref, 'placeholder') | |
sref[#sref] = 'local '..val2str(key,gensym(key),indent,gensym(key)) end | |
table.insert(sref, 'placeholder') | |
local path = seen[t]..'['..(seen[key] or globals[key] or gensym(key))..']' | |
sref[#sref] = path..space..'='..space..(seen[value] or val2str(value,nil,indent,path)) | |
else | |
table.insert(out,val2str(value,key,indent,insref,seen[t],plainindex,level+1)) | |
end | |
end | |
local prefix = string.rep(indent or '', level) | |
local head = indent and '{\n'..prefix..indent or '{' | |
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) | |
local tail = indent and "\n"..prefix..'}' or '}' | |
return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level) | |
else return tag..safestr(t) end -- handle all other types | |
end | |
local sepr = indent and "\n" or ";"..space | |
local body = val2str(t, name, indent) -- this call also populates sref | |
local tail = #sref>0 and table.concat(sref, sepr)..sepr or '' | |
return not name and body or "do local "..body..sepr..tail.."return "..name..sepr.."end" | |
end | |
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end | |
serpent = { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, | |
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, | |
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, | |
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function prototype(parent, t) | |
if not t then | |
t = parent | |
parent = nil | |
end -- when there is no inheritance | |
local t = t or {} | |
local mt = { __index = t } | |
setmetatable(t, { | |
__call = function(_, ...) | |
local obj = setmetatable({}, mt) | |
if obj.__construct then obj:__construct(unpack(arg)) end | |
return obj | |
end, | |
__index = parent | |
}) | |
return t | |
end | |
function prototyptify(cls, obj) | |
local mt = {} | |
mt.__index = cls | |
setmetatable(obj, mt) | |
return obj | |
end | |
function drawPixel(xPos, yPos, text) | |
term.setCursorPos(xPos, yPos) | |
term.write(text or " ") | |
end | |
-- from ComputerCraft | |
function drawLine(startX, startY, endX, endY, text, bgColor, textColor) | |
if bgColor then term.setBackgroundColor(bgColor) end | |
if textColor then term.setTextColor(textColor) end | |
startX = math.floor(startX) | |
startY = math.floor(startY) | |
endX = math.floor(endX) | |
endY = math.floor(endY) | |
if startX == endX and startY == endY then | |
drawPixel(startX, startY, text) | |
return | |
end | |
local minX = math.min(startX, endX) | |
if minX == startX then | |
minY = startY | |
maxX = endX | |
maxY = endY | |
else | |
minY = endY | |
maxX = startX | |
maxY = startY | |
end | |
local xDiff = maxX - minX | |
local yDiff = maxY - minY | |
if xDiff > math.abs(yDiff) then | |
local y = minY | |
local dy = yDiff / xDiff | |
for x=minX,maxX do | |
drawPixel(x, math.floor(y + 0.5), text) | |
y = y + dy | |
end | |
else | |
local x = minX | |
local dx = xDiff / yDiff | |
if maxY >= minY then | |
for y=minY,maxY do | |
drawPixel(math.floor(x + 0.5), y, text) | |
x = x + dx | |
end | |
else | |
for y=minY,maxY,-1 do | |
drawPixel(math.floor(x + 0.5), y, text) | |
x = x - dx | |
end | |
end | |
end | |
end | |
function drawText(x, y, text, bgColor, textColor) | |
term.setCursorPos(x, y) | |
term.setBackgroundColor(bgColor or colors.black) | |
term.setTextColor(textColor or colors.black) | |
term.write(text) | |
end | |
function getColor(num) | |
for k, v in pairs(colors) do | |
if v == num then | |
return k | |
end | |
end | |
return "?" | |
end | |
function trim(s) | |
return s:match"^%s*(.*)":match"(.-)%s*$" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment