Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Filename: open.lua
- Author: quenti77
- Description:
- --]]
- -- Require
- local event = require "event"
- local component = require "component"
- local unicode = require "unicode"
- local shell = require "shell"
- local fs = require "filesystem"
- -- Configuration
- local config = {
- defaultColor = {
- back = 0x263238,
- front = 0xC3CEE3
- },
- menuColor = {
- bar = {
- back = 0x304047,
- front = 0xC3CEE3
- },
- quitButton = {
- back = 0xC41F1A,
- front = 0xC3CEE3
- },
- select = {
- back = 0xC7C7C7,
- front = 0x383838
- },
- sub = {
- back = 0xA1A1A1,
- front = 0x252525
- }
- },
- statusColor = {
- bar = {
- back = 0x304047,
- front = 0xC3CEE3,
- normal = 0x3A8C4C,
- updated = 0xF08C65
- }
- },
- editorColor = {
- lineNumber = {
- back = 0x34444c,
- front = 0xC3CEE3
- },
- content = {
- back = 0x263238,
- front = 0xC3CEE3
- }
- },
- modalColor = {
- background = {
- back = 0x485F6A,
- front = 0xC3CEE3
- },
- titleBar = {
- back = 0x34444c,
- front = 0xC3CEE3
- },
- textbox = {
- back = 0xF0F3F5,
- front = 0x383838
- },
- button = {
- success = {
- back = 0x00802B,
- front = 0xC3CEE3
- },
- cancel = {
- back = 0xB30000,
- front = 0xC3CEE3
- }
- }
- },
- screen = {
- width = 154,
- height = 50
- },
- screenRefresh = 0.05
- }
- -- Menu
- local menu = {
- file = {
- x = 1,
- textX = 3,
- width = 8,
- name = "File",
- items = {
- x = 1,
- y = 2,
- width = 11,
- height = 7,
- items = {{
- x = 3,
- y = 2,
- name = "New"
- }, {
- x = 3,
- y = 3,
- name = "Open"
- }, {
- x = 1,
- y = 4,
- name = "-----------"
- }, {
- x = 3,
- y = 5,
- name = "Save"
- }, {
- x = 3,
- y = 6,
- name = "Save As"
- }, {
- x = 1,
- y = 7,
- name = "-----------"
- }, {
- x = 3,
- y = 8,
- name = "Quit"
- }}
- }
- }
- }
- -- Status
- local status = {
- menuOpen = {
- file = false
- },
- filename = nil,
- updated = false,
- blink = false
- }
- -- File in editor
- local files = {
- cursor = {
- line = 1,
- column = 1
- },
- content = nil,
- view = {
- top = 1,
- left = 1
- }
- }
- -- Modal
- local modal = {
- open = false,
- value = "",
- action = nil,
- title = ""
- }
- -- Other variable
- local running = true
- local gpu = component.gpu
- local blinkConter = 0
- -- Basic function
- function checkPos(x, y, xmin, ymin, xmax, ymax)
- return ((x >= xmin and x <= xmax) and (y >= ymin and y <= ymax))
- end
- -- Display function
- function clearScreen()
- gpu.setBackground(config.defaultColor.back)
- gpu.setForeground(config.defaultColor.front)
- gpu.fill(1, 1, config.screen.width, config.screen.height, " ")
- end
- function menuFile()
- if (status.menuOpen.file) then
- gpu.setBackground(config.menuColor.select.back)
- gpu.setForeground(config.menuColor.select.front)
- gpu.fill(menu.file.x, 1, menu.file.width, 1, " ")
- gpu.set(menu.file.textX, 1, menu.file.name)
- gpu.setBackground(config.menuColor.sub.back)
- gpu.setForeground(config.menuColor.sub.front)
- gpu.fill(menu.file.items.x, menu.file.items.y, menu.file.items.width, menu.file.items.height, " ")
- for i = 1, #menu.file.items.items do
- local item = menu.file.items.items[i]
- gpu.set(item.x, item.y, item.name)
- end
- else
- gpu.setBackground(config.menuColor.bar.back)
- gpu.setForeground(config.menuColor.bar.front)
- gpu.fill(menu.file.x, 1, menu.file.width, 1, " ")
- gpu.set(menu.file.textX, 1, menu.file.name)
- end
- end
- function menuScreen()
- -- Bar
- gpu.setBackground(config.menuColor.bar.back)
- gpu.setForeground(config.menuColor.bar.front)
- gpu.fill(1, 1, config.screen.width, 1, " ")
- -- X button for close app
- gpu.setBackground(config.menuColor.quitButton.back)
- gpu.setForeground(config.menuColor.quitButton.front)
- gpu.fill(config.screen.width - 2, 1, 3, 1, " ")
- gpu.set(config.screen.width - 1, 1, "×")
- end
- function statusScreen()
- -- Bar
- gpu.setBackground(config.statusColor.bar.back)
- gpu.setForeground(config.statusColor.bar.front)
- gpu.fill(1, config.screen.height, config.screen.width, 1, " ")
- local textRight = string.format("L: %u ¦ C: %u", files.cursor.line, files.cursor.column)
- local length = unicode.len(textRight)
- gpu.set(config.screen.width - 1 - length, config.screen.height, textRight)
- local textLeft = "Aucun fichier"
- if (status.filename ~= nil) then
- if (unicode.len(status.filename) > 50) then
- textLeft = unicode.sub(status.filename, -50)
- else
- textLeft = status.filename
- end
- gpu.setForeground(config.statusColor.bar.normal)
- if (status.updated) then
- gpu.setForeground(config.statusColor.bar.updated)
- end
- end
- gpu.set(3, config.screen.height, textLeft)
- end
- function editorScreen()
- local content = files.content
- local contentSize = #content
- local top = files.view.top
- local bottom = top + config.screen.height - 3
- if (bottom > contentSize) then
- bottom = contentSize
- end
- local lengthBottom = unicode.len(string.format("%u", bottom))
- local gutterWidth = lengthBottom + 2
- local width = config.screen.width - gutterWidth - 2
- gpu.setBackground(config.editorColor.lineNumber.back)
- gpu.setForeground(config.editorColor.lineNumber.front)
- gpu.fill(1, 2, gutterWidth, config.screen.height - 2, " ")
- for line = top, bottom do
- gpu.set(2 + lengthBottom - (unicode.len(string.format("%u", line))), line - top + 2, string.format("%u", line))
- end
- gpu.setBackground(config.editorColor.content.back)
- gpu.setForeground(config.editorColor.content.front)
- for line = top, bottom do
- gpu.set(gutterWidth + 2, line - top + 2, unicode.sub(content[line], files.view.left, files.view.left + width))
- end
- -- ColorCursor
- if (status.blink) then
- local t = files.cursor.line - top + 2
- local l = gutterWidth + 1 + files.cursor.column
- gpu.setBackground(config.editorColor.content.front)
- gpu.setForeground(config.editorColor.content.back)
- gpu.set(l, t, unicode.sub(files.content[files.cursor.line], files.cursor.column, files.cursor.column))
- end
- end
- function modalScreen()
- local x = 15
- local y = config.screen.height / 2 - 2
- local w = config.screen.width - 30
- local h = 6
- local middleW = config.screen.width / 2
- -- Modal
- gpu.setBackground(config.modalColor.background.back)
- gpu.setForeground(config.modalColor.background.front)
- gpu.fill(x, y, w, h, " ")
- -- Titlebar
- gpu.setBackground(config.modalColor.titleBar.back)
- gpu.setForeground(config.modalColor.titleBar.front)
- gpu.fill(x, y, w, 1, " ")
- gpu.set(x + 2, y, modal.title)
- gpu.setBackground(config.menuColor.quitButton.back)
- gpu.setForeground(config.menuColor.quitButton.front)
- gpu.fill(x + w - 3, y, 3, 1, " ")
- gpu.set(x + w - 2, y, "×")
- -- Textbox
- local contentTextbox = modal.value
- if (status.blink) then
- contentTextbox = contentTextbox.."|"
- end
- gpu.setBackground(config.modalColor.textbox.back)
- gpu.setForeground(config.modalColor.textbox.front)
- gpu.fill(x + 2, y + 2, w - 4, 1, " ")
- gpu.set(x + 2, y + 2, contentTextbox)
- -- Buttons
- gpu.setBackground(config.modalColor.button.success.back)
- gpu.setForeground(config.modalColor.button.success.front)
- gpu.fill(middleW - 10, y + 4, 10, 1, " ")
- gpu.set(middleW - 8, y + 4, " Ok ")
- gpu.setBackground(config.modalColor.button.cancel.back)
- gpu.setForeground(config.modalColor.button.cancel.front)
- gpu.fill(middleW + 2, y + 4, 10, 1, " ")
- gpu.set(middleW + 4, y + 4, "Cancel")
- end
- function updateScreen()
- clearScreen()
- menuScreen()
- statusScreen()
- if (files.content ~= nil) then
- editorScreen()
- end
- blinkConter = blinkConter + 1
- if (blinkConter >= 10) then
- blinkConter = 0
- status.blink = not status.blink
- end
- menuFile()
- if (modal.open) then
- modalScreen()
- end
- end
- function clearContent()
- if (files.content ~= nil) then
- for k, v in pairs(files.content) do
- files.content[k] = nil
- end
- files.content = nil
- end
- end
- function saveFile(filename)
- local f = io.open(filename, "w")
- if (f ~= nil) then
- for k, v in pairs(files.content) do
- local l = files.content[k]
- f:write(unicode.sub(l, 1, unicode.len(l) - 1).."\n")
- end
- f:close()
- end
- end
- function openFile(filename)
- if (unicode.sub(filename, 1, 1) ~= "/") then
- filename = "/"..filename
- end
- if (fs.exists(filename) and not fs.isDirectory(filename)) then
- local f = io.open(filename, "r")
- if (f ~= nil) then
- local l = 1
- clearContent()
- files.content = {}
- for line in f:lines() do
- files.content[l] = line.." "
- l = l + 1
- end
- f:close()
- if (#files.content == 0) then
- files.content = {" "}
- end
- files.cursor.line = 1
- files.cursor.column = 1
- files.view.top = 1
- files.view.left = 1
- status.filename = filename
- end
- end
- end
- function menuFileClick(item)
- local filename = ""
- if (status.filename ~= nil) then
- filename = status.filename
- end
- if (item.name == "New") then
- modal.open = true
- modal.title = "Nouveau fichier ..."
- modal.action = "new"
- modal.value = shell.getWorkingDirectory()
- status.menuOpen.file = false
- elseif (item.name == "Open") then
- modal.open = true
- modal.title = "Ouvrir un fichier ..."
- modal.action = "open"
- modal.value = shell.getWorkingDirectory()
- status.menuOpen.file = false
- elseif (item.name == "Save") then
- if (filename == "") then
- item.name = "Save As"
- menuFileClick(item)
- else
- saveFile(filename)
- status.updated = false
- end
- status.menuOpen.file = false
- elseif (item.name == "Save As") then
- modal.open = true
- modal.title = "Enregistrer sous ..."
- modal.action = "saveAs"
- if (filename == "") then
- modal.value = shell.getWorkingDirectory()
- else
- modal.value = filename
- end
- status.menuOpen.file = false
- elseif (item.name == "Quit") then
- running = false
- end
- end
- -- Handler event
- function unknownEvent()
- --print("Unknown event called")
- end
- local handler = setmetatable({}, { __index = function() return unknownEvent end })
- function modalTouch()
- local filename = modal.value
- if (modal.action == "new") then
- clearContent()
- files.content = {" "}
- elseif (modal.action == "open") then
- openFile(filename)
- elseif (modal.action == "saveAs") then
- saveFile(filename)
- end
- status.filename = filename
- status.updated = false
- end
- function handler.touch(address, x, y, button, playerName)
- if (checkPos(x, y, config.screen.width - 2, 1, config.screen.width, 1)) then
- running = false
- return true
- end
- if (not modal.open) then
- if (not status.menuOpen.file and checkPos(x, y, menu.file.x, 1, menu.file.width, 1)) then
- status.menuOpen.file = true
- return true
- end
- if (status.menuOpen.file) then
- local itemClicked
- for i = 1, #menu.file.items.items do
- local item = menu.file.items.items[i]
- if (checkPos(x, y, menu.file.items.x, item.y, menu.file.items.width, item.y)) then
- itemClicked = item
- end
- end
- if (itemClicked ~= nil) then
- menuFileClick(itemClicked)
- else
- status.menuOpen.file = false
- end
- return true
- end
- local content = files.content
- if (content == nil) then
- return true
- end
- local contentSize = #content
- local top = files.view.top
- local bottom = top + config.screen.height - 3
- if (bottom > contentSize) then
- bottom = contentSize
- end
- local lengthBottom = unicode.len(string.format("%u", bottom))
- local gutterWidth = lengthBottom + 2
- local width = config.screen.width - gutterWidth - 2
- if (checkPos(x, y, gutterWidth + 2, 2, config.screen.width, config.screen.height - 2)) then
- local line = top + (y - 2)
- local column = x - gutterWidth - files.view.left
- if (line < 1) then
- line = 1
- end
- if (line > #files.content) then
- line = #files.content
- end
- local columnMax = unicode.len(files.content[line])
- if (column < 1) then
- column = 1
- end
- if (column > columnMax) then
- column = columnMax
- end
- files.cursor.line = line
- files.cursor.column = column
- blinkConter = 0
- status.blink = true
- end
- else
- local xStart = 15
- local yStart = config.screen.height / 2 - 2
- local w = config.screen.width - 30
- local h = 5
- local middleW = config.screen.width / 2
- -- Cancel button
- if (checkPos(x, y, middleW + 2, yStart + 4, middleW + 11, yStart + 5)) then
- modal.open = false
- end
- -- Ok button
- if (checkPos(x, y, middleW - 10, yStart + 4, middleW - 1, yStart + 5)) then
- modalTouch()
- modal.open = false
- end
- end
- return false
- end
- function handler.scroll(address, x, y, direction, playerName)
- if (not modal.open) then
- local newTop = files.view.top + (direction * -1)
- local maxTop = #files.content - 5
- if (newTop < 1) then
- newTop = 1
- elseif (newTop > maxTop) then
- newTop = maxTop
- end
- files.view.top = newTop
- end
- end
- function keyEditor(char, code)
- local line = files.cursor.line
- local column = files.cursor.column
- local direction = 0
- local updated = false
- if (files.content == nil) then
- return true
- end
- if (code == 0xC8) then
- -- up
- line = line - 1
- elseif (code == 0xCB) then
- -- left
- column = column - 1
- elseif (code == 0xD0) then
- -- down
- line = line + 1
- elseif (code == 0xCD) then
- -- right
- column = column + 1
- elseif (code == 0x2A or code == 0x36) then
- -- shift
- elseif (code == 0x1D or code == 0x9D) then
- -- ctrl
- elseif (code == 0x38 or code == 0xB8) then
- -- alt
- elseif (code == 0xC7) then
- -- home
- column = 1
- elseif (code == 0x0F) then
- -- tab
- for i = 1, 2 do
- keyEditor(string.byte(" "), 0x39)
- end
- column = column + 2
- updated = true
- elseif (code == 0xCF) then
- -- end
- column = unicode.len(files.content[line])
- elseif (code == 0x1C) then
- -- enter
- local contentLine = files.content[line]
- local saveLine = ""
- if (column > 1) then
- saveLine = unicode.sub(contentLine, 1, column - 1)
- end
- local newLine = unicode.sub(contentLine, column, unicode.len(contentLine))
- local spaces = ""
- local posChar = 1
- local charTest = unicode.sub(saveLine, posChar, posChar)
- while (charTest == " ") do
- spaces = spaces.." "
- posChar = posChar + 1
- charTest = unicode.sub(saveLine, posChar, posChar)
- end
- local countSpace = unicode.len(spaces)
- column = countSpace + 1
- files.content[line] = saveLine.." "
- line = line + 1
- table.insert(files.content, line, spaces..newLine)
- updated = true
- elseif (code == 0x0E) then
- -- backspace
- local lineContent = files.content[line]
- if (column == 1) then
- if (line == 1) then
- return true
- end
- table.remove(files.content, line)
- line = line - 1
- column = unicode.len(files.content[line])
- lineContent = unicode.sub(files.content[line], 1, unicode.len(files.content[line]) - 1)..lineContent
- else
- lineContent = unicode.sub(lineContent, 1, files.cursor.column - 2)..unicode.sub(lineContent, files.cursor.column, unicode.len(lineContent))
- column = column - 1
- end
- files.content[line] = lineContent
- updated = true
- elseif (code == 0xD3) then
- -- del
- local lineContent = files.content[line]
- local sizeLineContent = unicode.len(lineContent)
- if (column == sizeLineContent) then
- local lineDownContent = files.content[line + 1]
- if (lineDownContent ~= nil) then
- lineContent = unicode.sub(lineContent, 1, sizeLineContent - 1)
- files.content[line] = lineContent..lineDownContent
- table.remove(files.content, line + 1)
- end
- else
- local before = ""
- if (column > 1) then
- before = unicode.sub(lineContent, 1, column - 1)
- end
- local after = unicode.sub(lineContent, column + 1, sizeLineContent)
- files.content[line] = before..""..after
- end
- update = true
- else
- local lineContent = files.content[files.cursor.line]
- lineContent = unicode.sub(lineContent, 1, files.cursor.column - 1)..unicode.char(char)..unicode.sub(lineContent, files.cursor.column, unicode.len(lineContent))
- files.content[files.cursor.line] = lineContent
- column = column + 1
- updated = true
- end
- if (line < 1) then
- line = 1
- end
- if (line > #files.content) then
- line = #files.content
- end
- local columnMax = unicode.len(files.content[line])
- if (column < 1) then
- column = 1
- end
- if (column > columnMax) then
- column = columnMax
- end
- if (files.view.top > line) then
- direction = files.view.top - line
- end
- if ((files.view.top + config.screen.height - 3) < line) then
- direction = (files.view.top + config.screen.height - 3) - line
- end
- if (direction ~= 0) then
- handler.scroll(address, 0, 0, direction, playerName)
- end
- files.cursor.line = line
- files.cursor.column = column
- if (updated) then
- status.updated = true
- end
- end
- function keyModal(char, code)
- if (code == 0xC8) then
- -- up
- elseif (code == 0xCB) then
- -- left
- elseif (code == 0xD0) then
- -- down
- elseif (code == 0xCD) then
- -- right
- elseif (code == 0x2A or code == 0x36) then
- -- shift
- elseif (code == 0x1D or code == 0x9D) then
- -- ctrl
- elseif (code == 0x38 or code == 0xB8) then
- -- alt
- elseif (code == 0xC7) then
- -- home
- elseif (code == 0xCF) then
- -- end
- elseif (code == 0x1C) then
- -- enter
- modalTouch()
- modal.open = false
- elseif (code == 0x0E) then
- -- backspace
- modal.value = unicode.sub(modal.value, 1, unicode.len(modal.value) - 1)
- elseif (code == 0xD3) then
- -- del
- else
- modal.value = modal.value..unicode.char(char)
- end
- end
- function handler.key_down(address, char, code, playerName)
- if (modal.open) then
- keyModal(char, code)
- else
- keyEditor(char, code)
- end
- end
- function handleEvent(eventId, ...)
- if (eventId) then
- handler[eventId](...)
- --updateScreen()
- end
- end
- -- Start app
- local args = { ... }
- if (#args == 1) then
- openFile(shell.getWorkingDirectory()..args[1])
- end
- gpu.setResolution(config.screen.width, config.screen.height)
- local timerId = event.timer(config.screenRefresh, updateScreen, math.huge)
- while running do
- handleEvent(event.pull())
- end
- -- Stop app
- event.cancel(timerId)
- clearScreen()
- shell.execute("clear")
Advertisement
Add Comment
Please, Sign In to add comment