diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index ffd0486..8bae671 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -81,7 +81,7 @@ function page:eventHandler(event) end elseif event.type == 'text_change' then - if #event.text == 0 then + if not event.text then self.grid.values = topics else self.grid.values = { } diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index 45cec04..2de6195 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -153,10 +153,11 @@ function page:eventHandler(event) self.tabs:selectTab(self.tabs[2]) elseif event.type == 'autocomplete' then - local sz = #self.prompt.value + local value = self.prompt.value or '' + local sz = #value local pos = self.prompt.entry.pos - self:setPrompt(autocomplete(sandboxEnv, self.prompt.value, self.prompt.entry.pos)) - self.prompt:setPosition(pos + #self.prompt.value - sz) + self:setPrompt(autocomplete(sandboxEnv, value, self.prompt.entry.pos)) + self.prompt:setPosition(pos + #value - sz) self.prompt:updateCursor() elseif event.type == 'device' then @@ -177,7 +178,7 @@ function page:eventHandler(event) history:reset() elseif event.type == 'command_enter' then - local s = tostring(self.prompt.value) + local s = tostring(self.prompt.value or '') if #s > 0 then self:executeStatement(s) diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 04b60f9..a25278f 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -120,7 +120,9 @@ local page = UI.Page { } function page.wizard.pages.label:validate() - os.setComputerLabel(self.label.value) + if self.label.value then + os.setComputerLabel(self.label.value) + end return true end diff --git a/sys/apps/inspect.lua b/sys/apps/inspect.lua index ce41738..ae991d6 100644 --- a/sys/apps/inspect.lua +++ b/sys/apps/inspect.lua @@ -6,11 +6,6 @@ local multishell = _ENV.multishell local name = ({ ... })[1] or error('Syntax: inspect COMPONENT') local events = { } local page -local component = UI[name] and UI[name]() or error('Invalid component') - -if not component.example then - error('No example present') -end local function isRelevant(el) return page.testContainer == el or el.parent and isRelevant(el.parent) @@ -18,8 +13,7 @@ end local emitter = UI.Window.emit function UI.Window:emit(event) - if not event.recorded and isRelevant(self) then - event.recorded = true + if not event._recorded and isRelevant(self) then local t = { } for k,v in pairs(event) do if k ~= 'type' and k ~= 'recorded' then @@ -35,9 +29,16 @@ function UI.Window:emit(event) page.tabs.events.grid:draw() end end + event._recorded = true return emitter(self, event) end +-- do not load component until emit hook is in place +local component = UI[name] and UI[name]() or error('Invalid component') +if not component.example then + error('No example present') +end + page = UI.Page { testContainer = UI.Window { ey = 10, @@ -122,7 +123,7 @@ page = UI.Page { self.tabs.methodsTab.grid:draw() elseif event.type == 'grid_select' and event.element == self.tabs.events.grid then - event.selected.raw.recorded = nil + event.selected.raw._recorded = nil multishell.openTab({ path = 'sys/apps/Lua.lua', args = { event.selected.raw }, diff --git a/sys/apps/system/label.lua b/sys/apps/system/label.lua index e4a73f2..0dc77a7 100644 --- a/sys/apps/system/label.lua +++ b/sys/apps/system/label.lua @@ -39,7 +39,7 @@ local labelTab = UI.Tab { } function labelTab:eventHandler(event) - if event.type == 'update_label' then + if event.type == 'update_label' and self.label.value then os.setComputerLabel(self.label.value) self:emit({ type = 'success_message', message = 'Label updated' }) return true diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index bf30f7e..33249dd 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -59,7 +59,7 @@ function tab:save() end function tab:eventHandler(event) - if event.type == 'update_path' then + if event.type == 'update_path' and self.entry.value then table.insert(self.grid.values, { value = self.entry.value, }) diff --git a/sys/modules/opus/entry.lua b/sys/modules/opus/entry.lua index 693fe87..46e4eeb 100644 --- a/sys/modules/opus/entry.lua +++ b/sys/modules/opus/entry.lua @@ -2,39 +2,48 @@ local class = require('opus.class') local os = _G.os +-- convert value to a string (supporting nils or numbers in value) +local function _val(a) + return a and tostring(a) or '' +end + local Entry = class() function Entry:init(args) self.pos = 0 self.scroll = 0 - self.value = '' + self.value = args.value self.width = args.width or 256 self.limit = args.limit or 1024 self.mark = { } self.offset = args.offset or 1 + self.transform = args.transform or function(a) return a end end function Entry:reset() self.pos = 0 self.scroll = 0 - self.value = '' + self.value = nil self.mark = { } end function Entry:nextWord() - return select(2, self.value:find("[%s%p]?%w[%s%p]", self.pos + 1)) or #self.value + local value = _val(self.value) + return select(2, value:find("[%s%p]?%w[%s%p]", self.pos + 1)) or #value end function Entry:prevWord() - local x = #self.value - (self.pos - 1) - local _, n = self.value:reverse():find("[%s%p]?%w[%s%p]", x) - return n and #self.value - n + 1 or 0 + local value = _val(self.value) + local x = #value - (self.pos - 1) + local _, n = value:reverse():find("[%s%p]?%w[%s%p]", x) + return n and #value - n + 1 or 0 end function Entry:updateScroll() local ps = self.scroll - if self.pos > #self.value then - self.pos = #self.value + local value = _val(self.value) + if self.pos > #value then + self.pos = #value self.scroll = 0 -- ?? end if self.pos - self.scroll > self.width then @@ -48,21 +57,25 @@ function Entry:updateScroll() end function Entry:copyText(cx, ex) - return self.value:sub(cx + 1, ex) + -- this should be transformed (ie. if number) + return _val(self.value):sub(cx + 1, ex) end function Entry:insertText(x, text) - if #self.value + #text > self.limit then - text = text:sub(1, self.limit-#self.value) + text = tostring(self.transform(text)) or '' + local value = _val(self.value) + if #value + #text > self.limit then + text = text:sub(1, self.limit-#value) end - self.value = self.value:sub(1, x) .. text .. self.value:sub(x + 1) + self.value = self.transform(value:sub(1, x) .. text .. value:sub(x + 1)) self.pos = self.pos + #text end function Entry:deleteText(sx, ex) - local front = self.value:sub(1, sx) - local back = self.value:sub(ex + 1, #self.value) - self.value = front .. back + local value = _val(self.value) + local front = value:sub(1, sx) + local back = value:sub(ex + 1, #value) + self.value = self.transform(front .. back) self.pos = sx end @@ -74,7 +87,7 @@ function Entry:moveLeft() end function Entry:moveRight() - if self.pos < #self.value then + if self.pos < #_val(self.value) then self.pos = self.pos + 1 return true end @@ -88,14 +101,14 @@ function Entry:moveHome() end function Entry:moveEnd() - if self.pos ~= #self.value then - self.pos = #self.value + if self.pos ~= #_val(self.value) then + self.pos = #_val(self.value) return true end end function Entry:moveTo(ie) - self.pos = math.max(0, math.min(ie.x + self.scroll - self.offset, #self.value)) + self.pos = math.max(0, math.min(ie.x + self.scroll - self.offset, #_val(self.value))) end function Entry:backspace() @@ -107,7 +120,7 @@ function Entry:backspace() end function Entry:moveWordRight() - if self.pos < #self.value then + if self.pos < #_val(self.value) then self.pos = self:nextWord(self.value, self.pos + 1) return true end @@ -123,7 +136,7 @@ end function Entry:delete() if self.mark.active then self:deleteText(self.mark.x, self.mark.ex) - elseif self.pos < #self.value then + elseif self.pos < #_val(self.value) then self:deleteText(self.pos, self.pos + 1) end end @@ -137,15 +150,16 @@ function Entry:cutFromStart() end function Entry:cutToEnd() - if self.pos < #self.value then - local text = self:copyText(self.pos, #self.value) - self:deleteText(self.pos, #self.value) + local value = _val(self.value) + if self.pos < #value then + local text = self:copyText(self.pos, #value) + self:deleteText(self.pos, #value) os.queueEvent('clipboard_copy', text) end end function Entry:cutNextWord() - if self.pos < #self.value then + if self.pos < #_val(self.value) then local ex = self:nextWord(self.value, self.pos) local text = self:copyText(self.pos, ex) self:deleteText(self.pos, ex) @@ -170,7 +184,7 @@ function Entry:insertChar(ie) end function Entry:copy() - if #self.value > 0 then + if #_val(self.value) > 0 then self.mark.continue = true if self.mark.active then self:copyMarked() @@ -202,7 +216,7 @@ function Entry:paste(ie) end function Entry:clearLine() - if #self.value > 0 then + if #_val(self.value) > 0 then self:reset() end end @@ -233,10 +247,13 @@ function Entry:unmark() end function Entry:markAnchor(ie) + local wasMarking = self.mark.active self:unmark() self:moveTo(ie) self:markBegin() self:markFinish() + + self.textChanged = wasMarking end function Entry:markLeft() @@ -257,7 +274,7 @@ function Entry:markWord(ie) local index = 1 self:moveTo(ie) while true do - local s, e = self.value:find('%w+', index) + local s, e = _val(self.value):find('%w+', index) if not s or s - 1 > self.pos then break end @@ -288,12 +305,12 @@ function Entry:markPrevWord() end function Entry:markAll() - if #self.value > 0 then + if #_val(self.value) > 0 then self.mark.anchor = { x = 1 } self.mark.active = true self.mark.continue = true self.mark.x = 0 - self.mark.ex = #self.value + self.mark.ex = #_val(self.value) self.textChanged = true end end @@ -373,6 +390,10 @@ function Entry:process(ie) action(self, ie) + if not self.value or #_val(self.value) == 0 then + self.value = nil + end +_syslog(tostring(line) .. ' ' .. tostring(self.value) .. ' ' .. tostring(self.textChanged)) self.textChanged = self.textChanged or self.value ~= line self.posChanged = pos ~= self.pos self:updateScroll() diff --git a/sys/modules/opus/ui/components/Form.lua b/sys/modules/opus/ui/components/Form.lua index ed9ae0d..da312d9 100644 --- a/sys/modules/opus/ui/components/Form.lua +++ b/sys/modules/opus/ui/components/Form.lua @@ -32,7 +32,7 @@ function UI.Form:setValues(values) if child.setValue then child:setValue(self.values[child.formKey]) else - child.value = self.values[child.formKey] or '' + child.value = self.values[child.formKey] end end end @@ -56,7 +56,7 @@ function UI.Form:createForm() for _, child in pairs(self) do if type(child) == 'table' and child.UIElement then if child.formKey then - child.value = self.values[child.formKey] or '' + child.value = self.values[child.formKey] end if child.formLabel then child.x = self.labelWidth + self.margin - 1 @@ -99,14 +99,6 @@ function UI.Form:validateField(field) return false, 'Field is required' end end - if field.validate == 'numeric' then - field.value = field.value or '' - if #tostring(field.value) > 0 then - if not tonumber(field.value) then - return false, 'Invalid number' - end - end - end return true end @@ -124,11 +116,7 @@ function UI.Form:save() end for _,child in pairs(self.children) do if child.formKey then - if child.validate == 'numeric' then - self.values[child.formKey] = tonumber(child.value) - else - self.values[child.formKey] = child.value - end + self.values[child.formKey] = child.value end end diff --git a/sys/modules/opus/ui/components/Grid.lua b/sys/modules/opus/ui/components/Grid.lua index bcdab81..e1edfe8 100644 --- a/sys/modules/opus/ui/components/Grid.lua +++ b/sys/modules/opus/ui/components/Grid.lua @@ -493,3 +493,43 @@ function UI.Grid:eventHandler(event) end return true end + +function UI.Grid.example() + local values = { + { key = 'key1', value = 'value1' }, + { key = 'key2', value = 'value2' }, + { key = 'key3', value = 'value3-longer value text' }, + { key = 'key4', value = 'value4' }, + { key = 'key5', value = 'value5' }, + } + return UI.Window { + regular = UI.Grid { + ex = '48%', ey = 4, + values = values, + sortColumn = 'key', + inverseSort = true, + columns = { + { heading = 'key', key = 'key' }, + { heading = 'value', key = 'value' }, + }, + }, + noheader = UI.Grid { + ex = '48%', y = 6, ey = -2, + disableHeader = true, + values = values, + columns = { + { heading = 'key', key = 'key', width = 6, }, + { heading = 'value', key = 'value', textColor = colors.yellow }, + }, + }, + autospace = UI.Grid { + x = '52%', ey = 4, + autospace = true, + values = values, + columns = { + { heading = 'key', key = 'key' }, + { heading = 'value', key = 'value' }, + }, + }, + } +end diff --git a/sys/modules/opus/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua index ea507c8..1a3f604 100644 --- a/sys/modules/opus/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -5,8 +5,15 @@ local Util = require('opus.util') local colors = _G.colors local _rep = string.rep -local _lower = string.lower -local _upper = string.upper + +local function transform(directive) + local transforms = { + lowercase = string.lower, + uppercase = string.upper, + number = tonumber, + } + return transforms[directive] +end UI.TextEntry = class(UI.Window) UI.TextEntry.defaults = { @@ -25,7 +32,7 @@ UI.TextEntry.defaults = { } } function UI.TextEntry:postInit() - self.entry = entry({ limit = self.limit, offset = 2 }) + self.entry = entry({ limit = self.limit, offset = 2, transform = transform(self.transform) }) end function UI.TextEntry:layout() @@ -36,13 +43,13 @@ end function UI.TextEntry:setValue(value) self.value = value --or '' self.entry:unmark() - self.entry.value = tostring(value) + self.entry.value = value --tostring(value or '') self.entry:updateScroll() end function UI.TextEntry:setPosition(pos) self.entry.pos = pos - self.entry.value = tostring(self.value or '') + self.entry.value = self.value --tostring(self.value or '') -- WHY HERE ? self.entry:updateScroll() end @@ -105,27 +112,15 @@ function UI.TextEntry:focus() end end -function UI.TextEntry:_transform(text) - if self.transform == 'lowercase' then - return _lower(text) - elseif self.transform == 'uppercase' then - return _upper(text) - elseif self.transform == 'number' then - return tonumber(text) --or 0 - end - return text -end - function UI.TextEntry:eventHandler(event) - local text = self.value --or '' - self.entry.value = tostring(text or '') + local text = self.value + self.entry.value = text if event.ie and self.entry:process(event.ie) then if self.entry.textChanged then - self.value = self:_transform(self.entry.value) +--_syslog(tostring(self.entry.value) .. ' ' .. tostring(self.value)) + self.value = self.entry.value self:draw() - if text ~= self.value then - self:emit({ type = 'text_change', text = self.value, element = self }) - end + self:emit({ type = 'text_change', text = self.value, element = self }) elseif self.entry.posChanged then self:updateCursor() end