mirror of https://github.com/kepler155c/opus
partition manager + tab/wizard rework
This commit is contained in:
parent
b0d2ce0199
commit
ef9f0e09b6
|
@ -45,8 +45,9 @@ local page = UI.Page {
|
||||||
},
|
},
|
||||||
tabs = UI.Tabs {
|
tabs = UI.Tabs {
|
||||||
y = 3,
|
y = 3,
|
||||||
[1] = UI.Tab {
|
formatted = UI.Tab {
|
||||||
tabTitle = 'Formatted',
|
title = 'Formatted',
|
||||||
|
index = 1,
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Key', key = 'name' },
|
{ heading = 'Key', key = 'name' },
|
||||||
|
@ -56,8 +57,9 @@ local page = UI.Page {
|
||||||
autospace = true,
|
autospace = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[2] = UI.Tab {
|
output = UI.Tab {
|
||||||
tabTitle = 'Output',
|
title = 'Output',
|
||||||
|
index = 2,
|
||||||
backgroundColor = 'black',
|
backgroundColor = 'black',
|
||||||
output = UI.Embedded {
|
output = UI.Embedded {
|
||||||
y = 2,
|
y = 2,
|
||||||
|
@ -72,8 +74,8 @@ local page = UI.Page {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
page.grid = page.tabs[1].grid
|
page.grid = page.tabs.formatted.grid
|
||||||
page.output = page.tabs[2].output
|
page.output = page.tabs.output.output
|
||||||
|
|
||||||
function page:setPrompt(value, focus)
|
function page:setPrompt(value, focus)
|
||||||
self.prompt:setValue(value)
|
self.prompt:setValue(value)
|
||||||
|
@ -142,7 +144,7 @@ function page:eventHandler(event)
|
||||||
self:setFocus(self.prompt)
|
self:setFocus(self.prompt)
|
||||||
|
|
||||||
elseif event.type == 'show_output' then
|
elseif event.type == 'show_output' then
|
||||||
self.tabs:selectTab(self.tabs[2])
|
self.tabs:selectTab(self.tabs.output)
|
||||||
|
|
||||||
elseif event.type == 'autocomplete' then
|
elseif event.type == 'autocomplete' then
|
||||||
local value = self.prompt.value or ''
|
local value = self.prompt.value or ''
|
||||||
|
|
|
@ -29,12 +29,14 @@ if not _ENV.multishell then
|
||||||
end
|
end
|
||||||
|
|
||||||
local REGISTRY_DIR = 'usr/.registry'
|
local REGISTRY_DIR = 'usr/.registry'
|
||||||
local DEFAULT_ICON = NFT.parse("\0308\0317\153\153\153\153\153\
|
|
||||||
\0307\0318\153\153\153\153\153\
|
-- icon:gsub('.', function(b) return '\\' .. b:byte() end)
|
||||||
\0308\0317\153\153\153\153\153")
|
local DEFAULT_ICON = NFT.parse('\30\55\31\48\136\140\140\140\132\
|
||||||
local TRANS_ICON = NFT.parse("\0302\0312\32\32\32\32\32\
|
\30\48\31\55\149\31\48\128\128\128\30\55\149\
|
||||||
|
\30\55\31\48\138\143\143\143\133')
|
||||||
|
local TRANS_ICON = NFT.parse('\0302\0312\32\32\32\32\32\
|
||||||
\0302\0312\32\32\32\32\32\
|
\0302\0312\32\32\32\32\32\
|
||||||
\0302\0312\32\32\32\32\32")
|
\0302\0312\32\32\32\32\32')
|
||||||
|
|
||||||
-- overview
|
-- overview
|
||||||
local uid = _ENV.multishell.getCurrent()
|
local uid = _ENV.multishell.getCurrent()
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
local Ansi = require('opus.ansi')
|
||||||
|
local Event = require('opus.event')
|
||||||
|
local UI = require('opus.ui')
|
||||||
|
local Util = require('opus.util')
|
||||||
|
|
||||||
|
local fs = _G.fs
|
||||||
|
local peripheral = _G.peripheral
|
||||||
|
|
||||||
|
local source, target
|
||||||
|
|
||||||
|
local function getDriveInfo(tgt)
|
||||||
|
local total = 0
|
||||||
|
local throttle = Util.throttle()
|
||||||
|
|
||||||
|
tgt = fs.combine(tgt, '')
|
||||||
|
local src = fs.getNode(tgt).source or tgt
|
||||||
|
|
||||||
|
local function recurse(path)
|
||||||
|
throttle()
|
||||||
|
if fs.isDir(path) then
|
||||||
|
if path ~= src then
|
||||||
|
total = total + 500
|
||||||
|
end
|
||||||
|
for _, v in pairs(fs.native.list(path)) do
|
||||||
|
recurse(fs.combine(path, v))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local sz = fs.getSize(path)
|
||||||
|
total = total + math.max(500, sz)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
recurse(src)
|
||||||
|
|
||||||
|
local drive = fs.getDrive(src)
|
||||||
|
return {
|
||||||
|
path = tgt,
|
||||||
|
drive = drive,
|
||||||
|
type = peripheral.getType(drive) or drive,
|
||||||
|
used = total,
|
||||||
|
free = fs.getFreeSpace(src),
|
||||||
|
mountPoint = src,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getDrives(exclude)
|
||||||
|
local drives = { }
|
||||||
|
|
||||||
|
for _, path in pairs(fs.native.list('/')) do
|
||||||
|
local side = fs.getDrive(path)
|
||||||
|
if side and not drives[side] and not fs.isReadOnly(path) and side ~= exclude then
|
||||||
|
if side == 'hdd' then
|
||||||
|
path = ''
|
||||||
|
end
|
||||||
|
drives[side] = getDriveInfo(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return drives
|
||||||
|
end
|
||||||
|
|
||||||
|
local page = UI.Page {
|
||||||
|
wizard = UI.Wizard {
|
||||||
|
ey = -2,
|
||||||
|
partitions = UI.WizardPage {
|
||||||
|
index = 1,
|
||||||
|
info = UI.TextArea {
|
||||||
|
x = 3, y = 2, ex = -3, ey = 5,
|
||||||
|
value = [[Move the contents of a directory to another disk. A link will be created to point to that location.]]
|
||||||
|
},
|
||||||
|
grid = UI.Grid {
|
||||||
|
x = 2, y = 7, ex = -2, ey = -2,
|
||||||
|
columns = {
|
||||||
|
{ heading = 'Path', key = 'path', textColor = 'yellow', width = 10 },
|
||||||
|
{ heading = 'Mount Point', key = 'mountPoint' },
|
||||||
|
{ heading = 'Used', key = 'used', width = 6 },
|
||||||
|
},
|
||||||
|
sortColumn = 'path',
|
||||||
|
getDisplayValues = function (_, row)
|
||||||
|
row = Util.shallowCopy(row)
|
||||||
|
row.used = Util.toBytes(row.used)
|
||||||
|
return row
|
||||||
|
end,
|
||||||
|
enable = function(self)
|
||||||
|
Event.onTimeout(0, function()
|
||||||
|
local mounts = {
|
||||||
|
usr = getDriveInfo('usr/config'),
|
||||||
|
packages = getDriveInfo('packages'),
|
||||||
|
}
|
||||||
|
self:setValues(mounts)
|
||||||
|
self:draw()
|
||||||
|
self:sync()
|
||||||
|
end)
|
||||||
|
self:setValues({ })
|
||||||
|
UI.Grid.enable(self)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
validate = function(self)
|
||||||
|
target = self.grid:getSelected()
|
||||||
|
return not not target
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
mounts = UI.WizardPage {
|
||||||
|
index = 2,
|
||||||
|
info = UI.TextArea {
|
||||||
|
x = 3, y = 2, ex = -3, ey = 5,
|
||||||
|
value = [[Select the target disk. Labeled computers can be inserted into disk drives for larger volumes.]]
|
||||||
|
},
|
||||||
|
grid = UI.Grid {
|
||||||
|
x = 2, y = 7, ex = -2, ey = -2,
|
||||||
|
columns = {
|
||||||
|
{ heading = 'Path', key = 'path', textColor = 'yellow', width = 10 },
|
||||||
|
{ heading = 'Type', key = 'type' },
|
||||||
|
{ heading = 'Side', key = 'drive' },
|
||||||
|
{ heading = 'Free', key = 'free', width = 6 },
|
||||||
|
},
|
||||||
|
sortColumn = 'path',
|
||||||
|
getDisplayValues = function (_, row)
|
||||||
|
row = Util.shallowCopy(row)
|
||||||
|
row.free = Util.toBytes(row.free)
|
||||||
|
return row
|
||||||
|
end,
|
||||||
|
getRowTextColor = function(self, row)
|
||||||
|
if row.free < target.used then
|
||||||
|
return 'lightGray'
|
||||||
|
end
|
||||||
|
return UI.Grid.getRowTextColor(self, row)
|
||||||
|
end,
|
||||||
|
enable = function(self)
|
||||||
|
Event.on({ 'disk', 'disk_eject', 'partition_update' }, function()
|
||||||
|
self:setValues(getDrives(target.drive))
|
||||||
|
self:draw()
|
||||||
|
self:sync()
|
||||||
|
end)
|
||||||
|
os.queueEvent('partition_update')
|
||||||
|
self:setValues({ })
|
||||||
|
UI.Grid.enable(self)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
validate = function(self)
|
||||||
|
source = self.grid:getSelected()
|
||||||
|
if not source then
|
||||||
|
self:emit({ type = 'notify', message = 'No drive selected' })
|
||||||
|
elseif source.free < target.used then
|
||||||
|
self:emit({ type = 'notify', message = 'Insufficient disk space' })
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
confirm = UI.WizardPage {
|
||||||
|
index = 3,
|
||||||
|
info = UI.TextArea {
|
||||||
|
x = 2, y = 2, ex = -2, ey = -2,
|
||||||
|
marginTop = 1, marginLeft = 1,
|
||||||
|
backgroundColor = 'black',
|
||||||
|
},
|
||||||
|
enable = function(self)
|
||||||
|
local fstab = Util.readFile('usr/etc/fstab')
|
||||||
|
local lines = { }
|
||||||
|
table.insert(lines, string.format('%sReview changes%s\n', Ansi.yellow, Ansi.reset))
|
||||||
|
if fstab then
|
||||||
|
for _,l in ipairs(Util.split(fstab)) do
|
||||||
|
l = Util.trim(l)
|
||||||
|
if #l > 0 and l:sub(1, 1) ~= '#' then
|
||||||
|
local m = Util.matches(l)
|
||||||
|
if m and m[1] and m[1] == target.path then
|
||||||
|
table.insert(lines, string.format('Removed from usr/etc/fstab:\n%s%s%s\n', Ansi.red, l, Ansi.reset))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local t = target.path
|
||||||
|
local s = fs.combine(source.path .. '/' .. target.path, '')
|
||||||
|
if t ~= s then
|
||||||
|
table.insert(lines, string.format('Added to usr/etc/fstab:\n%s%s linkfs %s%s\n', Ansi.green, t, s, Ansi.reset))
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(lines, string.format('Move directory:\n%s/%s -> /%s', Ansi.green, target.mountPoint, s))
|
||||||
|
|
||||||
|
self.info:setText(table.concat(lines, '\n'))
|
||||||
|
UI.WizardPage.enable(self)
|
||||||
|
end,
|
||||||
|
validate = function(self)
|
||||||
|
if self.changesApplied then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local fstab = Util.readFile('usr/etc/fstab')
|
||||||
|
local lines = { }
|
||||||
|
if fstab then
|
||||||
|
for _,l in ipairs(Util.split(fstab)) do
|
||||||
|
table.insert(lines, l)
|
||||||
|
l = Util.trim(l)
|
||||||
|
if #l > 0 and l:sub(1, 1) ~= '#' then
|
||||||
|
local m = Util.matches(l)
|
||||||
|
if m and m[1] and m[1] == target.path then
|
||||||
|
fs.unmount(m[1])
|
||||||
|
table.remove(lines)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = target.path
|
||||||
|
local s = fs.combine(source.path .. '/' .. target.path, '')
|
||||||
|
|
||||||
|
fs.move('/' .. target.mountPoint, '/' .. s)
|
||||||
|
|
||||||
|
if t ~= s then
|
||||||
|
table.insert(lines, string.format('%s linkfs %s', t, s))
|
||||||
|
fs.mount(t, 'linkfs', s)
|
||||||
|
end
|
||||||
|
|
||||||
|
Util.writeFile('usr/etc/fstab', table.concat(lines, '\n'))
|
||||||
|
|
||||||
|
self.parent.nextButton.text = 'Exit'
|
||||||
|
self.parent.cancelButton:disable()
|
||||||
|
self.parent.previousButton:disable()
|
||||||
|
|
||||||
|
self.changesApplied = true
|
||||||
|
self.info:setValue('Changes have been applied')
|
||||||
|
self.parent:draw()
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
notification = UI.Notification { },
|
||||||
|
eventHandler = function(self, event)
|
||||||
|
if event.type == 'notify' then
|
||||||
|
self.notification:error(event.message)
|
||||||
|
elseif event.type == 'accept' or event.type == 'cancel' then
|
||||||
|
UI:quit()
|
||||||
|
end
|
||||||
|
return UI.Page.eventHandler(self, event)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
UI:disableEffects()
|
||||||
|
UI:setPage(page)
|
||||||
|
UI:start()
|
|
@ -46,7 +46,7 @@ local page = UI.Page {
|
||||||
configTabs = UI.Tabs {
|
configTabs = UI.Tabs {
|
||||||
y = 2,
|
y = 2,
|
||||||
filterTab = UI.Tab {
|
filterTab = UI.Tab {
|
||||||
tabTitle = 'Filter',
|
title = 'Filter',
|
||||||
noFill = true,
|
noFill = true,
|
||||||
filterGridText = UI.Text {
|
filterGridText = UI.Text {
|
||||||
x = 2, y = 2,
|
x = 2, y = 2,
|
||||||
|
@ -93,7 +93,7 @@ local page = UI.Page {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
modemTab = UI.Tab {
|
modemTab = UI.Tab {
|
||||||
tabTitle = 'Modem',
|
title = 'Modem',
|
||||||
channelGrid = UI.ScrollingGrid {
|
channelGrid = UI.ScrollingGrid {
|
||||||
x = 2, y = 2,
|
x = 2, y = 2,
|
||||||
width = 12, height = 5,
|
width = 12, height = 5,
|
||||||
|
|
|
@ -6,62 +6,6 @@ local shell = _ENV.shell
|
||||||
|
|
||||||
UI:configure('System', ...)
|
UI:configure('System', ...)
|
||||||
|
|
||||||
local systemPage = UI.Page {
|
|
||||||
tabs = UI.Tabs {
|
|
||||||
settings = UI.Tab {
|
|
||||||
tabTitle = 'Category',
|
|
||||||
grid = UI.ScrollingGrid {
|
|
||||||
x = 2, y = 2, ex = -2, ey = -2,
|
|
||||||
columns = {
|
|
||||||
{ heading = 'Name', key = 'name' },
|
|
||||||
{ heading = 'Description', key = 'description' },
|
|
||||||
},
|
|
||||||
sortColumn = 'name',
|
|
||||||
autospace = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
notification = UI.Notification(),
|
|
||||||
accelerators = {
|
|
||||||
[ 'control-q' ] = 'quit',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
function systemPage.tabs.settings:eventHandler(event)
|
|
||||||
if event.type == 'grid_select' then
|
|
||||||
local tab = event.selected.tab
|
|
||||||
if not systemPage.tabs[tab.tabTitle] then
|
|
||||||
systemPage.tabs:add({ [ tab.tabTitle ] = tab })
|
|
||||||
tab:disable()
|
|
||||||
end
|
|
||||||
systemPage.tabs:selectTab(tab)
|
|
||||||
--self.parent:draw()
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function systemPage:eventHandler(event)
|
|
||||||
if event.type == 'quit' then
|
|
||||||
UI:quit()
|
|
||||||
|
|
||||||
elseif event.type == 'success_message' then
|
|
||||||
self.notification:success(event.message)
|
|
||||||
|
|
||||||
elseif event.type == 'info_message' then
|
|
||||||
self.notification:info(event.message)
|
|
||||||
|
|
||||||
elseif event.type == 'error_message' then
|
|
||||||
self.notification:error(event.message)
|
|
||||||
|
|
||||||
elseif event.type == 'tab_activate' then
|
|
||||||
event.activated:focusFirst()
|
|
||||||
|
|
||||||
else
|
|
||||||
return UI.Page.eventHandler(self, event)
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function loadDirectory(dir)
|
local function loadDirectory(dir)
|
||||||
local plugins = { }
|
local plugins = { }
|
||||||
for _, file in pairs(fs.list(dir)) do
|
for _, file in pairs(fs.list(dir)) do
|
||||||
|
@ -70,7 +14,7 @@ local function loadDirectory(dir)
|
||||||
_G.printError('Error loading: ' .. file)
|
_G.printError('Error loading: ' .. file)
|
||||||
error(m or 'Unknown error')
|
error(m or 'Unknown error')
|
||||||
elseif s and m then
|
elseif s and m then
|
||||||
table.insert(plugins, { tab = m, name = m.tabTitle, description = m.description })
|
table.insert(plugins, { tab = m, name = m.title, description = m.description })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return plugins
|
return plugins
|
||||||
|
@ -79,7 +23,60 @@ end
|
||||||
local programDir = fs.getDir(shell.getRunningProgram())
|
local programDir = fs.getDir(shell.getRunningProgram())
|
||||||
local plugins = loadDirectory(fs.combine(programDir, 'system'), { })
|
local plugins = loadDirectory(fs.combine(programDir, 'system'), { })
|
||||||
|
|
||||||
systemPage.tabs.settings.grid:setValues(plugins)
|
local page = UI.Page {
|
||||||
|
tabs = UI.Tabs {
|
||||||
|
settings = UI.Tab {
|
||||||
|
title = 'Category',
|
||||||
|
grid = UI.ScrollingGrid {
|
||||||
|
x = 2, y = 2, ex = -2, ey = -2,
|
||||||
|
columns = {
|
||||||
|
{ heading = 'Name', key = 'name' },
|
||||||
|
{ heading = 'Description', key = 'description' },
|
||||||
|
},
|
||||||
|
sortColumn = 'name',
|
||||||
|
autospace = true,
|
||||||
|
values = plugins,
|
||||||
|
},
|
||||||
|
accelerators = {
|
||||||
|
grid_select = 'category_select',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
notification = UI.Notification(),
|
||||||
|
accelerators = {
|
||||||
|
[ 'control-q' ] = 'quit',
|
||||||
|
},
|
||||||
|
eventHandler = function(self, event)
|
||||||
|
if event.type == 'quit' then
|
||||||
|
UI:quit()
|
||||||
|
|
||||||
UI:setPage(systemPage)
|
elseif event.type == 'category_select' then
|
||||||
|
local tab = event.selected.tab
|
||||||
|
|
||||||
|
if not self.tabs[tab.title] then
|
||||||
|
self.tabs:add({ [ tab.title ] = tab })
|
||||||
|
end
|
||||||
|
self.tabs:selectTab(tab)
|
||||||
|
return true
|
||||||
|
|
||||||
|
elseif event.type == 'success_message' then
|
||||||
|
self.notification:success(event.message)
|
||||||
|
|
||||||
|
elseif event.type == 'info_message' then
|
||||||
|
self.notification:info(event.message)
|
||||||
|
|
||||||
|
elseif event.type == 'error_message' then
|
||||||
|
self.notification:error(event.message)
|
||||||
|
|
||||||
|
elseif event.type == 'tab_activate' then
|
||||||
|
event.activated:focusFirst()
|
||||||
|
|
||||||
|
else
|
||||||
|
return UI.Page.eventHandler(self, event)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
UI:setPage(page)
|
||||||
UI:start()
|
UI:start()
|
||||||
|
|
|
@ -33,87 +33,85 @@ https://github.com/kepler155c/opus]]
|
||||||
local page = UI.Page {
|
local page = UI.Page {
|
||||||
wizard = UI.Wizard {
|
wizard = UI.Wizard {
|
||||||
ey = -2,
|
ey = -2,
|
||||||
pages = {
|
splash = UI.WizardPage {
|
||||||
splash = UI.WizardPage {
|
index = 1,
|
||||||
index = 1,
|
intro = UI.TextArea {
|
||||||
intro = UI.TextArea {
|
textColor = colors.yellow,
|
||||||
textColor = colors.yellow,
|
inactive = true,
|
||||||
inactive = true,
|
x = 3, ex = -3, y = 2, ey = -2,
|
||||||
x = 3, ex = -3, y = 2, ey = -2,
|
value = string.format(splashIntro, Ansi.white),
|
||||||
value = string.format(splashIntro, Ansi.white),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
label = UI.WizardPage {
|
},
|
||||||
index = 2,
|
label = UI.WizardPage {
|
||||||
labelText = UI.Text {
|
index = 2,
|
||||||
x = 3, y = 2,
|
labelText = UI.Text {
|
||||||
value = 'Label'
|
x = 3, y = 2,
|
||||||
},
|
value = 'Label'
|
||||||
label = UI.TextEntry {
|
|
||||||
x = 9, y = 2, ex = -3,
|
|
||||||
limit = 32,
|
|
||||||
value = os.getComputerLabel(),
|
|
||||||
},
|
|
||||||
intro = UI.TextArea {
|
|
||||||
textColor = colors.yellow,
|
|
||||||
inactive = true,
|
|
||||||
x = 3, ex = -3, y = 4, ey = -3,
|
|
||||||
value = string.format(labelIntro, Ansi.white),
|
|
||||||
},
|
|
||||||
validate = function (self)
|
|
||||||
if self.label.value then
|
|
||||||
os.setComputerLabel(self.label.value)
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end,
|
|
||||||
},
|
},
|
||||||
password = UI.WizardPage {
|
label = UI.TextEntry {
|
||||||
index = 3,
|
x = 9, y = 2, ex = -3,
|
||||||
passwordLabel = UI.Text {
|
limit = 32,
|
||||||
x = 3, y = 2,
|
value = os.getComputerLabel(),
|
||||||
value = 'Password'
|
|
||||||
},
|
|
||||||
newPass = UI.TextEntry {
|
|
||||||
x = 12, ex = -3, y = 2,
|
|
||||||
limit = 32,
|
|
||||||
mask = true,
|
|
||||||
shadowText = 'password',
|
|
||||||
},
|
|
||||||
intro = UI.TextArea {
|
|
||||||
textColor = colors.yellow,
|
|
||||||
inactive = true,
|
|
||||||
x = 3, ex = -3, y = 5, ey = -3,
|
|
||||||
value = string.format(passwordIntro, Ansi.white),
|
|
||||||
},
|
|
||||||
validate = function (self)
|
|
||||||
if type(self.newPass.value) == "string" and #self.newPass.value > 0 then
|
|
||||||
Security.updatePassword(SHA.compute(self.newPass.value))
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end,
|
|
||||||
},
|
},
|
||||||
packages = UI.WizardPage {
|
intro = UI.TextArea {
|
||||||
index = 4,
|
textColor = colors.yellow,
|
||||||
button = UI.Button {
|
inactive = true,
|
||||||
x = 3, y = -3,
|
x = 3, ex = -3, y = 4, ey = -3,
|
||||||
text = 'Open Package Manager',
|
value = string.format(labelIntro, Ansi.white),
|
||||||
event = 'packages',
|
|
||||||
},
|
|
||||||
intro = UI.TextArea {
|
|
||||||
textColor = colors.yellow,
|
|
||||||
inactive = true,
|
|
||||||
x = 3, ex = -3, y = 2, ey = -4,
|
|
||||||
value = string.format(packagesIntro, Ansi.white),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
contributors = UI.WizardPage {
|
validate = function (self)
|
||||||
index = 5,
|
if self.label.value then
|
||||||
intro = UI.TextArea {
|
os.setComputerLabel(self.label.value)
|
||||||
textColor = colors.yellow,
|
end
|
||||||
inactive = true,
|
return true
|
||||||
x = 3, ex = -3, y = 2, ey = -2,
|
end,
|
||||||
value = string.format(contributorsIntro, Ansi.white, Ansi.yellow, Ansi.white),
|
},
|
||||||
},
|
password = UI.WizardPage {
|
||||||
|
index = 3,
|
||||||
|
passwordLabel = UI.Text {
|
||||||
|
x = 3, y = 2,
|
||||||
|
value = 'Password'
|
||||||
|
},
|
||||||
|
newPass = UI.TextEntry {
|
||||||
|
x = 12, ex = -3, y = 2,
|
||||||
|
limit = 32,
|
||||||
|
mask = true,
|
||||||
|
shadowText = 'password',
|
||||||
|
},
|
||||||
|
intro = UI.TextArea {
|
||||||
|
textColor = colors.yellow,
|
||||||
|
inactive = true,
|
||||||
|
x = 3, ex = -3, y = 5, ey = -3,
|
||||||
|
value = string.format(passwordIntro, Ansi.white),
|
||||||
|
},
|
||||||
|
validate = function (self)
|
||||||
|
if type(self.newPass.value) == "string" and #self.newPass.value > 0 then
|
||||||
|
Security.updatePassword(SHA.compute(self.newPass.value))
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
packages = UI.WizardPage {
|
||||||
|
index = 4,
|
||||||
|
button = UI.Button {
|
||||||
|
x = 3, y = -3,
|
||||||
|
text = 'Open Package Manager',
|
||||||
|
event = 'packages',
|
||||||
|
},
|
||||||
|
intro = UI.TextArea {
|
||||||
|
textColor = colors.yellow,
|
||||||
|
inactive = true,
|
||||||
|
x = 3, ex = -3, y = 2, ey = -4,
|
||||||
|
value = string.format(packagesIntro, Ansi.white),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
contributors = UI.WizardPage {
|
||||||
|
index = 5,
|
||||||
|
intro = UI.TextArea {
|
||||||
|
textColor = colors.yellow,
|
||||||
|
inactive = true,
|
||||||
|
x = 3, ex = -3, y = 2, ey = -2,
|
||||||
|
value = string.format(contributorsIntro, Ansi.white, Ansi.yellow, Ansi.white),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,7 @@ page = UI.Page {
|
||||||
backgroundColor = colors.red,
|
backgroundColor = colors.red,
|
||||||
y = '50%',
|
y = '50%',
|
||||||
properties = UI.Tab {
|
properties = UI.Tab {
|
||||||
tabTitle = 'Properties',
|
title = 'Properties',
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
headerBackgroundColor = colors.red,
|
headerBackgroundColor = colors.red,
|
||||||
sortColumn = 'key',
|
sortColumn = 'key',
|
||||||
|
@ -64,7 +64,7 @@ page = UI.Page {
|
||||||
},
|
},
|
||||||
methodsTab = UI.Tab {
|
methodsTab = UI.Tab {
|
||||||
index = 2,
|
index = 2,
|
||||||
tabTitle = 'Methods',
|
title = 'Methods',
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
ex = '50%',
|
ex = '50%',
|
||||||
headerBackgroundColor = colors.red,
|
headerBackgroundColor = colors.red,
|
||||||
|
@ -85,7 +85,7 @@ page = UI.Page {
|
||||||
},
|
},
|
||||||
events = UI.Tab {
|
events = UI.Tab {
|
||||||
index = 1,
|
index = 1,
|
||||||
tabTitle = 'Events',
|
title = 'Events',
|
||||||
UI.MenuBar {
|
UI.MenuBar {
|
||||||
y = -1,
|
y = -1,
|
||||||
backgroundColor = colors.red,
|
backgroundColor = colors.red,
|
||||||
|
|
|
@ -4,7 +4,7 @@ local UI = require('opus.ui')
|
||||||
local kernel = _G.kernel
|
local kernel = _G.kernel
|
||||||
|
|
||||||
local aliasTab = UI.Tab {
|
local aliasTab = UI.Tab {
|
||||||
tabTitle = 'Aliases',
|
title = 'Aliases',
|
||||||
description = 'Shell aliases',
|
description = 'Shell aliases',
|
||||||
alias = UI.TextEntry {
|
alias = UI.TextEntry {
|
||||||
x = 2, y = 2, ex = -2,
|
x = 2, y = 2, ex = -2,
|
||||||
|
|
|
@ -3,7 +3,7 @@ local Config = require('opus.config')
|
||||||
local UI = require('opus.ui')
|
local UI = require('opus.ui')
|
||||||
|
|
||||||
local tab = UI.Tab {
|
local tab = UI.Tab {
|
||||||
tabTitle = 'Preferred',
|
title = 'Preferred',
|
||||||
description = 'Select preferred applications',
|
description = 'Select preferred applications',
|
||||||
apps = UI.ScrollingGrid {
|
apps = UI.ScrollingGrid {
|
||||||
x = 2, y = 2,
|
x = 2, y = 2,
|
||||||
|
|
|
@ -6,7 +6,7 @@ if _G.http.websocket then
|
||||||
local config = Config.load('cloud')
|
local config = Config.load('cloud')
|
||||||
|
|
||||||
local tab = UI.Tab {
|
local tab = UI.Tab {
|
||||||
tabTitle = 'Cloud',
|
title = 'Cloud',
|
||||||
description = 'Cloud Catcher options',
|
description = 'Cloud Catcher options',
|
||||||
[1] = UI.Window {
|
[1] = UI.Window {
|
||||||
x = 2, y = 2, ex = -2, ey = 4,
|
x = 2, y = 2, ex = -2, ey = 4,
|
||||||
|
|
|
@ -16,7 +16,7 @@ local NftImages = {
|
||||||
}
|
}
|
||||||
|
|
||||||
local tab = UI.Tab {
|
local tab = UI.Tab {
|
||||||
tabTitle = 'Disks Usage',
|
title = 'Disks Usage',
|
||||||
description = 'Visualise HDD and disks usage',
|
description = 'Visualise HDD and disks usage',
|
||||||
|
|
||||||
drives = UI.ScrollingGrid {
|
drives = UI.ScrollingGrid {
|
||||||
|
@ -138,11 +138,9 @@ function tab:enable()
|
||||||
UI.Tab.enable(self)
|
UI.Tab.enable(self)
|
||||||
self.handler = Event.on({ 'disk', 'disk_eject' }, function()
|
self.handler = Event.on({ 'disk', 'disk_eject' }, function()
|
||||||
os.sleep(1)
|
os.sleep(1)
|
||||||
if tab.enabled then
|
tab:updateDrives()
|
||||||
tab:updateDrives()
|
tab:updateInfo()
|
||||||
tab:updateInfo()
|
tab:sync()
|
||||||
tab:sync()
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ local peripheral = _G.peripheral
|
||||||
local settings = _G.settings
|
local settings = _G.settings
|
||||||
|
|
||||||
return peripheral.find('monitor') and UI.Tab {
|
return peripheral.find('monitor') and UI.Tab {
|
||||||
tabTitle = 'Kiosk',
|
title = 'Kiosk',
|
||||||
description = 'Kiosk options',
|
description = 'Kiosk options',
|
||||||
form = UI.Form {
|
form = UI.Form {
|
||||||
x = 2, y = 2, ex = -2, ey = 5,
|
x = 2, y = 2, ex = -2, ey = 5,
|
||||||
|
|
|
@ -5,7 +5,7 @@ local fs = _G.fs
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
|
||||||
return UI.Tab {
|
return UI.Tab {
|
||||||
tabTitle = 'Label',
|
title = 'Label',
|
||||||
description = 'Set the computer label',
|
description = 'Set the computer label',
|
||||||
labelText = UI.Text {
|
labelText = UI.Text {
|
||||||
x = 3, y = 3,
|
x = 3, y = 3,
|
||||||
|
|
|
@ -7,7 +7,7 @@ local fs = _G.fs
|
||||||
local config = Config.load('multishell')
|
local config = Config.load('multishell')
|
||||||
|
|
||||||
local tab = UI.Tab {
|
local tab = UI.Tab {
|
||||||
tabTitle = 'Launcher',
|
title = 'Launcher',
|
||||||
description = 'Set the application launcher',
|
description = 'Set the application launcher',
|
||||||
[1] = UI.Window {
|
[1] = UI.Window {
|
||||||
x = 2, y = 2, ex = -2, ey = 5,
|
x = 2, y = 2, ex = -2, ey = 5,
|
||||||
|
|
|
@ -6,7 +6,7 @@ local colors = _G.colors
|
||||||
local device = _G.device
|
local device = _G.device
|
||||||
|
|
||||||
return UI.Tab {
|
return UI.Tab {
|
||||||
tabTitle = 'Network',
|
title = 'Network',
|
||||||
description = 'Networking options',
|
description = 'Networking options',
|
||||||
info = UI.TextArea {
|
info = UI.TextArea {
|
||||||
x = 2, y = 5, ex = -2, ey = -2,
|
x = 2, y = 5, ex = -2, ey = -2,
|
||||||
|
|
|
@ -3,7 +3,7 @@ local SHA = require('opus.crypto.sha2')
|
||||||
local UI = require('opus.ui')
|
local UI = require('opus.ui')
|
||||||
|
|
||||||
return UI.Tab {
|
return UI.Tab {
|
||||||
tabTitle = 'Password',
|
title = 'Password',
|
||||||
description = 'Wireless network password',
|
description = 'Wireless network password',
|
||||||
[1] = UI.Window {
|
[1] = UI.Window {
|
||||||
x = 2, y = 2, ex = -2, ey = 4,
|
x = 2, y = 2, ex = -2, ey = 4,
|
||||||
|
|
|
@ -3,7 +3,7 @@ local UI = require('opus.ui')
|
||||||
local Util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local tab = UI.Tab {
|
local tab = UI.Tab {
|
||||||
tabTitle = 'Path',
|
title = 'Path',
|
||||||
description = 'Set the shell path',
|
description = 'Set the shell path',
|
||||||
tabClose = true,
|
tabClose = true,
|
||||||
[1] = UI.Window {
|
[1] = UI.Window {
|
||||||
|
|
|
@ -3,7 +3,7 @@ local UI = require('opus.ui')
|
||||||
local Util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local tab = UI.Tab {
|
local tab = UI.Tab {
|
||||||
tabTitle = 'Requires',
|
title = 'Requires',
|
||||||
description = 'Require path',
|
description = 'Require path',
|
||||||
tabClose = true,
|
tabClose = true,
|
||||||
entry = UI.TextEntry {
|
entry = UI.TextEntry {
|
||||||
|
|
|
@ -8,7 +8,7 @@ local transform = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings and UI.Tab {
|
return settings and UI.Tab {
|
||||||
tabTitle = 'Settings',
|
title = 'Settings',
|
||||||
description = 'Computercraft settings',
|
description = 'Computercraft settings',
|
||||||
grid = UI.Grid {
|
grid = UI.Grid {
|
||||||
x = 2, y = 2, ex = -2, ey = -2,
|
x = 2, y = 2, ex = -2, ey = -2,
|
||||||
|
|
|
@ -39,7 +39,7 @@ if not _colors.backgroundColor then
|
||||||
end
|
end
|
||||||
|
|
||||||
return UI.Tab {
|
return UI.Tab {
|
||||||
tabTitle = 'Shell',
|
title = 'Shell',
|
||||||
description = 'Shell options',
|
description = 'Shell options',
|
||||||
grid1 = UI.ScrollingGrid {
|
grid1 = UI.ScrollingGrid {
|
||||||
y = 2, ey = -10, x = 2, ex = -17,
|
y = 2, ey = -10, x = 2, ex = -17,
|
||||||
|
|
|
@ -17,7 +17,7 @@ for k,v in pairs(UI.colors) do
|
||||||
end
|
end
|
||||||
|
|
||||||
return UI.Tab {
|
return UI.Tab {
|
||||||
tabTitle = 'Theme',
|
title = 'Theme',
|
||||||
description = 'Theme colors',
|
description = 'Theme colors',
|
||||||
grid1 = UI.ScrollingGrid {
|
grid1 = UI.ScrollingGrid {
|
||||||
y = 2, ey = -10, x = 2, ex = -17,
|
y = 2, ey = -10, x = 2, ex = -17,
|
||||||
|
|
|
@ -136,4 +136,10 @@
|
||||||
iconExt = "\030 \031 \128\0307\143\131\131\131\131\143\030 \128\010\0307\031 \129\0317\128\0319\136\0309\031b\136\132\0307\0319\132\0317\128\031 \130\010\030 \0317\130\143\0307\128\128\128\128\030 \143\129",
|
iconExt = "\030 \031 \128\0307\143\131\131\131\131\143\030 \128\010\0307\031 \129\0317\128\0319\136\0309\031b\136\132\0307\0319\132\0317\128\031 \130\010\030 \0317\130\143\0307\128\128\128\128\030 \143\129",
|
||||||
run = "/rom/programs/fun/dj",
|
run = "/rom/programs/fun/dj",
|
||||||
},
|
},
|
||||||
|
[ "4dbdd221e957eff27cc47796f3ed8447290f71c7ad8b95e5bd828b31c1858f15" ] = {
|
||||||
|
title = "Partition",
|
||||||
|
category = "System",
|
||||||
|
iconExt = "\30\55\31\55\128\30\48\135\131\139\30\55\128\128\128\10\30\48\31\55\149\31\48\128\30\55\145\30\48\31\56\140\30\55\157\144\144\10\30\55\31\55\128\31\48\139\143\135\31\55\128\31\56\142\133",
|
||||||
|
run = "Partition",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,8 @@ local function getNode(dir)
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
|
|
||||||
|
fs.getNode = getNode
|
||||||
|
|
||||||
local methods = { 'delete', 'getFreeSpace', 'exists', 'isDir', 'getSize',
|
local methods = { 'delete', 'getFreeSpace', 'exists', 'isDir', 'getSize',
|
||||||
'isReadOnly', 'makeDir', 'getDrive', 'list', 'open' }
|
'isReadOnly', 'makeDir', 'getDrive', 'list', 'open' }
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,13 @@ if not fs.exists('usr/autorun') then
|
||||||
fs.makeDir('usr/autorun')
|
fs.makeDir('usr/autorun')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- move the fstab out of config so that the config directory
|
||||||
|
-- can be remapped to another disk (and for consistency)
|
||||||
|
if fs.exists('usr/config/fstab') and not fs.exists('usr/etc/fstab') then
|
||||||
|
fs.move('usr/config/fstab', 'usr/etc/fstab')
|
||||||
|
end
|
||||||
|
fs.loadTab('usr/etc/fstab')
|
||||||
|
|
||||||
-- TODO: Temporary
|
-- TODO: Temporary
|
||||||
local upgrade = Util.readTable('usr/config/shell')
|
local upgrade = Util.readTable('usr/config/shell')
|
||||||
if upgrade and (not upgrade.upgraded or upgrade.upgraded ~= 1) then
|
if upgrade and (not upgrade.upgraded or upgrade.upgraded ~= 1) then
|
||||||
|
@ -45,5 +52,3 @@ shell.setPath(table.concat(path, ':'))
|
||||||
|
|
||||||
--_G.LUA_PATH = config.lua_path
|
--_G.LUA_PATH = config.lua_path
|
||||||
--_G.settings.set('mbs.shell.require_path', config.lua_path)
|
--_G.settings.set('mbs.shell.require_path', config.lua_path)
|
||||||
|
|
||||||
fs.loadTab('usr/config/fstab')
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ for name in pairs(Packages:installed()) do
|
||||||
local packageDir = fs.combine('packages', name)
|
local packageDir = fs.combine('packages', name)
|
||||||
|
|
||||||
table.insert(appPaths, 1, '/' .. packageDir)
|
table.insert(appPaths, 1, '/' .. packageDir)
|
||||||
local apiPath = fs.combine(packageDir, 'apis')
|
local apiPath = fs.combine(packageDir, 'apis') -- TODO: rename dir to 'modules' (someday)
|
||||||
if fs.exists(apiPath) then
|
if fs.exists(apiPath) then
|
||||||
fs.mount(fs.combine('rom/modules/main', name), 'linkfs', apiPath)
|
fs.mount(fs.combine('rom/modules/main', name), 'linkfs', apiPath)
|
||||||
end
|
end
|
||||||
|
|
|
@ -675,7 +675,7 @@ function UI.Window:drawChildren()
|
||||||
end
|
end
|
||||||
|
|
||||||
UI.Window.docs.getDoc = [[getDoc(STRING method)
|
UI.Window.docs.getDoc = [[getDoc(STRING method)
|
||||||
Gets the documentation for a method.]]
|
Get the documentation for a method.]]
|
||||||
function UI.Window:getDoc(method)
|
function UI.Window:getDoc(method)
|
||||||
local m = getmetatable(self) -- get the class for this instance
|
local m = getmetatable(self) -- get the class for this instance
|
||||||
repeat
|
repeat
|
||||||
|
@ -743,6 +743,8 @@ function UI.Window:clear(bg, fg)
|
||||||
Canvas.clear(self, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
|
Canvas.clear(self, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UI.Window.docs.clearLine = [[clearLine(NUMBER y, opt COLOR bg)
|
||||||
|
Clears the specified line.]]
|
||||||
function UI.Window:clearLine(y, bg)
|
function UI.Window:clearLine(y, bg)
|
||||||
self:write(1, y, _rep(' ', self.width), bg)
|
self:write(1, y, _rep(' ', self.width), bg)
|
||||||
end
|
end
|
||||||
|
@ -760,6 +762,10 @@ function UI.Window:fillArea(x, y, width, height, fillChar, bg, fg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UI.Window.docs.write = [[write(NUMBER x, NUMBER y, String text, opt COLOR bg, opt COLOR fg)
|
||||||
|
Write text to the canvas.
|
||||||
|
If colors are not specified, the colors from the base class will be used.
|
||||||
|
If the base class does not have colors defined, colors will be inherited from the parent container.]]
|
||||||
function UI.Window:write(x, y, text, bg, fg)
|
function UI.Window:write(x, y, text, bg, fg)
|
||||||
Canvas.write(self, x, y, text, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
|
Canvas.write(self, x, y, text, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,86 +1,75 @@
|
||||||
local class = require('opus.class')
|
local class = require('opus.class')
|
||||||
local UI = require('opus.ui')
|
local UI = require('opus.ui')
|
||||||
local Util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local colors = _G.colors
|
local fs = _G.fs
|
||||||
local fs = _G.fs
|
|
||||||
|
|
||||||
UI.FileSelect = class(UI.Window)
|
UI.FileSelect = class(UI.Window)
|
||||||
UI.FileSelect.defaults = {
|
UI.FileSelect.defaults = {
|
||||||
UIElement = 'FileSelect',
|
UIElement = 'FileSelect',
|
||||||
}
|
}
|
||||||
function UI.FileSelect:postInit()
|
function UI.FileSelect:postInit()
|
||||||
self.grid = UI.ScrollingGrid {
|
self.grid = UI.ScrollingGrid {
|
||||||
x = 2, y = 2, ex = -2, ey = -4,
|
x = 2, y = 2, ex = -2, ey = -4,
|
||||||
dir = '/',
|
dir = '/',
|
||||||
sortColumn = 'name',
|
sortColumn = 'name',
|
||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Name', key = 'name' },
|
{ heading = 'Name', key = 'name' },
|
||||||
{ heading = 'Size', key = 'size', width = 5 }
|
{ heading = 'Size', key = 'size', width = 5 }
|
||||||
},
|
},
|
||||||
getDisplayValues = function(_, row)
|
getDisplayValues = function(_, row)
|
||||||
if row.size then
|
return {
|
||||||
row = Util.shallowCopy(row)
|
name = row.name,
|
||||||
row.size = Util.toBytes(row.size)
|
size = row.size and Util.toBytes(row.size),
|
||||||
end
|
}
|
||||||
return row
|
end,
|
||||||
end,
|
getRowTextColor = function(_, file)
|
||||||
getRowTextColor = function(_, file)
|
return file.isDir and 'cyan' or file.isReadOnly and 'pink' or 'white'
|
||||||
if file.isDir then
|
end,
|
||||||
return colors.cyan
|
sortCompare = function(self, a, b)
|
||||||
end
|
if self.sortColumn == 'size' then
|
||||||
if file.isReadOnly then
|
return a.size < b.size
|
||||||
return colors.pink
|
end
|
||||||
end
|
if a.isDir == b.isDir then
|
||||||
return colors.white
|
return a.name:lower() < b.name:lower()
|
||||||
end,
|
end
|
||||||
sortCompare = function(self, a, b)
|
return a.isDir
|
||||||
if self.sortColumn == 'size' then
|
end,
|
||||||
return a.size < b.size
|
draw = function(self)
|
||||||
end
|
local files = fs.listEx(self.dir)
|
||||||
if a.isDir == b.isDir then
|
if #self.dir > 0 then
|
||||||
return a.name:lower() < b.name:lower()
|
table.insert(files, {
|
||||||
end
|
name = '..',
|
||||||
return a.isDir
|
isDir = true,
|
||||||
end,
|
})
|
||||||
draw = function(self)
|
end
|
||||||
local files = fs.listEx(self.dir)
|
self:setValues(files)
|
||||||
if #self.dir > 0 then
|
self:setIndex(1)
|
||||||
table.insert(files, {
|
UI.Grid.draw(self)
|
||||||
name = '..',
|
end,
|
||||||
isDir = true,
|
}
|
||||||
})
|
self.path = UI.TextEntry {
|
||||||
end
|
x = 2, y = -2, ex = -11,
|
||||||
self:setValues(files)
|
limit = 256,
|
||||||
self:setIndex(1)
|
accelerators = {
|
||||||
UI.Grid.draw(self)
|
enter = 'path_enter',
|
||||||
end,
|
}
|
||||||
}
|
}
|
||||||
self.path = UI.TextEntry {
|
self.cancel = UI.Button {
|
||||||
x = 2,
|
x = -9, y = -2,
|
||||||
y = -2,
|
text = 'Cancel',
|
||||||
ex = -11,
|
event = 'select_cancel',
|
||||||
limit = 256,
|
}
|
||||||
accelerators = {
|
|
||||||
enter = 'path_enter',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.cancel = UI.Button {
|
|
||||||
text = 'Cancel',
|
|
||||||
x = -9,
|
|
||||||
y = -2,
|
|
||||||
event = 'select_cancel',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.FileSelect:draw()
|
function UI.FileSelect:draw()
|
||||||
self:fillArea(1, 1, self.width, self.height, string.rep('\127', self.width), colors.black, colors.gray)
|
self:fillArea(1, 1, self.width, self.height, string.rep('\127', self.width), 'black', 'gray')
|
||||||
self:drawChildren()
|
self:drawChildren()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.FileSelect:enable(path)
|
function UI.FileSelect:enable(path)
|
||||||
self:setPath(path or '')
|
self:setPath(path or '')
|
||||||
UI.Window.enable(self)
|
UI.Window.enable(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.FileSelect:setPath(path)
|
function UI.FileSelect:setPath(path)
|
||||||
|
@ -98,21 +87,21 @@ function UI.FileSelect:eventHandler(event)
|
||||||
if event.selected.isDir then
|
if event.selected.isDir then
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
self.path:draw()
|
self.path:draw()
|
||||||
else
|
else
|
||||||
self:emit({ type = 'select_file', file = '/' .. self.path.value, element = self })
|
self:emit({ type = 'select_file', file = '/' .. self.path.value, element = self })
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
|
||||||
elseif event.type == 'path_enter' then
|
elseif event.type == 'path_enter' then
|
||||||
if self.path.value then
|
if self.path.value then
|
||||||
if fs.isDir(self.path.value) then
|
if fs.isDir(self.path.value) then
|
||||||
self:setPath(self.path.value)
|
self:setPath(self.path.value)
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
self.path:draw()
|
self.path:draw()
|
||||||
else
|
else
|
||||||
self:emit({ type = 'select_file', file = '/' .. self.path.value, element = self })
|
self:emit({ type = 'select_file', file = '/' .. self.path.value, element = self })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,7 +33,7 @@ function UI.Image:draw()
|
||||||
for x = 1, #line do
|
for x = 1, #line do
|
||||||
local ch = lookup:find(line:sub(x, x))
|
local ch = lookup:find(line:sub(x, x))
|
||||||
if ch then
|
if ch then
|
||||||
self:write(x, y, ' ', 2 ^ (ch -1))
|
self:write(x, y, ' ', 2 ^ (ch - 1))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,6 +47,7 @@ end
|
||||||
|
|
||||||
function UI.Image.example()
|
function UI.Image.example()
|
||||||
return UI.Image {
|
return UI.Image {
|
||||||
|
backgroundColor = 'primary',
|
||||||
filename = 'test.paint',
|
filename = 'test.paint',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ local colors = _G.colors
|
||||||
UI.ScrollBar = class(UI.Window)
|
UI.ScrollBar = class(UI.Window)
|
||||||
UI.ScrollBar.defaults = {
|
UI.ScrollBar.defaults = {
|
||||||
UIElement = 'ScrollBar',
|
UIElement = 'ScrollBar',
|
||||||
lineChar = '|',
|
lineChar = '\166',
|
||||||
sliderChar = UI.extChars and '\127' or '#',
|
sliderChar = UI.extChars and '\127' or '#',
|
||||||
upArrowChar = UI.extChars and '\30' or '^',
|
upArrowChar = UI.extChars and '\30' or '^',
|
||||||
downArrowChar = UI.extChars and '\31' or 'v',
|
downArrowChar = UI.extChars and '\31' or 'v',
|
||||||
|
|
|
@ -4,7 +4,7 @@ local UI = require('opus.ui')
|
||||||
UI.Tab = class(UI.Window)
|
UI.Tab = class(UI.Window)
|
||||||
UI.Tab.defaults = {
|
UI.Tab.defaults = {
|
||||||
UIElement = 'Tab',
|
UIElement = 'Tab',
|
||||||
tabTitle = 'tab',
|
title = 'tab',
|
||||||
y = 2,
|
y = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,3 +14,8 @@ function UI.Tab:draw()
|
||||||
end
|
end
|
||||||
self:drawChildren()
|
self:drawChildren()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function UI.Tab:enable()
|
||||||
|
UI.Window.enable(self)
|
||||||
|
self:emit({ type = 'tab_activate', activated = self })
|
||||||
|
end
|
||||||
|
|
|
@ -37,9 +37,3 @@ function UI.TabBar:eventHandler(event)
|
||||||
return UI.MenuBar.eventHandler(self, event)
|
return UI.MenuBar.eventHandler(self, event)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.TabBar:selectTab(text)
|
|
||||||
local menuItem = Util.find(self.children, 'text', text)
|
|
||||||
if menuItem then
|
|
||||||
menuItem.selected = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -14,11 +14,11 @@ end
|
||||||
function UI.Tabs:add(children)
|
function UI.Tabs:add(children)
|
||||||
local buttons = { }
|
local buttons = { }
|
||||||
for _,child in pairs(children) do
|
for _,child in pairs(children) do
|
||||||
if type(child) == 'table' and child.UIElement and child.tabTitle then
|
if type(child) == 'table' and child.UIElement and child.UIElement == 'Tab' then
|
||||||
child.y = 2
|
child.y = 2
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
index = child.index,
|
index = child.index,
|
||||||
text = child.tabTitle,
|
text = child.title,
|
||||||
event = 'tab_select',
|
event = 'tab_select',
|
||||||
tabUid = child.uid,
|
tabUid = child.uid,
|
||||||
})
|
})
|
||||||
|
@ -34,7 +34,12 @@ function UI.Tabs:add(children)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.parent then
|
if self.parent then
|
||||||
|
local enabled = self.enabled
|
||||||
|
|
||||||
|
-- don't enable children upon add
|
||||||
|
self.enabled = nil
|
||||||
UI.Window.add(self, children)
|
UI.Window.add(self, children)
|
||||||
|
self.enabled = enabled
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -43,7 +48,15 @@ Make to the passed tab active.]]
|
||||||
function UI.Tabs:selectTab(tab)
|
function UI.Tabs:selectTab(tab)
|
||||||
local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid)
|
local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid)
|
||||||
if menuItem then
|
if menuItem then
|
||||||
self.tabBar:emit({ type = 'tab_select', button = { uid = menuItem.uid } })
|
if self.enabled then
|
||||||
|
self.tabBar:emit({ type = 'tab_select', button = { uid = menuItem.uid } })
|
||||||
|
else
|
||||||
|
local previous = Util.find(self.tabBar.children, 'selected', true)
|
||||||
|
if previous then
|
||||||
|
previous.selected = false
|
||||||
|
end
|
||||||
|
menuItem.selected = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,14 +72,20 @@ function UI.Tabs:enable()
|
||||||
self.tabBar:enable()
|
self.tabBar:enable()
|
||||||
|
|
||||||
local menuItem = Util.find(self.tabBar.children, 'selected', true)
|
local menuItem = Util.find(self.tabBar.children, 'selected', true)
|
||||||
|
self:enableTab(menuItem.tabUid)
|
||||||
|
end
|
||||||
|
|
||||||
|
function UI.Tabs:enableTab(tabUid, hint)
|
||||||
for child in self:eachChild() do
|
for child in self:eachChild() do
|
||||||
child.transitionHint = nil
|
child.transitionHint = hint
|
||||||
if child.uid == menuItem.tabUid then
|
if child.uid == tabUid then
|
||||||
child:enable()
|
if not child.enabled then
|
||||||
self:emit({ type = 'tab_activate', activated = child })
|
child:enable()
|
||||||
elseif child.tabTitle then
|
end
|
||||||
child:disable()
|
elseif child.UIElement == 'Tab' then
|
||||||
|
if child.enabled then
|
||||||
|
child:disable()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -76,15 +95,7 @@ function UI.Tabs:eventHandler(event)
|
||||||
local tab = self:find(event.tab.tabUid)
|
local tab = self:find(event.tab.tabUid)
|
||||||
local hint = event.current > event.last and 'slideLeft' or 'slideRight'
|
local hint = event.current > event.last and 'slideLeft' or 'slideRight'
|
||||||
|
|
||||||
for child in self:eachChild() do
|
self:enableTab(event.tab.tabUid, hint)
|
||||||
if child.uid == event.tab.tabUid then
|
|
||||||
child.transitionHint = hint
|
|
||||||
child:enable()
|
|
||||||
elseif child.tabTitle then
|
|
||||||
child:disable()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:emit({ type = 'tab_activate', activated = tab })
|
|
||||||
tab:draw()
|
tab:draw()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -94,28 +105,28 @@ function UI.Tabs.example()
|
||||||
return UI.Tabs {
|
return UI.Tabs {
|
||||||
tab1 = UI.Tab {
|
tab1 = UI.Tab {
|
||||||
index = 1,
|
index = 1,
|
||||||
tabTitle = 'tab1',
|
title = 'tab1',
|
||||||
entry = UI.TextEntry { y = 3, shadowText = 'text' },
|
entry = UI.TextEntry { y = 3, shadowText = 'text' },
|
||||||
},
|
},
|
||||||
tab2 = UI.Tab {
|
tab2 = UI.Tab {
|
||||||
index = 2,
|
index = 2,
|
||||||
tabTitle = 'tab2',
|
title = 'tab2',
|
||||||
subtabs = UI.Tabs {
|
subtabs = UI.Tabs {
|
||||||
x = 3, y = 2, ex = -3, ey = -2,
|
x = 3, y = 2, ex = -3, ey = -2,
|
||||||
tab1 = UI.Tab {
|
tab1 = UI.Tab {
|
||||||
index = 1,
|
index = 1,
|
||||||
tabTitle = 'tab4',
|
title = 'tab4',
|
||||||
entry = UI.TextEntry { y = 3, shadowText = 'text' },
|
entry = UI.TextEntry { y = 3, shadowText = 'text' },
|
||||||
},
|
},
|
||||||
tab3 = UI.Tab {
|
tab3 = UI.Tab {
|
||||||
index = 2,
|
index = 2,
|
||||||
tabTitle = 'tab5',
|
title = 'tab5',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tab3 = UI.Tab {
|
tab3 = UI.Tab {
|
||||||
index = 3,
|
index = 3,
|
||||||
tabTitle = 'tab3',
|
title = 'tab3',
|
||||||
},
|
},
|
||||||
enable = function(self)
|
enable = function(self)
|
||||||
UI.Tabs.enable(self)
|
UI.Tabs.enable(self)
|
||||||
|
|
|
@ -8,11 +8,12 @@ UI.TextArea.defaults = {
|
||||||
value = '',
|
value = '',
|
||||||
showScrollBar = true,
|
showScrollBar = true,
|
||||||
}
|
}
|
||||||
function UI.TextArea:setText(text)
|
function UI.TextArea:setValue(text)
|
||||||
self:reset()
|
self:reset()
|
||||||
self.value = text
|
self.value = text
|
||||||
self:draw()
|
self:draw()
|
||||||
end
|
end
|
||||||
|
UI.TextArea.setText = UI.TextArea.setValue -- deprecate
|
||||||
|
|
||||||
function UI.TextArea.focus()
|
function UI.TextArea.focus()
|
||||||
-- allow keyboard scrolling
|
-- allow keyboard scrolling
|
||||||
|
|
|
@ -15,52 +15,50 @@ function UI.Wizard:postInit()
|
||||||
}
|
}
|
||||||
self.previousButton = UI.Button {
|
self.previousButton = UI.Button {
|
||||||
x = -18, y = -1,
|
x = -18, y = -1,
|
||||||
text = '< Back',
|
text = '\17 Back',
|
||||||
event = 'previousView',
|
event = 'previousView',
|
||||||
}
|
}
|
||||||
self.nextButton = UI.Button {
|
self.nextButton = UI.Button {
|
||||||
x = -9, y = -1,
|
x = -9, y = -1,
|
||||||
text = 'Next >',
|
text = 'Next \16',
|
||||||
event = 'nextView',
|
event = 'nextView',
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.merge(self, self.pages)
|
Util.merge(self, self.pages)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Wizard:add(pages)
|
function UI.Wizard:getPages()
|
||||||
Util.merge(self.pages, pages)
|
local t = { }
|
||||||
Util.merge(self, pages)
|
for child in self:eachChild() do
|
||||||
|
if type(child) == 'table' and child.UIElement == 'WizardPage' then
|
||||||
for _, child in pairs(self.pages) do
|
table.insert(t, child)
|
||||||
child.ey = child.ey or -2
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if self.parent then
|
|
||||||
self:initChildren()
|
|
||||||
end
|
end
|
||||||
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Wizard:getPage(index)
|
function UI.Wizard:getPage(index)
|
||||||
return Util.find(self.pages, 'index', index)
|
local pages = self:getPages()
|
||||||
|
return Util.find(pages, 'index', index)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Wizard:enable(...)
|
function UI.Wizard:enable()
|
||||||
self.enabled = true
|
self.enabled = true
|
||||||
self.index = 1
|
self.index = 1
|
||||||
local initial = self:getPage(1)
|
|
||||||
for child in self:eachChild() do
|
for child in self:eachChild() do
|
||||||
if child == initial or not child.index then
|
if child.UIElement ~= 'WizardPage' then
|
||||||
child:enable(...)
|
child:enable()
|
||||||
else
|
elseif child.enabled then
|
||||||
child:disable()
|
child:disable()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local initial = self:getPage(1)
|
||||||
self:emit({ type = 'enable_view', next = initial })
|
self:emit({ type = 'enable_view', next = initial })
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Wizard:isViewValid()
|
function UI.Wizard:isViewValid()
|
||||||
local currentView = self:getPage(self.index)
|
local currentView = self:getPage(self.index)
|
||||||
return not currentView.validate and true or currentView:validate()
|
return currentView:validate()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Wizard:eventHandler(event)
|
function UI.Wizard:eventHandler(event)
|
||||||
|
@ -107,7 +105,7 @@ function UI.Wizard:eventHandler(event)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:getPage(self.index + 1) then
|
if self:getPage(self.index + 1) then
|
||||||
self.nextButton.text = 'Next >'
|
self.nextButton.text = 'Next \16'
|
||||||
self.nextButton.event = 'nextView'
|
self.nextButton.event = 'nextView'
|
||||||
else
|
else
|
||||||
self.nextButton.text = 'Accept'
|
self.nextButton.text = 'Accept'
|
||||||
|
@ -124,29 +122,27 @@ end
|
||||||
function UI.Wizard.example()
|
function UI.Wizard.example()
|
||||||
return UI.Wizard {
|
return UI.Wizard {
|
||||||
ey = -2,
|
ey = -2,
|
||||||
pages = {
|
splash = UI.WizardPage {
|
||||||
splash = UI.WizardPage {
|
index = 1,
|
||||||
index = 1,
|
intro = UI.TextArea {
|
||||||
intro = UI.TextArea {
|
inactive = true,
|
||||||
inactive = true,
|
x = 3, ex = -3, y = 2, ey = -2,
|
||||||
x = 3, ex = -3, y = 2, ey = -2,
|
value = 'sample text',
|
||||||
value = 'sample text',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
label = UI.WizardPage {
|
},
|
||||||
index = 2,
|
label = UI.WizardPage {
|
||||||
intro = UI.TextArea {
|
index = 2,
|
||||||
inactive = true,
|
intro = UI.TextArea {
|
||||||
x = 3, ex = -3, y = 2, ey = -2,
|
inactive = true,
|
||||||
value = 'sample more text',
|
x = 3, ex = -3, y = 2, ey = -2,
|
||||||
},
|
value = 'sample more text',
|
||||||
},
|
},
|
||||||
password = UI.WizardPage {
|
},
|
||||||
index = 3,
|
password = UI.WizardPage {
|
||||||
text = UI.TextEntry {
|
index = 3,
|
||||||
x = 12, ex = -3, y = 2,
|
text = UI.TextEntry {
|
||||||
shadowText = 'tet',
|
x = 12, ex = -3, y = 2,
|
||||||
},
|
shadowText = 'tet',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,3 +6,6 @@ UI.WizardPage.defaults = {
|
||||||
UIElement = 'WizardPage',
|
UIElement = 'WizardPage',
|
||||||
ey = -2,
|
ey = -2,
|
||||||
}
|
}
|
||||||
|
function UI.WizardPage.validate()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue