diff --git a/.github/workflows/black_format.yml b/.github/workflows/black_format.yml new file mode 100644 index 000000000..063068c35 --- /dev/null +++ b/.github/workflows/black_format.yml @@ -0,0 +1,22 @@ + +name: Black format check + +on: + pull_request: + paths: + - '.github/workflows/black_format.yml' + - '**.py' + +jobs: + black-format-check: + runs-on: "ubuntu-latest" + steps: + - uses: actions/checkout@v3.5.2 + - name: Set up Python 3.11 + uses: actions/setup-python@v4.6.0 + with: + python-version: 3.11 + - name: Install black + run: python -m pip install black + - name: Run black + run: black --check src diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml index 46cf1677f..d26259360 100644 --- a/.github/workflows/comment.yml +++ b/.github/workflows/comment.yml @@ -1,7 +1,8 @@ -name: issues +name: Closed issue comment on: issues: types: [closed] + jobs: add-comment: runs-on: ubuntu-latest @@ -14,5 +15,5 @@ jobs: issue-number: ${{ github.event.issue.number }} body: | Don't forget to [star](https://github.com/Textualize/textual) the repository! - + Follow [@textualizeio](https://twitter.com/textualizeio) for Textual updates. diff --git a/.github/workflows/new_issue.yml b/.github/workflows/new_issue.yml index 3dd9d9a3a..cb55213ec 100644 --- a/.github/workflows/new_issue.yml +++ b/.github/workflows/new_issue.yml @@ -1,7 +1,8 @@ -name: issues +name: FAQ issue comment on: issues: types: [opened] + jobs: add-comment: if: ${{ !contains( 'willmcgugan,darrenburns,davep,rodrigogiraoserrao', github.actor ) }} diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 2891b4bcf..27f36d406 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,6 +3,7 @@ name: Test Textual module on: pull_request: paths: + - '.github/workflows/pythonpackage.yml' - '**.py' - '**.pyi' - '**.css' @@ -21,27 +22,28 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - architecture: x64 - - name: Install and configure Poetry + - uses: actions/checkout@v3.5.2 + - name: Install and configure Poetry # This could be cached, too... uses: snok/install-poetry@v1.3.3 with: version: 1.4.2 virtualenvs-in-project: true + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4.6.0 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v3 + with: + path: .venv + key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies run: poetry install --extras "dev" if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - - name: Format check with black - run: | - source $VENV - make format-check # - name: Typecheck with mypy # run: | -# source $VENV # make typecheck - name: Test with pytest run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 07ac9ab9c..c6ccdb9fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - App `title` and `sub_title` attributes can be set to any type https://github.com/Textualize/textual/issues/2521 - `DirectoryTree` now loads directory contents in a worker https://github.com/Textualize/textual/issues/2456 +- Using `Widget.move_child` where the target and the child being moved are the same is now a no-op https://github.com/Textualize/textual/issues/1743 +- Calling `dismiss` on a screen that is not at the top of the stack now raises an exception https://github.com/Textualize/textual/issues/2575 ### Fixed @@ -20,6 +22,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed `TreeNode.collapse` and `TreeNode.collapse_all` not posting a `Tree.NodeCollapsed` message https://github.com/Textualize/textual/issues/2535 - Fixed `TreeNode.toggle` and `TreeNode.toggle_all` not posting a `Tree.NodeExpanded` or `Tree.NodeCollapsed` message https://github.com/Textualize/textual/issues/2535 - `footer--description` component class was being ignored https://github.com/Textualize/textual/issues/2544 +- Pasting empty selection in `Input` would raise an exception https://github.com/Textualize/textual/issues/2563 + +### Added + +- Class variable `AUTO_FOCUS` to screens https://github.com/Textualize/textual/issues/2457 ## [0.24.1] - 2023-05-08 diff --git a/docs/examples/guide/screens/modal02.py b/docs/examples/guide/screens/modal02.py index bb6c49c59..418030f80 100644 --- a/docs/examples/guide/screens/modal02.py +++ b/docs/examples/guide/screens/modal02.py @@ -42,6 +42,7 @@ class ModalApp(App): yield Footer() def action_request_quit(self) -> None: + """Action to display the quit dialog.""" self.push_screen(QuitScreen()) diff --git a/docs/examples/guide/screens/modal03.py b/docs/examples/guide/screens/modal03.py new file mode 100644 index 000000000..e19fc527b --- /dev/null +++ b/docs/examples/guide/screens/modal03.py @@ -0,0 +1,57 @@ +from textual.app import App, ComposeResult +from textual.containers import Grid +from textual.screen import ModalScreen +from textual.widgets import Button, Footer, Header, Label + +TEXT = """I must not fear. +Fear is the mind-killer. +Fear is the little-death that brings total obliteration. +I will face my fear. +I will permit it to pass over me and through me. +And when it has gone past, I will turn the inner eye to see its path. +Where the fear has gone there will be nothing. Only I will remain.""" + + +class QuitScreen(ModalScreen[bool]): # (1)! + """Screen with a dialog to quit.""" + + def compose(self) -> ComposeResult: + yield Grid( + Label("Are you sure you want to quit?", id="question"), + Button("Quit", variant="error", id="quit"), + Button("Cancel", variant="primary", id="cancel"), + id="dialog", + ) + + def on_button_pressed(self, event: Button.Pressed) -> None: + if event.button.id == "quit": + self.dismiss(True) + else: + self.dismiss(False) + + +class ModalApp(App): + """An app with a modal dialog.""" + + CSS_PATH = "modal01.css" + BINDINGS = [("q", "request_quit", "Quit")] + + def compose(self) -> ComposeResult: + yield Header() + yield Label(TEXT * 8) + yield Footer() + + def action_request_quit(self) -> None: + """Action to display the quit dialog.""" + + def check_quit(quit: bool) -> None: + """Called when QuitScreen is dismissed.""" + if quit: + self.exit() + + self.push_screen(QuitScreen(), check_quit) + + +if __name__ == "__main__": + app = ModalApp() + app.run() diff --git a/docs/guide/screens.md b/docs/guide/screens.md index fe8e3616f..0119ef655 100644 --- a/docs/guide/screens.md +++ b/docs/guide/screens.md @@ -219,3 +219,40 @@ Let's see what happens when we use `ModalScreen`. Now when we press ++q++, the dialog is displayed over the main screen. The main screen is darkened to indicate to the user that it is not active, and only the dialog will respond to input. + +## Returning data from screens + +It is a common requirement for screens to be able to return data. +For instance, you may want a screen to show a dialog and have the result of that dialog processed *after* the screen has been popped. + +To return data from a screen, call [`dismiss()`][textual.screen.dismiss] on the screen with the data you wish to return. +This will pop the screen and invoke a callback set when the screen was pushed (with [`push_screen`][textual.app.push_screen]). + +Let's modify the previous example to use `dismiss` rather than an explicit `pop_screen`. + +=== "modal03.py" + + ```python title="modal03.py" hl_lines="15 27-30 47-50 52" + --8<-- "docs/examples/guide/screens/modal03.py" + ``` + + 1. See below for an explanation of the `[bool]` + +=== "modal01.css" + + ```sass title="modal01.css" + --8<-- "docs/examples/guide/screens/modal01.css" + ``` + +In the `on_button_pressed` message handler we call `dismiss` with a boolean that indicates if the user has chosen to quit the app. +This boolean is passed to the `check_quit` function we provided when `QuitScreen` was pushed. + +Although this example behaves the same as the previous code, it is more flexible because it has removed responsibility for exiting from the modal screen to the caller. +This makes it easier for the app to perform any cleanup actions prior to exiting, for example. + +Returning data in this way can help keep your code manageable by making it easy to re-use your `Screen` classes in other contexts. + +### Typing screen results + +You may have noticed in the previous example that we changed the base class to `ModalScreen[bool]`. +The addition of `[bool]` adds typing information that tells the type checker to expect a boolean in the call to `dismiss`, and that any callback set in `push_screen` should also expect the same type. As always, typing is optional in Textual, but this may help you catch bugs. diff --git a/reference/spacing.monopic b/reference/spacing.monopic new file mode 100644 index 000000000..474d7d3ad Binary files /dev/null and b/reference/spacing.monopic differ diff --git a/src/textual/_arrange.py b/src/textual/_arrange.py index b415d8983..87879573a 100644 --- a/src/textual/_arrange.py +++ b/src/textual/_arrange.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections import defaultdict from fractions import Fraction from operator import attrgetter -from typing import TYPE_CHECKING, Sequence +from typing import TYPE_CHECKING, Iterable, Mapping, Sequence from ._layout import DockArrangeResult, WidgetPlacement from ._partition import partition @@ -16,6 +16,21 @@ if TYPE_CHECKING: TOP_Z = 2**31 - 1 +def _build_dock_layers(widgets: Iterable[Widget]) -> Mapping[str, Sequence[Widget]]: + """Organize widgets into layers. + + Args: + widgets: The widgets. + + Returns: + A mapping of layer name onto the widgets within the layer. + """ + layers: defaultdict[str, list[Widget]] = defaultdict(list) + for widget in widgets: + layers[widget.layer].append(widget) + return layers + + def arrange( widget: Widget, children: Sequence[Widget], size: Size, viewport: Size ) -> DockArrangeResult: @@ -30,107 +45,120 @@ def arrange( Widget arrangement information. """ - arrange_widgets: set[Widget] = set() - - dock_layers: defaultdict[str, list[Widget]] = defaultdict(list) - for child in children: - if child.display: - dock_layers[child.layer].append(child) - - width, height = size - placements: list[WidgetPlacement] = [] - add_placement = placements.append - - _WidgetPlacement = WidgetPlacement - top_z = TOP_Z scroll_spacing = Spacing() - null_spacing = Spacing() get_dock = attrgetter("styles.dock") styles = widget.styles + # Widgets which will be displayed + display_widgets = [child for child in children if child.styles.display != "none"] + + # Widgets organized into layers + dock_layers = _build_dock_layers(display_widgets) + layer_region = size.region for widgets in dock_layers.values(): region = layer_region + # Partition widgets into "layout" widgets (those that appears in the normal 'flow' of the + # document), and "dock" widgets which are positioned relative to an edge layout_widgets, dock_widgets = partition(get_dock, widgets) - arrange_widgets.update(dock_widgets) - top = right = bottom = left = 0 - - for dock_widget in dock_widgets: - edge = dock_widget.styles.dock - - box_model = dock_widget._get_box_model( - size, viewport, Fraction(size.width), Fraction(size.height) - ) - widget_width_fraction, widget_height_fraction, margin = box_model - - widget_width = int(widget_width_fraction) + margin.width - widget_height = int(widget_height_fraction) + margin.height - - if edge == "bottom": - dock_region = Region( - 0, height - widget_height, widget_width, widget_height - ) - bottom = max(bottom, widget_height) - elif edge == "top": - dock_region = Region(0, 0, widget_width, widget_height) - top = max(top, widget_height) - elif edge == "left": - dock_region = Region(0, 0, widget_width, widget_height) - left = max(left, widget_width) - elif edge == "right": - dock_region = Region( - width - widget_width, 0, widget_width, widget_height - ) - right = max(right, widget_width) - else: - # Should not occur, mainly to keep Mypy happy - raise AssertionError("invalid value for edge") # pragma: no-cover - - align_offset = dock_widget.styles._align_size( - (widget_width, widget_height), size - ) - dock_region = dock_region.shrink(margin).translate(align_offset) - add_placement( - _WidgetPlacement(dock_region, null_spacing, dock_widget, top_z, True) - ) - - dock_spacing = Spacing(top, right, bottom, left) - region = region.shrink(dock_spacing) - layout_placements, arranged_layout_widgets = widget._layout.arrange( - widget, layout_widgets, region.size + # Arrange docked widgets + _dock_placements, dock_spacing = _arrange_dock_widgets( + dock_widgets, size, viewport ) - if arranged_layout_widgets: + placements.extend(_dock_placements) + + # Reduce the region to compensate for docked widgets + region = region.shrink(dock_spacing) + + if layout_widgets: + # Arrange layout widgets (i.e. not docked) + layout_placements = widget._layout.arrange( + widget, + layout_widgets, + region.size, + ) + scroll_spacing = scroll_spacing.grow_maximum(dock_spacing) - arrange_widgets.update(arranged_layout_widgets) placement_offset = region.offset + # Perform any alignment of the widgets. if styles.align_horizontal != "left" or styles.align_vertical != "top": - placement_size = Region.from_union( - [ - placement.region.grow(placement.margin) - for placement in layout_placements - ] - ).size + bounding_region = WidgetPlacement.get_bounds(layout_placements) placement_offset += styles._align_size( - placement_size, region.size + bounding_region.size, region.size ).clamped if placement_offset: - layout_placements = [ - _WidgetPlacement( - _region + placement_offset, - margin, - layout_widget, - order, - fixed, - overlay, - ) - for _region, margin, layout_widget, order, fixed, overlay in layout_placements - ] + # Translate placements if required. + layout_placements = WidgetPlacement.translate( + layout_placements, placement_offset + ) - placements.extend(layout_placements) + placements.extend(layout_placements) - return DockArrangeResult(placements, arrange_widgets, scroll_spacing) + return DockArrangeResult(placements, set(display_widgets), scroll_spacing) + + +def _arrange_dock_widgets( + dock_widgets: Sequence[Widget], size: Size, viewport: Size +) -> tuple[list[WidgetPlacement], Spacing]: + """Arrange widgets which are *docked*. + + Args: + dock_widgets: Widgets with a non-empty dock. + size: Size of the container. + viewport: Size of the viewport. + + Returns: + A tuple of widget placements, and additional spacing around them + """ + _WidgetPlacement = WidgetPlacement + top_z = TOP_Z + width, height = size + null_spacing = Spacing() + + top = right = bottom = left = 0 + + placements: list[WidgetPlacement] = [] + append_placement = placements.append + + for dock_widget in dock_widgets: + edge = dock_widget.styles.dock + + box_model = dock_widget._get_box_model( + size, viewport, Fraction(size.width), Fraction(size.height) + ) + widget_width_fraction, widget_height_fraction, margin = box_model + + widget_width = int(widget_width_fraction) + margin.width + widget_height = int(widget_height_fraction) + margin.height + + if edge == "bottom": + dock_region = Region(0, height - widget_height, widget_width, widget_height) + bottom = max(bottom, widget_height) + elif edge == "top": + dock_region = Region(0, 0, widget_width, widget_height) + top = max(top, widget_height) + elif edge == "left": + dock_region = Region(0, 0, widget_width, widget_height) + left = max(left, widget_width) + elif edge == "right": + dock_region = Region(width - widget_width, 0, widget_width, widget_height) + right = max(right, widget_width) + else: + # Should not occur, mainly to keep Mypy happy + raise AssertionError("invalid value for edge") # pragma: no-cover + + align_offset = dock_widget.styles._align_size( + (widget_width, widget_height), size + ) + dock_region = dock_region.shrink(margin).translate(align_offset) + append_placement( + _WidgetPlacement(dock_region, null_spacing, dock_widget, top_z, True) + ) + dock_spacing = Spacing(top, right, bottom, left) + + return (placements, dock_spacing) diff --git a/src/textual/_layout.py b/src/textual/_layout.py index e0061c148..338b72192 100644 --- a/src/textual/_layout.py +++ b/src/textual/_layout.py @@ -2,17 +2,17 @@ from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import TYPE_CHECKING, ClassVar, NamedTuple +from typing import TYPE_CHECKING, ClassVar, Iterable, NamedTuple from ._spatial_map import SpatialMap -from .geometry import Region, Size, Spacing +from .geometry import Offset, Region, Size, Spacing if TYPE_CHECKING: from typing_extensions import TypeAlias from .widget import Widget -ArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget]]" +ArrangeResult: TypeAlias = "list[WidgetPlacement]" @dataclass @@ -76,6 +76,41 @@ class WidgetPlacement(NamedTuple): fixed: bool = False overlay: bool = False + @classmethod + def translate( + cls, placements: list[WidgetPlacement], offset: Offset + ) -> list[WidgetPlacement]: + """Move all placements by a given offset. + + Args: + placements: List of placements. + offset: Offset to add to placements. + + Returns: + Placements with adjusted region, or same instance if offset is null. + """ + if offset: + return [ + cls(region + offset, margin, layout_widget, order, fixed, overlay) + for region, margin, layout_widget, order, fixed, overlay in placements + ] + return placements + + @classmethod + def get_bounds(cls, placements: Iterable[WidgetPlacement]) -> Region: + """Get a bounding region around all placements. + + Args: + placements: A number of placements. + + Returns: + An optimal binding box around all placements. + """ + bounding_region = Region.from_union( + [placement.region.grow(placement.margin) for placement in placements] + ) + return bounding_region + class Layout(ABC): """Responsible for arranging Widgets in a view and rendering them.""" diff --git a/src/textual/app.py b/src/textual/app.py index 12f66cf04..841d854e2 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -156,7 +156,7 @@ class ScreenError(Exception): class ScreenStackError(ScreenError): - """Raised when attempting to pop the last screen from the stack.""" + """Raised when trying to manipulate the screen stack incorrectly.""" class CssPathError(Exception): @@ -1416,7 +1416,7 @@ class App(Generic[ReturnType], DOMNode): Args: screen: A Screen instance or the name of an installed screen. - callback: An optional callback function that is called if the screen is dismissed with a result. + callback: An optional callback function that will be called if the screen is [dismissed][textual.screen.Screen.dismiss] with a result. Returns: An optional awaitable that awaits the mounting of the screen and its children. diff --git a/src/textual/dom.py b/src/textual/dom.py index e136a5588..c6efd1c4f 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -887,7 +887,7 @@ class DOMNode(MessagePump): Example: - Here's how you could detect when the app changes from dark to light mode (and visa versa). + Here's how you could detect when the app changes from dark to light mode (and vice versa). ```python def on_dark_change(old_value:bool, new_value:bool): diff --git a/src/textual/geometry.py b/src/textual/geometry.py index 32dbd0a7d..4b337a4d9 100644 --- a/src/textual/geometry.py +++ b/src/textual/geometry.py @@ -853,7 +853,7 @@ class Region(NamedTuple): Args: cut: An offset from self.y where the cut should be made. May be negative, - for the offset to start from the bottom edge. + for the offset to start from the lower edge. Returns: Two regions, which add up to the original (self). @@ -909,7 +909,19 @@ class Region(NamedTuple): class Spacing(NamedTuple): """The spacing around a renderable, such as padding and border - Spacing is defined by four integers for the space at the top, right, bottom, and left of a region, + Spacing is defined by four integers for the space at the top, right, bottom, and left of a region. + + ``` + ┌ ─ ─ ─ ─ ─ ─ ─▲─ ─ ─ ─ ─ ─ ─ ─ ┐ + │ top + │ ┏━━━━━▼━━━━━━┓ │ + ◀──────▶┃ ┃◀───────▶ + │ left ┃ ┃ right │ + ┃ ┃ + │ ┗━━━━━▲━━━━━━┛ │ + │ bottom + └ ─ ─ ─ ─ ─ ─ ─▼─ ─ ─ ─ ─ ─ ─ ─ ┘ + ``` Example: ```python diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index 3ade70ab2..3b030f30f 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -156,4 +156,4 @@ class GridLayout(Layout): add_placement(WidgetPlacement(region, margin, widget)) add_widget(widget) - return (placements, set(widgets)) + return placements diff --git a/src/textual/layouts/horizontal.py b/src/textual/layouts/horizontal.py index d2fb3146e..a1c4eea4a 100644 --- a/src/textual/layouts/horizontal.py +++ b/src/textual/layouts/horizontal.py @@ -65,8 +65,6 @@ class HorizontalLayout(Layout): x = Fraction(box_models[0].margin.left if box_models else 0) - displayed_children = [child for child in children if child.display] - _Region = Region _WidgetPlacement = WidgetPlacement for widget, box_model, margin in zip(children, box_models, margins): @@ -86,4 +84,4 @@ class HorizontalLayout(Layout): if not overlay: x = next_x + margin - return placements, set(displayed_children) + return placements diff --git a/src/textual/layouts/vertical.py b/src/textual/layouts/vertical.py index 0001efdb6..c74332535 100644 --- a/src/textual/layouts/vertical.py +++ b/src/textual/layouts/vertical.py @@ -86,4 +86,4 @@ class VerticalLayout(Layout): if not overlay: y = next_y + margin - return placements, set(children) + return placements diff --git a/src/textual/screen.py b/src/textual/screen.py index 34db473ef..535b621ea 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -9,6 +9,7 @@ from typing import ( TYPE_CHECKING, Awaitable, Callable, + ClassVar, Generic, Iterable, Iterator, @@ -30,7 +31,7 @@ from ._types import CallbackType from .binding import Binding from .css.match import match from .css.parse import parse_selectors -from .css.query import QueryType +from .css.query import NoMatches, QueryType from .dom import DOMNode from .geometry import Offset, Region, Size from .reactive import Reactive @@ -93,6 +94,13 @@ class ResultCallback(Generic[ScreenResultType]): class Screen(Generic[ScreenResultType], Widget): """The base class for screens.""" + AUTO_FOCUS: ClassVar[str | None] = "*" + """A selector to determine what to focus automatically when the screen is activated. + + The widget focused is the first that matches the given [CSS selector](/guide/queries/#query-selectors). + Set to `None` to disable auto focus. + """ + DEFAULT_CSS = """ Screen { layout: vertical; @@ -100,7 +108,6 @@ class Screen(Generic[ScreenResultType], Widget): background: $surface; } """ - focused: Reactive[Widget | None] = Reactive(None) """The focused [widget][textual.widget.Widget] or `None` for no focus.""" stack_updates: Reactive[int] = Reactive(0, repaint=False) @@ -659,6 +666,13 @@ class Screen(Generic[ScreenResultType], Widget): """Screen has resumed.""" self.stack_updates += 1 size = self.app.size + if self.AUTO_FOCUS is not None and self.focused is None: + try: + to_focus = self.query(self.AUTO_FOCUS).first() + except NoMatches: + pass + else: + self.set_focus(to_focus) self._refresh_layout(size, full=True) self.refresh() @@ -754,16 +768,23 @@ class Screen(Generic[ScreenResultType], Widget): def dismiss(self, result: ScreenResultType | Type[_NoResult] = _NoResult) -> None: """Dismiss the screen, optionally with a result. + If `result` is provided and a callback was set when the screen was [pushed][textual.app.push_screen], then + the callback will be invoked with `result`. + Args: result: The optional result to be passed to the result callback. - Note: - If the screen was pushed with a callback, the callback will be - called with the given result and then a call to - [`App.pop_screen`][textual.app.App.pop_screen] is performed. If - no callback was provided calling this method is the same as - simply calling [`App.pop_screen`][textual.app.App.pop_screen]. + Raises: + ScreenStackError: If trying to dismiss a screen that is not at the top of + the stack. + """ + if self is not self.app.screen: + from .app import ScreenStackError + + raise ScreenStackError( + f"Can't dismiss screen {self} that's not at the top of the stack." + ) if result is not self._NoResult and self._result_callbacks: self._result_callbacks[-1](cast(ScreenResultType, result)) self.app.pop_screen() diff --git a/src/textual/strip.py b/src/textual/strip.py index 554acdecf..c1f9e2587 100644 --- a/src/textual/strip.py +++ b/src/textual/strip.py @@ -379,16 +379,22 @@ class Strip: """ pos = 0 + cell_length = self.cell_length + cuts = [cut for cut in cuts if cut <= cell_length] cache_key = tuple(cuts) cached = self._divide_cache.get(cache_key) if cached is not None: return cached - strips: list[Strip] = [] - add_strip = strips.append - for segments, cut in zip(Segment.divide(self._segments, cuts), cuts): - add_strip(Strip(segments, cut - pos)) - pos = cut + strips: list[Strip] + if cuts == [cell_length]: + strips = [self] + else: + strips = [] + add_strip = strips.append + for segments, cut in zip(Segment.divide(self._segments, cuts), cuts): + add_strip(Strip(segments, cut - pos)) + pos = cut self._divide_cache[cache_key] = strips return strips diff --git a/src/textual/widget.py b/src/textual/widget.py index 4fc364ebf..b116f5393 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -795,19 +795,15 @@ class Widget(DOMNode): Args: child: The child widget to move. - before: Optional location to move before. An `int` is the index - of the child to move before, a `str` is a `query_one` query to - find the widget to move before. - after: Optional location to move after. An `int` is the index - of the child to move after, a `str` is a `query_one` query to - find the widget to move after. + before: Child widget or location index to move before. + after: Child widget or location index to move after. Raises: WidgetError: If there is a problem with the child or target. Note: - Only one of ``before`` or ``after`` can be provided. If neither - or both are provided a ``WidgetError`` will be raised. + Only one of `before` or `after` can be provided. If neither + or both are provided a `WidgetError` will be raised. """ # One or the other of before or after are required. Can't do @@ -817,6 +813,10 @@ class Widget(DOMNode): elif before is not None and after is not None: raise WidgetError("Only one of `before` or `after` can be handled.") + # We short-circuit the no-op, otherwise it will error later down the road. + if child is before or child is after: + return + def _to_widget(child: int | Widget, called: str) -> Widget: """Ensure a given child reference is a Widget.""" if isinstance(child, int): diff --git a/src/textual/widgets/_input.py b/src/textual/widgets/_input.py index 9e5bf2d07..e14dcdf10 100644 --- a/src/textual/widgets/_input.py +++ b/src/textual/widgets/_input.py @@ -332,8 +332,9 @@ class Input(Widget, can_focus=True): event.prevent_default() def _on_paste(self, event: events.Paste) -> None: - line = event.text.splitlines()[0] - self.insert_text_at_cursor(line) + if event.text: + line = event.text.splitlines()[0] + self.insert_text_at_cursor(line) event.stop() async def _on_click(self, event: events.Click) -> None: diff --git a/src/textual/widgets/_option_list.py b/src/textual/widgets/_option_list.py index 3b9413181..dfe530543 100644 --- a/src/textual/widgets/_option_list.py +++ b/src/textual/widgets/_option_list.py @@ -627,11 +627,17 @@ class OptionList(ScrollView, can_focus=True): """ self._contents.clear() self._options.clear() - self._refresh_content_tracking(force=True) self.highlighted = None self._mouse_hovering_over = None self.virtual_size = Size(self.scrollable_content_region.width, 0) - self.refresh() + # TODO: See https://github.com/Textualize/textual/issues/2582 -- it + # should not be necessary to do this like this here; ideally here in + # clear_options it would be a forced refresh, and also in a + # `on_show` it would be the same (which, I think, would actually + # solve the problem we're seeing). But, until such a time as we get + # to the bottom of 2582... this seems to delay the refresh enough + # that things fall into place. + self._request_content_tracking_refresh() return self def _set_option_disabled(self, index: int, disabled: bool) -> Self: diff --git a/src/textual/widgets/_select.py b/src/textual/widgets/_select.py index 25564af95..dddd9e157 100644 --- a/src/textual/widgets/_select.py +++ b/src/textual/widgets/_select.py @@ -185,10 +185,6 @@ class Select(Generic[SelectType], Vertical, can_focus=True): border: tall $accent; } - Select { - height: auto; - } - Select > SelectOverlay { width: 1fr; display: none; diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index cbee7ba35..018558247 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -21,137 +21,138 @@ font-weight: 700; } - .terminal-369237853-matrix { + .terminal-1593336641-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-369237853-title { + .terminal-1593336641-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-369237853-r1 { fill: #c5c8c6 } - .terminal-369237853-r2 { fill: #7ae998 } - .terminal-369237853-r3 { fill: #0a180e;font-weight: bold } - .terminal-369237853-r4 { fill: #008139 } - .terminal-369237853-r5 { fill: #e1e1e1 } - .terminal-369237853-r6 { fill: #e76580 } - .terminal-369237853-r7 { fill: #f5e5e9;font-weight: bold } - .terminal-369237853-r8 { fill: #780028 } + .terminal-1593336641-r1 { fill: #c5c8c6 } + .terminal-1593336641-r2 { fill: #7ae998 } + .terminal-1593336641-r3 { fill: #0a180e;font-weight: bold } + .terminal-1593336641-r4 { fill: #008139 } + .terminal-1593336641-r5 { fill: #e3dbce } + .terminal-1593336641-r6 { fill: #e1e1e1 } + .terminal-1593336641-r7 { fill: #e76580 } + .terminal-1593336641-r8 { fill: #f5e5e9;font-weight: bold } + .terminal-1593336641-r9 { fill: #780028 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AlignContainersApp + AlignContainersApp - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - center - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - middle - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + center + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + middle + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + @@ -346,202 +347,202 @@ font-weight: 700; } - .terminal-2978213952-matrix { + .terminal-3056812568-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2978213952-title { + .terminal-3056812568-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2978213952-r1 { fill: #c5c8c6 } - .terminal-2978213952-r2 { fill: #e3e3e3 } - .terminal-2978213952-r3 { fill: #004578 } - .terminal-2978213952-r4 { fill: #e1e1e1 } - .terminal-2978213952-r5 { fill: #632ca6 } - .terminal-2978213952-r6 { fill: #dde6ed;font-weight: bold } - .terminal-2978213952-r7 { fill: #14191f } - .terminal-2978213952-r8 { fill: #23568b } + .terminal-3056812568-r1 { fill: #c5c8c6 } + .terminal-3056812568-r2 { fill: #e3e3e3 } + .terminal-3056812568-r3 { fill: #004578 } + .terminal-3056812568-r4 { fill: #e1e1e1 } + .terminal-3056812568-r5 { fill: #632ca6 } + .terminal-3056812568-r6 { fill: #dde6ed;font-weight: bold } + .terminal-3056812568-r7 { fill: #14191f } + .terminal-3056812568-r8 { fill: #23568b } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - MyApp + MyApp - - - - MyApp - ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── - oktest - ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ -  0 ────────────────────────────────────── 1 ────────────────────────────────────── 2 ───── - -  Foo       Bar         Baz               Foo       Bar         Baz               Foo      -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY▁▁ ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY▁▁ ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH -  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH - ───────────────────────────────────────────────────────────────────────────────────────────── - - ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── + + + + MyApp + ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── + oktest + ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ +  0 ────────────────────────────────────── 1 ────────────────────────────────────── 2 ───── + +  Foo       Bar         Baz               Foo       Bar         Baz               Foo      +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY▁▁ ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY▁▁ ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH +  ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH  0123456789  IJKLMNOPQRSTUVWXY ABCDEFGH + ───────────────────────────────────────────────────────────────────────────────────────────── + + ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── @@ -571,136 +572,136 @@ font-weight: 700; } - .terminal-3956291897-matrix { + .terminal-1625062503-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3956291897-title { + .terminal-1625062503-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3956291897-r1 { fill: #c5c8c6 } - .terminal-3956291897-r2 { fill: #e3e3e3 } - .terminal-3956291897-r3 { fill: #1e1e1e } - .terminal-3956291897-r4 { fill: #0178d4 } - .terminal-3956291897-r5 { fill: #e1e1e1 } - .terminal-3956291897-r6 { fill: #e2e2e2 } - .terminal-3956291897-r7 { fill: #ddedf9 } + .terminal-1625062503-r1 { fill: #c5c8c6 } + .terminal-1625062503-r2 { fill: #e3e3e3 } + .terminal-1625062503-r3 { fill: #1e1e1e } + .terminal-1625062503-r4 { fill: #0178d4 } + .terminal-1625062503-r5 { fill: #e1e1e1 } + .terminal-1625062503-r6 { fill: #e2e2e2 } + .terminal-1625062503-r7 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - InputWidthAutoApp + InputWidthAutoApp - - - - InputWidthAutoApp - ▔▔▔▔▔▔▔▔▔▔ - Hello - ▁▁▁▁▁▁▁▁▁▁ - - - - - - - - - - - - - - - - - - - + + + + InputWidthAutoApp + ▔▔▔▔▔▔▔▔▔▔ + Hello + ▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + @@ -731,136 +732,137 @@ font-weight: 700; } - .terminal-2059832628-matrix { + .terminal-2470781732-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2059832628-title { + .terminal-2470781732-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2059832628-r1 { fill: #1e1e1e } - .terminal-2059832628-r2 { fill: #c5c8c6 } - .terminal-2059832628-r3 { fill: #183118 } - .terminal-2059832628-r4 { fill: #124512 } - .terminal-2059832628-r5 { fill: #0c580c } - .terminal-2059832628-r6 { fill: #066c06 } - .terminal-2059832628-r7 { fill: #008000 } + .terminal-2470781732-r1 { fill: #1e1e1e } + .terminal-2470781732-r2 { fill: #c5c8c6 } + .terminal-2470781732-r3 { fill: #e1e1e1 } + .terminal-2470781732-r4 { fill: #183118 } + .terminal-2470781732-r5 { fill: #124512 } + .terminal-2470781732-r6 { fill: #0c580c } + .terminal-2470781732-r7 { fill: #066c06 } + .terminal-2470781732-r8 { fill: #008000 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BorderAlphaApp + BorderAlphaApp - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - - - - + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + + @@ -1055,161 +1057,162 @@ font-weight: 700; } - .terminal-3643133712-matrix { + .terminal-619468389-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3643133712-title { + .terminal-619468389-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3643133712-r1 { fill: #c5c8c6 } - .terminal-3643133712-r2 { fill: #e1e1e1;font-weight: bold } - .terminal-3643133712-r3 { fill: #454a50 } - .terminal-3643133712-r4 { fill: #35383c } - .terminal-3643133712-r5 { fill: #24292f;font-weight: bold } - .terminal-3643133712-r6 { fill: #7c7d7e;font-weight: bold } - .terminal-3643133712-r7 { fill: #000000 } - .terminal-3643133712-r8 { fill: #0c0c0c } - .terminal-3643133712-r9 { fill: #507bb3 } - .terminal-3643133712-r10 { fill: #3c5577 } - .terminal-3643133712-r11 { fill: #dde6ed;font-weight: bold } - .terminal-3643133712-r12 { fill: #75828b;font-weight: bold } - .terminal-3643133712-r13 { fill: #001541 } - .terminal-3643133712-r14 { fill: #0c1833 } - .terminal-3643133712-r15 { fill: #7ae998 } - .terminal-3643133712-r16 { fill: #559767 } - .terminal-3643133712-r17 { fill: #0a180e;font-weight: bold } - .terminal-3643133712-r18 { fill: #192e1f;font-weight: bold } - .terminal-3643133712-r19 { fill: #008139 } - .terminal-3643133712-r20 { fill: #0c592e } - .terminal-3643133712-r21 { fill: #ffcf56 } - .terminal-3643133712-r22 { fill: #a5883f } - .terminal-3643133712-r23 { fill: #211505;font-weight: bold } - .terminal-3643133712-r24 { fill: #3a2a13;font-weight: bold } - .terminal-3643133712-r25 { fill: #b86b00 } - .terminal-3643133712-r26 { fill: #7a4c0c } - .terminal-3643133712-r27 { fill: #e76580 } - .terminal-3643133712-r28 { fill: #964858 } - .terminal-3643133712-r29 { fill: #f5e5e9;font-weight: bold } - .terminal-3643133712-r30 { fill: #978186;font-weight: bold } - .terminal-3643133712-r31 { fill: #780028 } - .terminal-3643133712-r32 { fill: #540c24 } + .terminal-619468389-r1 { fill: #e1e1e1 } + .terminal-619468389-r2 { fill: #c5c8c6 } + .terminal-619468389-r3 { fill: #e1e1e1;font-weight: bold } + .terminal-619468389-r4 { fill: #454a50 } + .terminal-619468389-r5 { fill: #35383c } + .terminal-619468389-r6 { fill: #24292f;font-weight: bold } + .terminal-619468389-r7 { fill: #7c7d7e;font-weight: bold } + .terminal-619468389-r8 { fill: #000000 } + .terminal-619468389-r9 { fill: #0c0c0c } + .terminal-619468389-r10 { fill: #507bb3 } + .terminal-619468389-r11 { fill: #3c5577 } + .terminal-619468389-r12 { fill: #dde6ed;font-weight: bold } + .terminal-619468389-r13 { fill: #75828b;font-weight: bold } + .terminal-619468389-r14 { fill: #001541 } + .terminal-619468389-r15 { fill: #0c1833 } + .terminal-619468389-r16 { fill: #7ae998 } + .terminal-619468389-r17 { fill: #559767 } + .terminal-619468389-r18 { fill: #0a180e;font-weight: bold } + .terminal-619468389-r19 { fill: #192e1f;font-weight: bold } + .terminal-619468389-r20 { fill: #008139 } + .terminal-619468389-r21 { fill: #0c592e } + .terminal-619468389-r22 { fill: #ffcf56 } + .terminal-619468389-r23 { fill: #a5883f } + .terminal-619468389-r24 { fill: #211505;font-weight: bold } + .terminal-619468389-r25 { fill: #3a2a13;font-weight: bold } + .terminal-619468389-r26 { fill: #b86b00 } + .terminal-619468389-r27 { fill: #7a4c0c } + .terminal-619468389-r28 { fill: #e76580 } + .terminal-619468389-r29 { fill: #964858 } + .terminal-619468389-r30 { fill: #f5e5e9;font-weight: bold } + .terminal-619468389-r31 { fill: #978186;font-weight: bold } + .terminal-619468389-r32 { fill: #780028 } + .terminal-619468389-r33 { fill: #540c24 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ButtonsApp + ButtonsApp - - - - - Standard ButtonsDisabled Buttons - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - DefaultDefault - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Primary!Primary! - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Success!Success! - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Warning!Warning! - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Error!Error! - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - + + + + + Standard ButtonsDisabled Buttons + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + DefaultDefault + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Primary!Primary! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Success!Success! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Warning!Warning! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Error!Error! + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + @@ -2482,134 +2485,135 @@ font-weight: 700; } - .terminal-2323733830-matrix { + .terminal-1331556511-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2323733830-title { + .terminal-1331556511-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2323733830-r1 { fill: #808080 } - .terminal-2323733830-r2 { fill: #e1e1e1 } - .terminal-2323733830-r3 { fill: #c5c8c6 } - .terminal-2323733830-r4 { fill: #ddedf9 } + .terminal-1331556511-r1 { fill: #808080 } + .terminal-1331556511-r2 { fill: #e1e1e1 } + .terminal-1331556511-r3 { fill: #c5c8c6 } + .terminal-1331556511-r4 { fill: #ddedf9 } + .terminal-1331556511-r5 { fill: #e2e2e2 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AlignAllApp + AlignAllApp - - - - ──────────────────────────────────────────────────────────────────────── - left topcenter topright top - - - - - ──────────────────────────────────────────────────────────────────────── - - ──────────────────────────────────────────────────────────────────────── - - - left middlecenter middleright middle - - - ──────────────────────────────────────────────────────────────────────── - - ──────────────────────────────────────────────────────────────────────── - - - - - - left bottomcenter bottomright bottom - ──────────────────────────────────────────────────────────────────────── + + + + ──────────────────────────────────────────────────────────────────────── + left topcenter topright top + + + + + ──────────────────────────────────────────────────────────────────────── + + ──────────────────────────────────────────────────────────────────────── + + + left middlecenter middleright middle + + + ──────────────────────────────────────────────────────────────────────── + + ──────────────────────────────────────────────────────────────────────── + + + + + + left bottomcenter bottomright bottom + ──────────────────────────────────────────────────────────────────────── @@ -3273,141 +3277,141 @@ font-weight: 700; } - .terminal-1536397390-matrix { + .terminal-1997861159-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1536397390-title { + .terminal-1997861159-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1536397390-r1 { fill: #c5c8c6 } - .terminal-1536397390-r2 { fill: #fea62b } - .terminal-1536397390-r3 { fill: #fea62b;font-weight: bold } - .terminal-1536397390-r4 { fill: #fea62b;font-weight: bold;font-style: italic; } - .terminal-1536397390-r5 { fill: #cc555a;font-weight: bold } - .terminal-1536397390-r6 { fill: #e1e1e1 } - .terminal-1536397390-r7 { fill: #1e1e1e } - .terminal-1536397390-r8 { fill: #1e1e1e;text-decoration: underline; } - .terminal-1536397390-r9 { fill: #fea62b;text-decoration: underline; } - .terminal-1536397390-r10 { fill: #4b4e55;text-decoration: underline; } - .terminal-1536397390-r11 { fill: #4ebf71 } - .terminal-1536397390-r12 { fill: #b93c5b } + .terminal-1997861159-r1 { fill: #e1e1e1 } + .terminal-1997861159-r2 { fill: #c5c8c6 } + .terminal-1997861159-r3 { fill: #fea62b } + .terminal-1997861159-r4 { fill: #fea62b;font-weight: bold } + .terminal-1997861159-r5 { fill: #fea62b;font-weight: bold;font-style: italic; } + .terminal-1997861159-r6 { fill: #cc555a;font-weight: bold } + .terminal-1997861159-r7 { fill: #1e1e1e } + .terminal-1997861159-r8 { fill: #1e1e1e;text-decoration: underline; } + .terminal-1997861159-r9 { fill: #fea62b;text-decoration: underline; } + .terminal-1997861159-r10 { fill: #4b4e55;text-decoration: underline; } + .terminal-1997861159-r11 { fill: #4ebf71 } + .terminal-1997861159-r12 { fill: #b93c5b } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BorderSubTitleAlignAll + BorderSubTitleAlignAll - - - - - - Border titleLef…▁▁▁▁Left▁▁▁▁ - This is the story ofa Pythondeveloper that - Border subtitleCen…▔▔▔▔@@@▔▔▔▔▔ - - - - - - +--------------+Title───────────────── - |had to fill up|nine labelsand ended up redoing it - +-Left-------+──────────────Subtitle - - - - - Title, but really looo… - Title, but r…Title, but reall… - because the first tryhad some labelsthat were too long. - Subtitle, bu…Subtitle, but re… - Subtitle, but really l… - + + + + + + Border titleLef…▁▁▁▁Left▁▁▁▁ + This is the story ofa Pythondeveloper that + Border subtitleCen…▔▔▔▔@@@▔▔▔▔▔ + + + + + + +--------------+Title───────────────── + |had to fill up|nine labelsand ended up redoing it + +-Left-------+──────────────Subtitle + + + + + Title, but really looo… + Title, but r…Title, but reall… + because the first tryhad some labelsthat were too long. + Subtitle, bu…Subtitle, but re… + Subtitle, but really l… + @@ -5014,132 +5018,132 @@ font-weight: 700; } - .terminal-1564714526-matrix { + .terminal-1840966081-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1564714526-title { + .terminal-1840966081-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1564714526-r1 { fill: #e1e1e1 } - .terminal-1564714526-r2 { fill: #c5c8c6 } - .terminal-1564714526-r3 { fill: #ffffff } + .terminal-1840966081-r1 { fill: #e1e1e1 } + .terminal-1840966081-r2 { fill: #c5c8c6 } + .terminal-1840966081-r3 { fill: #ffffff } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - DockAllApp + DockAllApp - - - - - - - ────────────────────────────────────────────────────────── - top - - - - - - - leftright - - - - - - - - bottom - ────────────────────────────────────────────────────────── - - + + + + + + + ────────────────────────────────────────────────────────── + top + + + + + + + leftright + + + + + + + + bottom + ────────────────────────────────────────────────────────── + + @@ -6427,132 +6431,134 @@ font-weight: 700; } - .terminal-2726481143-matrix { + .terminal-2838975926-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2726481143-title { + .terminal-2838975926-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2726481143-r1 { fill: #c5c8c6 } - .terminal-2726481143-r2 { fill: #000000 } - .terminal-2726481143-r3 { fill: #e1e1e1 } + .terminal-2838975926-r1 { fill: #efddef } + .terminal-2838975926-r2 { fill: #c5c8c6 } + .terminal-2838975926-r3 { fill: #000000 } + .terminal-2838975926-r4 { fill: #ddefef } + .terminal-2838975926-r5 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - LayoutApp + LayoutApp - - - - - Layout - - Is - - Vertical - - - LayoutIsHorizontal - - - - - - - - - - - - - - + + + + + Layout + + Is + + Vertical + + + LayoutIsHorizontal + + + + + + + + + + + + + + @@ -7839,140 +7845,141 @@ font-weight: 700; } - .terminal-4172255139-matrix { + .terminal-2245771963-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4172255139-title { + .terminal-2245771963-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4172255139-r1 { fill: #ffffff } - .terminal-4172255139-r2 { fill: #c5c8c6 } - .terminal-4172255139-r3 { fill: #ece5e5 } - .terminal-4172255139-r4 { fill: #eee8e3 } - .terminal-4172255139-r5 { fill: #e7e0e6 } - .terminal-4172255139-r6 { fill: #eae2e4 } - .terminal-4172255139-r7 { fill: #e3ede7 } - .terminal-4172255139-r8 { fill: #e8ede4 } - .terminal-4172255139-r9 { fill: #e1eceb } - .terminal-4172255139-r10 { fill: #eeeddf } + .terminal-2245771963-r1 { fill: #ffffff } + .terminal-2245771963-r2 { fill: #c5c8c6 } + .terminal-2245771963-r3 { fill: #e0e0e0 } + .terminal-2245771963-r4 { fill: #ece5e5 } + .terminal-2245771963-r5 { fill: #eee8e3 } + .terminal-2245771963-r6 { fill: #e7e0e6 } + .terminal-2245771963-r7 { fill: #eae2e4 } + .terminal-2245771963-r8 { fill: #e3ede7 } + .terminal-2245771963-r9 { fill: #e8ede4 } + .terminal-2245771963-r10 { fill: #e1eceb } + .terminal-2245771963-r11 { fill: #eeeddf } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - MarginAllApp + MarginAllApp - - - - ────────────────────────────────────────────────────────────────── - - - - marginmargin: 1  - no marginmargin: 1: 1 51 2 6 - - - - - ────────────────────────────────────────────────────────────────── - - ────────────────────────────────────────────────────────────────── - - - margin-bottom: 4 - - margin-right: margin-left: 3 - 3 - margin-top: 4 - - - - ────────────────────────────────────────────────────────────────── + + + + ────────────────────────────────────────────────────────────────── + + + + marginmargin: 1  + no marginmargin: 1: 1 51 2 6 + + + + + ────────────────────────────────────────────────────────────────── + + ────────────────────────────────────────────────────────────────── + + + margin-bottom: 4 + + margin-right: margin-left: 3 + 3 + margin-top: 4 + + + + ────────────────────────────────────────────────────────────────── @@ -8160,134 +8167,134 @@ font-weight: 700; } - .terminal-987506037-matrix { + .terminal-1398959741-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-987506037-title { + .terminal-1398959741-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-987506037-r1 { fill: #c5c8c6 } - .terminal-987506037-r2 { fill: #e8e0e7 } - .terminal-987506037-r3 { fill: #eae3e5 } - .terminal-987506037-r4 { fill: #ede6e6 } - .terminal-987506037-r5 { fill: #efe9e4 } + .terminal-1398959741-r1 { fill: #c5c8c6 } + .terminal-1398959741-r2 { fill: #e8e0e7 } + .terminal-1398959741-r3 { fill: #eae3e5 } + .terminal-1398959741-r4 { fill: #ede6e6 } + .terminal-1398959741-r5 { fill: #efe9e4 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - MaxWidthApp + MaxWidthApp - - - - - - max-width:  - 50h - - - - - max-width: 999 - - - - - - max-width: 50% - - - - - - max-width: 30 - - + + + + + + max-width:  + 50h + + + + + max-width: 999 + + + + + + max-width: 50% + + + + + + max-width: 30 + + @@ -8637,134 +8644,134 @@ font-weight: 700; } - .terminal-3520697079-matrix { + .terminal-292160688-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3520697079-title { + .terminal-292160688-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3520697079-r1 { fill: #000000 } - .terminal-3520697079-r2 { fill: #0000ff } - .terminal-3520697079-r3 { fill: #c5c8c6 } - .terminal-3520697079-r4 { fill: #ff0000 } - .terminal-3520697079-r5 { fill: #008000 } + .terminal-292160688-r1 { fill: #000000 } + .terminal-292160688-r2 { fill: #0000ff } + .terminal-292160688-r3 { fill: #c5c8c6 } + .terminal-292160688-r4 { fill: #ff0000 } + .terminal-292160688-r5 { fill: #008000 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OffsetApp + OffsetApp - - - - - Chani (offset 0  - ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀-3) - - - - Paul (offset 8 2)▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ - - - - ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ - ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ - - - Duncan (offset 4  - 10) - - - - ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ - - - + + + + + Chani (offset 0  + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀-3) + + + + Paul (offset 8 2)▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + + + + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + + + Duncan (offset 4  + 10) + + + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + + + @@ -9429,136 +9436,136 @@ font-weight: 700; } - .terminal-3720200886-matrix { + .terminal-2990670852-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3720200886-title { + .terminal-2990670852-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3720200886-r1 { fill: #c5c8c6 } - .terminal-3720200886-r2 { fill: #000000 } - .terminal-3720200886-r3 { fill: #008000 } - .terminal-3720200886-r4 { fill: #e5f0e5 } - .terminal-3720200886-r5 { fill: #036a03 } - .terminal-3720200886-r6 { fill: #14191f } + .terminal-2990670852-r1 { fill: #c5c8c6 } + .terminal-2990670852-r2 { fill: #000000 } + .terminal-2990670852-r3 { fill: #008000 } + .terminal-2990670852-r4 { fill: #e5f0e5 } + .terminal-2990670852-r5 { fill: #036a03 } + .terminal-2990670852-r6 { fill: #14191f } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OverflowApp + OverflowApp - - - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - I must not fear.I must not fear. - Fear is the mind-killer.Fear is the mind-killer. - Fear is the little-death that Fear is the little-death that  - brings total obliteration.brings total obliteration. - I will face my fear.I will face my fear. - I will permit it to pass over meI will permit it to pass over me  - and through me.and through me. - And when it has gone past, I And when it has gone past, I will  - will turn the inner eye to see turn the inner eye to see its  - its path.▁▁path. - Where the fear has gone there Where the fear has gone there will - will be nothing. Only I will be nothing. Only I will remain. - remain.▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁I must not fear. - I must not fear.Fear is the mind-killer. - Fear is the mind-killer.Fear is the little-death that  - Fear is the little-death that brings total obliteration. - brings total obliteration.I will face my fear. - I will face my fear.I will permit it to pass over me  - I will permit it to pass over meand through me. + + + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + I must not fear.I must not fear. + Fear is the mind-killer.Fear is the mind-killer. + Fear is the little-death that Fear is the little-death that  + brings total obliteration.brings total obliteration. + I will face my fear.I will face my fear. + I will permit it to pass over meI will permit it to pass over me  + and through me.and through me. + And when it has gone past, I And when it has gone past, I will  + will turn the inner eye to see turn the inner eye to see its  + its path.▁▁path. + Where the fear has gone there Where the fear has gone there will + will be nothing. Only I will be nothing. Only I will remain. + remain.▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁I must not fear. + I must not fear.Fear is the mind-killer. + Fear is the mind-killer.Fear is the little-death that  + Fear is the little-death that brings total obliteration. + brings total obliteration.I will face my fear. + I will face my fear.I will permit it to pass over me  + I will permit it to pass over meand through me. @@ -9743,138 +9750,138 @@ font-weight: 700; } - .terminal-2103878337-matrix { + .terminal-1642992271-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2103878337-title { + .terminal-1642992271-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2103878337-r1 { fill: #e7e0e6 } - .terminal-2103878337-r2 { fill: #c5c8c6 } - .terminal-2103878337-r3 { fill: #eae2e4 } - .terminal-2103878337-r4 { fill: #ece5e5 } - .terminal-2103878337-r5 { fill: #eee8e3 } - .terminal-2103878337-r6 { fill: #e8ede4 } - .terminal-2103878337-r7 { fill: #e3ede7 } - .terminal-2103878337-r8 { fill: #e1eceb } - .terminal-2103878337-r9 { fill: #eeeddf } + .terminal-1642992271-r1 { fill: #c5c8c6 } + .terminal-1642992271-r2 { fill: #e7e0e6 } + .terminal-1642992271-r3 { fill: #eae2e4 } + .terminal-1642992271-r4 { fill: #ece5e5 } + .terminal-1642992271-r5 { fill: #eee8e3 } + .terminal-1642992271-r6 { fill: #e8ede4 } + .terminal-1642992271-r7 { fill: #e3ede7 } + .terminal-1642992271-r8 { fill: #e1eceb } + .terminal-1642992271-r9 { fill: #eeeddf } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - PaddingAllApp + PaddingAllApp - - - - no padding - padding: 1padding:padding: 1 1 - 1 52 6 - - - - - - - - - - padding-right: 3padding-bottom: 4padding-left: 3 - - - - padding-top: 4 - - - - - - + + + + no padding + padding: 1padding:padding: 1 1 + 1 52 6 + + + + + + + + + + padding-right: 3padding-bottom: 4padding-left: 3 + + + + padding-top: 4 + + + + + + @@ -12284,141 +12291,141 @@ font-weight: 700; } - .terminal-1052270191-matrix { + .terminal-1938916138-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1052270191-title { + .terminal-1938916138-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1052270191-r1 { fill: #c5c8c6 } - .terminal-1052270191-r2 { fill: #e8e0e7 } - .terminal-1052270191-r3 { fill: #eae3e5 } - .terminal-1052270191-r4 { fill: #ede6e6 } - .terminal-1052270191-r5 { fill: #efe9e4 } - .terminal-1052270191-r6 { fill: #efeedf } - .terminal-1052270191-r7 { fill: #e9eee5 } - .terminal-1052270191-r8 { fill: #e4eee8 } - .terminal-1052270191-r9 { fill: #e2edeb } - .terminal-1052270191-r10 { fill: #dfebed } - .terminal-1052270191-r11 { fill: #ddedf9 } + .terminal-1938916138-r1 { fill: #c5c8c6 } + .terminal-1938916138-r2 { fill: #e8e0e7 } + .terminal-1938916138-r3 { fill: #eae3e5 } + .terminal-1938916138-r4 { fill: #ede6e6 } + .terminal-1938916138-r5 { fill: #efe9e4 } + .terminal-1938916138-r6 { fill: #efeedf } + .terminal-1938916138-r7 { fill: #e9eee5 } + .terminal-1938916138-r8 { fill: #e4eee8 } + .terminal-1938916138-r9 { fill: #e2edeb } + .terminal-1938916138-r10 { fill: #dfebed } + .terminal-1938916138-r11 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - HeightComparisonApp + HeightComparisonApp - - - - - - - - - - - - - - - #cells#percent#w#h#vw#vh#auto#fr1#fr3 - - - - - - - - - - - - ····•····•····•····•····•····•····•····•····•····•····•····•····•····•····•····• + + + + + + + + + + + + + + + #cells#percent#w#h#vw#vh#auto#fr1#fr3 + + + + + + + + + + + + ····•····•····•····•····•····•····•····•····•····•····•····•····•····•····•····• @@ -13562,168 +13569,168 @@ font-weight: 700; } - .terminal-614458704-matrix { + .terminal-4033540874-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-614458704-title { + .terminal-4033540874-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-614458704-r1 { fill: #c5c8c6 } - .terminal-614458704-r2 { fill: #e3e3e3 } - .terminal-614458704-r3 { fill: #e1e1e1 } - .terminal-614458704-r4 { fill: #e2e2e2 } - .terminal-614458704-r5 { fill: #14191f } - .terminal-614458704-r6 { fill: #004578 } - .terminal-614458704-r7 { fill: #262626 } - .terminal-614458704-r8 { fill: #e2e2e2;font-weight: bold;text-decoration: underline; } - .terminal-614458704-r9 { fill: #e2e2e2;font-weight: bold } - .terminal-614458704-r10 { fill: #7ae998 } - .terminal-614458704-r11 { fill: #4ebf71;font-weight: bold } - .terminal-614458704-r12 { fill: #008139 } - .terminal-614458704-r13 { fill: #dde8f3;font-weight: bold } - .terminal-614458704-r14 { fill: #ddedf9 } + .terminal-4033540874-r1 { fill: #c5c8c6 } + .terminal-4033540874-r2 { fill: #e3e3e3 } + .terminal-4033540874-r3 { fill: #e1e1e1 } + .terminal-4033540874-r4 { fill: #e2e2e2 } + .terminal-4033540874-r5 { fill: #14191f } + .terminal-4033540874-r6 { fill: #004578 } + .terminal-4033540874-r7 { fill: #262626 } + .terminal-4033540874-r8 { fill: #e2e2e2;font-weight: bold;text-decoration: underline; } + .terminal-4033540874-r9 { fill: #e2e2e2;font-weight: bold } + .terminal-4033540874-r10 { fill: #7ae998 } + .terminal-4033540874-r11 { fill: #4ebf71;font-weight: bold } + .terminal-4033540874-r12 { fill: #008139 } + .terminal-4033540874-r13 { fill: #dde8f3;font-weight: bold } + .terminal-4033540874-r14 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Textual Demo + Textual Demo - - - - Textual Demo - - - TOP - - ▆▆ - - Widgets - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - Rich contentTextual Demo - - Welcome! Textual is a framework for creating sophisticated - applications with the terminal. - CSS - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Start - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - - - - - - - -  CTRL+C  Quit  CTRL+B  Sidebar  CTRL+T  Toggle Dark mode  CTRL+S  Screenshot  F1  Notes  + + + + Textual Demo + + + TOP + + ▆▆ + + Widgets + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + Rich contentTextual Demo + + Welcome! Textual is a framework for creating sophisticated + applications with the terminal. + CSS + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Start + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + + + + + + +  CTRL+C  Quit  CTRL+B  Sidebar  CTRL+T  Toggle Dark mode  CTRL+S  Screenshot  F1  Notes  @@ -14094,141 +14101,141 @@ font-weight: 700; } - .terminal-2216843056-matrix { + .terminal-2702154472-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2216843056-title { + .terminal-2702154472-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2216843056-r1 { fill: #c5c8c6 } - .terminal-2216843056-r2 { fill: #1e1e1e } - .terminal-2216843056-r3 { fill: #1f1f1f } - .terminal-2216843056-r4 { fill: #ff0000 } - .terminal-2216843056-r5 { fill: #dde8f3;font-weight: bold } - .terminal-2216843056-r6 { fill: #ddedf9 } - .terminal-2216843056-r7 { fill: #c7cdd2 } + .terminal-2702154472-r1 { fill: #c5c8c6 } + .terminal-2702154472-r2 { fill: #1e1e1e } + .terminal-2702154472-r3 { fill: #1f1f1f } + .terminal-2702154472-r4 { fill: #ff0000 } + .terminal-2702154472-r5 { fill: #dde8f3;font-weight: bold } + .terminal-2702154472-r6 { fill: #ddedf9 } + .terminal-2702154472-r7 { fill: #c7cdd2 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TestApp + TestApp - - - - TestApp - ───────── - this - is - a - sample - sentence - and - here - are - some - wordsthis - is - a - sample - sentence - and - here - are - some - words -  CTRL+Q  Quit  - - - ▇▇ + + + + TestApp + ───────── + this + is + a + sample + sentence + and + here + are + some + wordsthis + is + a + sample + sentence + and + here + are + some + words +  CTRL+Q  Quit  + + + ▇▇ @@ -14428,135 +14435,135 @@ font-weight: 700; } - .terminal-2886576672-matrix { + .terminal-1801121102-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2886576672-title { + .terminal-1801121102-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2886576672-r1 { fill: #c5c8c6 } - .terminal-2886576672-r2 { fill: #e3e3e3 } - .terminal-2886576672-r3 { fill: #ffdddd } - .terminal-2886576672-r4 { fill: #e1e1e1 } - .terminal-2886576672-r5 { fill: #14191f } - .terminal-2886576672-r6 { fill: #ddedf9 } + .terminal-1801121102-r1 { fill: #c5c8c6 } + .terminal-1801121102-r2 { fill: #e3e3e3 } + .terminal-1801121102-r3 { fill: #ffdddd } + .terminal-1801121102-r4 { fill: #e1e1e1 } + .terminal-1801121102-r5 { fill: #14191f } + .terminal-1801121102-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - StyleBugApp + StyleBugApp - - - - StyleBugApp - test widget 0 - test widget 1 - test widget 2 - test widget 3 - test widget 4 - test widget 5 - test widget 6 - test widget 7 - test widget 8 - test widget 9 - test widget 10 - test widget 11 - test widget 12▇▇ - test widget 13 - test widget 14 - test widget 15 - test widget 16 - test widget 17 - test widget 18 - test widget 19 - test widget 20 - test widget 21 + + + + StyleBugApp + test widget 0 + test widget 1 + test widget 2 + test widget 3 + test widget 4 + test widget 5 + test widget 6 + test widget 7 + test widget 8 + test widget 9 + test widget 10 + test widget 11 + test widget 12▇▇ + test widget 13 + test widget 14 + test widget 15 + test widget 16 + test widget 17 + test widget 18 + test widget 19 + test widget 20 + test widget 21 @@ -14744,137 +14751,138 @@ font-weight: 700; } - .terminal-1298369243-matrix { + .terminal-1665781252-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1298369243-title { + .terminal-1665781252-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1298369243-r1 { fill: #008000 } - .terminal-1298369243-r2 { fill: #c5c8c6 } - .terminal-1298369243-r3 { fill: #e0e6e0 } + .terminal-1665781252-r1 { fill: #008000 } + .terminal-1665781252-r2 { fill: #c5c8c6 } + .terminal-1665781252-r3 { fill: #e0e4e0 } + .terminal-1665781252-r4 { fill: #e0e6e0 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TestApp + TestApp - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - - Hello - - - - - - - World - - - - - - - !! - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + + Hello + + + + + + + World + + + + + + + !! + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -14904,135 +14912,136 @@ font-weight: 700; } - .terminal-2371169958-matrix { + .terminal-1035580841-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2371169958-title { + .terminal-1035580841-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2371169958-r1 { fill: #c5c8c6 } - .terminal-2371169958-r2 { fill: #e3e3e3 } - .terminal-2371169958-r3 { fill: #e3e4e5 } - .terminal-2371169958-r4 { fill: #e2e3e3 } - .terminal-2371169958-r5 { fill: #14191f } - .terminal-2371169958-r6 { fill: #ddedf9 } + .terminal-1035580841-r1 { fill: #c5c8c6 } + .terminal-1035580841-r2 { fill: #e3e3e3 } + .terminal-1035580841-r3 { fill: #ddddff } + .terminal-1035580841-r4 { fill: #e3e4e5 } + .terminal-1035580841-r5 { fill: #e2e3e3 } + .terminal-1035580841-r6 { fill: #14191f } + .terminal-1035580841-r7 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ScreenSplitApp + ScreenSplitApp - - - - ScreenSplitApp - This is content This is content number 0 - number 0This is content number 1 - This is content ▄▄This is content number 2 - number 1This is content number 3 - This is content This is content number 4▁▁ - number 2This is content number 5 - This is content This is content number 6 - number 3This is content number 7 - This is content This is content number 8 - number 4This is content number 9 - This is content This is content number 10 - number 5This is content number 11 - This is content This is content number 12 - number 6This is content number 13 - This is content This is content number 14 - number 7This is content number 15 - This is content This is content number 16 - number 8This is content number 17 - This is content This is content number 18 - number 9This is content number 19 - This is content This is content number 20 - number 10This is content number 21 + + + + ScreenSplitApp + This is content This is content number 0 + number 0This is content number 1 + This is content ▄▄This is content number 2 + number 1This is content number 3 + This is content This is content number 4▁▁ + number 2This is content number 5 + This is content This is content number 6 + number 3This is content number 7 + This is content This is content number 8 + number 4This is content number 9 + This is content This is content number 10 + number 5This is content number 11 + This is content This is content number 12 + number 6This is content number 13 + This is content This is content number 14 + number 7This is content number 15 + This is content This is content number 16 + number 8This is content number 17 + This is content This is content number 18 + number 9This is content number 19 + This is content This is content number 20 + number 10This is content number 21 @@ -15687,132 +15696,132 @@ font-weight: 700; } - .terminal-2648118808-matrix { + .terminal-4077214022-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2648118808-title { + .terminal-4077214022-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2648118808-r1 { fill: #c5c8c6 } - .terminal-2648118808-r2 { fill: #e3e3e3 } - .terminal-2648118808-r3 { fill: #e1e1e1 } + .terminal-4077214022-r1 { fill: #c5c8c6 } + .terminal-4077214022-r2 { fill: #e3e3e3 } + .terminal-4077214022-r3 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - HeaderApp + HeaderApp - - - - HeaderApp - - - - - - - - - - - - - - - - - - - - - - + + + + HeaderApp + + + + + + + + + + + + + + + + + + + + + + @@ -16473,146 +16482,146 @@ font-weight: 700; } - .terminal-641812469-matrix { + .terminal-2572323619-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-641812469-title { + .terminal-2572323619-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-641812469-r1 { fill: #c5c8c6 } - .terminal-641812469-r2 { fill: #e3e3e3 } - .terminal-641812469-r3 { fill: #e1e1e1 } - .terminal-641812469-r4 { fill: #e1e1e1;text-decoration: underline; } - .terminal-641812469-r5 { fill: #e1e1e1;font-weight: bold } - .terminal-641812469-r6 { fill: #e1e1e1;font-style: italic; } - .terminal-641812469-r7 { fill: #98729f;font-weight: bold } - .terminal-641812469-r8 { fill: #d0b344 } - .terminal-641812469-r9 { fill: #98a84b } - .terminal-641812469-r10 { fill: #00823d;font-style: italic; } - .terminal-641812469-r11 { fill: #ffcf56 } - .terminal-641812469-r12 { fill: #e76580 } - .terminal-641812469-r13 { fill: #211505;font-weight: bold } - .terminal-641812469-r14 { fill: #f5e5e9;font-weight: bold } - .terminal-641812469-r15 { fill: #b86b00 } - .terminal-641812469-r16 { fill: #780028 } + .terminal-2572323619-r1 { fill: #c5c8c6 } + .terminal-2572323619-r2 { fill: #e3e3e3 } + .terminal-2572323619-r3 { fill: #e1e1e1 } + .terminal-2572323619-r4 { fill: #e1e1e1;text-decoration: underline; } + .terminal-2572323619-r5 { fill: #e1e1e1;font-weight: bold } + .terminal-2572323619-r6 { fill: #e1e1e1;font-style: italic; } + .terminal-2572323619-r7 { fill: #98729f;font-weight: bold } + .terminal-2572323619-r8 { fill: #d0b344 } + .terminal-2572323619-r9 { fill: #98a84b } + .terminal-2572323619-r10 { fill: #00823d;font-style: italic; } + .terminal-2572323619-r11 { fill: #ffcf56 } + .terminal-2572323619-r12 { fill: #e76580 } + .terminal-2572323619-r13 { fill: #211505;font-weight: bold } + .terminal-2572323619-r14 { fill: #f5e5e9;font-weight: bold } + .terminal-2572323619-r15 { fill: #b86b00 } + .terminal-2572323619-r16 { fill: #780028 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Textual Keys + Textual Keys - - - - Textual Keys - ╭────────────────────────────────────────────────────────────────────────────╮ - Press some keys! - - To quit the app press ctrl+ctwice or press the Quit button below. - ╰────────────────────────────────────────────────────────────────────────────╯ - Key(key='a'character='a'name='a'is_printable=True) - Key(key='b'character='b'name='b'is_printable=True) - - - - - - - - - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ClearQuit - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + Textual Keys + ╭────────────────────────────────────────────────────────────────────────────╮ + Press some keys! + + To quit the app press ctrl+ctwice or press the Quit button below. + ╰────────────────────────────────────────────────────────────────────────────╯ + Key(key='a'character='a'name='a'is_printable=True) + Key(key='b'character='b'name='b'is_printable=True) + + + + + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ClearQuit + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ @@ -16800,136 +16809,136 @@ font-weight: 700; } - .terminal-513592180-matrix { + .terminal-1675990519-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-513592180-title { + .terminal-1675990519-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-513592180-r1 { fill: #c5c8c6 } - .terminal-513592180-r2 { fill: #e3e3e3 } - .terminal-513592180-r3 { fill: #ff0000 } - .terminal-513592180-r4 { fill: #e1e1e1 } - .terminal-513592180-r5 { fill: #dde8f3;font-weight: bold } - .terminal-513592180-r6 { fill: #ddedf9 } + .terminal-1675990519-r1 { fill: #c5c8c6 } + .terminal-1675990519-r2 { fill: #e3e3e3 } + .terminal-1675990519-r3 { fill: #e1e1e1 } + .terminal-1675990519-r4 { fill: #ff0000 } + .terminal-1675990519-r5 { fill: #dde8f3;font-weight: bold } + .terminal-1675990519-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - DialogIssueApp + DialogIssueApp - - - - DialogIssueApp - - - - - - ─────────────────────────────────────── - - - - - - This should not cause a scrollbar to ap - - - - - - ─────────────────────────────────────── - - - - -  D  Toggle the dialog  + + + + DialogIssueApp + + + + + + ─────────────────────────────────────── + + + + + + This should not cause a scrollbar to ap + + + + + + ─────────────────────────────────────── + + + + +  D  Toggle the dialog  @@ -17927,135 +17936,135 @@ font-weight: 700; } - .terminal-2423395429-matrix { + .terminal-543315859-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2423395429-title { + .terminal-543315859-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2423395429-r1 { fill: #c5c8c6 } - .terminal-2423395429-r2 { fill: #e3e3e3 } - .terminal-2423395429-r3 { fill: #e1e1e1 } - .terminal-2423395429-r4 { fill: #dde8f3;font-weight: bold } - .terminal-2423395429-r5 { fill: #ddedf9 } + .terminal-543315859-r1 { fill: #c5c8c6 } + .terminal-543315859-r2 { fill: #e3e3e3 } + .terminal-543315859-r3 { fill: #e1e1e1 } + .terminal-543315859-r4 { fill: #dde8f3;font-weight: bold } + .terminal-543315859-r5 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ModalApp + ModalApp - - - - ModalApp - Hello - - - - - - - - - - - - - - - - - - - - - -  ⏎  Open Dialog  + + + + ModalApp + Hello + + + + + + + + + + + + + + + + + + + + + +  ⏎  Open Dialog  @@ -18722,136 +18731,136 @@ font-weight: 700; } - .terminal-1829927563-matrix { + .terminal-1812315577-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1829927563-title { + .terminal-1812315577-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1829927563-r1 { fill: #c5c8c6 } - .terminal-1829927563-r2 { fill: #e3e3e3 } - .terminal-1829927563-r3 { fill: #e1e1e1 } - .terminal-1829927563-r4 { fill: #004578 } - .terminal-1829927563-r5 { fill: #e0e8ee;font-weight: bold } - .terminal-1829927563-r6 { fill: #e2e3e3 } - .terminal-1829927563-r7 { fill: #ddedf9 } + .terminal-1812315577-r1 { fill: #c5c8c6 } + .terminal-1812315577-r2 { fill: #e3e3e3 } + .terminal-1812315577-r3 { fill: #e1e1e1 } + .terminal-1812315577-r4 { fill: #004578 } + .terminal-1812315577-r5 { fill: #e0e8ee;font-weight: bold } + .terminal-1812315577-r6 { fill: #e2e3e3 } + .terminal-1812315577-r7 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - - - - OptionListApp - - - - ────────────────────────────────────────────────────── - Aerilon - Aquaria - Canceron - Caprica - Gemenon - Leonis - Libran - Picon - Sagittaron - Scorpia - Tauron - Virgon - - - ────────────────────────────────────────────────────── - - - + + + + OptionListApp + + + + ────────────────────────────────────────────────────── + Aerilon + Aquaria + Canceron + Caprica + Gemenon + Leonis + Libran + Picon + Sagittaron + Scorpia + Tauron + Virgon + + + ────────────────────────────────────────────────────── + + + @@ -18882,139 +18891,139 @@ font-weight: 700; } - .terminal-2055091312-matrix { + .terminal-1041266590-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2055091312-title { + .terminal-1041266590-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2055091312-r1 { fill: #c5c8c6 } - .terminal-2055091312-r2 { fill: #e3e3e3 } - .terminal-2055091312-r3 { fill: #e1e1e1 } - .terminal-2055091312-r4 { fill: #004578 } - .terminal-2055091312-r5 { fill: #e0e8ee;font-weight: bold } - .terminal-2055091312-r6 { fill: #e2e3e3 } - .terminal-2055091312-r7 { fill: #42464b } - .terminal-2055091312-r8 { fill: #777a7e } - .terminal-2055091312-r9 { fill: #14191f } - .terminal-2055091312-r10 { fill: #ddedf9 } + .terminal-1041266590-r1 { fill: #c5c8c6 } + .terminal-1041266590-r2 { fill: #e3e3e3 } + .terminal-1041266590-r3 { fill: #e1e1e1 } + .terminal-1041266590-r4 { fill: #004578 } + .terminal-1041266590-r5 { fill: #e0e8ee;font-weight: bold } + .terminal-1041266590-r6 { fill: #e2e3e3 } + .terminal-1041266590-r7 { fill: #42464b } + .terminal-1041266590-r8 { fill: #777a7e } + .terminal-1041266590-r9 { fill: #14191f } + .terminal-1041266590-r10 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - - - - OptionListApp - - - - ────────────────────────────────────────────────────── - Aerilon - Aquaria - ──────────────────────────────────────────────────── - Canceron - Caprica - ──────────────────────────────────────────────────── - Gemenon - ──────────────────────────────────────────────────── - Leonis - Libran - ────────────────────────────────────────────────────▅▅ - Picon - ──────────────────────────────────────────────────── - Sagittaron - ────────────────────────────────────────────────────── - - - + + + + OptionListApp + + + + ────────────────────────────────────────────────────── + Aerilon + Aquaria + ──────────────────────────────────────────────────── + Canceron + Caprica + ──────────────────────────────────────────────────── + Gemenon + ──────────────────────────────────────────────────── + Leonis + Libran + ────────────────────────────────────────────────────▅▅ + Picon + ──────────────────────────────────────────────────── + Sagittaron + ────────────────────────────────────────────────────── + + + @@ -19045,140 +19054,140 @@ font-weight: 700; } - .terminal-1395459687-matrix { + .terminal-1620527509-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1395459687-title { + .terminal-1620527509-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1395459687-r1 { fill: #c5c8c6 } - .terminal-1395459687-r2 { fill: #e3e3e3 } - .terminal-1395459687-r3 { fill: #e1e1e1 } - .terminal-1395459687-r4 { fill: #004578 } - .terminal-1395459687-r5 { fill: #e0e8ee;font-weight: bold;font-style: italic; } - .terminal-1395459687-r6 { fill: #e2e3e3 } - .terminal-1395459687-r7 { fill: #e0e8ee;font-weight: bold } - .terminal-1395459687-r8 { fill: #14191f } - .terminal-1395459687-r9 { fill: #e2e3e3;font-style: italic; } - .terminal-1395459687-r10 { fill: #e2e3e3;font-weight: bold } - .terminal-1395459687-r11 { fill: #ddedf9 } + .terminal-1620527509-r1 { fill: #c5c8c6 } + .terminal-1620527509-r2 { fill: #e3e3e3 } + .terminal-1620527509-r3 { fill: #e1e1e1 } + .terminal-1620527509-r4 { fill: #004578 } + .terminal-1620527509-r5 { fill: #e0e8ee;font-weight: bold;font-style: italic; } + .terminal-1620527509-r6 { fill: #e2e3e3 } + .terminal-1620527509-r7 { fill: #e0e8ee;font-weight: bold } + .terminal-1620527509-r8 { fill: #14191f } + .terminal-1620527509-r9 { fill: #e2e3e3;font-style: italic; } + .terminal-1620527509-r10 { fill: #e2e3e3;font-weight: bold } + .terminal-1620527509-r11 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - - - - OptionListApp - - - - ────────────────────────────────────────────────────── -                   Data for Aerilon                   - ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ - Patron God   Population    Capital City   ▂▂ - ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ - Demeter      1.2 Billion   Gaoth           - └───────────────┴────────────────┴─────────────────┘ -                   Data for Aquaria                   - ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ - Patron God    Population   Capital City    - ┡━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ - Hermes        75,000       None            - └────────────────┴───────────────┴─────────────────┘ -                  Data for Canceron                   - ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ - ────────────────────────────────────────────────────── - - - + + + + OptionListApp + + + + ────────────────────────────────────────────────────── +                   Data for Aerilon                   + ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ + Patron God   Population    Capital City   ▂▂ + ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ + Demeter      1.2 Billion   Gaoth           + └───────────────┴────────────────┴─────────────────┘ +                   Data for Aquaria                   + ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ + Patron God    Population   Capital City    + ┡━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ + Hermes        75,000       None            + └────────────────┴───────────────┴─────────────────┘ +                  Data for Canceron                   + ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ + ────────────────────────────────────────────────────── + + + @@ -19367,136 +19376,136 @@ font-weight: 700; } - .terminal-3980370474-matrix { + .terminal-1392305496-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3980370474-title { + .terminal-1392305496-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3980370474-r1 { fill: #ffff00 } - .terminal-3980370474-r2 { fill: #e3e3e3 } - .terminal-3980370474-r3 { fill: #c5c8c6 } - .terminal-3980370474-r4 { fill: #e1e1e1 } - .terminal-3980370474-r5 { fill: #dde8f3;font-weight: bold } - .terminal-3980370474-r6 { fill: #ddedf9 } + .terminal-1392305496-r1 { fill: #ffff00 } + .terminal-1392305496-r2 { fill: #e3e3e3 } + .terminal-1392305496-r3 { fill: #c5c8c6 } + .terminal-1392305496-r4 { fill: #e1e1e1 } + .terminal-1392305496-r5 { fill: #dde8f3;font-weight: bold } + .terminal-1392305496-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Layers + Layers - - - - ──────────────────────────────────Layers - It's full of stars! My God! It's full of sta - - This should float over the top - - - ────────────────────────────────── - - - - - - - - - - - - - - - - -  T  Toggle Screen  + + + + ──────────────────────────────────Layers + It's full of stars! My God! It's full of sta + + This should float over the top + + + ────────────────────────────────── + + + + + + + + + + + + + + + + +  T  Toggle Screen  @@ -19526,136 +19535,136 @@ font-weight: 700; } - .terminal-1053593998-matrix { + .terminal-3727479996-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1053593998-title { + .terminal-3727479996-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1053593998-r1 { fill: #ffff00 } - .terminal-1053593998-r2 { fill: #e3e3e3 } - .terminal-1053593998-r3 { fill: #c5c8c6 } - .terminal-1053593998-r4 { fill: #ddeedd } - .terminal-1053593998-r5 { fill: #dde8f3;font-weight: bold } - .terminal-1053593998-r6 { fill: #ddedf9 } + .terminal-3727479996-r1 { fill: #ffff00 } + .terminal-3727479996-r2 { fill: #e3e3e3 } + .terminal-3727479996-r3 { fill: #c5c8c6 } + .terminal-3727479996-r4 { fill: #ddeedd } + .terminal-3727479996-r5 { fill: #dde8f3;font-weight: bold } + .terminal-3727479996-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Layers + Layers - - - - ──────────────────────────────────Layers - It's full of stars! My God! It's full of sta - - This should float over the top - - - ────────────────────────────────── - - - - - - - - - - - - - - - - -  T  Toggle Screen  + + + + ──────────────────────────────────Layers + It's full of stars! My God! It's full of sta + + This should float over the top + + + ────────────────────────────────── + + + + + + + + + + + + + + + + +  T  Toggle Screen  @@ -19685,142 +19694,142 @@ font-weight: 700; } - .terminal-700023403-matrix { + .terminal-1570661136-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-700023403-title { + .terminal-1570661136-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-700023403-r1 { fill: #c5c8c6 } - .terminal-700023403-r2 { fill: #eae3e5 } - .terminal-700023403-r3 { fill: #e8e0e7 } - .terminal-700023403-r4 { fill: #efe9e4 } - .terminal-700023403-r5 { fill: #ede6e6 } - .terminal-700023403-r6 { fill: #efeedf } - .terminal-700023403-r7 { fill: #e9eee5 } - .terminal-700023403-r8 { fill: #e2edeb } - .terminal-700023403-r9 { fill: #e4eee8;font-weight: bold } - .terminal-700023403-r10 { fill: #dfebed;font-weight: bold } - .terminal-700023403-r11 { fill: #dfe9ed } - .terminal-700023403-r12 { fill: #e3e6eb;font-weight: bold } - .terminal-700023403-r13 { fill: #e6e3e9 } + .terminal-1570661136-r1 { fill: #c5c8c6 } + .terminal-1570661136-r2 { fill: #eae3e5 } + .terminal-1570661136-r3 { fill: #e8e0e7 } + .terminal-1570661136-r4 { fill: #efe9e4 } + .terminal-1570661136-r5 { fill: #ede6e6 } + .terminal-1570661136-r6 { fill: #efeedf } + .terminal-1570661136-r7 { fill: #e9eee5 } + .terminal-1570661136-r8 { fill: #e2edeb } + .terminal-1570661136-r9 { fill: #e4eee8;font-weight: bold } + .terminal-1570661136-r10 { fill: #dfebed;font-weight: bold } + .terminal-1570661136-r11 { fill: #dfe9ed } + .terminal-1570661136-r12 { fill: #e3e6eb;font-weight: bold } + .terminal-1570661136-r13 { fill: #e6e3e9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - PlaceholderApp + PlaceholderApp - - - - - Placeholder p2 here! - This is a custom label for p1. - #p4 - #p3#p5Placeholde - r - - Lorem ipsum dolor sit  - 26 x 6amet, consectetur 27 x 6 - adipiscing elit. Etiam  - feugiat ac elit sit amet  - - - Lorem ipsum dolor sit amet,  - consectetur adipiscing elit. Etiam 40 x 6 - feugiat ac elit sit amet accumsan.  - Suspendisse bibendum nec libero quis  - gravida. Phasellus id eleifend ligula. - Nullam imperdiet sem tellus, sed  - vehicula nisl faucibus sit amet. Lorem ipsum dolor sit amet,  - Praesent iaculis tempor ultricies. Sedconsectetur adipiscing elit. Etiam  - lacinia, tellus id rutrum lacinia, feugiat ac elit sit amet accumsan.  - sapien sapien congue mauris, sit amet Suspendisse bibendum nec libero quis  + + + + + Placeholder p2 here! + This is a custom label for p1. + #p4 + #p3#p5Placeholde + r + + Lorem ipsum dolor sit  + 26 x 6amet, consectetur 27 x 6 + adipiscing elit. Etiam  + feugiat ac elit sit amet  + + + Lorem ipsum dolor sit amet,  + consectetur adipiscing elit. Etiam 40 x 6 + feugiat ac elit sit amet accumsan.  + Suspendisse bibendum nec libero quis  + gravida. Phasellus id eleifend ligula. + Nullam imperdiet sem tellus, sed  + vehicula nisl faucibus sit amet. Lorem ipsum dolor sit amet,  + Praesent iaculis tempor ultricies. Sedconsectetur adipiscing elit. Etiam  + lacinia, tellus id rutrum lacinia, feugiat ac elit sit amet accumsan.  + sapien sapien congue mauris, sit amet Suspendisse bibendum nec libero quis  @@ -20006,135 +20015,135 @@ font-weight: 700; } - .terminal-1426024135-matrix { + .terminal-230009450-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1426024135-title { + .terminal-230009450-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1426024135-r1 { fill: #c5c8c6 } - .terminal-1426024135-r2 { fill: #4ebf71 } - .terminal-1426024135-r3 { fill: #e1e1e1 } - .terminal-1426024135-r4 { fill: #dde8f3;font-weight: bold } - .terminal-1426024135-r5 { fill: #ddedf9 } + .terminal-230009450-r1 { fill: #c5c8c6 } + .terminal-230009450-r2 { fill: #e1e1e1 } + .terminal-230009450-r3 { fill: #4ebf71 } + .terminal-230009450-r4 { fill: #dde8f3;font-weight: bold } + .terminal-230009450-r5 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - IndeterminateProgressBar + IndeterminateProgressBar - - - - - - - - - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━100%--:--:-- - - - - - - - - - - - -  S  Start  + + + + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━100%--:--:-- + + + + + + + + + + + +  S  Start  @@ -20164,136 +20173,137 @@ font-weight: 700; } - .terminal-1998155485-matrix { + .terminal-3162092160-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1998155485-title { + .terminal-3162092160-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1998155485-r1 { fill: #c5c8c6 } - .terminal-1998155485-r2 { fill: #b93c5b } - .terminal-1998155485-r3 { fill: #1e1e1e } - .terminal-1998155485-r4 { fill: #e1e1e1;text-decoration: underline; } - .terminal-1998155485-r5 { fill: #dde8f3;font-weight: bold } - .terminal-1998155485-r6 { fill: #ddedf9 } + .terminal-3162092160-r1 { fill: #c5c8c6 } + .terminal-3162092160-r2 { fill: #e1e1e1 } + .terminal-3162092160-r3 { fill: #b93c5b } + .terminal-3162092160-r4 { fill: #1e1e1e } + .terminal-3162092160-r5 { fill: #e1e1e1;text-decoration: underline; } + .terminal-3162092160-r6 { fill: #dde8f3;font-weight: bold } + .terminal-3162092160-r7 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - StyledProgressBar + StyledProgressBar - - - - - - - - - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━100%--:--:-- - - - - - - - - - - - -  S  Start  + + + + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━100%--:--:-- + + + + + + + + + + + +  S  Start  @@ -20323,136 +20333,136 @@ font-weight: 700; } - .terminal-836496735-matrix { + .terminal-1630089489-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-836496735-title { + .terminal-1630089489-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-836496735-r1 { fill: #c5c8c6 } - .terminal-836496735-r2 { fill: #fea62b } - .terminal-836496735-r3 { fill: #323232 } - .terminal-836496735-r4 { fill: #e1e1e1 } - .terminal-836496735-r5 { fill: #dde8f3;font-weight: bold } - .terminal-836496735-r6 { fill: #ddedf9 } + .terminal-1630089489-r1 { fill: #c5c8c6 } + .terminal-1630089489-r2 { fill: #e1e1e1 } + .terminal-1630089489-r3 { fill: #fea62b } + .terminal-1630089489-r4 { fill: #323232 } + .terminal-1630089489-r5 { fill: #dde8f3;font-weight: bold } + .terminal-1630089489-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - IndeterminateProgressBar + IndeterminateProgressBar - - - - - - - - - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━39%00:00:07 - - - - - - - - - - - -  S  Start  + + + + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━39%00:00:07 + + + + + + + + + + + +  S  Start  @@ -20482,137 +20492,138 @@ font-weight: 700; } - .terminal-1783624548-matrix { + .terminal-1532901142-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1783624548-title { + .terminal-1532901142-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1783624548-r1 { fill: #c5c8c6 } - .terminal-1783624548-r2 { fill: #004578 } - .terminal-1783624548-r3 { fill: #152939 } - .terminal-1783624548-r4 { fill: #1e1e1e } - .terminal-1783624548-r5 { fill: #e1e1e1;text-decoration: underline; } - .terminal-1783624548-r6 { fill: #dde8f3;font-weight: bold } - .terminal-1783624548-r7 { fill: #ddedf9 } + .terminal-1532901142-r1 { fill: #c5c8c6 } + .terminal-1532901142-r2 { fill: #e1e1e1 } + .terminal-1532901142-r3 { fill: #004578 } + .terminal-1532901142-r4 { fill: #152939 } + .terminal-1532901142-r5 { fill: #1e1e1e } + .terminal-1532901142-r6 { fill: #e1e1e1;text-decoration: underline; } + .terminal-1532901142-r7 { fill: #dde8f3;font-weight: bold } + .terminal-1532901142-r8 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - StyledProgressBar + StyledProgressBar - - - - - - - - - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━39%00:00:07 - - - - - - - - - - - -  S  Start  + + + + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━39%00:00:07 + + + + + + + + + + + +  S  Start  @@ -20642,136 +20653,136 @@ font-weight: 700; } - .terminal-2036756687-matrix { + .terminal-3440292978-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2036756687-title { + .terminal-3440292978-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2036756687-r1 { fill: #c5c8c6 } - .terminal-2036756687-r2 { fill: #323232 } - .terminal-2036756687-r3 { fill: #b93c5b } - .terminal-2036756687-r4 { fill: #e1e1e1 } - .terminal-2036756687-r5 { fill: #dde8f3;font-weight: bold } - .terminal-2036756687-r6 { fill: #ddedf9 } + .terminal-3440292978-r1 { fill: #c5c8c6 } + .terminal-3440292978-r2 { fill: #e1e1e1 } + .terminal-3440292978-r3 { fill: #323232 } + .terminal-3440292978-r4 { fill: #b93c5b } + .terminal-3440292978-r5 { fill: #dde8f3;font-weight: bold } + .terminal-3440292978-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - IndeterminateProgressBar + IndeterminateProgressBar - - - - - - - - - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--%--:--:-- - - - - - - - - - - - -  S  Start  + + + + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--%--:--:-- + + + + + + + + + + + +  S  Start  @@ -20801,137 +20812,138 @@ font-weight: 700; } - .terminal-4086988071-matrix { + .terminal-4046569674-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4086988071-title { + .terminal-4046569674-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4086988071-r1 { fill: #c5c8c6 } - .terminal-4086988071-r2 { fill: #fea62b } - .terminal-4086988071-r3 { fill: #004578 } - .terminal-4086988071-r4 { fill: #1e1e1e } - .terminal-4086988071-r5 { fill: #e1e1e1;text-decoration: underline; } - .terminal-4086988071-r6 { fill: #dde8f3;font-weight: bold } - .terminal-4086988071-r7 { fill: #ddedf9 } + .terminal-4046569674-r1 { fill: #c5c8c6 } + .terminal-4046569674-r2 { fill: #e1e1e1 } + .terminal-4046569674-r3 { fill: #fea62b } + .terminal-4046569674-r4 { fill: #004578 } + .terminal-4046569674-r5 { fill: #1e1e1e } + .terminal-4046569674-r6 { fill: #e1e1e1;text-decoration: underline; } + .terminal-4046569674-r7 { fill: #dde8f3;font-weight: bold } + .terminal-4046569674-r8 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - StyledProgressBar + StyledProgressBar - - - - - - - - - - - - - - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--%--:--:-- - - - - - - - - - - - -  S  Start  + + + + + + + + + + + + + + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--%--:--:-- + + + + + + + + + + + +  S  Start  @@ -21444,137 +21456,137 @@ font-weight: 700; } - .terminal-2779683141-matrix { + .terminal-1869274227-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2779683141-title { + .terminal-1869274227-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2779683141-r1 { fill: #c5c8c6 } - .terminal-2779683141-r2 { fill: #e3e3e3 } - .terminal-2779683141-r3 { fill: #008000 } - .terminal-2779683141-r4 { fill: #ffff00 } - .terminal-2779683141-r5 { fill: #e1e1e1 } - .terminal-2779683141-r6 { fill: #dde8f3;font-weight: bold } - .terminal-2779683141-r7 { fill: #ddedf9 } + .terminal-1869274227-r1 { fill: #c5c8c6 } + .terminal-1869274227-r2 { fill: #e3e3e3 } + .terminal-1869274227-r3 { fill: #008000 } + .terminal-1869274227-r4 { fill: #ffff00 } + .terminal-1869274227-r5 { fill: #e1e1e1 } + .terminal-1869274227-r6 { fill: #dde8f3;font-weight: bold } + .terminal-1869274227-r7 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - VerticalRemoveApp + VerticalRemoveApp - - - - VerticalRemoveApp - ────────────────────────────────────────────────────────────────────────────── - ──────────────────── - This is a test label - ──────────────────── - ────────────────────────────────────────────────────────────────────────────── - - - - - - - - - - - - - - - - - -  A  Add  D  Delete  + + + + VerticalRemoveApp + ────────────────────────────────────────────────────────────────────────────── + ──────────────────── + This is a test label + ──────────────────── + ────────────────────────────────────────────────────────────────────────────── + + + + + + + + + + + + + + + + + +  A  Add  D  Delete  @@ -21604,135 +21616,135 @@ font-weight: 700; } - .terminal-3992644605-matrix { + .terminal-1316892474-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3992644605-title { + .terminal-1316892474-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3992644605-r1 { fill: #c5c8c6 } - .terminal-3992644605-r2 { fill: #e3e3e3 } - .terminal-3992644605-r3 { fill: #e1e1e1 } - .terminal-3992644605-r4 { fill: #dde8f3;font-weight: bold } - .terminal-3992644605-r5 { fill: #ddedf9 } + .terminal-1316892474-r1 { fill: #c5c8c6 } + .terminal-1316892474-r2 { fill: #e3e3e3 } + .terminal-1316892474-r3 { fill: #e1e1e1 } + .terminal-1316892474-r4 { fill: #dde8f3;font-weight: bold } + .terminal-1316892474-r5 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ModalApp + ModalApp - - - - ModalApp - B - - - - - - - - - - - - - - - - - - - - - -  A  Push screen A  + + + + ModalApp + B + + + + + + + + + + + + + + + + + + + + + +  A  Push screen A  @@ -22075,134 +22087,134 @@ font-weight: 700; } - .terminal-2749576739-matrix { + .terminal-1647606097-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2749576739-title { + .terminal-1647606097-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2749576739-r1 { fill: #c5c8c6 } - .terminal-2749576739-r2 { fill: #e3e3e3 } - .terminal-2749576739-r3 { fill: #ff0000 } - .terminal-2749576739-r4 { fill: #dde2e8 } - .terminal-2749576739-r5 { fill: #ddedf9 } + .terminal-1647606097-r1 { fill: #c5c8c6 } + .terminal-1647606097-r2 { fill: #e3e3e3 } + .terminal-1647606097-r3 { fill: #ff0000 } + .terminal-1647606097-r4 { fill: #dde2e8 } + .terminal-1647606097-r5 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ScrollViewTester + ScrollViewTester - - - - ScrollViewTester -  1 ────────────────────────────────────────────────────────────────────────── - Welcome to line 980 - Welcome to line 981 - Welcome to line 982 - Welcome to line 983 - Welcome to line 984 - Welcome to line 985 - Welcome to line 986 - Welcome to line 987 - Welcome to line 988 - Welcome to line 989 - Welcome to line 990 - Welcome to line 991 - Welcome to line 992 - Welcome to line 993 - Welcome to line 994 - Welcome to line 995 - Welcome to line 996 - Welcome to line 997 - Welcome to line 998 - Welcome to line 999 - ────────────────────────────────────────────────────────────────────────────── + + + + ScrollViewTester +  1 ────────────────────────────────────────────────────────────────────────── + Welcome to line 980 + Welcome to line 981 + Welcome to line 982 + Welcome to line 983 + Welcome to line 984 + Welcome to line 985 + Welcome to line 986 + Welcome to line 987 + Welcome to line 988 + Welcome to line 989 + Welcome to line 990 + Welcome to line 991 + Welcome to line 992 + Welcome to line 993 + Welcome to line 994 + Welcome to line 995 + Welcome to line 996 + Welcome to line 997 + Welcome to line 998 + Welcome to line 999 + ────────────────────────────────────────────────────────────────────────────── @@ -22233,136 +22245,136 @@ font-weight: 700; } - .terminal-4198692207-matrix { + .terminal-1422407852-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4198692207-title { + .terminal-1422407852-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4198692207-r1 { fill: #c5c8c6 } - .terminal-4198692207-r2 { fill: #e3e3e3 } - .terminal-4198692207-r3 { fill: #e1e1e1 } - .terminal-4198692207-r4 { fill: #1e1e1e } - .terminal-4198692207-r5 { fill: #121212 } - .terminal-4198692207-r6 { fill: #787878 } - .terminal-4198692207-r7 { fill: #a8a8a8 } + .terminal-1422407852-r1 { fill: #c5c8c6 } + .terminal-1422407852-r2 { fill: #e3e3e3 } + .terminal-1422407852-r3 { fill: #e1e1e1 } + .terminal-1422407852-r4 { fill: #1e1e1e } + .terminal-1422407852-r5 { fill: #121212 } + .terminal-1422407852-r6 { fill: #787878 } + .terminal-1422407852-r7 { fill: #a8a8a8 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SelectApp + SelectApp - - - - SelectApp - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Select - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - - - - - - - - - - + + + + SelectApp + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Select + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + @@ -22393,140 +22405,140 @@ font-weight: 700; } - .terminal-1874975621-matrix { + .terminal-2035490498-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1874975621-title { + .terminal-2035490498-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1874975621-r1 { fill: #c5c8c6 } - .terminal-1874975621-r2 { fill: #e3e3e3 } - .terminal-1874975621-r3 { fill: #e1e1e1 } - .terminal-1874975621-r4 { fill: #1e1e1e } - .terminal-1874975621-r5 { fill: #0178d4 } - .terminal-1874975621-r6 { fill: #787878 } - .terminal-1874975621-r7 { fill: #a8a8a8 } - .terminal-1874975621-r8 { fill: #121212 } - .terminal-1874975621-r9 { fill: #ddedf9;font-weight: bold } - .terminal-1874975621-r10 { fill: #85beea;font-weight: bold } - .terminal-1874975621-r11 { fill: #e2e3e3 } + .terminal-2035490498-r1 { fill: #c5c8c6 } + .terminal-2035490498-r2 { fill: #e3e3e3 } + .terminal-2035490498-r3 { fill: #e1e1e1 } + .terminal-2035490498-r4 { fill: #1e1e1e } + .terminal-2035490498-r5 { fill: #0178d4 } + .terminal-2035490498-r6 { fill: #787878 } + .terminal-2035490498-r7 { fill: #a8a8a8 } + .terminal-2035490498-r8 { fill: #121212 } + .terminal-2035490498-r9 { fill: #ddedf9;font-weight: bold } + .terminal-2035490498-r10 { fill: #85beea;font-weight: bold } + .terminal-2035490498-r11 { fill: #e2e3e3 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SelectApp + SelectApp - - - - SelectApp - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Select - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Select - I must not fear. - Fear is the mind-killer. - Fear is the little-death that brings total  - obliteration. - I will face my fear. - I will permit it to pass over me and through me. - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - + + + + SelectApp + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Select + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Select + I must not fear. + Fear is the mind-killer. + Fear is the little-death that brings total  + obliteration. + I will face my fear. + I will permit it to pass over me and through me. + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + @@ -22557,136 +22569,299 @@ font-weight: 700; } - .terminal-2181889025-matrix { + .terminal-4010426174-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2181889025-title { + .terminal-4010426174-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2181889025-r1 { fill: #c5c8c6 } - .terminal-2181889025-r2 { fill: #e3e3e3 } - .terminal-2181889025-r3 { fill: #e1e1e1 } - .terminal-2181889025-r4 { fill: #1e1e1e } - .terminal-2181889025-r5 { fill: #0178d4 } - .terminal-2181889025-r6 { fill: #e2e2e2 } - .terminal-2181889025-r7 { fill: #a8a8a8 } + .terminal-4010426174-r1 { fill: #c5c8c6 } + .terminal-4010426174-r2 { fill: #e3e3e3 } + .terminal-4010426174-r3 { fill: #e1e1e1 } + .terminal-4010426174-r4 { fill: #1e1e1e } + .terminal-4010426174-r5 { fill: #0178d4 } + .terminal-4010426174-r6 { fill: #e2e2e2 } + .terminal-4010426174-r7 { fill: #a8a8a8 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SelectApp + SelectApp - - - - I must not fear. - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - I must not fear. - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - - - - - - - - - - + + + + I must not fear. + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + I must not fear. + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + ''' +# --- +# name: test_select_rebuild + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SelectRebuildApp + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Select + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Select + This + Should + Be + What + Goes + Into + The + Snapshit + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + @@ -22717,136 +22892,136 @@ font-weight: 700; } - .terminal-932889121-matrix { + .terminal-2914557706-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-932889121-title { + .terminal-2914557706-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-932889121-r1 { fill: #e1e1e1 } - .terminal-932889121-r2 { fill: #c5c8c6 } - .terminal-932889121-r3 { fill: #e1e1e1;font-weight: bold } - .terminal-932889121-r4 { fill: #1e1e1e } - .terminal-932889121-r5 { fill: #0178d4 } - .terminal-932889121-r6 { fill: #e2e3e3 } - .terminal-932889121-r7 { fill: #e3e8e8 } + .terminal-2914557706-r1 { fill: #e1e1e1 } + .terminal-2914557706-r2 { fill: #c5c8c6 } + .terminal-2914557706-r3 { fill: #e1e1e1;font-weight: bold } + .terminal-2914557706-r4 { fill: #1e1e1e } + .terminal-2914557706-r5 { fill: #0178d4 } + .terminal-2914557706-r6 { fill: #e2e3e3 } + .terminal-2914557706-r7 { fill: #e3e8e8 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SwitchApp + SwitchApp - - - - - - - - Example switches - - - ▔▔▔▔▔▔▔▔ - off:      - ▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔ - on:       - ▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔ - focused:  - ▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔ - custom:   - ▁▁▁▁▁▁▁▁ - - - - + + + + + + + + Example switches + + + ▔▔▔▔▔▔▔▔ + off:      + ▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔ + on:       + ▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔ + focused:  + ▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔ + custom:   + ▁▁▁▁▁▁▁▁ + + + + diff --git a/tests/snapshot_tests/snapshot_apps/select_rebuild.py b/tests/snapshot_tests/snapshot_apps/select_rebuild.py new file mode 100644 index 000000000..190db3b4b --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/select_rebuild.py @@ -0,0 +1,21 @@ +"""Test https://github.com/Textualize/textual/issues/2557""" + +from textual.app import App, ComposeResult +from textual.widgets import Select, Button + + +class SelectRebuildApp(App[None]): + + def compose(self) -> ComposeResult: + yield Select[int]((("1", 1), ("2", 2))) + yield Button("Rebuild") + + def on_button_pressed(self): + self.query_one(Select).set_options(( + ("This", 0), ("Should", 1), ("Be", 2), + ("What", 3), ("Goes", 4), ("Into",5), + ("The", 6), ("Snapshit", 7) + )) + +if __name__ == "__main__": + SelectRebuildApp().run() diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index ea5e32153..9bb589f7a 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -493,3 +493,12 @@ def test_quickly_change_tabs(snap_compare): def test_fr_unit_with_min(snap_compare): # https://github.com/Textualize/textual/issues/2378 assert snap_compare(SNAPSHOT_APPS_DIR / "fr_with_min.py") + + +def test_select_rebuild(snap_compare): + # https://github.com/Textualize/textual/issues/2557 + assert snap_compare( + SNAPSHOT_APPS_DIR / "select_rebuild.py", + press=["tab", "space", "escape", "tab", "enter", "tab", "space"] + ) + diff --git a/tests/test_paste.py b/tests/test_paste.py index 774ad5038..45be6d536 100644 --- a/tests/test_paste.py +++ b/tests/test_paste.py @@ -1,5 +1,6 @@ from textual import events from textual.app import App +from textual.widgets import Input async def test_paste_app(): @@ -16,3 +17,28 @@ async def test_paste_app(): assert len(paste_events) == 1 assert paste_events[0].text == "Hello" + + +async def test_empty_paste(): + """Regression test for https://github.com/Textualize/textual/issues/2563.""" + + paste_events = [] + + class MyInput(Input): + def on_paste(self, event): + super()._on_paste(event) + paste_events.append(event) + + class PasteApp(App): + def compose(self): + yield MyInput() + + def key_p(self): + self.query_one(MyInput).post_message(events.Paste("")) + + app = PasteApp() + async with app.run_test() as pilot: + await pilot.press("p") + assert app.query_one(MyInput).value == "" + assert len(paste_events) == 1 + assert paste_events[0].text == "" diff --git a/tests/test_screens.py b/tests/test_screens.py index 6825c101c..5b29b1dd5 100644 --- a/tests/test_screens.py +++ b/tests/test_screens.py @@ -6,6 +6,7 @@ import pytest from textual.app import App, ScreenStackError from textual.screen import Screen +from textual.widgets import Button, Input skip_py310 = pytest.mark.skipif( sys.version_info.minor == 10 and sys.version_info.major == 3, @@ -150,3 +151,58 @@ async def test_screens(): screen2.remove() screen3.remove() await app._shutdown() + + +async def test_auto_focus(): + class MyScreen(Screen[None]): + def compose(self) -> None: + print("composing") + yield Button() + yield Input(id="one") + yield Input(id="two") + + class MyApp(App[None]): + pass + + app = MyApp() + async with app.run_test(): + await app.push_screen(MyScreen()) + assert isinstance(app.focused, Button) + app.pop_screen() + + MyScreen.AUTO_FOCUS = None + await app.push_screen(MyScreen()) + assert app.focused is None + app.pop_screen() + + MyScreen.AUTO_FOCUS = "Input" + await app.push_screen(MyScreen()) + assert isinstance(app.focused, Input) + assert app.focused.id == "one" + app.pop_screen() + + MyScreen.AUTO_FOCUS = "#two" + await app.push_screen(MyScreen()) + assert isinstance(app.focused, Input) + assert app.focused.id == "two" + + # If we push and pop another screen, focus should be preserved for #two. + MyScreen.AUTO_FOCUS = None + await app.push_screen(MyScreen()) + assert app.focused is None + app.pop_screen() + assert app.focused.id == "two" + + +async def test_dismiss_non_top_screen(): + class MyApp(App[None]): + async def key_p(self) -> None: + self.bottom, top = Screen(), Screen() + await self.push_screen(self.bottom) + await self.push_screen(top) + + app = MyApp() + async with app.run_test() as pilot: + await pilot.press("p") + with pytest.raises(ScreenStackError): + app.bottom.dismiss() diff --git a/tests/test_widget_child_moving.py b/tests/test_widget_child_moving.py index 520ef7810..f2d40a4aa 100644 --- a/tests/test_widget_child_moving.py +++ b/tests/test_widget_child_moving.py @@ -42,22 +42,18 @@ async def test_move_child_to_outside() -> None: pilot.app.screen.move_child(child, before=Widget()) -@pytest.mark.xfail( - strict=True, reason="https://github.com/Textualize/textual/issues/1743" -) async def test_move_child_before_itself() -> None: """Test moving a widget before itself.""" + async with App().run_test() as pilot: child = Widget(Widget()) await pilot.app.mount(child) pilot.app.screen.move_child(child, before=child) -@pytest.mark.xfail( - strict=True, reason="https://github.com/Textualize/textual/issues/1743" -) async def test_move_child_after_itself() -> None: """Test moving a widget after itself.""" + # Regression test for https://github.com/Textualize/textual/issues/1743 async with App().run_test() as pilot: child = Widget(Widget()) await pilot.app.mount(child)