diff --git a/apps/plugins/lua/include_lua/printsubmenu.lua b/apps/plugins/lua/include_lua/printsubmenu.lua index 3c61b5fda8..f4b93db98d 100644 --- a/apps/plugins/lua/include_lua/printsubmenu.lua +++ b/apps/plugins/lua/include_lua/printsubmenu.lua @@ -21,15 +21,31 @@ ****************************************************************************/ ]] if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end +--GLOBALS menu_ctx = {} +submenu_insert = table.insert +submenu_remove = table.remove + local last_ctx = false local p_settings +local function empty_fn() end --[[root menu tables expanded menus get inserted / removed -and context menus replace them but never overwritten -unless you want a new root menu +and context menus replace them but unless you +want a new root menu they are never overwritten +func_t functions get 3 variables passed by the menu_system +func_t[i] =function sample(i, menu_t, func_t] +this function gets run on user selection +for every function in func_t: +'i' is the selected item +'menu_t' is the current strings table +'func_t' is the current function table + +menu_t[i] will returnm the text of the item user selected and +func_t[i] will return the function we are currently in ]] + menu_t = {} func_t = {} @@ -110,16 +126,9 @@ local function dpad(x, xi, xir, y, yi, yir, timeout, overflow, selected) return cancel, select, x_chg, x, y_chg, y, 0xffff end -- dpad - - -local function menu_set_defaults(settings, ctx) - p_settings = settings or {wrap = true, hasheader = true, justify = "left", dpad_fn = dpad} - menu_ctx = ctx or {collapse_fn = {}, lv = 0, update = false, start = 1} -end - local function ctx_loop() local loopfn = ctx_loop - ctx_loop = function() end --prevent another execution + ctx_loop = empty_fn() --prevent another execution local mt, ft = get_menu() local i repeat @@ -130,25 +139,23 @@ local function ctx_loop() ctx_loop = loopfn --restore for another run end -function get_menu() - return menu_t, func_t -end - +--[[ push_ctx() save surrent menu and load another ]] local function push_ctx(new_getmenu) last_ctx = last_ctx or {} - table.insert(last_ctx, menu_ctx) + submenu_insert(last_ctx, menu_ctx) menu_ctx.getmenu = get_menu menu_ctx.settings = p_settings --menu_ctx is a new variable after this point - menu_set_defaults() + submenu_set_defaults() menu_ctx.update = true if type(new_getmenu) == 'function' then get_menu = new_getmenu end end +--[[ pop_ctx() restore last menu ]] local function pop_ctx() - menu_ctx = table.remove(last_ctx) + menu_ctx = submenu_remove(last_ctx) if menu_ctx then get_menu = menu_ctx.getmenu p_settings = menu_ctx.settings @@ -163,13 +170,17 @@ local function pop_ctx() end end +--[[ display_context_menu_internal() supplies a new get_menu function that returns + the context menu 'user_context_fn' supplied by set_menu() + this menu is immediately displayed and when finished will + automatically restore the last menu +]] local function display_context_menu_internal(sel) - if sel <= 0 or not menu_ctx.user_context_fn then return false end - local parent = get_parent() or 0 + local parent = submenu_get_parent() or 0 local user_context_fn = menu_ctx.user_context_fn - local function display_context_menu(i, menu_t, func_t) + local function display_context_menu(i, menu_t, func_t) local function new_getmenu() local mt, ft = user_context_fn(parent, i, menu_t, func_t) ft[0] = pop_ctx --set back fn @@ -179,6 +190,7 @@ local function display_context_menu_internal(sel) return true end + --save the current function in closure restore_fn for later local funct = func_t[sel] local function restore_fn(mt, ft) ft[sel] = funct @@ -192,30 +204,43 @@ local function display_context_menu_internal(sel) return true end -function get_parent(lv) - lv = lv or #menu_ctx.collapse_fn +--[[ submenu_get_parent() gets the parent of the top most level + if lv is supplied it instead gets the parent of that level ]] +function submenu_get_parent(lv) + lv = lv or #menu_ctx.collapse_fn or 1 collectgarbage("step") local t = menu_ctx.collapse_fn[lv] or {} - return t[2] or -1 + return t[2] or -1, lv end -function set_menu(mt, ft, user_context_fn, settings) - local function empty_fn() end - menu_set_defaults(settings) - if type(user_context_fn) == 'function' then - display_context_menu = display_context_menu_internal - menu_ctx.user_context_fn = user_context_fn - else - display_context_menu = empty_fn - menu_ctx.user_context_fn = false +--[[ submenu_collapse() collapses submenu till level or ROOT is reached ]] +function submenu_collapse(parent, lv) + local lv_out, menu_sz = 0, 0 + local item_out = -1 + local items_removed = 0 + if lv <= #menu_ctx.collapse_fn then + repeat + local collapse_fn = submenu_remove(menu_ctx.collapse_fn) + if collapse_fn then + lv_out, item_out, menu_sz = collapse_fn[1](parent, menu_t, func_t) + items_removed = items_removed + menu_sz + end + + until not collapse_fn or lv >= lv_out end - p_settings = settings or p_settings - menu_t, func_t = mt, ft - ctx_loop() + return lv_out, item_out, items_removed end -function create_sub_menu(lv, mt, ft) +--[[ submenu_create() supply level of submenu > 0, ROOT is lv 0 + supply menu strings table and function table + closure returned run this function to expand the menu +]] +function submenu_create(lv, mt, ft) if lv < 1 then error("Level < 1") end + if type(mt) ~= 'table' or type(ft) ~= 'table' then + error("mt and ft must be tables") + end + -- everything in lua is 1 based menu level is no exception local lv_tab = string.rep ("\t", lv) local function submenu_closure(i, m, f) @@ -224,7 +249,7 @@ function create_sub_menu(lv, mt, ft) local item_in, item_out = i, i if lv <= #menu_ctx.collapse_fn then --something else expanded?? repeat - local collapse_fn = table.remove(menu_ctx.collapse_fn) + local collapse_fn = submenu_remove(menu_ctx.collapse_fn) if collapse_fn then lv_out, item_out, menusz_out = collapse_fn[1](i, m, f) -- if the item i is below this menu, it needs to shift too @@ -241,23 +266,49 @@ function create_sub_menu(lv, mt, ft) menu_ctx.update = true for item, _ in ipairs(mt) do i = i + 1 - table.insert(m, i, lv_tab .. mt[item]) - table.insert(f, i, ft[item]) + submenu_insert(m, i, lv_tab .. mt[item]) + submenu_insert(f, i, ft[item]) end local function collapse_closure(i, m, f) --creates a closure around lv, start_item and menu_sz for j = 1, menu_sz, 1 do - table.remove(m, start_item + 1) - table.remove(f, start_item + 1) + submenu_remove(m, start_item + 1) + submenu_remove(f, start_item + 1) end return lv, start_item, menu_sz end - table.insert(menu_ctx.collapse_fn, lv, {collapse_closure, start_item}) + submenu_insert(menu_ctx.collapse_fn, lv, {collapse_closure, start_item}) return true end return submenu_closure end +-- +function submenu_set_defaults(settings, ctx) + p_settings = settings or {wrap = true, hasheader = true, justify = "left", dpad_fn = dpad} + menu_ctx = ctx or {collapse_fn = {}, lv = 0, update = false, start = 1} +end + +--[[ get_menu() returns the ROOT string and fn tables]] +function get_menu() + return menu_t, func_t +end + +--[[ set_menu() set your menu and the menu has now been entered ]] +function set_menu(mt, ft, user_context_fn, settings) + + submenu_set_defaults(settings) + if type(user_context_fn) == 'function' then + display_context_menu = display_context_menu_internal + menu_ctx.user_context_fn = user_context_fn + else + display_context_menu = empty_fn + menu_ctx.user_context_fn = false + end + p_settings = settings or p_settings + menu_t, func_t = mt, ft + ctx_loop() +end diff --git a/apps/plugins/lua/include_lua/printtable.lua b/apps/plugins/lua/include_lua/printtable.lua index bf81c7b060..7a883367b7 100644 --- a/apps/plugins/lua/include_lua/printtable.lua +++ b/apps/plugins/lua/include_lua/printtable.lua @@ -336,6 +336,16 @@ function print_table(t, t_count, settings) table_p = init_position(15, 5) line, maxline = _print.opt.area(5, 1, rb.LCD_WIDTH - 10 - sb_width, rb.LCD_HEIGHT - 2) + + if curpos > maxline then + local c = maxline / 2 + start = (start or 1) + curpos - maxline + curpos = maxline + while start + maxline <= t_count and curpos > c do + curpos = curpos - 1 + start = start + 1 + end + end maxline = math.min(maxline, t_count) -- allow user to start at a position other than the beginning diff --git a/apps/plugins/lua_scripts/submenu_demo.lua b/apps/plugins/lua_scripts/submenu_demo.lua index 75fec11979..8eac825474 100644 --- a/apps/plugins/lua_scripts/submenu_demo.lua +++ b/apps/plugins/lua_scripts/submenu_demo.lua @@ -13,17 +13,17 @@ end local function ITEM_MENU() local function flung(i, menu_t, func_t) - local parent = get_parent() or 0 + local parent = submenu_get_parent() or 0 rb.splash(100, "flung " .. (menu_t[parent] or "?")) end local function foo(i, menu_t, func_t) - local parent = get_parent() or 0 + local parent = submenu_get_parent() or 0 rb.splash(100, "FOO " .. menu_t[parent]) end local function far(i, menu_t, func_t) - local parent = get_parent() or 0 + local parent = submenu_get_parent() or 0 rb.splash(100, "far" .. menu_t[parent]) end @@ -32,16 +32,44 @@ local function ITEM_MENU() end local function USERITEMS() + local lv = 2 + local mt = {"Item_1", "Item_2", "Item_3"} + local ft = {} - return {"Item_1", "Item_2", "Item_3"}, - {create_sub_menu(2, ITEM_MENU()), create_sub_menu(2, ITEM_MENU()), - create_sub_menu(2, ITEM_MENU()), function() end} + local function insert_item(i, name, func) --closure + submenu_insert(mt, i, name) + submenu_insert(ft, i, func) + end + + for i = 1, #mt, 1 do + ft[i] = submenu_create(lv, ITEM_MENU()) + end + + local function add_new(i, menu_t, func_t) + local parent, lv = submenu_get_parent(lv - 1) + local last = #mt + local name = "Item_" .. tostring(last) + local func = submenu_create(lv + 1, ITEM_MENU()) + + local lv_out, item_out, removed = submenu_collapse(parent, lv + 1)-- collapse others + submenu_collapse(parent, lv) -- collapse the parent + + insert_item(last, name, func) + + func_t[parent](parent, menu_t, func_t) -- reopen parent + menu_ctx.start = i - removed + return true + end + + local next = #mt + 1 + insert_item(next, "Add New", add_new) + return mt, ft end local function MAIN_MENU() local function go_back(i, m, f) - local parent = get_parent() or 0 + local parent = submenu_get_parent() or 0 if parent > 0 then f[parent](parent, m, f) else @@ -60,7 +88,7 @@ local function MAIN_MENU() local ft = { [0] = go_back, --if user cancels do this function [1] = false, -- shouldn't happen title occupies this slot - [2] = create_sub_menu(1, USERITEMS()), + [2] = submenu_create(1, USERITEMS()), [3] = go_back, } return mt, ft, get_ctx_menu