summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/include_lua/printsubmenu.lua
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lua/include_lua/printsubmenu.lua')
-rw-r--r--apps/plugins/lua/include_lua/printsubmenu.lua263
1 files changed, 263 insertions, 0 deletions
diff --git a/apps/plugins/lua/include_lua/printsubmenu.lua b/apps/plugins/lua/include_lua/printsubmenu.lua
new file mode 100644
index 0000000000..3c61b5fda8
--- /dev/null
+++ b/apps/plugins/lua/include_lua/printsubmenu.lua
@@ -0,0 +1,263 @@
1--[[
2/***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
10 *
11 * Copyright (C) 2021 William Wilgus
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22]]
23if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
24menu_ctx = {}
25local last_ctx = false
26local p_settings
27
28--[[root menu tables
29expanded menus get inserted / removed
30and context menus replace them but never overwritten
31unless you want a new root menu
32]]
33menu_t = {}
34func_t = {}
35
36require("printmenus")
37
38local BUTTON = require("menubuttons")
39local last_sel = 0
40
41local function display_context_menu() end -- forward declaration
42
43local function dpad(x, xi, xir, y, yi, yir, timeout, overflow, selected)
44 local scroll_is_fixed = overflow ~= "manual"
45 if timeout == nil then timeout = -1 end
46 local cancel, select = 0, 0
47 local x_chg, y_chg = 0, 0
48 local button
49 while true do
50 button = rb.get_plugin_action(timeout)
51
52 if button == BUTTON.CANCEL then
53 cancel = 1
54 break;
55 elseif button == BUTTON.EXIT then
56 cancel = 1
57 break;
58 elseif button == BUTTON.SEL then
59 last_sel = 1
60 timeout = timeout + 1
61 elseif button == BUTTON.SELR then
62 last_sel = 2
63 if display_context_menu(selected or -1) == true then
64 select = 1
65 break;
66 end
67 timeout = timeout + 1
68 elseif button == BUTTON.SELREL then
69 if last_sel == 1 then
70 select = 1
71 end
72 last_sel = 0
73 timeout = timeout + 1
74 elseif button == BUTTON.LEFT then
75 x_chg = x_chg - xi
76 if scroll_is_fixed then
77 cancel = 1
78 break;
79 end
80 elseif button == BUTTON.LEFTR then
81 x_chg = x_chg - xir
82 elseif button == BUTTON.RIGHT then
83 x_chg = x_chg + xi
84 if scroll_is_fixed then
85 select = 1
86 timeout = timeout + 1
87 end
88 elseif button == BUTTON.RIGHTR then
89 x_chg = x_chg + xir
90 elseif button == BUTTON.UP then
91 y_chg = y_chg + yi
92 elseif button == BUTTON.UPR then
93 y_chg = y_chg + yir
94 elseif button == BUTTON.DOWN then
95 y_chg = y_chg - yi
96 elseif button == BUTTON.DOWNR then
97 y_chg = y_chg - yir
98 elseif timeout >= 0 then--and rb.button_queue_count() < 1 then
99 break;
100 end
101
102 if x_chg ~= 0 or y_chg ~= 0 then
103 timeout = timeout + 1
104 end
105 end
106
107 x = x + x_chg
108 y = y + y_chg
109
110 return cancel, select, x_chg, x, y_chg, y, 0xffff
111end -- dpad
112
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()
121 local loopfn = ctx_loop
122 ctx_loop = function() end --prevent another execution
123 local mt, ft = get_menu()
124 local i
125 repeat
126 if menu_ctx.update then mt, ft = get_menu(); menu_ctx.update = false end
127 _, i = print_menu(mt, ft, menu_ctx.start, p_settings)
128 until menu_ctx.quit
129
130 ctx_loop = loopfn --restore for another run
131end
132
133function get_menu()
134 return menu_t, func_t
135end
136
137local function push_ctx(new_getmenu)
138 last_ctx = last_ctx or {}
139 table.insert(last_ctx, menu_ctx)
140 menu_ctx.getmenu = get_menu
141 menu_ctx.settings = p_settings
142 --menu_ctx is a new variable after this point
143 menu_set_defaults()
144 menu_ctx.update = true
145 if type(new_getmenu) == 'function' then
146 get_menu = new_getmenu
147 end
148end
149
150local function pop_ctx()
151 menu_ctx = table.remove(last_ctx)
152 if menu_ctx then
153 get_menu = menu_ctx.getmenu
154 p_settings = menu_ctx.settings
155 if menu_ctx.restorefn then
156 menu_ctx.restorefn(menu_t, func_t)
157 menu_ctx.restorefn = nil
158 end
159 menu_ctx.getmenu = nil
160 menu_ctx.settings = nil
161 menu_ctx.update = true
162 return true
163 end
164end
165
166local function display_context_menu_internal(sel)
167
168 if sel <= 0 or not menu_ctx.user_context_fn then return false end
169 local parent = get_parent() or 0
170 local user_context_fn = menu_ctx.user_context_fn
171 local function display_context_menu(i, menu_t, func_t)
172
173 local function new_getmenu()
174 local mt, ft = user_context_fn(parent, i, menu_t, func_t)
175 ft[0] = pop_ctx --set back fn
176 return mt, ft
177 end
178 push_ctx(new_getmenu)
179 return true
180 end
181
182 local funct = func_t[sel]
183 local function restore_fn(mt, ft)
184 ft[sel] = funct
185 menu_ctx.start = sel - 1
186 end
187
188 menu_ctx.restorefn = restore_fn
189 -- insert into the current fn table so it gets execd by the menu
190 func_t[sel] = display_context_menu
191
192 return true
193end
194
195function get_parent(lv)
196 lv = lv or #menu_ctx.collapse_fn
197 collectgarbage("step")
198 local t = menu_ctx.collapse_fn[lv] or {}
199 return t[2] or -1
200end
201
202function set_menu(mt, ft, user_context_fn, settings)
203 local function empty_fn() end
204 menu_set_defaults(settings)
205 if type(user_context_fn) == 'function' then
206 display_context_menu = display_context_menu_internal
207 menu_ctx.user_context_fn = user_context_fn
208 else
209 display_context_menu = empty_fn
210 menu_ctx.user_context_fn = false
211 end
212 p_settings = settings or p_settings
213 menu_t, func_t = mt, ft
214 ctx_loop()
215end
216
217function create_sub_menu(lv, mt, ft)
218 if lv < 1 then error("Level < 1") end
219 -- everything in lua is 1 based menu level is no exception
220 local lv_tab = string.rep ("\t", lv)
221 local function submenu_closure(i, m, f)
222 menu_ctx.lv = lv
223 local lv_out, menusz_out, start_item
224 local item_in, item_out = i, i
225 if lv <= #menu_ctx.collapse_fn then --something else expanded??
226 repeat
227 local collapse_fn = table.remove(menu_ctx.collapse_fn)
228 if collapse_fn then
229 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
231 if item_in > item_out then i = i - (menusz_out) end
232 end
233 until not collapse_fn or lv >= lv_out
234 menu_ctx.start = i
235 if item_out == item_in then return end
236 end
237
238 local menu_sz = #mt
239 menu_ctx.start = i
240 start_item = i
241 menu_ctx.update = true
242 for item, _ in ipairs(mt) do
243 i = i + 1
244 table.insert(m, i, lv_tab .. mt[item])
245 table.insert(f, i, ft[item])
246 end
247
248 local function collapse_closure(i, m, f)
249 --creates a closure around lv, start_item and menu_sz
250 for j = 1, menu_sz, 1 do
251 table.remove(m, start_item + 1)
252 table.remove(f, start_item + 1)
253 end
254 return lv, start_item, menu_sz
255 end
256
257 table.insert(menu_ctx.collapse_fn, lv, {collapse_closure, start_item})
258 return true
259 end
260
261 return submenu_closure
262end
263