diff --git a/README.md b/README.md index 902a2d9..ba30599 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,12 @@ Exported functions: - `reflow(text)`: split text into a list of lines not exceeding terminal width - `print_paged(text)`: reflow and print the text in a paginated manner, prompting for Enter presses to move to the next page +### `deck.menu` + +A library for easy menu systems for T-DeckARD programs. Allows displaying up to 10 menu items with the ability to select them with a single digit or a key on the `QWERTYUIOP` keyboard row. + +Exports the only function, `menu(choices)`, which accepts a list of **tuples**, each in the format `(id, label)`. The `label` field is what's displayed on the screen, the `id` field is the string that gets returned upon selection. If the user selects `c`, the operation is canceled and an empty `id` string is returned. + ### `deck.time` A wrapper for standard Python `date`, `time` and `datetime` modules. Just run `from deck.time import *` to activate. diff --git a/deck/menu.py b/deck/menu.py new file mode 100644 index 0000000..918159e --- /dev/null +++ b/deck/menu.py @@ -0,0 +1,54 @@ +# A simple menu system for T-DeckARD +# Created by Luxferre in 2025, released into public domain + +from deck.input import input + +_idx_map = { + '1': 0, 'q': 0, + '2': 1, 'w': 1, + '3': 2, 'e': 2, + '4': 3, 'r': 3, + '5': 4, 't': 4, + '6': 5, 'y': 5, + '7': 6, 'u': 6, + '8': 7, 'i': 7, + '9': 8, 'o': 8, + '0': 9, 'p': 9 +} + +def menu(choices, max_size = 10): + """ + Presents a menu of choices and prompts for numeric or + alphabetical input + Accepts a list of (id, label) tuples (up to 10 items) + Returns the associated id of the selected menu items + """ + cnum = 1 + for (cid, clbl) in choices: + try: + cletter = 'qwertyuiop'[cnum - 1] + print(f'[{cletter}] {cnum % 10}. {clbl}') + except: + print(f'{cnum % 10} {clbl}') + cnum += 1 + if cnum > max_size: + break + sel = '' + while len(sel) < 1: + sel = input('Your choice (c to cancel): ').strip().lower() + sel = str(sel[0]) + if sel == 'c': + print('Selection canceled') + return '' # empty label denotes canceled operation + elif sel in _idx_map: + idx = _idx_map[sel] + if idx < len(choices): + return choices[idx][0] + else: + print('Invalid choice!') + return menu(choices) + else: + print('Invalid choice!') + return menu(choices) + + diff --git a/tdeckboot.py b/tdeckboot.py index c1cf2e1..723c12f 100644 --- a/tdeckboot.py +++ b/tdeckboot.py @@ -7,6 +7,7 @@ from deck.fs import unlock_rootfs, lock_rootfs, mount_sd, umount_sd, env, rnd from deck.fs import du, df, sep, pwd, ls, md, cd, rd, rm, mv, cp, sync from deck.input import input, input_multi from deck.pager import print_paged, term_size +from deck.menu import menu from deck.time import * from deck.hwinfo import board_id, battery_v, cpu_f, REAL_HW from deck.http import wget, wput, http_fetch, http_set_ua