canvas overhaul

This commit is contained in:
kepler155c@gmail.com 2020-03-31 09:57:23 -06:00
parent 369070e19c
commit 5a874c1944
69 changed files with 1134 additions and 786 deletions

View File

@ -91,7 +91,6 @@ local Browser = UI.Page {
},
notification = UI.Notification { },
associations = UI.SlideOut {
backgroundColor = colors.cyan,
menuBar = UI.MenuBar {
buttons = {
{ text = 'Save', event = 'save' },
@ -99,7 +98,7 @@ local Browser = UI.Page {
},
},
grid = UI.ScrollingGrid {
x = 2, ex = -6, y = 3, ey = -5,
x = 2, ex = -6, y = 3, ey = -8,
columns = {
{ heading = 'Extension', key = 'name' },
{ heading = 'Program', key = 'value' },
@ -114,8 +113,11 @@ local Browser = UI.Page {
x = -4, y = 6,
text = '-', event = 'remove_entry', help = 'Remove',
},
[1] = UI.Window {
x = 2, y = -6, ex = -6, ey = -3,
},
form = UI.Form {
x = 3, y = -3, ey = -2,
x = 3, y = -5, ex = -7, ey = -3,
margin = 1,
manualControls = true,
[1] = UI.TextEntry {

View File

@ -59,7 +59,6 @@ local page = UI.Page {
[2] = UI.Tab {
tabTitle = 'Output',
output = UI.Embedded {
visible = true,
maxScroll = 1000,
backgroundColor = colors.black,
},

View File

@ -74,7 +74,6 @@ local page = UI.Page {
},
},
help = UI.SlideOut {
backgroundColor = colors.cyan,
x = 5, ex = -5, height = 8, y = -8,
titleBar = UI.TitleBar {
title = 'Network Help',
@ -82,7 +81,6 @@ local page = UI.Page {
},
text = UI.TextArea {
x = 2, y = 2,
backgroundColor = colors.cyan,
value = [[
In order to connect to another computer:

View File

@ -26,6 +26,9 @@ local REGISTRY_DIR = 'usr/.registry'
local DEFAULT_ICON = NFT.parse("\0308\0317\153\153\153\153\153\
\0307\0318\153\153\153\153\153\
\0308\0317\153\153\153\153\153")
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")
-- overview
local uid = _ENV.multishell.getCurrent()
@ -65,6 +68,7 @@ local function parseIcon(iconText)
if icon.height > 3 or icon.width > 8 then
error('Must be an NFT image - 3 rows, 8 cols max')
end
NFT.transparency(icon)
end
return icon
end)
@ -89,6 +93,7 @@ function UI.VerticalTabBar:setParent()
c.ox, c.oy = c.x, c.y
c.ow = 8
c.width = 8
c:reposition(c.x, c.y, c.width, c.height)
end
end
@ -114,7 +119,6 @@ local page = UI.Page {
},
editor = UI.SlideOut {
y = -12, height = 12,
backgroundColor = colors.cyan,
titleBar = UI.TitleBar {
title = 'Edit Application',
event = 'slide_hide',
@ -122,7 +126,7 @@ local page = UI.Page {
form = UI.Form {
y = 2, ey = -2,
[1] = UI.TextEntry {
formLabel = 'Title', formKey = 'title', limit = 11, help = 'Application title',
formLabel = 'Title', formKey = 'title', limit = 11, width = 13, help = 'Application title',
required = true,
},
[2] = UI.TextEntry {
@ -130,21 +134,24 @@ local page = UI.Page {
required = true,
},
[3] = UI.TextEntry {
formLabel = 'Category', formKey = 'category', limit = 11, help = 'Category of application',
formLabel = 'Category', formKey = 'category', limit = 6, width = 8, help = 'Category of application',
required = true,
},
iconFile = UI.TextEntry {
x = 11, ex = -12, y = 7,
limit = 128, help = 'Path to icon file',
shadowText = 'Path to icon file',
editIcon = UI.Button {
x = 11, y = 9,
text = 'Edit', event = 'editIcon', help = 'Edit icon file',
},
loadIcon = UI.Button {
x = 11, y = 9,
x = 18, y = 9,
text = 'Load', event = 'loadIcon', help = 'Load icon file',
},
info = UI.TextArea {
x = 11, y = 6, height = 2,
value = 'magenta is transparent\n3 high - max width is 8'
},
image = UI.NftImage {
backgroundColor = colors.black,
y = 7, x = 2, height = 3, width = 8,
y = 6, x = 2, height = 3, width = 8,
},
},
notification = UI.Notification(),
@ -226,6 +233,7 @@ local function loadApplications()
page:add {
tabBar = UI.VerticalTabBar {
buttons = buttons,
selectedBackgroundColor = UI.colors.primary,
},
}
@ -308,14 +316,12 @@ function page.container:setCategory(categoryName, animate)
image = UI.NftImage({
x = math.floor((width - icon.width) / 2) + 1,
image = icon,
width = 5,
height = 3,
}),
button = UI.Button({
x = math.floor((width - #title - 2) / 2) + 1,
y = 4,
text = title,
backgroundColor = self.backgroundColor,
backgroundColor = self:getProperty('backgroundColor'),
backgroundFocusColor = colors.gray,
textColor = colors.white,
textFocusColor = colors.white,
@ -333,7 +339,8 @@ function page.container:setCategory(categoryName, animate)
local col, row = gutter, 2
local count = #self.children
local r = math.random(1, 5)
local r = math.random(1, 7)
local frames = 5
-- reposition all children
for k,child in ipairs(self.children) do
if r == 1 then
@ -355,14 +362,22 @@ function page.container:setCategory(categoryName, animate)
child.x = self.width
child.y = self.height - 3
end
elseif r == 6 then
child.x = col
child.y = 1
elseif r == 7 then
child.x = 1
child.y = self.height - 3
end
child.tween = Tween.new(6, child, { x = col, y = row }, 'linear')
child.tween = Tween.new(frames, child, { x = col, y = row }, 'inQuad')
if not animate then
child.x = col
child.y = row
end
self:setViewHeight(row + 3)
if k < count then
col = col + child.width
if col + self.children[k + 1].width + gutter - 2 > self.width then
@ -377,15 +392,13 @@ function page.container:setCategory(categoryName, animate)
local function transition()
local i = 1
return function()
self:clear()
for _,child in pairs(self.children) do
child.tween:update(1)
child.x = math.floor(child.x)
child.y = math.floor(child.y)
child:draw()
child:move(math.floor(child.x), math.floor(child.y))
end
--os.sleep(.5)
i = i + 1
return i < 7
return i <= frames
end
end
self:addTransition(transition)
@ -512,6 +525,30 @@ function page.editor:updateApplications(app)
loadApplications()
end
function page.editor:loadImage(filename)
local s, m = pcall(function()
local iconLines = Util.readFile(filename)
if not iconLines then
error('Must be an NFT image - 3 rows, 8 cols max')
end
local icon, m = parseIcon(iconLines)
if not icon then
error(m)
end
if extSupport then
self.form.values.iconExt = iconLines
else
self.form.values.icon = iconLines
end
self.form.image:setImage(icon)
self.form.image:draw()
end)
if not s and m then
local msg = m:gsub('.*: (.*)', '%1')
self.notification:error(msg)
end
end
function page.editor:eventHandler(event)
if event.type == 'form_cancel' or event.type == 'cancel' then
self:hide()
@ -520,27 +557,20 @@ function page.editor:eventHandler(event)
self.statusBar:setStatus(event.focused.help or '')
self.statusBar:draw()
elseif event.type == 'editIcon' then
local filename = '/tmp/editing.nft'
NFT.save(self.form.image.image or TRANS_ICON, filename)
local success = shell.run('pain.lua ' .. filename)
self.parent:dirty(true)
if success then
self:loadImage(filename)
end
elseif event.type == 'loadIcon' then
local s, m = pcall(function()
local iconLines = Util.readFile(self.form.iconFile.value)
if not iconLines then
error('Must be an NFT image - 3 rows, 8 cols max')
end
local icon, m = parseIcon(iconLines)
if not icon then
error(m)
end
if extSupport then
self.form.values.iconExt = iconLines
else
self.form.values.icon = iconLines
end
self.form.image:setImage(icon)
self.form.image:draw()
end)
if not s and m then
local msg = m:gsub('.*: (.*)', '%1')
self.notification:error(msg)
local success, filename = shell.run('fileui.lua')
self.parent:dirty(true)
if success and filename then
self:loadImage(filename)
end
elseif event.type == 'form_invalid' then
@ -590,5 +620,4 @@ end)
loadApplications()
UI:setPage(page)
UI:pullEvents()
UI:start()

View File

@ -44,7 +44,6 @@ local page = UI.Page {
marginRight = 0, marginLeft = 0,
},
action = UI.SlideOut {
backgroundColor = colors.cyan,
titleBar = UI.TitleBar {
event = 'hide-action',
},

View File

@ -48,6 +48,7 @@ local page = UI.Page {
y = 2,
filterTab = UI.Tab {
tabTitle = 'Filter',
noFill = true,
filterGridText = UI.Text {
x = 2, y = 2,
value = 'ID filter',
@ -130,7 +131,6 @@ local page = UI.Page {
title = 'Packet Information',
event = 'packet_close',
},
backgroundColor = colors.cyan,
accelerators = {
['backspace'] = 'packet_close',
['left'] = 'prev_packet',

View File

@ -11,7 +11,7 @@ local systemPage = UI.Page {
settings = UI.Tab {
tabTitle = 'Category',
grid = UI.ScrollingGrid {
y = 2,
x = 2, y = 2, ex = -2, ey = -2,
columns = {
{ heading = 'Name', key = 'name' },
{ heading = 'Description', key = 'description' },
@ -35,7 +35,7 @@ function systemPage.tabs.settings:eventHandler(event)
tab:disable()
end
systemPage.tabs:selectTab(tab)
self.parent:draw()
--self.parent:draw()
return true
end
end

View File

@ -3,6 +3,7 @@ local UI = require('opus.ui')
local kernel = _G.kernel
local multishell = _ENV.multishell
local tasks = multishell and multishell.getTabs and multishell.getTabs() or kernel.routines
UI:configure('Tasks', ...)
@ -21,7 +22,7 @@ local page = UI.Page {
{ heading = 'Status', key = 'status' },
{ heading = 'Time', key = 'timestamp' },
},
values = kernel.routines,
values = tasks,
sortColumn = 'uid',
autospace = true,
getDisplayValues = function (_, row)

138
sys/apps/fileui.lua Normal file
View File

@ -0,0 +1,138 @@
local UI = require('opus.ui')
local Util = require('opus.util')
local colors = _G.colors
local fs = _G.fs
local shell = _ENV.shell
local selected
-- fileui [--path=path] [--exec=filename]
local page = UI.Page {
title = 'Select File',
-- x = 3, ex = -3, y = 2, ey = -2,
grid = UI.ScrollingGrid {
x = 2, y = 2, ex = -2, ey = -4,
path = '',
sortColumn = 'name',
columns = {
{ heading = 'Name', key = 'name' },
{ heading = 'Size', key = 'size', width = 5 }
},
getDisplayValues = function(_, row)
if row.size then
row = Util.shallowCopy(row)
row.size = Util.toBytes(row.size)
end
return row
end,
getRowTextColor = function(_, file)
if file.isDir then
return colors.cyan
end
if file.isReadOnly then
return colors.pink
end
return colors.white
end,
sortCompare = function(self, a, b)
if self.sortColumn == 'size' then
return a.size < b.size
end
if a.isDir == b.isDir then
return a.name:lower() < b.name:lower()
end
return a.isDir
end,
draw = function(self)
local files = fs.listEx(self.dir)
if #self.dir > 0 then
table.insert(files, {
name = '..',
isDir = true,
})
end
self:setValues(files)
self:setIndex(1)
UI.Grid.draw(self)
end,
},
path = UI.TextEntry {
x = 2,
y = -2,
ex = -11,
limit = 256,
accelerators = {
enter = 'path_enter',
}
},
cancel = UI.Button {
text = 'Cancel',
x = -9,
y = -2,
event = 'cancel',
},
draw = function(self)
self:fillArea(1, 1, self.width, self.height, string.rep('\127', self.width), colors.black, colors.gray)
self:drawChildren()
end,
}
function page:enable(path)
self:setPath(path or shell.dir())
UI.Page.enable(self)
end
function page:setPath(path)
self.grid.dir = path
while not fs.isDir(self.grid.dir) do
self.grid.dir = fs.getDir(self.grid.dir)
end
self.path.value = self.grid.dir
end
function page:eventHandler(event)
if event.type == 'grid_select' then
self.grid.dir = fs.combine(self.grid.dir, event.selected.name)
self.path.value = self.grid.dir
if event.selected.isDir then
self.grid:draw()
self.path:draw()
else
selected = self.path.value
UI:quit()
end
elseif event.type == 'path_enter' then
if fs.isDir(self.path.value) then
self:setPath(self.path.value)
self.grid:draw()
self.path:draw()
else
selected = self.path.value
UI:quit()
end
elseif event.type == 'cancel' then
UI:quit()
else
return UI.Page.eventHandler(self, event)
end
return true
end
local _, args = Util.parse(...)
UI:setPage(page, args.path)
UI:start()
UI.term:setCursorBlink(false)
if args.exec and selected then
shell.openForegroundTab(string.format('%s %s', args.exec, selected))
return
end
--print('selected: ' .. tostring(selected))
return selected

View File

@ -1,5 +1,3 @@
_G.requireInjector(_ENV)
local Event = require('opus.event')
local Util = require('opus.util')

View File

@ -66,11 +66,11 @@ local function run(env, ...)
_ENV.multishell.setTitle(_ENV.multishell.getCurrent(), fs.getName(path):match('([^%.]+)'))
end
if isUrl then
tProgramStack[#tProgramStack + 1] = path -- path:match("^https?://([^/:]+:?[0-9]*/?.*)$")
else
tProgramStack[#tProgramStack + 1] = path
end
tProgramStack[#tProgramStack + 1] = {
path = path, -- path:match("^https?://([^/:]+:?[0-9]*/?.*)$")
env = env,
args = args,
}
env[ "arg" ] = { [0] = path, table.unpack(args) }
local r = { fn(table.unpack(args)) }
@ -278,6 +278,10 @@ function shell.getCompletionInfo()
end
function shell.getRunningProgram()
return tProgramStack[#tProgramStack] and tProgramStack[#tProgramStack].path
end
function shell.getRunningInfo()
return tProgramStack[#tProgramStack]
end

View File

@ -20,7 +20,7 @@ local aliasTab = UI.Tab {
},
},
grid = UI.Grid {
y = 5,
x = 2, y = 5, ex = -2, ey = -2,
sortColumn = 'alias',
columns = {
{ heading = 'Alias', key = 'alias' },

View File

@ -22,20 +22,19 @@ local tab = UI.Tab {
disableHeader = true,
columns = {
{ key = 'file' },
}
},
getRowTextColor = function(self, row)
if row == self.values[1] then
return colors.yellow
end
return UI.Grid.getRowTextColor(self, row)
end,
},
statusBar = UI.StatusBar {
values = 'Double-click to set as preferred'
},
}
function tab.choices:getRowTextColor(row)
if row == self.values[1] then
return colors.yellow
end
return UI.Grid.getRowTextColor(self, row)
end
function tab:updateChoices()
local app = self.apps:getSelected().name
local choices = { }

View File

@ -4,16 +4,17 @@ local UI = require('opus.ui')
local colors = _G.colors
-- -t80x30
if _G.http.websocket then
local config = Config.load('cloud')
local tab = UI.Tab {
tabTitle = 'Cloud',
description = 'Cloud Catcher options',
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 4,
},
key = UI.TextEntry {
x = 3, ex = -3, y = 2,
x = 3, ex = -3, y = 3,
limit = 32,
value = config.key,
shadowText = 'Cloud key',
@ -22,13 +23,14 @@ if _G.http.websocket then
},
},
button = UI.Button {
x = 3, y = 4,
text = 'Update',
x = -8, ex = -2, y = -2,
text = 'Apply',
event = 'update_key',
},
labelText = UI.TextArea {
x = 3, ex = -3, y = 6,
x = 2, ex = -2, y = 6, ey = -4,
textColor = colors.yellow,
backgroundColor = colors.black,
marginLeft = 0, marginRight = 0,
value = string.format(
[[Use a non-changing cloud key. Note that only a single computer can use this session at one time.

View File

@ -20,8 +20,8 @@ local tab = UI.Tab {
description = 'Visualise HDD and disks usage',
drives = UI.ScrollingGrid {
x = 2, y = 1,
ex = '47%', ey = -7,
x = 2, y = 2,
ex = '47%', ey = -8,
columns = {
{ heading = 'Drive', key = 'name' },
{ heading = 'Side' ,key = 'side', textColor = colors.yellow }
@ -30,7 +30,7 @@ local tab = UI.Tab {
},
infos = UI.Grid {
x = '52%', y = 2,
ex = -2, ey = -4,
ex = -2, ey = -8,
disableHeader = true,
unfocusedBackgroundSelectedColor = colors.black,
inactive = true,
@ -40,18 +40,23 @@ local tab = UI.Tab {
{ key = 'value', align = 'right', textColor = colors.yellow },
}
},
[1] = UI.Window {
x = 2, y = -6, ex = -2, ey = -2,
backgroundColor = colors.black,
},
progress = UI.ProgressBar {
x = 11, y = -2,
ex = -2,
x = 11, y = -3,
ex = -3,
},
percentage = UI.Text {
x = 11, y = -3,
ex = '47%',
align = 'center',
y = -4, width = 5,
x = 12,
--align = 'center',
backgroundColor = colors.black,
},
icon = UI.NftImage {
x = 2, y = -5,
x = 2, y = -6, ey = -2,
backgroundColor = colors.black,
image = NFT.parse(NftImages.blank)
},
}

View File

@ -8,7 +8,7 @@ local tab = UI.Tab {
tabTitle = 'Kiosk',
description = 'Kiosk options',
form = UI.Form {
x = 2, ex = -2,
x = 2, y = 2, ex = -2, ey = 5,
manualControls = true,
monitor = UI.Chooser {
formLabel = 'Monitor', formKey = 'monitor',
@ -22,11 +22,12 @@ local tab = UI.Tab {
},
help = 'Adjust text scaling',
},
labelText = UI.TextArea {
x = 2, ex = -2, y = 5,
textColor = colors.yellow,
value = 'Settings apply to kiosk mode selected during startup'
},
},
labelText = UI.TextArea {
x = 2, ex = -2, y = 7, ey = -2,
textColor = colors.yellow,
backgroundColor = colors.black,
value = 'Settings apply to kiosk mode selected during startup'
},
}

View File

@ -8,19 +8,22 @@ local labelTab = UI.Tab {
tabTitle = 'Label',
description = 'Set the computer label',
labelText = UI.Text {
x = 3, y = 2,
x = 3, y = 3,
value = 'Label'
},
label = UI.TextEntry {
x = 9, y = 2, ex = -4,
x = 9, y = 3, ex = -4,
limit = 32,
value = os.getComputerLabel(),
accelerators = {
enter = 'update_label',
},
},
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 4,
},
grid = UI.ScrollingGrid {
y = 3,
x = 2, y = 6, ex = -2, ey = -2,
values = {
{ name = '', value = '' },
{ name = 'CC version', value = Util.getVersion() },
@ -30,10 +33,11 @@ local labelTab = UI.Tab {
{ name = 'Computer ID', value = tostring(os.getComputerID()) },
{ name = 'Day', value = tostring(os.day()) },
},
disableHeader = true,
inactive = true,
columns = {
{ key = 'name', width = 12 },
{ key = 'value' },
{ key = 'value', textColor = colors.yellow },
},
},
}

View File

@ -9,12 +9,15 @@ local config = Config.load('multishell')
local tab = UI.Tab {
tabTitle = 'Launcher',
description = 'Set the application launcher',
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 5,
},
launcherLabel = UI.Text {
x = 3, y = 2,
x = 3, y = 3,
value = 'Launcher',
},
launcher = UI.Chooser {
x = 13, y = 2, width = 12,
x = 13, y = 3, width = 12,
choices = {
{ name = 'Overview', value = 'sys/apps/Overview.lua' },
{ name = 'Shell', value = 'sys/apps/ShellLauncher.lua' },
@ -22,17 +25,18 @@ local tab = UI.Tab {
},
},
custom = UI.TextEntry {
x = 13, ex = -3, y = 3,
x = 13, ex = -3, y = 4,
limit = 128,
shadowText = 'File name',
},
button = UI.Button {
x = 3, y = 5,
text = 'Update',
x = -8, ex = -2, y = -2,
text = 'Apply',
event = 'update',
},
labelText = UI.TextArea {
x = 3, ex = -3, y = 7,
x = 2, ex = -2, y = 7, ey = -4,
backgroundColor = colors.black,
textColor = colors.yellow,
value = 'Choose an application launcher',
},

View File

@ -2,24 +2,29 @@ local Ansi = require('opus.ansi')
local Config = require('opus.config')
local UI = require('opus.ui')
local colors = _G.colors
local device = _G.device
local tab = UI.Tab {
tabTitle = 'Network',
description = 'Networking options',
info = UI.TextArea {
x = 3, y = 4,
x = 2, y = 6, ex = -2, ey = -2,
backgroundColor = colors.black,
value = string.format(
[[%sSet the primary modem used for wireless communications.%s
Reboot to take effect.]], Ansi.yellow, Ansi.reset)
},
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 4,
},
label = UI.Text {
x = 3, y = 2,
x = 3, y = 3,
value = 'Modem',
},
modem = UI.Chooser {
x = 10, ex = -3, y = 2,
x = 10, ex = -3, y = 3,
nochoice = 'auto',
},
}

View File

@ -7,6 +7,9 @@ local colors = _G.colors
local passwordTab = UI.Tab {
tabTitle = 'Password',
description = 'Wireless network password',
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 4,
},
newPass = UI.TextEntry {
x = 3, ex = -3, y = 3,
limit = 32,
@ -17,12 +20,13 @@ local passwordTab = UI.Tab {
},
},
button = UI.Button {
x = 3, y = 5,
text = 'Update',
x = -8, ex = -2, y = -2,
text = 'Apply',
event = 'update_password',
},
info = UI.TextArea {
x = 3, ex = -3, y = 7,
x = 2, ex = -2, y = 6, ey = -4,
backgroundColor = colors.black,
textColor = colors.yellow,
inactive = true,
value = 'Add a password to enable other computers to connect to this one.',

View File

@ -6,8 +6,11 @@ local tab = UI.Tab {
tabTitle = 'Path',
description = 'Set the shell path',
tabClose = true,
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 4,
},
entry = UI.TextEntry {
x = 2, y = 2, ex = -2,
x = 3, y = 3, ex = -3,
limit = 256,
shadowText = 'enter new path',
accelerators = {
@ -16,7 +19,7 @@ local tab = UI.Tab {
help = 'add a new path',
},
grid = UI.Grid {
y = 4, ey = -3,
x = 2, y = 6, ex = -2, ey = -3,
disableHeader = true,
columns = { { key = 'value' } },
autospace = true,

View File

@ -7,7 +7,7 @@ if settings then
tabTitle = 'Settings',
description = 'Computercraft configurable settings',
grid = UI.Grid {
y = 2,
x = 2, y = 2, ex = -2, ey = -2,
autospace = true,
sortColumn = 'name',
columns = {

View File

@ -42,25 +42,23 @@ local tab = UI.Tab {
tabTitle = 'Shell',
description = 'Shell options',
grid1 = UI.ScrollingGrid {
y = 2, ey = -10, x = 3, ex = -16,
y = 2, ey = -10, x = 2, ex = -17,
disableHeader = true,
columns = { { key = 'name' } },
values = allSettings,
sortColumn = 'name',
},
grid2 = UI.ScrollingGrid {
y = 2, ey = -10, x = -14, ex = -3,
y = 2, ey = -10, x = -14, ex = -2,
disableHeader = true,
columns = { { key = 'name' } },
values = allColors,
sortColumn = 'name',
},
directoryLabel = UI.Text {
x = 2, y = -2,
value = 'Display directory',
},
directory = UI.Checkbox {
x = 20, y = -2,
x = 2, y = -2,
labelBackgroundColor = colors.black,
label = 'Directory',
value = config.displayDirectory
},
reset = UI.Button {
@ -74,7 +72,7 @@ local tab = UI.Tab {
event = 'update',
},
display = UI.Window {
x = 3, ex = -3, y = -8, height = 5,
x = 2, ex = -2, y = -8, height = 5,
},
}

View File

@ -21,4 +21,4 @@ deleteIfExists('sys/autorun/apps.lua')
deleteIfExists('sys/init/6.tl3.lua')
-- remove this file
deleteIfExists('sys/autorun/upgraded.lua')
--deleteIfExists('sys/autorun/upgraded.lua')

View File

@ -1,5 +1,3 @@
_G.requireInjector(_ENV)
local Peripheral = require('opus.peripheral')
_G.device = Peripheral.getList()

View File

@ -4,11 +4,8 @@ if fs.native then
return
end
_G.requireInjector(_ENV)
local Util = require('opus.util')
-- TODO: support getDrive for virtual nodes
fs.native = Util.shallowCopy(fs)
local fstypes = { }
@ -23,7 +20,6 @@ for k,fn in pairs(fs) do
end
function nativefs.list(node, dir)
local files
if fs.native.isDir(dir) then
files = fs.native.list(dir)
@ -265,7 +261,6 @@ local function getfstype(fstype)
end
function fs.mount(path, fstype, ...)
local vfs = getfstype(fstype)
if not vfs then
error('Invalid file system type')

View File

@ -1,5 +1,3 @@
_G.requireInjector(_ENV)
local Config = require('opus.config')
local device = _G.device

View File

@ -1,5 +1,3 @@
_G.requireInjector(_ENV)
local Config = require('opus.config')
local trace = require('opus.trace')
local Util = require('opus.util')
@ -334,16 +332,12 @@ kernel.hook('mouse_scroll', function(_, eventData)
end)
kernel.hook('kernel_ready', function()
local env = Util.shallowCopy(shell.getEnv())
_G.requireInjector(env)
overviewId = multishell.openTab({
path = config.launcher or 'sys/apps/Overview.lua',
isOverview = true,
noTerminate = true,
focused = true,
title = '+',
env = env,
})
multishell.openTab({

View File

@ -1,5 +1,3 @@
_G.requireInjector(_ENV)
local Array = require('opus.array')
local Terminal = require('opus.terminal')
local Util = require('opus.util')

View File

@ -14,7 +14,7 @@ function Array.removeByValue(t, e)
for k,v in pairs(t) do
if v == e then
table.remove(t, k)
break
return e
end
end
end

View File

@ -50,18 +50,20 @@ function input:toCode(ch, code)
table.insert(result, 'alt')
end
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
code == keys.leftShift or code == keys.rightShift then
if code and modifiers[code] then
table.insert(result, 'shift')
elseif #ch == 1 then
table.insert(result, ch:upper())
else
table.insert(result, 'shift')
if ch then -- some weird things happen with control/command on mac
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
code == keys.leftShift or code == keys.rightShift then
if code and modifiers[code] then
table.insert(result, 'shift')
elseif #ch == 1 then
table.insert(result, ch:upper())
else
table.insert(result, 'shift')
table.insert(result, ch)
end
elseif not code or not modifiers[code] then
table.insert(result, ch)
end
elseif not code or not modifiers[code] then
table.insert(result, ch)
end
return table.concat(result, '-')
@ -118,6 +120,7 @@ function input:translate(event, code, p1, p2)
local buttons = { 'mouse_click', 'mouse_rightclick' }
self.mch = buttons[code]
self.mfired = nil
self.anchor = { x = p1, y = p2 }
return {
code = input:toCode('mouse_down', 255),
button = code,
@ -132,6 +135,8 @@ function input:translate(event, code, p1, p2)
button = code,
x = p1,
y = p2,
dx = p1 - self.anchor.x,
dy = p2 - self.anchor.y,
}
elseif event == 'mouse_up' then

View File

@ -1,16 +1,19 @@
local Util = require('opus.util')
local colors = _G.colors
local NFT = { }
-- largely copied from http://www.computercraft.info/forums2/index.php?/topic/5029-145-npaintpro/
local tColourLookup = { }
local hexToColor = { }
for n = 1, 16 do
tColourLookup[string.byte("0123456789abcdef", n, n)] = 2 ^ (n - 1)
hexToColor[string.sub("0123456789abcdef", n, n)] = 2 ^ (n - 1)
end
local colorToHex = Util.transpose(hexToColor)
local function getColourOf(hex)
return tColourLookup[hex:byte()]
return hexToColor[hex]
end
function NFT.parse(imageText)
@ -62,8 +65,22 @@ function NFT.parse(imageText)
return image
end
function NFT.load(path)
function NFT.transparency(image)
for y = 1, image.height do
for _,key in pairs(Util.keys(image.fg[y])) do
if image.fg[y][key] == colors.magenta then
image.fg[y][key] = nil
end
end
for _,key in pairs(Util.keys(image.bg[y])) do
if image.bg[y][key] == colors.magenta then
image.bg[y][key] = nil
end
end
end
end
function NFT.load(path)
local imageText = Util.readFile(path)
if not imageText then
error('Unable to read image file')
@ -71,4 +88,35 @@ function NFT.load(path)
return NFT.parse(imageText)
end
function NFT.save(image, filename)
local bgcode, txcode = '\30', '\31'
local output = { }
for y = 1, image.height do
local lastBG, lastFG
if image.text[y] then
for x = 1, #image.text[y] do
local bg = image.bg[y][x] or colors.magenta
if bg ~= lastBG then
lastBG = bg
table.insert(output, bgcode .. colorToHex[bg])
end
local fg = image.fg[y][x] or colors.magenta
if fg ~= lastFG then
lastFG = fg
table.insert(output, txcode .. colorToHex[fg])
end
table.insert(output, image.text[y][x])
end
end
if y < image.height then
table.insert(output, '\n')
end
end
Util.writeFile(filename, table.concat(output))
end
return NFT

View File

@ -38,7 +38,7 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
local blink = false
local bg, fg = parent.getBackgroundColor(), parent.getTextColor()
local canvas = Canvas({
win.canvas = Canvas({
x = sx,
y = sy,
width = w,
@ -47,50 +47,53 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
offy = 0,
})
win.canvas = canvas
local function update()
if isVisible then
canvas:render(parent)
win.canvas:render(parent)
win.setCursorPos(cx, cy)
end
end
local function scrollTo(y)
y = math.max(0, y)
y = math.min(#canvas.lines - canvas.height, y)
y = math.min(#win.canvas.lines - win.canvas.height, y)
if y ~= canvas.offy then
canvas.offy = y
canvas:dirty()
if y ~= win.canvas.offy then
win.canvas.offy = y
win.canvas:dirty()
update()
end
end
function win.write(str)
str = tostring(str) or ''
canvas:write(cx, cy + canvas.offy, str, bg, fg)
win.canvas:write(cx, cy + win.canvas.offy, str, bg, fg)
win.setCursorPos(cx + #str, cy)
update()
end
function win.blit(str, fg, bg)
canvas:blit(cx, cy + canvas.offy, str, bg, fg)
win.canvas:blit(cx, cy + win.canvas.offy, str, bg, fg)
win.setCursorPos(cx + #str, cy)
update()
end
function win.clear()
canvas.offy = 0
for i = #canvas.lines, canvas.height + 1, -1 do
canvas.lines[i] = nil
win.canvas.offy = 0
for i = #win.canvas.lines, win.canvas.height + 1, -1 do
win.canvas.lines[i] = nil
end
canvas:clear(bg, fg)
win.canvas:clear(bg, fg)
update()
end
function win.getLine(n)
local line = win.canvas.lines[n]
return line.text, line.fg, line.bg
end
function win.clearLine()
canvas:clearLine(cy + canvas.offy, bg, fg)
win.canvas:clearLine(cy + win.canvas.offy, bg, fg)
win.setCursorPos(cx, cy)
update()
end
@ -102,10 +105,14 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
function win.setCursorPos(x, y)
cx, cy = math.floor(x), math.floor(y)
if isVisible then
parent.setCursorPos(cx + canvas.x - 1, cy + canvas.y - 1)
parent.setCursorPos(cx + win.canvas.x - 1, cy + win.canvas.y - 1)
end
end
function win.getCursorBlink()
return blink
end
function win.setCursorBlink(b)
blink = b
if isVisible then
@ -114,7 +121,7 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
end
function win.isColor()
return canvas.isColor
return win.canvas.isColor
end
win.isColour = win.isColor
@ -144,22 +151,22 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
win.setBackgroundColour = win.setBackgroundColor
function win.getSize()
return canvas.width, canvas.height
return win.canvas.width, win.canvas.height
end
function win.scroll(n)
n = n or 1
if n > 0 then
local lines = #canvas.lines
local lines = #win.canvas.lines
for i = 1, n do
canvas.lines[lines + i] = { }
canvas:clearLine(lines + i, bg, fg)
win.canvas.lines[lines + i] = { }
win.canvas:clearLine(lines + i, bg, fg)
end
while #canvas.lines > maxScroll do
table.remove(canvas.lines, 1)
while #win.canvas.lines > maxScroll do
table.remove(win.canvas.lines, 1)
end
scrollTo(#canvas.lines)
canvas:dirty()
scrollTo(#win.canvas.lines)
win.canvas:dirty()
update()
end
end
@ -178,7 +185,7 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
if visible ~= isVisible then
isVisible = visible
if isVisible then
canvas:dirty()
win.canvas:dirty()
update()
end
end
@ -186,7 +193,7 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
function win.redraw()
if isVisible then
canvas:dirty()
win.canvas:dirty()
update()
end
end
@ -200,21 +207,21 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
end
function win.getPosition()
return canvas.x, canvas.y
return win.canvas.x, win.canvas.y
end
function win.reposition(x, y, width, height)
canvas.x, canvas.y = x, y
canvas:resize(width or canvas.width, height or canvas.height)
win.canvas.x, win.canvas.y = x, y
win.canvas:resize(width or win.canvas.width, height or win.canvas.height)
end
--[[ Additional methods ]]--
function win.scrollDown()
scrollTo(canvas.offy + 1)
scrollTo(win.canvas.offy + 1)
end
function win.scrollUp()
scrollTo(canvas.offy - 1)
scrollTo(win.canvas.offy - 1)
end
function win.scrollTop()
@ -222,7 +229,7 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
end
function win.scrollBottom()
scrollTo(#canvas.lines)
scrollTo(#win.canvas.lines)
end
function win.setMaxScroll(ms)
@ -230,37 +237,35 @@ function Terminal.window(parent, sx, sy, w, h, isVisible)
end
function win.getCanvas()
return canvas
return win.canvas
end
function win.getParent()
return parent
end
canvas:clear()
win.canvas:clear()
return win
end
-- get windows contents
function Terminal.getContents(win, parent)
local oblit, oscp = parent.blit, parent.setCursorPos
local lines = { }
function Terminal.getContents(win)
if not win.getLine then
error('window is required')
end
parent.blit = function(text, fg, bg)
lines[#lines + 1] = {
local lines = { }
local _, h = win.getSize()
for i = 1, h do
local text, fg, bg = win.getLine(i)
lines[i] = {
text = text,
fg = fg,
bg = bg,
}
end
parent.setCursorPos = function() end
win.setVisible(true)
win.redraw()
parent.blit = oblit
parent.setCursorPos = oscp
return lines
end

View File

@ -1,8 +1,10 @@
local Array = require('opus.array')
local class = require('opus.class')
local Event = require('opus.event')
local Input = require('opus.input')
local Transition = require('opus.ui.transition')
local Util = require('opus.util')
local Canvas = require('opus.ui.canvas')
local _rep = string.rep
local _sub = string.sub
@ -44,8 +46,7 @@ function Manager:init()
local currentPage = self:getActivePage()
if ie and currentPage then
local target = currentPage.focused or currentPage
self:inputEvent(target,
{ type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target, ie = ie })
target:emit({ type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target, ie = ie })
currentPage:sync()
end
end
@ -81,8 +82,7 @@ function Manager:init()
}
-- revisit - should send out scroll_up and scroll_down events
-- let the element convert them to up / down
self:inputEvent(event.element,
{ type = 'key', key = directions[direction] })
event.element:emit({ type = 'key', key = directions[direction] })
currentPage:sync()
end
end,
@ -92,7 +92,7 @@ function Manager:init()
if dev and dev.currentPage then
Input:translate('mouse_click', 1, x, y)
local ie = Input:translate('mouse_up', 1, x, y)
self:click(dev.currentPage, ie.code, 1, x, y)
self:click(dev.currentPage, ie)
end
end,
@ -107,7 +107,7 @@ function Manager:init()
currentPage:setFocus(event.element)
currentPage:sync()
end
self:click(currentPage, ie.code, button, x, y)
self:click(currentPage, ie)
end
end
end,
@ -125,7 +125,7 @@ function Manager:init()
elseif ie and currentPage then
if not currentPage.parent.device.side then
self:click(currentPage, ie.code, button, x, y)
self:click(currentPage, ie)
end
end
end,
@ -135,7 +135,7 @@ function Manager:init()
local currentPage = self:getActivePage()
if ie and currentPage then
self:click(currentPage, ie.code, button, x, y)
self:click(currentPage, ie)
end
end,
@ -247,30 +247,44 @@ function Manager:emitEvent(event)
end
end
function Manager:inputEvent(parent, event) -- deprecate ?
return parent and parent:emit(event)
end
function Manager:click(target, ie)
local clickEvent
function Manager:click(target, code, button, x, y)
local clickEvent = target:pointToChild(x, y)
if ie.code == 'mouse_drag' then
clickEvent = {
element = self.lastClicked,
x = ie.x,
y = ie.y, -- this is not correct (should be relative to element)
dx = ie.dx,
dy = ie.dy,
}
else
clickEvent = target:pointToChild(ie.x, ie.y)
end
if code == 'mouse_doubleclick' then
if self.doubleClickElement ~= clickEvent.element then
-- hack for dropdown menus
if ie.code == 'mouse_click' and not clickEvent.element.focus then
self:emitEvent({ type = 'mouse_out' })
end
if ie.code == 'mouse_doubleclick' then
if self.lastClicked ~= clickEvent.element then
return
end
else
self.doubleClickElement = clickEvent.element
self.lastClicked = clickEvent.element
end
clickEvent.button = button
clickEvent.type = code
clickEvent.key = code
clickEvent.ie = { code = code, x = clickEvent.x, y = clickEvent.y }
clickEvent.button = ie.button
clickEvent.type = ie.code
clickEvent.key = ie.code
clickEvent.ie = { code = ie.code, x = clickEvent.x, y = clickEvent.y }
clickEvent.raw = ie
if clickEvent.element.focus then
target:setFocus(clickEvent.element)
end
self:inputEvent(clickEvent.element, clickEvent)
clickEvent.element:emit(clickEvent)
target:sync()
end
@ -310,7 +324,6 @@ end
function Manager:setActivePage(page)
page.parent.currentPage = page
page.parent.canvas = page.canvas
end
function Manager:setPage(pageOrName, ...)
@ -388,6 +401,12 @@ function Manager:pullEvents(...)
end
end
Manager.colors = {
primary = colors.cyan,
secondary = colors.blue,
tertiary = colors.blue,
}
Manager.exitPullEvents = Event.exitPullEvents
Manager.quit = Event.exitPullEvents
Manager.start = Manager.pullEvents
@ -395,7 +414,7 @@ Manager.start = Manager.pullEvents
local UI = Manager()
--[[-- Basic drawable area --]]--
UI.Window = class()
UI.Window = class(Canvas)
UI.Window.uid = 1
UI.Window.docs = { }
UI.Window.defaults = {
@ -413,7 +432,9 @@ function UI.Window:init(args)
local defaults = args
local m = getmetatable(self) -- get the class for this instance
repeat
defaults = UI:getDefaults(m, defaults)
if m.disable then
defaults = UI:getDefaults(m, defaults)
end
m = m._base
until not m
UI:mergeProperties(self, defaults)
@ -531,6 +552,8 @@ function UI.Window:layout()
if not self.height then
self.height = self.parent.height - self.y + 1
end
self:reposition(self.x, self.y, self.width, self.height)
end
-- Called when the window's parent has be assigned
@ -539,23 +562,6 @@ function UI.Window:setParent()
self.ox, self.oy = self.x, self.y
self:layout()
-- Experimental
-- Inherit properties from the parent container
-- does this need to be in reverse order ?
local m = getmetatable(self) -- get the class for this instance
repeat
if m.inherits then
for k, v in pairs(m.inherits) do
local value = self.parent:getProperty(v)
if value then
self[k] = value
end
end
end
m = m._base
until not m
self:initChildren()
end
@ -566,12 +572,33 @@ function UI.Window:resize()
self:layout()
if self.children then
for _,child in ipairs(self.children) do
for child in self:eachChild() do
child:resize()
end
end
end
function UI.Window:reposition(x, y, w, h)
if not self.lines then
Canvas.init(self, {
x = x,
y = y,
width = w,
height = h,
isColor = self.parent.isColor,
})
else
self:move(x, y)
Canvas.resize(self, w, h)
end
end
function UI.Window:raise()
Array.removeByValue(self.parent.children, self)
table.insert(self.parent.children, self)
self:dirty(true)
end
UI.Window.docs.add = [[add(TABLE)
Add element(s) to a window. Example:
page:add({
@ -584,6 +611,20 @@ function UI.Window:add(children)
self:initChildren()
end
function UI.Window:eachChild()
local c = self.children and Util.shallowCopy(self.children)
local i = 0
return function()
i = i + 1
return c and c[i]
end
end
function UI.Window:remove()
Array.removeByValue(self.parent.children, self)
self.parent:dirty(true)
end
function UI.Window:getCursorPos()
return self.cursorX, self.cursorY
end
@ -601,12 +642,14 @@ end
UI.Window.docs.draw = [[draw(VOID)
Redraws the window in the internal buffer.]]
function UI.Window:draw()
self:clear(self.backgroundColor)
if self.children then
for _,child in pairs(self.children) do
if child.enabled then
child:draw()
end
self:clear()
self:drawChildren()
end
function UI.Window:drawChildren()
for child in self:eachChild() do
if child.enabled then
child:draw()
end
end
end
@ -634,19 +677,30 @@ end
function UI.Window:enable(...)
self.enabled = true
if self.children then
for _,child in pairs(self.children) do
child:enable(...)
end
if self.transitionHint then
self:addTransition(self.transitionHint)
end
if self.modal then
self:raise()
self:capture(self)
end
for child in self:eachChild() do
child:enable(...)
end
end
function UI.Window:disable()
self.enabled = false
if self.children then
for _,child in pairs(self.children) do
child:disable()
end
self.parent:dirty(true)
if self.modal then
self:release(self)
end
for child in self:eachChild() do
child:disable()
end
end
@ -656,13 +710,9 @@ function UI.Window:setTextScale(textScale)
end
UI.Window.docs.clear = [[clear(opt COLOR bg, opt COLOR fg)
Clears the window using the either the passed values or the defaults for that window.]]
Clears the window using either the passed values or the defaults for that window.]]
function UI.Window:clear(bg, fg)
if self.canvas then
self.canvas:clear(bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
else
self:clearArea(1 + self.offx, 1 + self.offy, self.width, self.height, bg)
end
Canvas.clear(self, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
end
function UI.Window:clearLine(y, bg)
@ -670,28 +720,20 @@ function UI.Window:clearLine(y, bg)
end
function UI.Window:clearArea(x, y, width, height, bg)
self:fillArea(x, y, width, height, ' ', bg)
end
function UI.Window:fillArea(x, y, width, height, fillChar, bg, fg)
if width > 0 then
local filler = _rep(' ', width)
local filler = _rep(fillChar, width)
for i = 0, height - 1 do
self:write(x, y + i, filler, bg)
self:write(x, y + i, filler, bg, fg)
end
end
end
function UI.Window:write(x, y, text, bg, fg)
bg = bg or self.backgroundColor
fg = fg or self.textColor
if self.canvas then
self.canvas:write(x, y, text, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
else
x = x - self.offx
y = y - self.offy
if y <= self.height and y > 0 then
self.parent:write(
self.x + x - 1, self.y + y - 1, tostring(text), bg, fg)
end
end
Canvas.write(self, x, y, text, bg or self:getProperty('backgroundColor'), fg or self:getProperty('textColor'))
end
function UI.Window:centeredWrite(y, text, bg, fg)
@ -826,7 +868,8 @@ function UI.Window:pointToChild(x, y)
x = x + self.offx - self.x + 1
y = y + self.offy - self.y + 1
if self.children then
for _,child in pairs(self.children) do
for i = #self.children, 1, -1 do
local child = self.children[i]
if child.enabled and not child.inactive and
x >= child.x and x < child.x + child.width and
y >= child.y and y < child.y + child.height then
@ -882,36 +925,28 @@ function UI.Window:focusFirst()
end
end
function UI.Window:refocus()
local el = self
while el do
local focusables = el:getFocusables()
if focusables[1] then
self:setFocus(focusables[1])
break
end
el = el.parent
end
end
function UI.Window:scrollIntoView()
local parent = self.parent
local offx, offy = parent.offx, parent.offy
if self.x <= parent.offx then
parent.offx = math.max(0, self.x - 1)
parent:draw()
if offx ~= parent.offx then
parent:draw()
end
elseif self.x + self.width > parent.width + parent.offx then
parent.offx = self.x + self.width - parent.width - 1
parent:draw()
if offx ~= parent.offx then
parent:draw()
end
end
-- TODO: fix
local function setOffset(y)
parent.offy = y
if parent.canvas then
parent.canvas.offy = parent.offy
if offy ~= parent.offy then
parent:draw()
end
parent:draw()
end
if self.y <= parent.offy then
@ -921,43 +956,16 @@ function UI.Window:scrollIntoView()
end
end
function UI.Window:getCanvas()
local el = self
repeat
if el.canvas then
return el.canvas
end
el = el.parent
until not el
end
function UI.Window:addLayer(bg, fg)
local canvas = self:getCanvas()
local x, y = self.x, self.y
local parent = self.parent
while parent and not parent.canvas do
x = x + parent.x - 1
y = y + parent.y - 1
parent = parent.parent
end
canvas = canvas:addLayer({
x = x, y = y, height = self.height, width = self.width
}, bg, fg)
canvas:clear(bg or self.backgroundColor, fg or self.textColor)
return canvas
end
function UI.Window:addTransition(effect, args)
if self.parent then
args = args or { }
if not args.x then -- not good
args.x, args.y = self.x, self.y -- getPosition(self)
args.x, args.y = self.x, self.y
args.width = self.width
args.height = self.height
args.canvas = self
end
args.canvas = args.canvas or self.canvas
self.parent:addTransition(effect, args)
end
end
@ -991,7 +999,16 @@ function UI.Window:getProperty(property)
end
function UI.Window:find(uid)
return self.children and Util.find(self.children, 'uid', uid)
local el = self.children and Util.find(self.children, 'uid', uid)
if not el then
for child in self:eachChild() do
el = child:find(uid)
if el then
break
end
end
end
return el
end
function UI.Window:eventHandler()
@ -1010,18 +1027,14 @@ UI.Device.defaults = {
function UI.Device:postInit()
self.device = self.device or term.current()
--if self.deviceType then
-- self.device = device[self.deviceType]
--end
if not self.device.setTextScale then
self.device.setTextScale = function() end
end
self.device.setTextScale(self.textScale)
self.width, self.height = self.device.getSize()
self.isColor = self.device.isColor()
Canvas.init(self, { isColor = self.isColor })
UI.devices[self.device.side or 'terminal'] = self
end
@ -1031,8 +1044,8 @@ function UI.Device:resize()
self.width, self.height = self.device.getSize()
self.lines = { }
-- TODO: resize all pages added to this device
self.canvas:resize(self.width, self.height)
self.canvas:clear(self.backgroundColor, self.textColor)
Canvas.resize(self, self.width, self.height)
Canvas.clear(self, self.backgroundColor, self.textColor)
end
function UI.Device:setCursorPos(x, y)
@ -1069,7 +1082,7 @@ function UI.Device:addTransition(effect, args)
args = args or { }
args.ex = args.x + args.width - 1
args.ey = args.y + args.height - 1
args.canvas = args.canvas or self.canvas
args.canvas = args.canvas or self
if type(effect) == 'string' then
effect = Transition[effect]
@ -1078,10 +1091,13 @@ function UI.Device:addTransition(effect, args)
end
end
table.insert(self.transitions, { update = effect(args), args = args })
table.insert(self.transitions, { effect = effect, args = args })
end
function UI.Device:runTransitions(transitions, canvas)
function UI.Device:runTransitions(transitions)
for _,k in pairs(transitions) do
k.update = k.effect(k.args)
end
while true do
for _,k in ipairs(Util.keys(transitions)) do
local transition = transitions[k]
@ -1089,7 +1105,7 @@ function UI.Device:runTransitions(transitions, canvas)
transitions[k] = nil
end
end
canvas:render(self.device)
self.currentPage:render(self.device)
if Util.empty(transitions) then
break
end
@ -1105,9 +1121,9 @@ function UI.Device:sync()
self.device.setCursorBlink(false)
end
self.canvas:render(self.device)
self.currentPage:render(self.device)
if transitions then
self:runTransitions(transitions, self.canvas)
self:runTransitions(transitions)
end
if self:getCursorBlink() then

View File

@ -9,7 +9,6 @@ local colors = _G.colors
local Canvas = class()
Canvas.__visualize = false
Canvas.colorPalette = { }
Canvas.darkPalette = { }
Canvas.grayscalePalette = { }
@ -22,15 +21,17 @@ end
--[[
A canvas can have more lines than canvas.height in order to scroll
]]
TODO: finish vertical scrolling
]]
function Canvas:init(args)
self.x = 1
self.y = 1
self.layers = { }
self.bg = colors.black
self.fg = colors.white
Util.merge(self, args)
self.x = self.x or 1
self.y = self.y or 1
self.ex = self.x + self.width - 1
self.ey = self.y + self.height - 1
@ -46,15 +47,30 @@ function Canvas:init(args)
for i = 1, self.height do
self.lines[i] = { }
end
self:clear()
end
function Canvas:move(x, y)
self.x, self.y = x, y
self.ex = self.x + self.width - 1
self.ey = self.y + self.height - 1
if self.parent then
self.parent:dirty(true)
end
end
function Canvas:resize(w, h)
self:resizeBuffer(w, h)
self.ex = self.x + w - 1
self.ey = self.y + h - 1
self.width = w
self.height = h
end
-- resize the canvas buffer - not the canvas itself
function Canvas:resizeBuffer(w, h)
for i = #self.lines, h do
self.lines[i] = { }
self:clearLine(i)
@ -66,26 +82,24 @@ function Canvas:resize(w, h)
if w < self.width then
for i = 1, h do
self.lines[i].text = _sub(self.lines[i].text, 1, w)
self.lines[i].fg = _sub(self.lines[i].fg, 1, w)
self.lines[i].bg = _sub(self.lines[i].bg, 1, w)
local ln = self.lines[i]
ln.text = _sub(ln.text, 1, w)
ln.fg = _sub(ln.fg, 1, w)
ln.bg = _sub(ln.bg, 1, w)
end
elseif w > self.width then
local d = w - self.width
local text = _rep(' ', d)
local fg = _rep(self.palette[self.fg or colors.white], d)
local bg = _rep(self.palette[self.bg or colors.black], d)
local fg = _rep(self.palette[self.fg], d)
local bg = _rep(self.palette[self.bg], d)
for i = 1, h do
self.lines[i].text = self.lines[i].text .. text
self.lines[i].fg = self.lines[i].fg .. fg
self.lines[i].bg = self.lines[i].bg .. bg
local ln = self.lines[i]
ln.text = ln.text .. text
ln.fg = ln.fg .. fg
ln.bg = ln.bg .. bg
ln.dirty = true
end
end
self.ex = self.x + w - 1
self.ey = self.y + h - 1
self.width = w
self.height = h
end
function Canvas:copy()
@ -113,22 +127,25 @@ function Canvas:addLayer(layer)
isColor = self.isColor,
})
canvas.parent = self
table.insert(self.layers, canvas)
if not self.children then
self.children = { }
end
table.insert(self.children, canvas)
return canvas
end
function Canvas:removeLayer()
for k, layer in pairs(self.parent.layers) do
for k, layer in pairs(self.parent.children) do
if layer == self then
self:setVisible(false)
table.remove(self.parent.layers, k)
table.remove(self.parent.children, k)
break
end
end
end
function Canvas:setVisible(visible)
self.visible = visible
self.visible = visible -- TODO: use self.active = visible
if not visible and self.parent then
self.parent:dirty()
-- TODO: set parent's lines to dirty for each line in self
@ -137,11 +154,10 @@ end
-- Push a layer to the top
function Canvas:raise()
if self.parent then
local layers = self.parent.layers or { }
for k, v in pairs(layers) do
if self.parent and self.parent.children then
for k, v in pairs(self.parent.children) do
if v == self then
table.insert(layers, table.remove(layers, k))
table.insert(self.parent.children, table.remove(self.parent.children, k))
break
end
end
@ -224,15 +240,15 @@ function Canvas:writeLine(y, text, fg, bg)
end
function Canvas:clearLine(y, bg, fg)
fg = _rep(self.palette[fg or colors.white], self.width)
bg = _rep(self.palette[bg or colors.black], self.width)
fg = _rep(self.palette[fg or self.fg], self.width)
bg = _rep(self.palette[bg or self.bg], self.width)
self:writeLine(y, _rep(' ', self.width), fg, bg)
end
function Canvas:clear(bg, fg)
local text = _rep(' ', self.width)
fg = _rep(self.palette[fg or colors.white], self.width)
bg = _rep(self.palette[bg or colors.black], self.width)
fg = _rep(self.palette[fg or self.fg], self.width)
bg = _rep(self.palette[bg or self.bg], self.width)
for i = 1, #self.lines do
self:writeLine(i, text, fg, bg)
end
@ -246,13 +262,16 @@ function Canvas:isDirty()
end
end
function Canvas:dirty()
for i = 1, #self.lines do
self.lines[i].dirty = true
end
if self.layers then
for _, canvas in pairs(self.layers) do
canvas:dirty()
function Canvas:dirty(includingChildren)
if self.lines then
for i = 1, #self.lines do
self.lines[i].dirty = true
end
if includingChildren and self.children then
for _, child in pairs(self.children) do
child:dirty(true)
end
end
end
end
@ -280,104 +299,89 @@ end
function Canvas:render(device)
local offset = { x = 0, y = 0 }
-- WIP
local function getRegion(canvas)
local region
if canvas.parent then
region = getRegion(canvas.parent)
else
region = Region.new(self.x, self.y, self.ex, self.ey)
end
offset.x = offset.x + canvas.x - 1
offset.y = offset.y + canvas.y - 1
-- clip against parent
return region
end
-- this code works - but is all kinds of wrong
-- adding a margin to UI.Page will cause issues
-- and could be clipping issues
offset = { x = self.x - 1, y = self.y - 1 }
local parent = self.parent
while parent do
offset.x = offset.x + parent.x - 1
offset.y = offset.y + parent.y - 1
parent = parent.parent
end
if #self.layers > 0 then
self:__renderLayers(device, offset)
else
self:__blitRect(device, nil, {
x = self.x + offset.x,
y = self.y + offset.y
})
self:clean()
end
-- TODO: need to clip if there is a parent
--self.regions = Region.new(self.x + offset.x, self.y + offset.y, self.ex + offset.x, self.ey + offset.y)
--self:__renderLayers(device, offset)
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
self:__renderLayers(device, { x = self.x - 1, y = self.y - 1 })
end
-- regions are comprised of absolute values that coorespond to the output device.
-- regions are comprised of absolute values that correspond to the output device.
-- canvases have coordinates relative to their parent.
-- canvas layer's stacking order is determined by the position within the array.
-- layers in the beginning of the array are overlayed by layers further down in
-- the array.
function Canvas:__renderLayers(device, offset)
if #self.layers > 0 then
self.regions = self.regions or Region.new(self.x + offset.x, self.y + offset.y, self.ex + offset.x, self.ey + offset.y)
for i = 1, #self.layers do
local canvas = self.layers[i]
if canvas.visible then
-- punch out this area from the parent's canvas
self:__punch(canvas, offset)
if self.children then
for i = #self.children, 1, -1 do
local canvas = self.children[i]
if canvas.visible or canvas.enabled then
-- get the area to render for this layer
canvas.regions = Region.new(
canvas.x + offset.x,
canvas.y + offset.y,
canvas.ex + offset.x,
canvas.ey + offset.y)
canvas.x + offset.x - (self.offx or 0),
canvas.y + offset.y - (self.offy or 0),
canvas.ex + offset.x - (self.offx or 0),
canvas.ey + offset.y - (self.offy or 0))
-- contain within parent
canvas.regions:andRegion(self.regions)
-- punch out this area from the parent's canvas
self.regions:subRect(
canvas.x + offset.x - (self.offx or 0),
canvas.y + offset.y - (self.offy or 0),
canvas.ex + offset.x - (self.offx or 0),
canvas.ey + offset.y - (self.offy or 0))
-- punch out any layers that overlap this one
for j = i + 1, #self.layers do
if self.layers[j].visible then
canvas:__punch(self.layers[j], offset)
end
end
if #canvas.regions.region > 0 then
canvas:__renderLayers(device, {
x = canvas.x + offset.x - 1,
y = canvas.y + offset.y - 1,
x = canvas.x + offset.x - 1 - (self.offx or 0),
y = canvas.y + offset.y - 1 - (self.offy or 0),
})
end
canvas.regions = nil
end
end
self:__blitClipped(device, offset)
self.regions = nil
elseif self.regions and #self.regions.region > 0 then
self:__blitClipped(device, offset)
self.regions = nil
else
self:__blitRect(device, nil, {
x = self.x + offset.x,
y = self.y + offset.y
})
self.regions = nil
end
self:clean()
end
function Canvas:__blitClipped(device, offset)
if self.parent then
-- contain the rendered region in the parent's region
local p = Region.new(1, 1,
self.parent.width + offset.x - self.x + 1,
self.parent.height + offset.y - self.y + 1)
self.regions:andRegion(p)
end
for _,region in ipairs(self.regions.region) do
self:__blitRect(device,
{ x = region[1] - offset.x,
y = region[2] - offset.y,
ex = region[3] - offset.x,
ey = region[4] - offset.y},
y = region[2] - offset.y,
ex = region[3] - offset.x,
ey = region[4] - offset.y },
{ x = region[1], y = region[2] })
end
end
self.regions = nil
function Canvas:__punch(rect, offset)
self.regions:subRect(
rect.x + offset.x,
rect.y + offset.y,
rect.ex + offset.x,
rect.ey + offset.y)
self:clean()
end
-- performance can probably be improved by using one more buffer tied to the device
@ -386,7 +390,7 @@ function Canvas:__blitRect(device, src, tgt)
tgt = tgt or self
-- for visualizing updates on the screen
if Canvas.__visualize then
if Canvas.__visualize or self.visualize then
local drew
local t = _rep(' ', src.ex-src.x + 1)
local bg = _rep(2, src.ex-src.x + 1)
@ -399,8 +403,8 @@ function Canvas:__blitRect(device, src, tgt)
end
end
if drew then
local t = os.clock()
repeat until os.clock()-t > .2
local c = os.clock()
repeat until os.clock()-c > .03
end
end
for i = 0, src.ey - src.y do
@ -418,4 +422,16 @@ function Canvas:__blitRect(device, src, tgt)
end
end
if not ({ ... })[1] then
local UI = require('opus.ui')
UI:setPage(UI.Page {
button = UI.Button {
x = 5, y = 5,
text = 'abc'
}
})
UI:start()
end
return Canvas

View File

@ -1,32 +0,0 @@
local class = require('opus.class')
local UI = require('opus.ui')
UI.ActiveLayer = class(UI.Window)
UI.ActiveLayer.defaults = {
UIElement = 'ActiveLayer',
}
function UI.ActiveLayer:layout()
UI.Window.layout(self)
if not self.canvas then
self.canvas = self:addLayer()
else
self.canvas:resize(self.width, self.height)
end
end
function UI.ActiveLayer:enable(...)
self.canvas:raise()
self.canvas:setVisible(true)
UI.Window.enable(self, ...)
if self.parent.transitionHint then
self:addTransition(self.parent.transitionHint)
end
self:focusFirst()
end
function UI.ActiveLayer:disable()
if self.canvas then
self.canvas:setVisible(false)
end
UI.Window.disable(self)
end

View File

@ -35,11 +35,11 @@ function UI.Button:draw()
local bg = self.backgroundColor
local ind = ' '
if self.focused then
bg = self.backgroundFocusColor
fg = self.textFocusColor
bg = self:getProperty('backgroundFocusColor')
fg = self:getProperty('textFocusColor')
ind = self.focusIndicator
elseif self.inactive then
fg = self.textInactiveColor
fg = self:getProperty('textInactiveColor')
end
local text = ind .. self.text .. ' '
if self.centered then

View File

@ -21,9 +21,6 @@ UI.Checkbox.defaults = {
mouse_click = 'checkbox_toggle',
}
}
UI.Checkbox.inherits = {
labelBackgroundColor = 'backgroundColor',
}
function UI.Checkbox:postInit()
self.width = self.label and #self.label + 4 or 3
end

View File

@ -11,8 +11,8 @@ UI.Chooser.defaults = {
nochoice = 'Select',
backgroundFocusColor = colors.lightGray,
textInactiveColor = colors.gray,
leftIndicator = UI.extChars and '\17' or '<',
rightIndicator = UI.extChars and '\16' or '>',
leftIndicator = UI.extChars and '\171' or '<',
rightIndicator = UI.extChars and '\187' or '>',
height = 1,
accelerators = {
space = 'choice_next',

View File

@ -1,4 +1,3 @@
local Canvas = require('opus.ui.canvas')
local class = require('opus.class')
local UI = require('opus.ui')
@ -19,14 +18,14 @@ function UI.Dialog:postInit()
end
function UI.Dialog:show(...)
local canvas = self.parent:getCanvas()
local canvas = self.parent
self.oldPalette = canvas.palette
canvas:applyPalette(Canvas.darkPalette)
canvas:applyPalette(self.darkPalette)
UI.SlideOut.show(self, ...)
end
function UI.Dialog:hide(...)
self.parent:getCanvas().palette = self.oldPalette
self.parent.palette = self.oldPalette
UI.SlideOut.hide(self, ...)
self.parent:draw()
end
@ -37,3 +36,30 @@ function UI.Dialog:eventHandler(event)
end
return UI.SlideOut.eventHandler(self, event)
end
function UI.Dialog.example()
return UI.Dialog {
title = 'Enter Starting Level',
height = 7,
form = UI.Form {
y = 3, x = 2, height = 4,
event = 'setStartLevel',
cancelEvent = 'slide_hide',
text = UI.Text {
x = 5, y = 1, width = 20,
textColor = colors.gray,
},
textEntry = UI.TextEntry {
formKey = 'level',
x = 15, y = 1, width = 7,
},
},
statusBar = UI.StatusBar(),
enable = function(self)
require('opus.event').onTimeout(0, function()
self:show()
self:sync()
end)
end,
}
end

View File

@ -32,42 +32,38 @@ function UI.DropMenu:layout()
self.height = #self.children + 1
self.width = maxWidth + 2
if not self.canvas then
self.canvas = self:addLayer()
else
self.canvas:resize(self.width, self.height)
if self.x + self.width > self.parent.width then
self.x = self.parent.width - self.width + 1
end
self:reposition(self.x, self.y, self.width, self.height)
end
function UI.DropMenu:enable()
end
function UI.DropMenu:show(x, y)
self.x, self.y = x, y
self.canvas:move(x, y)
self.canvas:setVisible(true)
for _,c in pairs(self.children) do
if not c.spacer then
c.inactive = not self:getActive(c)
end
end
UI.Window.enable(self)
self:draw()
self:capture(self)
self:focusFirst()
self:draw()
end
function UI.DropMenu:hide()
self:disable()
self.canvas:setVisible(false)
self:release(self)
function UI.DropMenu:disable()
UI.Window.disable(self)
self:remove()
end
function UI.DropMenu:eventHandler(event)
if event.type == 'focus_lost' and self.enabled then
if not Util.contains(self.children, event.focused) then
self:hide()
self:disable()
end
elseif event.type == 'mouse_out' and self.enabled then
self:hide()
self:refocus()
self:disable()
self:setFocus(self.parent:find(self.lastFocus))
else
return UI.MenuBar.eventHandler(self, event)
end
@ -83,6 +79,15 @@ function UI.DropMenu.example()
{ spacer = true },
{ text = 'Quit ^q', event = 'quit' },
} },
{ text = 'Edit', dropdown = {
{ text = 'Copy', event = 'run' },
{ text = 'Paste s', event = 'shell' },
} },
{ text = '\187',
x = -3,
dropdown = {
{ text = 'Associations', event = 'associate' },
} },
}
}
end

View File

@ -14,7 +14,7 @@ UI.DropMenuItem.defaults = {
}
function UI.DropMenuItem:eventHandler(event)
if event.type == 'button_activate' then
self.parent:hide()
self.parent:disable()
end
return UI.Button.eventHandler(self, event)
end

View File

@ -18,45 +18,33 @@ UI.Embedded.defaults = {
function UI.Embedded:setParent()
UI.Window.setParent(self)
function self.render()
self:sync()
end
self.win = Terminal.window(UI.term.device, self.x, self.y, self.width, self.height, false)
self.win.canvas = self
self.win.setMaxScroll(self.maxScroll)
local canvas = self:getCanvas()
self.win.getCanvas().parent = canvas
table.insert(canvas.layers, self.win.getCanvas())
self.canvas = self.win.getCanvas()
self.win.setCursorPos(1, 1)
self.win.setBackgroundColor(self.backgroundColor)
self.win.setTextColor(self.textColor)
self.win.clear()
end
function UI.Embedded:layout()
UI.Window.layout(self)
if self.win then
self.win.reposition(self.x, self.y, self.width, self.height)
end
function UI.Embedded:draw()
self:dirty()
end
function UI.Embedded:draw()
self.canvas:dirty()
function UI.Embedded:focus()
-- allow scrolling
end
function UI.Embedded:enable()
self.canvas:setVisible(true)
self.canvas:raise()
if self.visible then
-- the window will automatically update on changes
-- the canvas does not need to be rendereed
self.win.setVisible(true)
end
UI.Window.enable(self)
self.canvas:dirty()
self.win.setVisible(true)
self:dirty()
end
function UI.Embedded:disable()
self.canvas:setVisible(false)
self.win.setVisible(false)
UI.Window.disable(self)
end
@ -71,17 +59,12 @@ function UI.Embedded:eventHandler(event)
end
end
function UI.Embedded:focus()
-- allow scrolling
end
function UI.Embedded.example()
local Event = require('opus.event')
local Util = require('opus.util')
local term = _G.term
return UI.Embedded {
visible = true,
enable = function (self)
UI.Embedded.enable(self)
Event.addRoutine(function()

View File

@ -60,7 +60,7 @@ UI.Grid.defaults = {
textSelectedColor = colors.white,
backgroundColor = colors.black,
backgroundSelectedColor = colors.gray,
headerBackgroundColor = colors.cyan,
headerBackgroundColor = UI.colors.tertiary,
headerTextColor = colors.white,
headerSortColor = colors.yellow,
unfocusedTextSelectedColor = colors.white,

View File

@ -1,19 +1,28 @@
local class = require('opus.class')
local UI = require('opus.ui')
local Util = require('opus.util')
local lookup = '0123456789abcdef'
-- handle files produced by Paint
UI.Image = class(UI.Window)
UI.Image.defaults = {
UIElement = 'Image',
event = 'button_press',
}
function UI.Image:setParent()
if self.image then
function UI.Image:postInit()
if self.filename then
self.image = Util.readLines(self.filename)
end
if self.image and not (self.height or self.ey) then
self.height = #self.image
end
if self.image and not self.width then
self.width = #self.image[1]
if self.image and not (self.width or self.ex) then
for i = 1, self.height do
self.width = math.max(self.width or 0, #self.image[i])
end
end
UI.Window.setParent(self)
end
function UI.Image:draw()
@ -22,19 +31,22 @@ function UI.Image:draw()
for y = 1, #self.image do
local line = self.image[y]
for x = 1, #line do
local ch = line[x]
if type(ch) == 'number' then
if ch > 0 then
self:write(x, y, ' ', ch)
end
else
self:write(x, y, ch)
local ch = lookup:find(line:sub(x, x))
if ch then
self:write(x, y, ' ', 2 ^ (ch -1))
end
end
end
end
self:drawChildren()
end
function UI.Image:setImage(image)
self.image = image
end
function UI.Image.example()
return UI.Image {
filename = 'test.paint',
}
end

View File

@ -3,16 +3,6 @@ local UI = require('opus.ui')
local colors = _G.colors
local function getPosition(element)
local x, y = 1, 1
repeat
x = element.x + x - 1
y = element.y + y - 1
element = element.parent
until not element
return x, y
end
UI.MenuBar = class(UI.Window)
UI.MenuBar.defaults = {
UIElement = 'MenuBar',
@ -22,7 +12,6 @@ UI.MenuBar.defaults = {
textColor = colors.black,
spacing = 2,
lastx = 1,
showBackButton = false,
buttonClass = 'MenuItem',
}
function UI.MenuBar:postInit()
@ -62,10 +51,6 @@ function UI.MenuBar:addButtons(buttons)
else
table.insert(self.children, button)
end
if button.dropdown then
button.dropmenu = UI.DropMenu { buttons = button.dropdown }
end
end
end
if self.parent then
@ -78,23 +63,27 @@ function UI.MenuBar:getActive(menuItem)
end
function UI.MenuBar:eventHandler(event)
if event.type == 'button_press' and event.button.dropmenu then
if event.button.dropmenu.enabled then
event.button.dropmenu:hide()
self:refocus()
return true
else
local x, y = getPosition(event.button)
if x + event.button.dropmenu.width > self.width then
x = self.width - event.button.dropmenu.width + 1
end
for _,c in pairs(event.button.dropmenu.children) do
if not c.spacer then
c.inactive = not self:getActive(c)
end
end
event.button.dropmenu:show(x, y + 1)
if event.type == 'button_press' and event.button.dropdown then
local function getPosition(element)
local x, y = 1, 1
repeat
x = element.x + x - 1
y = element.y + y - 1
element = element.parent
until not element
return x, y
end
local x, y = getPosition(event.button)
local menu = UI.DropMenu {
buttons = event.button.dropdown,
x = x,
y = y + 1,
lastFocus = event.button.uid,
}
self.parent:add({ dropmenu = menu })
return true
end
end

View File

@ -6,8 +6,6 @@ local colors = _G.colors
UI.MenuItem = class(UI.Button)
UI.MenuItem.defaults = {
UIElement = 'MenuItem',
textColor = colors.black,
backgroundColor = colors.lightGray,
textFocusColor = colors.white,
backgroundFocusColor = colors.lightGray,
}

View File

@ -5,17 +5,18 @@ UI.NftImage = class(UI.Window)
UI.NftImage.defaults = {
UIElement = 'NftImage',
}
function UI.NftImage:setParent()
if self.image then
function UI.NftImage:postInit()
if self.image and not (self.ey or self.height) then
self.height = self.image.height
end
if self.image and not self.width then
if self.image and not (self.ex or self.width) then
self.width = self.image.width
end
UI.Window.setParent(self)
end
function UI.NftImage:draw()
self:clear()
if self.image then
-- due to blittle, the background and foreground transparent
-- color is the same as the background color
@ -25,8 +26,6 @@ function UI.NftImage:draw()
self:write(x, y, self.image.text[y][x], self.image.bg[y][x], self.image.fg[y][x] or bg)
end
end
else
self:clear()
end
end

View File

@ -43,32 +43,34 @@ function UI.Notification:cancel()
self.timer = nil
end
if self.canvas then
self.enabled = false
self.canvas:removeLayer()
self.canvas = nil
end
self:disable()
end
function UI.Notification:display(value, timeout)
self:cancel()
self.enabled = true
local lines = Util.wordWrap(value, self.width - 3)
self.enabled = true
self.height = #lines
if self.anchor == 'bottom' then
self.y = self.parent.height - self.height + 1
self.canvas = self:addLayer(self.backgroundColor, self.textColor)
self:addTransition('expandUp', { ticks = self.height })
else
self.canvas = self:addLayer(self.backgroundColor, self.textColor)
self.y = 1
end
self.canvas:setVisible(true)
self:reposition(self.x, self.y, self.width, self.height)
self:raise()
self:clear()
for k,v in pairs(lines) do
self:write(2, k, v)
end
self:write(self.width, 1, self.closeInd)
if self.timer then
Event.off(self.timer)
self.timer = nil
end
timeout = timeout or self.timeout
if timeout > 0 then
@ -77,7 +79,6 @@ function UI.Notification:display(value, timeout)
self:sync()
end)
else
self:write(self.width, 1, self.closeInd)
self:sync()
end
end
@ -92,7 +93,7 @@ function UI.Notification:eventHandler(event)
end
function UI.Notification.example()
return UI.ActiveLayer {
return UI.Window {
notify1 = UI.Notification {
anchor = 'top',
},
@ -111,7 +112,9 @@ function UI.Notification.example()
if event.type == 'test_success' then
self.notify1:success('Example text')
elseif event.type == 'test_error' then
self.notify2:error('Example text', 0)
self.notify2:error([[Example text test test
test test test test test
test test test]], 0)
end
end,
}

View File

@ -1,21 +1,9 @@
local Canvas = require('opus.ui.canvas')
local class = require('opus.class')
local UI = require('opus.ui')
local Util = require('opus.util')
local colors = _G.colors
-- need to add offsets to this test
local function getPosition(element)
local x, y = 1, 1
repeat
x = element.x + x - 1
y = element.y + y - 1
element = element.parent
until not element
return x, y
end
UI.Page = class(UI.Window)
UI.Page.defaults = {
UIElement = 'Page',
@ -26,21 +14,15 @@ UI.Page.defaults = {
['shift-tab' ] = 'focus_prev',
up = 'focus_prev',
},
backgroundColor = colors.cyan,
backgroundColor = UI.colors.primary,
textColor = colors.white,
}
function UI.Page:postInit()
self.parent = self.parent or UI.defaultDevice
self.__target = self
self.canvas = Canvas({
x = 1, y = 1, width = self.parent.width, height = self.parent.height,
isColor = self.parent.isColor,
})
self.canvas:clear(self.backgroundColor, self.textColor)
end
function UI.Page:enable()
self.canvas.visible = true
UI.Window.enable(self)
if not self.focused or not self.focused.enabled then
@ -49,12 +31,12 @@ function UI.Page:enable()
end
function UI.Page:disable()
self.canvas.visible = false
UI.Window.disable(self)
end
function UI.Page:sync()
if self.enabled then
self:checkFocus()
self.parent:sync()
end
end
@ -73,22 +55,24 @@ function UI.Page:pointToChild(x, y)
if self.__target == self then
return UI.Window.pointToChild(self, x, y)
end
x = x + self.offx - self.x + 1
y = y + self.offy - self.y + 1
--[[
-- this is supposed to fix when there are multiple sub canvases
local absX, absY = getPosition(self.__target)
if self.__target.canvas then
x = x - (self.__target.canvas.x - self.__target.x)
y = y - (self.__target.canvas.y - self.__target.y)
_syslog({'raw', self.__target.canvas.y, self.__target.y})
-- need to add offsets to this test
local function getPosition(element)
local x, y = 1, 1
repeat
x = element.x + x - 1
y = element.y + y - 1
element = element.parent
until not element
return x, y
end
]]
return self.__target:pointToChild(x, y)
local absX, absY = getPosition(self.__target)
return self.__target:pointToChild(x - absX + self.__target.x, y - absY + self.__target.y)
end
function UI.Page:getFocusables()
if self.__target == self or self.__target.pageType ~= 'modal' then
if self.__target == self or not self.__target.modal then
return UI.Window.getFocusables(self)
end
return self.__target:getFocusables()
@ -149,12 +133,25 @@ function UI.Page:setFocus(child)
if not child.focused then
child.focused = true
child:emit({ type = 'focus_change', focused = child })
--self:emit({ type = 'focus_change', focused = child })
end
child:focus()
end
function UI.Page:checkFocus()
if not self.focused or not self.focused.enabled then
local el = self.__target
while el do
local focusables = el:getFocusables()
if focusables[1] then
self:setFocus(focusables[1])
break
end
el = el.parent
end
end
end
function UI.Page:eventHandler(event)
if self.focused then
if event.type == 'focus_next' then

View File

@ -28,12 +28,11 @@ function UI.ProgressBar:draw()
end
function UI.ProgressBar.example()
local Event = require('opus.event')
return UI.ProgressBar {
x = 2, ex = -2, y = 2,
focus = function() end,
enable = function(self)
Event.onInterval(.25, function()
require('opus.event').onInterval(.25, function()
self.value = self.value == 100 and 0 or self.value + 5
self:draw()
self:sync()

View File

@ -17,7 +17,10 @@ UI.ScrollBar.defaults = {
ey = -1,
}
function UI.ScrollBar:draw()
local view = self.parent:getViewArea()
local parent = self.target or self.parent --self:find(self.target)
local view = parent:getViewArea()
self:clear()
if view.totalHeight > view.height then
local maxScroll = view.totalHeight - view.height
@ -27,7 +30,7 @@ function UI.ScrollBar:draw()
local row = view.y
if not view.static then -- does the container scroll ?
self.height = view.totalHeight
self:reposition(self.x, self.y, self.width, view.totalHeight)
end
for i = 1, view.height - 2 do
@ -56,16 +59,17 @@ end
function UI.ScrollBar:eventHandler(event)
if event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then
if event.x == 1 then
local view = self.parent:getViewArea()
local parent = self.target or self.parent --self:find(self.target)
local view = parent:getViewArea()
if view.totalHeight > view.height then
if event.y == view.y then
self:emit({ type = 'scroll_up'})
parent:emit({ type = 'scroll_up'})
elseif event.y == view.y + view.height - 1 then
self:emit({ type = 'scroll_down'})
parent:emit({ type = 'scroll_down'})
else
local percent = (event.y - view.y) / (view.height - 2)
local y = math.floor((view.totalHeight - view.height) * percent)
self:emit({ type = 'scroll_to', offset = y })
parent :emit({ type = 'scroll_to', offset = y })
end
end
return true

View File

@ -57,3 +57,21 @@ function UI.ScrollingGrid:setIndex(index)
end
UI.Grid.setIndex(self, index)
end
function UI.ScrollingGrid.example()
local values = { }
for i = 1, 20 do
table.insert(values, { key = 'key' .. i, value = 'value' .. i })
end
return UI.ScrollingGrid {
values = values,
sortColumn = 'key',
columns = {
{ heading = 'key', key = 'key' },
{ heading = 'value', key = 'value' },
},
accelerators = {
grid_select = 'custom_select',
}
}
end

View File

@ -4,17 +4,9 @@ local UI = require('opus.ui')
UI.SlideOut = class(UI.Window)
UI.SlideOut.defaults = {
UIElement = 'SlideOut',
pageType = 'modal',
transitionHint = 'expandUp',
modal = true,
}
function UI.SlideOut:layout()
UI.Window.layout(self)
if not self.canvas then
self.canvas = self:addLayer()
else
self.canvas:resize(self.width, self.height)
end
end
function UI.SlideOut:enable()
end
@ -27,24 +19,20 @@ function UI.SlideOut:toggle()
end
function UI.SlideOut:show(...)
self:addTransition('expandUp')
self.canvas:raise()
self.canvas:setVisible(true)
UI.Window.enable(self, ...)
self:draw()
self:capture(self)
self:focusFirst()
end
function UI.SlideOut:disable()
self.canvas:setVisible(false)
UI.Window.disable(self)
end
function UI.SlideOut:hide()
self:disable()
self:release(self)
self:refocus()
end
function UI.SlideOut:draw()
if not self.noFill then
self:fillArea(1, 1, self.width, self.height, string.rep('\127', self.width), colors.black, colors.gray)
end
self:drawChildren()
end
function UI.SlideOut:eventHandler(event)
@ -59,24 +47,27 @@ function UI.SlideOut:eventHandler(event)
end
function UI.SlideOut.example()
-- for the transistion to work properly, the parent must have a canvas
return UI.ActiveLayer {
y = 2,
return UI.Window {
y = 3,
backgroundColor = 2048,
button = UI.Button {
x = 2, y = 5,
text = 'show',
},
slideOut = UI.SlideOut {
backgroundColor = _G.colors.yellow,
y = -4, height = 4, x = 3, ex = -3,
backgroundColor = 16,
y = -7, height = 4, x = 3, ex = -3,
titleBar = UI.TitleBar {
title = 'test',
},
button = UI.Button {
x = 2, y = 2,
text = 'hide',
--visualize = true,
},
},
eventHandler = function (self, event)
if event.type == 'button_press' then
self.slideOut.canvas.xxx = true
self.slideOut:toggle()
end
end,

View File

@ -57,8 +57,16 @@ end
function UI.Slider:eventHandler(event)
if event.type == "mouse_down" or event.type == "mouse_drag" then
local pos = event.x - 1
if event.type == 'mouse_down' then
self.anchor = event.x - 1
else
pos = self.anchor + event.dx
end
local range = self.max - self.min
local i = (event.x - 1) / (self.width - 1)
local i = pos / (self.width - 1)
self.value = self.min + (i * range)
self:emit({ type = self.event, value = self.value, element = self })
self:draw()

View File

@ -63,7 +63,7 @@ end
function UI.StatusBar:timedStatus(status, timeout)
self:write(2, 1, Util.widthify(status, self.width-2), self.backgroundColor)
Event.on(timeout or 3, function()
Event.onTimeout(timeout or 3, function()
if self.enabled then
self:draw()
self:sync()

View File

@ -1,9 +1,16 @@
local class = require('opus.class')
local UI = require('opus.ui')
UI.Tab = class(UI.ActiveLayer)
UI.Tab = class(UI.Window)
UI.Tab.defaults = {
UIElement = 'Tab',
tabTitle = 'tab',
y = 2,
}
function UI.Tab:draw()
if not self.noFill then
self:fillArea(1, 1, self.width, self.height, string.rep('\127', self.width), colors.black, colors.gray)
end
self:drawChildren()
end

View File

@ -2,13 +2,14 @@ local class = require('opus.class')
local UI = require('opus.ui')
local Util = require('opus.util')
local colors = _G.colors
UI.TabBar = class(UI.MenuBar)
UI.TabBar.defaults = {
UIElement = 'TabBar',
buttonClass = 'TabBarMenuItem',
}
UI.TabBar.inherits = {
selectedBackgroundColor = 'backgroundColor',
selectedBackgroundColor = UI.colors.secondary,
unselectedBackgroundColor = colors.lightGray,
}
function UI.TabBar:enable()
UI.MenuBar.enable(self)

View File

@ -1,27 +1,18 @@
local class = require('opus.class')
local UI = require('opus.ui')
local colors = _G.colors
UI.TabBarMenuItem = class(UI.Button)
UI.TabBarMenuItem.defaults = {
UIElement = 'TabBarMenuItem',
event = 'tab_select',
textColor = colors.black,
selectedBackgroundColor = colors.cyan,
unselectedBackgroundColor = colors.lightGray,
backgroundColor = colors.lightGray,
}
UI.TabBarMenuItem.inherits = {
selectedBackgroundColor = 'selectedBackgroundColor',
}
function UI.TabBarMenuItem:draw()
if self.selected then
self.backgroundColor = self.selectedBackgroundColor
self.backgroundFocusColor = self.selectedBackgroundColor
self.backgroundColor = self:getProperty('selectedBackgroundColor')
self.backgroundFocusColor = self.backgroundColor
else
self.backgroundColor = self.unselectedBackgroundColor
self.backgroundFocusColor = self.unselectedBackgroundColor
self.backgroundColor = self:getProperty('unselectedBackgroundColor')
self.backgroundFocusColor = self.backgroundColor
end
UI.Button.draw(self)
end

View File

@ -56,12 +56,12 @@ end
function UI.Tabs:enable()
self.enabled = true
self.transitionHint = nil
self.tabBar:enable()
local menuItem = Util.find(self.tabBar.children, 'selected', true)
for _,child in pairs(self.children or { }) do
for child in self:eachChild() do
child.transitionHint = nil
if child.uid == menuItem.tabUid then
child:enable()
self:emit({ type = 'tab_activate', activated = child })
@ -74,14 +74,11 @@ end
function UI.Tabs:eventHandler(event)
if event.type == 'tab_change' then
local tab = self:find(event.tab.tabUid)
if event.current > event.last then
self.transitionHint = 'slideLeft'
else
self.transitionHint = 'slideRight'
end
local hint = event.current > event.last and 'slideLeft' or 'slideRight'
for _,child in pairs(self.children) do
for child in self:eachChild() do
if child.uid == event.tab.tabUid then
child.transitionHint = hint
child:enable()
elseif child.tabTitle then
child:disable()
@ -89,6 +86,7 @@ function UI.Tabs:eventHandler(event)
end
self:emit({ type = 'tab_activate', activated = tab })
tab:draw()
return true
end
end
@ -102,7 +100,18 @@ function UI.Tabs.example()
tab2 = UI.Tab {
index = 2,
tabTitle = 'tab2',
button = UI.Button { y = 3 },
subtabs = UI.Tabs {
x = 3, y = 2, ex = -3, ey = -2,
tab1 = UI.Tab {
index = 1,
tabTitle = 'tab4',
entry = UI.TextEntry { y = 3, shadowText = 'text' },
},
tab3 = UI.Tab {
index = 2,
tabTitle = 'tab5',
},
},
},
tab3 = UI.Tab {
index = 3,

View File

@ -6,11 +6,8 @@ UI.TextArea.defaults = {
UIElement = 'TextArea',
marginRight = 2,
value = '',
showScrollBar = true,
}
function UI.TextArea:postInit()
self.scrollBar = UI.ScrollBar()
end
function UI.TextArea:setText(text)
self:reset()
self.value = text
@ -23,19 +20,28 @@ end
function UI.TextArea:draw()
self:clear()
-- self:setCursorPos(1, 1)
self.cursorX, self.cursorY = 1, 1
self:print(self.value)
for _,child in pairs(self.children) do
if child.enabled then
child:draw()
end
end
self:drawChildren()
end
function UI.TextArea.example()
return UI.TextArea {
value = 'sample text\nabc'
return UI.Window {
backgroundColor = 2048,
t1 = UI.TextArea {
ey = 3,
value = 'sample text\nabc'
},
t2 = UI.TextArea {
y = 5,
value = [[1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
3
4
5
6
7
8]]
}
}
end

View File

@ -19,7 +19,6 @@ UI.TextEntry = class(UI.Window)
UI.TextEntry.docs = { }
UI.TextEntry.defaults = {
UIElement = 'TextEntry',
--value = '',
shadowText = '',
focused = false,
textColor = colors.white,

View File

@ -20,24 +20,15 @@ UI.Throttle.defaults = {
' //) (O ). @ \\-d ) (@ '
}
}
function UI.Throttle:setParent()
function UI.Throttle:layout()
self.x = math.ceil((self.parent.width - self.width) / 2)
self.y = math.ceil((self.parent.height - self.height) / 2)
UI.Window.setParent(self)
self:reposition(self.x, self.y, self.width, self.height)
end
function UI.Throttle:enable()
self.c = os.clock()
self.enabled = false
end
function UI.Throttle:disable()
if self.canvas then
self.enabled = false
self.canvas:removeLayer()
self.canvas = nil
self.ctr = 0
end
self.ctr = 0
end
function UI.Throttle:update()
@ -46,11 +37,7 @@ function UI.Throttle:update()
os.sleep(0)
self.c = os.clock()
self.enabled = true
if not self.canvas then
self.canvas = self:addLayer(self.backgroundColor, self.borderColor)
self.canvas:setVisible(true)
self:clear(self.borderColor)
end
self:clear(self.borderColor)
local image = self.image[self.ctr + 1]
local width = self.width - 2
for i = 0, #self.image do
@ -63,3 +50,25 @@ function UI.Throttle:update()
self:sync()
end
end
function UI.Throttle.example()
return UI.Window {
button1 = UI.Button {
x = 2, y = 2,
text = 'Test',
},
throttle = UI.Throttle {
textColor = colors.yellow,
borderColor = colors.green,
},
eventHandler = function (self, event)
if event.type == 'button_press' then
for _ = 1, 40 do
self.throttle:update()
os.sleep(.05)
end
self.throttle:disable()
end
end,
}
end

View File

@ -38,8 +38,6 @@ UI.TitleBar = class(UI.Window)
UI.TitleBar.defaults = {
UIElement = 'TitleBar',
height = 1,
textColor = colors.white,
backgroundColor = colors.cyan,
title = '',
frameChar = UI.extChars and '\140' or '-',
closeInd = UI.extChars and '\215' or '*',
@ -69,5 +67,73 @@ function UI.TitleBar:eventHandler(event)
end
return true
end
elseif event.type == 'mouse_down' then
self.anchor = { x = event.x, y = event.y, ox = self.parent.x, oy = self.parent.y, h = self.parent.height }
elseif event.type == 'mouse_drag' then
if self.expand == 'height' then
local d = event.dy
if self.anchor.h - d > 0 and self.anchor.oy + d > 0 then
self.parent:reposition(self.parent.x, self.anchor.oy + event.dy, self.width, self.anchor.h - d)
end
else --if self.moveable then
local d = event.dy
if self.anchor.oy + d > 0 and self.anchor.oy + d <= self.parent.parent.height then
self.parent:move(self.anchor.ox + event.dx, self.anchor.oy + event.dy)
end
end
end
end
function UI.TitleBar.example()
return UI.Window {
win1 = UI.Window {
x = 9, y = 2, ex = -7, ey = -3,
backgroundColor = colors.green,
titleBar = UI.TitleBar {
title = 'test', moveable = true,
},
button1 = UI.Button {
x = 2, y = 3,
text = 'Press',
},
focus = function (self)
self:raise()
end,
},
win2 = UI.Window {
x = 7, y = 3, ex = -9, ey = -2,
backgroundColor = colors.orange,
titleBar = UI.TitleBar {
title = 'test', moveable = true,
},
button1 = UI.Button {
x = 2, y = 3,
text = 'Press',
},
focus = function (self)
self:raise()
end,
},
draw = function(self, isBG)
for i = 1, self.height do
self:write(1, i, self.filler or '')
end
if not isBG then
for _,v in pairs(self.children) do
v:draw()
end
end
end,
enable = function (self)
require('opus.event').onInterval(.5, function()
self.filler = string.rep(string.char(math.random(33, 126)), self.width)
self:draw(true)
self:sync()
end)
UI.Window.enable(self)
end
}
end

View File

@ -18,12 +18,11 @@ function UI.VerticalMeter:draw()
end
function UI.VerticalMeter.example()
local Event = require('opus.event')
return UI.VerticalMeter {
x = 2, width = 3, y = 2, ey = -2,
focus = function() end,
enable = function(self)
Event.onInterval(.25, function()
require('opus.event').onInterval(.25, function()
self.value = self.value == 100 and 0 or self.value + 5
self:draw()
self:sync()

View File

@ -1,16 +1,15 @@
local class = require('opus.class')
local UI = require('opus.ui')
local colors = _G.colors
UI.Viewport = class(UI.Window)
UI.Viewport.defaults = {
UIElement = 'Viewport',
backgroundColor = colors.cyan,
accelerators = {
down = 'scroll_down',
up = 'scroll_up',
home = 'scroll_top',
left = 'scroll_left',
right = 'scroll_right',
[ 'end' ] = 'scroll_bottom',
pageUp = 'scroll_pageUp',
[ 'control-b' ] = 'scroll_pageUp',
@ -18,53 +17,53 @@ UI.Viewport.defaults = {
[ 'control-f' ] = 'scroll_pageDown',
},
}
function UI.Viewport:layout()
UI.Window.layout(self)
if not self.canvas then
self.canvas = self:addLayer()
else
self.canvas:resize(self.width, self.height)
function UI.Viewport:postInit()
if self.showScrollBar then
self.scrollBar = UI.ScrollBar()
end
end
function UI.Viewport:enable()
UI.Window.enable(self)
self.canvas:setVisible(true)
end
function UI.Viewport:disable()
UI.Window.disable(self)
self.canvas:setVisible(false)
end
function UI.Viewport:setScrollPosition(offset)
local oldOffset = self.offy
self.offy = math.max(offset, 0)
self.offy = math.min(self.offy, math.max(#self.canvas.lines, self.height) - self.height)
if self.offy ~= oldOffset then
function UI.Viewport:setScrollPosition(offy, offx) -- argh - reverse
local oldOffy = self.offy
self.offy = math.max(offy, 0)
self.offy = math.min(self.offy, math.max(#self.lines, self.height) - self.height)
if self.offy ~= oldOffy then
if self.scrollBar then
self.scrollBar:draw()
end
self.canvas.offy = offset
self.canvas:dirty()
self.offy = offy
self:dirty(true)
end
local oldOffx = self.offx
self.offx = math.max(offx or 0, 0)
self.offx = math.min(self.offx, math.max(#self.lines[1], self.width) - self.width)
if self.offx ~= oldOffx then
if self.scrollBar then
--self.scrollBar:draw()
end
self.offx = offx or 0
self:dirty(true)
end
end
function UI.Viewport:write(x, y, text, bg, tc)
if y > #self.canvas.lines then
for i = #self.canvas.lines, y do
self.canvas.lines[i + 1] = { }
self.canvas:clearLine(i + 1, self.backgroundColor, self.textColor)
end
if y > #self.lines then
self:resizeBuffer(self.width, y)
end
return UI.Window.write(self, x, y, text, bg, tc)
end
function UI.Viewport:setViewHeight(h)
if h > #self.lines then
self:resizeBuffer(self.width, h)
end
end
function UI.Viewport:reset()
self.offy = 0
self.canvas.offy = 0
for i = self.height + 1, #self.canvas.lines do
self.canvas.lines[i] = nil
for i = self.height + 1, #self.lines do
self.lines[i] = nil
end
end
@ -72,26 +71,30 @@ function UI.Viewport:getViewArea()
return {
y = (self.offy or 0) + 1,
height = self.height,
totalHeight = #self.canvas.lines,
totalHeight = #self.lines,
offsetY = self.offy or 0,
}
end
function UI.Viewport:eventHandler(event)
if event.type == 'scroll_down' then
self:setScrollPosition(self.offy + 1)
self:setScrollPosition(self.offy + 1, self.offx)
elseif event.type == 'scroll_up' then
self:setScrollPosition(self.offy - 1)
self:setScrollPosition(self.offy - 1, self.offx)
elseif event.type == 'scroll_left' then
self:setScrollPosition(self.offy, self.offx - 1)
elseif event.type == 'scroll_right' then
self:setScrollPosition(self.offy, self.offx + 1)
elseif event.type == 'scroll_top' then
self:setScrollPosition(0)
self:setScrollPosition(0, 0)
elseif event.type == 'scroll_bottom' then
self:setScrollPosition(10000000)
self:setScrollPosition(10000000, 0)
elseif event.type == 'scroll_pageUp' then
self:setScrollPosition(self.offy - self.height)
self:setScrollPosition(self.offy - self.height, self.offx)
elseif event.type == 'scroll_pageDown' then
self:setScrollPosition(self.offy + self.height)
self:setScrollPosition(self.offy + self.height, self.offx)
elseif event.type == 'scroll_to' then
self:setScrollPosition(event.offset)
self:setScrollPosition(event.offset, 0)
else
return false
end

View File

@ -25,9 +25,6 @@ function UI.Wizard:postInit()
}
Util.merge(self, self.pages)
--for _, child in pairs(self.pages) do
-- child.ey = -2
--end
end
function UI.Wizard:add(pages)
@ -50,9 +47,8 @@ end
function UI.Wizard:enable(...)
self.enabled = true
self.index = 1
self.transitionHint = nil
local initial = self:getPage(1)
for _,child in pairs(self.children) do
for child in self:eachChild() do
if child == initial or not child.index then
child:enable(...)
else
@ -93,12 +89,13 @@ function UI.Wizard:eventHandler(event)
elseif event.type == 'enable_view' then
local current = event.next or event.prev
if not current then error('property "index" is required on wizard pages') end
local hint
if event.current then
if event.next then
self.transitionHint = 'slideLeft'
hint = 'slideLeft'
elseif event.prev then
self.transitionHint = 'slideRight'
hint = 'slideRight'
end
event.current:disable()
end
@ -117,6 +114,7 @@ function UI.Wizard:eventHandler(event)
self.nextButton.event = 'wizard_complete'
end
-- a new current view
current.transitionHint = hint
current:enable()
current:emit({ type = 'view_enabled', view = current })
self:draw()

View File

@ -1,11 +1,8 @@
local class = require('opus.class')
local UI = require('opus.ui')
local colors = _G.colors
UI.WizardPage = class(UI.ActiveLayer)
UI.WizardPage = class(UI.Window)
UI.WizardPage.defaults = {
UIElement = 'WizardPage',
backgroundColor = colors.cyan,
ey = -2,
}

View File

@ -13,7 +13,7 @@ function Transition.slideLeft(args)
return function()
local finished = tween:update(1)
args.canvas:move(math.floor(pos.x), args.canvas.y)
args.canvas:dirty()
args.canvas:dirty(true)
return not finished
end
end
@ -29,7 +29,7 @@ function Transition.slideRight(args)
return function()
local finished = tween:update(1)
args.canvas:move(math.floor(pos.x), args.canvas.y)
args.canvas:dirty()
args.canvas:dirty(true)
return not finished
end
end
@ -45,7 +45,7 @@ function Transition.expandUp(args)
return function()
local finished = tween:update(1)
args.canvas:move(args.x, math.floor(pos.y))
args.canvas:dirty()
args.canvas.parent:dirty(true)
return not finished
end
end