From 75b1d2e4c7044cdbe38d1f0293811d2f3f63fe14 Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 29 Nov 2020 21:23:37 +0800 Subject: [PATCH] support scrollbar for menuconf --- src/ltui/choicebox.lua | 6 +- src/ltui/choicedialog.lua | 12 ++- src/ltui/mconfdialog.lua | 43 +++++++++- src/ltui/menuconf.lua | 176 +++++++++++++++++++++++++++++--------- src/ltui/textdialog.lua | 4 +- 5 files changed, 192 insertions(+), 49 deletions(-) diff --git a/src/ltui/choicebox.lua b/src/ltui/choicebox.lua index 4e16476..969cda6 100644 --- a/src/ltui/choicebox.lua +++ b/src/ltui/choicebox.lua @@ -72,11 +72,11 @@ function choicebox:load(values, selected) -- select the first item self:select(self:first()) - -- invalidate - self:invalidate() - -- on loaded self:action_on(action.ac_on_load) + + -- invalidate + self:invalidate() end -- is scrollable? diff --git a/src/ltui/choicedialog.lua b/src/ltui/choicedialog.lua index 7a16412..2820702 100644 --- a/src/ltui/choicedialog.lua +++ b/src/ltui/choicedialog.lua @@ -64,10 +64,15 @@ function choicedialog:init(name, bounds, title) 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())) + if self:choicebox():scrollable() then + self:scrollbar_box():show(true) + else + self:scrollbar_box():show(false) + end end) -- show scrollbar? - self:choicebox():action_set(action.ac_on_load, function (v) + self:choicebox():action_add(action.ac_on_load, function (v) if v:scrollable() then self:scrollbar_box():show(true) else @@ -76,7 +81,7 @@ function choicedialog:init(name, bounds, title) end) -- on scroll - self:choicebox():action_set(action.ac_on_scrolled, function (v, progress) + self:choicebox():action_add(action.ac_on_scrolled, function (v, progress) if self:scrollbar_box():state("visible") then self:scrollbar_box():progress_set(progress) end @@ -96,7 +101,8 @@ 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())) + local bounds = self:box():panel():bounds() + self._SCROLLBAR_BOX = scrollbar:new("choicedialog.scrollbar", rect:new(bounds:width() - 1, 0, 1, bounds:height())) self._SCROLLBAR_BOX:show(false) end return self._SCROLLBAR_BOX diff --git a/src/ltui/mconfdialog.lua b/src/ltui/mconfdialog.lua index d4a2e08..454500e 100644 --- a/src/ltui/mconfdialog.lua +++ b/src/ltui/mconfdialog.lua @@ -26,6 +26,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 menuconf = require("ltui/menuconf") local boxdialog = require("ltui/boxdialog") local textdialog = require("ltui/textdialog") @@ -54,6 +55,9 @@ Pressing includes, excludes. Enter or to go back, for H self:button_add("save", "< Save >", function (v, e) self:action_on(action.ac_on_save) end) self:buttons():select(self:button("select")) + -- insert scrollbar + self:box():panel():insert(self:scrollbar_menuconf()) + -- insert menu config self:box():panel():insert(self:menuconf()) self:box():panel():action_add(action.ac_on_resized, function (v) @@ -64,6 +68,17 @@ Pressing includes, excludes. Enter or to go back, for H -- 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:menuconf():bounds_set(rect:new(0, 0, v:width() - 1, v:height())) + self:scrollbar_menuconf():bounds_set(rect:new(v:width() - 1, 0, 1, v:height())) + if self:menuconf():scrollable() then + self:scrollbar_menuconf():show(true) + else + self:scrollbar_menuconf():show(false) + end + end) + -- on selected self:menuconf():action_set(action.ac_on_selected, function (v, config) @@ -94,6 +109,22 @@ Pressing includes, excludes. Enter or to go back, for H return true end end) + + -- show scrollbar? + self:menuconf():action_add(action.ac_on_load, function (v) + if v:scrollable() then + self:scrollbar_menuconf():show(true) + else + self:scrollbar_menuconf():show(false) + end + end) + + -- on scroll + self:menuconf():action_add(action.ac_on_scrolled, function (v, progress) + if self:scrollbar_menuconf():state("visible") then + self:scrollbar_menuconf():progress_set(progress) + end + end) end -- load configs @@ -111,12 +142,22 @@ end function mconfdialog:menuconf() if not self._MENUCONF then local bounds = self:box():panel():bounds() - self._MENUCONF = menuconf:new("mconfdialog.menuconf", rect:new(0, 0, bounds:width(), bounds:height())) + self._MENUCONF = menuconf:new("mconfdialog.menuconf", rect:new(0, 0, bounds:width() - 1, bounds:height())) self._MENUCONF:state_set("focused", true) -- we can select and highlight selected item end return self._MENUCONF end +-- get menu scrollbar +function mconfdialog:scrollbar_menuconf() + if not self._SCROLLBAR_MENUCONF then + local bounds = self:box():panel():bounds() + self._SCROLLBAR_MENUCONF = scrollbar:new("mconfdialog.scrollbar", rect:new(bounds:width() - 1, 0, 1, bounds:height())) + self._SCROLLBAR_MENUCONF:show(false) + end + return self._SCROLLBAR_MENUCONF +end + -- get help dialog function mconfdialog:helpdialog() if not self._HELPDIALOG then diff --git a/src/ltui/menuconf.lua b/src/ltui/menuconf.lua index 8709ae9..ac109c6 100644 --- a/src/ltui/menuconf.lua +++ b/src/ltui/menuconf.lua @@ -40,18 +40,132 @@ function menuconf:init(name, bounds) -- init configs self._CONFIGS = {} + + -- init items + self._ITEMS = {} + + -- init start index + self._STARTINDEX = 1 + + -- on resize for panel + self:action_add(action.ac_on_resized, function (v) + local items = self:_items() + local totalcount = #items + local startindex = self._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 + self:select(self:first()) + self:invalidate() + end) +end + +-- load configs +function menuconf:load(configs) + + -- clear the views first + self:clear() + + -- detach the previous config and view + local configs_prev = self._CONFIGS._PREV + if configs_prev then + for _, config in ipairs(configs_prev) do + config._view = nil + end + end + + -- save configs + self._CONFIGS = configs + + -- load items + local items = {} + for idx, config in ipairs(configs) do + table.insert(items, self:_load_item(config, idx)) + 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()) + + -- on loaded + self:action_on(action.ac_on_load) + + -- invalidate + self:invalidate() +end + +-- is scrollable? +function menuconf:scrollable() + return #self:_items() > self:height() +end + +-- scroll +function menuconf: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 function menuconf:on_event(e) - - -- select config local back = false 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 @@ -85,54 +199,36 @@ function menuconf:on_event(e) end end --- load configs -function menuconf:load(configs) - - -- clear the views first - self:clear() - - -- detach the previous config and view - local configs_prev = self._CONFIGS._PREV - if configs_prev then - for _, config in ipairs(configs_prev) do - config._view = nil - end - end - - -- insert configs - self._CONFIGS = configs - for _, config in ipairs(configs) do - if self:count() < self:height() then - self:_do_insert(config) - end - end - - -- select the first item - self:select(self:first()) - - -- invalidate - self:invalidate() -end - --- do insert a config item -function menuconf:_do_insert(config) +-- load a config item +function menuconf:_load_item(config, index) -- init a config item view - local item = button:new("menuconf.config." .. self:count(), - rect:new(0, self:count(), self:width(), 1), + local item = button:new("menuconf.config." .. index, + rect:new(0, index - 1, self:width(), 1), tostring(config), function (v, e) self:_do_select() end) - -- attach this config + -- attach this index and config + item:extra_set("index", index) item:extra_set("config", config) -- attach this view config._view = item + return item +end - -- insert this config item - self:insert(item) +-- notify scrolled +function menuconf:_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 menuconf:_items() + return self._ITEMS end -- do select the current config diff --git a/src/ltui/textdialog.lua b/src/ltui/textdialog.lua index c375fc3..a0f7d12 100644 --- a/src/ltui/textdialog.lua +++ b/src/ltui/textdialog.lua @@ -60,7 +60,7 @@ function textdialog:init(name, bounds, title) end) -- show scrollbar? - self:text():action_set(action.ac_on_text_changed, function (v) + self:text():action_add(action.ac_on_text_changed, function (v) if self:option("scrollable") then if v:scrollable() then self:scrollbar():show(true) @@ -71,7 +71,7 @@ function textdialog:init(name, bounds, title) end) -- on scroll for text and scrollbar - self:text():action_set(action.ac_on_scrolled, function (v, progress) + self:text():action_add(action.ac_on_scrolled, function (v, progress) if self:scrollbar():state("visible") then self:scrollbar():progress_set(progress) end