mirror of
https://github.com/kepler155c/opus
synced 2024-06-14 09:26:54 +00:00
Overlapping windows
This commit is contained in:
parent
977998ebdb
commit
d61260ec9b
|
@ -35,26 +35,32 @@ local Browser = UI.Page {
|
||||||
},
|
},
|
||||||
fileMenu = UI.DropMenu {
|
fileMenu = UI.DropMenu {
|
||||||
buttons = {
|
buttons = {
|
||||||
{ text = 'Run', event = 'run' },
|
{ text = 'Run', event = 'run' },
|
||||||
{ text = 'Edit e', event = 'edit' },
|
{ text = 'Edit e', event = 'edit' },
|
||||||
{ text = 'Shell s', event = 'shell' },
|
{ text = 'Shell s', event = 'shell' },
|
||||||
{ text = 'Quit q', event = 'quit' },
|
UI.Text { value = ' ------------ ' },
|
||||||
|
{ text = 'Quit q', event = 'quit' },
|
||||||
|
UI.Text { },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
editMenu = UI.DropMenu {
|
editMenu = UI.DropMenu {
|
||||||
buttons = {
|
buttons = {
|
||||||
{ text = 'Mark m', event = 'mark' },
|
{ text = 'Cut ^x', event = 'cut' },
|
||||||
{ text = 'Cut ^x', event = 'cut' },
|
{ text = 'Copy ^c', event = 'copy' },
|
||||||
{ text = 'Copy ^c', event = 'copy' },
|
{ text = 'Paste ^v', event = 'paste' },
|
||||||
{ text = 'Paste ^v', event = 'paste' },
|
UI.Text { value = ' --------------- ' },
|
||||||
{ text = 'Delete del', event = 'delete' },
|
{ text = 'Mark m', event = 'mark' },
|
||||||
{ text = 'Unmark all u', event = 'unmark' },
|
{ text = 'Unmark all u', event = 'unmark' },
|
||||||
|
UI.Text { value = ' --------------- ' },
|
||||||
|
{ text = 'Delete del', event = 'delete' },
|
||||||
|
UI.Text { },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
viewMenu = UI.DropMenu {
|
viewMenu = UI.DropMenu {
|
||||||
buttons = {
|
buttons = {
|
||||||
{ text = 'Refresh r', event = 'refresh' },
|
{ text = 'Refresh r', event = 'refresh' },
|
||||||
{ text = 'Hidden ^h', event = 'toggle_hidden' },
|
{ text = 'Hidden ^h', event = 'toggle_hidden' },
|
||||||
|
UI.Text { },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
|
@ -69,8 +75,8 @@ local Browser = UI.Page {
|
||||||
},
|
},
|
||||||
statusBar = UI.StatusBar {
|
statusBar = UI.StatusBar {
|
||||||
columns = {
|
columns = {
|
||||||
{ '', 'status', UI.term.width - 19 },
|
{ '', 'status', UI.term.width - 8 },
|
||||||
{ '', 'info', 10 },
|
--{ '', 'info', 10 },
|
||||||
{ 'Size: ', 'totalSize', 8 },
|
{ 'Size: ', 'totalSize', 8 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
19
apps/Lua.lua
19
apps/Lua.lua
|
@ -1,4 +1,5 @@
|
||||||
require = requireInjector(getfenv(1))
|
local injector = requireInjector or load(http.get('http://pastebin.com/raw/c0TWsScv').readAll())()
|
||||||
|
require = injector(getfenv(1))
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
|
@ -6,7 +7,7 @@ local History = require('history')
|
||||||
|
|
||||||
local sandboxEnv = Util.shallowCopy(getfenv(1))
|
local sandboxEnv = Util.shallowCopy(getfenv(1))
|
||||||
sandboxEnv.exit = function() Event.exitPullEvents() end
|
sandboxEnv.exit = function() Event.exitPullEvents() end
|
||||||
sandboxEnv.require = requireInjector(sandboxEnv)
|
sandboxEnv.require = injector(sandboxEnv)
|
||||||
setmetatable(sandboxEnv, { __index = _G })
|
setmetatable(sandboxEnv, { __index = _G })
|
||||||
|
|
||||||
multishell.setTitle(multishell.getCurrent(), 'Lua')
|
multishell.setTitle(multishell.getCurrent(), 'Lua')
|
||||||
|
@ -20,7 +21,7 @@ local page = UI.Page({
|
||||||
buttons = {
|
buttons = {
|
||||||
{ text = 'Local', event = 'local' },
|
{ text = 'Local', event = 'local' },
|
||||||
{ text = 'Global', event = 'global' },
|
{ text = 'Global', event = 'global' },
|
||||||
{ text = 'Device', event = 'device' },
|
{ text = 'Device', event = 'device', name = 'Device' },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
prompt = UI.TextEntry({
|
prompt = UI.TextEntry({
|
||||||
|
@ -66,6 +67,9 @@ end
|
||||||
function page:enable()
|
function page:enable()
|
||||||
self:setFocus(self.prompt)
|
self:setFocus(self.prompt)
|
||||||
UI.Page.enable(self)
|
UI.Page.enable(self)
|
||||||
|
if not device then
|
||||||
|
self.menuBar.Device:disable()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function page:eventHandler(event)
|
function page:eventHandler(event)
|
||||||
|
@ -233,6 +237,8 @@ function page:executeStatement(statement)
|
||||||
|
|
||||||
if s and m then
|
if s and m then
|
||||||
self:setResult(m)
|
self:setResult(m)
|
||||||
|
elseif s and type(m) == 'boolean' then
|
||||||
|
self:setResult(m)
|
||||||
else
|
else
|
||||||
self.grid:setValues({ })
|
self.grid:setValues({ })
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
|
@ -242,10 +248,11 @@ function page:executeStatement(statement)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
sandboxEnv.args = { ... }
|
local args = { ... }
|
||||||
if sandboxEnv.args[1] then
|
if args[1] then
|
||||||
command = 'args[1]'
|
command = 'args[1]'
|
||||||
page:setResult(sandboxEnv.args[1])
|
sandboxEnv.args = args
|
||||||
|
page:setResult(args[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
UI:setPage(page)
|
UI:setPage(page)
|
||||||
|
|
|
@ -331,64 +331,68 @@ function page:eventHandler(event)
|
||||||
end
|
end
|
||||||
|
|
||||||
local formWidth = math.max(UI.term.width - 14, 26)
|
local formWidth = math.max(UI.term.width - 14, 26)
|
||||||
local gutter = math.floor((UI.term.width - formWidth) / 2) + 1
|
|
||||||
|
|
||||||
local editor = UI.Page({
|
local editor = UI.Page {
|
||||||
backgroundColor = colors.blue,
|
backgroundColor = colors.white,
|
||||||
form = UI.Form({
|
x = math.ceil((UI.term.width - formWidth) / 2) + 1,
|
||||||
fields = {
|
y = math.ceil((UI.term.height - 11) / 2) + 1,
|
||||||
{ label = 'Title', key = 'title', width = 15, limit = 11, display = UI.Form.D.entry,
|
z = 2,
|
||||||
help = 'Application title' },
|
height = 11,
|
||||||
{ label = 'Run', key = 'run', width = formWidth - 11, limit = 100, display = UI.Form.D.entry,
|
width = formWidth,
|
||||||
help = 'Full path to application' },
|
titleBar = UI.TitleBar {
|
||||||
{ label = 'Category', key = 'category', width = 15, limit = 11, display = UI.Form.D.entry,
|
title = 'Edit application',
|
||||||
help = 'Category of application' },
|
},
|
||||||
{ text = 'Accept', event = 'accept', display = UI.Form.D.button,
|
inset = UI.Window {
|
||||||
x = 1, y = 9, width = 10 },
|
x = 2,
|
||||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
y = 3,
|
||||||
x = formWidth - 11, y = 9, width = 10 },
|
rex = -2,
|
||||||
|
rey = -3,
|
||||||
|
form = UI.Form {
|
||||||
|
textColor = colors.black,
|
||||||
|
fields = {
|
||||||
|
{ label = 'Title', key = 'title', width = formWidth - 11, limit = 11, display = UI.Form.D.entry,
|
||||||
|
help = 'Application title' },
|
||||||
|
{ label = 'Run', key = 'run', width = formWidth - 11, limit = 100, display = UI.Form.D.entry,
|
||||||
|
help = 'Full path to application' },
|
||||||
|
{ label = 'Category', key = 'category', width = formWidth - 11, limit = 11, display = UI.Form.D.entry,
|
||||||
|
help = 'Category of application' },
|
||||||
|
{ text = 'Icon', event = 'loadIcon', display = UI.Form.D.button,
|
||||||
|
x = 10, y = 5, textColor = colors.white, help = 'Select icon' },
|
||||||
|
{ text = 'Ok', event = 'accept', display = UI.Form.D.button,
|
||||||
|
x = formWidth - 14, y = 7, textColor = colors.white },
|
||||||
|
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||||
|
x = formWidth - 9, y = 7, textColor = colors.white },
|
||||||
|
},
|
||||||
|
labelWidth = 8,
|
||||||
|
image = UI.NftImage {
|
||||||
|
y = 5,
|
||||||
|
x = 1,
|
||||||
|
height = 3,
|
||||||
|
width = 8,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
labelWidth = 8,
|
},
|
||||||
x = gutter + 1,
|
|
||||||
y = math.max(2, math.floor((UI.term.height - 9) / 2)),
|
|
||||||
height = 9,
|
|
||||||
width = UI.term.width - (gutter * 2),
|
|
||||||
image = UI.NftImage({
|
|
||||||
y = 5,
|
|
||||||
x = 1,
|
|
||||||
height = 3,
|
|
||||||
width = 8,
|
|
||||||
}),
|
|
||||||
button = UI.Button({
|
|
||||||
x = 10,
|
|
||||||
y = 6,
|
|
||||||
text = 'Load icon',
|
|
||||||
width = 11,
|
|
||||||
event = 'loadIcon',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
statusBar = UI.StatusBar(),
|
statusBar = UI.StatusBar(),
|
||||||
notification = UI.Notification(),
|
notification = UI.Notification(),
|
||||||
iconFile = '',
|
iconFile = '',
|
||||||
})
|
}
|
||||||
|
|
||||||
function editor:enable(app)
|
function editor:enable(app)
|
||||||
if app then
|
if app then
|
||||||
self.original = app
|
self.original = app
|
||||||
self.form:setValues(Util.shallowCopy(app))
|
self.inset.form:setValues(Util.shallowCopy(app))
|
||||||
|
|
||||||
local icon
|
local icon
|
||||||
if app.icon then
|
if app.icon then
|
||||||
icon = parseIcon(app.icon)
|
icon = parseIcon(app.icon)
|
||||||
end
|
end
|
||||||
self.form.image:setImage(icon)
|
self.inset.form.image:setImage(icon)
|
||||||
|
|
||||||
self:setFocus(self.form.children[1])
|
|
||||||
end
|
end
|
||||||
UI.Page.enable(self)
|
UI.Page.enable(self)
|
||||||
|
self:focusFirst()
|
||||||
end
|
end
|
||||||
|
|
||||||
function editor.form.image:draw()
|
function editor.inset.form.image:draw()
|
||||||
self:clear()
|
self:clear()
|
||||||
UI.NftImage.draw(self)
|
UI.NftImage.draw(self)
|
||||||
end
|
end
|
||||||
|
@ -414,7 +418,13 @@ function editor:eventHandler(event)
|
||||||
self.statusBar:draw()
|
self.statusBar:draw()
|
||||||
|
|
||||||
elseif event.type == 'loadIcon' then
|
elseif event.type == 'loadIcon' then
|
||||||
local fileui = FileUI()
|
local fileui = FileUI({
|
||||||
|
x = self.x,
|
||||||
|
y = self.y,
|
||||||
|
z = 2,
|
||||||
|
width = self.width,
|
||||||
|
height = self.height,
|
||||||
|
})
|
||||||
--fileui:setTransition(UI.effect.explode)
|
--fileui:setTransition(UI.effect.explode)
|
||||||
UI:setPage(fileui, fs.getDir(self.iconFile), function(fileName)
|
UI:setPage(fileui, fs.getDir(self.iconFile), function(fileName)
|
||||||
if fileName then
|
if fileName then
|
||||||
|
@ -428,18 +438,19 @@ function editor:eventHandler(event)
|
||||||
if not icon then
|
if not icon then
|
||||||
error(m)
|
error(m)
|
||||||
end
|
end
|
||||||
self.form.values.icon = iconLines
|
self.inset.form.values.icon = iconLines
|
||||||
self.form.image:setImage(icon)
|
self.inset.form.image:setImage(icon)
|
||||||
self.form.image:draw()
|
self.inset.form.image:draw()
|
||||||
end)
|
end)
|
||||||
if not s and m then
|
if not s and m then
|
||||||
self.notification:error(m:gsub('.*: (.*)', '%1'))
|
local msg = m:gsub('.*: (.*)', '%1')
|
||||||
|
self.notification:error(msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
elseif event.type == 'accept' then
|
elseif event.type == 'accept' then
|
||||||
local values = self.form.values
|
local values = self.inset.form.values
|
||||||
if #values.run > 0 and #values.title > 0 and #values.category > 0 then
|
if #values.run > 0 and #values.title > 0 and #values.category > 0 then
|
||||||
UI:setPreviousPage()
|
UI:setPreviousPage()
|
||||||
self:updateApplications(values, self.original)
|
self:updateApplications(values, self.original)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
require = requireInjector(getfenv(1))
|
local injector = requireInjector or load(http.get('http://pastebin.com/raw/c0TWsScv').readAll())()
|
||||||
|
require = injector(getfenv(1))
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
|
|
|
@ -66,7 +66,7 @@ local keyMapping = {
|
||||||
pageUp = 'pageUp',
|
pageUp = 'pageUp',
|
||||||
[ 'control-b' ] = 'pageUp',
|
[ 'control-b' ] = 'pageUp',
|
||||||
pageDown = 'pageDown',
|
pageDown = 'pageDown',
|
||||||
[ 'control-f' ] = 'pageDown',
|
-- [ 'control-f' ] = 'pageDown',
|
||||||
home = 'home',
|
home = 'home',
|
||||||
[ 'end' ] = 'toend',
|
[ 'end' ] = 'toend',
|
||||||
[ 'control-home' ] = 'top',
|
[ 'control-home' ] = 'top',
|
||||||
|
@ -101,6 +101,7 @@ local keyMapping = {
|
||||||
paste = 'paste',
|
paste = 'paste',
|
||||||
tab = 'tab',
|
tab = 'tab',
|
||||||
[ 'control-z' ] = 'undo',
|
[ 'control-z' ] = 'undo',
|
||||||
|
[ 'control-space' ] = 'autocomplete',
|
||||||
|
|
||||||
-- copy/paste
|
-- copy/paste
|
||||||
[ 'control-x' ] = 'cut',
|
[ 'control-x' ] = 'cut',
|
||||||
|
@ -114,6 +115,7 @@ local keyMapping = {
|
||||||
[ 'control-enter' ] = 'run',
|
[ 'control-enter' ] = 'run',
|
||||||
|
|
||||||
-- search
|
-- search
|
||||||
|
[ 'control-f' ] = 'find_prompt',
|
||||||
[ 'control-slash' ] = 'find_prompt',
|
[ 'control-slash' ] = 'find_prompt',
|
||||||
[ 'control-n' ] = 'find_next',
|
[ 'control-n' ] = 'find_next',
|
||||||
|
|
||||||
|
@ -476,6 +478,41 @@ local __actions = {
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
autocomplete = function()
|
||||||
|
local sLine = tLines[y]:sub(1, x - 1)
|
||||||
|
local nStartPos = sLine:find("[a-zA-Z0-9_%.]+$")
|
||||||
|
if nStartPos then
|
||||||
|
sLine = sLine:sub(nStartPos)
|
||||||
|
end
|
||||||
|
if #sLine > 0 then
|
||||||
|
local results = textutils.complete(sLine)
|
||||||
|
|
||||||
|
if #results == 0 then
|
||||||
|
setError('No completions available')
|
||||||
|
|
||||||
|
elseif #results == 1 then
|
||||||
|
actions.insertText(x, y, results[1])
|
||||||
|
|
||||||
|
elseif #results > 1 then
|
||||||
|
local prefix = results[1]
|
||||||
|
for n = 1, #results do
|
||||||
|
local result = results[n]
|
||||||
|
while #prefix > 0 do
|
||||||
|
if result:find(prefix, 1, true) == 1 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
prefix = prefix:sub(1, #prefix - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #prefix > 0 then
|
||||||
|
actions.insertText(x, y, prefix)
|
||||||
|
else
|
||||||
|
setStatus('Too many results')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
refresh = function()
|
refresh = function()
|
||||||
actions.dirty_all()
|
actions.dirty_all()
|
||||||
mark.continue = mark.active
|
mark.continue = mark.active
|
||||||
|
@ -528,7 +565,7 @@ local __actions = {
|
||||||
find_prompt = function()
|
find_prompt = function()
|
||||||
local text = actions.input('/')
|
local text = actions.input('/')
|
||||||
if #text > 0 then
|
if #text > 0 then
|
||||||
searchPattern = text
|
searchPattern = text:lower()
|
||||||
if searchPattern then
|
if searchPattern then
|
||||||
actions.unmark()
|
actions.unmark()
|
||||||
actions.find(searchPattern, x)
|
actions.find(searchPattern, x)
|
||||||
|
|
|
@ -36,6 +36,7 @@ if turtle and device.wireless_modem then
|
||||||
|
|
||||||
Util.print('Setting turtle point to %d %d %d', pt.x, pt.y, pt.z)
|
Util.print('Setting turtle point to %d %d %d', pt.x, pt.y, pt.z)
|
||||||
turtle.setPoint(pt)
|
turtle.setPoint(pt)
|
||||||
|
turtle.getState().coordSystem = 'GPS'
|
||||||
|
|
||||||
if not turtle.pathfind(homePt) then
|
if not turtle.pathfind(homePt) then
|
||||||
error('Failed to return home')
|
error('Failed to return home')
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
|
|
||||||
return function()
|
return function(args)
|
||||||
|
|
||||||
local columns = {
|
local columns = {
|
||||||
{ heading = 'Name', key = 'name', width = UI.term.width - 9 },
|
{ heading = 'Name', key = 'name', width = UI.term.width - 9 },
|
||||||
|
@ -13,18 +13,23 @@ return function()
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local selectFile = UI.Page({
|
args = args or { }
|
||||||
x = 3,
|
|
||||||
y = 2,
|
local selectFile = UI.Page {
|
||||||
rex = -3,
|
x = args.x or 3,
|
||||||
rey = -3,
|
y = args.y or 2,
|
||||||
|
z = args.z or 2,
|
||||||
|
-- rex = args.rex or -3,
|
||||||
|
-- rey = args.rey or -3,
|
||||||
|
height = args.height,
|
||||||
|
width = args.width,
|
||||||
backgroundColor = colors.brown,
|
backgroundColor = colors.brown,
|
||||||
titleBar = UI.TitleBar({
|
titleBar = UI.TitleBar {
|
||||||
title = 'Select file',
|
title = 'Select file',
|
||||||
previousPage = true,
|
previousPage = true,
|
||||||
event = 'cancel',
|
event = 'cancel',
|
||||||
}),
|
},
|
||||||
grid = UI.ScrollingGrid({
|
grid = UI.ScrollingGrid {
|
||||||
x = 2,
|
x = 2,
|
||||||
y = 2,
|
y = 2,
|
||||||
rex = -2,
|
rex = -2,
|
||||||
|
@ -32,8 +37,8 @@ return function()
|
||||||
path = '',
|
path = '',
|
||||||
sortColumn = 'name',
|
sortColumn = 'name',
|
||||||
columns = columns,
|
columns = columns,
|
||||||
}),
|
},
|
||||||
path = UI.TextEntry({
|
path = UI.TextEntry {
|
||||||
x = 2,
|
x = 2,
|
||||||
ry = -1,
|
ry = -1,
|
||||||
rex = -11,
|
rex = -11,
|
||||||
|
@ -41,14 +46,14 @@ return function()
|
||||||
accelerators = {
|
accelerators = {
|
||||||
enter = 'path_enter',
|
enter = 'path_enter',
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
cancel = UI.Button({
|
cancel = UI.Button {
|
||||||
text = 'Cancel',
|
text = 'Cancel',
|
||||||
rx = -8,
|
rx = -8,
|
||||||
ry = -1,
|
ry = -1,
|
||||||
event = 'cancel',
|
event = 'cancel',
|
||||||
}),
|
},
|
||||||
})
|
}
|
||||||
|
|
||||||
function selectFile:enable(path, fn)
|
function selectFile:enable(path, fn)
|
||||||
self:setPath(path)
|
self:setPath(path)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
local json = require('json')
|
local json = require('craigmj.json4lua.master.json.json')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1'
|
local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1'
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
local DEFAULT_UPATH = 'https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis'
|
local DEFAULT_UPATH = 'https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis'
|
||||||
local PASTEBIN_URL = 'http://pastebin.com/raw'
|
local PASTEBIN_URL = 'http://pastebin.com/raw'
|
||||||
local GIT_URL = 'https://raw.githubusercontent.com/'
|
local GIT_URL = 'https://raw.githubusercontent.com'
|
||||||
|
|
||||||
|
local function standardSearcher(modname, env, shell)
|
||||||
|
if package.loaded[modname] then
|
||||||
|
return function()
|
||||||
|
return package.loaded[modname]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function shellSearcher(modname, env, shell)
|
local function shellSearcher(modname, env, shell)
|
||||||
local fname = modname:gsub('%.', '/') .. '.lua'
|
local fname = modname:gsub('%.', '/') .. '.lua'
|
||||||
|
@ -80,7 +88,8 @@ local function gitSearcher(modname, env, shell)
|
||||||
local fname = modname:gsub('%.', '/') .. '.lua'
|
local fname = modname:gsub('%.', '/') .. '.lua'
|
||||||
local _, count = fname:gsub("/", "")
|
local _, count = fname:gsub("/", "")
|
||||||
if count >= 3 then
|
if count >= 3 then
|
||||||
local url = GIT_URL .. '/' .. modname
|
local url = GIT_URL .. '/' .. fname
|
||||||
|
debug(url)
|
||||||
local c = loadUrl(url)
|
local c = loadUrl(url)
|
||||||
if c then
|
if c then
|
||||||
return load(c, modname, nil, env)
|
return load(c, modname, nil, env)
|
||||||
|
@ -105,7 +114,16 @@ end
|
||||||
_G.package = {
|
_G.package = {
|
||||||
path = LUA_PATH or 'sys/apis',
|
path = LUA_PATH or 'sys/apis',
|
||||||
upath = LUA_UPATH or DEFAULT_UPATH,
|
upath = LUA_UPATH or DEFAULT_UPATH,
|
||||||
|
config = '/\n:\n?\n!\n-',
|
||||||
|
loaded = {
|
||||||
|
math = math,
|
||||||
|
string = string,
|
||||||
|
table = table,
|
||||||
|
io = io,
|
||||||
|
os = os,
|
||||||
|
},
|
||||||
loaders = {
|
loaders = {
|
||||||
|
standardSearcher,
|
||||||
shellSearcher,
|
shellSearcher,
|
||||||
pathSearcher,
|
pathSearcher,
|
||||||
pastebinSearcher,
|
pastebinSearcher,
|
||||||
|
@ -125,7 +143,7 @@ local function requireWrapper(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,searcher in ipairs(package.loaders) do
|
for _,searcher in ipairs(package.loaders) do
|
||||||
local fn = searcher(modname, env, shell)
|
local fn, msg = searcher(modname, env, shell)
|
||||||
if fn then
|
if fn then
|
||||||
local module, msg = fn(modname, env)
|
local module, msg = fn(modname, env)
|
||||||
if not module then
|
if not module then
|
||||||
|
@ -134,6 +152,9 @@ local function requireWrapper(env)
|
||||||
loaded[modname] = module
|
loaded[modname] = module
|
||||||
return module
|
return module
|
||||||
end
|
end
|
||||||
|
if msg then
|
||||||
|
error(msg)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
error('Unable to find module ' .. modname)
|
error('Unable to find module ' .. modname)
|
||||||
end
|
end
|
||||||
|
|
455
sys/apis/ui.lua
455
sys/apis/ui.lua
|
@ -112,7 +112,6 @@ function Manager:init(args)
|
||||||
Event.addHandler('mouse_click', function(h, button, x, y)
|
Event.addHandler('mouse_click', function(h, button, x, y)
|
||||||
|
|
||||||
if button == 1 and shift and control then -- hack
|
if button == 1 and shift and control then -- hack
|
||||||
|
|
||||||
local event = self:pointToChild(self.target, x, y)
|
local event = self:pointToChild(self.target, x, y)
|
||||||
multishell.openTab({ path = 'apps/Lua.lua', args = { event.element }, focused = true })
|
multishell.openTab({ path = 'apps/Lua.lua', args = { event.element }, focused = true })
|
||||||
|
|
||||||
|
@ -226,13 +225,15 @@ function Manager:disableEffects()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Manager:loadTheme(filename)
|
function Manager:loadTheme(filename)
|
||||||
local theme, err = Util.loadTable(filename)
|
if fs.exists(filename) then
|
||||||
if not theme then
|
local theme, err = Util.loadTable(filename)
|
||||||
error(err)
|
if not theme then
|
||||||
end
|
error(err)
|
||||||
for k,v in pairs(theme) do
|
end
|
||||||
if self[k] and self[k].defaults then
|
for k,v in pairs(theme) do
|
||||||
Util.merge(self[k].defaults, v)
|
if self[k] and self[k].defaults then
|
||||||
|
Util.merge(self[k].defaults, v)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -292,7 +293,6 @@ function Manager:click(button, x, y)
|
||||||
if x < self.target.x or y < self.target.y or
|
if x < self.target.x or y < self.target.y or
|
||||||
x > self.target.x + self.target.width - 1 or
|
x > self.target.x + self.target.width - 1 or
|
||||||
y > self.target.y + self.target.height - 1 then
|
y > self.target.y + self.target.height - 1 then
|
||||||
|
|
||||||
target:emit({ type = 'mouse_out' })
|
target:emit({ type = 'mouse_out' })
|
||||||
|
|
||||||
target = self.currentPage
|
target = self.currentPage
|
||||||
|
@ -658,8 +658,12 @@ function UI.Window:write(x, y, text, bg, tc)
|
||||||
x = x - self.offx
|
x = x - self.offx
|
||||||
y = y - self.offy
|
y = y - self.offy
|
||||||
if y <= self.height and y > 0 then
|
if y <= self.height and y > 0 then
|
||||||
self.parent:write(
|
if self.canvas then
|
||||||
self.x + x - 1, self.y + y - 1, tostring(text), bg, tc)
|
self.canvas:write(x, y, text, bg, tc)
|
||||||
|
else
|
||||||
|
self.parent:write(
|
||||||
|
self.x + x - 1, self.y + y - 1, tostring(text), bg, tc)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -830,20 +834,24 @@ function UI.Window:eventHandler(event)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- Blit data manipulation --]]--
|
--[[-- Blit data manipulation --]]--
|
||||||
local Blob = class()
|
local Canvas = class()
|
||||||
function Blob:init(args)
|
function Canvas:init(args)
|
||||||
self.x = 1
|
self.x = 1
|
||||||
self.y = 1
|
self.y = 1
|
||||||
self.lines = { }
|
|
||||||
Util.merge(self, args)
|
Util.merge(self, args)
|
||||||
|
|
||||||
for i = 1, self.ey - self.y + 1 do
|
self.height = self.ey - self.y + 1
|
||||||
|
self.width = self.ex - self.x + 1
|
||||||
|
|
||||||
|
self.lines = { }
|
||||||
|
for i = 1, self.height do
|
||||||
self.lines[i] = { }
|
self.lines[i] = { }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Blob:copy()
|
function Canvas:copy()
|
||||||
local b = Blob({ x = self.x, y = self.y, ex = self.ex, ey = self.ey })
|
local b = Canvas({ x = self.x, y = self.y, ex = self.ex, ey = self.ey })
|
||||||
for i = 1, self.ey - self.y + 1 do
|
for i = 1, self.ey - self.y + 1 do
|
||||||
b.lines[i].text = self.lines[i].text
|
b.lines[i].text = self.lines[i].text
|
||||||
b.lines[i].fg = self.lines[i].fg
|
b.lines[i].fg = self.lines[i].fg
|
||||||
|
@ -852,43 +860,170 @@ function Blob:copy()
|
||||||
return b
|
return b
|
||||||
end
|
end
|
||||||
|
|
||||||
function Blob:write(y, text, fg, bg)
|
function Canvas:addLayer(layer, bg, fg)
|
||||||
|
local canvas = Canvas({
|
||||||
|
x = layer.x,
|
||||||
|
y = layer.y,
|
||||||
|
ex = layer.x + layer.width - 1,
|
||||||
|
ey = layer.y + layer.height - 1,
|
||||||
|
isColor = self.isColor,
|
||||||
|
})
|
||||||
|
canvas:clear(colorToPaintColor(bg, self.isColor),
|
||||||
|
colorToPaintColor(fg, self.isColor))
|
||||||
|
|
||||||
|
canvas.parent = self
|
||||||
|
if not self.layers then
|
||||||
|
self.layers = { }
|
||||||
|
end
|
||||||
|
table.insert(self.layers, canvas)
|
||||||
|
return canvas
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:removeLayer()
|
||||||
|
for k, layer in pairs(self.parent.layers) do
|
||||||
|
if layer == self then
|
||||||
|
self:setVisible(false)
|
||||||
|
table.remove(self.parent.layers, k)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:setVisible(visible)
|
||||||
|
self.visible = visible
|
||||||
|
if not visible then
|
||||||
|
self.parent:dirty()
|
||||||
|
-- set parent's lines to dirty for each line in self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:write(x, y, text, bg, tc)
|
||||||
|
|
||||||
|
if y > 0 and y <= self.height and x <= self.width then
|
||||||
|
|
||||||
|
local width = #text
|
||||||
|
|
||||||
|
if x < 1 then
|
||||||
|
text = text:sub(2 - x)
|
||||||
|
width = width + x - 1
|
||||||
|
x = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if x + width - 1 > self.width then
|
||||||
|
text = text:sub(1, self.width - x + 1)
|
||||||
|
width = #text
|
||||||
|
end
|
||||||
|
|
||||||
|
if width > 0 then
|
||||||
|
|
||||||
|
local function replace(sstr, pos, rstr, width)
|
||||||
|
return sstr:sub(1, pos-1) .. rstr .. sstr:sub(pos+width)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fill(sstr, pos, rstr, width)
|
||||||
|
return sstr:sub(1, pos-1) .. string.rep(rstr, width) .. sstr:sub(pos+width)
|
||||||
|
end
|
||||||
|
|
||||||
|
local line = self.lines[y]
|
||||||
|
line.dirty = true
|
||||||
|
line.text = replace(line.text, x, text, width)
|
||||||
|
if bg then
|
||||||
|
line.bg = fill(line.bg, x, colorToPaintColor(bg, self.isColor), width)
|
||||||
|
end
|
||||||
|
if tc then
|
||||||
|
line.fg = fill(line.fg, x, colorToPaintColor(tc, self.isColor), width)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:writeLine(y, text, fg, bg)
|
||||||
self.lines[y].dirty = true
|
self.lines[y].dirty = true
|
||||||
self.lines[y].text = text
|
self.lines[y].text = text
|
||||||
self.lines[y].fg = fg
|
self.lines[y].fg = fg
|
||||||
self.lines[y].bg = bg
|
self.lines[y].bg = bg
|
||||||
end
|
end
|
||||||
|
|
||||||
function Blob:reset()
|
function Canvas:reset()
|
||||||
self.region = nil
|
self.region = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function Blob:punch(rect)
|
function Canvas:clear(bg, fg)
|
||||||
|
local width = self.ex - self.x + 1
|
||||||
|
local text = string.rep(' ', width)
|
||||||
|
fg = string.rep(fg, width)
|
||||||
|
bg = string.rep(bg, width)
|
||||||
|
for i = 1, self.ey - self.y + 1 do
|
||||||
|
self:writeLine(i, text, fg, bg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:punch(rect)
|
||||||
if not self.regions then
|
if not self.regions then
|
||||||
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
||||||
end
|
end
|
||||||
self.regions:subRect(rect.x, rect.y, rect.ex, rect.ey)
|
self.regions:subRect(rect.x, rect.y, rect.ex, rect.ey)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Blob:blitClipped(device)
|
function Canvas:blitClipped(device)
|
||||||
for _,region in ipairs(self.regions.region) do
|
for _,region in ipairs(self.regions.region) do
|
||||||
self:blit(device,
|
self:blit(device,
|
||||||
{ x = region[1], y = region[2], ex = region[3], ey = region[4] },
|
{ x = region[1] - self.x + 1,
|
||||||
|
y = region[2] - self.y + 1,
|
||||||
|
ex = region[3]- self.x + 1,
|
||||||
|
ey = region[4] - self.y + 1 },
|
||||||
{ x = region[1], y = region[2] })
|
{ x = region[1], y = region[2] })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Blob:blit(device, src, tgt)
|
function Canvas:dirty()
|
||||||
|
for _, line in pairs(self.lines) do
|
||||||
|
line.dirty = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:clean()
|
||||||
|
for y, line in ipairs(self.lines) do
|
||||||
|
line.dirty = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:render(device, layers)
|
||||||
|
layers = layers or self.layers
|
||||||
|
if layers then
|
||||||
|
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
||||||
|
local l = Util.shallowCopy(layers)
|
||||||
|
for _, canvas in ipairs(layers) do
|
||||||
|
table.remove(l, 1)
|
||||||
|
if canvas.visible then
|
||||||
|
self:punch(canvas)
|
||||||
|
canvas:render(device, l)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:blitClipped(device)
|
||||||
|
self:reset()
|
||||||
|
else
|
||||||
|
self:blit(device)
|
||||||
|
end
|
||||||
|
self:clean()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:blit(device, src, tgt)
|
||||||
|
src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 }
|
||||||
|
tgt = tgt or self
|
||||||
|
|
||||||
for i = 0, src.ey - src.y do
|
for i = 0, src.ey - src.y do
|
||||||
local line = self.lines[src.y + i]
|
local line = self.lines[src.y + i]
|
||||||
local t, fg, bg = line.text, line.fg, line.bg
|
if line.dirty then
|
||||||
if src.x > 1 or src.ex < self.ex then
|
local t, fg, bg = line.text, line.fg, line.bg
|
||||||
t = t:sub(src.x, src.ex)
|
if src.x > 1 or src.ex < self.ex then
|
||||||
fg = fg:sub(src.x, src.ex)
|
t = t:sub(src.x, src.ex)
|
||||||
bg = bg:sub(src.x, src.ex)
|
fg = fg:sub(src.x, src.ex)
|
||||||
|
bg = bg:sub(src.x, src.ex)
|
||||||
|
end
|
||||||
|
device.setCursorPos(tgt.x, tgt.y + i)
|
||||||
|
device.blit(t, fg, bg)
|
||||||
end
|
end
|
||||||
device.setCursorPos(tgt.x, tgt.y + i)
|
|
||||||
device.blit(t, fg, bg)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -906,21 +1041,23 @@ function UI.TransitionSlideLeft:init(args)
|
||||||
self.pos = { x = self.ex }
|
self.pos = { x = self.ex }
|
||||||
self.tween = Tween.new(self.ticks, self.pos, { x = self.x }, self.easing)
|
self.tween = Tween.new(self.ticks, self.pos, { x = self.x }, self.easing)
|
||||||
self.lastx = 0
|
self.lastx = 0
|
||||||
|
self.lastScreen = self.canvas:copy()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.TransitionSlideLeft:update(device, screen, lastScreen)
|
function UI.TransitionSlideLeft:update(device)
|
||||||
self.tween:update(1)
|
self.tween:update(1)
|
||||||
local x = math.floor(self.pos.x)
|
local x = math.floor(self.pos.x)
|
||||||
if x ~= self.lastx then
|
if x ~= self.lastx then
|
||||||
self.lastx = x
|
self.lastx = x
|
||||||
lastScreen:blit(device, {
|
self.lastScreen:dirty()
|
||||||
|
self.lastScreen:blit(device, {
|
||||||
x = self.ex - x + self.x,
|
x = self.ex - x + self.x,
|
||||||
y = self.y,
|
y = self.y,
|
||||||
ex = self.ex,
|
ex = self.ex,
|
||||||
ey = self.ey },
|
ey = self.ey },
|
||||||
{ x = self.x, y = self.y })
|
{ x = self.x, y = self.y })
|
||||||
|
|
||||||
screen:blit(device, {
|
self.canvas:blit(device, {
|
||||||
x = self.x,
|
x = self.x,
|
||||||
y = self.y,
|
y = self.y,
|
||||||
ex = self.ex - x + self.x + 1,
|
ex = self.ex - x + self.x + 1,
|
||||||
|
@ -944,20 +1081,22 @@ function UI.TransitionSlideRight:init(args)
|
||||||
self.pos = { x = self.x }
|
self.pos = { x = self.x }
|
||||||
self.tween = Tween.new(self.ticks, self.pos, { x = self.ex }, self.easing)
|
self.tween = Tween.new(self.ticks, self.pos, { x = self.ex }, self.easing)
|
||||||
self.lastx = 0
|
self.lastx = 0
|
||||||
|
self.lastScreen = self.canvas:copy()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.TransitionSlideRight:update(device, screen, lastScreen)
|
function UI.TransitionSlideRight:update(device)
|
||||||
self.tween:update(1)
|
self.tween:update(1)
|
||||||
local x = math.floor(self.pos.x)
|
local x = math.floor(self.pos.x)
|
||||||
if x ~= self.lastx then
|
if x ~= self.lastx then
|
||||||
self.lastx = x
|
self.lastx = x
|
||||||
lastScreen:blit(device, {
|
self.lastScreen:dirty()
|
||||||
|
self.lastScreen:blit(device, {
|
||||||
x = self.x,
|
x = self.x,
|
||||||
y = self.y,
|
y = self.y,
|
||||||
ex = self.ex - x + self.x + 1,
|
ex = self.ex - x + self.x + 1,
|
||||||
ey = self.ey },
|
ey = self.ey },
|
||||||
{ x = x, y = self.y })
|
{ x = x, y = self.y })
|
||||||
screen:blit(device, {
|
self.canvas:blit(device, {
|
||||||
x = self.ex - x + self.x,
|
x = self.ex - x + self.x,
|
||||||
y = self.y,
|
y = self.y,
|
||||||
ex = self.ex + 1,
|
ex = self.ex + 1,
|
||||||
|
@ -967,6 +1106,26 @@ function UI.TransitionSlideRight:update(device, screen, lastScreen)
|
||||||
return self.pos.x ~= self.ex
|
return self.pos.x ~= self.ex
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[-- TransitionExpandUp --]]--
|
||||||
|
UI.TransitionExpandUp = class()
|
||||||
|
UI.TransitionExpandUp.defaults = {
|
||||||
|
UIElement = 'TransitionExpandUp',
|
||||||
|
ticks = 3,
|
||||||
|
easing = 'linear',
|
||||||
|
}
|
||||||
|
function UI.TransitionExpandUp:init(args)
|
||||||
|
local defaults = UI:getDefaults(UI.TransitionExpandUp, args)
|
||||||
|
UI.setProperties(self, defaults)
|
||||||
|
self.pos = { y = self.ey + 1 }
|
||||||
|
self.tween = Tween.new(self.ticks, self.pos, { y = self.y }, self.easing)
|
||||||
|
end
|
||||||
|
|
||||||
|
function UI.TransitionExpandUp:update(device)
|
||||||
|
self.tween:update(1)
|
||||||
|
self.canvas:blit(device, nil, { x = self.x, y = math.floor(self.pos.y) })
|
||||||
|
return self.pos.y ~= self.y
|
||||||
|
end
|
||||||
|
|
||||||
--[[-- Terminal for computer / advanced computer / monitor --]]--
|
--[[-- Terminal for computer / advanced computer / monitor --]]--
|
||||||
UI.Device = class(UI.Window)
|
UI.Device = class(UI.Window)
|
||||||
UI.Device.defaults = {
|
UI.Device.defaults = {
|
||||||
|
@ -994,22 +1153,19 @@ function UI.Device:init(args)
|
||||||
|
|
||||||
UI.Window.init(self, defaults)
|
UI.Window.init(self, defaults)
|
||||||
|
|
||||||
self.blob = Blob({
|
|
||||||
x = 1, y = 1, ex = self.width, ey = self.height
|
|
||||||
})
|
|
||||||
for i = 1, self.height do
|
|
||||||
self.blob:write(i,
|
|
||||||
string.rep(' ', self.width),
|
|
||||||
string.rep(colorToPaintColor(self.backgroundColor, self.isColor), self.width),
|
|
||||||
string.rep(colorToPaintColor(self.textColor, self.isColor), self.width))
|
|
||||||
end
|
|
||||||
|
|
||||||
self.isColor = self.device.isColor()
|
self.isColor = self.device.isColor()
|
||||||
|
|
||||||
|
self.canvas = Canvas({
|
||||||
|
x = 1, y = 1, ex = self.width, ey = self.height,
|
||||||
|
isColor = self.isColor,
|
||||||
|
})
|
||||||
|
self.canvas:clear(colorToPaintColor(self.backgroundColor, self.isColor),
|
||||||
|
colorToPaintColor(self.textColor, self.isColor))
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Device:resize()
|
function UI.Device:resize()
|
||||||
self.width, self.height = self.device.getSize()
|
self.width, self.height = self.device.getSize()
|
||||||
self.lines = { }
|
self.lines = { } -- TODO -- resize canvas
|
||||||
UI.Window.resize(self)
|
UI.Window.resize(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1056,30 +1212,31 @@ function UI.Device:addTransition(effect, x, y, width, height)
|
||||||
y = y,
|
y = y,
|
||||||
ex = x + width - 1,
|
ex = x + width - 1,
|
||||||
ey = y + height - 1,
|
ey = y + height - 1,
|
||||||
|
canvas = self.canvas,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
table.insert(self.transitions, effect)
|
table.insert(self.transitions, effect)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Device:runTransitions(transitions)
|
function UI.Device:runTransitions(transitions, canvas)
|
||||||
|
|
||||||
for _,t in ipairs(transitions) do
|
for _,t in ipairs(transitions) do
|
||||||
self.blob:punch(t) -- punch out the effect areas
|
canvas:punch(t) -- punch out the effect areas
|
||||||
end
|
end
|
||||||
self.blob:blitClipped(self.device) -- and blit the remainder
|
canvas:blitClipped(self.device) -- and blit the remainder
|
||||||
self.blob:reset()
|
canvas:reset()
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
for _,k in ipairs(Util.keys(transitions)) do
|
for _,k in ipairs(Util.keys(transitions)) do
|
||||||
local transition = transitions[k]
|
local transition = transitions[k]
|
||||||
if not transition:update(self.device, self.blob, self.lastScreen) then
|
if not transition:update(self.device) then
|
||||||
transitions[k] = nil
|
transitions[k] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Util.empty(transitions) then
|
if Util.empty(transitions) then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
Event.sleep()
|
os.sleep() -- ?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1091,68 +1248,22 @@ function UI.Device:sync()
|
||||||
self.transitions = nil
|
self.transitions = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if transitions then
|
if self:getCursorBlink() then
|
||||||
self:runTransitions(transitions)
|
self.device.setCursorBlink(false)
|
||||||
else
|
|
||||||
for y, line in pairs(self.blob.lines) do
|
|
||||||
if line.dirty then
|
|
||||||
self.device.setCursorPos(1, y)
|
|
||||||
self.device.blit(line.text, line.fg, line.bg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.lastScreen = self.blob:copy()
|
if transitions then
|
||||||
|
self:runTransitions(transitions, self.canvas)
|
||||||
for y, line in ipairs(self.blob.lines) do
|
else
|
||||||
line.dirty = false
|
self.canvas:render(self.device)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:getCursorBlink() then
|
if self:getCursorBlink() then
|
||||||
|
self.device.setCursorBlink(true)
|
||||||
self.device.setCursorPos(self.cursorX, self.cursorY)
|
self.device.setCursorPos(self.cursorX, self.cursorY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Device:write(x, y, text, bg, tc)
|
|
||||||
|
|
||||||
if y > 0 and y <= self.height and x <= self.width then
|
|
||||||
|
|
||||||
local width = #text
|
|
||||||
|
|
||||||
if x < 1 then
|
|
||||||
text = text:sub(2 - x)
|
|
||||||
width = width + x - 1
|
|
||||||
x = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if x + width - 1 > self.width then
|
|
||||||
text = text:sub(1, self.width - x + 1)
|
|
||||||
width = #text
|
|
||||||
end
|
|
||||||
|
|
||||||
if width > 0 then
|
|
||||||
|
|
||||||
local function replace(sstr, pos, rstr, width)
|
|
||||||
return sstr:sub(1, pos-1) .. rstr .. sstr:sub(pos+width)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fill(sstr, pos, rstr, width)
|
|
||||||
return sstr:sub(1, pos-1) .. string.rep(rstr, width) .. sstr:sub(pos+width)
|
|
||||||
end
|
|
||||||
|
|
||||||
local line = self.blob.lines[y]
|
|
||||||
line.dirty = true
|
|
||||||
line.text = replace(line.text, x, text, width)
|
|
||||||
if bg then
|
|
||||||
line.bg = fill(line.bg, x, colorToPaintColor(bg, self.isColor), width)
|
|
||||||
end
|
|
||||||
if tc then
|
|
||||||
line.fg = fill(line.fg, x, colorToPaintColor(tc, self.isColor), width)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[-- StringBuffer --]]--
|
--[[-- StringBuffer --]]--
|
||||||
UI.StringBuffer = class()
|
UI.StringBuffer = class()
|
||||||
function UI.StringBuffer:init(bufSize)
|
function UI.StringBuffer:init(bufSize)
|
||||||
|
@ -1198,9 +1309,16 @@ function UI.Page:init(args)
|
||||||
defaults.parent = UI.defaultDevice
|
defaults.parent = UI.defaultDevice
|
||||||
UI.setProperties(defaults, args)
|
UI.setProperties(defaults, args)
|
||||||
UI.Window.init(self, defaults)
|
UI.Window.init(self, defaults)
|
||||||
|
|
||||||
|
if self.z then
|
||||||
|
self.canvas = self.parent.canvas:addLayer(self, self.backgroundColor, self.textColor)
|
||||||
|
else
|
||||||
|
self.canvas = self.parent.canvas
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Page:enable()
|
function UI.Page:enable()
|
||||||
|
self.canvas.visible = true
|
||||||
UI.Window.enable(self)
|
UI.Window.enable(self)
|
||||||
|
|
||||||
if not self.focused or not self.focused.enabled then
|
if not self.focused or not self.focused.enabled then
|
||||||
|
@ -1208,6 +1326,12 @@ function UI.Page:enable()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function UI.Page:disable()
|
||||||
|
if self.z then
|
||||||
|
self.canvas.visible = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function UI.Page:getFocused()
|
function UI.Page:getFocused()
|
||||||
return self.focused
|
return self.focused
|
||||||
end
|
end
|
||||||
|
@ -1305,6 +1429,8 @@ UI.Grid.defaults = {
|
||||||
unfocusedTextSelectedColor = colors.white,
|
unfocusedTextSelectedColor = colors.white,
|
||||||
unfocusedBackgroundSelectedColor = colors.gray,
|
unfocusedBackgroundSelectedColor = colors.gray,
|
||||||
focusIndicator = '>',
|
focusIndicator = '>',
|
||||||
|
sortIndicator = ' ',
|
||||||
|
inverseSortIndicator = '^',
|
||||||
values = { },
|
values = { },
|
||||||
columns = { },
|
columns = { },
|
||||||
}
|
}
|
||||||
|
@ -1461,8 +1587,12 @@ function UI.Grid:drawHeadings()
|
||||||
local sb = UI.StringBuffer(self.width)
|
local sb = UI.StringBuffer(self.width)
|
||||||
for _,col in ipairs(self.columns) do
|
for _,col in ipairs(self.columns) do
|
||||||
local ind = ' '
|
local ind = ' '
|
||||||
if self.inverseSort and col.key == self.sortColumn then
|
if col.key == self.sortColumn then
|
||||||
ind = '^'
|
if self.inverseSort then
|
||||||
|
ind = self.inverseSortIndicator
|
||||||
|
else
|
||||||
|
ind = self.sortIndicator
|
||||||
|
end
|
||||||
end
|
end
|
||||||
sb:insert(ind .. col.heading, col.width + 1)
|
sb:insert(ind .. col.heading, col.width + 1)
|
||||||
end
|
end
|
||||||
|
@ -1652,7 +1782,11 @@ end
|
||||||
UI.ScrollingGrid = class(UI.Grid)
|
UI.ScrollingGrid = class(UI.Grid)
|
||||||
UI.ScrollingGrid.defaults = {
|
UI.ScrollingGrid.defaults = {
|
||||||
UIElement = 'ScrollingGrid',
|
UIElement = 'ScrollingGrid',
|
||||||
scrollOffset = 1
|
scrollOffset = 1,
|
||||||
|
lineChar = '|',
|
||||||
|
sliderChar = '#',
|
||||||
|
upArrowChar = '^',
|
||||||
|
downArrowChar = 'v',
|
||||||
}
|
}
|
||||||
function UI.ScrollingGrid:init(args)
|
function UI.ScrollingGrid:init(args)
|
||||||
local defaults = UI:getDefaults(UI.ScrollingGrid, args)
|
local defaults = UI:getDefaults(UI.ScrollingGrid, args)
|
||||||
|
@ -1683,25 +1817,25 @@ function UI.ScrollingGrid:drawScrollbar()
|
||||||
|
|
||||||
local x = self.width
|
local x = self.width
|
||||||
if self.scrollOffset > 1 then
|
if self.scrollOffset > 1 then
|
||||||
self:write(x, 2, '^')
|
self:write(x, 2, self.upArrowChar)
|
||||||
else
|
else
|
||||||
self:write(x, 2, ' ')
|
self:write(x, 2, ' ')
|
||||||
end
|
end
|
||||||
local row = 0
|
local row = 0
|
||||||
for i = 1, sp - 1 do
|
for i = 1, sp - 1 do
|
||||||
self:write(x, row+3, '|')
|
self:write(x, row+3, self.lineChar)
|
||||||
row = row + 1
|
row = row + 1
|
||||||
end
|
end
|
||||||
for i = 1, sa do
|
for i = 1, sa do
|
||||||
self:write(x, row+3, '#')
|
self:write(x, row+3, self.sliderChar)
|
||||||
row = row + 1
|
row = row + 1
|
||||||
end
|
end
|
||||||
for i = row, sbSize do
|
for i = row, sbSize do
|
||||||
self:write(x, row+3, '|')
|
self:write(x, row+3, self.lineChar)
|
||||||
row = row + 1
|
row = row + 1
|
||||||
end
|
end
|
||||||
if self.scrollOffset + self.pageSize - 1 < Util.size(self.values) then
|
if self.scrollOffset + self.pageSize - 1 < Util.size(self.values) then
|
||||||
self:write(x, self.pageSize + 1, 'v')
|
self:write(x, self.pageSize + 1, self.downArrowChar)
|
||||||
else
|
else
|
||||||
self:write(x, self.pageSize + 1, ' ')
|
self:write(x, self.pageSize + 1, ' ')
|
||||||
end
|
end
|
||||||
|
@ -1946,19 +2080,23 @@ function UI.MenuBar:init(args)
|
||||||
|
|
||||||
local x = 1
|
local x = 1
|
||||||
for k,button in pairs(self.buttons) do
|
for k,button in pairs(self.buttons) do
|
||||||
local buttonProperties = {
|
if button.UIElement then
|
||||||
x = x,
|
table.insert(self.children, button)
|
||||||
width = #button.text + self.spacing,
|
|
||||||
backgroundColor = self.backgroundColor,
|
|
||||||
textColor = self.textColor,
|
|
||||||
centered = false,
|
|
||||||
}
|
|
||||||
x = x + buttonProperties.width
|
|
||||||
UI.setProperties(buttonProperties, button)
|
|
||||||
if button.name then
|
|
||||||
self[button.name] = UI.Button(buttonProperties)
|
|
||||||
else
|
else
|
||||||
table.insert(self.children, UI.Button(buttonProperties))
|
local buttonProperties = {
|
||||||
|
x = x,
|
||||||
|
width = #button.text + self.spacing,
|
||||||
|
backgroundColor = self.backgroundColor,
|
||||||
|
textColor = self.textColor,
|
||||||
|
centered = false,
|
||||||
|
}
|
||||||
|
x = x + buttonProperties.width
|
||||||
|
UI.setProperties(buttonProperties, button)
|
||||||
|
if button.name then
|
||||||
|
self[button.name] = UI.Button(buttonProperties)
|
||||||
|
else
|
||||||
|
table.insert(self.children, UI.Button(buttonProperties))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self.showBackButton then
|
if self.showBackButton then
|
||||||
|
@ -1997,6 +2135,7 @@ end
|
||||||
UI.DropMenu = class(UI.MenuBar)
|
UI.DropMenu = class(UI.MenuBar)
|
||||||
UI.DropMenu.defaults = {
|
UI.DropMenu.defaults = {
|
||||||
UIElement = 'DropMenu',
|
UIElement = 'DropMenu',
|
||||||
|
backgroundColor = colors.white,
|
||||||
}
|
}
|
||||||
function UI.DropMenu:init(args)
|
function UI.DropMenu:init(args)
|
||||||
local defaults = UI:getDefaults(UI.DropMenu, args)
|
local defaults = UI:getDefaults(UI.DropMenu, args)
|
||||||
|
@ -2011,7 +2150,7 @@ function UI.DropMenu:setParent()
|
||||||
for y,child in ipairs(self.children) do
|
for y,child in ipairs(self.children) do
|
||||||
child.x = 1
|
child.x = 1
|
||||||
child.y = y
|
child.y = y
|
||||||
if #child.text > maxWidth then
|
if #(child.text or '') > maxWidth then
|
||||||
maxWidth = #child.text
|
maxWidth = #child.text
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2155,9 +2294,9 @@ function UI.Tabs:activateTab(tab)
|
||||||
child:disable()
|
child:disable()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
self.tabBar:selectTab(tab.tabTitle)
|
||||||
tab:enable()
|
tab:enable()
|
||||||
tab:draw()
|
tab:draw()
|
||||||
self.tabBar:selectTab(tab.tabTitle)
|
|
||||||
self:emit({ type = 'tab_activate', activated = tab, element = self })
|
self:emit({ type = 'tab_activate', activated = tab, element = self })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2232,33 +2371,21 @@ UI.Notification = class(UI.Window)
|
||||||
UI.Notification.defaults = {
|
UI.Notification.defaults = {
|
||||||
UIElement = 'Notification',
|
UIElement = 'Notification',
|
||||||
backgroundColor = colors.gray,
|
backgroundColor = colors.gray,
|
||||||
height = 1,
|
height = 3,
|
||||||
}
|
}
|
||||||
function UI.Notification:init(args)
|
function UI.Notification:init(args)
|
||||||
local defaults = UI:getDefaults(UI.Notification, args)
|
local defaults = UI:getDefaults(UI.Notification, args)
|
||||||
UI.Window.init(self, defaults)
|
UI.Window.init(self, defaults)
|
||||||
|
Util.print(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Notification:draw()
|
function UI.Notification:draw()
|
||||||
if self.enabled then
|
|
||||||
local lines = Util.wordWrap(self.value, self.width - 2)
|
|
||||||
self.height = #lines -- + 2
|
|
||||||
self.y = UI.term.height - self.height + 1
|
|
||||||
self:clear()
|
|
||||||
for k,v in pairs(lines) do
|
|
||||||
self:write(2, k, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Notification:enable()
|
function UI.Notification:enable()
|
||||||
self.enabled = false
|
self.enabled = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Notification:resize()
|
|
||||||
self.y = UI.term.height + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function UI.Notification:error(value, timeout)
|
function UI.Notification:error(value, timeout)
|
||||||
self.backgroundColor = colors.red
|
self.backgroundColor = colors.red
|
||||||
self:display(value, timeout)
|
self:display(value, timeout)
|
||||||
|
@ -2275,16 +2402,32 @@ function UI.Notification:success(value, timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Notification:display(value, timeout)
|
function UI.Notification:display(value, timeout)
|
||||||
self.value = value
|
|
||||||
self.enabled = true
|
self.enabled = true
|
||||||
self:draw()
|
local lines = Util.wordWrap(value, self.width - 2)
|
||||||
|
self.height = #lines + 1
|
||||||
|
self.y = self.parent.height - self.height + 1
|
||||||
|
if self.canvas then
|
||||||
|
self.canvas:removeLayer()
|
||||||
|
end
|
||||||
|
self.canvas = UI.term.canvas:addLayer(self, self.backgroundColor, self.textColor or colors.white)
|
||||||
|
self:addTransition(UI.TransitionExpandUp {
|
||||||
|
x = self.x,
|
||||||
|
y = self.y,
|
||||||
|
ex = self.x + self.width - 1,
|
||||||
|
ey = self.y + self.height - 1,
|
||||||
|
canvas = self.canvas,
|
||||||
|
ticks = self.height,
|
||||||
|
})
|
||||||
|
self.canvas:setVisible(true)
|
||||||
|
self:clear()
|
||||||
|
for k,v in pairs(lines) do
|
||||||
|
self:write(2, k, v)
|
||||||
|
end
|
||||||
|
|
||||||
Event.addNamedTimer('notificationTimer', timeout or 3, false, function()
|
Event.addNamedTimer('notificationTimer', timeout or 3, false, function()
|
||||||
-- self.y = UI.term.height + 1
|
|
||||||
self.enabled = false
|
self.enabled = false
|
||||||
if self.parent.enabled then
|
self.canvas:removeLayer()
|
||||||
self.parent:draw()
|
self:sync()
|
||||||
self:sync()
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2592,7 +2735,7 @@ UI.TextEntry.defaults = {
|
||||||
shadowText = '',
|
shadowText = '',
|
||||||
focused = false,
|
focused = false,
|
||||||
backgroundColor = colors.lightGray,
|
backgroundColor = colors.lightGray,
|
||||||
backgroundFocusColor = colors.green,
|
backgroundFocusColor = colors.lightGray,
|
||||||
height = 1,
|
height = 1,
|
||||||
limit = 6,
|
limit = 6,
|
||||||
pos = 0,
|
pos = 0,
|
||||||
|
@ -2940,6 +3083,9 @@ function UI.Form:createFields()
|
||||||
if field.limit then
|
if field.limit then
|
||||||
width = field.limit + 2
|
width = field.limit + 2
|
||||||
end
|
end
|
||||||
|
if width == 0 then
|
||||||
|
width = nil
|
||||||
|
end
|
||||||
local fieldProperties = {
|
local fieldProperties = {
|
||||||
x = self.labelWidth + 2,
|
x = self.labelWidth + 2,
|
||||||
y = k,
|
y = k,
|
||||||
|
@ -2952,17 +3098,13 @@ function UI.Form:createFields()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Form:eventHandler(event)
|
function UI.Form:eventHandler(event)
|
||||||
|
|
||||||
if event.type == 'accept' then
|
if event.type == 'accept' then
|
||||||
for _,child in pairs(self.children) do
|
for _,child in pairs(self.children) do
|
||||||
if child.key then
|
if child.key then
|
||||||
self.values[child.key] = child.value
|
self.values[child.key] = child.value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- Dialog --]]--
|
--[[-- Dialog --]]--
|
||||||
|
@ -3087,8 +3229,9 @@ function UI.NftImage:setImage(image)
|
||||||
self.image = image
|
self.image = image
|
||||||
end
|
end
|
||||||
|
|
||||||
if fs.exists('/config/ui.theme') then
|
UI:loadTheme('config/ui.theme')
|
||||||
UI:loadTheme('/config/ui.theme')
|
if _HOST and string.find(_HOST, 'CCEmuRedux') then
|
||||||
|
UI:loadTheme('config/ccemuredux.theme')
|
||||||
end
|
end
|
||||||
|
|
||||||
UI:setDefaultDevice(UI.Device({ device = term.current() }))
|
UI:setDefaultDevice(UI.Device({ device = term.current() }))
|
||||||
|
|
|
@ -57,10 +57,12 @@ function turtle.run(fn, ...)
|
||||||
local e, id, abort = os.pullEventRaw('turtle_ticket')
|
local e, id, abort = os.pullEventRaw('turtle_ticket')
|
||||||
if e == 'terminate' then
|
if e == 'terminate' then
|
||||||
releaseTicket(ticketId)
|
releaseTicket(ticketId)
|
||||||
|
os.queueEvent('turtle_response')
|
||||||
error('Terminated')
|
error('Terminated')
|
||||||
end
|
end
|
||||||
if abort then
|
if abort then
|
||||||
-- the function was queued, but the queue was cleared
|
-- the function was queued, but the queue was cleared
|
||||||
|
os.queueEvent('turtle_response')
|
||||||
return false, 'aborted'
|
return false, 'aborted'
|
||||||
end
|
end
|
||||||
if id == ticketId then
|
if id == ticketId then
|
||||||
|
@ -72,6 +74,7 @@ function turtle.run(fn, ...)
|
||||||
if not s and m then
|
if not s and m then
|
||||||
printError(m)
|
printError(m)
|
||||||
end
|
end
|
||||||
|
os.queueEvent('turtle_response')
|
||||||
return s, m
|
return s, m
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,7 @@ local state = {
|
||||||
moveDig = noop,
|
moveDig = noop,
|
||||||
moveCallback = noop,
|
moveCallback = noop,
|
||||||
locations = {},
|
locations = {},
|
||||||
|
coordSystem = 'relative', -- type of coordinate system being used
|
||||||
}
|
}
|
||||||
|
|
||||||
function turtle.getState()
|
function turtle.getState()
|
||||||
|
@ -44,6 +45,7 @@ function turtle.reset()
|
||||||
state.moveDig = noop
|
state.moveDig = noop
|
||||||
state.moveCallback = noop
|
state.moveCallback = noop
|
||||||
state.locations = {}
|
state.locations = {}
|
||||||
|
state.coordSystem = 'relative'
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -231,7 +233,6 @@ turtle.digPolicies = {
|
||||||
if not turtle.isTurtleAtSide(action.side) then
|
if not turtle.isTurtleAtSide(action.side) then
|
||||||
return action.dig()
|
return action.dig()
|
||||||
end
|
end
|
||||||
|
|
||||||
return Util.tryTimes(6, function()
|
return Util.tryTimes(6, function()
|
||||||
-- if not turtle.isTurtleAtSide(action.side) then
|
-- if not turtle.isTurtleAtSide(action.side) then
|
||||||
-- return true --action.dig()
|
-- return true --action.dig()
|
||||||
|
|
|
@ -117,15 +117,19 @@ process:newThread('discovery_server', function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local info = {
|
||||||
|
id = os.getComputerID()
|
||||||
|
}
|
||||||
|
|
||||||
local function sendInfo()
|
local function sendInfo()
|
||||||
local info = {
|
info.label = os.getComputerLabel()
|
||||||
id = os.getComputerID(),
|
info.uptime = math.floor(os.clock())
|
||||||
label = os.getComputerLabel(),
|
|
||||||
uptime = math.floor(os.clock()),
|
|
||||||
}
|
|
||||||
if turtle then
|
if turtle then
|
||||||
info.fuel = turtle.getFuelLevel()
|
info.fuel = turtle.getFuelLevel()
|
||||||
info.status = turtle.status
|
info.status = turtle.status
|
||||||
|
info.point = turtle.point
|
||||||
|
info.inventory = turtle.getInventory()
|
||||||
|
info.coordSystem = turtle.getState().coordSystem
|
||||||
end
|
end
|
||||||
device.wireless_modem.transmit(999, os.getComputerID(), info)
|
device.wireless_modem.transmit(999, os.getComputerID(), info)
|
||||||
end
|
end
|
||||||
|
@ -152,13 +156,11 @@ end)
|
||||||
if os.isTurtle() then
|
if os.isTurtle() then
|
||||||
process:newThread('turtle_heartbeat', function()
|
process:newThread('turtle_heartbeat', function()
|
||||||
|
|
||||||
local lastUpdate = os.clock()
|
|
||||||
os.sleep(1)
|
os.sleep(1)
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
os.pullEvent('turtle_response')
|
os.pullEvent('turtle_response')
|
||||||
if os.clock() - lastUpdate >= 1 then
|
if turtle.status ~= info.status or
|
||||||
lastUpdate = os.clock()
|
turtle.fuel ~= info.fuel then
|
||||||
sendInfo()
|
sendInfo()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user