├── .luacheckrc ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── main.lua ├── notes.txt ├── os ├── dat │ └── cour.ttf ├── globals.lua ├── lib │ ├── app.lua │ ├── gra.lua │ └── lgc.lua └── sysapps │ └── taskmgr.lua ├── packages └── api.lua └── programs ├── notepad.lua └── test.lua /.luacheckrc: -------------------------------------------------------------------------------- 1 | stds.sOS = { 2 | globals = { 3 | 'state', 'apps', 'grid', 4 | 'gra', 'app', 'lgc', 'api', 'utf8', 5 | }; 6 | read_globals = {}; 7 | } 8 | 9 | 10 | local trav = os.getenv('TRAVIS_BUILD_DIR') 11 | 12 | 13 | return { 14 | codes = true; 15 | std = 'luajit+love+sOS'; 16 | ignore = { 17 | '611', 18 | }; 19 | exclude_files = { 20 | trav..'./programs/test.lua' 21 | }; 22 | files = { 23 | ['main.lua'] = { 24 | ignore = { 25 | '212' 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | 4 | env: 5 | - LUA="luajit 2.0" 6 | - LUA="luajit 2.1" 7 | 8 | before_install: 9 | - pip install hererocks 10 | - hererocks env --$LUA -rlatest 11 | - source env/bin/activate 12 | 13 | - luarocks install luafilesystem 14 | - luarocks install luacheck 15 | # - luarocks install luacov # these come later once we have unit tests >:D 16 | # - luarocks install luacov-coveralls 17 | # - luarocks install busted 18 | 19 | install: 20 | # - luarocks make 21 | - echo 'build' 22 | 23 | script: 24 | - luacheck $TRAVIS_BUILD_DIR/os $TRAVIS_BUILD_DIR/packages $TRAVIS_BUILD_DIR/programs $TRAVIS_BUILD_DIR/main.lua 25 | # - busted 26 | 27 | after_success: 28 | # - luacov-coveralls 29 | 30 | notifications: 31 | email: 32 | recipients: 33 | - zeeatgit@gmail.com 34 | on_success: change 35 | on_failure: change -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # If you find a bug or have a suggestion you wish to bring to our attention... 2 | 3 | Make a post on the 'Issues' tab of the SolarsSupremacy/sOS repository. 4 | 5 | # If you want to fix an existing or newly discovered bug yourself... 6 | 7 | Make sure there is an issue posted about it and that you put in the description (or comment if there already is one) that you are fixing the bug yourself and will make a source pull request. 8 | 9 | # If you want to contribute to sOS... 10 | 11 | I strongly recommend you join our Discord server (avaliable in README.md). We would be happy to work with you or help you work with us on our tasks. However, if Discord isn't an option, making a pull request and including details of what you changed/added and why you did it would be the best optoin. 12 | 13 | # If you want to develop sOS apps... 14 | 15 | We don't have a universal place for uploading / downloading apps yet, but we have a channel in Discord for it. Again, I recommend you join as it's arguably the most important part of the sOS community. 16 | 17 | Thank you! 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SolarSupremacy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solar Operating System (sOS) - 0.1 2 | The ASCII operating system nobody asked for. 3 | 4 | Join us on Discord! https://discord.gg/fpTu8Eb 5 | 6 | # What is sOS? 7 | sOS is a simulation of a text-based OS written in Lua with the help of LÖVE 2D. Apps can also be loaded, allowing you to develop or download anything you can imagine and run it in sOS! This is completely safe for you as a user to download random lua scripts on the internet and throw them in /programs/ because all apps are loaded in a sandboxed environment. The apps only get access to math functions, the sOS api, and a few other utilities. 8 | 9 | # How to run sOS 10 | You need to have LOVE 2D installed to run sOS. If you have ZeroBrane IDE installed, you can open sOS as a project, go to Project > Lua Interpreter and set it to LOVE, then use F6 to execute. Otherwise, drag the *folder* that sOS is in onto 'love.exe'. 11 | 12 | # New Version News - 0.1 13 | 0.1 is our first major-ish milestone. It feels weird calling it that because sOS is still a buggy-as-hell text based pseudo operating system written in Lua, but it's here. Apps can now be loaded, closed, we have a new and slightly more optimised method of rendering. Now, you have one app which is pretty much fullscreened in the middle of the screen and a sidebar on each side displaying current running apps and other system information. We've got a long way to go, but for a project that started less than a week ago (yeah, I know... o_O) we've made it pretty far. 14 | 15 | Stay tuned! 16 | 17 | # Controls 18 | 19 | *On the Left...* 20 | 21 | **Tab** (or **Shift + Tab**) cycles through open apps. Even when apps are open, you can cycle through the 'no app' entry, making all apps run in the background. 22 | 23 | **Escape** closes the currentlty selected app. If no app is selected (described above), Escape closes sOS. 24 | 25 | *On the Right...* 26 | 27 | **Page Up** and **Page Down** cycle through the apps detected. The selected app has a '>' next to it. 28 | 29 | **End** switches between selecting system apps (on the top) and user apps (on the bottom). 30 | 31 | **Home** starts a new process with the app selected. 32 | 33 | # App Development Documentation 34 | App development uses S-Code, which is just an easier way of saying environment-limited Lua with sOS api. The link for the setup for the sandbox environment is here: https://hastebin.com/acolabiqez.lua You may use any Lua functions included in there, including the api functions at the bottom. This page will be updated as more features are implimented. 35 | 36 | # API.G - Graphics 37 | > api.g.set(x, y, char) 38 | 39 | Inputs: 'x' and 'y' are the coordinates for the character, with (1, 1) being the top left. 'char' should be a single character. 40 | 41 | Result: 'char' is put onto that coordinate on the canvas to be rendered in the next draw(). Use in draw(). 42 | 43 | Return: true 44 | 45 | > api.g.get(x, y) 46 | 47 | Inputs: 'x' and 'y' are the coordinates for the character, with (1, 1) being the top left. 48 | 49 | Result: Fetches the char at that coordinate from the last draw(). Use in tick(). 50 | 51 | Return: string 52 | 53 | > api.g.text(x, y, str) 54 | 55 | Inputs: 'x' and 'y' are the coordinates for the start of the string, with (1, 1) being the top left. 'str' should be a string of one or more characters. 56 | 57 | Result: 'str' is put onto that coordinate on the canvas to be rendered in the next draw(). Use in draw(). 58 | 59 | Return: true 60 | 61 | > api.g.box(x, y, w, h, adapt) 62 | 63 | Inputs: 'x' and 'y' are the coordinates for the start of the box, with (1, 1) being the top left. 'w' and 'h' are the width and height of the outside of the box, so the inside is 2 units less on each dimension. 'adapt' is a boolean for if the edges and corners of the box being drawn should automatically reformat to make grids or intersecting lines instead of overwriting the edges of other boxes. 64 | 65 | Result: Draws a rectangle out of ASCII characters. Adapt has special effects described above. 66 | 67 | Return: true 68 | 69 | > api.g.bar(x, y, legth, direction, style, percentage) 70 | 71 | Inputs: 'x' and 'y' are coordinates for the start of the bar, with (1, 1) being the top left. 'length' is how many characters long the bar should be. 'direction' is the direction, from the start, that the bar will go in. 'style' is the appearance of the bar (more info on styles later, current styles are 'block' and 'fade'). 'percentage' is how much of the bar should be filled. 72 | 73 | Result: Creates a progress-bar display using characters. Bars always round DOWN to the nearest unique display, so 0.9999 will not fill the bar, only 1.0 (or greater) will. 0.0 will always be an empty bar. 74 | 75 | Return: true 76 | 77 | # API.I - Input 78 | > api.i.keyStat(key) 79 | 80 | Inputs: 'key' is a string for the name of the key to be checked. For example, "a", "shift", "space". 81 | 82 | Result: Checks to see if the key is being pressed. Will not detect keys if not active app. 83 | 84 | Return: true if key is pressed, false otherwise. 85 | 86 | # API.S - System (only avaliable to system apps, which you can also develop if you wish) 87 | > api.s.appsTable() 88 | 89 | Inputs: Nothing. 90 | 91 | Result: Returns (a deep copy of) the table of apps. This is a bit more complicated and will be documented on the wiki later. 92 | 93 | Return: apps (Table) 94 | 95 | # Called Functions 96 | The following functions are called by sOS. This is also the order in which they are called, so code accordingly. 97 | 98 | > load() 99 | 100 | Called once on load. Should contain information about the app. 101 | 102 | > textInput(char) 103 | 104 | Optional. 'char' is a character typed and formatted correctly. For example, if you hold 'shift' and hit 'a', this function will call with the argument 'A'. Useful for easy typing. 105 | 106 | > keyPress(key, rep) 107 | 108 | Optional. 'key' is the name of a key. 'rep' is if the call is because of the key being repeated without releasing it, just like if you hold a key in a chat box and it types one letter, pauses, and then repeats that character. This is defined by your actual operating system and can be ignored by ignoring the call if 'rep' is true. 109 | 110 | > keyRelease(key) 111 | 112 | Optional. 'key' is the name of a key. This function is called if a key is released. 113 | 114 | > tick() 115 | 116 | Called every tick. Still has access to last cycle's canvas, so api.g.get() will still work. 117 | 118 | *The canvas is reset after tick() and before draw().* 119 | 120 | > draw(width, height) 121 | 122 | Called after every tick. Now is the time to draw things onto the canvas to display. 'width' and 'height' are arguments for the current canvas width and height. 123 | 124 | # App Template and Other Information 125 | 126 | This is a template: https://hastebin.com/iqukigiril.lua 127 | It doesn't do anything but set up the app. 128 | 129 | The app must start with 'local app = {}' and end with 'return (app)'. 130 | All functions must start with 'app.', such as 'app.load()' or 'app.customFunction()'. 131 | 132 | Apps must be placed into the /programs/ folder of sOS. They will be automatically be detected. 133 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | --[[ Solar Operating System 2 | 3 | ╔═════╦═════╗ 4 | ║ ║ ║ 5 | ║ ║ ║ ═══╣ 6 | ╔═════╣ ║ ║ ║ 7 | ║ ═══╣ ║ ╠═══ ║ 8 | ╠═══ ║ ║ ║ 9 | ╚═════╩═════╩═════╝ 10 | Version: 0.1 11 | 12 | ╔────────────────╗ 13 | │ ▄▄ █▄▀██▄▀█ ▄▀ │ 14 | │ ▄▄█ ▀▄▄ █▄█▄▄ │ 15 | │ ▄█ ▄█ ▀▄▀▄▄▄▀ │ 16 | │ █▄▄▀ ▄▄▀ █▄█▀▄ │ 17 | ╚────────────────╝ 18 | ]] 19 | 20 | -- local core = require("sos.core") 21 | 22 | require 'os.globals' -- load globals 23 | 24 | local gra, app, love, crypto = gra, app, love, crypto 25 | 26 | function love.run() 27 | 28 | if love.math then 29 | love.math.setRandomSeed(os.time()) 30 | end 31 | 32 | if love.load then love.load(arg) end 33 | 34 | if love.timer then love.timer.step() end 35 | 36 | local dt = 0 37 | 38 | while true do 39 | -- Process events. 40 | if love.event then 41 | love.event.pump() 42 | for name, a,b,c,d,e,f in love.event.poll() do 43 | if name == "quit" then 44 | if not love.quit or not love.quit() then 45 | return a 46 | end 47 | end 48 | love.handlers[name](a,b,c,d,e,f) 49 | end 50 | end 51 | 52 | if love.timer then 53 | love.timer.step() 54 | dt = love.timer.getDelta() 55 | end 56 | if love.update then love.update(dt) end 57 | 58 | if love.graphics and love.graphics.isActive() then 59 | love.graphics.clear(love.graphics.getBackgroundColor()) 60 | love.graphics.origin() 61 | if love.draw then love.draw() end 62 | love.graphics.present() 63 | end 64 | 65 | -- if love.timer then love.timer.sleep(0.0001) end 66 | end 67 | 68 | end 69 | 70 | function love.load() 71 | 72 | -- Loading Files 73 | local mainFont = love.graphics.newFont("os/dat/cour.ttf") 74 | 75 | systemApps = love.filesystem.getDirectoryItems("os/sysapps") 76 | userApps = love.filesystem.getDirectoryItems("programs") 77 | 78 | -- Graphics 79 | love.graphics.setBackgroundColor(0, 0, 0) 80 | --love.window.setMode(800, 600) 81 | love.window.setFullscreen(true) 82 | 83 | -- Processing 84 | ticks = 0 85 | 86 | love.keyboard.setKeyRepeat(true) 87 | love.graphics.setFont(mainFont) 88 | local fontWidth = mainFont:getWidth(" ") -- 7 89 | local fontHeight = mainFont:getHeight(" ") -- 14 90 | 91 | math.randomseed(os.time()) 92 | 93 | -- populate global grid object 94 | grid.width = math.floor(love.graphics.getWidth() / fontWidth) 95 | grid.height = math.floor(love.graphics.getHeight() / fontHeight) 96 | grid.widthbuffer = (love.graphics.getWidth() - grid.width * fontWidth) / 2 97 | grid.heightbuffer = (love.graphics.getHeight() - grid.height * fontHeight) / 2 98 | grid.fontwidth = fontWidth 99 | grid.fontheight = fontHeight 100 | 101 | -- Load Apps 102 | --[[ 103 | for k,v in ipairs(systemApps) do 104 | app.newTask(love.filesystem.getSource( ).. "/os/sysapps/"..v, "SYS") 105 | end 106 | for k,v in ipairs(userApps) do 107 | app.newTask(love.filesystem.getSource( ).. "/programs/"..v, "APP") 108 | end 109 | --]] 110 | 111 | end 112 | 113 | function love.update(dt) 114 | -- Tick Counter 115 | ticks = ticks + 1 116 | 117 | -- OS Controls 118 | 119 | --[[ Window Moving 120 | if love.keyboard.isDown("lctrl") or love.keyboard.isDown("rctrl") then 121 | if ticks % 2 == 0 then 122 | local pen = appManager[1] 123 | if love.keyboard.isDown("up") then 124 | apps[pen].y = apps[pen].y - 1 125 | end 126 | if love.keyboard.isDown("down") then 127 | apps[pen].y = apps[pen].y + 1 128 | end 129 | if love.keyboard.isDown("left") then 130 | apps[pen].x = apps[pen].x - 1 131 | end 132 | if love.keyboard.isDown("right") then 133 | apps[pen].x = apps[pen].x + 1 134 | end 135 | end 136 | end 137 | --]] 138 | 139 | -- Process processor for processing processes 140 | for pid,_ in pairs(apps) do 141 | -- ID for graphics functions to handle 142 | state.pid = pid 143 | 144 | -- Run the app 145 | local status, err = pcall(apps[pid].code.tick) 146 | 147 | if status then 148 | apps[pid].code.tick() 149 | else 150 | apps[pid].err = err 151 | end 152 | 153 | 154 | 155 | 156 | end 157 | 158 | 159 | end 160 | 161 | function love.draw() 162 | 163 | state.pid = 0 164 | 165 | -- Reset Screen 166 | canvas = {} 167 | for i=1, grid.height do 168 | canvas[i] = {} 169 | for j=1, grid.width do 170 | canvas[i][j] = " " 171 | end 172 | end 173 | 174 | -- Reset Apps 175 | --[[ 176 | for pen,_ in pairs(apps) do 177 | gra.appCanvasReset(pen) 178 | end 179 | --]] 180 | 181 | -- Draw Apps 182 | if state.active ~= 0 then 183 | local pid = appList[state.active] 184 | gra.appCanvasReset(pid) 185 | 186 | state.pid = pid 187 | 188 | local status, err = pcall(apps[pid].code.draw, grid.width-66, grid.height) 189 | 190 | state.pid = 0 191 | 192 | if status then 193 | --apps[pen].code.draw(grid.width-66, grid.height) 194 | else 195 | apps[pid].err = err 196 | end 197 | 198 | if apps[pid].err ~= "" then 199 | api.g.area(1, 1, string.len(apps[pid].err) + 6, 6, "!") 200 | api.g.box(2, 2, string.len(apps[pid].err) + 4, 4, false) 201 | api.g.text(4, 3, apps[pid].err) 202 | api.g.text(4, 4, "'\\' to close error.") 203 | end 204 | 205 | --[[ 206 | for i=1, grid.height do 207 | for j=1, grid.width - 66 do 208 | gra.set(j+33, i, gra.appGet(pid, j, i)) 209 | end 210 | end 211 | --]] 212 | end 213 | 214 | -- Draw System Info 215 | --gra.setColor(15) 216 | api.g.area(32, 1, 1, grid.height, "-") 217 | api.g.area(grid.width-31, 1, 1, grid.height, "-") 218 | 219 | api.g.box(grid.width-29, 20, 30, #systemApps+2) 220 | for k,v in ipairs(systemApps) do 221 | if (state.selectType == 1) and (state.selectNum == k) then 222 | api.g.text(grid.width-27, 20+k, ">") 223 | end 224 | api.g.text(grid.width-25, 20+k, v) 225 | end 226 | 227 | api.g.box(grid.width-29, 20+#systemApps+2, 30, #userApps+2) 228 | for k,v in ipairs(userApps) do 229 | if (state.selectType == 2) and (state.selectNum == k) then 230 | api.g.text(grid.width-27, 20+k+#systemApps+2, ">") 231 | end 232 | api.g.text(grid.width-25, 20+k+#systemApps+2, v) 233 | end 234 | 235 | 236 | api.g.box(1, 1, 30, grid.height) 237 | local i = 0 238 | local pid 239 | local app 240 | for k,v in ipairs(appList) do 241 | pid = v 242 | app = apps[v] 243 | i = i + 1 244 | api.g.box(1, 1+(i-1)*4, 30, 5, true) 245 | api.g.text(3, 2+(i-1)*4, app.title) 246 | api.g.text(26, 2+(i-1)*4, app.tag) 247 | api.g.text(3, 3+(i-1)*4, "PID: " .. pid) 248 | 249 | if pid == appList[state.active] then 250 | api.g.text(20, 3+(i-1)*4, ">>>>>>") 251 | end 252 | 253 | if app.err ~= "" then 254 | api.g.text(3, 4+(k-1)*4, "Error!") 255 | end 256 | end 257 | 258 | api.g.area(grid.width-11, 1, 12, 7, " ") 259 | api.g.box(grid.width-11, 1, 12, 3) 260 | api.g.box(grid.width-11, 3, 12, 3, true) 261 | api.g.box(grid.width-11, 5, 12, 3, true) 262 | api.g.text(grid.width-9, 2, os.date():sub(10, 17)) 263 | api.g.text(grid.width-9, 4, os.date():sub(1, 8)) 264 | api.g.text(grid.width-9, 6, "TPS: " .. love.timer.getFPS()) 265 | 266 | -- Print Everything 267 | 268 | ---[[ 269 | local line 270 | for i=1, grid.height do 271 | line = "" 272 | for j=1, grid.width do 273 | if not (canvas[i][j] == nil) then 274 | line = line .. canvas[i][j] 275 | else 276 | line = line .. "!" 277 | end 278 | 279 | end 280 | love.graphics.print(line ,grid.widthbuffer, grid.heightbuffer + 14 * (i-1)) 281 | end 282 | --]] 283 | 284 | -- **** ALTERNATE PRINT METHODS FOR COLOR! NEEDS OPTIMIZATION! **** 285 | 286 | --[[ 287 | for i=1, grid.height do 288 | line = "" 289 | start = 0 290 | for j=1, grid.width do 291 | if start < 1 then 292 | start = j 293 | line = "" 294 | end 295 | if colorOut[i][j] ~= currentPrintColor then 296 | love.graphics.print(line, grid.widthbuffer + (start-1)*grid.fontwidth, 297 | grid.heightbuffer + (i-1)*grid.fontheight) 298 | line = canvas[i][j] 299 | gra.setColor(colorOut[i][j]) 300 | start = j 301 | elseif j == grid.width then 302 | line = line..canvas[i][j] 303 | love.graphics.print(line, grid.widthbuffer + (start-1)*grid.fontwidth, 304 | grid.heightbuffer + (i-1)*grid.fontheight) 305 | start = 0 306 | line = "" 307 | else 308 | line = line..canvas[i][j] 309 | end 310 | 311 | end 312 | 313 | end 314 | --]] 315 | 316 | --[[ 317 | finalPrint = {gra.getColor(15)} 318 | text = "" 319 | currentPrintColor = -1 320 | for i=1, #canvas do 321 | 322 | for j=1, #canvas[1] do 323 | 324 | if colorOut[i][j] ~= currentPrintColor then 325 | table.insert(finalPrint, text) 326 | table.insert(finalPrint, gra.getColor(colorOut[i][j])) 327 | text = "" 328 | end 329 | 330 | text = text .. canvas[i][j] 331 | 332 | end 333 | 334 | text = text .. "\n" 335 | end 336 | table.insert(finalPrint, text) 337 | love.graphics.print(finalPrint ,grid.widthbuffer, grid.heightbuffer) 338 | --]] 339 | 340 | --[[ 341 | colorPrints = {} 342 | for i=0, 15 do 343 | colorPrints[i] = {} 344 | end 345 | 346 | 347 | 348 | 349 | for i=1, #canvas do 350 | 351 | for j=1, #canvas[1] do 352 | 353 | for k=0, 15 do 354 | 355 | if colorOut[i][j] == k then 356 | table.insert(colorPrints[k], canvas[i][j]) 357 | else 358 | table.insert(colorPrints[k], " ") 359 | end 360 | 361 | end 362 | end 363 | for k=0, 15 do 364 | table.insert(colorPrints[k], "\n") 365 | end 366 | end 367 | 368 | for i=0, 15 do 369 | gra.setColor(i) 370 | love.graphics.print(table.concat(colorPrints[i]), grid.widthbuffer, grid.heightbuffer) 371 | 372 | 373 | end 374 | --]] 375 | 376 | end 377 | 378 | function setCanvas(x, y, char) 379 | canvas[y][x] = char 380 | end 381 | 382 | function getCanvas() 383 | return (canvas) 384 | end 385 | 386 | function love.textinput(char) 387 | 388 | -- App Controls 389 | if state.active ~= 0 and apps[appList[state.active]].code.textInput ~= nil then 390 | apps[appList[state.active]].code.textInput(char) 391 | end 392 | end 393 | 394 | function love.keypressed(key, scan, rep) 395 | 396 | if key == "\\" and state.active ~= 0 then 397 | print(state.active) 398 | apps[state.active].err = "" 399 | end 400 | 401 | -- OS Controls 402 | if love.keyboard.isDown("lctrl") or love.keyboard.isDown("rctrl") or true then 403 | 404 | if key == "tab" then 405 | if love.keyboard.isDown("lshift") then 406 | state.active = (state.active - 1) % (#appList + 1) 407 | else 408 | state.active = (state.active + 1) % (#appList + 1) 409 | end 410 | 411 | end 412 | 413 | if key == "escape" then 414 | if state.active == 0 then 415 | love.event.quit() 416 | elseif state.active <= #appList then 417 | app.endTask(appList[state.active]) 418 | if state.active > #appList then state.active = #appList end 419 | end 420 | end 421 | 422 | if key == "end" then 423 | state.selectType = (state.selectType) % 2 + 1 424 | state.selectNum = 1 425 | end 426 | 427 | if key == "pageup" then 428 | if state.selectType == 1 then 429 | state.selectNum = (state.selectNum - 2) % #systemApps + 1 430 | elseif state.selectType == 2 then 431 | state.selectNum = (state.selectNum - 2) % #userApps + 1 432 | end 433 | end 434 | 435 | if key == "pagedown" then 436 | if state.selectType == 1 then 437 | state.selectNum = (state.selectNum) % #systemApps + 1 438 | elseif state.selectType == 2 then 439 | state.selectNum = (state.selectNum) % #userApps + 1 440 | end 441 | end 442 | 443 | if key == "home" then 444 | if state.selectType == 1 then 445 | app.newTask(love.filesystem.getSource( ).. "/os/sysapps/"..systemApps[state.selectNum], "SYS") 446 | elseif state.selectType == 2 then 447 | app.newTask(love.filesystem.getSource( ).. "/programs/"..userApps[state.selectNum], "APP") 448 | end 449 | end 450 | end 451 | 452 | -- App Controls 453 | 454 | if state.active ~= 0 then 455 | if apps[appList[state.active]].code.keyPress ~= nil then 456 | apps[appList[state.active]].code.keyPress(key, rep) 457 | end 458 | end 459 | 460 | end 461 | 462 | function love.keyreleased(key, scan) 463 | 464 | -- App Controls 465 | if state.active ~= 0 and apps[appList[state.active]].code.keyRelease ~= nil then 466 | apps[state.active].code.keyRelease(key) 467 | end 468 | end 469 | -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | Fade 2 | █▓▒░ 3 | 4 | Bar Level 5 | █▄▀■ 6 | 7 | Box Chars 8 | ╔╦═╗ 9 | ╠╬ ╣ 10 | ║ 11 | ╚╩ ╝ 12 | 13 | ┌┬─┐ 14 | ├┼ ┤ 15 | │ 16 | └┴ ┘ 17 | 18 | -------------------------------------------------------------------------------- /os/dat/cour.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolarSupremacy/sOS/935cc09e0d8989026199299d2d948c10381b7a32/os/dat/cour.ttf -------------------------------------------------------------------------------- /os/globals.lua: -------------------------------------------------------------------------------- 1 | grid = {} 2 | 3 | canvas = {} 4 | 5 | systemApps = {} 6 | userApps = {} 7 | 8 | ticks = 0 9 | 10 | state = {} 11 | --state.activePEN = 0 12 | --state.currentPEN = 0 13 | state.active = 0 14 | state.pid = 0 15 | state.selectType = 1 16 | state.selectNum = 1 17 | 18 | apps = {} 19 | 20 | appList = {} 21 | 22 | gra = require("os.lib.gra") 23 | app = require("os.lib.app") 24 | lgc = require("os.lib.lgc") 25 | api = require("packages.api") 26 | utf8 = require("utf8") -------------------------------------------------------------------------------- /os/lib/app.lua: -------------------------------------------------------------------------------- 1 | local app = {} 2 | 3 | -- sOS Applications Library 4 | 5 | function app.newTask(dir, tag) 6 | 7 | -- Generating new 1000 - 9999 PID 8 | local pid 9 | local good 10 | while true do 11 | pid = ('%d'):format(love.math.random(1000, 9999)) 12 | good = true 13 | for v,_ in pairs(apps) do 14 | if v == pid then good = false end 15 | end 16 | if good then break end 17 | end 18 | 19 | -- Creating app in table apps. 20 | apps[pid] = {} 21 | apps[pid].code = {} 22 | apps[pid].dir = dir 23 | apps[pid].tag = tag 24 | apps[pid].err = "" 25 | 26 | app.newEnvironment(dir, pid) 27 | 28 | -- Running load() function to setup app. 29 | local appTable = apps[pid].code.load() 30 | apps[pid].title = appTable.title or "Untitled App, PID: " .. pid 31 | apps[pid].mini = appTable.mini or false 32 | apps[pid].max = appTable.max or 1 33 | 34 | --gra.appCanvasReset(pid) 35 | 36 | print("New Task Created. "..pid.." - "..apps[pid].title) 37 | 38 | table.insert(appList, pid) 39 | 40 | local similar = 0 41 | for _,v in pairs(apps) do 42 | if (v.title == apps[pid].title) then similar = similar + 1 end 43 | end 44 | if similar > apps[pid].max and apps[pid].max ~= -1 then app.endTask(pid) end 45 | 46 | end 47 | 48 | function app.endTask(pid) 49 | apps[pid] = nil 50 | for k,v in pairs(appList) do 51 | if v == pid then 52 | table.remove(appList, k) 53 | break 54 | end 55 | end 56 | 57 | end 58 | 59 | function app.newEnvironment(dir, pid) 60 | 61 | -- Setup Sandbox Environment 62 | local sandbox_env = { 63 | ipairs = ipairs, 64 | next = next, 65 | pairs = pairs, 66 | print = print, 67 | pcall = pcall, 68 | tonumber = tonumber, 69 | tostring = tostring, 70 | type = type, 71 | unpack = unpack, 72 | --[[coroutine = { create = coroutine.create, resume = coroutine.resume, 73 | running = coroutine.running, status = coroutine.status, 74 | wrap = coroutine.wrap },]] 75 | string = { byte = string.byte, char = string.char, find = string.find, 76 | format = string.format, gmatch = string.gmatch, gsub = string.gsub, 77 | len = string.len, lower = string.lower, match = string.match, 78 | rep = string.rep, reverse = string.reverse, sub = string.sub, 79 | upper = string.upper }, 80 | table = { insert = table.insert, maxn = table.maxn, remove = table.remove, 81 | sort = table.sort }, 82 | math = { abs = math.abs, acos = math.acos, asin = math.asin, 83 | atan = math.atan, atan2 = math.atan2, ceil = math.ceil, cos = math.cos, 84 | cosh = math.cosh, deg = math.deg, exp = math.exp, floor = math.floor, 85 | fmod = math.fmod, frexp = math.frexp, huge = math.huge, 86 | ldexp = math.ldexp, log = math.log, log10 = math.log10, max = math.max, 87 | min = math.min, modf = math.modf, pi = math.pi, pow = math.pow, 88 | rad = math.rad, random = math.random, sin = math.sin, sinh = math.sinh, 89 | sqrt = math.sqrt, tan = math.tan, tanh = math.tanh }, 90 | os = { clock = os.clock, difftime = os.difftime, time = os.time }, 91 | api = { g = { set=api.g.set, get=api.g.get, text=api.g.text, box=api.g.box, bar=api.g.bar }, 92 | i = {keyStat=api.i.keyStat}}, 93 | utf8 = { offset = utf8.offset }, 94 | lgc = { usub = lgc.usub } 95 | } 96 | 97 | if (apps[pid].tag == "SYS") then 98 | sandbox_env.api.s = {appsTable = api.s.appsTable} 99 | end 100 | 101 | -- Load app in environment 102 | local fnew = setfenv(assert(loadfile(dir, "bt")), sandbox_env) 103 | apps[pid].code = fnew() 104 | 105 | --[[ 106 | co = coroutine.create(fenv) 107 | 108 | print(coroutine.status(co)) 109 | 110 | coroutine.resume(co) 111 | print(coroutine.status(co)) 112 | 113 | coroutine.resume(co) 114 | print(coroutine.status(co)) 115 | 116 | 117 | coroutine.resume(co) 118 | print(coroutine.status(co)) 119 | ]] 120 | 121 | end 122 | 123 | return (app) -------------------------------------------------------------------------------- /os/lib/gra.lua: -------------------------------------------------------------------------------- 1 | local gra = {} 2 | 3 | -- sOS Graphics Library 4 | 5 | -- Convert color code (0-15) to RGB values 6 | local function _colorcodeToRGB(x) 7 | if (x == 0) then return 0, 0, 0 8 | elseif (x == 1) then return 128, 0, 0 9 | elseif (x == 2) then return 0, 128, 0 10 | elseif (x == 3) then return 128, 128, 0 11 | elseif (x == 4) then return 0, 0, 128 12 | elseif (x == 5) then return 128, 0, 128 13 | elseif (x == 6) then return 0, 128, 128 14 | elseif (x == 7) then return 192, 192, 192 15 | elseif (x == 8) then return 128, 128, 128 16 | elseif (x == 9) then return 255, 0, 0 17 | elseif (x == 10) then return 0, 255, 0 18 | elseif (x == 11) then return 255, 255, 0 19 | elseif (x == 12) then return 0, 0, 255 20 | elseif (x == 13) then return 255, 0, 255 21 | elseif (x == 14) then return 0, 255, 255 22 | else return 255, 255, 255 23 | end 24 | end 25 | 26 | -- currentSetColor = 15 27 | -- currentPrintColor = 15 28 | 29 | --[[ 30 | function gra.setColor(x) 31 | local r, g, b = _colorcodeToRGB(x) 32 | love.graphics.setColor(r, g, b) 33 | 34 | end 35 | --]] 36 | 37 | --[[ 38 | function gra.getColor(x) 39 | 40 | local r, g, b = _colorcodeToRGB(x) 41 | love.graphics.setColor(r, g, b) 42 | 43 | currentPrintColor = x 44 | 45 | return {r, g, b} 46 | 47 | end 48 | --]] 49 | 50 | --[[ 51 | function gra.color(color) 52 | currentSetColor = color 53 | end 54 | --]] 55 | 56 | function gra.set(x, y, str) 57 | 58 | if str == "\n" or str == "\t" then str = " " end 59 | --color = color or 15 60 | 61 | if state.pid == 0 then 62 | if (y > grid.height) or (x > grid.width) then 63 | return 64 | end 65 | if (y < 1) or (x < 1) then 66 | return 67 | end 68 | 69 | setCanvas(x, y, str) 70 | else 71 | if (y > grid.height) or (x > grid.width - 66) then 72 | return 73 | end 74 | if (y < 1) or (x < 1) then 75 | return 76 | end 77 | 78 | setCanvas(x+33, y, str) 79 | end 80 | 81 | --colorOut[y][x] = currentSetColor 82 | end 83 | 84 | function gra.get(x, y) 85 | if state.pid == 0 then 86 | if (y > grid.height) or (x > grid.width) then 87 | return (nil) 88 | end 89 | return (getCanvas()[y][x]) 90 | else 91 | if (y > grid.height) or (x > grid.width - 66) then 92 | return (nil) 93 | end 94 | return (getCanvas()[y][x+33]) 95 | end 96 | end 97 | 98 | local function _textBarToDirections(bar) 99 | local up, down, right, left = false, false, false, false 100 | if (bar == "║") then up = true; down = true 101 | elseif (bar == "═") then right = true; left = true 102 | elseif (bar == "╚") then up = true; right = true 103 | elseif (bar == "╝") then up = true; left = true 104 | elseif (bar == "╗") then left = true; down = true 105 | elseif (bar == "╔") then right = true; down = true 106 | elseif (bar == "╠") then up = true; down = true; right = true 107 | elseif (bar == "╣") then up = true; down = true; left = true 108 | elseif (bar == "╩") then up = true; right = true; left = true 109 | elseif (bar == "╦") then down = true; right = true; left = true 110 | elseif (bar == "╬") then up = true; down = true; right = true; left = true 111 | end 112 | 113 | return up, down, right, left 114 | end 115 | 116 | function gra.charCombine(stri, strf) 117 | local u1, d1, r1, l1 = _textBarToDirections(stri) 118 | local u2, d2, r2, l2 = _textBarToDirections(strf) 119 | local up, down, right, left = u1 or u2, d1 or d2, r1 or r2, l1 or l2 120 | 121 | -- drastically increased indentation here for easier readbility 122 | if up then 123 | if down then 124 | if right then 125 | if left then 126 | return ("╬") 127 | else 128 | return ("╠") 129 | end 130 | else 131 | if left then 132 | return ("╣") 133 | else 134 | return ("║") 135 | end 136 | end 137 | else 138 | if right then 139 | if left then 140 | return ("╩") 141 | else 142 | return ("╚") 143 | end 144 | else 145 | if left then 146 | return ("╝") 147 | else 148 | return ("#") 149 | end 150 | end 151 | end 152 | else 153 | if down then 154 | if right then 155 | if left then 156 | return ("╦") 157 | else 158 | return ("╔") 159 | end 160 | else 161 | if left then 162 | return ("╗") 163 | else 164 | return ("@") 165 | end 166 | end 167 | else 168 | if right then 169 | if left then 170 | return ("═") 171 | else 172 | return ("%") 173 | end 174 | else 175 | if left then 176 | return ("&") 177 | else 178 | return (" ") 179 | end 180 | end 181 | end 182 | end 183 | 184 | end 185 | 186 | --[[ 187 | function gra.seto(x, y, str) 188 | gra.set(x, y, gra.charCombine(gra.get(x, y), str)) 189 | end 190 | --]] 191 | 192 | function gra.makeBox(x, y, w, h) 193 | gra.set(x, y, "╔") 194 | gra.set(x+w-1, y, "╗") 195 | gra.set(x, y+h-1, "╚") 196 | gra.set(x+w-1, y+h-1, "╝") 197 | 198 | for i=1, w-2 do 199 | gra.set(x+i, y, "═") 200 | gra.set(x+i, y+h-1, "═") 201 | end 202 | 203 | for i=1, h-2 do 204 | gra.set(x, y+i, "║") 205 | gra.set(x+w-1, y+i, "║") 206 | end 207 | 208 | for i=1, w-2 do 209 | for j=1, h-2 do 210 | gra.set(x+i, y+j, " ") 211 | end 212 | end 213 | 214 | end 215 | 216 | function gra.makeBoxAdapt(x, y, w, h) 217 | gra.seto(x, y, "╔") 218 | gra.seto(x+w-1, y, "╗") 219 | gra.seto(x, y+h-1, "╚") 220 | gra.seto(x+w-1, y+h-1, "╝") 221 | 222 | for i=1, w-2 do 223 | gra.seto(x+i, y, "═") 224 | gra.seto(x+i, y+h-1, "═") 225 | end 226 | 227 | for i=1, h-2 do 228 | gra.seto(x, y+i, "║") 229 | gra.seto(x+w-1, y+i, "║") 230 | end 231 | 232 | for i=1, w-2 do 233 | for j=1, h-2 do 234 | gra.seto(x+i, y+j, " ") 235 | end 236 | end 237 | 238 | end 239 | 240 | function gra.text(x, y, str) 241 | for i=1, string.len(str) do 242 | gra.set(x+i-1, y, string.sub(str, utf8.offset(str, i), utf8.offset(str, i+1)-1)) 243 | end 244 | end 245 | 246 | 247 | -- [1, 2] 248 | -- [3, 4] 249 | 250 | -- [[1, 2], [3, 4]] 251 | 252 | function gra.setArea(x, y, w, h, str) 253 | for i=1, h do 254 | for j=1, w do 255 | gra.set(x+j-1, y+i-1, str) 256 | end 257 | end 258 | end 259 | 260 | -- App Functions 261 | 262 | function gra.appCanvasReset(pen) 263 | 264 | apps[pen].canvas = {} 265 | for i=1, grid.height do 266 | apps[pen].canvas[i] = {} 267 | for j=1, grid.width - 66 do 268 | apps[pen].canvas[i][j] = " " 269 | end 270 | end 271 | 272 | --[[ 273 | apps[pen].canvasColor = {} 274 | for i=1, grid.height do 275 | apps[pen].canvasColor[i] = {} 276 | for j=1, grid.width do 277 | apps[pen].canvasColor[i][j] = 15 278 | end 279 | end 280 | --]] 281 | 282 | end 283 | 284 | function gra.appSet(pid, x, y, str) 285 | if (y > #apps[pid].canvas) or (x > #apps[pid].canvas[1]) then 286 | return 287 | end 288 | if (y < 1) or (x < 1) then 289 | return 290 | end 291 | apps[pid].canvas[y][x] = str 292 | --[[ 293 | apps[pen].canvasColor[y][x] = currentSetColor 294 | --]] 295 | end 296 | 297 | function gra.appGet(pid, x, y) 298 | return (apps[pid].canvas[y][x]) 299 | end 300 | 301 | return (gra) -------------------------------------------------------------------------------- /os/lib/lgc.lua: -------------------------------------------------------------------------------- 1 | local lgc = {} 2 | 3 | function lgc.copyTable(object) -- mpappas @ forums.coronalabs.com 4 | local tableLookup = {} 5 | local function _copy(obj) 6 | if type(obj) ~= "table" then 7 | return obj 8 | elseif tableLookup[obj] then 9 | return tableLookup[obj] 10 | end 11 | local new_table = {} 12 | tableLookup[obj] = new_table 13 | for index, value in pairs(obj) do 14 | new_table[_copy(index)] = _copy(value) 15 | end 16 | return setmetatable(new_table, getmetatable(obj)) 17 | end 18 | return _copy(object) 19 | end 20 | 21 | function lgc.usub(str, i, j) 22 | if (j < i) then return ("") end 23 | return (string.sub(str, utf8.offset(str, i), utf8.offset(str, j))) 24 | end 25 | 26 | 27 | 28 | return (lgc) -------------------------------------------------------------------------------- /os/sysapps/taskmgr.lua: -------------------------------------------------------------------------------- 1 | local app = {} 2 | 3 | -- Define global variables for your app here. 4 | 5 | function app.load() 6 | local appInfo = {} 7 | -- Define values on load. 8 | -- For reference, inner window dimentions are 4 shorter and 2 thinner. 9 | -- Example: outer width 40 and height 20 makes inner width 38 and height 16. 10 | -- "title" is the text at the top of the window, "mini" is if the app is minimized. 11 | appInfo.title = "Task Manager" 12 | appInfo.mini = false 13 | return (appInfo) 14 | end 15 | 16 | function app.tick() 17 | 18 | end 19 | 20 | function app.draw()--app.draw(width, height) 21 | 22 | local at = api.s.appsTable() 23 | 24 | api.g.box(1, 1, 56, 3, false) 25 | api.g.box(7, 1, 7, 3, true) 26 | api.g.box(48, 1, 9, 3, true) 27 | 28 | api.g.text(3, 2, "PID") 29 | api.g.text(9, 2, "TAG") 30 | api.g.text(15, 2, "PROCESS NAME") 31 | api.g.text(50, 2, "MINI.") 32 | 33 | api.g.box(1, 3, 56, 22, true) 34 | api.g.box(7, 3, 7, 22, true) 35 | api.g.box(48, 3, 9, 22, true) 36 | 37 | 38 | local i = 1 39 | for pid,v in pairs(at) do 40 | api.g.text(3, 3+i, pid) 41 | api.g.text(9, 3+i, v.tag) 42 | api.g.text(15, 3+i, v.title) 43 | api.g.text(50, 3+i, tostring(v.mini)) 44 | 45 | i = i + 1 46 | end 47 | 48 | end 49 | 50 | -- Add more functions to do whatever you like down here. 51 | 52 | 53 | return (app) -------------------------------------------------------------------------------- /packages/api.lua: -------------------------------------------------------------------------------- 1 | local api = {} 2 | 3 | -- Graphics 4 | api.g = {} 5 | 6 | function api.g.get(x, y) 7 | return (gra.get(x, y)) 8 | end 9 | 10 | function api.g.set(x, y, char) 11 | gra.set(x, y, char) 12 | return (true) 13 | end 14 | 15 | function api.g.text(x, y, str) 16 | for i=1, utf8.len(str) do 17 | gra.set(x+i-1, y, string.sub(str, utf8.offset(str, i), utf8.offset(str, i+1)-1)) 18 | end 19 | return (true) 20 | end 21 | 22 | function api.g.area(x, y, w, h, char) 23 | for i=1, w do 24 | for j=1, h do 25 | gra.set(x+i-1, y+j-1, char) 26 | end 27 | end 28 | return (true) 29 | end 30 | 31 | function api.g.box(x, y, w, h, adapt) 32 | if adapt == nil then adapt = false end 33 | if not adapt then 34 | 35 | gra.set(x, y, "╔") 36 | gra.set(x+w-1, y, "╗") 37 | gra.set(x, y+h-1, "╚") 38 | gra.set(x+w-1, y+h-1, "╝") 39 | 40 | for i=1, w-2 do 41 | gra.set(x+i, y, "═") 42 | gra.set(x+i, y+h-1, "═") 43 | end 44 | 45 | for i=1, h-2 do 46 | gra.set(x, y+i, "║") 47 | gra.set(x+w-1, y+i, "║") 48 | end 49 | 50 | for i=1, w-2 do 51 | for j=1, h-2 do 52 | gra.set(x+i, y+j, " ") 53 | end 54 | end 55 | 56 | else 57 | 58 | gra.set(x, y, gra.charCombine("╔", gra.get(x, y))) 59 | gra.set(x+w-1, y, gra.charCombine("╗", gra.get(x+w-1, y))) 60 | gra.set(x, y+h-1, gra.charCombine("╚", gra.get(x, y+h-1))) 61 | gra.set(x+w-1, y+h-1, gra.charCombine("╝", gra.get(x+w-1, y+h-1))) 62 | 63 | for i=1, w-2 do 64 | gra.set(x+i, y, gra.charCombine("═", gra.get(x+i, y))) 65 | gra.set(x+i, y+h-1, gra.charCombine("═", gra.get(x+i, y+h-1))) 66 | end 67 | 68 | for i=1, h-2 do 69 | gra.set(x, y+i, gra.charCombine("║", gra.get(x, y+i))) 70 | gra.set(x+w-1, y+i, gra.charCombine("║", gra.get(x+w-1, y+i))) 71 | end 72 | 73 | for i=1, w-2 do 74 | for j=1, h-2 do 75 | gra.set(x+i, y+j, gra.charCombine(" ", gra.get(x+i, y+j))) 76 | end 77 | end 78 | 79 | end 80 | 81 | return (true) 82 | end 83 | 84 | function api.g.bar(x, y, length, direction, style, percentage) 85 | chList = {} 86 | for i=0, length do 87 | chPer = percentage * length - i 88 | 89 | if style == "block" then 90 | if chPer >= 1 then 91 | chList[i] = "█" 92 | else 93 | chList[i] = " " 94 | end 95 | end 96 | 97 | if style == "fade" then 98 | if chPer >= 1 then 99 | chList[i] = "█" 100 | elseif chPer >= 0.75 then 101 | chList[i] = "▓" 102 | elseif chPer >= 0.50 then 103 | chList[i] = "▒" 104 | elseif chPer >= 0.25 then 105 | chList[i] = "░" 106 | else 107 | chList[i] = " " 108 | end 109 | end 110 | 111 | return (true) 112 | end 113 | 114 | for i=0, length do 115 | gra.set(x+i, y, chList[i]) 116 | end 117 | 118 | end 119 | 120 | ---[[ 121 | function api.g.color(color) 122 | gra.color(color) 123 | end 124 | --]] 125 | 126 | -- Input 127 | api.i = {} 128 | 129 | function api.i.keyStat(key) 130 | return (love.keyboard.isDown(key)) 131 | end 132 | 133 | -- System 134 | api.s = {} 135 | 136 | function api.s.appsTable() 137 | return (lgc.copyTable(apps)) 138 | end 139 | 140 | return (api) 141 | -------------------------------------------------------------------------------- /programs/notepad.lua: -------------------------------------------------------------------------------- 1 | local app = {} 2 | 3 | -- Define global variables for your app here. 4 | cursor = {} 5 | text = {} 6 | ticks = 0 7 | 8 | function app.load() 9 | local appInfo = {} 10 | -- Define values on load. "width" and "height" are for outer window dimentions. 11 | -- For reference, inner window dimentions are 4 shorter and 2 thinner. 12 | -- Example: outer width 40 and height 20 makes inner width 38 and height 16. 13 | -- "title" is the text at the top of the window, "mini" is if the app is minimized. 14 | appInfo.width = 80 15 | appInfo.height = 40 16 | appInfo.title = "Notepad" 17 | appInfo.mini = false 18 | 19 | cursor = {1, 1} 20 | 21 | text = {""} 22 | 23 | ticks = 0 24 | 25 | return (appInfo) 26 | end 27 | 28 | function app.tick() 29 | 30 | -- Code here will be run every tick (or 1/60 of a second). 31 | ticks = ticks + 1 32 | 33 | end 34 | 35 | function app.draw() 36 | 37 | -- Code here will be run after every tick, and the app's canvas is cleared 38 | -- before this function, so all drawing must be done from here. 39 | 40 | for i=1, #text do 41 | api.g.text(1, i, text[i]) 42 | end 43 | 44 | if (ticks % 60) < 30 then 45 | api.g.set(cursor[1], cursor[2], "█") 46 | end 47 | 48 | end 49 | 50 | -- Add more functions to do whatever you like down here. 51 | 52 | function app.textInput(char) 53 | if (cursor[1] <= #text[cursor[2]]) or true then 54 | text[cursor[2]] = lgc.usub(text[cursor[2]], 1, cursor[1]-1) .. char .. 55 | lgc.usub(text[cursor[2]], cursor[1], #text[cursor[2]]) 56 | end 57 | 58 | cursor[1] = cursor[1] + 1 59 | 60 | end 61 | 62 | function app.keyPress(key)--app.keyPress(key, rep) 63 | ticks = 0 64 | if (key == "backspace") then 65 | if (text[#text] ~= "") then 66 | text[#text] = string.sub(text[#text], 1, #text[#text]-1) 67 | elseif (#text > 1) then 68 | table.remove(text, #text) 69 | end 70 | if cursor[1] > 1 then 71 | cursor[1] = cursor[1] - 1 72 | elseif cursor[2] > 1 then 73 | cursor[2] = cursor[2] - 1 74 | cursor[1] = #text[cursor[2]] + 1 75 | end 76 | elseif (key == "return") then 77 | text[#text+1] = "" 78 | cursor[1] = 1 79 | cursor[2] = cursor[2] + 1 80 | elseif (key == "right") then 81 | cursor[1] = cursor[1] + 1 82 | elseif (key == "left") then 83 | cursor[1] = cursor[1] - 1 84 | if cursor[1] < 1 and cursor[2] > 1 then 85 | cursor[2] = cursor[2] - 1 86 | cursor[1] = #text[cursor[2]] + 1 87 | end 88 | elseif (key == "down") then 89 | cursor[2] = cursor[2] + 1 90 | elseif (key == "up") then 91 | cursor[2] = cursor[2] - 1 92 | end 93 | 94 | if cursor[2] > #text then cursor[2] = #text end 95 | if cursor[2] < 1 then cursor[2] = 1 end 96 | if cursor[1] > #text[cursor[2]] + 1 then cursor[1] = #text[cursor[2]] + 1 end 97 | if cursor[1] < 1 then cursor[1] = 1 end 98 | 99 | end 100 | 101 | return (app) -------------------------------------------------------------------------------- /programs/test.lua: -------------------------------------------------------------------------------- 1 | local app = {} 2 | 3 | function app.load() 4 | 5 | -- Define values on load. 6 | local appInfo = {} 7 | 8 | appInfo.title = "Example Program" --Title of the program. 9 | appInfo.mini = true --If the app 10 | 11 | -- Define global variables here. 12 | countup = 0 13 | 14 | rand = 0 15 | rand2 = 0.5 16 | 17 | return (appInfo) 18 | end 19 | 20 | function app.tick() 21 | 22 | -- Code here will be run every tick (or 1/60 of a second). 23 | countup = countup + 0.001 24 | if countup > 1 then countup = 0 end 25 | 26 | rand = rand + (math.random()-0.5)*0.01 27 | 28 | if rand < -1 then rand = -1 end 29 | if rand > 1 then rand = 1 end 30 | 31 | rand2 = rand2 + rand * 0.001 32 | 33 | if rand2 < 0 then rand2 = 0 end 34 | if rand2 > 1 then rand2 = 1 end 35 | 36 | end 37 | 38 | function app.draw(width, height) 39 | 40 | -- Code here to draw on the canvas. 41 | 42 | api.g.text(5, 4, "Short Block") 43 | api.g.bar(5, 5, 10, "right", "block", countup) 44 | api.g.text(5, 6, "Long Block") 45 | api.g.bar(5, 7, 100, "right", "block", countup) 46 | api.g.text(5, 8, "Short Fade") 47 | api.g.bar(5, 9, 10, "right", "fade", countup) 48 | api.g.text(5, 10, "Long Fade") 49 | api.g.bar(5, 11, 100, "right", "fade", countup) 50 | 51 | api.g.text(5, 13, "static bars") 52 | api.g.bar(5, 14, 2, "right", "fade", 0.5) 53 | api.g.bar(5, 16, 2, "right", "fade", 0.625) 54 | api.g.bar(5, 18, 2, "right", "fade", 0.75) 55 | api.g.bar(5, 20, 2, "right", "fade", 0.875) 56 | api.g.bar(5, 22, 2, "right", "fade", 1.0) 57 | 58 | api.g.bar(10, 50, 100, "right", "fade", rand2) 59 | 60 | end 61 | 62 | -- Add more functions below, but they must be formatted 'app.'. 63 | 64 | 65 | return (app) --------------------------------------------------------------------------------