mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
21
sandbox/will/offset.css
Normal file
21
sandbox/will/offset.css
Normal file
@@ -0,0 +1,21 @@
|
||||
Screen {
|
||||
layout: center;
|
||||
}
|
||||
|
||||
#parent {
|
||||
width: 32;
|
||||
height: 8;
|
||||
background: $panel;
|
||||
}
|
||||
|
||||
#tag {
|
||||
color: $text;
|
||||
background: $success;
|
||||
padding: 2 4;
|
||||
width: auto;
|
||||
offset: -8 -4;
|
||||
}
|
||||
|
||||
#child {
|
||||
background: red;
|
||||
}
|
||||
17
sandbox/will/offset.py
Normal file
17
sandbox/will/offset.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from textual import layout
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
class OffsetExample(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield layout.Vertical(
|
||||
Static("Child", id="child"),
|
||||
id="parent"
|
||||
)
|
||||
yield Static("Tag", id="tag")
|
||||
|
||||
|
||||
app = OffsetExample(css_path="offset.css")
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
@@ -39,8 +39,8 @@ BORDER_CHARS: dict[EdgeType, tuple[str, str, str]] = {
|
||||
"outer": ("▛▀▜", "▌ ▐", "▙▄▟"),
|
||||
"hkey": ("▔▔▔", " ", "▁▁▁"),
|
||||
"vkey": ("▏ ▕", "▏ ▕", "▏ ▕"),
|
||||
"tall": ("▕▔▏", "▕ ▏", "▕▁▏"),
|
||||
"wide": ("▁▁▁", "▏ ▕", "▔▔▔"),
|
||||
"tall": ("▊▔▎", "▊ ▎", "▊▁▎"),
|
||||
"wide": ("▁▁▁", "▎ ▋", "▔▔▔"),
|
||||
}
|
||||
|
||||
# Some of the borders are on the widget background and some are on the background of the parent
|
||||
@@ -62,8 +62,8 @@ BORDER_LOCATIONS: dict[
|
||||
"outer": ((0, 0, 0), (0, 0, 0), (0, 0, 0)),
|
||||
"hkey": ((0, 0, 0), (0, 0, 0), (0, 0, 0)),
|
||||
"vkey": ((0, 0, 0), (0, 0, 0), (0, 0, 0)),
|
||||
"tall": ((1, 0, 1), (1, 0, 1), (1, 0, 1)),
|
||||
"wide": ((1, 1, 1), (0, 1, 0), (1, 1, 1)),
|
||||
"tall": ((2, 0, 1), (2, 0, 1), (2, 0, 1)),
|
||||
"wide": ((1, 1, 1), (0, 1, 3), (1, 1, 1)),
|
||||
}
|
||||
|
||||
INVISIBLE_EDGE_TYPES = cast("frozenset[EdgeType]", frozenset(("", "none", "hidden")))
|
||||
@@ -81,7 +81,10 @@ Borders: TypeAlias = Tuple[EdgeStyle, EdgeStyle, EdgeStyle, EdgeStyle]
|
||||
|
||||
@lru_cache(maxsize=1024)
|
||||
def get_box(
|
||||
name: EdgeType, inner_style: Style, outer_style: Style, style: Style
|
||||
name: EdgeType,
|
||||
inner_style: Style,
|
||||
outer_style: Style,
|
||||
style: Style,
|
||||
) -> BoxSegments:
|
||||
"""Get segments used to render a box.
|
||||
|
||||
@@ -107,23 +110,30 @@ def get_box(
|
||||
(lbottom1, lbottom2, lbottom3),
|
||||
) = BORDER_LOCATIONS[name]
|
||||
|
||||
styles = (inner_style, outer_style)
|
||||
inner = inner_style + style
|
||||
outer = outer_style + style
|
||||
styles = (
|
||||
inner,
|
||||
outer,
|
||||
Style.from_color(outer.bgcolor, inner.color),
|
||||
Style.from_color(inner.bgcolor, outer.color),
|
||||
)
|
||||
|
||||
return (
|
||||
(
|
||||
_Segment(top1, styles[ltop1] + style),
|
||||
_Segment(top2, styles[ltop2] + style),
|
||||
_Segment(top3, styles[ltop3] + style),
|
||||
_Segment(top1, styles[ltop1]),
|
||||
_Segment(top2, styles[ltop2]),
|
||||
_Segment(top3, styles[ltop3]),
|
||||
),
|
||||
(
|
||||
_Segment(mid1, styles[lmid1] + style),
|
||||
_Segment(mid2, styles[lmid2] + style),
|
||||
_Segment(mid3, styles[lmid3] + style),
|
||||
_Segment(mid1, styles[lmid1]),
|
||||
_Segment(mid2, styles[lmid2]),
|
||||
_Segment(mid3, styles[lmid3]),
|
||||
),
|
||||
(
|
||||
_Segment(bottom1, styles[lbottom1] + style),
|
||||
_Segment(bottom2, styles[lbottom2] + style),
|
||||
_Segment(bottom3, styles[lbottom3] + style),
|
||||
_Segment(bottom1, styles[lbottom1]),
|
||||
_Segment(bottom2, styles[lbottom2]),
|
||||
_Segment(bottom3, styles[lbottom3]),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ without having to render the entire screen.
|
||||
from __future__ import annotations
|
||||
|
||||
from itertools import chain
|
||||
from operator import attrgetter, itemgetter
|
||||
from operator import itemgetter
|
||||
import sys
|
||||
from typing import Callable, cast, Iterator, Iterable, NamedTuple, TYPE_CHECKING
|
||||
|
||||
@@ -26,7 +26,7 @@ from rich.segment import Segment
|
||||
from rich.style import Style
|
||||
|
||||
from . import errors
|
||||
from .geometry import Region, Offset, Size, Spacing
|
||||
from .geometry import Region, Offset, Size
|
||||
|
||||
from ._cells import cell_len
|
||||
from ._profile import timer
|
||||
@@ -55,7 +55,7 @@ class MapGeometry(NamedTuple):
|
||||
"""Defines the absolute location of a Widget."""
|
||||
|
||||
region: Region # The (screen) region occupied by the widget
|
||||
order: tuple[int, ...] # A tuple of ints defining the painting order
|
||||
order: tuple[tuple[int, ...], ...] # A tuple of ints defining the painting order
|
||||
clip: Region # A region to clip the widget by (if a Widget is within a container)
|
||||
virtual_size: Size # The virtual size (scrollable region) of a widget if it is a container
|
||||
container_size: Size # The container size (area not occupied by scrollbars)
|
||||
@@ -344,12 +344,14 @@ class Compositor:
|
||||
|
||||
map: CompositorMap = {}
|
||||
widgets: set[Widget] = set()
|
||||
layer_order: int = 0
|
||||
|
||||
def add_widget(
|
||||
widget: Widget,
|
||||
virtual_region: Region,
|
||||
region: Region,
|
||||
order: tuple[int, ...],
|
||||
order: tuple[tuple[int, ...], ...],
|
||||
layer_order: int,
|
||||
clip: Region,
|
||||
) -> None:
|
||||
"""Called recursively to place a widget and its children in the map.
|
||||
@@ -413,15 +415,19 @@ class Compositor:
|
||||
)
|
||||
widget_region = sub_region + placement_scroll_offset
|
||||
|
||||
widget_order = order + (get_layer_index(sub_widget.layer, 0), z)
|
||||
widget_order = order + (
|
||||
(get_layer_index(sub_widget.layer, 0), z, layer_order),
|
||||
)
|
||||
|
||||
add_widget(
|
||||
sub_widget,
|
||||
sub_region,
|
||||
widget_region,
|
||||
widget_order,
|
||||
layer_order,
|
||||
sub_clip,
|
||||
)
|
||||
layer_order -= 1
|
||||
|
||||
# Add any scrollbars
|
||||
for chrome_widget, chrome_region in widget._arrange_scrollbars(
|
||||
@@ -457,7 +463,7 @@ class Compositor:
|
||||
)
|
||||
|
||||
# Add top level (root) widget
|
||||
add_widget(root, size.region, size.region, (0,), size.region)
|
||||
add_widget(root, size.region, size.region, ((0,),), layer_order, size.region)
|
||||
return map, widgets
|
||||
|
||||
@property
|
||||
|
||||
@@ -124,13 +124,15 @@ class ColorSystem:
|
||||
background = self.background or Color.parse(DEFAULT_LIGHT_BACKGROUND)
|
||||
surface = self.surface or Color.parse(DEFAULT_LIGHT_SURFACE)
|
||||
|
||||
boost = self.boost or background.get_contrast_text(1.0).with_alpha(0.07)
|
||||
|
||||
if self.panel is None:
|
||||
panel = surface.blend(primary, luminosity_spread)
|
||||
if dark:
|
||||
panel += boost
|
||||
else:
|
||||
panel = self.panel
|
||||
|
||||
boost = self.boost or background.get_contrast_text(1.0).with_alpha(0.07)
|
||||
|
||||
colors: dict[str, str] = {}
|
||||
|
||||
def luminosity_range(spread) -> Iterable[tuple[str, float]]:
|
||||
|
||||
@@ -189,8 +189,6 @@ async def test_composition_of_vertical_container_with_children(
|
||||
"outer",
|
||||
"hkey",
|
||||
"vkey",
|
||||
"tall",
|
||||
"wide",
|
||||
]
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user