A sophisticated, layered TUI framework with weight-based layouts and focus management.
Project description
Vibe-TUI
A TUI library based in pure python that uses weighting to align your program perfectly.
Why should I use this?
- No
asyncio: Do what you want and manage as you like and display when you're finished; no rush here! - Weight based alignment: Remove the hassle of calculating widths and heights to the weight system! (I don't see hackers need to be game devs to make good TUIs)
What Nodes (or widgets) can I use?
UIBox(Node): A basic container box.UIImage(Node): Displays an image as block characters (requiresterm-imageandPillow).PyCodeText(UIBox)(In progress): Python text editor widget.UILabel(UIBox): A box without edges, used for text display.UIBar(UIBox): Loading bar, requires vibe_loadbar to be installed.ColorPicker(Node): A color selection widget.UICheckbox(UIBox): A checkbox widget.UIButton(UIBox): A clickable button.UIInput(Node): A text input field.UISelect(UIBox): A selection/list manager.TabManagerH(UiContainerHorizontal): A horizontal tab manager.UIScrollText(Node): A scrollable text view.UIEditor(UIBox): A full-featured text editor.UITerminal(UiContainerVertical): A terminal emulator widget.UITree(UIBox): A tree view widget.UIToast(Node): A toast notification overlay.UIModal(Node): A basic modal overlay.UIModalNode(UIModal): A modal that can contain another widget.CanvasNode(Node): A canvas for custom drawing. and more...
What layouts can I use?
UiContainerHorizontal(Node): Horizontal layout.UiContainerVertical(Node): Vertical layout.
You can also use FocusManager to manage Node focus.
File Structure:
.
├── architecture.svg
├── pyproject.toml
├── README.md
├── vibe_browser.py
├── example.py
└── vibe_tui
├── UI
│ ├── __init__.py
│ ├── base_widgets.py
│ ├── interactive
│ │ ├── __init__.py
│ │ ├── clickable.py
│ │ ├── images
│ │ │ ├── __init__.py
│ │ │ └── image.py
│ │ └── textinput.py
│ └── widgets.py
├── __init__.py
├── base
│ ├── __init__.py
│ ├── basic.py
│ ├── colors.py
│ └── theme.py
├── event
│ └── eventmanager.py
├── keyinput
│ ├── __init__.py
│ └── key.py
├── layouts
│ ├── __init__.py
│ └── baselayouts.py
├── managers
│ ├── __init__.py
│ ├── app.py
│ └── manager.py
├── node
│ ├── __init__.py
│ └── basenode.py
└── statements.py
Class structure:
New:
VibeApp()class makes a custom app for you without having to manage the event loop.
Example code:
Click to view the code
from vibe_tui import (
VibeApp,
UiContainerVertical,
UiContainerHorizontal,
UISelect,
UIScrollText,
UIInput,
UILabel,
Colors,
Theme
)
import random
import string
from vibe_tui.base.colors import LIGHT_BLUE_THEME
Theme.set_color_theme(LIGHT_BLUE_THEME)
class SimpleApp:
def __init__(self):
# Sample data for demonstration
self.all_items = items = [
f"root/{'sys' if i % 3 == 0 else 'usr'}/{i:02d}/{''.join(random.choices(string.ascii_lowercase, k=12))}.cfg"
for i in range(123)
]
# 2. Define Layout
self.root = UiContainerVertical()
# Header with bold colors
self.header = UILabel(weight=1, text=f" {Colors.BOLD}{Colors.BLUE}VIBE-TUI ENHANCED DEMO{Colors.RESET}")
# Interactive Search/Filter bar
self.search_bar = UIInput(weight=1, label=" Filter: ")
# Main content area using weights (1:2 ratio)
self.main_layout = UiContainerHorizontal(weight=8)
self.list_box = UISelect(weight=1, title=" SELECTOR ")
self.preview_box = UIScrollText(weight=2, title=" PREVIEW ", show_line_numbers=True)
self.main_layout.add(self.list_box).add(self.preview_box)
# Informative Footer
self.footer = UILabel(weight=1, text=f" {Colors.DIM}Press 'q' to Quit | Tab: Switch Focus | Arrows: Navigate{Colors.RESET}")
# Assemble the UI tree
self.root.add(self.header).add(self.search_bar).add(self.main_layout).add(self.footer)
# 3. Setup Logic & Events
self.list_box.options = self.all_items
# Bind events: Update preview on selection, and filter on search change
self.list_box.on("change", self.on_selection_change)
self.search_bar.on("change", self.on_search_change)
# 4. Initialize the App Engine
self.app = VibeApp(self.root)
self.on_selection_change(None) # Initial preview load
def on_selection_change(self, _):
"""Updates the preview pane based on the current selection."""
if not self.list_box.options:
self.preview_box.set_text("\n No matches found.")
return
selected = self.list_box.options[self.list_box.selection]
details = f"{Colors.BOLD}Details for:{Colors.RESET} {Colors.CYAN}{selected}{Colors.RESET}\n"
details += "═" * 40 + "\n\n"
details += "This UI is built using weight-based alignment,\n"
details += "ensuring it scales perfectly with your terminal size.\n\n"
details += f"Current Index: {Colors.YELLOW}{self.list_box.selection}{Colors.RESET}\n"
details += f"Status: {Colors.GREEN}Active{Colors.RESET}" if self.list_box.selection % random.choice([i for i in range(1, 16)]) != 0 else f"Status: {Colors.RED}DISABLED{Colors.RESET}"
self.preview_box.set_text(details)
def on_search_change(self, query):
"""Filters the list selection as you type."""
filtered = [item for item in self.all_items if query.lower() in item.lower()]
self.list_box.options = filtered
# Ensure selection index remains valid
if self.list_box.selection >= len(filtered):
self.list_box.selection = max(0, len(filtered) - 1)
self.on_selection_change(None)
def run(self):
"""Extends the input handler to support global shortcuts."""
original_handle = self.app.fm.handle_input
def custom_handle(key):
# Global quit shortcut (when not typing in the search bar)
if key == 'q' and self.app.fm.current != self.search_bar:
self.app.stop()
return
original_handle(key)
self.app.fm.handle_input = custom_handle
self.app.run()
if __name__ == "__main__":
try:
SimpleApp().run()
except Exception as e:
print(f"Error starting app: {e}")
Made with time and code by Adam Hany
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
vibe_tui-0.7.0.tar.gz
(24.9 kB
view details)
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
vibe_tui-0.7.0-py3-none-any.whl
(27.9 kB
view details)
File details
Details for the file vibe_tui-0.7.0.tar.gz.
File metadata
- Download URL: vibe_tui-0.7.0.tar.gz
- Upload date:
- Size: 24.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b993c876fe0b9bd23a3c6ea37556c499f3c243e177cddd43377b5286c6cda02
|
|
| MD5 |
b5c1f02378838233270cbe2b3b16c3cd
|
|
| BLAKE2b-256 |
a71ce695f0b989f86d948bf41c6ec88d28dd897646f631a44803acbefb2d9f0e
|
File details
Details for the file vibe_tui-0.7.0-py3-none-any.whl.
File metadata
- Download URL: vibe_tui-0.7.0-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d390a68d2119f796463c47226c2a974cff065e0d71d2a93533cb49bf7327e8c3
|
|
| MD5 |
42842ae0cd370965480b3eb742fe9168
|
|
| BLAKE2b-256 |
42f31de6232970c000973df866b86f4f1551329de387a28fbb83aeab7da02fa8
|