mirror of
https://github.com/kepler155c/opus
synced 2025-01-25 22:56:53 +00:00
format and installer branches
This commit is contained in:
parent
1eea0d7cd8
commit
5a32fe208e
1
startup
1
startup
@ -93,3 +93,4 @@ if bootOptions[bootOption].args then
|
|||||||
else
|
else
|
||||||
print(bootOptions[bootOption].prompt)
|
print(bootOptions[bootOption].prompt)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
151
sys/apis/entry.lua
Normal file
151
sys/apis/entry.lua
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
local class = require('class')
|
||||||
|
|
||||||
|
local os = _G.os
|
||||||
|
|
||||||
|
local Entry = class()
|
||||||
|
|
||||||
|
function Entry:init(args)
|
||||||
|
self.pos = 0
|
||||||
|
self.scroll = 0
|
||||||
|
self.value = ''
|
||||||
|
self.width = args.width
|
||||||
|
self.limit = 1024
|
||||||
|
end
|
||||||
|
|
||||||
|
function Entry:reset()
|
||||||
|
self.pos = 0
|
||||||
|
self.scroll = 0
|
||||||
|
self.value = ''
|
||||||
|
end
|
||||||
|
|
||||||
|
local function nextWord(line, cx)
|
||||||
|
local result = { line:find("(%w+)", cx) }
|
||||||
|
if #result > 1 and result[2] > cx then
|
||||||
|
return result[2] + 1
|
||||||
|
elseif #result > 0 and result[1] == cx then
|
||||||
|
result = { line:find("(%w+)", result[2] + 1) }
|
||||||
|
if #result > 0 then
|
||||||
|
return result[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Entry:updateScroll()
|
||||||
|
if self.pos - self.scroll > self.width then
|
||||||
|
self.scroll = self.pos - (self.width)
|
||||||
|
elseif self.pos < self.scroll then
|
||||||
|
self.scroll = self.pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Entry:process(ie)
|
||||||
|
local updated = false
|
||||||
|
|
||||||
|
if ie.code == 'left' then
|
||||||
|
if self.pos > 0 then
|
||||||
|
self.pos = math.max(self.pos - 1, 0)
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'right' then
|
||||||
|
local input = tostring(self.value)
|
||||||
|
if self.pos < #input then
|
||||||
|
self.pos = math.min(self.pos + 1, #input)
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'home' then
|
||||||
|
if self.pos ~= 0 then
|
||||||
|
self.pos = 0
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'end' then
|
||||||
|
if self.pos ~= #tostring(self.value) then
|
||||||
|
self.pos = #tostring(self.value)
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'backspace' then
|
||||||
|
if self.pos > 0 then
|
||||||
|
local input = tostring(self.value)
|
||||||
|
self.value = input:sub(1, self.pos - 1) .. input:sub(self.pos + 1)
|
||||||
|
self.pos = self.pos - 1
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'control-right' then
|
||||||
|
local nx = nextWord(self.value, self.pos + 1)
|
||||||
|
if nx then
|
||||||
|
self.pos = math.min(nx - 1, #self.value)
|
||||||
|
elseif self.pos < #self.value then
|
||||||
|
self.pos = #self.value
|
||||||
|
end
|
||||||
|
updated = true
|
||||||
|
|
||||||
|
elseif ie.code == 'control-left' then
|
||||||
|
if self.pos ~= 0 then
|
||||||
|
local lx = 1
|
||||||
|
while true do
|
||||||
|
local nx = nextWord(self.value, lx)
|
||||||
|
if not nx or nx >= self.pos then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
lx = nx
|
||||||
|
end
|
||||||
|
if not lx then
|
||||||
|
self.pos = 0
|
||||||
|
else
|
||||||
|
self.pos = lx - 1
|
||||||
|
end
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'delete' then
|
||||||
|
local input = tostring(self.value)
|
||||||
|
if self.pos < #input then
|
||||||
|
self.value = input:sub(1, self.pos) .. input:sub(self.pos + 2)
|
||||||
|
self.update = true
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'char' then
|
||||||
|
local input = tostring(self.value)
|
||||||
|
if #input < self.limit then
|
||||||
|
self.value = input:sub(1, self.pos) .. ie.ch .. input:sub(self.pos + 1)
|
||||||
|
self.pos = self.pos + 1
|
||||||
|
self.update = true
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ie.code == 'copy' then
|
||||||
|
os.queueEvent('clipboard_copy', self.value)
|
||||||
|
|
||||||
|
elseif ie.code == 'paste' then
|
||||||
|
local input = tostring(self.value)
|
||||||
|
if #input + #ie.text > self.limit then
|
||||||
|
ie.text = ie.text:sub(1, self.limit-#input)
|
||||||
|
end
|
||||||
|
self.value = input:sub(1, self.pos) .. ie.text .. input:sub(self.pos + 1)
|
||||||
|
self.pos = self.pos + #ie.text
|
||||||
|
updated = true
|
||||||
|
|
||||||
|
elseif ie.code == 'mouse_click' then
|
||||||
|
-- need starting x passed in instead of hardcoding 3
|
||||||
|
self.pos = math.min(ie.x - 3 + self.scroll, #self.value)
|
||||||
|
updated = true
|
||||||
|
|
||||||
|
elseif ie.code == 'mouse_rightclick' then
|
||||||
|
local input = tostring(self.value)
|
||||||
|
if #input > 0 then
|
||||||
|
self:reset()
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:updateScroll()
|
||||||
|
|
||||||
|
return updated
|
||||||
|
end
|
||||||
|
|
||||||
|
return Entry
|
@ -24,15 +24,22 @@ end
|
|||||||
function input:toCode(ch, code)
|
function input:toCode(ch, code)
|
||||||
local result = { }
|
local result = { }
|
||||||
|
|
||||||
|
if not ch and code == 1 then
|
||||||
|
ch = 'escape'
|
||||||
|
end
|
||||||
|
|
||||||
if keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl] or
|
if keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl] or
|
||||||
code == keys.leftCtrl or code == keys.rightCtrl then
|
code == keys.leftCtrl or code == keys.rightCtrl then
|
||||||
table.insert(result, 'control')
|
table.insert(result, 'control')
|
||||||
end
|
end
|
||||||
|
|
||||||
if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or
|
-- the key-up event for alt keys is not generated if the minecraft
|
||||||
code == keys.leftAlt or code == keys.rightAlt then
|
-- window loses focus
|
||||||
table.insert(result, 'alt')
|
--
|
||||||
end
|
-- if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or
|
||||||
|
-- code == keys.leftAlt or code == keys.rightAlt then
|
||||||
|
-- table.insert(result, 'alt')
|
||||||
|
-- end
|
||||||
|
|
||||||
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
|
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
|
||||||
code == keys.leftShift or code == keys.rightShift then
|
code == keys.leftShift or code == keys.rightShift then
|
||||||
@ -65,13 +72,13 @@ function input:translate(event, code, p1, p2)
|
|||||||
if p1 then -- key is held down
|
if p1 then -- key is held down
|
||||||
if not modifiers[code] then
|
if not modifiers[code] then
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return input:toCode(keys.getName(code), code)
|
return { code = input:toCode(keys.getName(code), code) }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.state[code] = true
|
self.state[code] = true
|
||||||
if self:modifierPressed() and not modifiers[code] or code == 57 then
|
if self:modifierPressed() and not modifiers[code] or code == 57 then
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return input:toCode(keys.getName(code), code)
|
return { code = input:toCode(keys.getName(code), code) }
|
||||||
else
|
else
|
||||||
self.fired = false
|
self.fired = false
|
||||||
end
|
end
|
||||||
@ -80,7 +87,7 @@ function input:translate(event, code, p1, p2)
|
|||||||
elseif event == 'char' then
|
elseif event == 'char' then
|
||||||
if not self:modifierPressed() then
|
if not self:modifierPressed() then
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return input:toCode(code)
|
return { code = event, ch = input:toCode(code) }
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == 'key_up' then
|
elseif event == 'key_up' then
|
||||||
@ -89,16 +96,18 @@ function input:translate(event, code, p1, p2)
|
|||||||
self.fired = true
|
self.fired = true
|
||||||
local ch = input:toCode(keys.getName(code), code)
|
local ch = input:toCode(keys.getName(code), code)
|
||||||
self.state[code] = nil
|
self.state[code] = nil
|
||||||
return ch
|
return { code = ch }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.state[code] = nil
|
self.state[code] = nil
|
||||||
|
|
||||||
elseif event == 'paste' then
|
elseif event == 'paste' then
|
||||||
--self.state[keys.leftCtrl] = nil
|
|
||||||
--self.state[keys.rightCtrl] = nil
|
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return input:toCode('paste', 255)
|
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] then
|
||||||
|
return { code = 'shift-paste', text = code }
|
||||||
|
else
|
||||||
|
return { code = 'paste', text = code }
|
||||||
|
end
|
||||||
|
|
||||||
elseif event == 'mouse_click' then
|
elseif event == 'mouse_click' then
|
||||||
local buttons = { 'mouse_click', 'mouse_rightclick' }
|
local buttons = { 'mouse_click', 'mouse_rightclick' }
|
||||||
@ -108,7 +117,12 @@ function input:translate(event, code, p1, p2)
|
|||||||
elseif event == 'mouse_drag' then
|
elseif event == 'mouse_drag' then
|
||||||
self.mfired = true
|
self.mfired = true
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return input:toCode('mouse_drag', 255)
|
return {
|
||||||
|
code = input:toCode('mouse_drag', 255),
|
||||||
|
button = code,
|
||||||
|
x = p1,
|
||||||
|
y = p2,
|
||||||
|
}
|
||||||
|
|
||||||
elseif event == 'mouse_up' then
|
elseif event == 'mouse_up' then
|
||||||
if not self.mfired then
|
if not self.mfired then
|
||||||
@ -130,15 +144,27 @@ function input:translate(event, code, p1, p2)
|
|||||||
self.mfired = input:toCode(self.mch, 255)
|
self.mfired = input:toCode(self.mch, 255)
|
||||||
end
|
end
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return self.mfired
|
return {
|
||||||
|
code = self.mfired,
|
||||||
|
button = code,
|
||||||
|
x = p1,
|
||||||
|
y = p2,
|
||||||
|
}
|
||||||
|
|
||||||
elseif event == "mouse_scroll" then
|
elseif event == "mouse_scroll" then
|
||||||
local directions = {
|
local directions = {
|
||||||
[ -1 ] = 'scrollUp',
|
[ -1 ] = 'scroll_up',
|
||||||
[ 1 ] = 'scrollDown'
|
[ 1 ] = 'scroll_down'
|
||||||
}
|
}
|
||||||
self.fired = true
|
self.fired = true
|
||||||
return input:toCode(directions[code], 255)
|
return {
|
||||||
|
code = input:toCode(directions[code], 255),
|
||||||
|
x = p1,
|
||||||
|
y = p2,
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif event == 'terminate' then
|
||||||
|
return { code = 'terminate' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -146,7 +172,7 @@ function input:test()
|
|||||||
while true do
|
while true do
|
||||||
local ch = self:translate(os.pullEvent())
|
local ch = self:translate(os.pullEvent())
|
||||||
if ch then
|
if ch then
|
||||||
print('GOT: ' .. tostring(ch))
|
Util.print(ch)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -9,23 +9,8 @@
|
|||||||
This work is under MIT-LICENSE
|
This work is under MIT-LICENSE
|
||||||
Copyright (c) 2012-2013 Roland Yonaba.
|
Copyright (c) 2012-2013 Roland Yonaba.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
-- https://opensource.org/licenses/MIT
|
||||||
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.
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local _VERSION = ""
|
local _VERSION = ""
|
||||||
|
@ -11,24 +11,7 @@ local sha1 = {
|
|||||||
|
|
||||||
Copyright (c) 2013 Enrique Garcia Cota + Eike Decker + Jeffrey Friedl
|
Copyright (c) 2013 Enrique Garcia Cota + Eike Decker + Jeffrey Friedl
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
https://opensource.org/licenses/MIT
|
||||||
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.
|
|
||||||
]]
|
]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,8 +50,9 @@ function Terminal.scrollable(win, maxScroll)
|
|||||||
function win.write(text)
|
function win.write(text)
|
||||||
local _, h = win.getSize()
|
local _, h = win.getSize()
|
||||||
|
|
||||||
|
text = tostring(text) or ''
|
||||||
scrollTo(#lines - h)
|
scrollTo(#lines - h)
|
||||||
win.blit(tostring(text),
|
win.blit(text,
|
||||||
_rep(palette[win.getTextColor()], #text),
|
_rep(palette[win.getTextColor()], #text),
|
||||||
_rep(palette[win.getBackgroundColor()], #text))
|
_rep(palette[win.getBackgroundColor()], #text))
|
||||||
local x, y = win.getCursorPos()
|
local x, y = win.getCursorPos()
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
_G.requireInjector()
|
|
||||||
|
|
||||||
local Grid = require('jumper.grid')
|
local Grid = require('jumper.grid')
|
||||||
local Pathfinder = require('jumper.pathfinder')
|
local Pathfinder = require('jumper.pathfinder')
|
||||||
local Point = require('point')
|
local Point = require('point')
|
||||||
|
@ -3,7 +3,6 @@ local class = require('class')
|
|||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local Input = require('input')
|
local Input = require('input')
|
||||||
local Peripheral = require('peripheral')
|
local Peripheral = require('peripheral')
|
||||||
local Terminal = require('terminal')
|
|
||||||
local Transition = require('ui.transition')
|
local Transition = require('ui.transition')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
@ -46,12 +45,12 @@ end
|
|||||||
local Manager = class()
|
local Manager = class()
|
||||||
function Manager:init()
|
function Manager:init()
|
||||||
local function keyFunction(event, code, held)
|
local function keyFunction(event, code, held)
|
||||||
local ch = Input:translate(event, code, held)
|
local ie = Input:translate(event, code, held)
|
||||||
|
|
||||||
if ch and self.currentPage then
|
if ie and self.currentPage then
|
||||||
local target = self.currentPage.focused or self.currentPage
|
local target = self.currentPage.focused or self.currentPage
|
||||||
self:inputEvent(target,
|
self:inputEvent(target,
|
||||||
{ type = 'key', key = ch, element = target })
|
{ type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target })
|
||||||
self.currentPage:sync()
|
self.currentPage:sync()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -94,10 +93,10 @@ function Manager:init()
|
|||||||
-- this should be moved to the device !
|
-- this should be moved to the device !
|
||||||
monitor_touch = function(_, side, x, y)
|
monitor_touch = function(_, side, x, y)
|
||||||
Input:translate('mouse_click', 1, x, y)
|
Input:translate('mouse_click', 1, x, y)
|
||||||
local ch = Input:translate('mouse_up', 1, x, y)
|
local ie = Input:translate('mouse_up', 1, x, y)
|
||||||
if self.currentPage then
|
if self.currentPage then
|
||||||
if self.currentPage.parent.device.side == side then
|
if self.currentPage.parent.device.side == side then
|
||||||
self:click(ch, 1, x, y)
|
self:click(ie.code, 1, x, y)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@ -117,27 +116,27 @@ function Manager:init()
|
|||||||
end,
|
end,
|
||||||
|
|
||||||
mouse_up = function(_, button, x, y)
|
mouse_up = function(_, button, x, y)
|
||||||
local ch = Input:translate('mouse_up', button, x, y)
|
local ie = Input:translate('mouse_up', button, x, y)
|
||||||
|
|
||||||
if ch == 'control-shift-mouse_click' then -- hack
|
if ie.code == 'control-shift-mouse_click' then -- hack
|
||||||
local event = self.currentPage:pointToChild(x, y)
|
local event = self.currentPage:pointToChild(x, y)
|
||||||
_ENV.multishell.openTab({
|
_ENV.multishell.openTab({
|
||||||
path = 'sys/apps/Lua.lua',
|
path = 'sys/apps/Lua.lua',
|
||||||
args = { event.element },
|
args = { event.element },
|
||||||
focused = true })
|
focused = true })
|
||||||
|
|
||||||
elseif ch and self.currentPage then
|
elseif ie and self.currentPage then
|
||||||
--if not self.currentPage.parent.device.side then
|
--if not self.currentPage.parent.device.side then
|
||||||
self:click(ch, button, x, y)
|
self:click(ie.code, button, x, y)
|
||||||
--end
|
--end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
mouse_drag = function(_, button, x, y)
|
mouse_drag = function(_, button, x, y)
|
||||||
local ch = Input:translate('mouse_drag', button, x, y)
|
local ie = Input:translate('mouse_drag', button, x, y)
|
||||||
if ch and self.currentPage then
|
if ie and self.currentPage then
|
||||||
local event = self.currentPage:pointToChild(x, y)
|
local event = self.currentPage:pointToChild(x, y)
|
||||||
event.type = ch
|
event.type = ie.code
|
||||||
self:inputEvent(event.element, event)
|
self:inputEvent(event.element, event)
|
||||||
self.currentPage:sync()
|
self.currentPage:sync()
|
||||||
end
|
end
|
||||||
@ -2298,7 +2297,7 @@ function UI.Wizard:enable()
|
|||||||
child:disable()
|
child:disable()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:emit({ type = 'enable_view', view = Util.find(self.pages, 'index', 1) })
|
self:emit({ type = 'enable_view', next = Util.find(self.pages, 'index', 1) })
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Wizard:nextView()
|
function UI.Wizard:nextView()
|
||||||
@ -2327,29 +2326,44 @@ end
|
|||||||
|
|
||||||
function UI.Wizard:eventHandler(event)
|
function UI.Wizard:eventHandler(event)
|
||||||
if event.type == 'nextView' then
|
if event.type == 'nextView' then
|
||||||
self:nextView()
|
local currentView = Util.find(self.pages, 'enabled', true)
|
||||||
self:draw()
|
local nextView = Util.find(self.pages, 'index', currentView.index + 1)
|
||||||
return true
|
currentView:emit({ type = 'enable_view', next = nextView, current = currentView })
|
||||||
|
|
||||||
elseif event.type == 'previousView' then
|
elseif event.type == 'previousView' then
|
||||||
self:prevView()
|
local currentView = Util.find(self.pages, 'enabled', true)
|
||||||
self:draw()
|
local nextView = Util.find(self.pages, 'index', currentView.index - 1)
|
||||||
|
currentView:emit({ type = 'enable_view', prev = nextView, current = currentView })
|
||||||
return true
|
return true
|
||||||
|
|
||||||
elseif event.type == 'enable_view' then
|
elseif event.type == 'enable_view' then
|
||||||
if Util.find(self.pages, 'index', event.view.index - 1) then
|
if event.current then
|
||||||
|
if event.next then
|
||||||
|
self:addTransition('slideLeft')
|
||||||
|
elseif event.prev then
|
||||||
|
self:addTransition('slideRight')
|
||||||
|
end
|
||||||
|
event.current:disable()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- a new current view
|
||||||
|
local current = event.next or event.prev
|
||||||
|
current:enable()
|
||||||
|
|
||||||
|
if Util.find(self.pages, 'index', current.index - 1) then
|
||||||
self.previousButton:enable()
|
self.previousButton:enable()
|
||||||
else
|
else
|
||||||
self.previousButton:disable()
|
self.previousButton:disable()
|
||||||
end
|
end
|
||||||
|
|
||||||
if Util.find(self.pages, 'index', event.view.index + 1) then
|
if Util.find(self.pages, 'index', current.index + 1) then
|
||||||
self.nextButton.text = 'Next >'
|
self.nextButton.text = 'Next >'
|
||||||
self.nextButton.event = 'nextView'
|
self.nextButton.event = 'nextView'
|
||||||
else
|
else
|
||||||
self.nextButton.text = 'Accept'
|
self.nextButton.text = 'Accept'
|
||||||
self.nextButton.event = 'accept'
|
self.nextButton.event = 'accept'
|
||||||
end
|
end
|
||||||
|
self:draw()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2422,8 +2436,9 @@ UI.Embedded.defaults = {
|
|||||||
function UI.Embedded:setParent()
|
function UI.Embedded:setParent()
|
||||||
UI.Window.setParent(self)
|
UI.Window.setParent(self)
|
||||||
self.win = window.create(UI.term.device, 1, 1, self.width, self.height, false)
|
self.win = window.create(UI.term.device, 1, 1, self.width, self.height, false)
|
||||||
Canvas.convertWindow(self.win, UI.term.device, self.x, self.y)
|
Canvas.scrollingWindow(self.win, self.x, self.y)
|
||||||
Terminal.scrollable(self.win, 100)
|
self.win.setParent(UI.term.device)
|
||||||
|
self.win.setMaxScroll(100)
|
||||||
|
|
||||||
local canvas = self:getCanvas()
|
local canvas = self:getCanvas()
|
||||||
self.win.canvas.parent = canvas
|
self.win.canvas.parent = canvas
|
||||||
|
@ -128,7 +128,7 @@ function Canvas:write(x, y, text, bg, fg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Canvas:writeBlit(x, y, text, bg, fg)
|
function Canvas:writeBlit(x, y, text, bg, fg)
|
||||||
if y > 0 and y <= self.height and x <= self.width then
|
if y > 0 and y <= #self.lines and x <= self.width then
|
||||||
local width = #text
|
local width = #text
|
||||||
|
|
||||||
-- fix ffs
|
-- fix ffs
|
||||||
@ -367,4 +367,132 @@ function Canvas.convertWindow(win, parent, wx, wy)
|
|||||||
win.clear()
|
win.clear()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Canvas.scrollingWindow(win, wx, wy)
|
||||||
|
local w, h = win.getSize()
|
||||||
|
local scrollPos = 0
|
||||||
|
local maxScroll = h
|
||||||
|
|
||||||
|
-- canvas lines are are a sliding window within the local lines table
|
||||||
|
local lines = { }
|
||||||
|
|
||||||
|
local parent
|
||||||
|
local canvas = Canvas({
|
||||||
|
x = wx,
|
||||||
|
y = wy,
|
||||||
|
width = w,
|
||||||
|
height = h,
|
||||||
|
isColor = win.isColor(),
|
||||||
|
})
|
||||||
|
win.canvas = canvas
|
||||||
|
|
||||||
|
local function scrollTo(p, forceRedraw)
|
||||||
|
local ms = #lines - canvas.height -- max scroll
|
||||||
|
p = math.min(math.max(p, 0), ms) -- normalize
|
||||||
|
|
||||||
|
if p ~= scrollPos or forceRedraw then
|
||||||
|
scrollPos = p
|
||||||
|
for i = 1, canvas.height do
|
||||||
|
canvas.lines[i] = lines[i + scrollPos]
|
||||||
|
end
|
||||||
|
canvas:dirty()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.blit(text, fg, bg)
|
||||||
|
local x, y = win.getCursorPos()
|
||||||
|
win.canvas:writeBlit(x, y, text, bg, fg)
|
||||||
|
win.redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.clear()
|
||||||
|
lines = { }
|
||||||
|
for i = 1, canvas.height do
|
||||||
|
lines[i] = canvas.lines[i]
|
||||||
|
end
|
||||||
|
scrollPos = 0
|
||||||
|
canvas:clear(win.getBackgroundColor(), win.getTextColor())
|
||||||
|
win.redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.clearLine()
|
||||||
|
local _, y = win.getCursorPos()
|
||||||
|
|
||||||
|
scrollTo(#lines - canvas.height)
|
||||||
|
win.canvas:write(1,
|
||||||
|
y,
|
||||||
|
_rep(' ', win.canvas.width),
|
||||||
|
win.getBackgroundColor(),
|
||||||
|
win.getTextColor())
|
||||||
|
win.redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.redraw()
|
||||||
|
if parent and canvas.visible then
|
||||||
|
local x, y = win.getCursorPos()
|
||||||
|
for i = 1, canvas.height do
|
||||||
|
local line = canvas.lines[i]
|
||||||
|
if line and line.dirty then
|
||||||
|
parent.setCursorPos(canvas.x, canvas.y + i - 1)
|
||||||
|
parent.blit(line.text, line.fg, line.bg)
|
||||||
|
line.dirty = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
win.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- doesn't support negative scrolling...
|
||||||
|
function win.scroll(n)
|
||||||
|
for _ = 1, n do
|
||||||
|
lines[#lines + 1] = {
|
||||||
|
text = _rep(' ', canvas.width),
|
||||||
|
fg = _rep(canvas.palette[win.getTextColor()], canvas.width),
|
||||||
|
bg = _rep(canvas.palette[win.getBackgroundColor()], canvas.width),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
while #lines > maxScroll do
|
||||||
|
table.remove(lines, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
scrollTo(maxScroll, true)
|
||||||
|
win.redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.scrollDown()
|
||||||
|
scrollTo(scrollPos + 1)
|
||||||
|
win.redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.scrollUp()
|
||||||
|
scrollTo(scrollPos - 1)
|
||||||
|
win.redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.setMaxScroll(ms)
|
||||||
|
maxScroll = ms
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.setParent(p)
|
||||||
|
parent = p
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.write(str)
|
||||||
|
str = tostring(str) or ''
|
||||||
|
|
||||||
|
local x, y = win.getCursorPos()
|
||||||
|
scrollTo(#lines - canvas.height)
|
||||||
|
win.blit(str,
|
||||||
|
_rep(canvas.palette[win.getTextColor()], #str),
|
||||||
|
_rep(canvas.palette[win.getBackgroundColor()], #str))
|
||||||
|
win.setCursorPos(x + #str, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.reposition(x, y, width, height)
|
||||||
|
win.canvas.x, win.canvas.y = x, y
|
||||||
|
win.canvas:resize(width or win.canvas.width, height or win.canvas.height)
|
||||||
|
end
|
||||||
|
|
||||||
|
win.clear()
|
||||||
|
end
|
||||||
return Canvas
|
return Canvas
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
-------------------------------------------------------------------------------
|
|
||||||
--
|
--
|
||||||
-- tek.lib.region
|
-- tek.lib.region
|
||||||
-- Written by Timm S. Mueller <tmueller at schulze-mueller.de>
|
-- Written by Timm S. Mueller <tmueller at schulze-mueller.de>
|
||||||
@ -9,49 +8,11 @@
|
|||||||
-- * Franciska Schulze <fschulze at schulze-mueller.de>
|
-- * Franciska Schulze <fschulze at schulze-mueller.de>
|
||||||
-- * Tobias Schwinger <tschwinger at isonews2.com>
|
-- * Tobias Schwinger <tschwinger at isonews2.com>
|
||||||
--
|
--
|
||||||
-- Permission is hereby granted, free of charge, to any person obtaining
|
-- https://opensource.org/licenses/MIT
|
||||||
-- 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
|
-- Some comments have been removed to reduce file size, see:
|
||||||
-- included in all copies or substantial portions of the Software.
|
-- https://github.com/technosaurus/tekui/blob/master/etc/region.lua
|
||||||
--
|
-- for the full source
|
||||||
-- === 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 insert = table.insert
|
||||||
local ipairs = ipairs
|
local ipairs = ipairs
|
||||||
@ -65,24 +26,18 @@ Region._VERSION = "Region 11.3"
|
|||||||
|
|
||||||
Region.__index = Region
|
Region.__index = Region
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- x0, y0, x1, y1 = Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4):
|
-- 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
|
-- Returns the coordinates of a rectangle where a rectangle specified by
|
||||||
-- the coordinates s1, s2, s3, s4 overlaps with the rectangle specified
|
-- the coordinates s1, s2, s3, s4 overlaps with the rectangle specified
|
||||||
-- by the coordinates d1, d2, d3, d4. The return value is '''nil''' if
|
-- by the coordinates d1, d2, d3, d4. The return value is '''nil''' if
|
||||||
-- the rectangles do not overlap.
|
-- the rectangles do not overlap.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4)
|
function Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||||
if s3 >= d1 and s1 <= d3 and s4 >= d2 and s2 <= d4 then
|
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)
|
return max(s1, d1), max(s2, d2), min(s3, d3), min(s4, d4)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- insertrect: insert rect to table, merging with an existing one if possible
|
-- insertrect: insert rect to table, merging with an existing one if possible
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local function insertrect(d, s1, s2, s3, s4)
|
local function insertrect(d, s1, s2, s3, s4)
|
||||||
for i = 1, min(4, #d) do
|
for i = 1, min(4, #d) do
|
||||||
local a = d[i]
|
local a = d[i]
|
||||||
@ -108,10 +63,7 @@ local function insertrect(d, s1, s2, s3, s4)
|
|||||||
insert(d, 1, { s1, s2, s3, s4 })
|
insert(d, 1, { s1, s2, s3, s4 })
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- cutrect: cut rect d into table of new rects, using rect s as a punch
|
-- 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)
|
local function cutrect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||||
if not Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4) then
|
if not Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4) then
|
||||||
return { { d1, d2, d3, d4 } }
|
return { { d1, d2, d3, d4 } }
|
||||||
@ -135,10 +87,7 @@ local function cutrect(d1, d2, d3, d4, s1, s2, s3, s4)
|
|||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- cutregion: cut region d, using s as a punch
|
-- cutregion: cut region d, using s as a punch
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local function cutregion(d, s1, s2, s3, s4)
|
local function cutregion(d, s1, s2, s3, s4)
|
||||||
local r = { }
|
local r = { }
|
||||||
for _, dr in ipairs(d) do
|
for _, dr in ipairs(d) do
|
||||||
@ -150,11 +99,8 @@ local function cutregion(d, s1, s2, s3, s4)
|
|||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region = Region.new(r1, r2, r3, r4): Creates a new region from the given
|
-- region = Region.new(r1, r2, r3, r4): Creates a new region from the given
|
||||||
-- coordinates.
|
-- coordinates.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region.new(r1, r2, r3, r4)
|
function Region.new(r1, r2, r3, r4)
|
||||||
if r1 then
|
if r1 then
|
||||||
return setmetatable({ region = { { r1, r2, r3, r4 } } }, Region)
|
return setmetatable({ region = { { r1, r2, r3, r4 } } }, Region)
|
||||||
@ -162,39 +108,27 @@ function Region.new(r1, r2, r3, r4)
|
|||||||
return setmetatable({ region = { } }, Region)
|
return setmetatable({ region = { } }, Region)
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- self = region:setRect(r1, r2, r3, r4): Resets an existing region
|
-- self = region:setRect(r1, r2, r3, r4): Resets an existing region
|
||||||
-- to the specified rectangle.
|
-- to the specified rectangle.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:setRect(r1, r2, r3, r4)
|
function Region:setRect(r1, r2, r3, r4)
|
||||||
self.region = { { r1, r2, r3, r4 } }
|
self.region = { { r1, r2, r3, r4 } }
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:orRect(r1, r2, r3, r4): Logical ''or''s a rectangle to a region
|
-- region:orRect(r1, r2, r3, r4): Logical ''or''s a rectangle to a region
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:orRect(s1, s2, s3, s4)
|
function Region:orRect(s1, s2, s3, s4)
|
||||||
self.region = cutregion(self.region, s1, s2, s3, s4)
|
self.region = cutregion(self.region, s1, s2, s3, s4)
|
||||||
insertrect(self.region, s1, s2, s3, s4)
|
insertrect(self.region, s1, s2, s3, s4)
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:orRegion(region): Logical ''or''s another region to a region
|
-- region:orRegion(region): Logical ''or''s another region to a region
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:orRegion(s)
|
function Region:orRegion(s)
|
||||||
for _, r in ipairs(s) do
|
for _, r in ipairs(s) do
|
||||||
self:orRect(r[1], r[2], r[3], r[4])
|
self:orRect(r[1], r[2], r[3], r[4])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:andRect(r1, r2, r3, r4): Logical ''and''s a rectange to a region
|
-- region:andRect(r1, r2, r3, r4): Logical ''and''s a rectange to a region
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:andRect(s1, s2, s3, s4)
|
function Region:andRect(s1, s2, s3, s4)
|
||||||
local r = { }
|
local r = { }
|
||||||
for _, d in ipairs(self.region) do
|
for _, d in ipairs(self.region) do
|
||||||
@ -207,10 +141,7 @@ function Region:andRect(s1, s2, s3, s4)
|
|||||||
self.region = r
|
self.region = r
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:xorRect(r1, r2, r3, r4): Logical ''xor''s a rectange to a region
|
-- region:xorRect(r1, r2, r3, r4): Logical ''xor''s a rectange to a region
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:xorRect(s1, s2, s3, s4)
|
function Region:xorRect(s1, s2, s3, s4)
|
||||||
local r1 = { }
|
local r1 = { }
|
||||||
local r2 = { { s1, s2, s3, s4 } }
|
local r2 = { { s1, s2, s3, s4 } }
|
||||||
@ -225,10 +156,7 @@ function Region:xorRect(s1, s2, s3, s4)
|
|||||||
self:orRegion(r2)
|
self:orRegion(r2)
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- self = region:subRect(r1, r2, r3, r4): Subtracts a rectangle from a region
|
-- self = region:subRect(r1, r2, r3, r4): Subtracts a rectangle from a region
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:subRect(s1, s2, s3, s4)
|
function Region:subRect(s1, s2, s3, s4)
|
||||||
local r1 = { }
|
local r1 = { }
|
||||||
for _, d in ipairs(self.region) do
|
for _, d in ipairs(self.region) do
|
||||||
@ -241,10 +169,7 @@ function Region:subRect(s1, s2, s3, s4)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:getRect - gets an iterator on the rectangles in a region [internal]
|
-- region:getRect - gets an iterator on the rectangles in a region [internal]
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:getRects()
|
function Region:getRects()
|
||||||
local index = 0
|
local index = 0
|
||||||
return function(object)
|
return function(object)
|
||||||
@ -255,12 +180,9 @@ function Region:getRects()
|
|||||||
end, self.region
|
end, self.region
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- success = region:checkIntersect(x0, y0, x1, y1): Returns a boolean
|
-- success = region:checkIntersect(x0, y0, x1, y1): Returns a boolean
|
||||||
-- indicating whether a rectangle specified by its coordinates overlaps
|
-- indicating whether a rectangle specified by its coordinates overlaps
|
||||||
-- with a region.
|
-- with a region.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:checkIntersect(s1, s2, s3, s4)
|
function Region:checkIntersect(s1, s2, s3, s4)
|
||||||
for _, d in ipairs(self.region) do
|
for _, d in ipairs(self.region) do
|
||||||
if Region.intersect(d[1], d[2], d[3], d[4], s1, s2, s3, s4) then
|
if Region.intersect(d[1], d[2], d[3], d[4], s1, s2, s3, s4) then
|
||||||
@ -270,10 +192,7 @@ function Region:checkIntersect(s1, s2, s3, s4)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:subRegion(region2): Subtracts {{region2}} from {{region}}.
|
-- region:subRegion(region2): Subtracts {{region2}} from {{region}}.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:subRegion(region)
|
function Region:subRegion(region)
|
||||||
if region then
|
if region then
|
||||||
for r1, r2, r3, r4 in region:getRects() do
|
for r1, r2, r3, r4 in region:getRects() do
|
||||||
@ -282,10 +201,7 @@ function Region:subRegion(region)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:andRegion(r): Logically ''and''s a region to a region
|
-- region:andRegion(r): Logically ''and''s a region to a region
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:andRegion(s)
|
function Region:andRegion(s)
|
||||||
local r = { }
|
local r = { }
|
||||||
for _, s in ipairs(s.region) do
|
for _, s in ipairs(s.region) do
|
||||||
@ -301,23 +217,17 @@ function Region:andRegion(s)
|
|||||||
self.region = r
|
self.region = r
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:forEach(func, obj, ...): For each rectangle in a region, calls the
|
-- region:forEach(func, obj, ...): For each rectangle in a region, calls the
|
||||||
-- specified function according the following scheme:
|
-- specified function according the following scheme:
|
||||||
-- func(obj, x0, y0, x1, y1, ...)
|
-- func(obj, x0, y0, x1, y1, ...)
|
||||||
-- Extra arguments are passed through to the function.
|
-- Extra arguments are passed through to the function.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:forEach(func, obj, ...)
|
function Region:forEach(func, obj, ...)
|
||||||
for x0, y0, x1, y1 in self:getRects() do
|
for x0, y0, x1, y1 in self:getRects() do
|
||||||
func(obj, x0, y0, x1, y1, ...)
|
func(obj, x0, y0, x1, y1, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:shift(dx, dy): Shifts a region by delta x and y.
|
-- region:shift(dx, dy): Shifts a region by delta x and y.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:shift(dx, dy)
|
function Region:shift(dx, dy)
|
||||||
for _, r in ipairs(self.region) do
|
for _, r in ipairs(self.region) do
|
||||||
r[1] = r[1] + dx
|
r[1] = r[1] + dx
|
||||||
@ -327,18 +237,12 @@ function Region:shift(dx, dy)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- region:isEmpty(): Returns '''true''' if a region is empty.
|
-- region:isEmpty(): Returns '''true''' if a region is empty.
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:isEmpty()
|
function Region:isEmpty()
|
||||||
return #self.region == 0
|
return #self.region == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- minx, miny, maxx, maxy = region:get(): Get region's min/max extents
|
-- minx, miny, maxx, maxy = region:get(): Get region's min/max extents
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function Region:get()
|
function Region:get()
|
||||||
if #self.region > 0 then
|
if #self.region > 0 then
|
||||||
local minx = 1000000 -- ui.HUGE
|
local minx = 1000000 -- ui.HUGE
|
||||||
|
@ -7,24 +7,7 @@ local tween = {
|
|||||||
|
|
||||||
Copyright (c) 2014 Enrique García Cota, Yuichi Tateno, Emmanuel Oga
|
Copyright (c) 2014 Enrique García Cota, Yuichi Tateno, Emmanuel Oga
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Licence details: https://opensource.org/licenses/MIT
|
||||||
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.
|
|
||||||
]]
|
]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
456
sys/apps/Installer.lua
Normal file
456
sys/apps/Installer.lua
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
local colors = _G.colors
|
||||||
|
local fs = _G.fs
|
||||||
|
local http = _G.http
|
||||||
|
local install = _ENV.install
|
||||||
|
local os = _G.os
|
||||||
|
|
||||||
|
local requireInjector
|
||||||
|
if not install.testing then
|
||||||
|
local url ='https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis/injector.lua'
|
||||||
|
requireInjector = load(http.get(url).readAll())()
|
||||||
|
else
|
||||||
|
requireInjector = _G.requireInjector
|
||||||
|
end
|
||||||
|
|
||||||
|
requireInjector(_ENV)
|
||||||
|
|
||||||
|
if not install.testing then
|
||||||
|
if package then
|
||||||
|
for _ = 1, 4 do
|
||||||
|
table.remove(package.loaders, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local Git = require('git')
|
||||||
|
local UI = require('ui')
|
||||||
|
local Util = require('util')
|
||||||
|
|
||||||
|
local currentFile = ''
|
||||||
|
local currentProgress = 0
|
||||||
|
local cancelEvent
|
||||||
|
|
||||||
|
local args = { ... }
|
||||||
|
local steps = install.steps[args[1] or 'install']
|
||||||
|
|
||||||
|
if not steps then
|
||||||
|
error('Invalid install type')
|
||||||
|
end
|
||||||
|
|
||||||
|
local mode = steps[#steps]
|
||||||
|
|
||||||
|
if UI.term.width < 32 then
|
||||||
|
cancelEvent = 'quit'
|
||||||
|
end
|
||||||
|
|
||||||
|
local page = UI.Page {
|
||||||
|
backgroundColor = colors.cyan,
|
||||||
|
titleBar = UI.TitleBar {
|
||||||
|
event = cancelEvent,
|
||||||
|
},
|
||||||
|
wizard = UI.Wizard {
|
||||||
|
y = 2, ey = -2,
|
||||||
|
},
|
||||||
|
notification = UI.Notification(),
|
||||||
|
accelerators = {
|
||||||
|
q = 'quit',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local pages = {
|
||||||
|
splash = UI.Viewport { },
|
||||||
|
review = UI.Viewport { },
|
||||||
|
license = UI.Viewport {
|
||||||
|
backgroundColor = colors.black,
|
||||||
|
},
|
||||||
|
branch = UI.Window {
|
||||||
|
grid = UI.ScrollingGrid {
|
||||||
|
ey = -3,
|
||||||
|
columns = {
|
||||||
|
{ heading = 'Branch', key = 'branch' },
|
||||||
|
{ heading = 'Description', key = 'description' },
|
||||||
|
},
|
||||||
|
values = install.branches,
|
||||||
|
autospace = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
files = UI.Window {
|
||||||
|
grid = UI.ScrollingGrid {
|
||||||
|
ey = -3,
|
||||||
|
columns = {
|
||||||
|
{ heading = 'Files', key = 'file' },
|
||||||
|
},
|
||||||
|
sortColumn = 'file',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
install = UI.Window {
|
||||||
|
progressBar = UI.ProgressBar {
|
||||||
|
y = -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninstall = UI.Window {
|
||||||
|
progressBar = UI.ProgressBar {
|
||||||
|
y = -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local function getFileList()
|
||||||
|
if install.gitRepo then
|
||||||
|
local gitFiles = Git.list(string.format('%s/%s', install.gitRepo, install.gitBranch or 'master'))
|
||||||
|
install.files = { }
|
||||||
|
install.diskspace = 0
|
||||||
|
for path, entry in pairs(gitFiles) do
|
||||||
|
install.files[path] = entry.url
|
||||||
|
install.diskspace = install.diskspace + entry.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not install.files or Util.empty(install.files) then
|
||||||
|
error('File list is missing or empty')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Splash ]]--
|
||||||
|
function pages.splash:enable()
|
||||||
|
page.titleBar.title = 'Installer v1.0'
|
||||||
|
UI.Viewport.enable(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.splash:draw()
|
||||||
|
self:clear()
|
||||||
|
self:setCursorPos(1, 1)
|
||||||
|
self:print(
|
||||||
|
string.format('%s v%s\n', install.title, install.version), nil, colors.yellow)
|
||||||
|
self:print(
|
||||||
|
string.format('By: %s\n\n%s\n', install.author, install.description))
|
||||||
|
|
||||||
|
self.ymax = self.cursorY
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ License ]]--
|
||||||
|
function pages.license:enable()
|
||||||
|
page.titleBar.title = 'License Review'
|
||||||
|
page.wizard.nextButton.text = 'Accept'
|
||||||
|
UI.Viewport.enable(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.license:draw()
|
||||||
|
self:clear()
|
||||||
|
self:setCursorPos(1, 1)
|
||||||
|
self:print(
|
||||||
|
string.format('Copyright (c) %s %s\n\n', install.copyrightYear,
|
||||||
|
install.copyrightHolders),
|
||||||
|
nil, colors.yellow)
|
||||||
|
self:print(install.license)
|
||||||
|
|
||||||
|
self.ymax = self.cursorY + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Review ]]--
|
||||||
|
function pages.review:enable()
|
||||||
|
if mode == 'uninstall' then
|
||||||
|
page.nextButton.text = 'Remove'
|
||||||
|
page.titleBar.title = 'Remove Installed Files'
|
||||||
|
else
|
||||||
|
page.wizard.nextButton.text = 'Begin'
|
||||||
|
page.titleBar.title = 'Download and Install'
|
||||||
|
end
|
||||||
|
UI.Viewport.enable(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.review:draw()
|
||||||
|
self:clear()
|
||||||
|
self:setCursorPos(1, 1)
|
||||||
|
|
||||||
|
local text = 'Ready to begin installation.\n\nProceeding will download and install the files to the hard drive.'
|
||||||
|
if mode == 'uninstall' then
|
||||||
|
text = 'Ready to begin.\n\nProceeding will remove the files previously installed.'
|
||||||
|
end
|
||||||
|
self:print(text)
|
||||||
|
|
||||||
|
self.ymax = self.cursorY + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Files ]]--
|
||||||
|
function pages.files:enable()
|
||||||
|
page.titleBar.title = 'Review Files'
|
||||||
|
self.grid.values = { }
|
||||||
|
for k,v in pairs(install.files) do
|
||||||
|
table.insert(self.grid.values, { file = k, code = v })
|
||||||
|
end
|
||||||
|
self.grid:update()
|
||||||
|
UI.Window.enable(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.files:draw()
|
||||||
|
self:clear()
|
||||||
|
|
||||||
|
local function formatSize(size)
|
||||||
|
if size >= 1000000 then
|
||||||
|
return string.format('%dM', math.floor(size/1000000, 2))
|
||||||
|
elseif size >= 1000 then
|
||||||
|
return string.format('%dK', math.floor(size/1000, 2))
|
||||||
|
end
|
||||||
|
return size
|
||||||
|
end
|
||||||
|
|
||||||
|
if install.diskspace then
|
||||||
|
|
||||||
|
local bg = self.backgroundColor
|
||||||
|
|
||||||
|
local diskFree = fs.getFreeSpace('/')
|
||||||
|
if install.diskspace > diskFree then
|
||||||
|
bg = colors.red
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = string.format('Space Required: %s, Free: %s',
|
||||||
|
formatSize(install.diskspace), formatSize(diskFree))
|
||||||
|
|
||||||
|
if #text > self.width then
|
||||||
|
text = string.format('Space: %s Free: %s',
|
||||||
|
formatSize(install.diskspace), formatSize(diskFree))
|
||||||
|
end
|
||||||
|
|
||||||
|
self:write(1, self.height, Util.widthify(text, self.width), bg)
|
||||||
|
end
|
||||||
|
self.grid:draw()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
function pages.files:view(url)
|
||||||
|
local s, m = pcall(function()
|
||||||
|
page.notification:info('Downloading')
|
||||||
|
page:sync()
|
||||||
|
Util.download(url, '/.source')
|
||||||
|
end)
|
||||||
|
page.notification:disable()
|
||||||
|
if s then
|
||||||
|
shell.run('edit /.source')
|
||||||
|
fs.delete('/.source')
|
||||||
|
page:draw()
|
||||||
|
page.notification:cancel()
|
||||||
|
else
|
||||||
|
page.notification:error(m:gsub('.*: (.*)', '%1'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.files:eventHandler(event)
|
||||||
|
if event.type == 'grid_select' then
|
||||||
|
self:view(event.selected.code)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local function drawCommon(self)
|
||||||
|
if currentFile then
|
||||||
|
self:write(1, 3, 'File:')
|
||||||
|
self:write(1, 4, Util.widthify(currentFile, self.width))
|
||||||
|
else
|
||||||
|
self:write(1, 3, 'Finished')
|
||||||
|
end
|
||||||
|
if self.failed then
|
||||||
|
self:write(1, 5, Util.widthify(self.failed, self.width), colors.red)
|
||||||
|
end
|
||||||
|
self:write(1, self.height - 1, 'Progress')
|
||||||
|
|
||||||
|
self.progressBar.value = currentProgress
|
||||||
|
self.progressBar:draw()
|
||||||
|
self:sync()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Branch ]]--
|
||||||
|
function pages.branch:enable()
|
||||||
|
page.titleBar.title = 'Select Branch'
|
||||||
|
UI.Window.enable(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.branch:eventHandler(event)
|
||||||
|
-- user is navigating to next view (not previous)
|
||||||
|
if event.type == 'enable_view' and event.next then
|
||||||
|
install.gitBranch = self.grid:getSelected().branch
|
||||||
|
getFileList()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Install ]]--
|
||||||
|
function pages.install:enable()
|
||||||
|
page.wizard.cancelButton:disable()
|
||||||
|
page.wizard.previousButton:disable()
|
||||||
|
page.wizard.nextButton:disable()
|
||||||
|
|
||||||
|
page.titleBar.title = 'Installing...'
|
||||||
|
page.titleBar.event = nil
|
||||||
|
|
||||||
|
UI.Window.enable(self)
|
||||||
|
|
||||||
|
page:draw()
|
||||||
|
page:sync()
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
local numFiles = Util.size(install.files)
|
||||||
|
for filename,url in pairs(install.files) do
|
||||||
|
currentFile = filename
|
||||||
|
currentProgress = i / numFiles * 100
|
||||||
|
self:draw(self)
|
||||||
|
self:sync()
|
||||||
|
local s, m = pcall(function()
|
||||||
|
Util.download(url, fs.combine(install.directory or '', filename))
|
||||||
|
end)
|
||||||
|
if not s then
|
||||||
|
self.failed = m:gsub('.*: (.*)', '%1')
|
||||||
|
break
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self.failed then
|
||||||
|
currentProgress = 100
|
||||||
|
currentFile = nil
|
||||||
|
|
||||||
|
if install.postInstall then
|
||||||
|
local s, m = pcall(function() install.postInstall(page, UI) end)
|
||||||
|
if not s then
|
||||||
|
self.failed = m:gsub('.*: (.*)', '%1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
page.wizard.nextButton.text = 'Exit'
|
||||||
|
page.wizard.nextButton.event = 'quit'
|
||||||
|
if not self.failed and install.rebootAfter then
|
||||||
|
page.wizard.nextButton.text = 'Reboot'
|
||||||
|
page.wizard.nextButton.event = 'reboot'
|
||||||
|
end
|
||||||
|
|
||||||
|
page.wizard.nextButton:enable()
|
||||||
|
page:draw()
|
||||||
|
page:sync()
|
||||||
|
|
||||||
|
if not self.failed and Util.key(args, 'automatic') then
|
||||||
|
if install.rebootAfter then
|
||||||
|
os.reboot()
|
||||||
|
else
|
||||||
|
UI:exitPullEvents()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.install:draw()
|
||||||
|
self:clear()
|
||||||
|
local text = 'The files are being installed'
|
||||||
|
if #text > self.width then
|
||||||
|
text = 'Installing files'
|
||||||
|
end
|
||||||
|
self:write(1, 1, text, nil, colors.yellow)
|
||||||
|
|
||||||
|
drawCommon(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Uninstall ]]--
|
||||||
|
function pages.uninstall:enable()
|
||||||
|
page.wizard.cancelButton:disable()
|
||||||
|
page.wizard.previousButton:disable()
|
||||||
|
page.wizard.nextButton:disable()
|
||||||
|
|
||||||
|
page.titleBar.title = 'Uninstalling...'
|
||||||
|
page.titleBar.event = nil
|
||||||
|
|
||||||
|
page:draw()
|
||||||
|
page:sync()
|
||||||
|
|
||||||
|
UI.Window.enable(self)
|
||||||
|
|
||||||
|
local function pruneDir(dir)
|
||||||
|
if #dir > 0 then
|
||||||
|
if fs.exists(dir) then
|
||||||
|
local files = fs.list(dir)
|
||||||
|
if #files == 0 then
|
||||||
|
fs.delete(dir)
|
||||||
|
pruneDir(fs.getDir(dir))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
local numFiles = Util.size(install.files)
|
||||||
|
for k in pairs(install.files) do
|
||||||
|
currentFile = k
|
||||||
|
currentProgress = i / numFiles * 100
|
||||||
|
self:draw()
|
||||||
|
self:sync()
|
||||||
|
fs.delete(k)
|
||||||
|
pruneDir(fs.getDir(k))
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
currentProgress = 100
|
||||||
|
currentFile = nil
|
||||||
|
|
||||||
|
page.wizard.nextButton.text = 'Exit'
|
||||||
|
page.wizard.nextButton.event = 'quit'
|
||||||
|
page.wizard.nextButton:enable()
|
||||||
|
|
||||||
|
page:draw()
|
||||||
|
page:sync()
|
||||||
|
end
|
||||||
|
|
||||||
|
function pages.uninstall:draw()
|
||||||
|
self:clear()
|
||||||
|
self:write(1, 1, 'Uninstalling files', nil, colors.yellow)
|
||||||
|
drawCommon(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function page:eventHandler(event)
|
||||||
|
if event.type == 'cancel' then
|
||||||
|
UI:exitPullEvents()
|
||||||
|
|
||||||
|
elseif event.type == 'reboot' then
|
||||||
|
os.reboot()
|
||||||
|
|
||||||
|
elseif event.type == 'quit' then
|
||||||
|
UI:exitPullEvents()
|
||||||
|
|
||||||
|
else
|
||||||
|
return UI.Page.eventHandler(self, event)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function page:enable()
|
||||||
|
UI.Page.enable(self)
|
||||||
|
self:setFocus(page.wizard.nextButton)
|
||||||
|
if UI.term.width < 32 then
|
||||||
|
page.wizard.cancelButton:disable()
|
||||||
|
page.wizard.previousButton.x = 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
getFileList()
|
||||||
|
|
||||||
|
local wizardPages = { }
|
||||||
|
for k,v in ipairs(steps) do
|
||||||
|
if not pages[v] then
|
||||||
|
error('Invalid step: ' .. v)
|
||||||
|
end
|
||||||
|
wizardPages[k] = pages[v]
|
||||||
|
wizardPages[k].index = k
|
||||||
|
wizardPages[k].x = 2
|
||||||
|
wizardPages[k].y = 2
|
||||||
|
wizardPages[k].ey = -3
|
||||||
|
wizardPages[k].ex = -2
|
||||||
|
end
|
||||||
|
page.wizard:add(wizardPages)
|
||||||
|
|
||||||
|
if Util.key(steps, 'install') and install.preInstall then
|
||||||
|
install.preInstall(page, UI)
|
||||||
|
end
|
||||||
|
|
||||||
|
UI:setPage(page)
|
||||||
|
local s, m = pcall(function() UI:pullEvents() end)
|
||||||
|
if not s then
|
||||||
|
UI.term:reset()
|
||||||
|
_G.printError(m)
|
||||||
|
end
|
@ -1,6 +1,5 @@
|
|||||||
_G.requireInjector(_ENV)
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Event = require('event')
|
|
||||||
local History = require('history')
|
local History = require('history')
|
||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
@ -10,8 +9,10 @@ local os = _G.os
|
|||||||
local textutils = _G.textutils
|
local textutils = _G.textutils
|
||||||
local term = _G.term
|
local term = _G.term
|
||||||
|
|
||||||
|
local _exit
|
||||||
|
|
||||||
local sandboxEnv = setmetatable(Util.shallowCopy(_ENV), { __index = _G })
|
local sandboxEnv = setmetatable(Util.shallowCopy(_ENV), { __index = _G })
|
||||||
sandboxEnv.exit = function() Event.exitPullEvents() end
|
sandboxEnv.exit = function() _exit = true end
|
||||||
sandboxEnv._echo = function( ... ) return { ... } end
|
sandboxEnv._echo = function( ... ) return { ... } end
|
||||||
_G.requireInjector(sandboxEnv)
|
_G.requireInjector(sandboxEnv)
|
||||||
|
|
||||||
@ -19,7 +20,6 @@ UI:configure('Lua', ...)
|
|||||||
|
|
||||||
local command = ''
|
local command = ''
|
||||||
local history = History.load('usr/.lua_history', 25)
|
local history = History.load('usr/.lua_history', 25)
|
||||||
local extChars = Util.getVersion() > 1.76
|
|
||||||
|
|
||||||
local page = UI.Page {
|
local page = UI.Page {
|
||||||
menuBar = UI.MenuBar {
|
menuBar = UI.MenuBar {
|
||||||
@ -41,10 +41,6 @@ local page = UI.Page {
|
|||||||
[ 'control-space' ] = 'autocomplete',
|
[ 'control-space' ] = 'autocomplete',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
indicator = UI.Text {
|
|
||||||
backgroundColor = colors.black,
|
|
||||||
y = 2, x = -1, width = 1,
|
|
||||||
},
|
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
y = 3, ey = -2,
|
y = 3, ey = -2,
|
||||||
columns = {
|
columns = {
|
||||||
@ -62,21 +58,10 @@ local page = UI.Page {
|
|||||||
},
|
},
|
||||||
output = UI.Embedded {
|
output = UI.Embedded {
|
||||||
y = -6,
|
y = -6,
|
||||||
|
backgroundColor = colors.gray,
|
||||||
},
|
},
|
||||||
--notification = UI.Notification(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function page.indicator:showResult(s)
|
|
||||||
local values = {
|
|
||||||
[ true ] = { c = colors.green, i = (extChars and '\003') or '+' },
|
|
||||||
[ false ] = { c = colors.red, i = 'x' }
|
|
||||||
}
|
|
||||||
|
|
||||||
self.textColor = values[s].c
|
|
||||||
self.value = values[s].i
|
|
||||||
self:draw()
|
|
||||||
end
|
|
||||||
|
|
||||||
function page:setPrompt(value, focus)
|
function page:setPrompt(value, focus)
|
||||||
self.prompt:setValue(value)
|
self.prompt:setValue(value)
|
||||||
self.prompt.scroll = 0
|
self.prompt.scroll = 0
|
||||||
@ -133,12 +118,12 @@ end
|
|||||||
|
|
||||||
function page:eventHandler(event)
|
function page:eventHandler(event)
|
||||||
if event.type == 'global' then
|
if event.type == 'global' then
|
||||||
self:setPrompt('', true)
|
self:setPrompt('_G', true)
|
||||||
self:executeStatement('_G')
|
self:executeStatement('_G')
|
||||||
command = nil
|
command = nil
|
||||||
|
|
||||||
elseif event.type == 'local' then
|
elseif event.type == 'local' then
|
||||||
self:setPrompt('', true)
|
self:setPrompt('_ENV', true)
|
||||||
self:executeStatement('_ENV')
|
self:executeStatement('_ENV')
|
||||||
command = nil
|
command = nil
|
||||||
|
|
||||||
@ -341,8 +326,11 @@ end
|
|||||||
function page:executeStatement(statement)
|
function page:executeStatement(statement)
|
||||||
command = statement
|
command = statement
|
||||||
|
|
||||||
|
local s, m
|
||||||
local oterm = term.redirect(self.output.win)
|
local oterm = term.redirect(self.output.win)
|
||||||
local s, m = self:rawExecute(command)
|
pcall(function()
|
||||||
|
s, m = self:rawExecute(command)
|
||||||
|
end)
|
||||||
if not s then
|
if not s then
|
||||||
_G.printError(m)
|
_G.printError(m)
|
||||||
end
|
end
|
||||||
@ -353,14 +341,14 @@ function page:executeStatement(statement)
|
|||||||
else
|
else
|
||||||
self.grid:setValues({ })
|
self.grid:setValues({ })
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
if m then
|
if m and not self.output.enabled then
|
||||||
if not self.output.enabled then
|
|
||||||
self:emit({ type = 'show_output' })
|
self:emit({ type = 'show_output' })
|
||||||
end
|
end
|
||||||
--self.notification:error(m, 5)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if _exit then
|
||||||
|
UI:exitPullEvents()
|
||||||
end
|
end
|
||||||
self.indicator:showResult(not not s)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local args = { ... }
|
local args = { ... }
|
||||||
@ -371,5 +359,4 @@ if args[1] then
|
|||||||
end
|
end
|
||||||
|
|
||||||
UI:setPage(page)
|
UI:setPage(page)
|
||||||
Event.pullEvents()
|
UI:pullEvents()
|
||||||
UI.term:reset()
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local class = require('class')
|
local class = require('class')
|
||||||
local Config = require('config')
|
local Config = require('config')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Config = require('config')
|
local Config = require('config')
|
||||||
local Security = require('security')
|
local Security = require('security')
|
||||||
@ -201,9 +201,13 @@ end
|
|||||||
if settings then
|
if settings then
|
||||||
local values = { }
|
local values = { }
|
||||||
for _,v in pairs(settings.getNames()) do
|
for _,v in pairs(settings.getNames()) do
|
||||||
|
local value = settings.get(v)
|
||||||
|
if not value then
|
||||||
|
value = false
|
||||||
|
end
|
||||||
table.insert(values, {
|
table.insert(values, {
|
||||||
name = v,
|
name = v,
|
||||||
value = not not settings.get(v),
|
value = value,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -224,7 +228,9 @@ if settings then
|
|||||||
})
|
})
|
||||||
function systemPage.tabs.settingsTab:eventHandler(event)
|
function systemPage.tabs.settingsTab:eventHandler(event)
|
||||||
if event.type == 'grid_select' then
|
if event.type == 'grid_select' then
|
||||||
|
if not event.selected.value or type(event.selected.value) == 'boolean' then
|
||||||
event.selected.value = not event.selected.value
|
event.selected.value = not event.selected.value
|
||||||
|
end
|
||||||
settings.set(event.selected.name, event.selected.value)
|
settings.set(event.selected.name, event.selected.value)
|
||||||
settings.save('.settings')
|
settings.save('.settings')
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
|
@ -58,11 +58,7 @@ function page.grid:getDisplayValues(row)
|
|||||||
else
|
else
|
||||||
row.timestamp = string.format("%sm", math.floor(elapsed/6)/10)
|
row.timestamp = string.format("%sm", math.floor(elapsed/6)/10)
|
||||||
end
|
end
|
||||||
if row.isDead then
|
row.status = row.isDead and 'error' or coroutine.status(row.co)
|
||||||
row.status = 'error'
|
|
||||||
else
|
|
||||||
row.status = coroutine.status(row.co)
|
|
||||||
end
|
|
||||||
return row
|
return row
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Security = require('security')
|
local Security = require('security')
|
||||||
local SHA1 = require('sha1')
|
local SHA1 = require('sha1')
|
||||||
|
170
sys/apps/shell
170
sys/apps/shell
@ -11,7 +11,7 @@ for k,v in pairs(_ENV) do
|
|||||||
end
|
end
|
||||||
sandboxEnv.shell = shell
|
sandboxEnv.shell = shell
|
||||||
|
|
||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
@ -118,6 +118,10 @@ function shell.resolveProgram( _sCommand )
|
|||||||
_sCommand = tAliases[_sCommand]
|
_sCommand = tAliases[_sCommand]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if _sCommand:match("^(https?:)") then
|
||||||
|
return _sCommand
|
||||||
|
end
|
||||||
|
|
||||||
local path = shell.resolve(_sCommand)
|
local path = shell.resolve(_sCommand)
|
||||||
if fs.exists(path) and not fs.isDir(path) then
|
if fs.exists(path) and not fs.isDir(path) then
|
||||||
return path
|
return path
|
||||||
@ -325,10 +329,8 @@ function shell.openTab( ... )
|
|||||||
local sPath = shell.resolveProgram(sCommand)
|
local sPath = shell.resolveProgram(sCommand)
|
||||||
if sPath == "sys/apps/shell" then
|
if sPath == "sys/apps/shell" then
|
||||||
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), sPath, table.unpack(tWords, 2))
|
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), sPath, table.unpack(tWords, 2))
|
||||||
elseif sPath ~= nil then
|
|
||||||
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), "sys/apps/shell", sCommand, table.unpack(tWords, 2))
|
|
||||||
else
|
else
|
||||||
return false, "No such program"
|
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), "sys/apps/shell", sCommand, table.unpack(tWords, 2))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -352,11 +354,12 @@ if #tArgs > 0 then
|
|||||||
end
|
end
|
||||||
|
|
||||||
local Config = require('config')
|
local Config = require('config')
|
||||||
|
local Entry = require('entry')
|
||||||
local History = require('history')
|
local History = require('history')
|
||||||
|
local Input = require('input')
|
||||||
local Terminal = require('terminal')
|
local Terminal = require('terminal')
|
||||||
|
|
||||||
local colors = _G.colors
|
local colors = _G.colors
|
||||||
local keys = _G.keys
|
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
local term = _G.term
|
local term = _G.term
|
||||||
local textutils = _G.textutils
|
local textutils = _G.textutils
|
||||||
@ -538,128 +541,81 @@ local function autocomplete(line)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function shellRead(history)
|
local function shellRead(history)
|
||||||
term.setCursorBlink( true )
|
local lastLen = 0
|
||||||
|
local entry = Entry({
|
||||||
local sLine = ""
|
width = term.getSize() - 3
|
||||||
local nPos = 0
|
})
|
||||||
|
|
||||||
local w = term.getSize()
|
|
||||||
local sx = term.getCursorPos()
|
|
||||||
|
|
||||||
history:reset()
|
history:reset()
|
||||||
|
term.setCursorBlink(true)
|
||||||
|
|
||||||
local function redraw( sReplace )
|
local function redraw()
|
||||||
local nScroll = 0
|
|
||||||
if sx + nPos >= w then
|
|
||||||
nScroll = (sx + nPos) - w
|
|
||||||
end
|
|
||||||
|
|
||||||
local _,cy = term.getCursorPos()
|
local _,cy = term.getCursorPos()
|
||||||
term.setCursorPos( sx, cy )
|
term.setCursorPos(3, cy)
|
||||||
if sReplace then
|
local filler = #entry.value < lastLen
|
||||||
term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) )
|
and string.rep(' ', lastLen - #entry.value)
|
||||||
else
|
or ''
|
||||||
term.write( string.sub( sLine, nScroll + 1 ) )
|
local str = string.sub(entry.value, entry.scroll + 1)
|
||||||
end
|
term.write(string.sub(str, 1, entry.width) .. filler)
|
||||||
term.setCursorPos( sx + nPos - nScroll, cy )
|
term.setCursorPos(3 + entry.pos - entry.scroll, cy)
|
||||||
|
lastLen = #entry.value
|
||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local sEvent, param = os.pullEventRaw()
|
local event, p1, p2, p3 = os.pullEventRaw()
|
||||||
|
|
||||||
if sEvent == "char" then
|
local ie = Input:translate(event, p1, p2, p3)
|
||||||
sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
|
if ie then
|
||||||
nPos = nPos + 1
|
if ie.code == 'scroll_up' then
|
||||||
redraw()
|
|
||||||
elseif sEvent == "paste" then
|
|
||||||
sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
|
|
||||||
nPos = nPos + string.len( param )
|
|
||||||
redraw()
|
|
||||||
elseif sEvent == 'mouse_click' and param == 2 then
|
|
||||||
redraw(string.rep(' ', #sLine))
|
|
||||||
sLine = ''
|
|
||||||
nPos = 0
|
|
||||||
redraw()
|
|
||||||
elseif sEvent == 'mouse_scroll' then
|
|
||||||
if param == -1 then
|
|
||||||
terminal.scrollUp()
|
terminal.scrollUp()
|
||||||
else
|
|
||||||
|
elseif ie.code == 'scroll_down' then
|
||||||
terminal.scrollDown()
|
terminal.scrollDown()
|
||||||
end
|
|
||||||
elseif sEvent == 'terminate' then
|
elseif ie.code == 'terminate' then
|
||||||
bExit = true
|
bExit = true
|
||||||
break
|
break
|
||||||
elseif sEvent == "key" then
|
|
||||||
if param == keys.enter then
|
elseif ie.code == 'enter' then
|
||||||
-- Enter
|
|
||||||
break
|
break
|
||||||
elseif param == keys.tab then
|
|
||||||
if nPos == #sLine then
|
elseif ie.code == 'up' or ie.code == 'down' then
|
||||||
local cline = autocomplete(sLine)
|
if ie.code == 'up' then
|
||||||
|
entry.value = history:back() or ''
|
||||||
|
else
|
||||||
|
entry.value = history:forward() or ''
|
||||||
|
end
|
||||||
|
entry.pos = string.len(entry.value)
|
||||||
|
entry.scroll = 0
|
||||||
|
entry:updateScroll()
|
||||||
|
redraw()
|
||||||
|
|
||||||
|
elseif ie.code == 'tab' then
|
||||||
|
if entry.pos == #entry.value then
|
||||||
|
local cline = autocomplete(entry.value)
|
||||||
if cline then
|
if cline then
|
||||||
sLine = cline
|
entry.value = cline
|
||||||
nPos = #sLine
|
entry.pos = #entry.value
|
||||||
redraw()
|
entry:updateScroll()
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif param == keys.left then
|
|
||||||
if nPos > 0 then
|
|
||||||
nPos = nPos - 1
|
|
||||||
redraw()
|
|
||||||
end
|
|
||||||
elseif param == keys.right then
|
|
||||||
if nPos < string.len(sLine) then
|
|
||||||
redraw(" ")
|
|
||||||
nPos = nPos + 1
|
|
||||||
redraw()
|
|
||||||
end
|
|
||||||
elseif param == keys.up or param == keys.down then
|
|
||||||
redraw(" ")
|
|
||||||
if param == keys.up then
|
|
||||||
sLine = history:back()
|
|
||||||
else
|
|
||||||
sLine = history:forward()
|
|
||||||
end
|
|
||||||
if sLine then
|
|
||||||
nPos = string.len(sLine)
|
|
||||||
else
|
|
||||||
sLine = ""
|
|
||||||
nPos = 0
|
|
||||||
end
|
|
||||||
redraw()
|
|
||||||
elseif param == keys.backspace then
|
|
||||||
if nPos > 0 then
|
|
||||||
redraw(" ")
|
|
||||||
sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
|
|
||||||
nPos = nPos - 1
|
|
||||||
redraw()
|
|
||||||
end
|
|
||||||
elseif param == keys.home then
|
|
||||||
redraw(" ")
|
|
||||||
nPos = 0
|
|
||||||
redraw()
|
|
||||||
elseif param == keys.delete then
|
|
||||||
if nPos < string.len(sLine) then
|
|
||||||
redraw(" ")
|
|
||||||
sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
|
|
||||||
redraw()
|
|
||||||
end
|
|
||||||
elseif param == keys["end"] then
|
|
||||||
redraw(" ")
|
|
||||||
nPos = string.len(sLine)
|
|
||||||
redraw()
|
|
||||||
end
|
|
||||||
elseif sEvent == "term_resize" then
|
|
||||||
w = term.getSize()
|
|
||||||
redraw()
|
redraw()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local _, cy = term.getCursorPos()
|
elseif entry:process(ie) then
|
||||||
term.setCursorPos( w + 1, cy )
|
redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif event == "term_resize" then
|
||||||
|
entry.width = term.getSize() - 3
|
||||||
|
redraw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--local _, cy = term.getCursorPos()
|
||||||
|
--term.setCursorPos( w + 1, cy )
|
||||||
print()
|
print()
|
||||||
term.setCursorBlink( false )
|
term.setCursorBlink( false )
|
||||||
return sLine
|
return entry.value
|
||||||
end
|
end
|
||||||
|
|
||||||
local history = History.load('usr/.shell_history', 25)
|
local history = History.load('usr/.shell_history', 25)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local Socket = require('socket')
|
local Socket = require('socket')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Crypto = require('crypto')
|
local Crypto = require('crypto')
|
||||||
local Security = require('security')
|
local Security = require('security')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local Socket = require('socket')
|
local Socket = require('socket')
|
||||||
|
@ -13,13 +13,13 @@ kernel.hook('clipboard_copy', function(_, args)
|
|||||||
data = args[1]
|
data = args[1]
|
||||||
end)
|
end)
|
||||||
|
|
||||||
keyboard.addHotkey('control-shift-paste', function(_, args)
|
keyboard.addHotkey('shift-paste', function()
|
||||||
if type(data) == 'table' then
|
if type(data) == 'table' then
|
||||||
local s, m = pcall(textutils.serialize, data)
|
local s, m = pcall(textutils.serialize, data)
|
||||||
data = (s and m) or Util.tostring(data)
|
data = (s and m) or Util.tostring(data)
|
||||||
end
|
end
|
||||||
-- replace the event paste data with our internal data
|
-- replace the event paste data with our internal data
|
||||||
args[1] = Util.tostring(data or '')
|
-- args[1] = Util.tostring(data or '')
|
||||||
if data then
|
if data then
|
||||||
os.queueEvent('paste', data)
|
os.queueEvent('paste', data)
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,7 @@ local turtle = _G.turtle
|
|||||||
if turtle and modem then
|
if turtle and modem then
|
||||||
local s, m = turtle.run(function()
|
local s, m = turtle.run(function()
|
||||||
|
|
||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Config = require('config')
|
local Config = require('config')
|
||||||
local config = {
|
local config = {
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
if _G.device.wireless_modem then
|
if _G.device.wireless_modem then
|
||||||
|
|
||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
local Config = require('config')
|
local Config = require('config')
|
||||||
|
|
||||||
|
local kernel = _G.kernel
|
||||||
|
|
||||||
local config = { }
|
local config = { }
|
||||||
Config.load('gps', config)
|
Config.load('gps', config)
|
||||||
|
|
||||||
if config.host and type(config.host) == 'table' then
|
if config.host and type(config.host) == 'table' then
|
||||||
_ENV._APP_TITLE = 'GPS Daemon'
|
kernel.run({
|
||||||
os.run(_ENV, '/rom/programs/gps', 'host', config.host.x, config.host.y, config.host.z)
|
title = 'GPS Daemon',
|
||||||
print('GPS daemon stopped')
|
hidden = true,
|
||||||
|
path = '/rom/programs/gps',
|
||||||
|
args = { 'host', config.host.x, config.host.y, config.host.z },
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ local multishell = _ENV.multishell
|
|||||||
keyboard.addHotkey('control-o', function()
|
keyboard.addHotkey('control-o', function()
|
||||||
for _,tab in pairs(multishell.getTabs()) do
|
for _,tab in pairs(multishell.getTabs()) do
|
||||||
if tab.isOverview then
|
if tab.isOverview then
|
||||||
multishell.setFocus(tab.tabId)
|
multishell.setFocus(tab.uid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -10,11 +10,8 @@ local multishell = _ENV.multishell
|
|||||||
local os = _G.os
|
local os = _G.os
|
||||||
local term = _G.term
|
local term = _G.term
|
||||||
|
|
||||||
|
local function systemLog()
|
||||||
local routine = kernel.getCurrent()
|
local routine = kernel.getCurrent()
|
||||||
if multishell then
|
|
||||||
multishell.setTitle(multishell.getCurrent(), 'System Log')
|
|
||||||
multishell.hideTab(routine.uid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local w, h = kernel.window.getSize()
|
local w, h = kernel.window.getSize()
|
||||||
kernel.window.reposition(1, 2, w, h - 1)
|
kernel.window.reposition(1, 2, w, h - 1)
|
||||||
@ -49,3 +46,10 @@ end)
|
|||||||
|
|
||||||
os.pullEventRaw('terminate')
|
os.pullEventRaw('terminate')
|
||||||
keyboard.removeHotkey('control-d')
|
keyboard.removeHotkey('control-d')
|
||||||
|
end
|
||||||
|
|
||||||
|
multishell.openTab({
|
||||||
|
title = 'System Log',
|
||||||
|
fn = systemLog,
|
||||||
|
hidden = true,
|
||||||
|
})
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
term.clear()
|
|
||||||
term.setCursorPos(1, 1)
|
|
||||||
print(os.version())
|
|
@ -70,8 +70,8 @@ kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData)
|
|||||||
-- and fire hotkeys
|
-- and fire hotkeys
|
||||||
local hotkey = Input:translate(event, eventData[1], eventData[2])
|
local hotkey = Input:translate(event, eventData[1], eventData[2])
|
||||||
|
|
||||||
if hotkey and keyboard.hotkeys[hotkey] then
|
if hotkey and keyboard.hotkeys[hotkey.code] then
|
||||||
keyboard.hotkeys[hotkey](event, eventData)
|
keyboard.hotkeys[hotkey.code](event, eventData)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ if fs.native then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
local fs = _G.fs
|
local fs = _G.fs
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ if not _G.turtle then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Pathing = require('turtle.pathfind')
|
local Pathing = require('turtle.pathfind')
|
||||||
local GPS = require('gps')
|
local GPS = require('gps')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
_G.requireInjector()
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local Config = require('config')
|
local Config = require('config')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
@ -199,6 +199,10 @@ kernel.hook('multishell_terminate', function(_, eventData)
|
|||||||
return true
|
return true
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
kernel.hook('terminate', function()
|
||||||
|
return kernel.getFocused().isOverview
|
||||||
|
end)
|
||||||
|
|
||||||
kernel.hook('multishell_redraw', function()
|
kernel.hook('multishell_redraw', function()
|
||||||
tabsDirty = false
|
tabsDirty = false
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user