This commit is contained in:
kepler155c@gmail.com 2019-11-18 14:32:10 -07:00
parent a3a8c64be8
commit ffa412c59d
8 changed files with 245 additions and 252 deletions

View File

@ -24,7 +24,7 @@ local page = UI.Page {
values = kernel.routines, values = kernel.routines,
sortColumn = 'uid', sortColumn = 'uid',
autospace = true, autospace = true,
getDisplayValues = function(_, row) getDisplayValues = function (_, row)
local elapsed = os.clock()-row.timestamp local elapsed = os.clock()-row.timestamp
return { return {
uid = row.uid, uid = row.uid,

View File

@ -60,6 +60,12 @@ local page = UI.Page {
x = 3, ex = -3, y = 4, ey = -3, x = 3, ex = -3, y = 4, ey = -3,
value = string.format(labelIntro, Ansi.white), 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 { password = UI.WizardPage {
index = 3, index = 3,
@ -73,23 +79,18 @@ local page = UI.Page {
mask = true, mask = true,
shadowText = 'password', shadowText = 'password',
}, },
--[[
groupLabel = UI.Text {
x = 3, y = 3,
value = 'Group'
},
group = UI.TextEntry {
x = 12, ex = -3, y = 3,
limit = 32,
shadowText = 'network group',
},
]]
intro = UI.TextArea { intro = UI.TextArea {
textColor = colors.yellow, textColor = colors.yellow,
inactive = true, inactive = true,
x = 3, ex = -3, y = 5, ey = -3, x = 3, ex = -3, y = 5, ey = -3,
value = string.format(passwordIntro, Ansi.white), 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 { packages = UI.WizardPage {
index = 4, index = 4,
@ -119,27 +120,6 @@ local page = UI.Page {
notification = UI.Notification { }, notification = UI.Notification { },
} }
function page.wizard.pages.label:validate()
if self.label.value then
os.setComputerLabel(self.label.value)
end
return true
end
function page.wizard.pages.password:validate()
if type(self.newPass.value) == "string" and #self.newPass.value > 0 then
Security.updatePassword(SHA.compute(self.newPass.value))
end
--[[
if #self.group.value > 0 then
local config = Config.load('os')
config.group = self.group.value
Config.update('os', config)
end
]]
return true
end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'skip' then if event.type == 'skip' then
self.wizard:emit({ type = 'nextView' }) self.wizard:emit({ type = 'nextView' })

View File

@ -1,4 +1,3 @@
local Canvas = require('opus.ui.canvas')
local class = require('opus.class') local class = require('opus.class')
local Event = require('opus.event') local Event = require('opus.event')
local Input = require('opus.input') local Input = require('opus.input')
@ -19,18 +18,18 @@ local textutils = _G.textutils
the bottom up. Once reaching the top, setParent is called top down. the bottom up. Once reaching the top, setParent is called top down.
On :init(), elements do not know the parent or can calculate sizing. On :init(), elements do not know the parent or can calculate sizing.
]]
-- need to add offsets to this test Calling order:
local function getPosition(element) window:postInit()
local x, y = 1, 1 at this point, the window has all default values set
repeat window:setParent()
x = element.x + x - 1 parent has been assigned
y = element.y + y - 1 following are called:
element = element.parent window:layout()
until not element sizing / positioning is performed
return x, y window:initChildren()
end each child of window will get initialized
]]
--[[-- Top Level Manager --]]-- --[[-- Top Level Manager --]]--
local Manager = class() local Manager = class()
@ -953,7 +952,7 @@ function UI.Window:addTransition(effect, args)
if self.parent then if self.parent then
args = args or { } args = args or { }
if not args.x then -- not good if not args.x then -- not good
args.x, args.y = getPosition(self) args.x, args.y = self.x, self.y -- getPosition(self)
args.width = self.width args.width = self.width
args.height = self.height args.height = self.height
end end
@ -1117,149 +1116,7 @@ function UI.Device:sync()
end end
end end
--[[-- Page (focus manager) --]]-- -- lazy load components
UI.Page = class(UI.Window)
UI.Page.defaults = {
UIElement = 'Page',
accelerators = {
down = 'focus_next',
enter = 'focus_next',
tab = 'focus_next',
['shift-tab' ] = 'focus_prev',
up = 'focus_prev',
},
backgroundColor = colors.cyan,
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
self:focusFirst()
end
end
function UI.Page:disable()
self.canvas.visible = false
UI.Window.disable(self)
end
function UI.Page:sync()
if self.enabled then
self.parent:sync()
end
end
function UI.Page:capture(child)
self.__target = child
end
function UI.Page:release(child)
if self.__target == child then
self.__target = self
end
end
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
return self.__target:pointToChild(x, y)
end
function UI.Page:getFocusables()
if self.__target == self or self.__target.pageType ~= 'modal' then
return UI.Window.getFocusables(self)
end
return self.__target:getFocusables()
end
function UI.Page:getFocused()
return self.focused
end
function UI.Page:focusPrevious()
local function getPreviousFocus(focused)
local focusables = self:getFocusables()
local k = Util.contains(focusables, focused)
if k then
if k > 1 then
return focusables[k - 1]
end
return focusables[#focusables]
end
end
local focused = getPreviousFocus(self.focused)
if focused then
self:setFocus(focused)
end
end
function UI.Page:focusNext()
local function getNextFocus(focused)
local focusables = self:getFocusables()
local k = Util.contains(focusables, focused)
if k then
if k < #focusables then
return focusables[k + 1]
end
return focusables[1]
end
end
local focused = getNextFocus(self.focused)
if focused then
self:setFocus(focused)
end
end
function UI.Page:setFocus(child)
if not child or not child.focus then
return
end
if self.focused and self.focused ~= child then
self.focused.focused = false
self.focused:focus()
self.focused:emit({ type = 'focus_lost', focused = child })
end
self.focused = 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:eventHandler(event)
if self.focused then
if event.type == 'focus_next' then
self:focusNext()
return true
elseif event.type == 'focus_prev' then
self:focusPrevious()
return true
end
end
end
local function loadComponents() local function loadComponents()
local function load(name) local function load(name)
local s, m = Util.run(_ENV, 'sys/modules/opus/ui/components/' .. name .. '.lua') local s, m = Util.run(_ENV, 'sys/modules/opus/ui/components/' .. name .. '.lua')
@ -1295,7 +1152,6 @@ end
loadComponents() loadComponents()
UI:loadTheme('usr/config/ui.theme') UI:loadTheme('usr/config/ui.theme')
Util.merge(UI.Window.defaults, UI.theme.Window) Util.merge(UI.Window.defaults, UI.theme.Window)
Util.merge(UI.Page.defaults, UI.theme.Page)
UI:setDefaultDevice(UI.Device({ device = term.current() })) UI:setDefaultDevice(UI.Device({ device = term.current() }))
return UI return UI

View File

@ -9,6 +9,7 @@ local colors = _G.colors
local Canvas = class() local Canvas = class()
Canvas.__visualize = false
Canvas.colorPalette = { } Canvas.colorPalette = { }
Canvas.darkPalette = { } Canvas.darkPalette = { }
Canvas.grayscalePalette = { } Canvas.grayscalePalette = { }
@ -303,7 +304,7 @@ end
-- the array. -- the array.
function Canvas:__renderLayers(device, offset) function Canvas:__renderLayers(device, offset)
if #self.layers > 0 then if #self.layers > 0 then
self.regions = self.regions or Region.new(self.x, self.y, self.ex, self.ey) 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 for i = 1, #self.layers do
local canvas = self.layers[i] local canvas = self.layers[i]
@ -379,31 +380,29 @@ function Canvas:__punch(rect, offset)
rect.ey + offset.y) rect.ey + offset.y)
end end
-- performance can probably be improved by using one more buffer tied to the device
function Canvas:__blitRect(device, src, tgt) function Canvas:__blitRect(device, src, tgt)
src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 } src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 }
tgt = tgt or self tgt = tgt or self
--[[ -- for visualizing updates on the screen
-- for visualizing updates on the screen if Canvas.__visualize then
local drew local drew
for i = 0, src.ey - src.y do local t = _rep(' ', src.ex-src.x + 1)
local line = self.lines[src.y + i + (self.offy or 0)] local bg = _rep(2, src.ex-src.x + 1)
if line and line.dirty then for i = 0, src.ey - src.y do
drew = true local line = self.lines[src.y + i + (self.offy or 0)]
local t, fg, bg = line.text, line.fg, line.bg if line and line.dirty then
if src.x > 1 or src.ex < self.ex then drew = true
t = _sub(t, src.x, src.ex) device.setCursorPos(tgt.x, tgt.y + i)
fg = _rep(1, src.ex-src.x + 1) device.blit(t, bg, bg)
bg = _rep(2, src.ex-src.x + 1)
end end
device.setCursorPos(tgt.x, tgt.y + i) end
device.blit(t, fg, bg) if drew then
local t = os.clock()
repeat until os.clock()-t > .2
end end
end end
if drew then
os.sleep(.3)
end
]]
for i = 0, src.ey - src.y do for i = 0, src.ey - src.y do
local line = self.lines[src.y + i + (self.offy or 0)] local line = self.lines[src.y + i + (self.offy or 0)]
if line and line.dirty then if line and line.dirty then

View File

@ -14,6 +14,11 @@ UI.Chooser.defaults = {
leftIndicator = UI.extChars and '\17' or '<', leftIndicator = UI.extChars and '\17' or '<',
rightIndicator = UI.extChars and '\16' or '>', rightIndicator = UI.extChars and '\16' or '>',
height = 1, height = 1,
accelerators = {
space = 'choice_next',
right = 'choice_next',
left = 'choice_prev',
}
} }
function UI.Chooser:setParent() function UI.Chooser:setParent()
if not self.width and not self.ex then if not self.width and not self.ex then
@ -29,16 +34,11 @@ function UI.Chooser:setParent()
end end
function UI.Chooser:draw() function UI.Chooser:draw()
local bg = self.backgroundColor local bg = self.focused and self.backgroundFocusColor or self.backgroundColor
if self.focused then
bg = self.backgroundFocusColor
end
local fg = self.inactive and self.textInactiveColor or self.textColor local fg = self.inactive and self.textInactiveColor or self.textColor
local choice = Util.find(self.choices, 'value', self.value) local choice = Util.find(self.choices, 'value', self.value)
local value = self.nochoice local value = choice and choice.name or self.nochoice
if choice then
value = choice.name
end
self:write(1, 1, self.leftIndicator, self.backgroundColor, colors.black) self:write(1, 1, self.leftIndicator, self.backgroundColor, colors.black)
self:write(2, 1, ' ' .. Util.widthify(tostring(value), self.width-4) .. ' ', bg, fg) self:write(2, 1, ' ' .. Util.widthify(tostring(value), self.width-4) .. ' ', bg, fg)
self:write(self.width, 1, self.rightIndicator, self.backgroundColor, colors.black) self:write(self.width, 1, self.rightIndicator, self.backgroundColor, colors.black)
@ -49,39 +49,37 @@ function UI.Chooser:focus()
end end
function UI.Chooser:eventHandler(event) function UI.Chooser:eventHandler(event)
if event.type == 'key' then if event.type == 'choice_next' then
if event.key == 'right' or event.key == 'space' then local _,k = Util.find(self.choices, 'value', self.value)
local _,k = Util.find(self.choices, 'value', self.value) local choice
local choice if not k then k = 0 end
if not k then k = 0 end if k and k < #self.choices then
if k and k < #self.choices then choice = self.choices[k+1]
choice = self.choices[k+1] else
else choice = self.choices[1]
choice = self.choices[1]
end
self.value = choice.value
self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice })
self:draw()
return true
elseif event.key == 'left' then
local _,k = Util.find(self.choices, 'value', self.value)
local choice
if k and k > 1 then
choice = self.choices[k-1]
else
choice = self.choices[#self.choices]
end
self.value = choice.value
self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice })
self:draw()
return true
end end
self.value = choice.value
self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice })
self:draw()
return true
elseif event.type == 'choice_prev' then
local _,k = Util.find(self.choices, 'value', self.value)
local choice
if k and k > 1 then
choice = self.choices[k-1]
else
choice = self.choices[#self.choices]
end
self.value = choice.value
self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice })
self:draw()
return true
elseif event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then elseif event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then
if event.x == 1 then if event.x == 1 then
self:emit({ type = 'key', key = 'left' }) self:emit({ type = 'choice_prev' })
return true return true
elseif event.x == self.width then elseif event.x == self.width then
self:emit({ type = 'key', key = 'right' }) self:emit({ type = 'choice_next' })
return true return true
end end
end end

