diff --git a/sys/apps/inspect.lua b/sys/apps/inspect.lua index 6cc4048..1d4f95b 100644 --- a/sys/apps/inspect.lua +++ b/sys/apps/inspect.lua @@ -6,8 +6,7 @@ local multishell = _ENV.multishell local name = ({ ... })[1] or error('Syntax: inspect COMPONENT') local events = { } -local page -local lastEvent +local page, lastEvent, focused local function isRelevant(el) return page.testContainer == el or el.parent and isRelevant(el.parent) @@ -43,11 +42,12 @@ end page = UI.Page { testContainer = UI.Window { - ey = 10, + ey = '50%', testing = component.example(), }, tabs = UI.Tabs { - y = 11, + backgroundColor = colors.red, + y = '50%', properties = UI.Tab { tabTitle = 'Properties', grid = UI.ScrollingGrid { @@ -66,18 +66,29 @@ page = UI.Page { index = 2, tabTitle = 'Methods', grid = UI.ScrollingGrid { + ex = '50%', headerBackgroundColor = colors.red, sortColumn = 'key', columns = { { heading = 'key', key = 'key' }, }, }, + docs = UI.TextArea { + x = '50%', + backgroundColor = colors.black, + }, + eventHandler = function (self, event) + if event.type == 'grid_focus_row' and focused then + self.docs:setText(focused:getDoc(event.selected.key) or '') + end + end, }, events = UI.Tab { index = 1, tabTitle = 'Events', UI.MenuBar { y = -1, + backgroundColor = colors.red, buttons = { { text = 'Clear' }, } @@ -124,6 +135,7 @@ page = UI.Page { }, eventHandler = function (self, event) if event.type == 'focus_change' and isRelevant(event.focused) then + focused = event.focused local t = { } for k,v in pairs(event.focused) do table.insert(t, { diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 5686f93..6e464ad 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -398,6 +398,7 @@ local UI = Manager() --[[-- Basic drawable area --]]-- UI.Window = class() UI.Window.uid = 1 +UI.Window.docs = { } UI.Window.defaults = { UIElement = 'Window', x = 1, @@ -482,13 +483,14 @@ function UI.Window:layout() end if type(self.x) == 'string' then - self.x = calc(self.x, self.parent.width) + self.x = calc(self.x, self.parent.width) + 1 + -- +1 in order to allow both x and ex to use the same % end if type(self.ex) == 'string' then self.ex = calc(self.ex, self.parent.width) end if type(self.y) == 'string' then - self.y = calc(self.y, self.parent.height) + self.y = calc(self.y, self.parent.height) + 1 end if type(self.ey) == 'string' then self.ey = calc(self.ey, self.parent.height) @@ -539,6 +541,22 @@ function UI.Window:setParent() 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 @@ -555,6 +573,13 @@ function UI.Window:resize() end end +UI.Window.docs.add = [[add(TABLE) +Add element(s) to a window. Example: +page:add({ + text = UI.Text { + x=5,value='help' + } +})]] function UI.Window:add(children) UI:mergeProperties(self, children) self:initChildren() @@ -574,6 +599,8 @@ function UI.Window:setCursorBlink(blink) self.parent:setCursorBlink(blink) 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 @@ -585,6 +612,21 @@ function UI.Window:draw() end end +UI.Window.docs.getDoc = [[getDoc(STRING method) +Gets the documentation for a method.]] +function UI.Window:getDoc(method) + local m = getmetatable(self) -- get the class for this instance + repeat + if m.docs and m.docs[method] then + return m.docs[method] + end + m = m._base + until not m +end + +UI.Window.docs.sync = [[sync(VOID) +Invoke a screen update. Automatically called at top level after an input event. +Call to force a screen update.]] function UI.Window:sync() if self.parent then self.parent:sync() @@ -614,9 +656,11 @@ function UI.Window:setTextScale(textScale) self.parent: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.]] function UI.Window:clear(bg, fg) if self.canvas then - self.canvas:clear(bg or self.backgroundColor, fg or self.textColor) + 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 @@ -635,18 +679,18 @@ function UI.Window:clearArea(x, y, width, height, bg) end end -function UI.Window:write(x, y, text, bg, tc) +function UI.Window:write(x, y, text, bg, fg) bg = bg or self.backgroundColor - tc = tc or self.textColor + fg = fg or self.textColor if self.canvas then - self.canvas:write(x, y, text, bg, tc) + 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, tc) + self.x + x - 1, self.y + y - 1, tostring(text), bg, fg) end end end @@ -752,12 +796,20 @@ function UI.Window:print(text, bg, fg) return self.cursorX, self.cursorY end +UI.Window.docs.focus = [[focus(VOID) +If the function is present on a class, it indicates +that this element can accept focus. Called when receiving focus.]] + +UI.Window.docs.setFocus = [[setFocus(ELEMENT el) +Set the page's focus to the passed element.]] function UI.Window:setFocus(focus) if self.parent then self.parent:setFocus(focus) end end +UI.Window.docs.capture = [[capture(ELEMENT el) +Restricts input to the passed element's tree.]] function UI.Window:capture(child) if self.parent then self.parent:capture(child) @@ -793,6 +845,8 @@ function UI.Window:pointToChild(x, y) } end +UI.Window.docs.getFocusables = [[getFocusables(VOID) +Returns a list of children that can accept focus.]] function UI.Window:getFocusables() local focusable = { } diff --git a/sys/modules/opus/ui/canvas.lua b/sys/modules/opus/ui/canvas.lua index d0d4ee9..cb46ede 100644 --- a/sys/modules/opus/ui/canvas.lua +++ b/sys/modules/opus/ui/canvas.lua @@ -355,7 +355,9 @@ 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, self.parent.height) + 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 diff --git a/sys/modules/opus/ui/components/Checkbox.lua b/sys/modules/opus/ui/components/Checkbox.lua index 54343e5..567833e 100644 --- a/sys/modules/opus/ui/components/Checkbox.lua +++ b/sys/modules/opus/ui/components/Checkbox.lua @@ -21,21 +21,20 @@ 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 + function UI.Checkbox:draw() - local bg = self.backgroundColor - if self.focused then - bg = self.backgroundFocusColor - end - if type(self.value) == 'string' then - self.value = nil -- TODO: fix form - end - local text = string.format('[%s]', not self.value and ' ' or self.checkedIndicator) + local bg = self.focused and self.backgroundFocusColor or self.backgroundColor local x = 1 if self.label then - self:write(1, 1, self.label) + self:write(1, 1, self.label, self.labelBackgroundColor) x = #self.label + 2 end - self:write(x, 1, text, bg) self:write(x, 1, self.leftMarker, self.backgroundColor, self.textColor) self:write(x + 1, 1, not self.value and ' ' or self.checkedIndicator, bg) self:write(x + 2, 1, self.rightMarker, self.backgroundColor, self.textColor) @@ -46,11 +45,12 @@ function UI.Checkbox:focus() end function UI.Checkbox:setValue(v) - self.value = v + self.value = not not v end function UI.Checkbox:reset() self.value = false + self:draw() end function UI.Checkbox:eventHandler(event) @@ -63,7 +63,13 @@ function UI.Checkbox:eventHandler(event) end function UI.Checkbox.example() - return UI.Checkbox { - x = 2, y = 2, + return UI.Window { + ex1 = UI.Checkbox { + label = 'test', + x = 2, y = 2, + }, + ex2 = UI.Checkbox { + x = 2, y = 4, + }, } end diff --git a/sys/modules/opus/ui/components/DropMenuItem.lua b/sys/modules/opus/ui/components/DropMenuItem.lua index 09263da..ff28047 100644 --- a/sys/modules/opus/ui/components/DropMenuItem.lua +++ b/sys/modules/opus/ui/components/DropMenuItem.lua @@ -3,7 +3,6 @@ local UI = require('opus.ui') local colors = _G.colors ---[[-- DropMenuItem --]]-- UI.DropMenuItem = class(UI.Button) UI.DropMenuItem.defaults = { UIElement = 'DropMenuItem', diff --git a/sys/modules/opus/ui/components/Menu.lua b/sys/modules/opus/ui/components/Menu.lua index 8f1c837..0e18682 100644 --- a/sys/modules/opus/ui/components/Menu.lua +++ b/sys/modules/opus/ui/components/Menu.lua @@ -1,7 +1,6 @@ local class = require('opus.class') local UI = require('opus.ui') ---[[-- Menu --]]-- UI.Menu = class(UI.Grid) UI.Menu.defaults = { UIElement = 'Menu', diff --git a/sys/modules/opus/ui/components/MenuBar.lua b/sys/modules/opus/ui/components/MenuBar.lua index 217fccd..1b544cc 100644 --- a/sys/modules/opus/ui/components/MenuBar.lua +++ b/sys/modules/opus/ui/components/MenuBar.lua @@ -51,6 +51,7 @@ function UI.MenuBar:addButtons(buttons) x = self.lastx, width = #(button.text or 'button') + self.spacing, centered = false, + backgroundColor = self.backgroundColor, } self.lastx = self.lastx + buttonProperties.width UI:mergeProperties(buttonProperties, button) diff --git a/sys/modules/opus/ui/components/MenuItem.lua b/sys/modules/opus/ui/components/MenuItem.lua index 2f0efe8..61bc0b1 100644 --- a/sys/modules/opus/ui/components/MenuItem.lua +++ b/sys/modules/opus/ui/components/MenuItem.lua @@ -3,7 +3,6 @@ local UI = require('opus.ui') local colors = _G.colors ---[[-- MenuItem --]]-- UI.MenuItem = class(UI.Button) UI.MenuItem.defaults = { UIElement = 'MenuItem', diff --git a/sys/modules/opus/ui/components/Notification.lua b/sys/modules/opus/ui/components/Notification.lua index 7b11543..701733e 100644 --- a/sys/modules/opus/ui/components/Notification.lua +++ b/sys/modules/opus/ui/components/Notification.lua @@ -92,25 +92,26 @@ function UI.Notification:eventHandler(event) end function UI.Notification.example() - return UI.Window { - notify = UI.Notification { + return UI.ActiveLayer { + notify1 = UI.Notification { anchor = 'top', }, + notify2 = UI.Notification { }, button1 = UI.Button { x = 2, y = 3, - text = 'success', + text = 'example 1', event = 'test_success', }, button2 = UI.Button { x = 2, y = 5, - text = 'error', + text = 'example 2', event = 'test_error', }, eventHandler = function (self, event) if event.type == 'test_success' then - self.notify:success('Example text') + self.notify1:success('Example text') elseif event.type == 'test_error' then - self.notify:error('Example text', 0) + self.notify2:error('Example text', 0) end end, } diff --git a/sys/modules/opus/ui/components/ScrollingGrid.lua b/sys/modules/opus/ui/components/ScrollingGrid.lua index 93a35e6..06dd5b8 100644 --- a/sys/modules/opus/ui/components/ScrollingGrid.lua +++ b/sys/modules/opus/ui/components/ScrollingGrid.lua @@ -2,7 +2,6 @@ local class = require('opus.class') local UI = require('opus.ui') local Util = require('opus.util') ---[[-- ScrollingGrid --]]-- UI.ScrollingGrid = class(UI.Grid) UI.ScrollingGrid.defaults = { UIElement = 'ScrollingGrid', diff --git a/sys/modules/opus/ui/components/SlideOut.lua b/sys/modules/opus/ui/components/SlideOut.lua index 1e9558f..789220f 100644 --- a/sys/modules/opus/ui/components/SlideOut.lua +++ b/sys/modules/opus/ui/components/SlideOut.lua @@ -1,7 +1,6 @@ local class = require('opus.class') local UI = require('opus.ui') ---[[-- SlideOut --]]-- UI.SlideOut = class(UI.Window) UI.SlideOut.defaults = { UIElement = 'SlideOut', @@ -62,9 +61,12 @@ end function UI.SlideOut.example() -- for the transistion to work properly, the parent must have a canvas return UI.ActiveLayer { + y = 1, -- TODO: if this is set to anything greater than 1, then + -- the layer is not rendered in the correct location + -- a general issue in canvas layers backgroundColor = colors.cyan, button = UI.Button { - x = 2, y = 2, + x = 2, y = 5, text = 'show', }, slideOut = UI.SlideOut { diff --git a/sys/modules/opus/ui/components/Tab.lua b/sys/modules/opus/ui/components/Tab.lua index 2f86b2f..1e31de6 100644 --- a/sys/modules/opus/ui/components/Tab.lua +++ b/sys/modules/opus/ui/components/Tab.lua @@ -1,12 +1,9 @@ local class = require('opus.class') local UI = require('opus.ui') -local colors = _G.colors - UI.Tab = class(UI.ActiveLayer) UI.Tab.defaults = { UIElement = 'Tab', tabTitle = 'tab', - backgroundColor = colors.cyan, y = 2, } diff --git a/sys/modules/opus/ui/components/TabBar.lua b/sys/modules/opus/ui/components/TabBar.lua index 72e07f6..e684cae 100644 --- a/sys/modules/opus/ui/components/TabBar.lua +++ b/sys/modules/opus/ui/components/TabBar.lua @@ -2,13 +2,13 @@ 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', - selectedBackgroundColor = colors.cyan, +} +UI.TabBar.inherits = { + selectedBackgroundColor = 'backgroundColor', } function UI.TabBar:enable() UI.MenuBar.enable(self) diff --git a/sys/modules/opus/ui/components/TabBarMenuItem.lua b/sys/modules/opus/ui/components/TabBarMenuItem.lua index 0a7799c..f9f549b 100644 --- a/sys/modules/opus/ui/components/TabBarMenuItem.lua +++ b/sys/modules/opus/ui/components/TabBarMenuItem.lua @@ -3,7 +3,6 @@ local UI = require('opus.ui') local colors = _G.colors ---[[-- TabBarMenuItem --]]-- UI.TabBarMenuItem = class(UI.Button) UI.TabBarMenuItem.defaults = { UIElement = 'TabBarMenuItem', @@ -13,6 +12,9 @@ UI.TabBarMenuItem.defaults = { unselectedBackgroundColor = colors.lightGray, backgroundColor = colors.lightGray, } +UI.TabBarMenuItem.inherits = { + selectedBackgroundColor = 'selectedBackgroundColor', +} function UI.TabBarMenuItem:draw() if self.selected then self.backgroundColor = self.selectedBackgroundColor diff --git a/sys/modules/opus/ui/components/Tabs.lua b/sys/modules/opus/ui/components/Tabs.lua index c9c0075..2b0c824 100644 --- a/sys/modules/opus/ui/components/Tabs.lua +++ b/sys/modules/opus/ui/components/Tabs.lua @@ -3,6 +3,7 @@ local UI = require('opus.ui') local Util = require('opus.util') UI.Tabs = class(UI.Window) +UI.Tabs.docs = { } UI.Tabs.defaults = { UIElement = 'Tabs', } @@ -37,6 +38,8 @@ function UI.Tabs:add(children) end end +UI.Tabs.docs.selectTab = [[selectTab(TAB) +Make to the passed tab active.]] function UI.Tabs:selectTab(tab) local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) if menuItem then diff --git a/sys/modules/opus/ui/components/TextArea.lua b/sys/modules/opus/ui/components/TextArea.lua index ea7540f..2b8c342 100644 --- a/sys/modules/opus/ui/components/TextArea.lua +++ b/sys/modules/opus/ui/components/TextArea.lua @@ -1,7 +1,6 @@ local class = require('opus.class') local UI = require('opus.ui') ---[[-- TextArea --]]-- UI.TextArea = class(UI.Viewport) UI.TextArea.defaults = { UIElement = 'TextArea', diff --git a/sys/modules/opus/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua index 523208c..929cb3c 100644 --- a/sys/modules/opus/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -16,6 +16,7 @@ local function transform(directive) end UI.TextEntry = class(UI.Window) +UI.TextEntry.docs = { } UI.TextEntry.defaults = { UIElement = 'TextEntry', --value = '', @@ -92,6 +93,8 @@ function UI.TextEntry:draw() end end +UI.TextEntry.docs.reset = [[reset() +Clears the value and resets the cursor.]] function UI.TextEntry:reset() self.entry:reset() self.value = nil--'' diff --git a/sys/modules/opus/ui/components/Viewport.lua b/sys/modules/opus/ui/components/Viewport.lua index acb84cd..35cd0eb 100644 --- a/sys/modules/opus/ui/components/Viewport.lua +++ b/sys/modules/opus/ui/components/Viewport.lua @@ -3,7 +3,6 @@ local UI = require('opus.ui') local colors = _G.colors ---[[-- Viewport --]]-- UI.Viewport = class(UI.Window) UI.Viewport.defaults = { UIElement = 'Viewport',