summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2021-04-29 01:56:49 -0400
committerWilliam Wilgus <me.theuser@yahoo.com>2021-04-30 13:38:54 +0000
commit20cd89908d3b7276c50295ccd6c4f09f7324f6e2 (patch)
tree794d3da185c17429a64881eb8702dae9659f1b5a
parent48b77898dce686f77b86adb977ba49400f5a3f7d (diff)
downloadrockbox-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.lua135
-rw-r--r--apps/plugins/lua/include_lua/printtable.lua10
-rw-r--r--apps/plugins/lua_scripts/submenu_demo.lua44
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]]
23if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 23if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
24--GLOBALS
24menu_ctx = {} 25menu_ctx = {}
26submenu_insert = table.insert
27submenu_remove = table.remove
28
25local last_ctx = false 29local last_ctx = false
26local p_settings 30local p_settings
31local function empty_fn() end
27 32
28--[[root menu tables 33--[[root menu tables
29expanded menus get inserted / removed 34expanded menus get inserted / removed
30and context menus replace them but never overwritten 35and context menus replace them but unless you
31unless you want a new root menu 36want a new root menu they are never overwritten
37func_t functions get 3 variables passed by the menu_system
38func_t[i] =function sample(i, menu_t, func_t]
39this function gets run on user selection
40for 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
45menu_t[i] will returnm the text of the item user selected and
46func_t[i] will return the function we are currently in
32]] 47]]
48
33menu_t = {} 49menu_t = {}
34func_t = {} 50func_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
111end -- dpad 127end -- dpad
112 128
113
114
115local 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}
118end
119
120local function ctx_loop() 129local 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
131end 140end
132 141
133function get_menu() 142--[[ push_ctx() save surrent menu and load another ]]
134 return menu_t, func_t
135end
136
137local function push_ctx(new_getmenu) 143local 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
148end 154end
149 155
156--[[ pop_ctx() restore last menu ]]
150local function pop_ctx() 157local 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
164end 171end
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]]
166local function display_context_menu_internal(sel) 178local 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
193end 205end
194 206
195function 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 ]]
209function 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
200end 214end
201 215
202function 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 217function 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()
215end 232end
216 233
217function 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]]
238function 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
262end 287end
263 288
289--
290function 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}
293end
294
295--[[ get_menu() returns the ROOT string and fn tables]]
296function get_menu()
297 return menu_t, func_t
298end
299
300--[[ set_menu() set your menu and the menu has now been entered ]]
301function 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()
314end
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
13local function ITEM_MENU() 13local 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()
32end 32end
33 33
34local function USERITEMS() 34local 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
39end 67end
40 68
41local function MAIN_MENU() 69local 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