Posted 06 March 2013 - 12:12 AM
Hi, i recently decided to make an OS but wanted to make it amazing with multitasking and amazing graphics so i stole some APIs from BlueSky, improved them and made them compatible, then added loads more to form one big API with everything in it.
What is has:
process api* - create processes and run them ( uses coroutines )
window api* - create windows and write to them, you can have multiple windows and do everything you normally could to them
file - read and save files into/from tables or strings, read and write specific lines ( lots more coming soon )
log api - save program logs, ( add to them in your code and see whats going on if it errors )
variable api - add, remove, save, and load variables to files which can be edited normally
shape api - create and edit shapes, add rectangles and circles, draw them or add them to windows ( window api )
menu api - create lists of data, scroll through it and get individual bits in it, a simple filebrowser example ( 68 lines ) using the apis:
misc functions - split( str, pattern ), join( tArgs, pattern ), splitChars( str )
You can literally use these API's in everything:
OS - use processes and screens to manage multitasking and graphics
Door lock-use variable to save passwords and save user inputted data
API - use these to extend an API you're using
Text Editor - use the menu api to hold the lines and print them
the possibilities are endless, it's all down to your imagination
code:
pastebin: pastebin
screenies coming soon when I make some programs with the APIS
Thanks for reading :P/>
What is has:
process api* - create processes and run them ( uses coroutines )
window api* - create windows and write to them, you can have multiple windows and do everything you normally could to them
file - read and save files into/from tables or strings, read and write specific lines ( lots more coming soon )
log api - save program logs, ( add to them in your code and see whats going on if it errors )
variable api - add, remove, save, and load variables to files which can be edited normally
shape api - create and edit shapes, add rectangles and circles, draw them or add them to windows ( window api )
menu api - create lists of data, scroll through it and get individual bits in it, a simple filebrowser example ( 68 lines ) using the apis:
Spoiler
local files = menu.create( fs.list( "" ), 31, 8 )
local screen = window:create( 1, 5, 31, 9, colours.lightGrey, colours.black, " ", "filebrowser" )
local path = ""
while true do
files:set( fs.list( path ) )
screen:setCursorPos( 1, 2 )
screen:clear( )
local m = files:getSelection( )
for i = 1,#m do
screen:print( m[i] )
end
screen:draw( )
ev = { os.pullEvent( ) }
if ev[1] == "mouse_click" then
if fs.isDir( tostring( files:getContents( ev[4]-5 ) ) ) then
path = path.."/"..files:getContents( ev[4]-5 )
elseif fs.exists( tostring( files:getContents( ev[4]-5 ) ) ) then
shell.run( path.."/"..files:getContents( ev[4]-5 ) )
end
elseif ev[1] == "key" and ev[2] == keys.backspace then
local t = split( path, "/" )
table.remove( t, #t )
path = join( t, "/" )
elseif ev[1] == "mouse_scroll" then
files:scroll( ev[2] )
end
end
You can literally use these API's in everything:
OS - use processes and screens to manage multitasking and graphics
Door lock-use variable to save passwords and save user inputted data
API - use these to extend an API you're using
Text Editor - use the menu api to hold the lines and print them
the possibilities are endless, it's all down to your imagination
code:
Spoiler
--Help:
--[[
how to use:
process:
create a process-variable = process:create( function to be run, function to be run if/when it errors )
to do things with the screen-variable:[any term functions]( args )
//please note that setCursorPos will set the cursor pos relevant to the screens position
to add a screen-variable:addWindow( name, x, y, width, height, default background colour, default text colour, default text, header ( can leave blank ) )
to change screen-variable:setScreen( name ( the name given to the window when created ) )
to run the process-variable:run( event )
//this will return different things depending on how it ran and what the function returned
window:
same as process but only the graphical parts of it ( anything that says screen or window )
shape:
create a blank shape-variable = shape.create( "any name", width, height )
add things to the shape-variable:addRectangle( x, y, width, height, fill?, background colour, text colour, text )/pixel( x, y, bc, tc, text )/circle( )
to load for drawing/adding to a screen-variable:load( )
to draw-variable:draw( )
log:
to add to the log-log.add( type, ...data )
to save the log-log.save( path )
variable:
to add a variable-variable.add( str name, data )
to save the variables-variable.save( path )
to load them again-variable.load( path )
to remove one-variable.remove( str name )
file:
to save data-file.save( path, tContents or sContents )
to read the file-file.read( path, into a table? )
to change one line-file.writeLine( path, line, data )
to read one line-file.readLine( path, line )
menu:
to make a menu-variable = menu.create( data, max width, max height )
to get all the contents-variable:getSelection( )
more help coming soon
//use this if you want a list of items in table format
other:
split-splits a string with a specified pattern
join-joins a string with a specified pattern
splitChars-splits the string into each char
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
still to come:
master process = overlays to the screen
pause processes
have multiple screens drawn at the same time from each process ( currently limited to one screen at a time )
term overwriting for compatibility with functions that use term
a demo function
more shapes
advanced variable loading and protection
file protection & encryption
file classpath loading ( load files into classes )
]]
shape = {
create = function( name, x, y )
local t = { }
t.name = name
t.data = { }
for i = 1,y do
t.data[i] = { }
for k = 1,x do
t.data[i][k] = { "", colours.black, colours.white }
end
end
return setmetatable( t, { __index = shape } )
end;
load = function( self )
local t = { }
for i = 1,#self.data do
for k = 1,#self.data[i] do
if self.data[i][k][1] ~= "" then
table.insert( t, { x = k, y = i, text = self.data[i][k][1], bc = self.data[i][k][2], tc = self.data[i][k][3] } )
end
end
end
return t
end;
draw = function( self, x, y )
for i = y, ( y+#self.data )-1 do
for k = x, ( x+self.data[i] )-1 do
term.native.setCursorPos( k, i )
term.native.setBackgroundColour( self.data[i][k][2] )
term.native.setTextColour( self.data[i][k][3] )
term.native.write( self.data[i][k][1] )
end
end
end;
addRectangle = function( self, x, y, x2, y2, fill, bc, tc, text )
local bc = bc or colours.black
local tc = tc or colours.white
local text = text or " "
if not tc then tc = colours.white end
if x > x2 then x3 = x2 x2 = x x = x3 end
if y > y2 then y3 = y2 y2 = y y = y3 end
local t = { }
for i = y, y2 do
for k = x, x2 do
table.insert( t, { x = k, y = i, text = text, bc = bc, tc = tc } )
end
end
if not fill then
local i = 1
while i < #t do
if t[i].x > x and t[i].x < x2 and t[i].y > y and t[i].y < y2 then
table.remove( t, i )
i = i-1
end
i = i+1
end
end
for i = 1,#t do
if self.data[t[i].y][t[i].x] then
self.data[t[i].y][t[i].x][3] = t[i].tc
self.data[t[i].y][t[i].x][2] = t[i].bc
self.data[t[i].y][t[i].x][1] = t[i].text
end
end
end;
addPixel = function( self, x, y, bc, tc, t )
self.data[y][x] = { t, bc, tc }
end;
addCircle = function( self, x, y, r, bc, tc, text, fill )
local t = { }
for tx = x-r,x+r do
for ty = y-r,y+r do
if (math.sqrt((x-tx)^2+(y-ty)^2) >= r and math.sqrt((x-tx)^2+(y-ty)^2) <= r+(r/math.sqrt((x-tx)^2+(y-ty)^2))) then
table.insert( t, { x = tx, y = ty, text = text, bc = bc, tc = tc } )
elseif (math.sqrt((x-tx)^2+(y-ty)^2) <= r+(r/math.sqrt((x-tx)^2+(y-ty)^2))) and fill then
table.insert( t, { x = tx, y = ty, text = text, bc = bc, tc = tc } )
end
end
end
for i = 1,#t do
if self.data[t[i].y][t[i].x] then
self.data[t[i].y][t[i].x][3] = t[i].tc
self.data[t[i].y][t[i].x][2] = t[i].bc
self.data[t[i].y][t[i].x][1] = t[i].text
end
end
end;
}
window = {
create = function( link, x, y, w, h, bc, tc, dt, header )
if type( link ) ~= "table" then self = window end
local t = { }
t.xPos = 1
t.yPos = 1
t.x = x
t.y = y
t.w = w
t.h = h
t.dt = dt
t.bc = bc
t.tc = tc
t.header = { text = header, bc = bc, tc = tc }
t.screen = { }
for i = 1,h do
t.screen[i] = { }
for k = 1,w do
t.screen[i][k] = { t = dt, bc = bc, tc = tc }
end
end
return setmetatable( t, { __index = link } )
end;
update = function( self )
if self.xPos > self.w then
self.xPos = self.w
end
if self.xPos < 1 then
self.xPos = 1
end
if self.yPos > self.h then
self.yPos = self.h
end
if self.yPos < 1 then
self.yPos = 1
end
end;
move = function( self, x, y )
if x + self.x >= 1 and x + self.x + ( self.w - 1 ) <= 51 then
self.x = self.x + x
end
if y + self.y >= 1 and y + self.y + ( self.h - 1 ) <= 19 then
self.y = self.y + y
end
self:update( )
end;
moveOutOfScreen = function( self, x, y )
self.x = x
self.y = y
self:update( )
end;
draw = function( self )
local s = self.screen
for i = 1,#s do
if i > self.h then break end
for k = 1,#s[i] do
if k > self.w then break end
term.native.setCursorPos( k + ( self.x - 1 ), i + ( self.y - 1 ) )
if term.isColour( ) then
term.native.setBackgroundColour( s[i][k].bc )
term.native.setTextColour( s[i][k].tc )
end
term.native.write( string.sub( tostring( s[i][k].t ), 1, 1 ) )
end
end
if self.header.text then
self.header.text = string.sub( self.header.text, 1, self.w )
term.native.setCursorPos( ( ( self.w/2 ) - ( self.header.text:len( )/2 ) ) + self.x, self.y )
if term.isColour( ) then
term.native.setBackgroundColour( self.header.bc )
term.native.setTextColour( self.header.tc )
end
term.native.write( self.header.text )
end
self:update( )
end;
write = function( self, txt )
local t = { }
for i = 1,txt:len( ) do
table.insert( t, txt:sub( i, i ) )
end
for i = 1,#t do
if self.screen[self.yPos][self.xPos] then
self.screen[self.yPos][self.xPos] = { t = t[i], bc = self.bc, tc = self.tc }
self.xPos = self.xPos+1
if self.xPos > self.w then
self.xPos = 1
self.yPos = self.yPos + 1
end
end
end
self:update( )
end;
print = function( self, text )
self:write( text )
self.yPos = self.yPos+1
self.xPos = 1
end;
pixel = function( self, x, y, text, bc, tc )
if self.screen[y][x] then
self.screen[y][x] = { bc = bc, tc = tc, t = text }
end
end;
addShape = function( self, t )
y = self.yPos
x = self.xPos
for i = 1,#t do
self:pixel( x+t[i].x-1, y+t[i].y-1, t[i].text, t[i].bc, t[i].tc )
end
end;
setCursorPos = function( self, x, y )
self.xPos = x
self.yPos = y
self:update( )
end;
setBackgroundColour = function( self, col )
self.bc = col
self:update( )
end;
setTextColour = function( self, col )
self.tc = col
self:update( )
end;
clear = function( self )
for i = 1,#self.screen do
for k = 1,#self.screen[i] do
self.screen[i][k] = { t = self.dt, bc = self.bc, tc = self.tc }
end
end
self:update( )
end;
setHeader = function( self, text )
self.header.text = text
self:update( )
end;
setHeaderColour = function( self, col, colo )
self.header = { text = self.header.text, bc = col, tc = colo }
self:update( )
end;
}
process = {
current = false;
create = function( link, func, stopfunc )
if type( link ) ~= "table" then link = process end
local t = { }
t.co = coroutine.create( func )
t.stopco = coroutine.create( stopfunc )
t.status = "created"
t.windows = { window:create( 1, 1, 51, 19, colours.black, colours.white, " ", "[ default window ]" ) }
t.window = t.windows[1]
return setmetatable( t, { __index = link } )
end;
run = function( self, ... )
if coroutine.status( self.co ) == "dead" then
self = nil
return "removed"
end
if self.status == "stopping" then
process.current = self
err = { pcall( coroutine.resume, self.stopco, unpack( arg ) ) }
elseif self.status == "running" or self.status == "created" then
process.current = self
err = { pcall( coroutine.resume, self.co, unpack( arg ) ) }
end
process.current = false
if not err[1] then
if self.status == "stopping" then
self = nil
err[1] = "removed"
else
self.status = "stopping"
err[1] = "stopping"
end
end
return( unpack( err ) )
end;
move = function( self, x, y )
self.window:move( x, y )
end;
addWindow = function( self, index, x, y, w, h, bc, tc, dt, header )
self.windows[index] = window:create( x, y, w, h, bc, tc, dt, header )
end;
setWindow = function( self, index )
if self.windows[index] then
self.window = self.windows[index]
end
end;
getWindows = function( self )
local t = { }
for k, v in pairs( self.windows ) do
table.insert( t, k )
end
return t
end;
draw = function( self )
self.window:draw( )
end;
write = function( self, text )
self.window:write( text )
end;
print = function( self, text )
self.window:print( text )
end;
setCursorPos = function( self, x, y )
self.window:setCursorPos( x, y )
end;
setBackgroundColour = function( self, col )
self.window:setBackgroundColour( col )
end;
setTextColour = function( self, col )
self.window:setTextColour( col )
end;
clear = function( self )
self.window:clear( )
end;
setHeader = function( self, text )
self.window:setHeader( text )
end;
setHeaderColour = function( self, col, colo )
self.window:setHeaderColour( col, colo )
end;
}
join = function( t, pat )
local str = ""
if not pat then pat = "" end
for i = 1,#t do
str = str..pat..tostring( t[i] )
end
return str
end
splitChars = function( str )
t = { }
for i = 1,string.len( str ) do
table.insert( t, string.sub( str, i, i ) )
end
return t
end
split = function(str,pat)
local t = {}
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
menu = {
create = function( tContents, w, h )
local t = { }
t.contents = tContents
t.os = 0
t.w = w
t.h = h
return setmetatable( t, { __index = menu } )
end;
add = function( self, data )
table.insert( self.contents, data )
end;
remove = function( self, index )
table.remove( self.contents, index )
end;
set = function( self, tContents )
self.contents = tContents
end;
getSelection = function( self )
local h = self.h < 20 and self.h or 19
local t = { }
for i = 1+self.os,h+self.os do
if not self.contents[i] then
table.insert( t, "" )
else
table.insert( t, self.contents[i] )
end
end
for i = 1,#t do
if t[i]:len( ) > self.w then
t[i] = string.sub( t[i], 1, self.w-3 ).."..."
end
end
return t
end;
getContents = function( self, index )
if index > self.h then return nil end
return self.contents[index + self.os]
end;
getIndex = function( self, index )
return self.contents[index]
end;
scroll = function( self, am )
self.os = self.os+am
if self.os < 0 then
self.os = 0
end
if self.os+self.h >= #self.contents and #self.contents > self.h then
self.os = #self.contents - self.h
elseif #self.contents <= self.h then
self.os = 0
end
end;
}
file = {
read = function( path, intoTable )
local k = assert( fs.open( path, "r" ), "File not found" )
m = k.readAll( )
k.close( )
if intoTable then
m = split( m, "\n" )
end
return m
end;
save = function( file, data )
if type( data ) == "table" then isTable = true end
local f = fs.open( file, "w" )
if not isTable then
f.write( tostring( data ) )
else
for i = 1,#data do
f.writeLine( tostring( data[i] ) )
end
end
f.close( )
end;
writeLine = function( path, line, data )
file = file.read( path, true )
file[line] = data
file.save( path, file )
end;
readLine = function( path, line )
local t = file.read( path, true )
return t[line]
end;
}
variable = {
vars = { };
add = function( name, data )
table.insert( variable.vars, { name = name, type = type( data ), data = data } )
end;
save = function( file )
local t = { }
for i = 1,#variable.vars do
if variable.vars[i].type == "table" then
variable.vars[i].data = textutils.serialize( variable.vars[i].data )
end
table.insert( t, variable.vars[i].name..";"..variable.vars[i].type..";"..tostring( variable.vars[i].data ) )
end
k = fs.open( file, "w" )
for i = 1,#t do
k.writeLine( t[i] )
end
k.close( )
end;
remove = function( index )
if type( index ) == "string" then
for i = 1,#variable.vars do
if variable.vars[i].name == index then
table.remove( variable.vars, i )
return true
end
end
else
table.remove( variable.vars, index )
end
end;
load = function( file )
local k = assert( fs.open( file, "r" ), "File not found" )
m = k.readAll( )
k.close( )
k = split( m, "\n" )
for i = 1,#k do
m = split( k[i], ";" )
if m[2] == "table" then
m[3] = textutils.unserialize( m[3] )
elseif m[2] == "number" then
m[3] = tonumber( m[3] )
elseif m[2] == "boolean" then
if m[3] == "false" then
m[3] = false
else
m[3] = true
end
end
variable.add( m[1], m[3] )
_G[m[1]] = m[3]
end
end;
}
log = {
data = {
exlude = { };
};
save = function( path )
local logging = { }
for i = 1,#sky.log.data do
local n = false
for k = 1,#sky.log.exclude do
if sky.log.data[i].type == sky.log.exclude[k] or reading then
n = true
end
end
if not n then
table.insert( logging, sky.log.data[i] )
end
end
sky.log.data = logging
sky.file.save( path, sky.log.data, true )
return true
end;
add = function( type, ... )
local str = ""
for i = 1,#arg do
str = str.." "..tostring( arg[i] )
end
table.insert( sky.log.data, { type = type, data = ":"..str } )
end;
load = function( path )
local t = { }
t = file.read( path, true )
for i = 1,#t do
t[i] = split( t[i], ":" )
end
return t
end;
}
pastebin: pastebin
screenies coming soon when I make some programs with the APIS
Thanks for reading :P/>