- Index
- Basics
doc revision: 4
The library must be loaded before doing anything with it, obviously... There are 2 ways to do so.
There's a very simple way to import the API but it comes with a drawback:
os.loadAPI('path to the API') -- load API with CraftOS's built-in feature
The drawback that this method has is that the Library must be in a specific path to be able to be loaded, we could do something like this to make sure that the user knows what's the issue:
local APIPath = 'path to the API' -- create a variable which contains the path to the API
assert(
fs.exists(APIPath),
'APLib must be in this path: '..APIPath..'\nto be able to run this program'
) -- check if the API is in that path, if not return with an error
os.loadAPI(APIPath) -- load API with CraftOS's built-in feature
But it still isn't fixed.
It's not really advanced but it uses a feature that the API has, and that's the Library Setup! The user can setup the library by launching it with setup arg (it still has a drawback but it's less painful for the developer):
What the setup does is making a new entry on CraftOS Settings that's called 'APLibPath' which contains the path to the library (drawback: when the API is moved, setup must be redone). Here's the code to open the library by using this cool feature:
assert( -- check if setup was done before, if not return with an error
type(settings.get('APLibPath')) == 'string',
"Couldn't open APLib through path: "..tostring(
settings.get('APLibPath')
)..";\n probably you haven't completed Lib setup\n via 'LIBFILE setup' or the setup failed"
)
assert( -- check if API is still there, if not return with an error
fs.exists(settings.get('APLibPath')),
"Couldn't open APLib through path: "..tostring(
settings.get('APLibPath')
)..";\n remember that if you move the API's folder\n you must set it up again via 'LIBFILE setup'"
)
os.loadAPI(settings.get('APLibPath')) -- load API with CraftOS's built-in feature
This API tries to help you keep your app working after API updates by giving you some tables that are useful to use with some functions.
table | link |
---|---|
rectangleTypes | ref |
event | ref |
A useful table that you have to keep in mind is also the CraftOS's colors table
This table contains all types of rectangles that are available in the API (to be used with setRectangleType function)
- filled
- hollow
This table contains all events that are triggered by the API (to be used with setCallback functions)
type | event |
---|---|
global | onInfo onBClear onSetMonitor |
header | onDraw onPress |
label | onDraw onPress |
button | onDraw onPress |
menu | onDraw onPress onButtonPress |
percentagebar | onDraw onPress |
memo | onDraw onPress onEdit onCursorBlink onActivated onDeactivated |
loop | onInit onClock onEvent onTimer onMonitorChange |
Here i'll teach you how to use basic functions (nothing related to objects) that this API provides you with.
function | args | return | link |
---|---|---|---|
tableHas | table, value | boolean | ref |
setGlobalCallback | event, callback | nil | ref |
getInfo | table | ref | |
bClear | nil | ref | |
setColor | color | nil | ref |
setTextColor | color | nil | ref |
setBackgroundTextColor | color | nil | ref |
setBackground | color | nil | ref |
setRectangleType | type | nil | ref |
text | x, y, text | nil | ref |
point | x, y | nil | ref |
rectangle | x1, y1, x2, y2 | nil | ref |
This function explains itself very easily, it searches in table if value exists and it return either true or false.
Very simple like the last one... Takes an event from event.global table and then calls callback when event was triggered. example:
-- API already loaded
APLib.setGlobalCallback(
APLib.event.global.onInfo,
function (info)
print('Infos were taken! '..tostring(info))
end
)
APLib.getInfo()
Very simple like the last two... It simply returns a table which contains all infos that are stored in the API.
bClear stands for 'Better Clear', it clears the currently selected monitor and keeps its background color that can be set with setBackground function.
It saves color to a variable that's in the API so it knows with which color it should draw shapes.
It saves color to a variable that's in the API so it knows with which color it should write text.
It saves color to a variable that's in the API so it knows with which color it should draw the background of a text.
As you saw earlier this function changes the background color of the currently selected monitor and bClears it so that the monitor shows that color on the background.
Takes a type from rectangleTypes table and stores it in a variable that's in the API so that the API knows how to draw a rectangle (the default stored type is 'filled').
-- API already loaded
APLib.setBackground(colors.green)
APLib.setColor(colors.blue)
APLib.setRectangleType(APLib.rectangleTypes.hollow)
APLib.rectangle(1, 19, 10, 9)
Really simple... writes text at x, y.
-- API already loaded
APLib.setBackground(colors.green)
APLib.setColor(colors.blue)
APLib.setRectangleType(APLib.rectangleTypes.hollow)
APLib.rectangle(1, 19, 10, 9)
APLib.setTextColor(colors.black)
APLib.setBackgroundTextColor(colors.blue)
APLib.text(1, 19, 'Hello World!')
Simple as always! Draws a point on x, y.
Last but not least... the RECTANGLE function, draws a rectangle from x1, y1 to x2, y2.
If you're here it means that you know all the things previously explained. NOTE: Every code example should be located in the assets folder for this chapter. So, to start off this chapter i'm going to make you aware of all the types of objects that this API provides you with.
type | desc | link |
---|---|---|
Header | Label but centered on the x axis | ref |
Label | Text as object | ref |
Button | A button | ref |
Menu | A group of buttons | ref |
PercentageBar | A percentage bar | ref |
Memo | A text field | ref |
Now that you know all types of objects, I'll show you what I call 'Universal methods' (functions that are common to all objects).
function | args | return | desc |
---|---|---|---|
new | depends on the object | table | Returns a new object |
draw | nil | Draws the object | |
update | x, y, event | bool | Checks if object was pressed |
setCallback | event, callback | nil | Sets a callback for the object |
hide | bool | nil | Hides the object depending on the given bool |
To make an example of the use of every function I'll use the simplest object, and that's the header object:
-- API already loaded
-- create an header with red text color and blue background text color that says 'This is an header'
-- at y = 2
local header = APLib.Header.new(2, 'This is an header', colors.red, colors.blue)
-- NOTE: header:setCallback(event, callback) is the same as
-- writing header.setCallback(header, event, callback)
header:setCallback(
APLib.event.header.onPress,
-- self is the object itself and event is the event that was passed through update function
function (self, event)
-- here we switch the color from red to white and vice-versa every time the header is pressed
if self.colors.textColor == colors.red then
self.colors.textColor = colors.white
else
self.colors.textColor = colors.red
end
end
)
-- if you're scared of this part, don't worry it will get simplified drastically in the chapter
-- after the next one
while true do
local event = {os.pullEvent()} -- here we pull an event from the computer
-- we check if the event was a mouse_click, if it was we update the object
if event[1] == 'mouse_click' then
local x, y = event[3], event[4]
header:update(x, y, event)
-- else if a key was pressed then we hide/unhide the object
elseif event[1] == 'key' then
header:hide(not header.hidden)
end
APLib.bClear() -- clears the monitor
-- at the end of all we draw it
header:draw()
end
That code above simply creates a Header and makes it change text color when pressed and hides/unhides it when a key is pressed!
As you saw in the previous chapter i used the setCallback 'Universal method', in this chapter i'll show you the 2 'Universal events':
event | desc |
---|---|
onDraw | It's called before the object is drawn |
onPress | It's called after the object was pressed and gives 2 arguments: 1. The object itself. 2. The event that was passed through Update 'Universal method'. |
Wasn't that easy to understand? Well, I hope so.
Loop functions:
function | args | return | desc |
---|---|---|---|
drawOnLoopClock | nil | Makes the loop draw on clock | |
drawOnLoopEvent | nil | Makes the loop draw on every event (laggy) | |
setLoopClockSpeed | sec | nil | Sets the speed of the loop clock |
setLoopTimerSpeed | sec | nil | Sets the speed of the loop timer (should be set lower than the clock) |
setLoopCallback | event, callback | nil | Sets a callback for the loop (check event table) |
loopAutoClear | bool | nil | Makes the loop clear the screen every time it draws objects |
addLoopGroup | groupName, group | nil | Adds group to groupName on loop groups where group is an Array of objects NOTE: the first object on the group is the one on top of everything and the first one to be updated so Menu should be put first as an example. |
setLoopGroup | groupName | nil | Sets currently active loop group (default: 'None') |
resetLoopSettings | nil | Deletes every custom loop group | |
stopLoop | nil | Stops the loop | |
loop | nil | Starts the loop |
Here's what we can change of the previous code with the stuff that we learned here:
-- API already loaded
-- create an header with red text color and blue background text color that says 'This is an header'
-- at y = 2
local header = APLib.Header.new(2, 'This is an header', colors.red, colors.blue)
-- NOTE: header:setCallback(event, callback) is the same as
-- writing header.setCallback(header, event, callback)
header:setCallback(
APLib.event.header.onPress,
-- self is the object itself and event is the event that was passed through update function
function (self, event)
-- here we switch the color from red to white and vice-versa every time the header is pressed
if self.colors.textColor == colors.red then
self.colors.textColor = colors.white
-- NEW STUFF
-- switching between the 2 draw modes (difference shouldn't be noticeable with what
-- we're working with)
APLib.drawOnLoopEvent()
else
self.colors.textColor = colors.red
-- NEW STUFF
-- switching between the 2 draw modes (difference shouldn't be noticeable with what
-- we're working with)
APLib.drawOnLoopClock()
end
end
)
-- NEW STUFF
-- Adding loop group 'Main' and putting the Header in it
APLib.addLoopGroup('Main', {header})
-- Setting 'Main' as the current loop group
APLib.setLoopGroup('Main')
-- Setting loop clock speed very slow to show the difference between the two modes
APLib.setLoopClockSpeed(3)
-- Setting loop timer speed very fast to show the difference between the two modes
APLib.setLoopTimerSpeed(0.1) -- this is overkill on this app btw
-- I'm lazy so i don't want to clear the screen by myself
APLib.loopAutoClear(true)
-- Adding loop callback onInit and onEvent
APLib.setLoopCallback(
APLib.event.loop.onInit,
function ()
print('Starting loop in 3 sec!')
sleep(3)
APLib.bClear()
end
)
APLib.setLoopCallback(
APLib.event.loop.onEvent,
function (event)
if event[1] == 'key' then
APLib.stopLoop()
end
end
)
-- Starting the loop
APLib.loop()
-- If loop ends then reset loop groups
APLib.resetLoopSettings()
-- Clearing screen
APLib.bClear()
It's just a Label but centered on the x axis, its text can be changed but the x axis gets adjusted only when drawn or updated.
It's only got 'Universal methods'.
It's only got 'Universal events'.
Already done in Making the loop easy (kind of) and 'Universal methods'
It's just a text but as an object, so it stays in a variable and it's x and y can be changed on the fly.
It's only got 'Universal methods'.
It's only got 'Universal events'.
A simple program that makes the label move depending on which arrow key was pressed and shows the difference between clock draw and event draw:
-- API already loaded
-- create a label with red text color and blue background text color that says 'ClockDraw'
-- at x = 1, y = 1
local label = APLib.Label.new(1, 1, 'ClockDraw', colors.red, colors.blue)
-- creating onPress label callback
label:setCallback(
APLib.event.label.onPress,
function (self, event)
-- here we switch the color from red to white and vice-versa every time the label is pressed
if self.colors.textColor == colors.red then
self.colors.textColor = colors.white
-- making the user know what's the current loop draw mode
self.text = 'EventDraw'
-- switching between the 2 draw modes (difference should now be noticeable with what
-- we're working with)
APLib.drawOnLoopEvent()
else
self.colors.textColor = colors.red
-- making the user know what's the current loop draw mode
self.text = 'ClockDraw'
-- switching between the 2 draw modes (difference should now be noticeable with what
-- we're working with)
APLib.drawOnLoopClock()
end
end
)
-- Adding loop group 'Main' and putting the Label in it
APLib.addLoopGroup('Main', {label})
-- Setting 'Main' as the current loop group
APLib.setLoopGroup('Main')
-- Setting loop clock speed very slow to show the difference between the two modes
APLib.setLoopClockSpeed(3)
-- Setting loop timer speed very fast to show the difference between the two modes
APLib.setLoopTimerSpeed(0.1)
-- I'm lazy so i don't want to clear the screen by myself
APLib.loopAutoClear(true)
-- Adding loop callback onInit and onEvent
APLib.setLoopCallback(
APLib.event.loop.onInit,
function ()
print('Starting loop in 1 sec!')
sleep(1)
APLib.bClear()
end
)
APLib.setLoopCallback(
APLib.event.loop.onEvent,
function (event)
if event[1] == 'key' then
-- making the label move depending on which arrow key was pressed
if event[2] == 200 then -- UP_ARROW_KEY
label.pos.y = label.pos.y - 1 -- making the label go up by 1 pixel
elseif event[2] == 208 then -- DOWN_ARROW_KEY
label.pos.y = label.pos.y + 1 -- making the label go down by 1 pixel
elseif event[2] == 205 then -- RIGHT_ARROW_KEY
label.pos.x = label.pos.x + 1 -- making the label go right by 1 pixel
elseif event[2] == 203 then -- LEFT_ARROW_KEY
label.pos.x = label.pos.x - 1 -- making the label go left by 1 pixel
-- if another button was pressed then stop loop
else
APLib.stopLoop()
end
end
end
)
-- Starting the loop
APLib.loop()
-- If loop ends then reset loop groups
APLib.resetLoopSettings()
-- Clearing screen
APLib.bClear()
It's just a rectangle that changes color depending on self.state
.
NOTE: Button's text could go out of it if it's too long.
It's only got 'Universal methods'.
It's only got 'Universal events'.
-- API already loaded
-- create a button with blue text color and 'transparent' background text color
-- that says 'Button' from x = 1, y = 1, to x = 10, y = 5
-- When it's on a true state it will be green and when on a false state red
local button = APLib.Button.new(1, 1, 10, 5, 'Button', colors.blue, nil, colors.green, colors.red)
-- creating onPress button callback
button:setCallback(
APLib.event.button.onPress,
function (self, event)
-- if when the button was pressed its state was changed to true then
if self.state then
local _colors = {colors.blue, colors.yellow, colors.white}
-- pick a random color from _colors array and change button's text color to it
self.colors.textColor = _colors[math.random(#_colors)]
self:draw()
-- switching button's state to its false one after .5 seconds
sleep(0.5)
self.state = false
end
end
)
-- Adding loop group 'Main' and putting the button in it
APLib.addLoopGroup('Main', {button})
-- Setting 'Main' as the current loop group
APLib.setLoopGroup('Main')
-- This time i'm keeping the default clock and timer's speeds
-- Drawing on loop event
APLib.drawOnLoopEvent()
-- I'm lazy so i don't want to clear the screen by myself
APLib.loopAutoClear(true)
-- Adding loop callback onInit and onEvent
APLib.setLoopCallback(
APLib.event.loop.onInit,
function ()
print('Starting loop in 1 sec!')
sleep(1)
APLib.bClear()
end
)
APLib.setLoopCallback(
APLib.event.loop.onEvent,
function (event)
if event[1] == 'key' then
-- making the button move depending on which arrow key was pressed
if event[2] == 200 then -- UP_ARROW_KEY
button.pos.y1 = button.pos.y1 - 1 -- making the button go up by 1 pixel
button.pos.y2 = button.pos.y2 - 1
elseif event[2] == 208 then -- DOWN_ARROW_KEY
button.pos.y1 = button.pos.y1 + 1 -- making the button go down by 1 pixel
button.pos.y2 = button.pos.y2 + 1
elseif event[2] == 205 then -- RIGHT_ARROW_KEY
button.pos.x1 = button.pos.x1 + 1 -- making the button go right by 1 pixel
button.pos.x2 = button.pos.x2 + 1
elseif event[2] == 203 then -- LEFT_ARROW_KEY
button.pos.x1 = button.pos.x1 - 1 -- making the button go left by 1 pixel
button.pos.x2 = button.pos.x2 - 1
-- if another key was pressed then stop loop
else
APLib.stopLoop()
end
end
end
)
-- Starting the loop
APLib.loop()
-- If loop ends then reset loop groups
APLib.resetLoopSettings()
-- Clearing screen
APLib.bClear()
It's basically an array of Buttons but when it's drawn it draws all of them and when updated it updates all of them too. NOTE: I'm sorry but Menu can't be moved... sorry, won't do a moving menu in the example.
It's got 'Universal methods' and also:
function | args | return | desc |
---|---|---|---|
set | table, fillmenu | nil | Puts table (of buttons) into itself and if fillmenu is set to true it will resize all buttons to fit perfectly in it and it will reject if there's more than it can hold*.* |
It's got 'Universal events' and also:
event | desc |
---|---|
onButtonPress | When a button in that menu is pressed it will call this event with args: 1. The object itself. 2. The button that was pressed. 3. The event that was passed through Update 'Universal method'. |