From 25405f15c8d60bc9d6ae66ee580c6efb829719ae Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 12 Nov 2019 21:13:17 -0700 Subject: [PATCH] UI inspector --- sys/apps/inspect.lua | 154 ++++++++++++++++++ sys/modules/opus/ui/components/Button.lua | 20 +++ .../opus/ui/components/CheckboxGrid.lua | 54 ++++++ sys/modules/opus/ui/components/Tabs.lua | 16 ++ sys/modules/opus/ui/components/TextArea.lua | 6 + sys/modules/opus/ui/components/TextEntry.lua | 32 ++++ 6 files changed, 282 insertions(+) create mode 100644 sys/apps/inspect.lua create mode 100644 sys/modules/opus/ui/components/CheckboxGrid.lua diff --git a/sys/apps/inspect.lua b/sys/apps/inspect.lua new file mode 100644 index 0000000..1824fde --- /dev/null +++ b/sys/apps/inspect.lua @@ -0,0 +1,154 @@ +local Event = require('opus.event') +local UI = require('opus.ui') + +local colors = _G.colors +local multishell = _ENV.multishell + +local args = { ... } +local name = args[1] or error('Syntax: inspect COMPONENT') +local events = { } +local page + +local function isRelevant(el) + return page.testContainer == el or el.parent and isRelevant(el.parent) +end + +local emitter = UI.Window.emit +function UI.Window:emit(event) + if not event.recorded and isRelevant(self) then + event.recorded = true + local t = { } + for k,v in pairs(event) do + if k ~= 'type' and k ~= 'recorded' then + table.insert(t, k .. ':' .. (type(v) == 'table' and (v.UIElement and v.uid or 'tbl') or tostring(v))) + end + end + table.insert(events, 1, { type = event.type, value = table.concat(t, ' '), raw = event }) + while #events > 10 do + table.remove(events) + end + end + return emitter(self, event) +end + +page = UI.Page { + testContainer = UI.Window { + ey = 10, + }, + tabs = UI.Tabs { + y = 11, + properties = UI.Tab { + backgroundColor = colors.red, + tabTitle = 'Properties', + grid = UI.ScrollingGrid { + headerBackgroundColor = colors.red, + sortColumn = 'key', + columns = { + { heading = 'key', key = 'key' }, + { heading = 'value', key = 'value', } + }, + accelerators = { + grid_select = 'edit_property', + }, + }, + }, + methodsTab = UI.Tab { + backgroundColor = colors.red, + tabTitle = 'Methods', + grid = UI.ScrollingGrid { + headerBackgroundColor = colors.red, + sortColumn = 'key', + columns = { + { heading = 'key', key = 'key' }, + }, + }, + }, + events = UI.Tab { + backgroundColor = colors.red, + tabTitle = 'Events', + grid = UI.ScrollingGrid { + headerBackgroundColor = colors.red, + values = events, + autospace = true, + columns = { + { heading = 'type', key = 'type' }, + { heading = 'value', key = 'value', } + }, + } + } + }, + editor = UI.SlideOut { + y = -4, height = 4, + backgroundColor = colors.green, + titleBar = UI.TitleBar { + event = 'editor_cancel', + title = 'Enter value', + }, + entry = UI.TextEntry { + y = 3, x = 2, ex = 10, + accelerators = { + enter = 'editor_apply', + }, + }, + }, + eventHandler = function (self, event) + if event.type == 'focus_change' and isRelevant(event.focused) then + local t = { } + for k,v in pairs(event.focused) do + table.insert(t, { + key = k, + value = tostring(v), + }) + end + self.tabs.properties.grid:setValues(t) + self.tabs.properties.grid:update() + self.tabs.properties.grid:draw() + + t = { } + for k,v in pairs(getmetatable(event.focused)) do + if type(v) == 'function' then + table.insert(t, { + key = k, + }) + end + end + self.tabs.methodsTab.grid:setValues(t) + self.tabs.methodsTab.grid:update() + self.tabs.methodsTab.grid:draw() + + elseif event.type == 'grid_select' and event.element == self.tabs.events.grid then + event.selected.raw.recorded = nil + multishell.openTab({ + path = 'sys/apps/Lua.lua', + args = { event.selected.raw }, + focused = true, + }) + + elseif event.type == 'grid_select' and event.element == self.tabs.properties.grid then + self.editor.entry.value = event.selected.value + self.editor:show() + + elseif event.type == 'editor_cancel' then + self.editor:hide() + + elseif event.type == 'editor_apply' then + self.editor:hide() + end + + return UI.Page.eventHandler(self, event) + end +} + +Event.onInterval(1, function() + page.tabs.events.grid:update() + page.tabs.events.grid:draw() + page.tabs.events.grid:sync() +end) + +local component = UI[name]() +local testing = component.example() + +page.testContainer:add({ test = testing }) + +UI:setPage(page) +UI:pullEvents() diff --git a/sys/modules/opus/ui/components/Button.lua b/sys/modules/opus/ui/components/Button.lua index c6ea3bf..2442614 100644 --- a/sys/modules/opus/ui/components/Button.lua +++ b/sys/modules/opus/ui/components/Button.lua @@ -64,3 +64,23 @@ function UI.Button:eventHandler(event) end return false end + +function UI.Button.example() + return UI.Window { + button1 = UI.Button { + x = 2, y = 2, + text = 'Press', + }, + button2 = UI.Button { + x = 2, y = 4, + backgroundColor = colors.green, + event = 'custom_event', + }, + button3 = UI.Button { + x = 12, y = 2, + height = 5, + event = 'big_event', + text = 'large button' + } + } +end diff --git a/sys/modules/opus/ui/components/CheckboxGrid.lua b/sys/modules/opus/ui/components/CheckboxGrid.lua new file mode 100644 index 0000000..c57c098 --- /dev/null +++ b/sys/modules/opus/ui/components/CheckboxGrid.lua @@ -0,0 +1,54 @@ +local class = require('opus.class') +local UI = require('opus.ui') + +local function safeValue(v) + local t = type(v) + if t == 'string' or t == 'number' then + return v + end + return tostring(v) +end + +UI.CheckboxGrid = class(UI.Grid) +UI.CheckboxGrid.defaults = { + UIElement = 'CheckboxGrid', + checkedKey = 'checked', + accelerators = { + space = 'grid_toggle', + }, +} +function UI.CheckboxGrid:drawRow(sb, row, focused, bg, fg) + local ind = focused and self.focusIndicator or ' ' + + for _,col in pairs(self.columns) do + sb:write(ind .. safeValue(row[col.key] or ''), + col.cw + 1, + col.align, + col.backgroundColor or bg, + col.textColor or fg) + ind = ' ' + end +end + +function UI.CheckboxGrid:eventHandler(event) + if event.type == 'key_enter' and self.selected then + self.selected.checked = not self.selected.checked + self:draw() + self:emit({ type = 'grid_check', checked = self.selected, element = self }) + else + return UI.Grid.eventHandler(self, event) + end +end + +function UI.CheckboxGrid.example() + return UI.CheckboxGrid { + values = { + { checked = false, name = 'unchecked' }, + { checked = true, name = 'checked' }, + }, + columns = { + { heading = 'Checked', key = 'checked' }, + { heading = 'Data', key = 'name', } + }, + } +end diff --git a/sys/modules/opus/ui/components/Tabs.lua b/sys/modules/opus/ui/components/Tabs.lua index 46f87d1..a27bcbb 100644 --- a/sys/modules/opus/ui/components/Tabs.lua +++ b/sys/modules/opus/ui/components/Tabs.lua @@ -87,3 +87,19 @@ function UI.Tabs:eventHandler(event) tab:draw() end end + +function UI.Tabs.example() + return UI.Tabs { + [1] = UI.Tab { + tabTitle = 'tab1', + entry = UI.TextEntry { y = 3, shadowText = 'text' }, + }, + [2] = UI.Tab { + tabTitle = 'tab2', + button = UI.Button { y = 3 }, + }, + [3] = UI.Tab { + tabTitle = 'tab3', + } + } +end diff --git a/sys/modules/opus/ui/components/TextArea.lua b/sys/modules/opus/ui/components/TextArea.lua index 51b8972..ea7540f 100644 --- a/sys/modules/opus/ui/components/TextArea.lua +++ b/sys/modules/opus/ui/components/TextArea.lua @@ -34,3 +34,9 @@ function UI.TextArea:draw() end end end + +function UI.TextArea.example() + return UI.TextArea { + value = 'sample text\nabc' + } +end \ No newline at end of file diff --git a/sys/modules/opus/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua index dda3766..ea507c8 100644 --- a/sys/modules/opus/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -134,3 +134,35 @@ function UI.TextEntry:eventHandler(event) return false end + +function UI.TextEntry.example() + return UI.Window { + text = UI.TextEntry { + x = 2, y = 2, + width = 12, + limit = 36, + shadowText = 'normal', + }, + upper = UI.TextEntry { + x = 2, y = 3, + width = 12, + limit = 36, + shadowText = 'upper', + transform = 'uppercase', + }, + lower = UI.TextEntry { + x = 2, y = 4, + width = 12, + limit = 36, + shadowText = 'lower', + transform = 'lowercase', + }, + number = UI.TextEntry { + x = 2, y = 5, + width = 12, + limit = 36, + transform = 'number', + shadowText = 'number', + }, + } +end