View File

@ -0,0 +1,163 @@
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',
accelerators = {
down = 'focus_next',
enter = 'focus_next',
tab = 'focus_next',
['shift-tab' ] = 'focus_prev',
up = 'focus_prev',
},
backgroundColor = colors.cyan,
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
self:focusFirst()
end
end
function UI.Page:disable()
self.canvas.visible = false
UI.Window.disable(self)
end
function UI.Page:sync()
if self.enabled then
self.parent:sync()
end
end
function UI.Page:capture(child)
self.__target = child
end
function UI.Page:release(child)
if self.__target == child then
self.__target = self
end
end
function UI.Page:pointToChild(x, y)
if self.__target == self then
return UI.Window.pointToChild(self, x, y)
end
local absX, absY = getPosition(self.__target)
-- this is sketchy
x = x + self.offx - self.x - (absX - self.__target.x) + 1
y = y + self.offy - self.y - (absY - self.__target.y) + 1
return self.__target:pointToChild(x, y)
end
function UI.Page:getFocusables()
if self.__target == self or self.__target.pageType ~= 'modal' then
return UI.Window.getFocusables(self)
end
return self.__target:getFocusables()
end
function UI.Page:getFocused()
return self.focused
end
function UI.Page:focusPrevious()
local function getPreviousFocus(focused)
local focusables = self:getFocusables()
local k = Util.contains(focusables, focused)
if k then
if k > 1 then
return focusables[k - 1]
end
return focusables[#focusables]
end
end
local focused = getPreviousFocus(self.focused)
if focused then
self:setFocus(focused)
end
end
function UI.Page:focusNext()
local function getNextFocus(focused)
local focusables = self:getFocusables()
local k = Util.contains(focusables, focused)
if k then
if k < #focusables then
return focusables[k + 1]
end
return focusables[1]
end
end
local focused = getNextFocus(self.focused)
if focused then
self:setFocus(focused)
end
end
function UI.Page:setFocus(child)
if not child or not child.focus then
return
end
if self.focused and self.focused ~= child then
self.focused.focused = false
self.focused:focus()
self.focused:emit({ type = 'focus_lost', focused = child, unfocused = self.focused })
end
self.focused = 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:eventHandler(event)
if self.focused then
if event.type == 'focus_next' then
self:focusNext()
return true
elseif event.type == 'focus_prev' then
self:focusPrevious()
return true
end
end
end

View File

@ -61,17 +61,14 @@ end
function UI.SlideOut.example() function UI.SlideOut.example()
-- for the transistion to work properly, the parent must have a canvas -- for the transistion to work properly, the parent must have a canvas
return UI.ActiveLayer { return UI.ActiveLayer {
y = 1, -- TODO: if this is set to anything greater than 1, then y = 2,
-- the layer is not rendered in the correct location
-- a general issue in canvas layers
backgroundColor = colors.cyan,
button = UI.Button { button = UI.Button {
x = 2, y = 5, x = 2, y = 5,
text = 'show', text = 'show',
}, },
slideOut = UI.SlideOut { slideOut = UI.SlideOut {
backgroundColor = colors.yellow, backgroundColor = _G.colors.yellow,
y = -4, height = 4, y = -4, height = 4, x = 3, ex = -3,
button = UI.Button { button = UI.Button {
x = 2, y = 2, x = 2, y = 2,
text = 'hide', text = 'hide',

View File

@ -39,7 +39,7 @@ function Transition.expandUp(args)
local easing = args.easing or 'linear' local easing = args.easing or 'linear'
local pos = { y = args.ey + 1 } local pos = { y = args.ey + 1 }
local tween = Tween.new(ticks, pos, { y = args.y }, easing) local tween = Tween.new(ticks, pos, { y = args.y }, easing)
_syslog(args)
args.canvas:move(args.x, pos.y) args.canvas:move(args.x, pos.y)
return function() return function()