Simple, keyboard-driven terminal menus for Python (1D lists & 2D grids).
Project description
ExpertTUI
Simple, keyboard-driven terminal menus for Python — 1D lists and 2D grids.
╭──────────────────────────────────╮ ╭──────────────────┬──────────────────╮
│ Settings │ │ New Game │ │
│ ─── Audio / Video ────────────── │ ├──────────────────┼──────────────────┤
│ > [x] Music │ │ > Class: < Mage │ Diff: Normal │
│ [ ] Fullscreen │ │ Name: hero... │ │
│ [x] Sound FX │ ├──────────────────┼──────────────────┤
│ ────────────────────────────── │ │ > Start │ Back │
│ Save & Exit │ ╰──────────────────┴──────────────────╯
╰──────────────────────────────────╯
menu_1D menu_2D
Features
- Five item types — action, selector (←→), text input, checkbox, hr separator
- Two layouts — vertical
menu_1Dand grid-basedmenu_2D - Five border styles —
singledoubleroundedheavyblockwith correct Unicode junction characters where borders meet separators (├ ┤ ┼ ╬ ┬ ┴ …) - Column alignment —
align=Truekeeps 2D columns in sync across all rows - Gap fill — styled column separators (
│ ║ ┃ █) that connect to borders - Inline editing — cursor jumps to the input field; menu stays visible
- Live border resize —
width="auto"shrinks/grows the border as you type - Scroll —
height=Nshows a window, scrolls with the cursor - enter_selector — require Enter to activate a selector (global or per-item)
- Full type hints — explicit keyword-only parameters for IDE autocomplete
- TypedDicts — importable item types for dict-key autocomplete
Installation
pip install experttui
Requirements: Python ≥ 3.8 · colorama · readchar
Quick Start
from experttui import menu_1D
menu_1D([
"Choose an option",
("Start game", lambda: print("Starting!")),
("Settings", lambda: print("Opening settings…")),
("Quit", lambda: quit()),
])
Item Types
| Type | Format | Description |
|---|---|---|
| Static label | "text" |
Non-selectable line |
| Action (tuple) | ("label", fn) |
Calls fn on Enter |
| Action (dict) | {"text": …, "function": fn} |
Same, with extra options |
| Selector | {"type": "selector", "options": […], "index": 0} |
←→ cycles values |
| Input | {"type": "input", "value": "", "placeholder": "…"} |
Enter opens inline editor |
| Checkbox | {"type": "checkbox", "checked": False} |
Enter toggles |
| Separator | {"type": "hr"} |
Horizontal line connecting to border |
Extra keys per type
Action dict — disabled (bool), color_selected (str), prefix (str), suffix (str)
Selector — color_selected, color_options, enter (bool — per-item enter_selector)
Input — color_selected
Checkbox — disabled, color_selected
Hr — fill (border style name), label (centred text)
Importing TypedDicts for autocomplete
from experttui import SelectorItem, InputItem, CheckboxItem, HrItem
quality: SelectorItem = {
"type": "selector",
"text": "Quality",
"options": ["Low", "Medium", "High"],
"index": 1,
}
menu_1D — Full Reference
from experttui import menu_1D
menu_1D(
items, # list — see Item Types above
*,
color = "YELLOW", # colorama colour name
selection_type = "left_arrow", # "left_arrow" | "two_arrows"
moving = "both", # "both" | "arrows" | "wsad"
border = False, # False | True/"double" | "single" |
# "rounded" | "heavy" | "block"
wait_after_function = False, # pause after action before redrawing
return_after_action = False, # exit menu after action (skip redraw)
enter_selector = False, # require Enter to activate selector edit mode
width = "auto", # "auto" (live resize) | int (fixed cols)
height = "auto", # "auto" | int (scrollable window)
margin = 0, # space outside border, all sides
margin_top = None, # per-side override
margin_right = None,
margin_bottom = None,
margin_left = None,
padding = 0, # space inside border, all sides
padding_top = None,
padding_right = None,
padding_bottom = None,
padding_left = None,
)
Keyboard reference
| Item | Up / Down | Left / Right | Enter | ESC |
|---|---|---|---|---|
| Navigate | ↑↓ / WS | — | — | Exit |
| Action | Run function | |||
| Selector | Cycle value | Activate (if enter_selector) |
||
| Input | Open inline editor | Exit editor | ||
| Checkbox | Toggle |
When enter_selector is active for a selector: Enter opens edit mode,
←→/AD change value, Enter confirms, ESC restores the original value.
menu_2D — Full Reference
All menu_1D parameters, plus:
menu_2D(
items, # list of rows — each row is a list or a single item
*,
# … all menu_1D params …
align = True, # align every column to the max width of that column
gap = 2, # columns of space between cells
gap_fill = False, # False | border-style name — vertical char in the gap
)
Row structure:
menu_2D([
"Full-width header", # single item → spans entire row
{"type": "hr", "label": "Setup"}, # full-width separator
[selector_a, selector_b], # two columns
[input_field], # one column (full width)
[("OK", fn), ("Cancel", fn2)], # two action buttons
])
Keyboard reference (2D)
| Action | Key |
|---|---|
| Move between rows | ↑↓ / WS |
| Move between columns | ←→ / AD |
| Cycle single-col selector | ←→ / AD |
Activate selector (enter_selector) |
Enter |
Border Styles
single rounded double heavy block
┌──────┐ ╭──────╮ ╔══════╗ ┏━━━━━━┓ ██████
│ item │ │ item │ ║ item ║ ┃ item ┃ █ item █
└──────┘ ╰──────╯ ╚══════╝ ┗━━━━━━┛ ██████
Junction characters are inserted automatically when border + hr or
border + gap_fill are both set:
┌──────────────┬──────────────┐ ← ┬ where gap meets top border
│ Class: Mage │ Diff: Normal │
├──────────────┼──────────────┤ ← ┼ where gap meets hr
│ Start │ Back │
└──────────────┴──────────────┘ ← ┴ where gap meets bottom border
Examples
Settings menu with checkboxes
from experttui import menu_1D
quality = {"type": "selector", "text": "Quality",
"options": ["Low", "Medium", "High"], "index": 1}
username = {"type": "input", "text": "Username",
"value": "", "placeholder": "enter name…"}
music = {"type": "checkbox", "text": "Music", "checked": True}
sfx = {"type": "checkbox", "text": "Sound FX", "checked": True}
menu_1D([
"Settings",
{"type": "hr", "fill": "single"},
quality, username,
{"type": "hr", "fill": "single", "label": "Audio"},
music, sfx,
{"type": "hr"},
("Save & Exit", lambda: print("Saved!")),
{"text": "Locked option", "disabled": True},
],
color="cyan", border="rounded", padding=1, margin_left=2,
wait_after_function=True, return_after_action=True, width=32,
)
Character select (2D grid)
from experttui import menu_2D
char_class = {"type": "selector", "text": "Class",
"options": ["Mage", "Warrior", "Rogue"], "index": 0}
difficulty = {"type": "selector", "text": "Diff",
"options": ["Easy", "Normal", "Hard"], "index": 1,
"enter": True} # this one needs Enter to activate
char_name = {"type": "input", "text": "Name",
"value": "", "placeholder": "hero…"}
def start():
print(f"Class={char_class['options'][char_class['index']]}, "
f"Diff={difficulty['options'][difficulty['index']]}, "
f"Name={char_name['value']}")
menu_2D([
"New Game",
{"type": "hr"},
[char_class, difficulty],
[char_name],
{"type": "hr"},
[("Start", start), ("Back", lambda: None)],
],
color="green", border="single", padding=1,
gap=3, gap_fill="single", align=True,
wait_after_function=True,
)
Utilities
from experttui import clear_screen, hide_cursor, show_cursor
clear_screen() # clear the entire terminal
hide_cursor() # hide blinking cursor
show_cursor() # restore cursor
Contributing
- Fork → feature branch → PR
- Run
pytestbefore submitting - Follow existing code style (type hints,
_prefix for private functions)
License
MIT — see LICENSE.
ExpertTUI — Dokumentacja (PL)
Proste, klawiaturowe menu terminalowe dla Pythona — listy 1D i siatki 2D.
Instalacja
pip install experttui
Wymagania: Python ≥ 3.8 · colorama · readchar
Szybki start
from experttui import menu_1D
menu_1D([
"Wybierz opcję",
("Nowa gra", lambda: print("Start!")),
("Ustawienia", lambda: print("Otwieranie…")),
("Wyjście", lambda: quit()),
])
Typy elementów
| Typ | Format | Opis |
|---|---|---|
| Etykieta | "tekst" |
Nieaktywna linia tekstowa |
| Akcja (tupla) | ("etykieta", fn) |
Wywołuje fn po Enter |
| Akcja (słownik) | {"text": …, "function": fn} |
To samo, z dodatkowymi opcjami |
| Selektor | {"type": "selector", "options": […], "index": 0} |
←→ zmienia wartość |
| Input | {"type": "input", "value": "", "placeholder": "…"} |
Enter otwiera edytor |
| Checkbox | {"type": "checkbox", "checked": False} |
Enter przełącza |
| Separator | {"type": "hr"} |
Pozioma linia łącząca się z ramką |
menu_1D — Parametry
menu_1D(
items,
*,
color = "YELLOW", # kolor zaznaczenia (nazwa colorama)
selection_type = "left_arrow",# "left_arrow" | "two_arrows"
moving = "both", # "both" | "arrows" | "wsad"
border = False, # False | "single"|"double"|"rounded"|"heavy"|"block"
wait_after_function = False, # czekaj na klawisz po akcji
return_after_action = False, # wyjdź z menu po akcji
enter_selector = False, # Enter wymagany do edycji selectora
width = "auto", # "auto" | int
height = "auto", # "auto" | int (scroll)
margin = 0, # margines zewnętrzny (wszystkie strony)
margin_top/right/bottom/left = None,
padding = 0, # padding wewnętrzny (wszystkie strony)
padding_top/right/bottom/left = None,
)
menu_2D — Dodatkowe parametry
menu_2D(
items,
*,
# … wszystkie parametry menu_1D …
align = True, # wyrównaj kolumny do tej samej szerokości
gap = 2, # odstęp między kolumnami (liczba znaków)
gap_fill = False, # False | nazwa stylu ramki — pionowy znak w odstępie
)
Struktura items:
menu_2D([
"Nagłówek pełnej szerokości",
{"type": "hr", "label": "Opcje"},
[selektor_a, selektor_b],
[pole_input],
[("OK", fn), ("Anuluj", fn2)],
])
Style ramki
single rounded double heavy block
┌──────┐ ╭──────╮ ╔══════╗ ┏━━━━━━┓ ██████
│ item │ │ item │ ║ item ║ ┃ item ┃ █ item █
└──────┘ ╰──────╯ ╚══════╝ ┗━━━━━━┛ ██████
Klawisze
| Akcja | Klawisz |
|---|---|
| Góra / dół | ↑↓ lub WS |
| Lewo / prawo (2D, wiele kolumn) | ←→ lub AD |
| Zmiana selectora (1 kolumna) | ←→ lub AD |
Aktywacja selectora (enter_selector) |
Enter → ←→ zmieniają wartość → Enter/ESC |
| Otwarcie / potwierdzenie inputu | Enter |
| Anulowanie inputu | ESC |
| Wyjście z menu | ESC |
Licencja
MIT — patrz LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file experttui-1.0.0.tar.gz.
File metadata
- Download URL: experttui-1.0.0.tar.gz
- Upload date:
- Size: 25.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99505e71081f26d61e9ac26232c0494321b0c45309da8d32e59ba7932c03250a
|
|
| MD5 |
7c61503f11744e5f52ff1c674c41b7ac
|
|
| BLAKE2b-256 |
38a0ba0bf646cf5802e6bcd32a8980f9d18be7377e577657744fcb7f1bc22265
|
File details
Details for the file experttui-1.0.0-py3-none-any.whl.
File metadata
- Download URL: experttui-1.0.0-py3-none-any.whl
- Upload date:
- Size: 17.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0722ef05d41d3dcbc11ab8edbbf24d388ebf7966acc67532f5803acc043ce8a
|
|
| MD5 |
be0e0e088bee0a4fc15294a34c21e7d7
|
|
| BLAKE2b-256 |
5319c068aeed62ec73f6ed868a8a5ad2ba587f7126568b713cb3f7bc15825ecf
|