diff --git a/apps/Overview.lua b/apps/Overview.lua index 6fd5143..a17aa5c 100644 --- a/apps/Overview.lua +++ b/apps/Overview.lua @@ -261,6 +261,13 @@ function page:eventHandler(event) event.focused.parent:scrollIntoView() end + elseif event.type == 'tab_change' then + if event.current > event.last then + self.container:setTransition('left') + else + self.container:setTransition('right') + end + elseif event.type == 'refresh' then applications = { } Config.load('apps', applications) diff --git a/apps/Peripherals.lua b/apps/Peripherals.lua index ccd3e21..682bbff 100644 --- a/apps/Peripherals.lua +++ b/apps/Peripherals.lua @@ -6,23 +6,23 @@ local UI = require('ui') multishell.setTitle(multishell.getCurrent(), 'Devices') --[[ -- PeripheralsPage -- ]] -- -local peripheralsPage = UI.Page({ - grid = UI.ScrollingGrid({ +local peripheralsPage = UI.Page { + grid = UI.ScrollingGrid { columns = { { heading = 'Type', key = 'type' }, - { heading = 'Side', key = 'side' } + { heading = 'Side', key = 'side' }, }, sortColumn = 'type', height = UI.term.height - 1, autospace = true, - }), - statusBar = UI.StatusBar({ + }, + statusBar = UI.StatusBar { status = 'Select peripheral' - }), + }, accelerators = { q = 'quit', }, -}) +} function peripheralsPage.grid:draw() local sides = peripheral.getNames() @@ -40,7 +40,6 @@ function peripheralsPage.grid:draw() end function peripheralsPage:updatePeripherals() - if UI:getCurrentPage() == self then self.grid:draw() self:sync() @@ -59,29 +58,27 @@ function peripheralsPage:eventHandler(event) end --[[ -- MethodsPage -- ]] -- -local methodsPage = UI.Page({ - grid = UI.ScrollingGrid({ +local methodsPage = UI.Page { + grid = UI.ScrollingGrid { columns = { { heading = 'Name', key = 'name', width = UI.term.width } }, sortColumn = 'name', height = 7, - }), - container = UI.Window({ + }, + viewportConsole = UI.ViewportWindow { y = 8, - height = UI.term.height-8, - viewportConsole = UI.ViewportWindow({ - backgroundColor = colors.brown - }), - }), - statusBar = UI.StatusBar({ + height = UI.term.height - 8, + backgroundColor = colors.brown, + }, + statusBar = UI.StatusBar { status = 'q to return', - }), + }, accelerators = { q = 'back', backspace = 'back', }, -}) +} function methodsPage:enable(p) @@ -103,6 +100,8 @@ function methodsPage:enable(p) end end + self.viewportConsole.offy = 0 + self.grid:update() self.grid:setIndex(1) @@ -110,31 +109,26 @@ function methodsPage:enable(p) UI.Page.enable(self) end -function methodsPage.container.viewportConsole:draw() - if methodsPage.grid:getSelected() then - methodsPage:drawMethodInfo(self, methodsPage.grid:getSelected()) - end -end - function methodsPage:eventHandler(event) if event.type == 'back' then UI:setPage(peripheralsPage) return true elseif event.type == 'grid_focus_row' then - self.container.viewportConsole.height = 1 - self.container.viewportConsole.offset = 0 - self.container.viewportConsole.y = 1 - self:drawMethodInfo(self.container.viewportConsole, event.selected) + self.viewportConsole.offy = 0 + self.viewportConsole:draw() end return UI.Page.eventHandler(self, event) end -function methodsPage:drawMethodInfo(c, method) +function methodsPage.viewportConsole:draw() + local c = self + local method = methodsPage.grid:getSelected() c:clear() c:setCursorPos(1, 1) if method.noext then + c.cursorY = 2 c:print('No extended Information') return 2 end @@ -189,10 +183,7 @@ function methodsPage:drawMethodInfo(c, method) end end - c.height = c.cursorY + 1 - - term.setBackgroundColor(colors.black) - return y + c.ymax = c.cursorY + 1 end Event.addHandler('peripheral', function() diff --git a/apps/System.lua b/apps/System.lua index 3af95c7..4aaa1ee 100644 --- a/apps/System.lua +++ b/apps/System.lua @@ -11,73 +11,79 @@ local env = { aliases = shell.aliases(), lua_path = LUA_PATH, } - Config.load('multishell', env) UI.TextEntry.defaults.backgroundFocusColor = colors.black -local systemPage = UI.Page({ +local systemPage = UI.Page { backgroundColor = colors.blue, - tabs = UI.Tabs({ - pathTab = UI.Window({ + tabs = UI.Tabs { + pathTab = UI.Window { tabTitle = 'Path', - entry = UI.TextEntry({ - y = 2, x = 2, limit = 256, - width = UI.term.width - 2, + entry = UI.TextEntry { + x = 2, y = 2, rex = -2, + limit = 256, value = shell.path(), shadowText = 'enter system path', accelerators = { enter = 'update_path', }, - }), - grid = UI.Grid({ + }, + grid = UI.Grid { y = 4, values = paths, disableHeader = true, columns = { { key = 'value' } }, autospace = true, - }), - }), + }, + }, - aliasTab = UI.Window({ + aliasTab = UI.Window { tabTitle = 'Aliases', - alias = UI.TextEntry({ - y = 2, x = 2, width = UI.term.width - 2, + alias = UI.TextEntry { + x = 2, y = 2, rex = -2, limit = 32, shadowText = 'Alias', - }), - path = UI.TextEntry({ - y = 3, x = 2, width = UI.term.width - 2, limit = 256, + }, + path = UI.TextEntry { + y = 3, x = 2, rex = -2, + limit = 256, shadowText = 'Program path', accelerators = { enter = 'new_alias', }, - }), - grid = UI.Grid({ - y = 5, values = aliases, autospace = true, + }, + grid = UI.Grid { + y = 5, + values = aliases, + autospace = true, + sortColumn = 'alias', columns = { { heading = 'Alias', key = 'alias' }, { heading = 'Program', key = 'path' }, }, - sortColumn = 'alias', accelerators = { delete = 'delete_alias', }, - }), - }), + }, + }, - infoTab = UI.Window({ + infoTab = UI.Window { tabTitle = 'Info', - labelText = UI.Text({ y = 2, x = 3, value = 'Label' }), - label = UI.TextEntry({ - y = 2, x = 9, width = UI.term.width - 12, - limit = 32, value = os.getComputerLabel(), + labelText = UI.Text { + x = 3, y = 2, + value = 'Label' + }, + label = UI.TextEntry { + x = 9, y = 2, rex = -12, + limit = 32, + value = os.getComputerLabel(), backgroundFocusColor = colors.black, accelerators = { enter = 'update_label', }, - }), - grid = UI.ScrollingGrid({ + }, + grid = UI.ScrollingGrid { y = 4, values = { { name = 'CC version', value = os.version() }, @@ -93,15 +99,14 @@ local systemPage = UI.Page({ { key = 'name', width = 12 }, { key = 'value', width = UI.term.width - 15 }, }, - }), - }), - }), --- statusBar = UI.StatusBar(), + }, + }, + }, notification = UI.Notification(), accelerators = { q = 'quit', }, -}) +} function systemPage.tabs.pathTab.grid:draw() self.values = { } @@ -120,10 +125,8 @@ function systemPage.tabs.pathTab:eventHandler(event) self.grid:draw() Config.update('multishell', env) systemPage.notification:success('reboot to take effect') - else - return UI.Window.eventHandler(self, event) + return true end - return true end function systemPage.tabs.aliasTab.grid:draw() @@ -144,6 +147,7 @@ function systemPage.tabs.aliasTab:eventHandler(event) self.grid:draw() Config.update('multishell', env) systemPage.notification:success('reboot to take effect') + return true elseif event.type == 'new_alias' then env.aliases[self.alias.value] = self.path.value @@ -153,10 +157,8 @@ function systemPage.tabs.aliasTab:eventHandler(event) self:setFocus(self.alias) Config.update('multishell', env) systemPage.notification:success('reboot to take effect') - else - return UI.Window.eventHandler(self, event) + return true end - return true end function systemPage.tabs.infoTab:eventHandler(event) @@ -164,21 +166,15 @@ function systemPage.tabs.infoTab:eventHandler(event) os.setComputerLabel(self.label.value) systemPage.notification:success('Label updated') return true - else - return UI.Window.eventHandler(self, event) end - return true end function systemPage:eventHandler(event) if event.type == 'quit' then Event.exitPullEvents() - elseif event.type == 'tab_activate' then event.activated:focusFirst() - --self.statusBar:setValue('') - --self.statusBar:draw() else return UI.Page.eventHandler(self, event) end diff --git a/apps/edit.lua b/apps/edit.lua index ee680d6..b64107e 100644 --- a/apps/edit.lua +++ b/apps/edit.lua @@ -811,6 +811,8 @@ local __actions = { local nx = nextWord(tLines[y], x) if nx then x = nx + elseif x < #tLines[y] + 1 then + x = #tLines[y] + 1 elseif y < #tLines then x = 1 y = y + 1 diff --git a/apps/multishell b/apps/multishell index a5d9dff..6f88988 100644 --- a/apps/multishell +++ b/apps/multishell @@ -455,7 +455,7 @@ end) local function startup() local hasError - local function runDir(directory, open) + local function runDir(directory, desc, open) if not fs.exists(directory) then return end @@ -464,8 +464,8 @@ local function startup() table.sort(files) for _,file in ipairs(files) do - print('Autorunning: ' .. file) - + print(desc .. file) + os.sleep(0) local result, err = open(directory .. '/' .. file) if not result then printError(err) @@ -474,7 +474,7 @@ local function startup() end end - runDir('/sys/extensions', shell.run) + runDir('/sys/extensions', '[ ext ] ', shell.run) local overviewId = multishell.openTab({ path = '/apps/Overview.lua', @@ -484,8 +484,8 @@ local function startup() }) overviewTab = tabs[overviewId] - runDir('/sys/services', shell.openHiddenTab) - runDir('/autorun', shell.run) + runDir('/sys/services', '[ svc ] ', shell.openHiddenTab) + runDir('/autorun', '[ aut ] ', shell.run) if hasError then error('An autorun program has errored') diff --git a/apps/recorder.lua b/apps/recorder.lua index 3674727..ea70a10 100644 --- a/apps/recorder.lua +++ b/apps/recorder.lua @@ -14,7 +14,7 @@ local version = "Version 1.1.6" -- Original code by Bomb Bloke -- Modified to integrate with opus os -local calls, recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput, callCount, callListCount = {{["delay"] = 0}}, {}, term.current(), {...}, false, false, 2, "", 1, 2 +local calls, recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput, callCount, callListCount = {{["delay"] = 0}}, {}, Util.shallowCopy(multishell.term), {...}, false, false, 2, "", 1, 2 local curBlink, oldBlink, curCalls, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, calls[1], {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, term.getSize() local greys, buttons = {["0"] = true, ["7"] = true, ["8"] = true, ["f"] = true}, {"l", "r", "m"} local charW, charH, chars, resp @@ -84,8 +84,6 @@ end package = loadAPI('.recGif/package', getfenv(1)) GIF = loadAPI('.recGif/GIF', getfenv(1)) -oldTerm = Util.shallowCopy(multishell.term) - local oldDir = shell.dir() shell.setDir('.recGif') shell.run("package get Y0eLUPtr") diff --git a/apps/update.lua b/apps/update.lua index 86ea65f..f0b63a8 100644 --- a/apps/update.lua +++ b/apps/update.lua @@ -1,6 +1,2 @@ -local args = { ... } -local options = '' -for _,v in pairs(args) do - options = options .. ' ' .. v -end -shell.run('pastebin run sj4VMVJj' .. options) \ No newline at end of file +local options = table.concat({ ... }, ' ') +shell.run('pastebin run sj4VMVJj ' .. options) diff --git a/sys/apis/fileui.lua b/sys/apis/fileui.lua index 01fe746..680dcda 100644 --- a/sys/apis/fileui.lua +++ b/sys/apis/fileui.lua @@ -15,9 +15,9 @@ return function() local selectFile = UI.Page({ x = 3, - y = 3, - ex = -3, - ey = -3, + y = 2, + rex = -3, + rey = -3, backgroundColor = colors.brown, titleBar = UI.TitleBar({ title = 'Select file', @@ -27,16 +27,16 @@ return function() grid = UI.ScrollingGrid({ x = 2, y = 2, - ex = -2, - ey = -4, + rex = -2, + rey = -4, path = '', sortColumn = 'name', columns = columns, }), path = UI.TextEntry({ x = 2, - oy = -1, - ex = -11, + ry = -1, + rex = -11, limit = 256, accelerators = { enter = 'path_enter', @@ -44,8 +44,8 @@ return function() }), cancel = UI.Button({ text = 'Cancel', - ox = -8, - oy = -1, + rx = -8, + ry = -1, event = 'cancel', }), }) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 7b690fc..c356841 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -267,9 +267,6 @@ function Manager:inputEvent(parent, event) if parent:emit({ type = acc, element = parent }) then return true end --- if parent:eventHandler({ type = acc, element = parent }) then --- return true --- end end if parent.eventHandler then if parent:eventHandler(event) then @@ -521,18 +518,26 @@ end function UI.Window:setParent() self.oh, self.ow = self.height, self.width - if self.ox then - self.x = self.parent.width + self.ox + if self.rx then + if self.rx > 0 then + self.x = self.rx + else + self.x = self.parent.width + self.rx + end end - if self.oy then - self.y = self.parent.height + self.oy + if self.ry then + if self.ry > 0 then + self.y = self.ry + else + self.y = self.parent.height + self.ry + end end - if self.ex then - self.width = self.parent.width - self.x + self.ex + 2 + if self.rex then + self.width = self.parent.width - self.x + self.rex + 2 end - if self.ey then - self.height = self.parent.height - self.y + self.ey + 2 + if self.rey then + self.height = self.parent.height - self.y + self.rey + 2 end if not self.width then @@ -583,21 +588,29 @@ end function UI.Window:resize() - if self.ox then - self.x = self.parent.width + self.ox + if self.rx then + if self.rx > 0 then + self.x = self.rx + else + self.x = self.parent.width + self.rx + end end - if self.oy then - self.y = self.parent.height + self.oy + if self.ry then + if self.ry > 0 then + self.y = self.ry + else + self.y = self.parent.height + self.ry + end end - if self.ex then - self.width = self.parent.width - self.x + self.ex + 2 + if self.rex then + self.width = self.parent.width - self.x + self.rex + 2 elseif not self.ow and self.parent then self.width = self.parent.width - self.x + 1 end - if self.ey then - self.oh = self.parent.height - self.y + self.ey + 2 + if self.rey then + self.height = self.parent.height - self.y + self.rey + 2 elseif not self.oh and self.parent then self.height = self.parent.height - self.y + 1 end @@ -700,11 +713,16 @@ function UI.Window:print(text, bg, fg, indent) end end - for _,line in pairs(Util.split(text)) do + local lines = Util.split(text) + for k,line in pairs(lines) do local lx = 1 while true do local word = nextWord(line, lx) if not word then + if lines[k + 1] then + self.cursorX = indent + self.cursorY = self.cursorY + 1 + end break end local w = word @@ -783,6 +801,14 @@ function UI.Window:scrollIntoView() end end +function UI.Window:setTransition(effect, y, height) + if self.parent then + y = y or 1 + height = height or self.height + self.parent:setTransition(effect, y + self.y - 1, height) + end +end + function UI.Window:emit(event) local parent = self --debug(self.UIElement .. ' emitting ' .. event.type) @@ -809,6 +835,7 @@ UI.Device.defaults = { textColor = colors.white, textScale = 1, lines = { }, + transitionsEnabled = true, } function UI.Device:init(args) @@ -834,6 +861,7 @@ end function UI.Device:resize() self.width, self.height = self.device.getSize() + self.lines = { } UI.Window.resize(self) end @@ -863,14 +891,112 @@ function UI.Device:reset() self.device.setCursorPos(1, 1) end -function UI.Device:sync() - for y, line in pairs(self.lines) do - if line.dirty then - self.device.setCursorPos(1, y) - self.device.blit(line.text, line.fg, line.bg) - line.dirty = false +function UI.Device:setTransition(effect, y, height) + if not self.transition then + self.transition = effect + for i = y, y + height - 1 do + local line = self.lines[i] + if line then + line.transition = true + end end end +end + +function UI.Device:runTransition(transition) + if transition == 'left' or transition == 'right' then + for y, line in ipairs(self.lines) do + if not line.transition then + self.device.setCursorPos(1, y) + self.device.blit(line.text, line.fg, line.bg) + end + end + + local c = os.clock() + local steps = math.floor(self.width * .34) -- 150 ms + + for i = 1, self.width do + for y, line in pairs(self.lines) do + if line.transition then + if transition == 'left' then + local text = self.lastScreen[y].text .. line.text + local bg = self.lastScreen[y].bg .. line.bg + local fg = self.lastScreen[y].fg .. line.fg + self.device.setCursorPos(1 - i, y) + self.device.blit(text, fg, bg) + else + local text = line.text .. self.lastScreen[y].text + local bg = line.bg .. self.lastScreen[y].bg + local fg = line.fg .. self.lastScreen[y].fg + self.device.setCursorPos(-self.width + i + 1, y) + self.device.blit(text, fg, bg) + end + end + end + if (i + math.floor(steps / 2)) % steps == 0 then + if c == os.clock() then + os.sleep(0) + c = os.clock() + end + end + end + + elseif transition == 'explode' then + local half = math.floor(self.width / 2) + local c = os.clock() + local steps = math.floor(self.width * .5) + for i = 1, half do + for y, line in pairs(self.lines) do + local width = i * 2 + local mid = half - i + 1 + self.device.setCursorPos(mid, y) + self.device.blit( + line.text:sub(mid, mid + width), + line.fg:sub(mid, mid + width), + line.bg:sub(mid, mid + width)) + end + if (i + math.floor(steps / 2)) % steps == 0 then + if c == os.clock() then + os.sleep(0) + c = os.clock() + end + end + end + end + + for y, line in ipairs(self.lines) do + line.dirty = false + line.transition = false + end +end + +function UI.Device:sync() + + local transition + if self.transition then + for y, line in pairs(self.lines) do + if line.dirty then + transition = self.transition + break + end + end + self.transition = nil + end + + if transition and self.transitionsEnabled then + self:runTransition(transition) + else + for y, line in pairs(self.lines) do + if line.dirty then + self.device.setCursorPos(1, y) + self.device.blit(line.text, line.fg, line.bg) + line.dirty = false + end + end + end + + self.lastScreen = Util.deepCopy(self.lines) + if self:getCursorBlink() then self.device.setCursorPos(self.cursorX, self.cursorY) end @@ -1596,12 +1722,16 @@ function UI.ViewportWindow:setScrollPosition(offset) max = math.max(child.y + child.height - 1, max) end end - self.offy = math.min(self.offy, max - self.height) + self.offy = math.min(self.offy, math.max(max, self.height) - self.height) if self.offy ~= oldOffset then self:draw() end end +function UI.ViewportWindow:reset() + self.offy = 0 +end + function UI.ViewportWindow:eventHandler(event) if event.type == 'scroll_down' then @@ -1731,7 +1861,7 @@ function UI.MenuBar:init(args) if self.showBackButton then table.insert(self.children, UI.Button({ x = UI.term.width - 2, - width = 4, + width = 3, backgroundColor = self.backgroundColor, textColor = self.textColor, text = '^-', @@ -1758,7 +1888,6 @@ function UI.MenuBar:eventHandler(event) end end end - return false end --[[-- DropMenu --]]-- @@ -1834,6 +1963,7 @@ function UI.DropMenu:eventHandler(event) else return UI.MenuBar.eventHandler(self, event) end + return true end --[[-- TabBar --]]-- @@ -1849,17 +1979,24 @@ function UI.TabBar:init(args) end function UI.TabBar:selectTab(text) - for _,child in pairs(self.children) do - if child.text == text then - child.selected = true + local selected, lastSelected + for k,child in pairs(self.children) do + if child.selected then + lastSelected = k + end + child.selected = child.text == text + if child.selected then + selected = k child.backgroundColor = self.selectedBackgroundColor child.backgroundFocusColor = self.selectedBackgroundColor else - child.selected = false child.backgroundColor = self.backgroundColor child.backgroundFocusColor = self.backgroundColor end end + if selected and lastSelected and selected ~= lastSelected then + self:emit({ type = 'tab_change', current = selected, last = lastSelected }) + end UI.MenuBar.draw(self) end @@ -1929,9 +2066,62 @@ function UI.Tabs:eventHandler(event) break end end - return true + elseif event.type == 'tab_change' then + for _,tab in ipairs(self.children) do + if tab ~= self.tabBar then + if event.current > event.last then + tab:setTransition('left') + else + tab:setTransition('right') + end + break + end + end + end +end + +--[[-- WindowScroller --]]-- +UI.WindowScroller = class(UI.Window) +UI.WindowScroller.defaults = { + UIElement = 'WindowScroller', + children = { }, +} +function UI.WindowScroller:init(args) + local defaults = UI:getDefaults(UI.WindowScroller, args) + UI.Window.init(self, defaults) +end + +function UI.WindowScroller:enable() + self.enabled = true + if #self.children > 0 then + self.children[1]:enable() + end +end + +function UI.WindowScroller:nextChild() + for i = 1, #self.children do + if self.children[i].enabled then + if i < #self.children then + self:setTransition('left') + self.children[i]:disable() + self.children[i + 1]:enable() + end + break + end + end +end + +function UI.WindowScroller:prevChild() + for i = 1, #self.children do + if self.children[i].enabled then + if i - 1 > 0 then + self:setTransition('right') + self.children[i]:disable() + self.children[i - 1]:enable() + end + break + end end - return UI.Window.eventHandler(self, event) end --[[-- Notification --]]--