Skip to content

Instantly share code, notes, and snippets.

@ptmcg
Last active May 19, 2023 17:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ptmcg/3364c98081d6b544c13922584bf1352c to your computer and use it in GitHub Desktop.
Save ptmcg/3364c98081d6b544c13922584bf1352c to your computer and use it in GitHub Desktop.
Textual Class Diagrams

Diagrams

Events

classDiagram
    
    class Message {
        time: float
        is_forwarded: bool
        handler_name: str
        can_replace(message): bool
        prevent_default(prevent: bool): Message
        stop(stop: bool): Message
    }
    
    Message <|-- Event
    Event <|-- Resize
    Event <|-- Compose
    Event <|-- Mount
    Mount <|-- Unmount
    Event <|-- Show
    Event <|-- Hide
    Event <|-- InputEvent
    InputEvent <|-- Key
    InputEvent <|-- MouseEvent
    Event <|-- Timer
    Event <|-- Enter
    Event <|-- Leave
    Event <|-- Focus
    Event <|-- Blur
    Event <|-- Paste
    MouseEvent <|-- Click
    MouseEvent <|-- MouseDown
    MouseEvent <|-- MouseUp
    MouseEvent <|-- MouseScrollDown
    MouseEvent <|-- MouseScrollUp
    MouseEvent <|-- MouseMove

Message handler names are composed from the message class name and optionally the message namespace:

        name = camel_to_snake(self.__class__.__name__)
        self._handler_name = (
            f"on_{self.namespace}_{name}" if self.namespace else f"on_{name}"
        )

InputEvents

classDiagram
    
    
    class InputEvent{
    }
    
    class Key {
        key: str
        character: str
        name: str
        is_printable: bool
        aliases: list[str]
    }

    class MouseEvent {
        x: int
        y: int
        delta_x: int
        delta_y: int
        button: int
        shift: bool
        meta: bool
        ctrl: bool
        screen_x: int
        screen_y: int
        style: Style
    }
    Event <|-- InputEvent
    InputEvent <|-- Key
    InputEvent <|-- MouseEvent
    MouseEvent <|-- Click
    MouseEvent <|-- MouseDown
    MouseEvent <|-- MouseUp
    MouseEvent <|-- MouseScrollDown
    MouseEvent <|-- MouseScrollUp
    MouseEvent <|-- MouseMove
    

More Events

classDiagram
    
    Event <|-- Callback
    Event <|-- ShutdownRequest
    Event <|-- Shutdown
    Event <|-- Load
    Event <|-- Idle
    Event <|-- Action
    Event <|-- Ready
    Event <|-- MouseCapture
    Event <|-- MouseRelease
    Event <|-- DescendantFocus
    Event <|-- DescendantBlur
    Event <|-- ScreenResume
    Event <|-- ScreenSuspend

Diagrams

Widget

classDiagram
    class Widget {
        can_focus: bool = False
        can_focus_children: bool = True
        expand: Reactive[bool] = False
        shrink: Reactive[bool] = True
        auto_links: Reactive[bool] = True
        disabled: Reactive[bool] = False
        hover_style: Reactive[Style] = Style
        highlight_link_id: Reactive[str] = ""

        virtual_size: Reactive[Size] = Size#40;0, 0#41;
        has_focus: Reactive[bool] = False
        mouse_over: Reactive[bool] = False
        scroll_x: Reactive[float] = 0.0
        scroll_y: Reactive[float] = 0.0
        scroll_target_x = 0.0
        scroll_target_y = 0.0
        show_vertical_scrollbar: Reactive[bool] = False
        show_horizontal_scrollbar: Reactive[bool] = False
        border_title: str | Text | None = _BorderTitle
        border_subtitle: str | Text | None = _BorderTitle

        siblings: list[Widget]
        visible_siblings: list[Widget]
        allow_vertical_scroll: bool
        allow_horizontal_scroll: bool
        offset: Offset

        get_child_by_id(id: str) Widget
        get_widget_by_id(id: str) Widget
        get_child_by_type(expect_type: type) Widget
        get_component_rich_style(name: str, partial: bool) Style
        render_str(text: str) Text
        mount(*widgets: Widget, before, after) AwaitMount
        mount_all(*widgets: Widget, before, after) AwaitMount
        move_child(child: Widget, before, after)
        compose() ComposeResult
        get_content_width(container: Size, viewport: Size) int
        get_content_height(container: Size, viewport: Size, width: int) int
        
        max_scroll_x: int
        max_scroll_y: int
        scrollbar_corner: ScrollBarCorner
        vertical_scrollbar: ScrollBar
        horizontal_scrollbar: ScrollBar
        scrollbars_enabled: tuple[bool, bool]
        scrollbars_space: tuple[int, int]
        scrollbar_size_vertical: int
        scrollbar_size_horizontal: int
        scrollbar_gutter: Spacing
        gutter: Spacing
        size: Size
        outer_size: Size
        container_size: Size
        content_region: Region
        scrollable_content_region: Region
        content_offset: Offset
        content_size: Size
        region: Region
        container_viewport: Region
        virtual_region: Region
        window_region: Region
        virtual_region_with_margin: Region
        focusable: bool
        focusable_children: list[Widget]
        scroll_offset: Offset
        is_transparent: bool
        animate(attribute, value, final_value, duration, speed, delay, easing, on_complete)
        is_container: bool
        is_scrollable: bool
        layer: str
        layers: tuple[str,...]
        link_style: Style
        link_hover_style: Style
        scroll_to(x, y, animate, speed, duration, easing, force)
        scroll_relative(x, y, animate, speed, duration, easing, force)
        scroll_home(animate, speed, duration, easing, force)
        scroll_end(animate, speed, duration, easing, force)
        scroll_left(animate, speed, duration, easing, force)
        scroll_right(animate, speed, duration, easing, force)
        scroll_down(animate, speed, duration, easing, force)
        scroll_up(animate, speed, duration, easing, force)
        scroll_page_down(animate, speed, duration, easing, force)
        scroll_page_up(animate, speed, duration, easing, force)
        scroll_page_left(animate, speed, duration, easing, force)
        scroll_page_right(animate, speed, duration, easing, force)
        scroll_to_widget(widget, animate, speed, duration, easing, force)
        scroll_to_region(region, spacing, animate, speed, duration, easing, force)
        scroll_visible(animate, speed, duration, top, easing, force)
        scroll_to_center(widget, animate, speed, duration, easing, force)
        render_line(y): Strip
        render_lines(crop): list[Strip]
        get_style_at(x, y): Style
        refresh(*regions, repaint, layout): Self
        remove(): AwaitRemove
        render(): RenderableType
        run_action(action:str)
        post_message(message): bool
        focus(scroll_visible): Self
        reset_focus(scroll_visible): Self
        capture_mouse(capture)
        release_mouse()
        check_message_enabled(message): bool
        action_scroll_home()
        action_scroll_end()
        action_scroll_left()
        action_scroll_right()
        action_scroll_up()
        action_scroll_down()
        action_page_down()
        action_page_up()
        
        
        __enter__()
        __exit__()
    }
