mirror of
https://github.com/kepler155c/opus
synced 2025-02-02 10:29:09 +00:00
Merge branch 'develop'
This commit is contained in:
commit
482c52b36f
@ -35,26 +35,32 @@ local Browser = UI.Page {
|
||||
},
|
||||
fileMenu = UI.DropMenu {
|
||||
buttons = {
|
||||
{ text = 'Run', event = 'run' },
|
||||
{ text = 'Edit e', event = 'edit' },
|
||||
{ text = 'Shell s', event = 'shell' },
|
||||
{ text = 'Quit q', event = 'quit' },
|
||||
{ text = 'Run', event = 'run' },
|
||||
{ text = 'Edit e', event = 'edit' },
|
||||
{ text = 'Shell s', event = 'shell' },
|
||||
UI.Text { value = ' ------------ ' },
|
||||
{ text = 'Quit q', event = 'quit' },
|
||||
UI.Text { },
|
||||
}
|
||||
},
|
||||
editMenu = UI.DropMenu {
|
||||
buttons = {
|
||||
{ text = 'Mark m', event = 'mark' },
|
||||
{ text = 'Cut ^x', event = 'cut' },
|
||||
{ text = 'Copy ^c', event = 'copy' },
|
||||
{ text = 'Paste ^v', event = 'paste' },
|
||||
{ text = 'Delete del', event = 'delete' },
|
||||
{ text = 'Unmark all u', event = 'unmark' },
|
||||
{ text = 'Cut ^x', event = 'cut' },
|
||||
{ text = 'Copy ^c', event = 'copy' },
|
||||
{ text = 'Paste ^v', event = 'paste' },
|
||||
UI.Text { value = ' --------------- ' },
|
||||
{ text = 'Mark m', event = 'mark' },
|
||||
{ text = 'Unmark all u', event = 'unmark' },
|
||||
UI.Text { value = ' --------------- ' },
|
||||
{ text = 'Delete del', event = 'delete' },
|
||||
UI.Text { },
|
||||
}
|
||||
},
|
||||
viewMenu = UI.DropMenu {
|
||||
buttons = {
|
||||
{ text = 'Refresh r', event = 'refresh' },
|
||||
{ text = 'Hidden ^h', event = 'toggle_hidden' },
|
||||
{ text = 'Refresh r', event = 'refresh' },
|
||||
{ text = 'Hidden ^h', event = 'toggle_hidden' },
|
||||
UI.Text { },
|
||||
}
|
||||
},
|
||||
grid = UI.ScrollingGrid {
|
||||
@ -69,8 +75,8 @@ local Browser = UI.Page {
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
columns = {
|
||||
{ '', 'status', UI.term.width - 19 },
|
||||
{ '', 'info', 10 },
|
||||
{ '', 'status', UI.term.width - 8 },
|
||||
--{ '', 'info', 10 },
|
||||
{ 'Size: ', 'totalSize', 8 },
|
||||
},
|
||||
},
|
||||
|
105
apps/Lua.lua
105
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 UI = require('ui')
|
||||
local Event = require('event')
|
||||
@ -6,7 +7,7 @@ local History = require('history')
|
||||
|
||||
local sandboxEnv = Util.shallowCopy(getfenv(1))
|
||||
sandboxEnv.exit = function() Event.exitPullEvents() end
|
||||
sandboxEnv.require = requireInjector(sandboxEnv)
|
||||
sandboxEnv.require = injector(sandboxEnv)
|
||||
setmetatable(sandboxEnv, { __index = _G })
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Lua')
|
||||
@ -15,12 +16,12 @@ UI:configure('Lua', ...)
|
||||
local command = ''
|
||||
local history = History.load('.lua_history', 25)
|
||||
|
||||
local resultsPage = UI.Page({
|
||||
local page = UI.Page({
|
||||
menuBar = UI.MenuBar({
|
||||
buttons = {
|
||||
{ text = 'Local', event = 'local' },
|
||||
{ text = 'Global', event = 'global' },
|
||||
{ text = 'Device', event = 'device' },
|
||||
{ text = 'Device', event = 'device', name = 'Device' },
|
||||
},
|
||||
}),
|
||||
prompt = UI.TextEntry({
|
||||
@ -29,10 +30,11 @@ local resultsPage = UI.Page({
|
||||
backgroundFocusColor = colors.black,
|
||||
limit = 256,
|
||||
accelerators = {
|
||||
enter = 'command_enter',
|
||||
up = 'history_back',
|
||||
down = 'history_forward',
|
||||
mouse_rightclick = 'clear_prompt',
|
||||
enter = 'command_enter',
|
||||
up = 'history_back',
|
||||
down = 'history_forward',
|
||||
mouse_rightclick = 'clear_prompt',
|
||||
-- [ 'control-space' ] = 'autocomplete',
|
||||
},
|
||||
}),
|
||||
grid = UI.ScrollingGrid({
|
||||
@ -47,7 +49,7 @@ local resultsPage = UI.Page({
|
||||
notification = UI.Notification(),
|
||||
})
|
||||
|
||||
function resultsPage:setPrompt(value, focus)
|
||||
function page:setPrompt(value, focus)
|
||||
self.prompt:setValue(value)
|
||||
self.prompt.scroll = 0
|
||||
self.prompt:setPosition(#value)
|
||||
@ -59,29 +61,77 @@ function resultsPage:setPrompt(value, focus)
|
||||
|
||||
self.prompt:draw()
|
||||
if focus then
|
||||
resultsPage:setFocus(self.prompt)
|
||||
page:setFocus(self.prompt)
|
||||
end
|
||||
end
|
||||
|
||||
function resultsPage:enable()
|
||||
function page:enable()
|
||||
self:setFocus(self.prompt)
|
||||
UI.Page.enable(self)
|
||||
if not device then
|
||||
self.menuBar.Device:disable()
|
||||
end
|
||||
end
|
||||
|
||||
function resultsPage:eventHandler(event)
|
||||
local function autocomplete(env, oLine, x)
|
||||
|
||||
local sLine = oLine:sub(1, x)
|
||||
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, env)
|
||||
|
||||
if #results == 0 then
|
||||
-- setError('No completions available')
|
||||
|
||||
elseif #results == 1 then
|
||||
return Util.insertString(oLine, results[1], x + 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
|
||||
return Util.insertString(oLine, prefix, x + 1)
|
||||
else
|
||||
-- setStatus('Too many results')
|
||||
end
|
||||
end
|
||||
end
|
||||
return oLine
|
||||
end
|
||||
|
||||
function page:eventHandler(event)
|
||||
|
||||
if event.type == 'global' then
|
||||
resultsPage:setPrompt('', true)
|
||||
self:setPrompt('', true)
|
||||
self:executeStatement('getfenv(0)')
|
||||
command = nil
|
||||
|
||||
elseif event.type == 'local' then
|
||||
resultsPage:setPrompt('', true)
|
||||
self:setPrompt('', true)
|
||||
self:executeStatement('getfenv(1)')
|
||||
command = nil
|
||||
|
||||
elseif event.type == 'autocomplete' then
|
||||
local sz = #self.prompt.value
|
||||
local pos = self.prompt.pos
|
||||
self:setPrompt(autocomplete(sandboxEnv, self.prompt.value, self.prompt.pos))
|
||||
self.prompt:setPosition(pos + #self.prompt.value - sz)
|
||||
self.prompt:updateCursor()
|
||||
|
||||
elseif event.type == 'device' then
|
||||
resultsPage:setPrompt('device', true)
|
||||
self:setPrompt('device', true)
|
||||
self:executeStatement('device')
|
||||
|
||||
elseif event.type == 'history_back' then
|
||||
@ -128,7 +178,7 @@ function resultsPage:eventHandler(event)
|
||||
return true
|
||||
end
|
||||
|
||||
function resultsPage:setResult(result)
|
||||
function page:setResult(result)
|
||||
local t = { }
|
||||
|
||||
local function safeValue(v)
|
||||
@ -169,7 +219,7 @@ function resultsPage:setResult(result)
|
||||
self:draw()
|
||||
end
|
||||
|
||||
function resultsPage.grid:eventHandler(event)
|
||||
function page.grid:eventHandler(event)
|
||||
|
||||
local entry = self:getSelected()
|
||||
|
||||
@ -199,18 +249,18 @@ function resultsPage.grid:eventHandler(event)
|
||||
|
||||
if event.type == 'grid_focus_row' then
|
||||
if self.focused then
|
||||
resultsPage:setPrompt(commandAppend())
|
||||
page:setPrompt(commandAppend())
|
||||
end
|
||||
elseif event.type == 'grid_select' then
|
||||
resultsPage:setPrompt(commandAppend(), true)
|
||||
resultsPage:executeStatement(commandAppend())
|
||||
page:setPrompt(commandAppend(), true)
|
||||
page:executeStatement(commandAppend())
|
||||
else
|
||||
return UI.Grid.eventHandler(self, event)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function resultsPage:rawExecute(s)
|
||||
function page:rawExecute(s)
|
||||
|
||||
local fn, m = loadstring("return (" .. s .. ')', 'lua')
|
||||
if not fn then
|
||||
@ -225,7 +275,7 @@ function resultsPage:rawExecute(s)
|
||||
return fn, m
|
||||
end
|
||||
|
||||
function resultsPage:executeStatement(statement)
|
||||
function page:executeStatement(statement)
|
||||
|
||||
command = statement
|
||||
|
||||
@ -233,6 +283,8 @@ function resultsPage:executeStatement(statement)
|
||||
|
||||
if s and m then
|
||||
self:setResult(m)
|
||||
elseif s and type(m) == 'boolean' then
|
||||
self:setResult(m)
|
||||
else
|
||||
self.grid:setValues({ })
|
||||
self.grid:draw()
|
||||
@ -242,6 +294,13 @@ function resultsPage:executeStatement(statement)
|
||||
end
|
||||
end
|
||||
|
||||
UI:setPage(resultsPage)
|
||||
local args = { ... }
|
||||
if args[1] then
|
||||
command = 'args[1]'
|
||||
sandboxEnv.args = args
|
||||
page:setResult(args[1])
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
Event.pullEvents()
|
||||
UI.term:reset()
|
||||
|
@ -7,37 +7,37 @@ multishell.setTitle(multishell.getCurrent(), 'Network')
|
||||
UI:configure('Network', ...)
|
||||
|
||||
local gridColumns = {
|
||||
{ heading = 'Label', key = 'label' },
|
||||
{ heading = 'Dist', key = 'distance' },
|
||||
{ heading = 'Status', key = 'status' },
|
||||
{ heading = 'Label', key = 'label' },
|
||||
{ heading = 'Dist', key = 'distance' },
|
||||
{ heading = 'Status', key = 'status' },
|
||||
}
|
||||
|
||||
if UI.term.width >= 30 then
|
||||
table.insert(gridColumns, { heading = 'Fuel', key = 'fuel' })
|
||||
table.insert(gridColumns, { heading = 'Fuel', key = 'fuel' })
|
||||
table.insert(gridColumns, { heading = 'Uptime', key = 'uptime' })
|
||||
end
|
||||
|
||||
local page = UI.Page({
|
||||
menuBar = UI.MenuBar({
|
||||
local page = UI.Page {
|
||||
menuBar = UI.MenuBar {
|
||||
buttons = {
|
||||
{ text = 'Telnet', event = 'telnet' },
|
||||
{ text = 'VNC', event = 'vnc' },
|
||||
{ text = 'Reboot', event = 'reboot' },
|
||||
},
|
||||
}),
|
||||
grid = UI.ScrollingGrid({
|
||||
},
|
||||
grid = UI.ScrollingGrid {
|
||||
y = 2,
|
||||
values = network,
|
||||
columns = gridColumns,
|
||||
sortColumn = 'label',
|
||||
autospace = true,
|
||||
}),
|
||||
notification = UI.Notification(),
|
||||
},
|
||||
notification = UI.Notification { },
|
||||
accelerators = {
|
||||
q = 'quit',
|
||||
c = 'clear',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function sendCommand(host, command)
|
||||
|
||||
@ -60,7 +60,7 @@ function sendCommand(host, command)
|
||||
end
|
||||
|
||||
function page:eventHandler(event)
|
||||
local t = self.grid.selected
|
||||
local t = self.grid:getSelected()
|
||||
if t then
|
||||
if event.type == 'telnet' or event.type == 'grid_select' then
|
||||
multishell.openTab({
|
||||
@ -113,22 +113,14 @@ function page.grid:getDisplayValues(row)
|
||||
return row
|
||||
end
|
||||
|
||||
function page.grid:draw()
|
||||
self:adjustWidth()
|
||||
UI.Grid.draw(self)
|
||||
if page.notification.enabled then
|
||||
page.notification:draw()
|
||||
end
|
||||
end
|
||||
|
||||
function updateComputers()
|
||||
Event.addThread(function()
|
||||
while true do
|
||||
page.grid:update()
|
||||
page.grid:draw()
|
||||
page:sync()
|
||||
os.sleep(1)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Event.addHandler('device_attach', function(h, deviceName)
|
||||
if deviceName == 'wireless_modem' then
|
||||
@ -149,5 +141,5 @@ if not device.wireless_modem then
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
Event.pullEvents(updateComputers)
|
||||
Event.pullEvents()
|
||||
UI.term:reset()
|
||||
|
@ -6,6 +6,7 @@ local Config = require('config')
|
||||
local NFT = require('nft')
|
||||
local class = require('class')
|
||||
local FileUI = require('fileui')
|
||||
local Tween = require('tween')
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Overview')
|
||||
UI:configure('Overview', ...)
|
||||
@ -190,8 +191,9 @@ function page.container:setCategory(categoryName)
|
||||
|
||||
-- reposition all children
|
||||
for k,child in ipairs(self.children) do
|
||||
child.x = col
|
||||
child.y = row
|
||||
child.x = -10
|
||||
child.y = math.floor(self.height)
|
||||
child.tween = Tween.new(6, child, { x = col, y = row }, 'outSine')
|
||||
|
||||
if k < count then
|
||||
col = col + child.width
|
||||
@ -203,6 +205,25 @@ function page.container:setCategory(categoryName)
|
||||
end
|
||||
|
||||
self:initChildren()
|
||||
self.animate = true
|
||||
end
|
||||
|
||||
function page.container:draw()
|
||||
if self.animate then
|
||||
self.animate = false
|
||||
for i = 1, 6 do
|
||||
for _,child in ipairs(self.children) do
|
||||
child.tween:update(1)
|
||||
child.x = math.floor(child.x)
|
||||
child.y = math.floor(child.y)
|
||||
end
|
||||
UI.ViewportWindow.draw(self)
|
||||
self:sync()
|
||||
os.sleep()
|
||||
end
|
||||
else
|
||||
UI.ViewportWindow.draw(self)
|
||||
end
|
||||
end
|
||||
|
||||
function page:refresh()
|
||||
@ -223,6 +244,8 @@ function page:eventHandler(event)
|
||||
self.tabBar:selectTab(event.button.text)
|
||||
self.container:setCategory(event.button.text)
|
||||
self.container:draw()
|
||||
self:sync()
|
||||
|
||||
config.currentCategory = event.button.text
|
||||
Config.update('Overview', config)
|
||||
|
||||
@ -263,9 +286,9 @@ function page:eventHandler(event)
|
||||
|
||||
elseif event.type == 'tab_change' then
|
||||
if event.current > event.last then
|
||||
self.container:setTransition('left')
|
||||
--self.container:setTransition(UI.effect.slideLeft)
|
||||
else
|
||||
self.container:setTransition('right')
|
||||
--self.container:setTransition(UI.effect.slideRight)
|
||||
end
|
||||
|
||||
elseif event.type == 'refresh' then
|
||||
@ -308,61 +331,53 @@ function page:eventHandler(event)
|
||||
end
|
||||
|
||||
local formWidth = math.max(UI.term.width - 14, 26)
|
||||
local gutter = math.floor((UI.term.width - formWidth) / 2) + 1
|
||||
|
||||
local editor = UI.Page({
|
||||
backgroundColor = colors.blue,
|
||||
form = UI.Form({
|
||||
fields = {
|
||||
{ label = 'Title', key = 'title', width = 15, 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 = 15, limit = 11, display = UI.Form.D.entry,
|
||||
help = 'Category of application' },
|
||||
{ text = 'Accept', event = 'accept', display = UI.Form.D.button,
|
||||
x = 1, y = 9, width = 10 },
|
||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||
x = formWidth - 11, y = 9, width = 10 },
|
||||
},
|
||||
labelWidth = 8,
|
||||
x = gutter + 1,
|
||||
y = math.max(2, math.floor((UI.term.height - 9) / 2)),
|
||||
local editor = UI.Dialog {
|
||||
height = 11,
|
||||
width = formWidth,
|
||||
title = 'Edit application',
|
||||
form = UI.Form {
|
||||
y = 2,
|
||||
height = 9,
|
||||
width = UI.term.width - (gutter * 2),
|
||||
image = UI.NftImage({
|
||||
y = 5,
|
||||
x = 1,
|
||||
title = UI.TextEntry {
|
||||
formLabel = 'Title', formKey = 'title', limit = 11, help = 'Application title',
|
||||
required = true,
|
||||
},
|
||||
run = UI.TextEntry {
|
||||
formLabel = 'Run', formKey = 'run', limit = 100, help = 'Full path to application',
|
||||
required = true,
|
||||
},
|
||||
category = UI.TextEntry {
|
||||
formLabel = 'Category', formKey = 'category', limit = 11, help = 'Category of application',
|
||||
required = true,
|
||||
},
|
||||
loadIcon = UI.Button {
|
||||
x = 11, y = 6,
|
||||
text = 'Icon', event = 'loadIcon', help = 'Select icon'
|
||||
},
|
||||
image = UI.NftImage {
|
||||
y = 6,
|
||||
x = 2,
|
||||
height = 3,
|
||||
width = 8,
|
||||
}),
|
||||
button = UI.Button({
|
||||
x = 10,
|
||||
y = 6,
|
||||
text = 'Load icon',
|
||||
width = 11,
|
||||
event = 'loadIcon',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
statusBar = UI.StatusBar(),
|
||||
notification = UI.Notification(),
|
||||
iconFile = '',
|
||||
})
|
||||
}
|
||||
|
||||
function editor:enable(app)
|
||||
if app then
|
||||
self.original = app
|
||||
self.form:setValues(Util.shallowCopy(app))
|
||||
self.form:setValues(app)
|
||||
|
||||
local icon
|
||||
if app.icon then
|
||||
icon = parseIcon(app.icon)
|
||||
end
|
||||
self.form.image:setImage(icon)
|
||||
|
||||
self:setFocus(self.form.children[1])
|
||||
end
|
||||
UI.Page.enable(self)
|
||||
self:focusFirst()
|
||||
end
|
||||
|
||||
function editor.form.image:draw()
|
||||
@ -370,11 +385,11 @@ function editor.form.image:draw()
|
||||
UI.NftImage.draw(self)
|
||||
end
|
||||
|
||||
function editor:updateApplications(app, original)
|
||||
if original.run then
|
||||
local _,k = Util.find(applications, 'run', original.run)
|
||||
if k then
|
||||
function editor:updateApplications(app)
|
||||
for k,v in pairs(applications) do
|
||||
if v == app then
|
||||
applications[k] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert(applications, app)
|
||||
@ -383,7 +398,7 @@ end
|
||||
|
||||
function editor:eventHandler(event)
|
||||
|
||||
if event.type == 'cancel' then
|
||||
if event.type == 'form_cancel' or event.type == 'cancel' then
|
||||
UI:setPreviousPage()
|
||||
|
||||
elseif event.type == 'focus_change' then
|
||||
@ -391,7 +406,15 @@ function editor:eventHandler(event)
|
||||
self.statusBar:draw()
|
||||
|
||||
elseif event.type == 'loadIcon' then
|
||||
UI:setPage(FileUI(), fs.getDir(self.iconFile), function(fileName)
|
||||
local fileui = FileUI({
|
||||
x = self.x,
|
||||
y = self.y,
|
||||
z = 2,
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
})
|
||||
--fileui:setTransition(UI.effect.explode)
|
||||
UI:setPage(fileui, fs.getDir(self.iconFile), function(fileName)
|
||||
if fileName then
|
||||
self.iconFile = fileName
|
||||
local s, m = pcall(function()
|
||||
@ -408,23 +431,21 @@ function editor:eventHandler(event)
|
||||
self.form.image:draw()
|
||||
end)
|
||||
if not s and m then
|
||||
self.notification:error(m:gsub('.*: (.*)', '%1'))
|
||||
local msg = m:gsub('.*: (.*)', '%1')
|
||||
page.notification:error(msg)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
elseif event.type == 'accept' then
|
||||
elseif event.type == 'form_invalid' then
|
||||
page.notification:error(event.message)
|
||||
|
||||
elseif event.type == 'form_complete' then
|
||||
local values = self.form.values
|
||||
if #values.run > 0 and #values.title > 0 and #values.category > 0 then
|
||||
UI:setPreviousPage()
|
||||
self:updateApplications(values, self.original)
|
||||
page:refresh()
|
||||
page:draw()
|
||||
else
|
||||
self.notification:error('Require fields missing')
|
||||
--self.statusBar:setStatus('Require fields missing')
|
||||
--self.statusBar:draw()
|
||||
end
|
||||
UI:setPreviousPage()
|
||||
self:updateApplications(values)
|
||||
page:refresh()
|
||||
page:draw()
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end
|
||||
|
@ -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 Event = require('event')
|
||||
local UI = require('ui')
|
||||
|
@ -8,7 +8,7 @@ local GROUPS_PATH = '/apps/groups'
|
||||
local SCRIPTS_PATH = '/apps/scripts'
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Script')
|
||||
UI:configure('Script', ...)
|
||||
UI:configure('script', ...)
|
||||
|
||||
local config = {
|
||||
showGroups = false,
|
||||
@ -17,7 +17,7 @@ local config = {
|
||||
}]],
|
||||
}
|
||||
|
||||
Config.load('Script', config)
|
||||
Config.load('script', config)
|
||||
|
||||
local width = math.floor(UI.term.width / 2) - 1
|
||||
if UI.term.width % 2 ~= 0 then
|
||||
@ -453,7 +453,7 @@ function mainPage:eventHandler(event)
|
||||
-- self.statusBar.toggleButton.text = text
|
||||
self:draw()
|
||||
|
||||
Config.update('Script', config)
|
||||
Config.update('script', config)
|
||||
|
||||
elseif event.type == 'grid_focus_row' then
|
||||
local computer = self.computers:getSelected()
|
||||
|
@ -75,7 +75,7 @@ local systemPage = UI.Page {
|
||||
value = 'Label'
|
||||
},
|
||||
label = UI.TextEntry {
|
||||
x = 9, y = 2, rex = -12,
|
||||
x = 9, y = 2, rex = -4,
|
||||
limit = 32,
|
||||
value = os.getComputerLabel(),
|
||||
backgroundFocusColor = colors.black,
|
||||
|
@ -62,11 +62,6 @@ function page.grid:getDisplayValues(row)
|
||||
return row
|
||||
end
|
||||
|
||||
function page.grid:draw()
|
||||
self:adjustWidth()
|
||||
UI.Grid.draw(self)
|
||||
end
|
||||
|
||||
Event.addTimer(1, true, function()
|
||||
page.grid:update()
|
||||
page.grid:draw()
|
||||
|
@ -33,6 +33,12 @@ local clipboard = { size, internal }
|
||||
local searchPattern
|
||||
local undo = { chain = { }, pointer = 0 }
|
||||
|
||||
if _G.__CLIPBOARD then
|
||||
clipboard = _G.__CLIPBOARD
|
||||
else
|
||||
_G.__CLIPBOARD = clipboard
|
||||
end
|
||||
|
||||
local color = {
|
||||
textColor = '0',
|
||||
keywordColor = '4',
|
||||
@ -66,7 +72,7 @@ local keyMapping = {
|
||||
pageUp = 'pageUp',
|
||||
[ 'control-b' ] = 'pageUp',
|
||||
pageDown = 'pageDown',
|
||||
[ 'control-f' ] = 'pageDown',
|
||||
-- [ 'control-f' ] = 'pageDown',
|
||||
home = 'home',
|
||||
[ 'end' ] = 'toend',
|
||||
[ 'control-home' ] = 'top',
|
||||
@ -101,6 +107,7 @@ local keyMapping = {
|
||||
paste = 'paste',
|
||||
tab = 'tab',
|
||||
[ 'control-z' ] = 'undo',
|
||||
[ 'control-space' ] = 'autocomplete',
|
||||
|
||||
-- copy/paste
|
||||
[ 'control-x' ] = 'cut',
|
||||
@ -114,6 +121,7 @@ local keyMapping = {
|
||||
[ 'control-enter' ] = 'run',
|
||||
|
||||
-- search
|
||||
[ 'control-f' ] = 'find_prompt',
|
||||
[ 'control-slash' ] = 'find_prompt',
|
||||
[ 'control-n' ] = 'find_next',
|
||||
|
||||
@ -476,6 +484,41 @@ local __actions = {
|
||||
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()
|
||||
actions.dirty_all()
|
||||
mark.continue = mark.active
|
||||
@ -528,7 +571,7 @@ local __actions = {
|
||||
find_prompt = function()
|
||||
local text = actions.input('/')
|
||||
if #text > 0 then
|
||||
searchPattern = text
|
||||
searchPattern = text:lower()
|
||||
if searchPattern then
|
||||
actions.unmark()
|
||||
actions.find(searchPattern, x)
|
||||
|
@ -14,12 +14,17 @@ local version = "Version 1.1.6"
|
||||
-- Original code by Bomb Bloke
|
||||
-- Modified to integrate with opus os
|
||||
|
||||
local calls, recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput, callCount, callListCount = {{["delay"] = 0}}, {}, Util.shallowCopy(multishell.term), {...}, false, false, 2, "", 1, 2
|
||||
local curBlink, oldBlink, curCalls, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, calls[1], {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, term.getSize()
|
||||
local recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput = {}, Util.shallowCopy(multishell.term), {...}, false, false, 2, ""
|
||||
local curBlink, oldBlink, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, oldTerm.getSize()
|
||||
local greys, buttons = {["0"] = true, ["7"] = true, ["8"] = true, ["f"] = true}, {"l", "r", "m"}
|
||||
local charW, charH, chars, resp
|
||||
local filename
|
||||
|
||||
local calls = { }
|
||||
local curCalls = { delay = 0 }
|
||||
local callListCount = 0
|
||||
local callCount = 0
|
||||
|
||||
local function showSyntax()
|
||||
print('Gif Recorder by Bomb Bloke\n')
|
||||
print('Syntax: recGif [-i] [-s] [-ld:<delay>] filename')
|
||||
@ -123,13 +128,14 @@ recTerm = multishell.term
|
||||
|
||||
for key, func in pairs(oldTerm) do
|
||||
recTerm[key] = function(...)
|
||||
local result = {pcall(func, ...)}
|
||||
local result = { func(...) }
|
||||
|
||||
if result[1] then
|
||||
curCalls[callCount] = {key, ...}
|
||||
callCount = callCount + 1
|
||||
return unpack(result, 2)
|
||||
else error(result[2], 2) end
|
||||
if callCount == 0 then
|
||||
os.queueEvent('capture_frame')
|
||||
end
|
||||
callCount = callCount + 1
|
||||
curCalls[callCount] = { key, ... }
|
||||
return unpack(result)
|
||||
end
|
||||
end
|
||||
|
||||
@ -149,36 +155,27 @@ for _,tab in pairs(tabs) do
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local curTime = os.clock() - 1
|
||||
local curTime = os.clock() - 1
|
||||
|
||||
while true do
|
||||
local event = { os.pullEventRaw() }
|
||||
while true do
|
||||
local event = { os.pullEventRaw() }
|
||||
|
||||
if event[1] == 'recorder_stop' or event[1] == 'terminate' then
|
||||
break
|
||||
end
|
||||
if event[1] == 'recorder_stop' or event[1] == 'terminate' then
|
||||
break
|
||||
end
|
||||
|
||||
if event[1] == 'capture_frame' then
|
||||
local newTime = os.clock()
|
||||
|
||||
if newTime ~= curTime then
|
||||
local delay = curCalls.delay + (newTime - curTime)
|
||||
curTime = newTime
|
||||
|
||||
if callCount > 1 then
|
||||
curCalls.delay = curCalls.delay + delay
|
||||
curCalls, callCount = {["delay"] = 0}, 1
|
||||
calls[callListCount] = curCalls
|
||||
callListCount = callListCount + 1
|
||||
elseif callListCount > 2 then
|
||||
calls[callListCount - 2].delay = calls[callListCount - 2].delay + delay
|
||||
end
|
||||
if callListCount > 0 then
|
||||
calls[callListCount].delay = (newTime - curTime)
|
||||
end
|
||||
|
||||
if showInput and (event[1] == "key" or event[1] == "mouse_click") then
|
||||
curCalls[callCount] = {unpack(event)}
|
||||
callCount = callCount + 1
|
||||
end
|
||||
curTime = newTime
|
||||
callListCount = callListCount + 1
|
||||
calls[callListCount] = curCalls
|
||||
|
||||
curCalls, callCount = { delay = 0 }, 0
|
||||
end
|
||||
end
|
||||
|
||||
@ -196,8 +193,6 @@ if skipLast and #calls > 1 then calls[#calls] = nil end
|
||||
|
||||
calls[#calls].delay = lastDelay
|
||||
|
||||
-- Recording done, bug user as to whether to encode it:
|
||||
|
||||
print(string.format("Encoding %d frames...", #calls))
|
||||
--Util.writeTable('tmp/raw.txt', calls)
|
||||
|
||||
@ -463,7 +458,14 @@ for i = 1, #calls do
|
||||
|
||||
oldBlink, oldXPos, oldYPos = curBlink, xPos, yPos
|
||||
|
||||
local thisFrame = {["xstart"] = (xMin - 1) * charW, ["ystart"] = (yMin - 1) * charH, ["xend"] = (xMax - xMin + 1) * charW, ["yend"] = (yMax - yMin + 1) * charH, ["delay"] = curCalls.delay, ["disposal"] = 1}
|
||||
local thisFrame = {
|
||||
["xstart"] = (xMin - 1) * charW,
|
||||
["ystart"] = (yMin - 1) * charH,
|
||||
["xend"] = (xMax - xMin + 1) * charW,
|
||||
["yend"] = (yMax - yMin + 1) * charH,
|
||||
["delay"] = curCalls.delay,
|
||||
["disposal"] = 1
|
||||
}
|
||||
|
||||
for y = 1, (yMax - yMin + 1) * charH do
|
||||
local row = {}
|
||||
@ -515,7 +517,11 @@ for i = 1, #calls do
|
||||
snooze()
|
||||
end
|
||||
|
||||
if changed then image[#image + 1] = thisFrame else image[#image].delay = image[#image].delay + curCalls.delay end
|
||||
if changed then
|
||||
image[#image + 1] = thisFrame
|
||||
else
|
||||
image[#image].delay = image[#image].delay + curCalls.delay
|
||||
end
|
||||
end
|
||||
|
||||
buffer = nil
|
||||
|
@ -212,7 +212,7 @@ function enderChestUnload()
|
||||
|
||||
turtle.select(1)
|
||||
turtle.drop(64)
|
||||
turtle.digDown()
|
||||
turtle.digDown()
|
||||
end
|
||||
end
|
||||
|
||||
@ -246,8 +246,9 @@ function makeWalkableTunnel(action, tpt, pt)
|
||||
if action ~= 'turn' and not Point.compare(tpt, { x = 0, z = 0 }) then -- not at source
|
||||
if not Point.compare(tpt, pt) then -- not at dest
|
||||
local r, block = turtle.inspectUp()
|
||||
if r and block.name ~= 'minecraft:cobblestone' then
|
||||
if block.name ~= 'minecraft:chest' then
|
||||
if r and not turtle.isTurtleAtSide('top') then
|
||||
if block.name ~= 'minecraft:cobblestone' and
|
||||
block.name ~= 'minecraft:chest' then
|
||||
turtle.digUp()
|
||||
end
|
||||
end
|
||||
@ -483,7 +484,10 @@ function boreCommand()
|
||||
|
||||
turtle.clearMoveCallback()
|
||||
|
||||
-- location is either mined, currently being mined or is the
|
||||
-- dropoff point for a turtle
|
||||
if inspect(turtle.getAction('up'), 'minecraft:cobblestone') or
|
||||
inspect(turtle.getAction('up'), 'minecraft:chest') or
|
||||
inspect(turtle.getAction('down'), 'minecraft:cobblestone') then
|
||||
return true
|
||||
end
|
||||
|
@ -452,51 +452,54 @@ function watchResources(items)
|
||||
return itemList
|
||||
end
|
||||
|
||||
itemPage = UI.Page({
|
||||
itemPage = UI.Page {
|
||||
backgroundColor = colors.lightGray,
|
||||
titleBar = UI.TitleBar({
|
||||
titleBar = UI.TitleBar {
|
||||
title = 'Limit Resource',
|
||||
previousPage = true,
|
||||
event = 'form_cancel',
|
||||
backgroundColor = colors.green
|
||||
}),
|
||||
idField = UI.Text({
|
||||
x = 5,
|
||||
y = 3,
|
||||
width = UI.term.width - 10
|
||||
}),
|
||||
form = UI.Form({
|
||||
fields = {
|
||||
{ label = 'Min', key = 'low', width = 7, display = UI.Form.D.entry,
|
||||
help = 'Craft if below min' },
|
||||
{ label = 'Max', key = 'limit', width = 7, display = UI.Form.D.entry,
|
||||
validation = UI.Form.V.number, dataType = UI.Form.T.number,
|
||||
help = 'Eject if above max' },
|
||||
{ label = 'Autocraft', key = 'auto', width = 7, display = UI.Form.D.chooser,
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Craft until out of ingredients' },
|
||||
{ label = 'Ignore Dmg', key = 'ignore_dmg', width = 7, display = UI.Form.D.chooser,
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Ignore damage of item' },
|
||||
{ text = 'Accept', event = 'accept', display = UI.Form.D.button,
|
||||
x = 1, y = 6, width = 10 },
|
||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||
x = 21, y = 6, width = 10 },
|
||||
},
|
||||
idField = UI.Text {
|
||||
x = 5, y = 3, width = UI.term.width - 10,
|
||||
},
|
||||
form = UI.Form {
|
||||
x = 4, y = 4, height = 8, rex = -4,
|
||||
[1] = UI.TextEntry {
|
||||
width = 7,
|
||||
backgroundColor = colors.gray,
|
||||
backgroundFocusColor = colors.gray,
|
||||
formLabel = 'Min', formKey = 'low', help = 'Craft if below min'
|
||||
},
|
||||
labelWidth = 10,
|
||||
x = 5,
|
||||
y = 5,
|
||||
height = 6
|
||||
}),
|
||||
statusBar = UI.StatusBar()
|
||||
})
|
||||
[2] = UI.TextEntry {
|
||||
width = 7,
|
||||
backgroundColor = colors.gray,
|
||||
backgroundFocusColor = colors.gray,
|
||||
formLabel = 'Max', formKey = 'limit', help = 'Eject if above max'
|
||||
},
|
||||
[3] = UI.Chooser {
|
||||
width = 7,
|
||||
formLabel = 'Autocraft', formKey = 'auto',
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Craft until out of ingredients'
|
||||
},
|
||||
[4] = UI.Chooser {
|
||||
width = 7,
|
||||
formLabel = 'Ignore Dmg', formKey = 'ignore_dmg',
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Ignore damage of item'
|
||||
},
|
||||
},
|
||||
statusBar = UI.StatusBar { }
|
||||
}
|
||||
|
||||
function itemPage:enable()
|
||||
UI.Page.enable(self)
|
||||
@ -504,12 +507,14 @@ function itemPage:enable()
|
||||
end
|
||||
|
||||
function itemPage:eventHandler(event)
|
||||
if event.type == 'cancel' then
|
||||
if event.type == 'form_cancel' then
|
||||
UI:setPreviousPage()
|
||||
|
||||
elseif event.type == 'focus_change' then
|
||||
self.statusBar:setStatus(event.focused.help)
|
||||
self.statusBar:draw()
|
||||
elseif event.type == 'accept' then
|
||||
|
||||
elseif event.type == 'form_complete' then
|
||||
local values = self.form.values
|
||||
local t = Util.readTable('resource.limits') or { }
|
||||
for k,v in pairs(t) do
|
||||
@ -527,55 +532,52 @@ function itemPage:eventHandler(event)
|
||||
table.insert(t, filtered)
|
||||
Util.writeTable('resource.limits', t)
|
||||
UI:setPreviousPage()
|
||||
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
listingPage = UI.Page({
|
||||
menuBar = UI.MenuBar({
|
||||
listingPage = UI.Page {
|
||||
menuBar = UI.MenuBar {
|
||||
buttons = {
|
||||
{ text = 'Learn', event = 'learn' },
|
||||
{ text = 'Forget', event = 'forget' },
|
||||
},
|
||||
}),
|
||||
grid = UI.Grid({
|
||||
},
|
||||
grid = UI.Grid {
|
||||
y = 2, height = UI.term.height - 2,
|
||||
columns = {
|
||||
{ heading = 'Name', key = 'name' , width = 22 },
|
||||
{ heading = 'Qty', key = 'qty' , width = 5 },
|
||||
{ heading = 'Min', key = 'low' , width = 4 },
|
||||
{ heading = 'Max', key = 'limit', width = 4 },
|
||||
},
|
||||
y = 2,
|
||||
sortColumn = 'name',
|
||||
height = UI.term.height-2,
|
||||
}),
|
||||
statusBar = UI.StatusBar({
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
backgroundColor = colors.gray,
|
||||
width = UI.term.width,
|
||||
filterText = UI.Text({
|
||||
filterText = UI.Text {
|
||||
x = 2, width = 6,
|
||||
value = 'Filter',
|
||||
x = 2,
|
||||
width = 6,
|
||||
}),
|
||||
filter = UI.TextEntry({
|
||||
width = 19,
|
||||
},
|
||||
filter = UI.TextEntry {
|
||||
x = 9, width = 19,
|
||||
limit = 50,
|
||||
x = 9,
|
||||
}),
|
||||
refresh = UI.Button({
|
||||
},
|
||||
refresh = UI.Button {
|
||||
x = 31, width = 8,
|
||||
text = 'Refresh',
|
||||
event = 'refresh',
|
||||
x = 31,
|
||||
width = 8
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
accelerators = {
|
||||
r = 'refresh',
|
||||
q = 'quit',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function listingPage.grid:getRowTextColor(row, selected)
|
||||
if row.is_craftable then
|
||||
@ -622,24 +624,26 @@ end
|
||||
function listingPage:eventHandler(event)
|
||||
if event.type == 'quit' then
|
||||
Event.exitPullEvents()
|
||||
|
||||
elseif event.type == 'grid_select' then
|
||||
local selected = event.selected
|
||||
itemPage.form:setValues(selected)
|
||||
itemPage.titleBar.title = selected.name
|
||||
itemPage.idField.value = selected.id
|
||||
UI:setPage('item')
|
||||
|
||||
elseif event.type == 'refresh' then
|
||||
self:refresh()
|
||||
self.grid:draw()
|
||||
|
||||
elseif event.type == 'learn' then
|
||||
if not duckAntenna then
|
||||
self.statusBar:timedStatus('Missing peripherals', 3)
|
||||
else
|
||||
UI:getPage('craft').form:setValues( { ignore_dmg = 'no' } )
|
||||
UI:setPage('craft')
|
||||
end
|
||||
elseif event.type == 'forget' then
|
||||
|
||||
elseif event.type == 'forget' then
|
||||
local item = self.grid:getSelected()
|
||||
if item then
|
||||
local recipes = Util.readTable('recipes') or { }
|
||||
@ -673,6 +677,7 @@ function listingPage:eventHandler(event)
|
||||
self:applyFilter()
|
||||
self.grid:draw()
|
||||
self.statusBar.filter:focus()
|
||||
|
||||
else
|
||||
UI.Page.eventHandler(self, event)
|
||||
end
|
||||
@ -747,7 +752,7 @@ local function filter(t, filter)
|
||||
end
|
||||
end
|
||||
|
||||
local function learnRecipe(page, ignore_dmg)
|
||||
local function learnRecipe(page)
|
||||
local t = Util.readTable('recipes') or { }
|
||||
local recipe = { }
|
||||
local ingredients = duckAntenna.getAllStacks(false) -- getTurtleInventory()
|
||||
@ -773,7 +778,7 @@ local function learnRecipe(page, ignore_dmg)
|
||||
end
|
||||
end
|
||||
recipe.ingredients = ingredients
|
||||
recipe.ignore_dmg = 'no' -- ignore_dmg
|
||||
recipe.ignore_dmg = 'no'
|
||||
|
||||
t[key] = recipe
|
||||
|
||||
@ -794,69 +799,52 @@ local function learnRecipe(page, ignore_dmg)
|
||||
end
|
||||
end
|
||||
|
||||
craftPage = UI.Page({
|
||||
x = 4,
|
||||
y = math.floor((UI.term.height - 8) / 2) + 1,
|
||||
height = 7,
|
||||
width = UI.term.width - 6,
|
||||
craftPage = UI.Dialog {
|
||||
height = 7, width = UI.term.width - 6,
|
||||
backgroundColor = colors.lightGray,
|
||||
titleBar = UI.TitleBar({
|
||||
titleBar = UI.TitleBar {
|
||||
title = 'Learn Recipe',
|
||||
previousPage = true,
|
||||
}),
|
||||
idField = UI.Text({
|
||||
},
|
||||
idField = UI.Text {
|
||||
x = 5,
|
||||
y = 3,
|
||||
width = UI.term.width - 10,
|
||||
value = 'Place recipe in turtle'
|
||||
}),
|
||||
form = UI.Form({
|
||||
fields = {
|
||||
--[[
|
||||
{ label = 'Ignore Damage', key = 'ignore_dmg', width = 7, display = UI.Form.D.chooser,
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Ignore damage of ingredients' },
|
||||
--]]
|
||||
{ text = 'Accept', event = 'accept', display = UI.Form.D.button,
|
||||
x = 1, y = 1, width = 10 },
|
||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||
x = 16, y = 1, width = 10 },
|
||||
},
|
||||
labelWidth = 13,
|
||||
x = 5,
|
||||
y = 5,
|
||||
height = 2
|
||||
}),
|
||||
statusBar = UI.StatusBar({
|
||||
},
|
||||
accept = UI.Button {
|
||||
rx = -13, ry = -2,
|
||||
text = 'Ok', event = 'accept',
|
||||
},
|
||||
cancel = UI.Button {
|
||||
rx = -8, ry = -2,
|
||||
text = 'Cancel', event = 'cancel'
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
status = 'Crafting paused'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function craftPage:enable()
|
||||
craftingPaused = true
|
||||
self:focusFirst()
|
||||
UI.Page.enable(self)
|
||||
UI.Dialog.enable(self)
|
||||
end
|
||||
|
||||
function craftPage:disable()
|
||||
craftingPaused = false
|
||||
UI.Dialog.disable(self)
|
||||
end
|
||||
|
||||
function craftPage:eventHandler(event)
|
||||
if event.type == 'cancel' then
|
||||
UI:setPreviousPage()
|
||||
elseif event.type == 'accept' then
|
||||
local values = self.form.values
|
||||
|
||||
if learnRecipe(self, values.ignore_dmg) then
|
||||
if learnRecipe(self) then
|
||||
UI:setPreviousPage()
|
||||
end
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
return UI.Dialog.eventHandler(self, event)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
@ -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)
|
||||
turtle.setPoint(pt)
|
||||
turtle.getState().coordSystem = 'GPS'
|
||||
|
||||
if not turtle.pathfind(homePt) then
|
||||
error('Failed to return home')
|
||||
|
@ -1,4 +1,5 @@
|
||||
local Util = require('util')
|
||||
local Process = require('process')
|
||||
|
||||
local Event = {
|
||||
uid = 1, -- unique id for handlers
|
||||
@ -120,13 +121,9 @@ end
|
||||
local exitPullEvents = false
|
||||
|
||||
local function _pullEvents()
|
||||
|
||||
--exitPullEvents = false
|
||||
while true do
|
||||
local e = Event.pullEvent()
|
||||
if exitPullEvents or e == 'terminate' then
|
||||
break
|
||||
end
|
||||
local e = { os.pullEvent() }
|
||||
Event.processEvent(e)
|
||||
end
|
||||
end
|
||||
|
||||
@ -137,12 +134,23 @@ function Event.sleep(t)
|
||||
until event == 'timer' and id == timerId
|
||||
end
|
||||
|
||||
function Event.addThread(fn)
|
||||
return Process:addThread(fn)
|
||||
end
|
||||
|
||||
function Event.pullEvents(...)
|
||||
Process:addThread(_pullEvents)
|
||||
local routines = { ... }
|
||||
if #routines > 0 then
|
||||
parallel.waitForAny(_pullEvents, ...)
|
||||
else
|
||||
_pullEvents()
|
||||
for _, routine in ipairs(routines) do
|
||||
Process:addThread(routine)
|
||||
end
|
||||
end
|
||||
while true do
|
||||
local e = Process:pullEvent()
|
||||
if exitPullEvents or e == 'terminate' then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
local UI = require('ui')
|
||||
|
||||
return function()
|
||||
return function(args)
|
||||
|
||||
local columns = {
|
||||
{ heading = 'Name', key = 'name', width = UI.term.width - 9 },
|
||||
@ -13,18 +13,19 @@ return function()
|
||||
)
|
||||
end
|
||||
|
||||
local selectFile = UI.Page({
|
||||
x = 3,
|
||||
y = 2,
|
||||
rex = -3,
|
||||
rey = -3,
|
||||
args = args or { }
|
||||
|
||||
local selectFile = UI.Dialog {
|
||||
x = args.x or 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,
|
||||
titleBar = UI.TitleBar({
|
||||
title = 'Select file',
|
||||
previousPage = true,
|
||||
event = 'cancel',
|
||||
}),
|
||||
grid = UI.ScrollingGrid({
|
||||
title = 'Select file',
|
||||
grid = UI.ScrollingGrid {
|
||||
x = 2,
|
||||
y = 2,
|
||||
rex = -2,
|
||||
@ -32,8 +33,8 @@ return function()
|
||||
path = '',
|
||||
sortColumn = 'name',
|
||||
columns = columns,
|
||||
}),
|
||||
path = UI.TextEntry({
|
||||
},
|
||||
path = UI.TextEntry {
|
||||
x = 2,
|
||||
ry = -1,
|
||||
rex = -11,
|
||||
@ -41,14 +42,14 @@ return function()
|
||||
accelerators = {
|
||||
enter = 'path_enter',
|
||||
}
|
||||
}),
|
||||
cancel = UI.Button({
|
||||
},
|
||||
cancel = UI.Button {
|
||||
text = 'Cancel',
|
||||
rx = -8,
|
||||
ry = -1,
|
||||
event = 'cancel',
|
||||
}),
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
function selectFile:enable(path, fn)
|
||||
self:setPath(path)
|
||||
|
@ -46,13 +46,13 @@ function urlfs.open(node, fn, fl)
|
||||
synchronized(node.url, function()
|
||||
c = Util.download(node.url)
|
||||
end)
|
||||
if c and #c > 0 then
|
||||
if c then
|
||||
node.cache = c
|
||||
node.size = #c
|
||||
end
|
||||
end
|
||||
|
||||
if not c or #c == 0 then
|
||||
if not c then
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -1,68 +1,164 @@
|
||||
local resolver, loader
|
||||
local DEFAULT_UPATH = 'https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis'
|
||||
local PASTEBIN_URL = 'http://pastebin.com/raw'
|
||||
local GIT_URL = 'https://raw.githubusercontent.com'
|
||||
|
||||
local function resolveFile(filename, dir, lua_path)
|
||||
|
||||
if filename:sub(1, 1) == "/" then
|
||||
if not fs.exists(filename) then
|
||||
error('Unable to load: ' .. filename, 2)
|
||||
local function standardSearcher(modname, env, shell)
|
||||
if package.loaded[modname] then
|
||||
return function()
|
||||
return package.loaded[modname]
|
||||
end
|
||||
return filename
|
||||
end
|
||||
end
|
||||
|
||||
if dir then
|
||||
local path = fs.combine(dir, filename)
|
||||
local function shellSearcher(modname, env, shell)
|
||||
local fname = modname:gsub('%.', '/') .. '.lua'
|
||||
|
||||
if shell and type(shell.dir) == 'function' then
|
||||
local path = shell.resolve(fname)
|
||||
if fs.exists(path) and not fs.isDir(path) then
|
||||
return path
|
||||
return loadfile(path, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if lua_path then
|
||||
for dir in string.gmatch(lua_path, "[^:]+") do
|
||||
local path = fs.combine(dir, filename)
|
||||
if fs.exists(path) and not fs.isDir(path) then
|
||||
return path
|
||||
local function pathSearcher(modname, env, shell)
|
||||
local fname = modname:gsub('%.', '/') .. '.lua'
|
||||
|
||||
for dir in string.gmatch(package.path, "[^:]+") do
|
||||
local path = fs.combine(dir, fname)
|
||||
if fs.exists(path) and not fs.isDir(path) then
|
||||
return loadfile(path, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- fix broken http get
|
||||
local syncLocks = { }
|
||||
|
||||
local function sync(obj, fn)
|
||||
local key = tostring(obj)
|
||||
if syncLocks[key] then
|
||||
local cos = tostring(coroutine.running())
|
||||
table.insert(syncLocks[key], cos)
|
||||
repeat
|
||||
local _, co = os.pullEvent('sync_lock')
|
||||
until co == cos
|
||||
else
|
||||
syncLocks[key] = { }
|
||||
end
|
||||
local s, m = pcall(fn)
|
||||
local co = table.remove(syncLocks[key], 1)
|
||||
if co then
|
||||
os.queueEvent('sync_lock', co)
|
||||
else
|
||||
syncLocks[key] = nil
|
||||
end
|
||||
if not s then
|
||||
error(m)
|
||||
end
|
||||
end
|
||||
|
||||
local function loadUrl(url)
|
||||
local c
|
||||
sync(url, function()
|
||||
local h = http.get(url)
|
||||
if h then
|
||||
c = h.readAll()
|
||||
h.close()
|
||||
end
|
||||
end)
|
||||
if c and #c > 0 then
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
-- require('BniCQPVf')
|
||||
local function pastebinSearcher(modname, env, shell)
|
||||
if #modname == 8 and not modname:match('%W') then
|
||||
local url = PASTEBIN_URL .. '/' .. modname
|
||||
local c = loadUrl(url)
|
||||
if c then
|
||||
return load(c, modname, nil, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- require('kepler155c.opus.master.sys.apis.util')
|
||||
local function gitSearcher(modname, env, shell)
|
||||
local fname = modname:gsub('%.', '/') .. '.lua'
|
||||
local _, count = fname:gsub("/", "")
|
||||
if count >= 3 then
|
||||
local url = GIT_URL .. '/' .. fname
|
||||
local c = loadUrl(url)
|
||||
if c then
|
||||
return load(c, modname, nil, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function urlSearcher(modname, env, shell)
|
||||
local fname = modname:gsub('%.', '/') .. '.lua'
|
||||
|
||||
if fname:sub(1, 1) ~= '/' then
|
||||
for entry in string.gmatch(package.upath, "[^;]+") do
|
||||
local url = entry .. '/' .. fname
|
||||
local c = loadUrl(url)
|
||||
if c then
|
||||
return load(c, modname, nil, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
error('Unable to load: ' .. filename, 2)
|
||||
end
|
||||
|
||||
_G.package = {
|
||||
path = LUA_PATH or 'sys/apis',
|
||||
upath = LUA_UPATH or DEFAULT_UPATH,
|
||||
config = '/\n:\n?\n!\n-',
|
||||
loaded = {
|
||||
math = math,
|
||||
string = string,
|
||||
table = table,
|
||||
io = io,
|
||||
os = os,
|
||||
},
|
||||
loaders = {
|
||||
standardSearcher,
|
||||
shellSearcher,
|
||||
pathSearcher,
|
||||
pastebinSearcher,
|
||||
gitSearcher,
|
||||
urlSearcher,
|
||||
}
|
||||
}
|
||||
|
||||
local function requireWrapper(env)
|
||||
|
||||
local modules = { }
|
||||
local loaded = { }
|
||||
|
||||
return function(filename)
|
||||
return function(modname)
|
||||
|
||||
local dir = DIR
|
||||
if not dir and shell and type(shell.dir) == 'function' then
|
||||
dir = shell.dir()
|
||||
if loaded[modname] then
|
||||
return loaded[modname]
|
||||
end
|
||||
|
||||
local fname = resolver(filename:gsub('%.', '/') .. '.lua',
|
||||
dir or '', LUA_PATH or '/sys/apis')
|
||||
|
||||
local rname = fname:gsub('%/', '.'):gsub('%.lua', '')
|
||||
|
||||
local module = modules[rname]
|
||||
if not module then
|
||||
|
||||
local f, err = loader(fname, env)
|
||||
if not f then
|
||||
error(err)
|
||||
end
|
||||
module = f(rname)
|
||||
modules[rname] = module
|
||||
for _,searcher in ipairs(package.loaders) do
|
||||
local fn, msg = searcher(modname, env, shell)
|
||||
if fn then
|
||||
local module, msg = fn(modname, env)
|
||||
if not module then
|
||||
error(msg)
|
||||
end
|
||||
loaded[modname] = module
|
||||
return module
|
||||
end
|
||||
if msg then
|
||||
error(msg, 2)
|
||||
end
|
||||
end
|
||||
|
||||
return module
|
||||
error('Unable to find module ' .. modname)
|
||||
end
|
||||
end
|
||||
|
||||
local args = { ... }
|
||||
resolver = args[1] or resolveFile
|
||||
loader = args[2] or loadfile
|
||||
|
||||
return function(env)
|
||||
setfenv(requireWrapper, env)
|
||||
return requireWrapper(env)
|
||||
|
@ -27,6 +27,11 @@ function Process:threadEvent(...)
|
||||
end
|
||||
end
|
||||
|
||||
function Process:addThread(fn, ...)
|
||||
return self:newThread(nil, fn, ...)
|
||||
end
|
||||
|
||||
-- deprecated
|
||||
function Process:newThread(name, fn, ...)
|
||||
|
||||
self.uid = self.uid + 1
|
||||
@ -45,7 +50,7 @@ function Process:newThread(name, fn, ...)
|
||||
local s, m = pcall(function() fn(unpack(args)) end)
|
||||
if not s and m then
|
||||
if m == 'Terminated' then
|
||||
printError(thread.name .. ' terminated')
|
||||
--printError(thread.name .. ' terminated')
|
||||
else
|
||||
printError(m)
|
||||
end
|
||||
@ -82,8 +87,11 @@ function Process:resume(event, ...)
|
||||
return true, self.filter
|
||||
end
|
||||
|
||||
function Process:pullEvent(filter)
|
||||
-- confusing...
|
||||
|
||||
-- pull either one event if no filter or until event matches filter
|
||||
-- or until terminated (regardless of filter)
|
||||
function Process:pullEvent(filter)
|
||||
while true do
|
||||
local e = { os.pullEventRaw() }
|
||||
self:threadEvent(unpack(e))
|
||||
@ -94,12 +102,12 @@ function Process:pullEvent(filter)
|
||||
end
|
||||
end
|
||||
|
||||
-- pull events until either the filter is matched or terminated
|
||||
function Process:pullEvents(filter)
|
||||
|
||||
while true do
|
||||
local e = { os.pullEventRaw(filter) }
|
||||
local e = { os.pullEventRaw() }
|
||||
self:threadEvent(unpack(e))
|
||||
if e[1] == 'terminate' then
|
||||
if (filter and e[1] == filter) or e[1] == 'terminate' then
|
||||
return unpack(e)
|
||||
end
|
||||
end
|
||||
|
358
sys/apis/region.lua
Normal file
358
sys/apis/region.lua
Normal file
@ -0,0 +1,358 @@
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- tek.lib.region
|
||||
-- Written by Timm S. Mueller <tmueller at schulze-mueller.de>
|
||||
--
|
||||
-- Copyright 2008 - 2016 by the authors and contributors:
|
||||
--
|
||||
-- * Timm S. Muller <tmueller at schulze-mueller.de>
|
||||
-- * Franciska Schulze <fschulze at schulze-mueller.de>
|
||||
-- * Tobias Schwinger <tschwinger at isonews2.com>
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining
|
||||
-- a copy of this software and associated documentation files (the
|
||||
-- "Software"), to deal in the Software without restriction, including
|
||||
-- without limitation the rights to use, copy, modify, merge, publish,
|
||||
-- distribute, sublicense, and/or sell copies of the Software, and to
|
||||
-- permit persons to whom the Software is furnished to do so, subject to
|
||||
-- the following conditions:
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be
|
||||
-- included in all copies or substantial portions of the Software.
|
||||
--
|
||||
-- === Disclaimer ===
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
--
|
||||
-- OVERVIEW::
|
||||
-- This library implements the management of regions, which are
|
||||
-- collections of non-overlapping rectangles.
|
||||
--
|
||||
-- FUNCTIONS::
|
||||
-- - Region:andRect() - ''And''s a rectangle to a region
|
||||
-- - Region:andRegion() - ''And''s a region to a region
|
||||
-- - Region:checkIntersect() - Checks if a rectangle intersects a region
|
||||
-- - Region:forEach() - Calls a function for each rectangle in a region
|
||||
-- - Region:get() - Get region's min/max extents
|
||||
-- - Region.intersect() - Returns the intersection of two rectangles
|
||||
-- - Region:isEmpty() - Checks if a Region is empty
|
||||
-- - Region.new() - Creates a new Region
|
||||
-- - Region:orRect() - ''Or''s a rectangle to a region
|
||||
-- - Region:orRegion() - ''Or''s a region to a region
|
||||
-- - Region:setRect() - Resets a region to the given rectangle
|
||||
-- - Region:shift() - Displaces a region
|
||||
-- - Region:subRect() - Subtracts a rectangle from a region
|
||||
-- - Region:subRegion() - Subtracts a region from a region
|
||||
-- - Region:xorRect() - ''Exclusive Or''s a rectangle to a region
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local insert = table.insert
|
||||
local ipairs = ipairs
|
||||
local max = math.max
|
||||
local min = math.min
|
||||
local setmetatable = setmetatable
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
local Region = { }
|
||||
Region._VERSION = "Region 11.3"
|
||||
|
||||
Region.__index = Region
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- x0, y0, x1, y1 = Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4):
|
||||
-- Returns the coordinates of a rectangle where a rectangle specified by
|
||||
-- the coordinates s1, s2, s3, s4 overlaps with the rectangle specified
|
||||
-- by the coordinates d1, d2, d3, d4. The return value is '''nil''' if
|
||||
-- the rectangles do not overlap.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||
if s3 >= d1 and s1 <= d3 and s4 >= d2 and s2 <= d4 then
|
||||
return max(s1, d1), max(s2, d2), min(s3, d3), min(s4, d4)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- insertrect: insert rect to table, merging with an existing one if possible
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function insertrect(d, s1, s2, s3, s4)
|
||||
for i = 1, min(4, #d) do
|
||||
local a = d[i]
|
||||
local a1, a2, a3, a4 = a[1], a[2], a[3], a[4]
|
||||
if a2 == s2 and a4 == s4 then
|
||||
if a3 + 1 == s1 then
|
||||
a[3] = s3
|
||||
return
|
||||
elseif a1 == s3 + 1 then
|
||||
a[1] = s1
|
||||
return
|
||||
end
|
||||
elseif a1 == s1 and a3 == s3 then
|
||||
if a4 + 1 == s2 then
|
||||
a[4] = s4
|
||||
return
|
||||
elseif a2 == s4 + 1 then
|
||||
a[2] = s2
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
insert(d, 1, { s1, s2, s3, s4 })
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- cutrect: cut rect d into table of new rects, using rect s as a punch
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function cutrect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||
if not Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4) then
|
||||
return { { d1, d2, d3, d4 } }
|
||||
end
|
||||
local r = { }
|
||||
if d1 < s1 then
|
||||
insertrect(r, d1, d2, s1 - 1, d4)
|
||||
d1 = s1
|
||||
end
|
||||
if d2 < s2 then
|
||||
insertrect(r, d1, d2, d3, s2 - 1)
|
||||
d2 = s2
|
||||
end
|
||||
if d3 > s3 then
|
||||
insertrect(r, s3 + 1, d2, d3, d4)
|
||||
d3 = s3
|
||||
end
|
||||
if d4 > s4 then
|
||||
insertrect(r, d1, s4 + 1, d3, d4)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- cutregion: cut region d, using s as a punch
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function cutregion(d, s1, s2, s3, s4)
|
||||
local r = { }
|
||||
for _, dr in ipairs(d) do
|
||||
local d1, d2, d3, d4 = dr[1], dr[2], dr[3], dr[4]
|
||||
for _, t in ipairs(cutrect(d1, d2, d3, d4, s1, s2, s3, s4)) do
|
||||
insertrect(r, t[1], t[2], t[3], t[4])
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region = Region.new(r1, r2, r3, r4): Creates a new region from the given
|
||||
-- coordinates.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region.new(r1, r2, r3, r4)
|
||||
if r1 then
|
||||
return setmetatable({ region = { { r1, r2, r3, r4 } } }, Region)
|
||||
end
|
||||
return setmetatable({ region = { } }, Region)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- self = region:setRect(r1, r2, r3, r4): Resets an existing region
|
||||
-- to the specified rectangle.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:setRect(r1, r2, r3, r4)
|
||||
self.region = { { r1, r2, r3, r4 } }
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:orRect(r1, r2, r3, r4): Logical ''or''s a rectangle to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:orRect(s1, s2, s3, s4)
|
||||
self.region = cutregion(self.region, s1, s2, s3, s4)
|
||||
insertrect(self.region, s1, s2, s3, s4)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:orRegion(region): Logical ''or''s another region to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:orRegion(s)
|
||||
for _, r in ipairs(s) do
|
||||
self:orRect(r[1], r[2], r[3], r[4])
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:andRect(r1, r2, r3, r4): Logical ''and''s a rectange to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:andRect(s1, s2, s3, s4)
|
||||
local r = { }
|
||||
for _, d in ipairs(self.region) do
|
||||
local t1, t2, t3, t4 =
|
||||
Region.intersect(d[1], d[2], d[3], d[4], s1, s2, s3, s4)
|
||||
if t1 then
|
||||
insertrect(r, t1, t2, t3, t4)
|
||||
end
|
||||
end
|
||||
self.region = r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:xorRect(r1, r2, r3, r4): Logical ''xor''s a rectange to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:xorRect(s1, s2, s3, s4)
|
||||
local r1 = { }
|
||||
local r2 = { { s1, s2, s3, s4 } }
|
||||
for _, d in ipairs(self.region) do
|
||||
local d1, d2, d3, d4 = d[1], d[2], d[3], d[4]
|
||||
for _, t in ipairs(cutrect(d1, d2, d3, d4, s1, s2, s3, s4)) do
|
||||
insertrect(r1, t[1], t[2], t[3], t[4])
|
||||
end
|
||||
r2 = cutregion(r2, d1, d2, d3, d4)
|
||||
end
|
||||
self.region = r1
|
||||
self:orRegion(r2)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- self = region:subRect(r1, r2, r3, r4): Subtracts a rectangle from a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:subRect(s1, s2, s3, s4)
|
||||
local r1 = { }
|
||||
for _, d in ipairs(self.region) do
|
||||
local d1, d2, d3, d4 = d[1], d[2], d[3], d[4]
|
||||
for _, t in ipairs(cutrect(d1, d2, d3, d4, s1, s2, s3, s4)) do
|
||||
insertrect(r1, t[1], t[2], t[3], t[4])
|
||||
end
|
||||
end
|
||||
self.region = r1
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:getRect - gets an iterator on the rectangles in a region [internal]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:getRects()
|
||||
local index = 0
|
||||
return function(object)
|
||||
index = index + 1
|
||||
if object[index] then
|
||||
return unpack(object[index])
|
||||
end
|
||||
end, self.region
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- success = region:checkIntersect(x0, y0, x1, y1): Returns a boolean
|
||||
-- indicating whether a rectangle specified by its coordinates overlaps
|
||||
-- with a region.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:checkIntersect(s1, s2, s3, s4)
|
||||
for _, d in ipairs(self.region) do
|
||||
if Region.intersect(d[1], d[2], d[3], d[4], s1, s2, s3, s4) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:subRegion(region2): Subtracts {{region2}} from {{region}}.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:subRegion(region)
|
||||
if region then
|
||||
for r1, r2, r3, r4 in region:getRects() do
|
||||
self:subRect(r1, r2, r3, r4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:andRegion(r): Logically ''and''s a region to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:andRegion(s)
|
||||
local r = { }
|
||||
for _, s in ipairs(s.region) do
|
||||
for _, d in ipairs(self.region) do
|
||||
local t1, t2, t3, t4 =
|
||||
Region.intersect(d[1], d[2], d[3], d[4],
|
||||
s[1], s[2], s[3], s[4])
|
||||
if t1 then
|
||||
insertrect(r, t1, t2, t3, t4)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.region = r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:forEach(func, obj, ...): For each rectangle in a region, calls the
|
||||
-- specified function according the following scheme:
|
||||
-- func(obj, x0, y0, x1, y1, ...)
|
||||
-- Extra arguments are passed through to the function.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:forEach(func, obj, ...)
|
||||
for x0, y0, x1, y1 in self:getRects() do
|
||||
func(obj, x0, y0, x1, y1, ...)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:shift(dx, dy): Shifts a region by delta x and y.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:shift(dx, dy)
|
||||
for _, r in ipairs(self.region) do
|
||||
r[1] = r[1] + dx
|
||||
r[2] = r[2] + dy
|
||||
r[3] = r[3] + dx
|
||||
r[4] = r[4] + dy
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:isEmpty(): Returns '''true''' if a region is empty.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:isEmpty()
|
||||
return #self.region == 0
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- minx, miny, maxx, maxy = region:get(): Get region's min/max extents
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:get()
|
||||
if #self.region > 0 then
|
||||
local minx = 1000000 -- ui.HUGE
|
||||
local miny = 1000000
|
||||
local maxx = 0
|
||||
local maxy = 0
|
||||
for _, r in ipairs(self.region) do
|
||||
minx = min(minx, r[1])
|
||||
miny = min(miny, r[2])
|
||||
maxx = max(maxx, r[3])
|
||||
maxy = max(maxy, r[4])
|
||||
end
|
||||
return minx, miny, maxx, maxy
|
||||
end
|
||||
end
|
||||
|
||||
return Region
|
@ -120,6 +120,18 @@ function Terminal.toGrayscale(ct)
|
||||
end
|
||||
end
|
||||
|
||||
function Terminal.getNullTerm(ct)
|
||||
local nt = Terminal.copy(ct)
|
||||
|
||||
local methods = { 'blit', 'clear', 'clearLine', 'scroll',
|
||||
'setCursorBlink', 'setCursorPos', 'write' }
|
||||
for _,v in pairs(methods) do
|
||||
nt[v] = function() end
|
||||
end
|
||||
|
||||
return nt
|
||||
end
|
||||
|
||||
function Terminal.copy(ot)
|
||||
local ct = { }
|
||||
for k,v in pairs(ot) do
|
||||
|
367
sys/apis/tween.lua
Normal file
367
sys/apis/tween.lua
Normal file
@ -0,0 +1,367 @@
|
||||
local tween = {
|
||||
_VERSION = 'tween 2.1.1',
|
||||
_DESCRIPTION = 'tweening for lua',
|
||||
_URL = 'https://github.com/kikito/tween.lua',
|
||||
_LICENSE = [[
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2014 Enrique García Cota, Yuichi Tateno, Emmanuel Oga
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
]]
|
||||
}
|
||||
|
||||
-- easing
|
||||
|
||||
-- Adapted from https://github.com/EmmanuelOga/easing. See LICENSE.txt for credits.
|
||||
-- For all easing functions:
|
||||
-- t = time == how much time has to pass for the tweening to complete
|
||||
-- b = begin == starting property value
|
||||
-- c = change == ending - beginning
|
||||
-- d = duration == running time. How much time has passed *right now*
|
||||
|
||||
local pow, sin, cos, pi, sqrt, abs, asin = math.pow, math.sin, math.cos, math.pi, math.sqrt, math.abs, math.asin
|
||||
|
||||
-- linear
|
||||
local function linear(t, b, c, d) return c * t / d + b end
|
||||
|
||||
-- quad
|
||||
local function inQuad(t, b, c, d) return c * pow(t / d, 2) + b end
|
||||
local function outQuad(t, b, c, d)
|
||||
t = t / d
|
||||
return -c * t * (t - 2) + b
|
||||
end
|
||||
local function inOutQuad(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(t, 2) + b end
|
||||
return -c / 2 * ((t - 1) * (t - 3) - 1) + b
|
||||
end
|
||||
local function outInQuad(t, b, c, d)
|
||||
if t < d / 2 then return outQuad(t * 2, b, c / 2, d) end
|
||||
return inQuad((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- cubic
|
||||
local function inCubic (t, b, c, d) return c * pow(t / d, 3) + b end
|
||||
local function outCubic(t, b, c, d) return c * (pow(t / d - 1, 3) + 1) + b end
|
||||
local function inOutCubic(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * t * t * t + b end
|
||||
t = t - 2
|
||||
return c / 2 * (t * t * t + 2) + b
|
||||
end
|
||||
local function outInCubic(t, b, c, d)
|
||||
if t < d / 2 then return outCubic(t * 2, b, c / 2, d) end
|
||||
return inCubic((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- quart
|
||||
local function inQuart(t, b, c, d) return c * pow(t / d, 4) + b end
|
||||
local function outQuart(t, b, c, d) return -c * (pow(t / d - 1, 4) - 1) + b end
|
||||
local function inOutQuart(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(t, 4) + b end
|
||||
return -c / 2 * (pow(t - 2, 4) - 2) + b
|
||||
end
|
||||
local function outInQuart(t, b, c, d)
|
||||
if t < d / 2 then return outQuart(t * 2, b, c / 2, d) end
|
||||
return inQuart((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- quint
|
||||
local function inQuint(t, b, c, d) return c * pow(t / d, 5) + b end
|
||||
local function outQuint(t, b, c, d) return c * (pow(t / d - 1, 5) + 1) + b end
|
||||
local function inOutQuint(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(t, 5) + b end
|
||||
return c / 2 * (pow(t - 2, 5) + 2) + b
|
||||
end
|
||||
local function outInQuint(t, b, c, d)
|
||||
if t < d / 2 then return outQuint(t * 2, b, c / 2, d) end
|
||||
return inQuint((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- sine
|
||||
local function inSine(t, b, c, d) return -c * cos(t / d * (pi / 2)) + c + b end
|
||||
local function outSine(t, b, c, d) return c * sin(t / d * (pi / 2)) + b end
|
||||
local function inOutSine(t, b, c, d) return -c / 2 * (cos(pi * t / d) - 1) + b end
|
||||
local function outInSine(t, b, c, d)
|
||||
if t < d / 2 then return outSine(t * 2, b, c / 2, d) end
|
||||
return inSine((t * 2) -d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- expo
|
||||
local function inExpo(t, b, c, d)
|
||||
if t == 0 then return b end
|
||||
return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001
|
||||
end
|
||||
local function outExpo(t, b, c, d)
|
||||
if t == d then return b + c end
|
||||
return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b
|
||||
end
|
||||
local function inOutExpo(t, b, c, d)
|
||||
if t == 0 then return b end
|
||||
if t == d then return b + c end
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005 end
|
||||
return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b
|
||||
end
|
||||
local function outInExpo(t, b, c, d)
|
||||
if t < d / 2 then return outExpo(t * 2, b, c / 2, d) end
|
||||
return inExpo((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- circ
|
||||
local function inCirc(t, b, c, d) return(-c * (sqrt(1 - pow(t / d, 2)) - 1) + b) end
|
||||
local function outCirc(t, b, c, d) return(c * sqrt(1 - pow(t / d - 1, 2)) + b) end
|
||||
local function inOutCirc(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return -c / 2 * (sqrt(1 - t * t) - 1) + b end
|
||||
t = t - 2
|
||||
return c / 2 * (sqrt(1 - t * t) + 1) + b
|
||||
end
|
||||
local function outInCirc(t, b, c, d)
|
||||
if t < d / 2 then return outCirc(t * 2, b, c / 2, d) end
|
||||
return inCirc((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- elastic
|
||||
local function calculatePAS(p,a,c,d)
|
||||
p, a = p or d * 0.3, a or 0
|
||||
if a < abs(c) then return p, c, p / 4 end -- p, a, s
|
||||
return p, a, p / (2 * pi) * asin(c/a) -- p,a,s
|
||||
end
|
||||
local function inElastic(t, b, c, d, a, p)
|
||||
local s
|
||||
if t == 0 then return b end
|
||||
t = t / d
|
||||
if t == 1 then return b + c end
|
||||
p,a,s = calculatePAS(p,a,c,d)
|
||||
t = t - 1
|
||||
return -(a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
|
||||
end
|
||||
local function outElastic(t, b, c, d, a, p)
|
||||
local s
|
||||
if t == 0 then return b end
|
||||
t = t / d
|
||||
if t == 1 then return b + c end
|
||||
p,a,s = calculatePAS(p,a,c,d)
|
||||
return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b
|
||||
end
|
||||
local function inOutElastic(t, b, c, d, a, p)
|
||||
local s
|
||||
if t == 0 then return b end
|
||||
t = t / d * 2
|
||||
if t == 2 then return b + c end
|
||||
p,a,s = calculatePAS(p,a,c,d)
|
||||
t = t - 1
|
||||
if t < 0 then return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b end
|
||||
return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p ) * 0.5 + c + b
|
||||
end
|
||||
local function outInElastic(t, b, c, d, a, p)
|
||||
if t < d / 2 then return outElastic(t * 2, b, c / 2, d, a, p) end
|
||||
return inElastic((t * 2) - d, b + c / 2, c / 2, d, a, p)
|
||||
end
|
||||
|
||||
-- back
|
||||
local function inBack(t, b, c, d, s)
|
||||
s = s or 1.70158
|
||||
t = t / d
|
||||
return c * t * t * ((s + 1) * t - s) + b
|
||||
end
|
||||
local function outBack(t, b, c, d, s)
|
||||
s = s or 1.70158
|
||||
t = t / d - 1
|
||||
return c * (t * t * ((s + 1) * t + s) + 1) + b
|
||||
end
|
||||
local function inOutBack(t, b, c, d, s)
|
||||
s = (s or 1.70158) * 1.525
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * (t * t * ((s + 1) * t - s)) + b end
|
||||
t = t - 2
|
||||
return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b
|
||||
end
|
||||
local function outInBack(t, b, c, d, s)
|
||||
if t < d / 2 then return outBack(t * 2, b, c / 2, d, s) end
|
||||
return inBack((t * 2) - d, b + c / 2, c / 2, d, s)
|
||||
end
|
||||
|
||||
-- bounce
|
||||
local function outBounce(t, b, c, d)
|
||||
t = t / d
|
||||
if t < 1 / 2.75 then return c * (7.5625 * t * t) + b end
|
||||
if t < 2 / 2.75 then
|
||||
t = t - (1.5 / 2.75)
|
||||
return c * (7.5625 * t * t + 0.75) + b
|
||||
elseif t < 2.5 / 2.75 then
|
||||
t = t - (2.25 / 2.75)
|
||||
return c * (7.5625 * t * t + 0.9375) + b
|
||||
end
|
||||
t = t - (2.625 / 2.75)
|
||||
return c * (7.5625 * t * t + 0.984375) + b
|
||||
end
|
||||
local function inBounce(t, b, c, d) return c - outBounce(d - t, 0, c, d) + b end
|
||||
local function inOutBounce(t, b, c, d)
|
||||
if t < d / 2 then return inBounce(t * 2, 0, c, d) * 0.5 + b end
|
||||
return outBounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b
|
||||
end
|
||||
local function outInBounce(t, b, c, d)
|
||||
if t < d / 2 then return outBounce(t * 2, b, c / 2, d) end
|
||||
return inBounce((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
tween.easing = {
|
||||
linear = linear,
|
||||
inQuad = inQuad, outQuad = outQuad, inOutQuad = inOutQuad, outInQuad = outInQuad,
|
||||
inCubic = inCubic, outCubic = outCubic, inOutCubic = inOutCubic, outInCubic = outInCubic,
|
||||
inQuart = inQuart, outQuart = outQuart, inOutQuart = inOutQuart, outInQuart = outInQuart,
|
||||
inQuint = inQuint, outQuint = outQuint, inOutQuint = inOutQuint, outInQuint = outInQuint,
|
||||
inSine = inSine, outSine = outSine, inOutSine = inOutSine, outInSine = outInSine,
|
||||
inExpo = inExpo, outExpo = outExpo, inOutExpo = inOutExpo, outInExpo = outInExpo,
|
||||
inCirc = inCirc, outCirc = outCirc, inOutCirc = inOutCirc, outInCirc = outInCirc,
|
||||
inElastic = inElastic, outElastic = outElastic, inOutElastic = inOutElastic, outInElastic = outInElastic,
|
||||
inBack = inBack, outBack = outBack, inOutBack = inOutBack, outInBack = outInBack,
|
||||
inBounce = inBounce, outBounce = outBounce, inOutBounce = inOutBounce, outInBounce = outInBounce
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- private stuff
|
||||
|
||||
local function copyTables(destination, keysTable, valuesTable)
|
||||
valuesTable = valuesTable or keysTable
|
||||
local mt = getmetatable(keysTable)
|
||||
if mt and getmetatable(destination) == nil then
|
||||
setmetatable(destination, mt)
|
||||
end
|
||||
for k,v in pairs(keysTable) do
|
||||
if type(v) == 'table' then
|
||||
destination[k] = copyTables({}, v, valuesTable[k])
|
||||
else
|
||||
destination[k] = valuesTable[k]
|
||||
end
|
||||
end
|
||||
return destination
|
||||
end
|
||||
|
||||
local function checkSubjectAndTargetRecursively(subject, target, path)
|
||||
path = path or {}
|
||||
local targetType, newPath
|
||||
for k,targetValue in pairs(target) do
|
||||
targetType, newPath = type(targetValue), copyTables({}, path)
|
||||
table.insert(newPath, tostring(k))
|
||||
if targetType == 'number' then
|
||||
assert(type(subject[k]) == 'number', "Parameter '" .. table.concat(newPath,'/') .. "' is missing from subject or isn't a number")
|
||||
elseif targetType == 'table' then
|
||||
checkSubjectAndTargetRecursively(subject[k], targetValue, newPath)
|
||||
else
|
||||
assert(targetType == 'number', "Parameter '" .. table.concat(newPath,'/') .. "' must be a number or table of numbers")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function checkNewParams(duration, subject, target, easing)
|
||||
assert(type(duration) == 'number' and duration > 0, "duration must be a positive number. Was " .. tostring(duration))
|
||||
local tsubject = type(subject)
|
||||
assert(tsubject == 'table' or tsubject == 'userdata', "subject must be a table or userdata. Was " .. tostring(subject))
|
||||
assert(type(target)== 'table', "target must be a table. Was " .. tostring(target))
|
||||
assert(type(easing)=='function', "easing must be a function. Was " .. tostring(easing))
|
||||
checkSubjectAndTargetRecursively(subject, target)
|
||||
end
|
||||
|
||||
local function getEasingFunction(easing)
|
||||
easing = easing or "linear"
|
||||
if type(easing) == 'string' then
|
||||
local name = easing
|
||||
easing = tween.easing[name]
|
||||
if type(easing) ~= 'function' then
|
||||
error("The easing function name '" .. name .. "' is invalid")
|
||||
end
|
||||
end
|
||||
return easing
|
||||
end
|
||||
|
||||
local function performEasingOnSubject(subject, target, initial, clock, duration, easing)
|
||||
local t,b,c,d
|
||||
for k,v in pairs(target) do
|
||||
if type(v) == 'table' then
|
||||
performEasingOnSubject(subject[k], v, initial[k], clock, duration, easing)
|
||||
else
|
||||
t,b,c,d = clock, initial[k], v - initial[k], duration
|
||||
subject[k] = easing(t,b,c,d)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Tween methods
|
||||
|
||||
local Tween = {}
|
||||
local Tween_mt = {__index = Tween}
|
||||
|
||||
function Tween:set(clock)
|
||||
assert(type(clock) == 'number', "clock must be a positive number or 0")
|
||||
|
||||
self.initial = self.initial or copyTables({}, self.target, self.subject)
|
||||
self.clock = clock
|
||||
|
||||
if self.clock <= 0 then
|
||||
|
||||
self.clock = 0
|
||||
copyTables(self.subject, self.initial)
|
||||
|
||||
elseif self.clock >= self.duration then -- the tween has expired
|
||||
|
||||
self.clock = self.duration
|
||||
copyTables(self.subject, self.target)
|
||||
|
||||
else
|
||||
|
||||
performEasingOnSubject(self.subject, self.target, self.initial, self.clock, self.duration, self.easing)
|
||||
|
||||
end
|
||||
|
||||
return self.clock >= self.duration
|
||||
end
|
||||
|
||||
function Tween:reset()
|
||||
return self:set(0)
|
||||
end
|
||||
|
||||
function Tween:update(dt)
|
||||
assert(type(dt) == 'number', "dt must be a number")
|
||||
return self:set(self.clock + dt)
|
||||
end
|
||||
|
||||
|
||||
-- Public interface
|
||||
|
||||
function tween.new(duration, subject, target, easing)
|
||||
easing = getEasingFunction(easing)
|
||||
checkNewParams(duration, subject, target, easing)
|
||||
return setmetatable({
|
||||
duration = duration,
|
||||
subject = subject,
|
||||
target = target,
|
||||
easing = easing,
|
||||
clock = 0
|
||||
}, Tween_mt)
|
||||
end
|
||||
|
||||
return tween
|
1020
sys/apis/ui.lua
1020
sys/apis/ui.lua
File diff suppressed because it is too large
Load Diff
@ -365,6 +365,10 @@ function Util.toBytes(n)
|
||||
return tostring(n)
|
||||
end
|
||||
|
||||
function Util.insertString(os, is, pos)
|
||||
return os:sub(1, pos - 1) .. is .. os:sub(pos)
|
||||
end
|
||||
|
||||
function Util.split(str, pattern)
|
||||
pattern = pattern or "(.-)\n"
|
||||
local t = {}
|
||||
@ -457,28 +461,30 @@ end
|
||||
local function getopt( arg, options )
|
||||
local tab = {}
|
||||
for k, v in ipairs(arg) do
|
||||
if string.sub( v, 1, 2) == "--" then
|
||||
local x = string.find( v, "=", 1, true )
|
||||
if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 )
|
||||
else tab[ string.sub( v, 3 ) ] = true
|
||||
end
|
||||
elseif string.sub( v, 1, 1 ) == "-" then
|
||||
local y = 2
|
||||
local l = string.len(v)
|
||||
local jopt
|
||||
while ( y <= l ) do
|
||||
jopt = string.sub( v, y, y )
|
||||
if string.find( options, jopt, 1, true ) then
|
||||
if y < l then
|
||||
tab[ jopt ] = string.sub( v, y+1 )
|
||||
y = l
|
||||
else
|
||||
tab[ jopt ] = arg[ k + 1 ]
|
||||
end
|
||||
else
|
||||
tab[ jopt ] = true
|
||||
if type(v) == 'string' then
|
||||
if string.sub( v, 1, 2) == "--" then
|
||||
local x = string.find( v, "=", 1, true )
|
||||
if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 )
|
||||
else tab[ string.sub( v, 3 ) ] = true
|
||||
end
|
||||
elseif string.sub( v, 1, 1 ) == "-" then
|
||||
local y = 2
|
||||
local l = string.len(v)
|
||||
local jopt
|
||||
while ( y <= l ) do
|
||||
jopt = string.sub( v, y, y )
|
||||
if string.find( options, jopt, 1, true ) then
|
||||
if y < l then
|
||||
tab[ jopt ] = string.sub( v, y+1 )
|
||||
y = l
|
||||
else
|
||||
tab[ jopt ] = arg[ k + 1 ]
|
||||
end
|
||||
else
|
||||
tab[ jopt ] = true
|
||||
end
|
||||
y = y + 1
|
||||
end
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -4,8 +4,8 @@ LUA_PATH = '/sys/apis'
|
||||
|
||||
math.randomseed(os.clock())
|
||||
|
||||
_G.debug = function() end
|
||||
_G.Util = dofile('/sys/apis/util.lua')
|
||||
_G.debug = function(...) Util.print(...) end
|
||||
_G.requireInjector = dofile('/sys/apis/injector.lua')
|
||||
|
||||
os.run(Util.shallowCopy(getfenv(1)), '/sys/extensions/device.lua')
|
||||
@ -21,6 +21,7 @@ local mounts = Util.readFile('config/fstab')
|
||||
if mounts then
|
||||
for _,l in ipairs(Util.split(mounts)) do
|
||||
if l:sub(1, 1) ~= '#' then
|
||||
print('mounting ' .. l)
|
||||
fs.mount(unpack(Util.matches(l)))
|
||||
end
|
||||
end
|
||||
|
@ -57,10 +57,12 @@ function turtle.run(fn, ...)
|
||||
local e, id, abort = os.pullEventRaw('turtle_ticket')
|
||||
if e == 'terminate' then
|
||||
releaseTicket(ticketId)
|
||||
os.queueEvent('turtle_response')
|
||||
error('Terminated')
|
||||
end
|
||||
if abort then
|
||||
-- the function was queued, but the queue was cleared
|
||||
os.queueEvent('turtle_response')
|
||||
return false, 'aborted'
|
||||
end
|
||||
if id == ticketId then
|
||||
@ -72,6 +74,7 @@ function turtle.run(fn, ...)
|
||||
if not s and m then
|
||||
printError(m)
|
||||
end
|
||||
os.queueEvent('turtle_response')
|
||||
return s, m
|
||||
end
|
||||
end
|
||||
|
@ -17,6 +17,7 @@ local state = {
|
||||
moveDig = noop,
|
||||
moveCallback = noop,
|
||||
locations = {},
|
||||
coordSystem = 'relative', -- type of coordinate system being used
|
||||
}
|
||||
|
||||
function turtle.getState()
|
||||
@ -44,6 +45,7 @@ function turtle.reset()
|
||||
state.moveDig = noop
|
||||
state.moveCallback = noop
|
||||
state.locations = {}
|
||||
state.coordSystem = 'relative'
|
||||
|
||||
return true
|
||||
end
|
||||
@ -231,7 +233,6 @@ turtle.digPolicies = {
|
||||
if not turtle.isTurtleAtSide(action.side) then
|
||||
return action.dig()
|
||||
end
|
||||
|
||||
return Util.tryTimes(6, function()
|
||||
-- if not turtle.isTurtleAtSide(action.side) then
|
||||
-- return true --action.dig()
|
||||
|
@ -117,15 +117,19 @@ process:newThread('discovery_server', function()
|
||||
end
|
||||
end)
|
||||
|
||||
local info = {
|
||||
id = os.getComputerID()
|
||||
}
|
||||
|
||||
local function sendInfo()
|
||||
local info = {
|
||||
id = os.getComputerID(),
|
||||
label = os.getComputerLabel(),
|
||||
uptime = math.floor(os.clock()),
|
||||
}
|
||||
info.label = os.getComputerLabel()
|
||||
info.uptime = math.floor(os.clock())
|
||||
if turtle then
|
||||
info.fuel = turtle.getFuelLevel()
|
||||
info.status = turtle.status
|
||||
info.point = turtle.point
|
||||
info.inventory = turtle.getInventory()
|
||||
info.coordSystem = turtle.getState().coordSystem
|
||||
end
|
||||
device.wireless_modem.transmit(999, os.getComputerID(), info)
|
||||
end
|
||||
@ -152,13 +156,11 @@ end)
|
||||
if os.isTurtle() then
|
||||
process:newThread('turtle_heartbeat', function()
|
||||
|
||||
local lastUpdate = os.clock()
|
||||
os.sleep(1)
|
||||
|
||||
while true do
|
||||
os.pullEvent('turtle_response')
|
||||
if os.clock() - lastUpdate >= 1 then
|
||||
lastUpdate = os.clock()
|
||||
if turtle.status ~= info.status or
|
||||
turtle.fuel ~= info.fuel then
|
||||
sendInfo()
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user