diff options
author | William Wilgus <wilgus.william@gmail.com> | 2021-04-29 01:56:49 -0400 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2021-04-30 13:38:54 +0000 |
commit | 20cd89908d3b7276c50295ccd6c4f09f7324f6e2 (patch) | |
tree | 794d3da185c17429a64881eb8702dae9659f1b5a | |
parent | 48b77898dce686f77b86adb977ba49400f5a3f7d (diff) | |
download | rockbox-20cd89908d3b7276c50295ccd6c4f09f7324f6e2.tar.gz rockbox-20cd89908d3b7276c50295ccd6c4f09f7324f6e2.zip |
lua submenus add a way to dynamically add items
updated example script and renamed some functions as well
fixed bug in printtable cursor position if greater than maxlines for the
screen would reset to item 1
now we move the list start and select it
(and try to center it on the screen)
fixed a few bugs in the add_menu code
Change-Id: I01dead0481ef2e925af8b4cc6c14e36c2859dbba
-rw-r--r-- | apps/plugins/lua/include_lua/printsubmenu.lua | 135 | ||||
-rw-r--r-- | apps/plugins/lua/include_lua/printtable.lua | 10 | ||||
-rw-r--r-- | apps/plugins/lua_scripts/submenu_demo.lua | 44 |
3 files changed, 139 insertions, 50 deletions
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 @@ | |||
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | ]] | 22 | ]] |
23 | if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end | 23 | if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end |
24 | --GLOBALS | ||
24 | menu_ctx = {} | 25 | menu_ctx = {} |
26 | submenu_insert = table.insert | ||
27 | submenu_remove = table.remove | ||
28 | |||
25 | local last_ctx = false | 29 | local last_ctx = false |
26 | local p_settings | 30 | local p_settings |
31 | local function empty_fn() end | ||
27 | 32 | ||
28 | --[[root menu tables | 33 | --[[root menu tables |
29 | expanded menus get inserted / removed | 34 | expanded menus get inserted / removed |
30 | and context menus replace them but never overwritten | 35 | and context menus replace them but unless you |
31 | unless you want a new root menu | 36 | want a new root menu they are never overwritten |
37 | func_t functions get 3 variables passed by the menu_system | ||
38 | func_t[i] =function sample(i, menu_t, func_t] | ||
39 | this function gets run on user selection | ||
40 | for every function in func_t: | ||
41 | 'i' is the selected item | ||
42 | 'menu_t' is the current strings table | ||
43 | 'func_t' is the current function table | ||
44 | |||
45 | menu_t[i] will returnm the text of the item user selected and | ||
46 | func_t[i] will return the function we are currently in | ||
32 | ]] | 47 | ]] |
48 | |||
33 | menu_t = {} | 49 | menu_t = {} |
34 | func_t = {} | 50 | func_t = {} |
35 | 51 | ||
@@ -110,16 +126,9 @@ local function dpad(x, xi, xir, y, yi, yir, timeout, overflow, selected) | |||
110 | return cancel, select, x_chg, x, y_chg, y, 0xffff | 126 | return cancel, select, x_chg, x, y_chg, y, 0xffff |
111 | end -- dpad | 127 | end -- dpad |
112 | 128 | ||
113 | |||
114 | |||
115 | local function menu_set_defaults(settings, ctx) | ||
116 | p_settings = settings or {wrap = true, hasheader = true, justify = "left", dpad_fn = dpad} | ||
117 | menu_ctx = ctx or {collapse_fn = {}, lv = 0, update = false, start = 1} | ||
118 | end | ||
119 | |||
120 | local function ctx_loop() | 129 | local function ctx_loop() |
121 | local loopfn = ctx_loop | 130 | local loopfn = ctx_loop |
122 | ctx_loop = function() end --prevent another execution | 131 | ctx_loop = empty_fn() --prevent another execution |
123 | local mt, ft = get_menu() | 132 | local mt, ft = get_menu() |
124 | local i | 133 | local i |
125 | repeat | 134 | repeat |
@@ -130,25 +139,23 @@ local function ctx_loop() | |||
130 | ctx_loop = loopfn --restore for another run | 139 | ctx_loop = loopfn --restore for another run |
131 | end | 140 | end |
132 | 141 | ||
133 | function get_menu() | 142 | --[[ push_ctx() save surrent menu and load another ]] |
134 | return menu_t, func_t | ||
135 | end | ||
136 | |||
137 | local function push_ctx(new_getmenu) | 143 | local function push_ctx(new_getmenu) |
138 | last_ctx = last_ctx or {} | 144 | last_ctx = last_ctx or {} |
139 | table.insert(last_ctx, menu_ctx) | 145 | submenu_insert(last_ctx, menu_ctx) |
140 | menu_ctx.getmenu = get_menu | 146 | menu_ctx.getmenu = get_menu |
141 | menu_ctx.settings = p_settings | 147 | menu_ctx.settings = p_settings |
142 | --menu_ctx is a new variable after this point | 148 | --menu_ctx is a new variable after this point |
143 | menu_set_defaults() | 149 | submenu_set_defaults() |
144 | menu_ctx.update = true | 150 | menu_ctx.update = true |
145 | if type(new_getmenu) == 'function' then | 151 | if type(new_getmenu) == 'function' then |
146 | get_menu = new_getmenu | 152 | get_menu = new_getmenu |
147 | end | 153 | end |
148 | end | 154 | end |
149 | 155 | ||
156 | --[[ pop_ctx() restore last menu ]] | ||
150 | local function pop_ctx() | 157 | local function pop_ctx() |
151 | menu_ctx = table.remove(last_ctx) | 158 | menu_ctx = submenu_remove(last_ctx) |
152 | if menu_ctx then | 159 | if menu_ctx then |
153 | get_menu = menu_ctx.getmenu | 160 | get_menu = menu_ctx.getmenu |
154 | p_settings = menu_ctx.settings | 161 | p_settings = menu_ctx.settings |
@@ -163,13 +170,17 @@ local function pop_ctx() | |||
163 | end | 170 | end |
164 | end | 171 | end |
165 | 172 | ||
173 | --[[ display_context_menu_internal() supplies a new get_menu function that returns | ||
174 | the context menu 'user_context_fn' supplied by set_menu() | ||
175 | this menu is immediately displayed and when finished will | ||
176 | automatically restore the last menu | ||
177 | ]] | ||
166 | local function display_context_menu_internal(sel) | 178 | local function display_context_menu_internal(sel) |
167 | |||
168 | if sel <= 0 or not menu_ctx.user_context_fn then return false end | 179 | if sel <= 0 or not menu_ctx.user_context_fn then return false end |
169 | local parent = get_parent() or 0 | 180 | local parent = submenu_get_parent() or 0 |
170 | local user_context_fn = menu_ctx.user_context_fn | 181 | local user_context_fn = menu_ctx.user_context_fn |
171 | local function display_context_menu(i, menu_t, func_t) | ||
172 | 182 | ||
183 | local function display_context_menu(i, menu_t, func_t) | ||
173 | local function new_getmenu() | 184 | local function new_getmenu() |
174 | local mt, ft = user_context_fn(parent, i, menu_t, func_t) | 185 | local mt, ft = user_context_fn(parent, i, menu_t, func_t) |
175 | ft[0] = pop_ctx --set back fn | 186 | ft[0] = pop_ctx --set back fn |
@@ -179,6 +190,7 @@ local function display_context_menu_internal(sel) | |||
179 | return true | 190 | return true |
180 | end | 191 | end |
181 | 192 | ||
193 | --save the current function in closure restore_fn for later | ||
182 | local funct = func_t[sel] | 194 | local funct = func_t[sel] |
183 | local function restore_fn(mt, ft) | 195 | local function restore_fn(mt, ft) |
184 | ft[sel] = funct | 196 | ft[sel] = funct |
@@ -192,30 +204,43 @@ local function display_context_menu_internal(sel) | |||
192 | return true | 204 | return true |
193 | end | 205 | end |
194 | 206 | ||
195 | function get_parent(lv) | 207 | --[[ submenu_get_parent() gets the parent of the top most level |
196 | lv = lv or #menu_ctx.collapse_fn | 208 | if lv is supplied it instead gets the parent of that level ]] |
209 | function submenu_get_parent(lv) | ||
210 | lv = lv or #menu_ctx.collapse_fn or 1 | ||
197 | collectgarbage("step") | 211 | collectgarbage("step") |
198 | local t = menu_ctx.collapse_fn[lv] or {} | 212 | local t = menu_ctx.collapse_fn[lv] or {} |
199 | return t[2] or -1 | 213 | return t[2] or -1, lv |
200 | end | 214 | end |
201 | 215 | ||
202 | function set_menu(mt, ft, user_context_fn, settings) | 216 | --[[ submenu_collapse() collapses submenu till level or ROOT is reached ]] |
203 | local function empty_fn() end | 217 | function submenu_collapse(parent, lv) |
204 | menu_set_defaults(settings) | 218 | local lv_out, menu_sz = 0, 0 |
205 | if type(user_context_fn) == 'function' then | 219 | local item_out = -1 |
206 | display_context_menu = display_context_menu_internal | 220 | local items_removed = 0 |
207 | menu_ctx.user_context_fn = user_context_fn | 221 | if lv <= #menu_ctx.collapse_fn then |
208 | else | 222 | repeat |
209 | display_context_menu = empty_fn | 223 | local collapse_fn = submenu_remove(menu_ctx.collapse_fn) |
210 | menu_ctx.user_context_fn = false | 224 | if collapse_fn then |
225 | lv_out, item_out, menu_sz = collapse_fn[1](parent, menu_t, func_t) | ||
226 | items_removed = items_removed + menu_sz | ||
227 | end | ||
228 | |||
229 | until not collapse_fn or lv >= lv_out | ||
211 | end | 230 | end |
212 | p_settings = settings or p_settings | 231 | return lv_out, item_out, items_removed |
213 | menu_t, func_t = mt, ft | ||
214 | ctx_loop() | ||
215 | end | 232 | end |
216 | 233 | ||
217 | function create_sub_menu(lv, mt, ft) | 234 | --[[ submenu_create() supply level of submenu > 0, ROOT is lv 0 |
235 | supply menu strings table and function table | ||
236 | closure returned run this function to expand the menu | ||
237 | ]] | ||
238 | function submenu_create(lv, mt, ft) | ||
218 | if lv < 1 then error("Level < 1") end | 239 | if lv < 1 then error("Level < 1") end |
240 | if type(mt) ~= 'table' or type(ft) ~= 'table' then | ||
241 | error("mt and ft must be tables") | ||
242 | end | ||
243 | |||
219 | -- everything in lua is 1 based menu level is no exception | 244 | -- everything in lua is 1 based menu level is no exception |
220 | local lv_tab = string.rep ("\t", lv) | 245 | local lv_tab = string.rep ("\t", lv) |
221 | local function submenu_closure(i, m, f) | 246 | local function submenu_closure(i, m, f) |
@@ -224,7 +249,7 @@ function create_sub_menu(lv, mt, ft) | |||
224 | local item_in, item_out = i, i | 249 | local item_in, item_out = i, i |
225 | if lv <= #menu_ctx.collapse_fn then --something else expanded?? | 250 | if lv <= #menu_ctx.collapse_fn then --something else expanded?? |
226 | repeat | 251 | repeat |
227 | local collapse_fn = table.remove(menu_ctx.collapse_fn) | 252 | local collapse_fn = submenu_remove(menu_ctx.collapse_fn) |
228 | if collapse_fn then | 253 | if collapse_fn then |
229 | lv_out, item_out, menusz_out = collapse_fn[1](i, m, f) | 254 | lv_out, item_out, menusz_out = collapse_fn[1](i, m, f) |
230 | -- if the item i is below this menu, it needs to shift too | 255 | -- if the item i is below this menu, it needs to shift too |
@@ -241,23 +266,49 @@ function create_sub_menu(lv, mt, ft) | |||
241 | menu_ctx.update = true | 266 | menu_ctx.update = true |
242 | for item, _ in ipairs(mt) do | 267 | for item, _ in ipairs(mt) do |
243 | i = i + 1 | 268 | i = i + 1 |
244 | table.insert(m, i, lv_tab .. mt[item]) | 269 | submenu_insert(m, i, lv_tab .. mt[item]) |
245 | table.insert(f, i, ft[item]) | 270 | submenu_insert(f, i, ft[item]) |
246 | end | 271 | end |
247 | 272 | ||
248 | local function collapse_closure(i, m, f) | 273 | local function collapse_closure(i, m, f) |
249 | --creates a closure around lv, start_item and menu_sz | 274 | --creates a closure around lv, start_item and menu_sz |
250 | for j = 1, menu_sz, 1 do | 275 | for j = 1, menu_sz, 1 do |
251 | table.remove(m, start_item + 1) | 276 | submenu_remove(m, start_item + 1) |
252 | table.remove(f, start_item + 1) | 277 | submenu_remove(f, start_item + 1) |
253 | end | 278 | end |
254 | return lv, start_item, menu_sz | 279 | return lv, start_item, menu_sz |
255 | end | 280 | end |
256 | 281 | ||
257 | table.insert(menu_ctx.collapse_fn, lv, {collapse_closure, start_item}) | 282 | submenu_insert(menu_ctx.collapse_fn, lv, {collapse_closure, start_item}) |
258 | return true | 283 | return true |
259 | end | 284 | end |
260 | 285 | ||
261 | return submenu_closure | 286 | return submenu_closure |
262 | end | 287 | end |
263 | 288 | ||
289 | -- | ||
290 | function submenu_set_defaults(settings, ctx) | ||
291 | p_settings = settings or {wrap = true, hasheader = true, justify = "left", dpad_fn = dpad} | ||
292 | menu_ctx = ctx or {collapse_fn = {}, lv = 0, update = false, start = 1} | ||
293 | end | ||
294 | |||
295 | --[[ get_menu() returns the ROOT string and fn tables]] | ||
296 | function get_menu() | ||
297 | return menu_t, func_t | ||
298 | end | ||
299 | |||
300 | --[[ set_menu() set your menu and the menu has now been entered ]] | ||
301 | function set_menu(mt, ft, user_context_fn, settings) | ||
302 | |||
303 | submenu_set_defaults(settings) | ||
304 | if type(user_context_fn) == 'function' then | ||
305 | display_context_menu = display_context_menu_internal | ||
306 | menu_ctx.user_context_fn = user_context_fn | ||
307 | else | ||
308 | display_context_menu = empty_fn | ||
309 | menu_ctx.user_context_fn = false | ||
310 | end | ||
311 | p_settings = settings or p_settings | ||
312 | menu_t, func_t = mt, ft | ||
313 | ctx_loop() | ||
314 | 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) | |||
336 | 336 | ||
337 | table_p = init_position(15, 5) | 337 | table_p = init_position(15, 5) |
338 | line, maxline = _print.opt.area(5, 1, rb.LCD_WIDTH - 10 - sb_width, rb.LCD_HEIGHT - 2) | 338 | line, maxline = _print.opt.area(5, 1, rb.LCD_WIDTH - 10 - sb_width, rb.LCD_HEIGHT - 2) |
339 | |||
340 | if curpos > maxline then | ||
341 | local c = maxline / 2 | ||
342 | start = (start or 1) + curpos - maxline | ||
343 | curpos = maxline | ||
344 | while start + maxline <= t_count and curpos > c do | ||
345 | curpos = curpos - 1 | ||
346 | start = start + 1 | ||
347 | end | ||
348 | end | ||
339 | maxline = math.min(maxline, t_count) | 349 | maxline = math.min(maxline, t_count) |
340 | 350 | ||
341 | -- allow user to start at a position other than the beginning | 351 | -- 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 | |||
13 | local function ITEM_MENU() | 13 | local function ITEM_MENU() |
14 | 14 | ||
15 | local function flung(i, menu_t, func_t) | 15 | local function flung(i, menu_t, func_t) |
16 | local parent = get_parent() or 0 | 16 | local parent = submenu_get_parent() or 0 |
17 | rb.splash(100, "flung " .. (menu_t[parent] or "?")) | 17 | rb.splash(100, "flung " .. (menu_t[parent] or "?")) |
18 | end | 18 | end |
19 | 19 | ||
20 | local function foo(i, menu_t, func_t) | 20 | local function foo(i, menu_t, func_t) |
21 | local parent = get_parent() or 0 | 21 | local parent = submenu_get_parent() or 0 |
22 | rb.splash(100, "FOO " .. menu_t[parent]) | 22 | rb.splash(100, "FOO " .. menu_t[parent]) |
23 | end | 23 | end |
24 | 24 | ||
25 | local function far(i, menu_t, func_t) | 25 | local function far(i, menu_t, func_t) |
26 | local parent = get_parent() or 0 | 26 | local parent = submenu_get_parent() or 0 |
27 | rb.splash(100, "far" .. menu_t[parent]) | 27 | rb.splash(100, "far" .. menu_t[parent]) |
28 | end | 28 | end |
29 | 29 | ||
@@ -32,16 +32,44 @@ local function ITEM_MENU() | |||
32 | end | 32 | end |
33 | 33 | ||
34 | local function USERITEMS() | 34 | local function USERITEMS() |
35 | local lv = 2 | ||
36 | local mt = {"Item_1", "Item_2", "Item_3"} | ||
37 | local ft = {} | ||
35 | 38 | ||
36 | return {"Item_1", "Item_2", "Item_3"}, | 39 | local function insert_item(i, name, func) --closure |
37 | {create_sub_menu(2, ITEM_MENU()), create_sub_menu(2, ITEM_MENU()), | 40 | submenu_insert(mt, i, name) |
38 | create_sub_menu(2, ITEM_MENU()), function() end} | 41 | submenu_insert(ft, i, func) |
42 | end | ||
43 | |||
44 | for i = 1, #mt, 1 do | ||
45 | ft[i] = submenu_create(lv, ITEM_MENU()) | ||
46 | end | ||
47 | |||
48 | local function add_new(i, menu_t, func_t) | ||
49 | local parent, lv = submenu_get_parent(lv - 1) | ||
50 | local last = #mt | ||
51 | local name = "Item_" .. tostring(last) | ||
52 | local func = submenu_create(lv + 1, ITEM_MENU()) | ||
53 | |||
54 | local lv_out, item_out, removed = submenu_collapse(parent, lv + 1)-- collapse others | ||
55 | submenu_collapse(parent, lv) -- collapse the parent | ||
56 | |||
57 | insert_item(last, name, func) | ||
58 | |||
59 | func_t[parent](parent, menu_t, func_t) -- reopen parent | ||
60 | menu_ctx.start = i - removed | ||
61 | return true | ||
62 | end | ||
63 | |||
64 | local next = #mt + 1 | ||
65 | insert_item(next, "Add New", add_new) | ||
66 | return mt, ft | ||
39 | end | 67 | end |
40 | 68 | ||
41 | local function MAIN_MENU() | 69 | local function MAIN_MENU() |
42 | 70 | ||
43 | local function go_back(i, m, f) | 71 | local function go_back(i, m, f) |
44 | local parent = get_parent() or 0 | 72 | local parent = submenu_get_parent() or 0 |
45 | if parent > 0 then | 73 | if parent > 0 then |
46 | f[parent](parent, m, f) | 74 | f[parent](parent, m, f) |
47 | else | 75 | else |
@@ -60,7 +88,7 @@ local function MAIN_MENU() | |||
60 | local ft = { | 88 | local ft = { |
61 | [0] = go_back, --if user cancels do this function | 89 | [0] = go_back, --if user cancels do this function |
62 | [1] = false, -- shouldn't happen title occupies this slot | 90 | [1] = false, -- shouldn't happen title occupies this slot |
63 | [2] = create_sub_menu(1, USERITEMS()), | 91 | [2] = submenu_create(1, USERITEMS()), |
64 | [3] = go_back, | 92 | [3] = go_back, |
65 | } | 93 | } |
66 | return mt, ft, get_ctx_menu | 94 | return mt, ft, get_ctx_menu |