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 &amp;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 &amp;gt; 1)then
   sop = sop - 1
   mdraw()
  elseif(ev[2] == keys.right and sop &amp;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 &amp;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
Download[GUI API]: pastebin get itF4iSMX ugapi

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)