mirror of
https://github.com/kepler155c/opus
synced 2025-05-05 17:04:13 +00:00
UI improvements
This commit is contained in:
parent
af981dd1f8
commit
98ec840db1
269
sys/apis/ui.lua
269
sys/apis/ui.lua
@ -6,6 +6,8 @@ local Util = require('util')
|
|||||||
|
|
||||||
local _rep = string.rep
|
local _rep = string.rep
|
||||||
local _sub = string.sub
|
local _sub = string.sub
|
||||||
|
local colors = _G.colors
|
||||||
|
local keys = _G.keys
|
||||||
|
|
||||||
local function safeValue(v)
|
local function safeValue(v)
|
||||||
local t = type(v)
|
local t = type(v)
|
||||||
@ -147,7 +149,8 @@ function Manager:init()
|
|||||||
singleThread('char', function(ch)
|
singleThread('char', function(ch)
|
||||||
control = false
|
control = false
|
||||||
if self.currentPage then
|
if self.currentPage then
|
||||||
self:inputEvent(self.currentPage.focused, { type = 'key', key = ch })
|
local target = self.currentPage.focused or self.currentPage
|
||||||
|
self:inputEvent(target, { type = 'key', key = ch })
|
||||||
self.currentPage:sync()
|
self.currentPage:sync()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@ -180,8 +183,9 @@ function Manager:init()
|
|||||||
-- as char events
|
-- as char events
|
||||||
if ch and #ch > 1 and (code < 2 or code > 11) then
|
if ch and #ch > 1 and (code < 2 or code > 11) then
|
||||||
if self.currentPage then
|
if self.currentPage then
|
||||||
self:inputEvent(self.currentPage.focused,
|
local target = self.currentPage.focused or self.currentPage
|
||||||
{ type = 'key', key = ch, element = self.currentPage.focused })
|
self:inputEvent(target,
|
||||||
|
{ type = 'key', key = ch, element = target })
|
||||||
self.currentPage:sync()
|
self.currentPage:sync()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -264,12 +268,14 @@ end
|
|||||||
function Manager:inputEvent(parent, event)
|
function Manager:inputEvent(parent, event)
|
||||||
|
|
||||||
while parent do
|
while parent do
|
||||||
|
if parent.accelerators then
|
||||||
local acc = parent.accelerators[event.key]
|
local acc = parent.accelerators[event.key]
|
||||||
if acc then
|
if acc then
|
||||||
if parent:emit({ type = acc, element = parent }) then
|
if parent:emit({ type = acc, element = parent }) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
if parent.eventHandler then
|
if parent.eventHandler then
|
||||||
if parent:eventHandler(event) then
|
if parent:eventHandler(event) then
|
||||||
return true
|
return true
|
||||||
@ -515,7 +521,7 @@ UI.Window.defaults = {
|
|||||||
offy = 0,
|
offy = 0,
|
||||||
cursorX = 1,
|
cursorX = 1,
|
||||||
cursorY = 1,
|
cursorY = 1,
|
||||||
accelerators = { },
|
-- accelerators = { },
|
||||||
}
|
}
|
||||||
function UI.Window:init(args)
|
function UI.Window:init(args)
|
||||||
local defaults = UI:getDefaults(UI.Window, args)
|
local defaults = UI:getDefaults(UI.Window, args)
|
||||||
@ -727,8 +733,10 @@ function UI.Window:centeredWrite(y, text, bg, fg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Window:print(text, bg, fg, indent)
|
function UI.Window:print(text, bg, fg)
|
||||||
indent = indent or 1
|
local marginLeft = self.marginLeft or 0
|
||||||
|
local marginRight = self.marginRight or 0
|
||||||
|
local width = self.width - marginLeft - marginRight
|
||||||
|
|
||||||
local function nextWord(line, cx)
|
local function nextWord(line, cx)
|
||||||
local result = { line:find("(%w+)", cx) }
|
local result = { line:find("(%w+)", cx) }
|
||||||
@ -749,7 +757,7 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
local pos = 1
|
local pos = 1
|
||||||
local t = { }
|
local t = { }
|
||||||
while true do
|
while true do
|
||||||
local s = f:find('\027', pos)
|
local s = string.find(f, '\027', pos, true)
|
||||||
if not s then
|
if not s then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@ -773,7 +781,7 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
table.insert(t, e)
|
table.insert(t, e)
|
||||||
pos = s + #seq + 3
|
pos = s + #seq + 3
|
||||||
end
|
end
|
||||||
if pos < #f then
|
if pos <= #f then
|
||||||
table.insert(t, _sub(f, pos))
|
table.insert(t, _sub(f, pos))
|
||||||
end
|
end
|
||||||
return t
|
return t
|
||||||
@ -794,8 +802,8 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
local w = word
|
local w = word
|
||||||
if self.cursorX + #word > self.width then
|
if self.cursorX + #word > width then
|
||||||
self.cursorX = indent
|
self.cursorX = marginLeft + 1
|
||||||
self.cursorY = self.cursorY + 1
|
self.cursorY = self.cursorY + 1
|
||||||
w = word:gsub(' ', '')
|
w = word:gsub(' ', '')
|
||||||
end
|
end
|
||||||
@ -806,7 +814,7 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if lines[k + 1] then
|
if lines[k + 1] then
|
||||||
self.cursorX = indent
|
self.cursorX = marginLeft + 1
|
||||||
self.cursorY = self.cursorY + 1
|
self.cursorY = self.cursorY + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1246,6 +1254,7 @@ UI.Grid.defaults = {
|
|||||||
index = 1,
|
index = 1,
|
||||||
inverseSort = false,
|
inverseSort = false,
|
||||||
disableHeader = false,
|
disableHeader = false,
|
||||||
|
marginRight = 0,
|
||||||
textColor = colors.white,
|
textColor = colors.white,
|
||||||
textSelectedColor = colors.white,
|
textSelectedColor = colors.white,
|
||||||
backgroundColor = colors.black,
|
backgroundColor = colors.black,
|
||||||
@ -1311,7 +1320,7 @@ end
|
|||||||
function UI.Grid:adjustWidth()
|
function UI.Grid:adjustWidth()
|
||||||
|
|
||||||
local t = { } -- cols without width
|
local t = { } -- cols without width
|
||||||
local w = self.width - #self.columns - 1 -- width remaing
|
local w = self.width - #self.columns - 1 - self.marginRight -- width remaing
|
||||||
|
|
||||||
for _,c in pairs(self.columns) do
|
for _,c in pairs(self.columns) do
|
||||||
if c.width then
|
if c.width then
|
||||||
@ -1668,109 +1677,59 @@ end
|
|||||||
UI.ScrollingGrid = class(UI.Grid)
|
UI.ScrollingGrid = class(UI.Grid)
|
||||||
UI.ScrollingGrid.defaults = {
|
UI.ScrollingGrid.defaults = {
|
||||||
UIElement = 'ScrollingGrid',
|
UIElement = 'ScrollingGrid',
|
||||||
scrollOffset = 1,
|
scrollOffset = 0,
|
||||||
lineChar = '|',
|
marginRight = 1,
|
||||||
sliderChar = '#',
|
|
||||||
upArrowChar = '^',
|
|
||||||
downArrowChar = 'v',
|
|
||||||
scrollbarColor = colors.lightGray,
|
|
||||||
}
|
}
|
||||||
function UI.ScrollingGrid:init(args)
|
function UI.ScrollingGrid:init(args)
|
||||||
UI.Grid.init(self, UI:getDefaults(UI.ScrollingGrid, args))
|
UI.Grid.init(self, UI:getDefaults(UI.ScrollingGrid, args))
|
||||||
|
self.scrollBar = UI.ScrollBar()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ScrollingGrid:drawRows()
|
function UI.ScrollingGrid:drawRows()
|
||||||
UI.Grid.drawRows(self)
|
UI.Grid.drawRows(self)
|
||||||
self:drawScrollbar()
|
self.scrollBar:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ScrollingGrid:drawScrollbar()
|
function UI.ScrollingGrid:getViewArea()
|
||||||
local ts = Util.size(self.values)
|
local y = 1
|
||||||
if ts > self.pageSize then
|
if not self.disableHeader then
|
||||||
local maxScroll = ts - self.pageSize
|
y = 2
|
||||||
local percent = (self.scrollOffset - 1) / maxScroll
|
|
||||||
local sliderSize = self.pageSize / ts * (self.pageSize - 2)
|
|
||||||
local row = 2
|
|
||||||
|
|
||||||
if self.disableHeader then
|
|
||||||
row = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local x = self.width
|
|
||||||
for i = 1, self.pageSize - 2 do
|
|
||||||
self:write(x, row + i, self.lineChar, nil, self.scrollbarColor)
|
|
||||||
end
|
|
||||||
|
|
||||||
local y = Util.round((self.pageSize - 2 - sliderSize) * percent)
|
|
||||||
for i = 1, Util.round(sliderSize) do
|
|
||||||
self:write(x, row + y + i, self.sliderChar, nil, self.scrollbarColor)
|
|
||||||
end
|
|
||||||
|
|
||||||
local color = self.scrollbarColor
|
|
||||||
if self.scrollOffset > 1 then
|
|
||||||
color = colors.white
|
|
||||||
end
|
|
||||||
self:write(x, 2, self.upArrowChar, nil, color)
|
|
||||||
|
|
||||||
color = self.scrollbarColor
|
|
||||||
if self.scrollOffset + self.pageSize - 1 < Util.size(self.values) then
|
|
||||||
color = colors.white
|
|
||||||
end
|
|
||||||
self:write(x, self.pageSize + 1, self.downArrowChar, nil, color)
|
|
||||||
end
|
end
|
||||||
|
return {
|
||||||
|
static = true, -- the container doesn't scroll
|
||||||
|
y = y, -- scrollbar Y
|
||||||
|
height = self.pageSize, -- viewable height
|
||||||
|
totalHeight = Util.size(self.values), -- total height
|
||||||
|
offsetY = self.scrollOffset, -- scroll offset
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ScrollingGrid:getStartRow()
|
function UI.ScrollingGrid:getStartRow()
|
||||||
local ts = Util.size(self.values)
|
local ts = Util.size(self.values)
|
||||||
if ts < self.pageSize then
|
if ts < self.pageSize then
|
||||||
self.scrollOffset = 1
|
self.scrollOffset = 0
|
||||||
end
|
end
|
||||||
return self.scrollOffset
|
return self.scrollOffset + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ScrollingGrid:setIndex(index)
|
function UI.ScrollingGrid:setIndex(index)
|
||||||
if index < self.scrollOffset then
|
if index < self.scrollOffset + 1 then
|
||||||
self.scrollOffset = index
|
self.scrollOffset = index - 1
|
||||||
elseif index - (self.scrollOffset - 1) > self.pageSize then
|
elseif index - self.scrollOffset > self.pageSize then
|
||||||
self.scrollOffset = index - self.pageSize + 1
|
self.scrollOffset = index - self.pageSize
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.scrollOffset < 1 then
|
if self.scrollOffset < 0 then
|
||||||
self.scrollOffset = 1
|
self.scrollOffset = 0
|
||||||
else
|
else
|
||||||
local ts = Util.size(self.values)
|
local ts = Util.size(self.values)
|
||||||
if self.pageSize + self.scrollOffset > ts then
|
if self.pageSize + self.scrollOffset + 1 > ts then
|
||||||
self.scrollOffset = math.max(1, ts - self.pageSize + 1)
|
self.scrollOffset = math.max(0, ts - self.pageSize)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
UI.Grid.setIndex(self, index)
|
UI.Grid.setIndex(self, index)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ScrollingGrid:eventHandler(event)
|
|
||||||
|
|
||||||
if event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then
|
|
||||||
if event.x == self.width then
|
|
||||||
local ts = Util.size(self.values)
|
|
||||||
if ts > self.pageSize then
|
|
||||||
local row = 2
|
|
||||||
if self.disableHeader then
|
|
||||||
row = 1
|
|
||||||
end
|
|
||||||
if event.y == row then
|
|
||||||
self:setIndex(self.scrollOffset - 1)
|
|
||||||
elseif event.y == self.height then
|
|
||||||
self:setIndex(self.scrollOffset + self.pageSize)
|
|
||||||
-- else
|
|
||||||
-- ... percentage ...
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return UI.Grid.eventHandler(self, event)
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[-- Menu --]]--
|
--[[-- Menu --]]--
|
||||||
UI.Menu = class(UI.Grid)
|
UI.Menu = class(UI.Grid)
|
||||||
UI.Menu.defaults = {
|
UI.Menu.defaults = {
|
||||||
@ -1832,10 +1791,10 @@ function UI.Menu:eventHandler(event)
|
|||||||
return UI.Grid.eventHandler(self, event)
|
return UI.Grid.eventHandler(self, event)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- ViewportWindow --]]--
|
--[[-- Viewport --]]--
|
||||||
UI.ViewportWindow = class(UI.Window)
|
UI.Viewport = class(UI.Window)
|
||||||
UI.ViewportWindow.defaults = {
|
UI.Viewport.defaults = {
|
||||||
UIElement = 'ViewportWindow',
|
UIElement = 'Viewport',
|
||||||
backgroundColor = colors.cyan,
|
backgroundColor = colors.cyan,
|
||||||
accelerators = {
|
accelerators = {
|
||||||
down = 'scroll_down',
|
down = 'scroll_down',
|
||||||
@ -1848,31 +1807,42 @@ UI.ViewportWindow.defaults = {
|
|||||||
[ 'control-f' ] = 'scroll_pageDown',
|
[ 'control-f' ] = 'scroll_pageDown',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
function UI.ViewportWindow:init(args)
|
function UI.Viewport:init(args)
|
||||||
local defaults = UI:getDefaults(UI.ViewportWindow, args)
|
local defaults = UI:getDefaults(UI.Viewport, args)
|
||||||
UI.Window.init(self, defaults)
|
UI.Window.init(self, defaults)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ViewportWindow:setScrollPosition(offset)
|
function UI.Viewport:setScrollPosition(offset)
|
||||||
local oldOffset = self.offy
|
local oldOffset = self.offy
|
||||||
self.offy = math.max(offset, 0)
|
self.offy = math.max(offset, 0)
|
||||||
local max = self.ymax or self.height
|
local max = self.ymax or self.height
|
||||||
if self.children then
|
if self.children then
|
||||||
for _, child in ipairs(self.children) do
|
for _, child in ipairs(self.children) do
|
||||||
|
if child ~= self.scrollBar then -- hack !
|
||||||
max = math.max(child.y + child.height - 1, max)
|
max = math.max(child.y + child.height - 1, max)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
self.offy = math.min(self.offy, math.max(max, self.height) - self.height)
|
self.offy = math.min(self.offy, math.max(max, self.height) - self.height)
|
||||||
if self.offy ~= oldOffset then
|
if self.offy ~= oldOffset then
|
||||||
self:draw()
|
self:draw()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ViewportWindow:reset()
|
function UI.Viewport:reset()
|
||||||
self.offy = 0
|
self.offy = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.ViewportWindow:eventHandler(event)
|
function UI.Viewport:getViewArea()
|
||||||
|
return {
|
||||||
|
y = (self.offy or 0) + 1,
|
||||||
|
height = self.height,
|
||||||
|
totalHeight = self.ymax,
|
||||||
|
offsetY = self.offy or 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function UI.Viewport:eventHandler(event)
|
||||||
|
|
||||||
if event.type == 'scroll_down' then
|
if event.type == 'scroll_down' then
|
||||||
self:setScrollPosition(self.offy + 1)
|
self:setScrollPosition(self.offy + 1)
|
||||||
@ -2042,8 +2012,7 @@ UI.MenuItem.defaults = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UI.MenuItem:init(args)
|
function UI.MenuItem:init(args)
|
||||||
local defaults = UI:getDefaults(UI.MenuItem, args)
|
UI.Button.init(self, UI:getDefaults(UI.MenuItem, args))
|
||||||
UI.Button.init(self, defaults)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- MenuBar --]]--
|
--[[-- MenuBar --]]--
|
||||||
@ -2144,8 +2113,7 @@ UI.DropMenuItem.defaults = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UI.DropMenuItem:init(args)
|
function UI.DropMenuItem:init(args)
|
||||||
local defaults = UI:getDefaults(UI.DropMenuItem, args)
|
UI.Button.init(self, UI:getDefaults(UI.DropMenuItem, args))
|
||||||
UI.Button.init(self, defaults)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- DropMenu --]]--
|
--[[-- DropMenu --]]--
|
||||||
@ -2466,9 +2434,9 @@ UI.Throttle.defaults = {
|
|||||||
ctr = 0,
|
ctr = 0,
|
||||||
image = {
|
image = {
|
||||||
' //) (O )~@ &~&-( ?Q ',
|
' //) (O )~@ &~&-( ?Q ',
|
||||||
' //) (O )- @ \-( ?) && ',
|
' //) (O )- @ \\-( ?) && ',
|
||||||
' //) (O ), @ \-(?) && ',
|
' //) (O ), @ \\-(?) && ',
|
||||||
' //) (O ). @ \-d ) (@ '
|
' //) (O ). @ \\-d ) (@ '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2949,22 +2917,100 @@ function UI.Text:setParent()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UI.Text:draw()
|
function UI.Text:draw()
|
||||||
local value = self.value or ''
|
self:write(1, 1, Util.widthify(self.value or '', self.width), self.backgroundColor)
|
||||||
self:write(1, 1, Util.widthify(value, self.width), self.backgroundColor)
|
end
|
||||||
|
|
||||||
|
--[[-- ScrollBar --]]--
|
||||||
|
UI.ScrollBar = class(UI.Window)
|
||||||
|
UI.ScrollBar.defaults = {
|
||||||
|
UIElement = 'ScrollBar',
|
||||||
|
lineChar = '|',
|
||||||
|
sliderChar = '#',
|
||||||
|
upArrowChar = '^',
|
||||||
|
downArrowChar = 'v',
|
||||||
|
scrollbarColor = colors.lightGray,
|
||||||
|
value = '',
|
||||||
|
width = 1,
|
||||||
|
x = -1,
|
||||||
|
ey = -1,
|
||||||
|
}
|
||||||
|
function UI.ScrollBar:init(args)
|
||||||
|
UI.Window.init(self, UI:getDefaults(UI.ScrollBar, args))
|
||||||
|
end
|
||||||
|
|
||||||
|
function UI.ScrollBar:draw()
|
||||||
|
local parent = self.parent
|
||||||
|
local view = parent:getViewArea()
|
||||||
|
|
||||||
|
if view.totalHeight > view.height then
|
||||||
|
local maxScroll = view.totalHeight - view.height
|
||||||
|
local percent = view.offsetY / maxScroll
|
||||||
|
local sliderSize = math.max(1, Util.round(view.height / view.totalHeight * (view.height - 2)))
|
||||||
|
local x = self.width
|
||||||
|
|
||||||
|
local row = view.y
|
||||||
|
if not view.static then -- does the container scroll ?
|
||||||
|
self.y = row -- if so, move the scrollbar onscreen
|
||||||
|
row = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, view.height - 2 do
|
||||||
|
self:write(x, row + i, self.lineChar, nil, self.scrollbarColor)
|
||||||
|
end
|
||||||
|
|
||||||
|
local y = Util.round((view.height - 2 - sliderSize) * percent)
|
||||||
|
for i = 1, sliderSize do
|
||||||
|
self:write(x, row + y + i, self.sliderChar, nil, self.scrollbarColor)
|
||||||
|
end
|
||||||
|
|
||||||
|
local color = self.scrollbarColor
|
||||||
|
if view.offsetY > 0 then
|
||||||
|
color = colors.white
|
||||||
|
end
|
||||||
|
self:write(x, row, self.upArrowChar, nil, color)
|
||||||
|
|
||||||
|
color = self.scrollbarColor
|
||||||
|
if view.offsetY + view.height < view.totalHeight then
|
||||||
|
color = colors.white
|
||||||
|
end
|
||||||
|
self:write(x, row + view.height - 1, self.downArrowChar, nil, color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function UI.ScrollBar:eventHandler(event)
|
||||||
|
|
||||||
|
if event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then
|
||||||
|
if event.x == 1 then
|
||||||
|
local view = self.parent:getViewArea()
|
||||||
|
if view.totalHeight > view.height then
|
||||||
|
if event.y == view.y then
|
||||||
|
self:emit({ type = 'scroll_up'})
|
||||||
|
elseif event.y == self.height then
|
||||||
|
self:emit({ type = 'scroll_down'})
|
||||||
|
-- else
|
||||||
|
-- ... percentage ...
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- TextArea --]]--
|
--[[-- TextArea --]]--
|
||||||
UI.TextArea = class(UI.Window)
|
UI.TextArea = class(UI.Viewport)
|
||||||
UI.TextArea.defaults = {
|
UI.TextArea.defaults = {
|
||||||
UIElement = 'TextArea',
|
UIElement = 'TextArea',
|
||||||
|
marginRight = 2,
|
||||||
value = '',
|
value = '',
|
||||||
}
|
}
|
||||||
function UI.TextArea:init(args)
|
function UI.TextArea:init(args)
|
||||||
local defaults = UI:getDefaults(UI.TextArea, args)
|
UI.Viewport.init(self, UI:getDefaults(UI.TextArea, args))
|
||||||
UI.Window.init(self, defaults)
|
self.scrollBar = UI.ScrollBar()
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.TextArea:setText(text)
|
function UI.TextArea:setText(text)
|
||||||
|
self.offy = 0
|
||||||
|
self.ymax = nil
|
||||||
self.value = text
|
self.value = text
|
||||||
self:draw()
|
self:draw()
|
||||||
end
|
end
|
||||||
@ -2973,6 +3019,13 @@ function UI.TextArea:draw()
|
|||||||
self:clear()
|
self:clear()
|
||||||
self:setCursorPos(1, 1)
|
self:setCursorPos(1, 1)
|
||||||
self:print(self.value)
|
self:print(self.value)
|
||||||
|
self.ymax = self.cursorY + 1
|
||||||
|
|
||||||
|
for _,child in pairs(self.children) do
|
||||||
|
if child.enabled then
|
||||||
|
child:draw()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- Form --]]--
|
--[[-- Form --]]--
|
||||||
|
@ -5,6 +5,7 @@ local Util = require('util')
|
|||||||
local _rep = string.rep
|
local _rep = string.rep
|
||||||
local _sub = string.sub
|
local _sub = string.sub
|
||||||
local _gsub = string.gsub
|
local _gsub = string.gsub
|
||||||
|
local colors = _G.colors
|
||||||
|
|
||||||
local Canvas = class()
|
local Canvas = class()
|
||||||
|
|
||||||
@ -251,7 +252,7 @@ function Canvas:dirty()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Canvas:clean()
|
function Canvas:clean()
|
||||||
for y, line in pairs(self.lines) do
|
for _, line in pairs(self.lines) do
|
||||||
line.dirty = false
|
line.dirty = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -314,13 +315,13 @@ function Canvas:applyPalette(palette)
|
|||||||
self.palette = palette
|
self.palette = palette
|
||||||
end
|
end
|
||||||
|
|
||||||
function Canvas.convertWindow(win, parent, x, y)
|
function Canvas.convertWindow(win, parent, wx, wy)
|
||||||
|
|
||||||
local w, h = win.getSize()
|
local w, h = win.getSize()
|
||||||
|
|
||||||
win.canvas = Canvas({
|
win.canvas = Canvas({
|
||||||
x = x,
|
x = wx,
|
||||||
y = y,
|
y = wy,
|
||||||
width = w,
|
width = w,
|
||||||
height = h,
|
height = h,
|
||||||
isColor = win.isColor(),
|
isColor = win.isColor(),
|
||||||
@ -331,7 +332,7 @@ function Canvas.convertWindow(win, parent, x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function win.clearLine()
|
function win.clearLine()
|
||||||
local x, y = win.getCursorPos()
|
local _, y = win.getCursorPos()
|
||||||
win.canvas:write(1,
|
win.canvas:write(1,
|
||||||
y,
|
y,
|
||||||
_rep(' ', win.canvas.width),
|
_rep(' ', win.canvas.width),
|
||||||
|
@ -5,6 +5,8 @@ local Event = require('event')
|
|||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
|
local colors = _G.colors
|
||||||
|
|
||||||
multishell.setTitle(multishell.getCurrent(), 'Files')
|
multishell.setTitle(multishell.getCurrent(), 'Files')
|
||||||
UI:configure('Files', ...)
|
UI:configure('Files', ...)
|
||||||
|
|
||||||
@ -20,7 +22,7 @@ local marked = { }
|
|||||||
local directories = { }
|
local directories = { }
|
||||||
local cutMode = false
|
local cutMode = false
|
||||||
|
|
||||||
function formatSize(size)
|
local function formatSize(size)
|
||||||
if size >= 1000000 then
|
if size >= 1000000 then
|
||||||
return string.format('%dM', math.floor(size/1000000, 2))
|
return string.format('%dM', math.floor(size/1000000, 2))
|
||||||
elseif size >= 1000 then
|
elseif size >= 1000 then
|
||||||
@ -61,7 +63,7 @@ local Browser = UI.Page {
|
|||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Name', key = 'name' },
|
{ heading = 'Name', key = 'name' },
|
||||||
{ key = 'flags', width = 2 },
|
{ key = 'flags', width = 2 },
|
||||||
{ heading = 'Size', key = 'fsize', width = 6 },
|
{ heading = 'Size', key = 'fsize', width = 5 },
|
||||||
},
|
},
|
||||||
sortColumn = 'name',
|
sortColumn = 'name',
|
||||||
y = 2, ey = -2,
|
y = 2, ey = -2,
|
||||||
@ -84,6 +86,7 @@ local Browser = UI.Page {
|
|||||||
d = 'delete',
|
d = 'delete',
|
||||||
delete = 'delete',
|
delete = 'delete',
|
||||||
[ 'control-h' ] = 'toggle_hidden',
|
[ 'control-h' ] = 'toggle_hidden',
|
||||||
|
[ 'control-s' ] = 'toggle_dirSize',
|
||||||
[ 'control-x' ] = 'cut',
|
[ 'control-x' ] = 'cut',
|
||||||
[ 'control-c' ] = 'copy',
|
[ 'control-c' ] = 'copy',
|
||||||
paste = 'paste',
|
paste = 'paste',
|
||||||
@ -117,7 +120,7 @@ function Browser.grid:sortCompare(a, b)
|
|||||||
return a.isDir
|
return a.isDir
|
||||||
end
|
end
|
||||||
|
|
||||||
function Browser.grid:getRowTextColor(file, selected)
|
function Browser.grid:getRowTextColor(file)
|
||||||
if file.marked then
|
if file.marked then
|
||||||
return colors.green
|
return colors.green
|
||||||
end
|
end
|
||||||
@ -130,13 +133,6 @@ function Browser.grid:getRowTextColor(file, selected)
|
|||||||
return colors.white
|
return colors.white
|
||||||
end
|
end
|
||||||
|
|
||||||
function Browser.grid:getRowBackgroundColorX(file, selected)
|
|
||||||
if selected then
|
|
||||||
return colors.gray
|
|
||||||
end
|
|
||||||
return self.backgroundColor
|
|
||||||
end
|
|
||||||
|
|
||||||
function Browser.grid:eventHandler(event)
|
function Browser.grid:eventHandler(event)
|
||||||
if event.type == 'copy' then -- let copy be handled by parent
|
if event.type == 'copy' then -- let copy be handled by parent
|
||||||
return false
|
return false
|
||||||
@ -169,7 +165,6 @@ function Browser:unmarkAll()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Browser:getDirectory(directory)
|
function Browser:getDirectory(directory)
|
||||||
|
|
||||||
local s, dir = pcall(function()
|
local s, dir = pcall(function()
|
||||||
|
|
||||||
local dir = directories[directory]
|
local dir = directories[directory]
|
||||||
@ -350,7 +345,7 @@ function Browser:eventHandler(event)
|
|||||||
self.statusBar:sync()
|
self.statusBar:sync()
|
||||||
local _, ch = os.pullEvent('char')
|
local _, ch = os.pullEvent('char')
|
||||||
if ch == 'y' or ch == 'Y' then
|
if ch == 'y' or ch == 'Y' then
|
||||||
for k,m in pairs(marked) do
|
for _,m in pairs(marked) do
|
||||||
pcall(function()
|
pcall(function()
|
||||||
fs.delete(m.fullName)
|
fs.delete(m.fullName)
|
||||||
end)
|
end)
|
||||||
@ -377,7 +372,7 @@ function Browser:eventHandler(event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
elseif event.type == 'paste' then
|
elseif event.type == 'paste' then
|
||||||
for k,m in pairs(copied) do
|
for _,m in pairs(copied) do
|
||||||
local s, m = pcall(function()
|
local s, m = pcall(function()
|
||||||
if cutMode then
|
if cutMode then
|
||||||
fs.move(m.fullName, fs.combine(self.dir.name, m.name))
|
fs.move(m.fullName, fs.combine(self.dir.name, m.name))
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
requireInjector(getfenv(1))
|
requireInjector(getfenv(1))
|
||||||
|
|
||||||
local Event = require('event')
|
|
||||||
local UI = require('ui')
|
local UI = require('ui')
|
||||||
|
local Util = require('util')
|
||||||
|
|
||||||
|
local colors = _G.colors
|
||||||
|
local help = _G.help
|
||||||
|
|
||||||
multishell.setTitle(multishell.getCurrent(), 'Help')
|
multishell.setTitle(multishell.getCurrent(), 'Help')
|
||||||
UI:configure('Help', ...)
|
UI:configure('Help', ...)
|
||||||
|
|
||||||
local files = { }
|
local topics = { }
|
||||||
for _,f in pairs(help.topics()) do
|
for _,topic in pairs(help.topics()) do
|
||||||
table.insert(files, { name = f })
|
if help.lookup(topic) then
|
||||||
|
table.insert(topics, { name = topic })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local page = UI.Page {
|
local page = UI.Page {
|
||||||
@ -22,9 +27,9 @@ local page = UI.Page {
|
|||||||
},
|
},
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
y = 4,
|
y = 4,
|
||||||
values = files,
|
values = topics,
|
||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Name', key = 'name' },
|
{ heading = 'Topic', key = 'name' },
|
||||||
},
|
},
|
||||||
sortColumn = 'name',
|
sortColumn = 'name',
|
||||||
},
|
},
|
||||||
@ -34,36 +39,56 @@ local page = UI.Page {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local function showHelp(name)
|
local topicPage = UI.Page {
|
||||||
UI.term:reset()
|
backgroundColor = colors.black,
|
||||||
shell.run('help ' .. name)
|
titleBar = UI.TitleBar {
|
||||||
print('Press enter to return')
|
title = 'text',
|
||||||
repeat
|
previousPage = true,
|
||||||
os.pullEvent('key')
|
},
|
||||||
local _, k = os.pullEvent('key_up')
|
helpText = UI.TextArea {
|
||||||
until k == keys.enter
|
backgroundColor = colors.black,
|
||||||
|
x = 2, ex = -1, y = 3, ey = -2,
|
||||||
|
},
|
||||||
|
accelerators = {
|
||||||
|
q = 'back',
|
||||||
|
backspace = 'back',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function topicPage.helpText:focus()
|
||||||
|
-- let the help text get focused so we consume key strokes
|
||||||
|
end
|
||||||
|
|
||||||
|
function topicPage:eventHandler(event)
|
||||||
|
if event.type == 'back' then
|
||||||
|
UI:setPreviousPage()
|
||||||
|
end
|
||||||
|
return UI.Page.eventHandler(self, event)
|
||||||
end
|
end
|
||||||
|
|
||||||
function page:eventHandler(event)
|
function page:eventHandler(event)
|
||||||
|
|
||||||
if event.type == 'quit' then
|
if event.type == 'quit' then
|
||||||
Event.exitPullEvents()
|
UI:exitPullEvents()
|
||||||
|
|
||||||
elseif event.type == 'grid_select' then
|
elseif event.type == 'grid_select' then
|
||||||
if self.grid:getSelected() then
|
if self.grid:getSelected() then
|
||||||
showHelp(self.grid:getSelected().name)
|
local name = self.grid:getSelected().name
|
||||||
self:setFocus(self.filter)
|
local f = help.lookup(name)
|
||||||
self:draw()
|
|
||||||
|
topicPage.titleBar.title = name
|
||||||
|
topicPage.helpText:setText(Util.readFile(f))
|
||||||
|
|
||||||
|
UI:setPage(topicPage)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event.type == 'text_change' then
|
elseif event.type == 'text_change' then
|
||||||
local text = event.text
|
if #event.text == 0 then
|
||||||
if #text == 0 then
|
self.grid.values = topics
|
||||||
self.grid.values = files
|
|
||||||
else
|
else
|
||||||
self.grid.values = { }
|
self.grid.values = { }
|
||||||
for _,f in pairs(files) do
|
for _,f in pairs(topics) do
|
||||||
if string.find(f.name, text) then
|
if string.find(f.name, event.text) then
|
||||||
table.insert(self.grid.values, f)
|
table.insert(self.grid.values, f)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -72,7 +97,7 @@ function page:eventHandler(event)
|
|||||||
self.grid:setIndex(1)
|
self.grid:setIndex(1)
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
else
|
else
|
||||||
UI.Page.eventHandler(self, event)
|
return UI.Page.eventHandler(self, event)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ local page = UI.Page {
|
|||||||
tabBar = UI.VerticalTabBar {
|
tabBar = UI.VerticalTabBar {
|
||||||
buttons = buttons,
|
buttons = buttons,
|
||||||
},
|
},
|
||||||
container = UI.ViewportWindow {
|
container = UI.Viewport {
|
||||||
x = cx,
|
x = cx,
|
||||||
y = cy,
|
y = cy,
|
||||||
},
|
},
|
||||||
@ -324,7 +324,7 @@ function page.container:setCategory(categoryName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function page.container:draw()
|
function page.container:draw()
|
||||||
UI.ViewportWindow.draw(self)
|
UI.Viewport.draw(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
function page:refresh()
|
function page:refresh()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
ScrollingGrid = {
|
ScrollBar = {
|
||||||
lineChar = '|',
|
lineChar = '|',
|
||||||
sliderChar = '\127',
|
sliderChar = '\127',
|
||||||
upArrowChar = '\30',
|
upArrowChar = '\30',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user