support scrollbar for choicedialog

This commit is contained in:
ruki
2020-11-29 19:10:28 +08:00
parent 3325a7394a
commit 66c7312db4
4 changed files with 148 additions and 45 deletions

View File

@@ -38,8 +38,81 @@ function choicebox:init(name, bounds)
-- init panel
panel.init(self, name, bounds)
-- init values
self._VALUES = {}
-- init items
self._ITEMS = {}
-- init start index
self._STARTINDEX = 1
end
-- load values
function choicebox:load(values, selected)
-- clear the views first
self:clear()
-- load items
local items = {}
for idx, value in ipairs(values) do
table.insert(items, self:_load_item(value, idx, idx == selected))
end
self._ITEMS = items
-- insert top-n items
local startindex = self._STARTINDEX
for idx = startindex, startindex + self:height() do
local item = items[idx]
if item then
self:insert(item)
else
break
end
end
-- select the first item
self:select(self:first())
-- invalidate
self:invalidate()
-- on loaded
self:action_on(action.ac_on_load)
end
-- is scrollable?
function choicebox:scrollable()
return #self:_items() > self:height()
end
-- scroll
function choicebox:scroll(count)
if self:scrollable() then
local items = self:_items()
local totalcount = #items
local startindex = self._STARTINDEX + count
if startindex > totalcount then
return
elseif startindex < 1 then
startindex = 1
end
self._STARTINDEX = startindex
self:clear()
for idx = startindex, startindex + self:height() do
local item = items[idx]
if item then
item:bounds():move2(0, idx - startindex)
self:insert(item)
else
break
end
end
if count > 0 then
self:select(self:first())
else
self:select(self:last())
end
self:invalidate()
end
end
-- on event
@@ -48,9 +121,19 @@ function choicebox:on_event(e)
-- select config
if e.type == event.ev_keyboard then
if e.key_name == "Down" then
return self:select_next()
if self:current() == self:last() then
self:scroll(self:height())
end
self:select_next()
self:_notify_scrolled()
return true
elseif e.key_name == "Up" then
return self:select_prev()
if self:current() == self:first() then
self:scroll(-self:height())
end
self:select_prev()
self:_notify_scrolled()
return true
elseif e.key_name == "Enter" or e.key_name == " " then
self:_do_select()
return true
@@ -61,44 +144,36 @@ function choicebox:on_event(e)
end
end
-- load values
function choicebox:load(values, selected)
-- clear the views first
self:clear()
-- insert values
self._VALUES = values
for idx, value in ipairs(values) do
self:_do_insert(value, idx, idx == selected)
end
-- select the first item
self:select(self:first())
-- invalidate
self:invalidate()
end
-- do insert a value item
function choicebox:_do_insert(value, index, selected)
-- load a item with value
function choicebox:_load_item(value, index, selected)
-- init text
local text = (selected and "(X) " or "( ) ") .. tostring(value)
-- init a value item view
local item = button:new("choicebox.value." .. self:count(),
rect:new(0, self:count(), self:width(), 1),
local item = button:new("choicebox.value." .. index,
rect:new(0, index - 1, self:width(), 1),
text,
function (v, e)
self:_do_select()
end)
-- attach this index
-- attach index and value
item:extra_set("index", index)
item:extra_set("value", value)
return item
end
-- insert this config item
self:insert(item)
-- notify scrolled
function choicebox:_notify_scrolled()
local totalcount = #self:_items()
local startindex = self:current():extra("index")
self:action_on(action.ac_on_scrolled, startindex / totalcount)
end
-- get all items
function choicebox:_items()
return self._ITEMS
end
-- do select the current config
@@ -108,24 +183,17 @@ function choicebox:_do_select()
for v in self:views() do
local text = v:text()
if text and text:startswith("(X) ") then
local i = v:extra("index")
if i then
local t = self._VALUES[i]
v:text_set("( ) " .. tostring(t))
end
local t = v:extra("value")
v:text_set("( ) " .. tostring(t))
end
end
-- get the current item
local item = self:current()
-- get the current index
local index = item:extra("index")
-- get the current value
local value = self._VALUES[index]
-- do action: on selected
local index = item:extra("index")
local value = item:extra("value")
self:action_on(action.ac_on_selected, index, value)
-- update text

View File

@@ -25,6 +25,7 @@ local event = require("ltui/event")
local action = require("ltui/action")
local curses = require("ltui/curses")
local window = require("ltui/window")
local scrollbar = require("ltui/scrollbar")
local choicebox = require("ltui/choicebox")
local boxdialog = require("ltui/boxdialog")
@@ -50,23 +51,57 @@ function choicedialog:init(name, bounds, title)
end)
self:buttons():select(self:button("select"))
-- insert scrollbar
self:box():panel():insert(self:scrollbar_box())
-- insert choice box
self:box():panel():insert(self:choicebox())
-- disable to select to box (disable Tab switch and only response to buttons)
self:box():option_set("selectable", false)
-- on resize for panel
self:box():panel():action_add(action.ac_on_resized, function (v)
self:choicebox():bounds_set(rect:new(0, 0, v:width() - 1, v:height()))
self:scrollbar_box():bounds_set(rect:new(v:width() - 1, 0, 1, v:height()))
end)
-- show scrollbar?
self:choicebox():action_set(action.ac_on_load, function (v)
if v:scrollable() then
self:scrollbar_box():show(true)
else
self:scrollbar_box():show(false)
end
end)
-- on scroll
self:choicebox():action_set(action.ac_on_scrolled, function (v, progress)
if self:scrollbar_box():state("visible") then
self:scrollbar_box():progress_set(progress)
end
end)
end
-- get choice box
function choicedialog:choicebox()
if not self._CHOICEBOX then
local bounds = self:box():panel():bounds()
self._CHOICEBOX = choicebox:new("choicedialog.choicebox", rect:new(0, 0, bounds:width(), bounds:height()))
self._CHOICEBOX = choicebox:new("choicedialog.choicebox", rect:new(0, 0, bounds:width() - 1, bounds:height()))
self._CHOICEBOX:state_set("focused", true) -- we can select and highlight selected item
end
return self._CHOICEBOX
end
-- get box scrollbar
function choicedialog:scrollbar_box()
if not self._SCROLLBAR_BOX then
self._SCROLLBAR_BOX = scrollbar:new("choicedialog.scrollbar", rect:new(self:box():panel():width() - 1, 0, 1, self:box():panel():height()))
self._SCROLLBAR_BOX:show(false)
end
return self._SCROLLBAR_BOX
end
-- on event
function choicedialog:on_event(e)

View File

@@ -79,7 +79,7 @@ function textarea:scroll(lines)
if self._STARTLINE < 0 then
self._STARTLINE = 0
end
local startline_end = self._LINECOUNT - self:height()
local startline_end = self._LINECOUNT > self:height() and self._LINECOUNT - self:height() or self._LINECOUNT
if self._STARTLINE > startline_end then
self._STARTLINE = startline_end
end
@@ -91,7 +91,7 @@ end
-- scroll to end
function textarea:scroll_to_end()
if self:scrollable() then
local startline_end = self._LINECOUNT - self:height()
local startline_end = self._LINECOUNT > self:height() and self._LINECOUNT - self:height() or self._LINECOUNT
self._STARTLINE = startline_end
self:action_on(action.ac_on_scrolled, self._STARTLINE / startline_end)
self:invalidate()

View File

@@ -72,7 +72,7 @@ function textdialog:init(name, bounds, title)
-- on scroll for text and scrollbar
self:text():action_set(action.ac_on_scrolled, function (v, progress)
if self:option("scrollable") then
if self:scrollbar():state("visible") then
self:scrollbar():progress_set(progress)
end
end)