classDiagram
direction LR

Widget <|-- ScrollBar
Widget <|-- ScrollBarCorner
Widget <|-- Container
Widget <|-- ScrollableContainer
Widget <|-- Vertical
Widget <|-- Horizontal
Widget <|-- Center
Widget <|-- Middle
Widget <|-- Grid
Widget <|-- Screen
Widget <|-- Static
Widget <|-- Footer
Widget <|-- HeaderIcon
Widget <|-- HeaderClockSpace
Widget <|-- HeaderTitle
Widget <|-- Header
Widget <|-- Input
Widget <|-- ListItem
Widget <|-- LoadingIndicator
Widget <|-- MarkdownTableContent
Widget <|-- MarkdownBullet
Widget <|-- Markdown
Widget <|-- MarkdownTableOfContents
Widget <|-- Placeholder
Widget <|-- Pretty
Widget <|-- Bar
Widget <|-- ProgressBar
Widget <|-- Switch
Widget <|-- Underline
Widget <|-- Tabs
Widget <|-- TabPane
Widget <|-- TabbedContent
Container <|-- ContentSwitcher
Container <|-- RadioSet
ScrollableContainer <|-- VerticalScroll
ScrollableContainer <|-- HorizontalScroll
ScrollableContainer <|-- ScrollView
Vertical <|-- Select
Horizontal <|-- SelectCurrent
Screen <|-- ModalScreen
Static <|-- Button
Static <|-- ToggleButton
Static <|-- Label
Static <|-- MarkdownBlock
Static <|-- Tab
Static <|-- Welcome
HeaderClockSpace <|-- HeaderClock
VerticalScroll <|-- ListView
VerticalScroll <|-- MarkdownViewer
ScrollView <|-- DataTable
ScrollView <|-- Tree
ScrollView <|-- OptionList
ScrollView <|-- TextLog
ToggleButton <|-- Checkbox
ToggleButton <|-- RadioButton
Label <|-- PercentageStatus
Label <|-- ETAStatus
MarkdownBlock <|-- MarkdownHeader
MarkdownBlock <|-- MarkdownHorizontalRule
MarkdownBlock <|-- MarkdownParagraph
MarkdownBlock <|-- MarkdownBlockQuote
MarkdownBlock <|-- MarkdownList
MarkdownBlock <|-- MarkdownTable
MarkdownBlock <|-- MarkdownTBody
MarkdownBlock <|-- MarkdownTHead
MarkdownBlock <|-- MarkdownTR
MarkdownBlock <|-- MarkdownTH
MarkdownBlock <|-- MarkdownTD
MarkdownBlock <|-- MarkdownListItem
MarkdownBlock <|-- MarkdownFence
Tab <|-- ContentTab
Tree <|-- DirectoryTree
OptionList <|-- SelectOverlay
MarkdownHeader <|-- MarkdownH1
MarkdownHeader <|-- MarkdownH2
MarkdownHeader <|-- MarkdownH3
MarkdownHeader <|-- MarkdownH4
MarkdownHeader <|-- MarkdownH5
MarkdownHeader <|-- MarkdownH6
MarkdownList <|-- MarkdownBulletList
MarkdownList <|-- MarkdownOrderedList
MarkdownListItem <|-- MarkdownOrderedListItem
MarkdownListItem <|-- MarkdownUnorderedListItem

@ptmcg
Copy link
Author

ptmcg commented May 19, 2023

Code used to generate the widgets.md file:

from collections import deque
from contextlib import redirect_stdout
import io
from pathlib import Path

# import all modules containing subclasses
from textual.widget import *
from textual.scrollbar import *
from textual.containers import *
from textual.screen import *
from textual.scroll_view import *
from textual.widgets import *


def get_subclasses(base: type):
    to_visit = deque([(base, "")])
    while to_visit:
        cls, parent_name = to_visit.popleft()
        cls_name = cls.__name__
        if parent_name:
            print(f"{parent_name} <|-- {cls_name}")
        to_visit.extend(
            (sub, cls_name) for sub in cls.__subclasses__()
        )


stdout_buffer = io.StringIO()
with redirect_stdout(stdout_buffer):
    get_subclasses(Widget)

script_dir = Path(__file__).parent
markdown = """
```mermaid
classDiagram
direction LR

"""
markdown += stdout_buffer.getvalue()
markdown += "\n```"

(script_dir / "widgets.md").write_text(
    markdown
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment