1
0
Fork 0
mirror of https://github.com/ctruLua/ctruLua.git synced 2025-10-27 16:39:29 +00:00

Added text editor, keyboard lib and stuff in Lua

This commit is contained in:
Reuh 2015-08-26 12:16:16 +02:00
parent 800dd6f963
commit 6a26be4b43
5 changed files with 408 additions and 64 deletions

View file

@ -0,0 +1,6 @@
-- Colors based on the Monokai theme
return {
background = 0x272822FF,
default = 0xF8F8F2FF,
cursor = 0xFF0000FF
}

View file

@ -0,0 +1,153 @@
local ctr = require("ctr")
local hid = require("ctr.hid")
local gfx = require("ctr.gfx")
-- Open libs
local keyboard = dofile("sdmc:/3ds/ctruLua/keyboard.lua")
local openfile = dofile("sdmc:/3ds/ctruLua/openfile.lua")
local color = dofile("sdmc:/3ds/ctruLua/editor/color.lua")
-- Open file
local path, status = openfile("Choose a file to edit", "/3ds/ctruLua/", nil, "any")
if not path then return end
local lines = {}
if status == "exist" then
for line in io.lines(path) do table.insert(lines, line) end
else
lines = { "" }
end
-- Variables
local lineHeight = 10
local cursorX, cursorY = 1, 1
local scrollX, scrollY = 0, 0
-- Set defaults
gfx.set3D(false)
gfx.color.setDefault(color.default)
gfx.color.setBackground(color.background)
while ctr.run() do
hid.read()
local keys = hid.keys()
-- Keys input
if keys.down.start then return end
if keys.down.dRight then
cursorX = cursorX + 1
if cursorX > utf8.len(lines[cursorY])+1 then
if cursorY < #lines then
cursorX, cursorY = 1, cursorY + 1
else
cursorX = cursorX - 1
end
end
end
if keys.down.dLeft then
if cursorX > utf8.len(lines[cursorY])+1 then cursorX = utf8.len(lines[cursorY])+1 end
cursorX = cursorX - 1
if cursorX < 1 then
if cursorY > 1 then
cursorX, cursorY = utf8.len(lines[cursorY-1])+1, cursorY - 1
else
cursorX = 1
end
end
end
if keys.down.dUp and cursorY > 1 then cursorY = cursorY - 1 end
if keys.down.dDown and cursorY < #lines then cursorY = cursorY + 1 end
if keys.held.cpadRight or keys.held.a then scrollX = scrollX + 3 end
if keys.held.cpadLeft or keys.held.y then scrollX = scrollX - 3 end
if keys.held.cpadUp or keys.held.x then scrollY = scrollY - 3 end
if keys.held.cpadDown or keys.held.b then scrollY = scrollY + 3 end
if keys.down.select then
local file = io.open(path, "w")
if not file then
local t = os.time()
repeat
gfx.startFrame(gfx.GFX_TOP)
gfx.text(3, 3, "Can't open file in write mode")
gfx.endFrame()
gfx.render()
until t + 5 < os.time()
else
for i = 1, #lines, 1 do
file:write(lines[i].."\n")
gfx.startFrame(gfx.GFX_TOP)
gfx.rectangle(0, 0, math.ceil(i/#lines*gfx.TOP_WIDTH), gfx.TOP_HEIGHT, 0, 0xFFFFFFFF)
gfx.color.setDefault(0x000000FF)
gfx.text(gfx.TOP_WIDTH/2, gfx.TOP_HEIGHT/2, math.ceil(i/#lines*100).."%")
gfx.color.setDefault(color.default)
gfx.endFrame()
gfx.render()
end
file:flush()
file:close()
end
end
-- Keyboard input
local input = keyboard.read()
if input then
if input == "BACK" then
if cursorX > utf8.len(lines[cursorY])+1 then cursorX = utf8.len(lines[cursorY])+1 end
if cursorX > 1 then
lines[cursorY] = lines[cursorY]:sub(1, utf8.offset(lines[cursorY], cursorX-1)-1)..
lines[cursorY]:sub(utf8.offset(lines[cursorY], cursorX), -1)
cursorX = cursorX - 1
elseif cursorY > 1 then
cursorX, cursorY = utf8.len(lines[cursorY-1])+1, cursorY - 1
lines[cursorY] = lines[cursorY]..lines[cursorY+1]
table.remove(lines, cursorY+1)
end
elseif input == "\n" then
local newline = lines[cursorY]:sub(utf8.offset(lines[cursorY], cursorX), -1)
local whitespace = lines[cursorY]:match("^%s+")
if whitespace then newline = whitespace .. newline end
lines[cursorY] = lines[cursorY]:sub(1, utf8.offset(lines[cursorY], cursorX)-1)
table.insert(lines, cursorY + 1, newline)
cursorX, cursorY = whitespace and #whitespace+1 or 1, cursorY + 1
else
lines[cursorY] = lines[cursorY]:sub(1, utf8.offset(lines[cursorY], cursorX)-1)..input..
lines[cursorY]:sub(utf8.offset(lines[cursorY], cursorX), -1)
cursorX = cursorX + 1
end
end
-- Draw
gfx.startFrame(gfx.GFX_TOP)
local sI = math.floor(scrollY / lineHeight)
if sI < 1 then sI = 1 end
local eI = math.ceil((scrollY + gfx.TOP_HEIGHT) / lineHeight)
if eI > #lines then eI = #lines end
for i = sI, eI, 1 do
local line = lines[i]
local y = -scrollY+ (i-1)*lineHeight
if cursorY == i then
gfx.color.setDefault(color.cursor)
gfx.text(-scrollX, y, line:sub(1, (utf8.offset(line, cursorX) or 0)-1):gsub("\t", " ").."|", nil) -- TODO: color doesn't work
gfx.color.setDefault(color.default)
end
gfx.text(-scrollX, y, line:gsub("\t", " "), nil)
end
gfx.endFrame()
gfx.startFrame(gfx.GFX_BOTTOM)
keyboard.draw(5, 115)
gfx.endFrame()
gfx.render()
end

View file

@ -0,0 +1,106 @@
local hid = require("ctr.hid")
local gfx = require("ctr.gfx")
-- Options
local keyWidth, keyHeight = 25, 25
local layout = {
["default"] = {
{ "&", "é", "\"", "'", "(", "-", "è", "_", "ç", "à", ")", "=", "Back" },
{ "a", "z", "e", "r", "t", "y", "u", "i", "o", "p", "^", "$", "Enter" },
{ "q", "s", "d", "f", "g", "h", "j", "k", "l", "m", "ù", "*", "Enter" },
{ "Shift", "<", "w", "x", "c", "v", "b", "n", ",", ";", ":", "!", "Tab" },
{ "CpLck", ">", "+", "/", " ", " ", " ", " ", " ", "{", "}", ".", "AltGr" }
},
["Shift"] = {
{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "°", "+", "Back" },
{ "A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P", "¨", "£", "Enter" },
{ "Q", "S", "D", "F", "G", "H", "J", "K", "L", "M", "%", "µ", "Enter" },
{ "Shift", ">", "W", "X", "C", "V", "B", "N", "?", ".", "/", "§", "Tab" },
{ "CpLck", "~", "#", "[", " ", " ", " ", " ", " ", "]", "|", "@", "AltGr" }
},
["AltGr"] = {
{ "²", "~", "#", "{", "[", "|", "`", "\\", "^", "@", "]", "}", "Back" },
{ "a", "z", "", "r", "t", "y", "u", "i", "o", "p", "", "¤", "Enter" },
{ "q", "s", "d", "f", "g", "h", "j", "k", "l", "m", "", "", "Enter" },
{ "Shift", "", "w", "x", "c", "v", "b", "n", "", "", "", "", "Tab" },
{ "CpLck", "", "", "", " ", " ", " ", " ", " ", "", "", "", "AltGr" }
},
}
local alias = {
["Tab"] = "\t",
["Enter"] = "\n",
["Back"] = "BACK"
}
local sticky = {
["CpLck"] = "Shift"
}
local keys = {
["l"] = "Shift",
["r"] = "Shift"
}
-- Variables
local currentModifier = { "default", "sticky" }
local buffer = ""
return {
draw = function(x, y)
local hidKeys = hid.keys()
local xTouch, yTouch
if hidKeys.down.touch then xTouch, yTouch = hid.touch() end
for key, modifier in pairs(keys) do
if hidKeys.down[key] then
currentModifier = { modifier, "key" }
elseif hidKeys.up[key] and currentModifier[2] == "key" and currentModifier[1] == modifier then
currentModifier = { "default", "sticky" }
end
end
for row, rowKeys in pairs(layout[currentModifier[1]]) do
for column, key in pairs(rowKeys) do
local xKey, yKey = x + (column-1)*(keyWidth-1), y + (row-1)*(keyHeight-1)
gfx.rectangle(xKey, yKey, keyWidth, keyHeight, 0, 0xFFFFFFFF)
gfx.rectangle(xKey + 1, yKey + 1, keyWidth - 2, keyHeight - 2, 0, 0x000000FF)
gfx.text(xKey + 2, yKey + 2, key)
if xTouch then
if xTouch > xKey and xTouch < xKey + keyWidth then
if yTouch > yKey and yTouch < yKey + keyHeight then
gfx.rectangle(xKey, yKey, keyWidth, keyHeight, 0, 0xFFFFFFDD)
local k = alias[key] or key
if sticky[k] and layout[sticky[k]] then
if currentModifier[1] == sticky[k] and currentModifier[2] == "sticky" then
currentModifier = { "default", "sticky" }
else
currentModifier = { sticky[k], "sticky" }
end
elseif layout[k] then
if currentModifier[1] == k and currentModifier[2] == "normal" then
currentModifier = { "default", "sticky" }
else
currentModifier = { k, "normal" }
end
else
buffer = buffer .. k
if currentModifier[1] ~= "default" and currentModifier[2] == "normal" then
currentModifier = { "default", "sticky" }
end
end
end
end
end
end
end
end,
read = function()
local ret = buffer
buffer = ""
return ret ~= "" and ret or nil
end
}

View file

@ -1,64 +1,4 @@
local ctr = require("ctr")
local gfx = require("ctr.gfx")
local sel = 1
local scroll = 0
local curdir = "/"
local files = ctr.fs.list(curdir)
while ctr.run() do
ctr.hid.read()
local keys = ctr.hid.keys()
if keys.down.start then break end
if keys.down.down and sel < #files then
sel = sel + 1
if sel > scroll + 14 then scroll = scroll + 1 end
elseif keys.down.up and sel > 1 then
sel = sel - 1
if sel <= scroll then scroll = scroll - 1 end
end
if keys.down.a then
local f = files[sel]
if f.isDirectory then
if f.name == ".." then curdir = curdir:gsub("[^/]+/$", "")
else curdir = curdir..f.name.."/" end
sel = 1
scroll = 0
files = ctr.fs.list(curdir)
if curdir ~= "/" then
table.insert(files, 1, { name = "..", isDirectory = true, fileSize = "parent directory" })
end
else
if f.name:match("%..+$") == ".lua" then
dofile(curdir..f.name)
-- reset things the script could have changed
gfx.set3D(false)
gfx.color.setDefault(0xFFFFFFFF)
gfx.color.setBackground(0x000000FF)
end
end
end
gfx.startFrame(gfx.GFX_TOP)
gfx.rectangle(0, 10+(sel-scroll)*15, gfx.TOP_WIDTH, 15, 0, gfx.color.RGBA8(0, 0, 200))
for i = scroll+1, scroll+14, 1 do
local f = files[i]
if not f then break end
local name = f.isDirectory and "["..f.name.."]" or f.name.." ("..f.fileSize.."b)"
if not f.isHidden then gfx.text(5, 12+(i-scroll)*15, name) end
end
gfx.rectangle(0, 0, gfx.TOP_WIDTH, 25, 0, gfx.color.RGBA8(200, 200, 200))
gfx.text(3, 3, curdir, 13, gfx.color.RGBA8(0, 0, 0))
gfx.endFrame()
gfx.render()
end
repeat
local file = dofile("sdmc:/3ds/ctruLua/openfile.lua")("Choose a Lua file to execute", "/3ds/ctruLua/", ".lua", "exist")
if file then dofile(file) end
until not file

View file

@ -0,0 +1,139 @@
--- Open a file explorer to select a file.
-- string title: title of the file explorer.
-- string curdir: the directory to initially open the file explorer in.
-- string exts: the file extensions the user can select, separated by ";". If nil, all extensions are accepted.
-- string type: "exist" to select an existing file, "new" to select an non-existing file or "any" to select a existing
-- or non-existing file name. If nil, defaults to "exist".
-- returns string: the file the user has selected, or nil if the explorer was closed without selecting a file.
-- string: "exist" if the file exist or "new" if it doesn't
return function(title, curdir, exts, type)
-- Open libs
local ctr = require("ctr")
local gfx = require("ctr.gfx")
local keyboard = dofile("sdmc:/3ds/ctruLua/keyboard.lua")
-- Arguments
local type = type or "exist"
-- Variables
local sel = 1
local scroll = 0
local files = ctr.fs.list(curdir)
if curdir ~= "/" then table.insert(files, 1, { name = "..", isDirectory = true }) end
local newFileName = ""
local ret = nil
-- Remember and set defaults
--local was3D = gfx.get3D() TODO: implement this thing in ctruLua
local wasDefault = gfx.color.getDefault()
local wasBackground = gfx.color.getBackground()
gfx.set3D(false)
gfx.color.setDefault(0xFFFFFFFF)
gfx.color.setBackground(0x000000FF)
while ctr.run() do
ctr.hid.read()
local keys = ctr.hid.keys()
if keys.down.start then break end
-- Keys input
if keys.down.down and sel < #files then
sel = sel + 1
if sel > scroll + 14 then scroll = scroll + 1 end
elseif keys.down.up and sel > 1 then
sel = sel - 1
if sel <= scroll then scroll = scroll - 1 end
end
if keys.down.a then
local f = files[sel]
if f.isDirectory then
if f.name == ".." then curdir = curdir:gsub("[^/]+/$", "")
else curdir = curdir..f.name.."/" end
sel = 1
scroll = 0
files = ctr.fs.list(curdir)
if curdir ~= "/" then
table.insert(files, 1, { name = "..", isDirectory = true })
end
elseif type == "exist" or type == "any" then
if exts then
for ext in (exts..";"):gmatch("[^;]+") do
if f.name:match("%..+$") == ext then
ret = { curdir..f.name, "exist" }
break
end
end
else
ret = { curdir..f.name, "exist" }
end
if ret then break end
end
end
-- Keyboard input
if type == "new" or type == "any" then
local input = keyboard.read()
if input then
if input == "BACK" then
newFileName = newFileName:sub(1, (utf8.offset(newFileName, -1) or 0)-1)
elseif input == "\n" then
local fileStatus = "new"
local f = io.open(curdir..newFileName)
if f then fileStatus = "exist" f:close() end
ret = { curdir..newFileName, fileStatus }
break
else
newFileName = newFileName..input
end
end
end
-- Draw
gfx.startFrame(gfx.GFX_TOP)
gfx.rectangle(0, 10+(sel-scroll)*15, gfx.TOP_WIDTH, 15, 0, gfx.color.RGBA8(0, 0, 200))
for i = scroll+1, scroll+14, 1 do
local f = files[i]
if not f then break end
local name = f.isDirectory and "["..f.name.."]" or f.name.." ("..f.fileSize.."b)"
if not f.isHidden then gfx.text(5, 12+(i-scroll)*15, name) end
end
gfx.rectangle(0, 0, gfx.TOP_WIDTH, 25, 0, gfx.color.RGBA8(200, 200, 200))
gfx.text(3, 3, curdir, 13, gfx.color.RGBA8(0, 0, 0))
gfx.endFrame()
gfx.startFrame(gfx.GFX_BOTTOM)
gfx.text(5, 5, title)
gfx.text(5, 20, "Accepted file extensions: "..(exts or "all"))
if type == "new" or type == "any" then
gfx.text(5, 90, newFileName)
keyboard.draw(5, 115)
end
gfx.endFrame()
gfx.render()
end
-- Reset defaults
--gfx.set3D(was3D)
gfx.color.setDefault(wasDefault)
gfx.color.setBackground(wasBackground)
if ret then
return table.unpack(ret)
else
return ret
end
end