Posted 18 February 2016 - 03:08 PM
Grid
The simplicity speaks for itself.
What is Grid?
Grid is a simple yet effect table API, it was essentially designed to help
with visual programs. For instance, paint, it uses a table to save and load images
in fact with each click you are writing to a table! now, a program like paint can a bit complex to write.
So, what i have done is make things a WHOLE lot easier, the example below is a paint-like program
Spoiler
os.loadAPI("grid")
local w, h = term.getSize()
local surface = grid.create(w,h-1)
local args = { ... }
if(#args &lt; 1)then error("Ussage: XPaint <file>") end
local file = args[1]
if(fs.exists(file))then
f=fs.open(file,"r")
ns = textutils.unserialize(f.readAll())
f.close()
surface:replace(ns)
else
surface:fill("\127")
end
local inMenu = false
local running = true
local moptions = {
{name='Save',run=function() f=fs.open(file,"w") f.write(surface:getSerial()) f.close() term.setCursorPos(1,h) write("File saved as: " .. file) end},
{name='Exit',run=function() term.setCursorPos(1,1) term.setBackgroundColor(colors.black) term.clear() running = false end},
}
local sop = 1
surface:draw()
term.setCursorPos(1,h)
term.setBackgroundColor(colors.gray)
term.clearLine()
write("press ctrl for menu. ")
function mdraw()
term.setCursorPos(1,h)
term.setBackgroundColor(colors.gray)
term.setTextColor(colors.white)
term.clearLine()
for i = 1, #moptions do
term.setCursorPos( ((i-1)*7) + 2,19)
if(sop == i)then write("[" .. moptions[i].name .. "]") end
if(sop ~= i)then write(" " .. moptions[i].name .. " ") end
end
end
function mupdate()
if(ev[1] == "key")then
if(ev[2] == keys.left and sop &gt; 1)then
sop = sop - 1
mdraw()
elseif(ev[2] == keys.right and sop &lt; #moptions)then
sop = sop + 1
mdraw()
elseif(ev[2] == keys.enter)then
moptions[sop].run()
end
end
end
while running do
ev = {os.pullEvent()}
if(ev[1] == "key" and ev[2] == keys['leftCtrl'])then
if(inMenu)then
inMenu = false
term.setCursorPos(1,h)
term.setBackgroundColor(colors.gray)
term.clearLine()
write("press ctrl for menu. ")
else
inMenu = true
mdraw()
end
end
if(inMenu ~= true)then
if(ev[1] == "mouse_click" or ev[1] == "mouse_drag")then
if(ev[2] == 1)then surface:set(ev[3],ev[4],"X") end
if(ev[2] == 2)then surface:set(ev[3],ev[4],"\127") end
surface:drawRegion(ev[3],ev[4],ev[3],ev[4])
end
else
mupdate()
end
end
An even smaller version, with my wip GUI API it shrinks this code down to 40lines!
Spoiler
os.loadAPI("grid")
os.loadAPI("ugapi")
local w, h = term.getSize()
local surface = grid.create(w,h-1)
local menu = ugapi.newMenu(1,h-2,5,2,colors.gray)
local menubtn = ugapi.newButton("Menu",2,h,4,1,colors.white,colors.black,colors.gray)
menu:setPreset("basic",colors.white,colors.gray,colors.gray,colors.black)
ugapi.clrlnycolor(colors.gray,h)
local args = { ... }
if(#args &lt; 1)then error("Ussage: XPaint <file>") end
local file = args[1]
if(fs.exists(file))then
f=fs.open(file,"r")
ns = textutils.unserialize(f.readAll())
f.close()
surface:replace(ns)
else
surface:fill("\127")
end
local inMenu = false
local running = true
menu:addOption('Save ',"basic",function() f=fs.open(file,"w") f.write(surface:getSerial()) f.close() ugapi.clrlny(h) write("File saved as: " .. file) os.pullEvent("mouse_click") ugapi.clrln() menubtn:draw() end)
menu:addOption('Exit ',"basic",function() ugapu.pos(1,1) ugapi.bcolor(colors.black) ugapi.clr() running = false end)
menubtn:onPress(function() if(inMenu)then inMenu = false menubtn:draw() surface:draw() else inMenu = true menu:draw() end end)
menubtn:draw()
surface:draw()
while running do
ev = {os.pullEvent()}
menubtn:update(ev)
if(inMenu ~= true)then
if(ev[1] == "mouse_click" or ev[1] == "mouse_drag")then
if(ev[2] == 1 and ev[4] ~= h)then surface:set(ev[3],ev[4],"X") end
if(ev[2] == 2 and ev[4] ~= h)then surface:set(ev[3],ev[4],"\127") end
if(ev[4] ~= h)then surface:drawRegion(ev[3],ev[4],ev[3],ev[4]) end
end
else
menu:update(ev)
end
end
You can also make games :P/>
Spoiler
os.loadAPI("grid") -- load the grid api
local level = grid.create(51,19) -- create the level grid
local pgrid = grid.create(51,19) -- create the grid where player will reside
-- create a table of blocks to use --
local blocks = {{char="@",tc=colors.white,bc=colors.blue,solid=true},{char=':',tc=colors.white,bc=colors.yellow,solid=false},{char='=',tc=colors.red,bc=colors.lightGray,solid=true},{char='=',tc=colors.yellow,bc=colors.brown,solid=false},{char='"',tc=colors.lime,bc=colors.green,solid=false},{char=' ',tc=colors.yellow,bc=colors.yellow,solid=true},{char=';',tc=colors.lightGray,bc=colors.white,solid=true},{char="L",tc=colors.gray,bc=colors.lightGray,solid=true},{char="*",tc=colors.green,bc=colors.brown,solid=false}}
level:fill(blocks[9]) -- fills level with "grass" block
pgrid:set(10,15,blocks[1]) -- places the "player" block on to the player grid
level:drawVisual('char','tc','bc') -- draw the level with visual attributes, char=graphic, tc = textcolor, bc = backgroundcolor
local selectedblock = 1 -- set our selected block to be the first block in out block list
function drawBlocks() -- draw the blocks and the selected block to the screen
term.setCursorPos(1,1)
term.setBackgroundColor(colors.gray)
term.setTextColor(colors.white)
term.clearLine()
local l = 0
for k, v in pairs(blocks) do
if(l == selectedblock)then
term.setCursorPos(((l)*3)-1,1)
term.setBackgroundColor(v.bc)
term.setTextColor(v.tc)
write(" " .. v.char .. " ")
else
term.setCursorPos((l)*3,1)
term.setBackgroundColor(v.bc)
term.setTextColor(v.tc)
write(v.char)
end
l = l +1
end
end
drawBlocks()
local px, py = 10, 15
while true do
ev = {os.pullEvent()}
if(ev[1] == "key")then
if(ev[2] == keys.up)then
if(level:get(px,py-1).solid ~= true and py > 2)then -- if where we are going to move has a solid block there, dont move.
pgrid:swapVisual('char','tc','bc',px,py,px,py-1) -- simple way of setting the block we are moving to a player and our previous block to a transparent block
level:drawRegionVisual('char','tc','bc',px,py,px,py) -- redraws the level tile, so we dont get a bunch of players xD
py = py - 1
end
elseif(ev[2] == keys.down)then
-- does the same stuff as the documentation states above --
if(level:get(px,py+1).solid ~= true and py < level:getHeight()-1)then
pgrid:swapVisual('char','tc','bc',px,py,px,py+1)
level:drawRegionVisual('char','tc','bc',px,py,px,py)
py = py + 1
end
elseif(ev[2] == keys.left)then
-- ^ --
if(level:get(px-1,py).solid ~= true and px > 2)then
pgrid:swapVisual('char','tc','bc',px,py,px-1,py)
level:drawRegionVisual('char','tc','bc',px,py,px,py)
px = px - 1
end
elseif(ev[2] == keys.right)then
-- ^ --
if(level:get(px+1,py).solid ~= true and px < level:getWidth()-1)then
pgrid:swapVisual('char','tc','bc',px,py,px+1,py)
level:drawRegionVisual('char','tc','bc',px,py,px,py)
px = px + 1
end
end
end
if(ev[1] == "mouse_click")then
if(ev[2] == 1)then
level:set(ev[3],ev[4],blocks[selectedblock+1]) -- sets where we click to be the block we currently have selected + 1
-- this +1 is so we cant place a "player" block
else
level:set(ev[3],ev[4],blocks[9]) -- if we right click set the block we click to grass
end
level:drawRegionVisual('char','tc','bc',ev[3],ev[4],ev[3],ev[4])
end
if(ev[1] == "mouse_scroll")then
if(ev[2] == -1 and selectedblock > 1)then -- if we scroll up and our selected block is within the block boundaries
selectedblock = selectedblock - 1 -- move back one block
end
if(ev[2] == 1 and selectedblock < 8)then -- if we scoll down and our selected block is within the block boundaries
selectedblock = selectedblock + 1 -- move forward one block
end
drawBlocks() -- update selected block and regular blocks
end
end
How do i use it?
Spoiler
-- DOCUMENTATION (Sorta...) --
--] grid.create(width,height) -- returns a grid object
--] grid:set(x,y,thing) -- sets "thing" to x and y on the grid
--] grid:find(obj) - returns the found objects x and y location
--] grid:findByAttrib(attrib,compare) -- returns x and y of an objects which "attrib" matches "compare" (an attrib by Grid's standards is basically a variable on a table for instance, table.attrib or table['attrib']
--] grid:get(x,y) - returns the object in the x any y of the grid
--] grid:getByAttrib(attrib,compare) -- same as findByAttrib but instead returns the entire object and not just the x and y
--] grid:getWidth() - returns width of grid
--] grid:getHeight() - returns grid height
--] grid:unset(x,y) - set grid spot to {}
--] grid:getRaw() - returns entire grid unserialized
--] grid:getSerial() - returns entire grid serialized
--] grid:replace(newgrid) - replaces grid with another grid
--] grid:draw() -- draws entire grid (may cause lag)
--] grid:drawAttrib(attrib) -- draws all the objects with the passed 'attrib'
--] grid:fill(with) - fills grid with something
--] grid:setRegion(startx,starty,endx,endy,with) -- fills grid from start x and start y to ends with something
--] grid:drawRegion(startx,starty,endx,endy) -- prevents lag by only drawing a specific region of the grid
Sound great gimme a download!
pastebin get QEXpahe1 grid
Hope you all enjoy my API, please leave any suggestions below. Also feel free to leave you're ideas for me to expand the API more :)/>
~ Redxone (Lewisk3)
Edited on 20 February 2016 - 12:22 PM