batgrl Documentation
repository·main·Indexed 20 days ago
https://github.com/salt-die/batgrlA terminal graphics library for creating visually rich terminal applications, including games and simulations. It features a hierarchical gadget tree structure for managing UI components, supporting responsive layouts via size and position hints, and an asynchronous event loop for handling input and continuous game logic. The library includes specialized gadget types such as Pane, Graphics, and Text, and provides built-in collision detection and event dispatching.
What's inside batgrl
- batgrl is a 'badass terminal graphics library' designed for creating high-fidelity terminal-based experiences. It is suitable for building games (like Tetris), simulations, and feature-filled terminal applications.
Control Gadget Rendering order
mainGadgets are drawn based on their position in the tree.
- Layering: Children are drawn on top of their parents.
- Sibling Order: Siblings are drawn in the order they appear in the
childrenlist. - Z-Index Management: To move a gadget to the front (ensuring it is drawn after all its siblings), use the
pull_to_front()method.
Use Size and Position hints for responsive layouts
mainSize and position hints allow gadgets to scale or reposition themselves relative to their parent if the parent is resized.
size_hint: A dictionary containing keys likeheight_hintorwidth_hint(values from 0.0 to 1.0).pos_hint: A dictionary containing keys likex_hintory_hint(values from 0.0 to 1.0).
Example: A divider that always takes up the full height of its parent and stays centered horizontally.
divider = Pane( size=(1, 1), size_hint={"height_hint": 1.0}, pos_hint={"x_hint": 0.5}, bg_color=BLUE, )Add gadgets to an application
mainAn application in
batgrlis a tree of gadgets. The root gadget automatically matches the terminal's current size. Useself.add_gadget(gadget)within anAppinstance to add a gadget to the root. To add multiple gadgets to a specific parent gadget, use theadd_gadgets(*gadgets)method.# Adding to the app root self.add_gadget(game_field) # Adding multiple gadgets to a parent game_field.add_gadgets(left_paddle, right_paddle, divider)Understand Gadget attributes and types
mainGadgets are the fundamental building blocks of a
batgrlapplication. Every gadget possesses a size, a position, and a tree of children.Key attributes that control gadget behavior include:
is_transparent: Determines if gadgets positioned beneath this gadget are rendered.is_visible: Determines if the gadget itself is rendered.is_enabled: Determines if input events are dispatched to this gadget.
Common gadget types include:
Pane: A gadget with a background color. Use thealphaattribute to control its transparency.Graphics: A gadget used for rendering arbitrary RGBA textures.Text: A general-purpose gadget representing state as an array of cells. Each cell contains terminal attributes like character, bold status, and foreground color.
Handle Input Dispatching and Event Handlers
mainInput events are dispatched across the entire gadget tree using a specific traversal order.
Dispatch Order: Events are dispatched to children in reversed order first. For a tree where
Roothas childrenAandB, andAhas childrenaandb, andBhas childc, the dispatch order is:c$\rightarrow$B$\rightarrow$b$\rightarrow$a$\rightarrow$A$\rightarrow$Root.Event Bubbling/Stopping: If any gadget's event handler returns
True, the dispatching process stops immediately, preventing the event from reaching other gadgets or ancestors.Available Event Handlers: Implement these methods in your gadget to respond to input:
on_key(): Handles key events.on_mouse(): Handles mouse events.on_paste(): Handles paste events.on_terminal_focus(): Handles terminal focus events.
Understand the Gadget Tree structure
mainIn
batgrl, application components (gadgets) are organized in a hierarchical tree structure.- The Root: A special gadget that automatically matches the terminal's size. It serves as the base of the tree.
- Hierarchy: Gadgets can have children, forming a parent-child relationship. Any gadget within the tree can access the top-level gadget via its
rootproperty. - Lifecycle Hooks: When a gadget is added to the tree (ensuring a path to the root exists), the
on_add()method is triggered. When a gadget is removed,on_remove()is triggered.
Configure Gadget size and position hints
mainYou can control how gadgets scale and position themselves relative to their parents using hints:
- Size Hints: If a gadget has a non-
Nonesize hint, its size will be a proportion of its parent's size. The gadget automatically updates when the parent is resized. - Position Hints: If a gadget has a non-
Noneposition hint, it will position itself at a specific proportion of its parent's size. - Anchoring: Use the
anchorattribute to specify which point within the gadget aligns with the position hint. The default value is"center".
- Size Hints: If a gadget has a non-
Initialize a batgrl application
mainTo create a basic application, subclass
batgrl.app.Appand implement theon_startasync method. Theon_startmethod is the entry point for adding gadgets to your application and scheduling tasks. Use the.run()method on your app instance to start the event loop.from batgrl.app import App class Pong(App): async def on_start(self): # Add gadgets and schedule tasks here pass if __name__ == "__main__": Pong().run()Run continuous game loops using Async
mainBecause
on_start()is anasyncmethod, you can implement a continuous game loop directly within it using awhile Trueloop. To prevent blocking the rest of the application's event loop (like input handling), you mustawait asyncio.sleep(delay)inside the loop.import asyncio class Pong(App): async def on_start(self): # ... setup gadgets ... speed = 0.04 while True: # ... update logic ... await asyncio.sleep(speed)Controls for the 3-D Rubik's Cube example
mainWhen running the Rubik's Cube example, use the following keyboard and mouse inputs to interact with the cube:
- Plane Rotation:
r: Rotate the selected plane counter-clockwise.R: Rotate the selected plane clockwise.
- Navigation:
up/down: Change the selected planes.left/right: Change the selected axis.
- Cube Actions:
s: Scramble the cube.
- Camera/View:
- Drag mouse: Rotate the entire cube view.
- Plane Rotation:
Create a terminal application by subclassing App
mainTo build a terminal application, subclass
batgrl.Appand implement theon_start()coroutine. Theon_start()method is called when the application begins running and is the place to initialize your gadget tree. Useself.add_gadget(gadget)orself.add_gadgets(*gadgets)to populate the application's UI.Key configuration options for the
Appconstructor include:fg_color: Foreground color of the root gadget. IfNone, it queries the terminal.bg_color: Background color of the root gadget. IfNone, it queries the terminal.title: The terminal's title.inline: IfTrue, renders the app inline in the current buffer; otherwise, uses the alternate screen.inline_height: Height of the app ifinlineisTrue.color_theme: AColorThemefor gadgets implementingThemable.double_click_timeout: Max duration (seconds) for a double-click.render_interval: Duration (seconds) between consecutive frame renders (set to0.0for default behavior).
from batgrl import App, Gadget class MyApp(App): async def on_start(self): # Initialize your gadgets here self.add_gadget(MyGadget()) if __name__ == "__main__": app = MyApp(title="My Awesome App", inline=True) app.run()