tweak for colors

This commit is contained in:
Will McGugan
2022-10-11 10:04:38 +01:00
parent 47effaddbb
commit 7bca184192
9 changed files with 199 additions and 18 deletions

View File

@@ -9,7 +9,6 @@ from .geometry import Region, Size, Spacing
from ._layout import DockArrangeResult, WidgetPlacement
from ._partition import partition
if TYPE_CHECKING:
from .widget import Widget
@@ -115,7 +114,7 @@ def arrange(
for placement in layout_placements
]
).size
placement_offset += styles._align_size(placement_size, size)
placement_offset += styles._align_size(placement_size, size).clamped
if placement_offset:
layout_placements = [

View File

@@ -439,13 +439,8 @@ class App(Generic[ReturnType], DOMNode):
"""Watches the dark bool."""
self.screen.dark = dark
if dark:
self.add_class("-dark-mode")
self.remove_class("-light-mode")
else:
self.remove_class("-dark-mode")
self.add_class("-light-mode")
self.set_class(dark, "-dark-mode")
self.set_class(not dark, "-light-mode")
self.refresh_css()
def get_driver_class(self) -> Type[Driver]:
@@ -1000,6 +995,7 @@ class App(Generic[ReturnType], DOMNode):
Args:
widget (Widget): A widget that is removed.
"""
if self.focused is widget:
for sibling in widget.siblings:
if sibling.can_focus:
sibling.focus()

View File

@@ -111,3 +111,11 @@ def easing():
from textual.cli.previews import easing
easing.app.run()
@run.command("colors")
def colors():
"""Explore the design system."""
from textual.cli.previews import colors
colors.app.run()

View File

@@ -0,0 +1,71 @@
ColorButtons {
dock: left;
overflow-y: auto;
width: 30;
}
ColorButtons > Button {
width: 30;
}
ColorsView {
width: 100%;
height: 100%;
align: center middle;
overflow-x: auto;
background: $background;
scrollbar-gutter: stable;
}
ColorItem {
layout: horizontal;
height: 3;
width: 1fr;
}
ColorBar {
height: auto;
width: 1fr;
content-align: center middle;
}
ColorItem {
width: 100%;
padding: 1 2;
}
ColorGroup {
margin: 2 0;
width: 110;
height: auto;
padding: 2 4;
background: $surface;
border: wide $surface;
}
ColorGroup.-active {
border: wide $secondary;
}
.text {
color: $text;
}
.muted {
color: $text-muted;
}
.disabled {
color: $text-disabled;
}
ColorLabel {
padding: 1 0;
content-align: center middle;
color: $text;
text-style: bold;
}

View File

@@ -0,0 +1,92 @@
from textual.app import App, ComposeResult
from textual.containers import Horizontal, Vertical
from textual.reactive import var
from textual.widgets import Button, Static, Footer
from textual.design import ColorSystem
class ColorButtons(Vertical):
def compose(self) -> ComposeResult:
for border in ColorSystem.COLOR_NAMES:
if border:
yield Button(border, id=border)
class ColorBar(Static):
pass
class ColorItem(Horizontal):
pass
class ColorGroup(Vertical):
pass
class Content(Vertical):
pass
class ColorLabel(Static):
pass
class ColorsView(Vertical):
def compose(self) -> ComposeResult:
LEVELS = [
"darken-3",
"darken-2",
"darken-1",
"",
"lighten-1",
"lighten-2",
"lighten-3",
]
variables = self.app.stylesheet._variables
for color_name in ColorSystem.COLOR_NAMES:
items = [ColorLabel(f'"{color_name}"')]
for level in LEVELS:
color = f"{color_name}-{level}" if level else color_name
item = ColorItem(
ColorBar(f"${color}", classes="text"),
ColorBar(f"$text", classes="text"),
ColorBar(f"$text-muted", classes="muted"),
ColorBar(f"$text-disabled", classes="disabled"),
)
item.styles.background = variables[color]
items.append(item)
yield ColorGroup(*items, id=f"group-{color_name}")
class ColorsApp(App):
CSS_PATH = "colors.css"
BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
def compose(self) -> ComposeResult:
yield Content(ColorButtons(), ColorsView())
yield Footer()
def on_button_pressed(self, event: Button.Pressed) -> None:
self.query(ColorGroup).remove_class("-active")
group = self.query_one(f"#group-{event.button.id}", ColorGroup)
group.add_class("-active")
group.scroll_visible(speed=150)
def action_toggle_dark(self) -> None:
content = self.query_one("Content", Content)
self.dark = not self.dark
content.mount(ColorsView())
content.query("ColorsView").first().remove()
app = ColorsApp()
if __name__ == "__main__":
app.run()

View File

@@ -68,6 +68,16 @@ class Offset(NamedTuple):
"""
return self == (0, 0)
@property
def clamped(self) -> Offset:
"""Ensure x and y are above zero.
Returns:
Offset: New offset.
"""
x, y = self
return Offset(max(x, 0), max(y, 0))
def __bool__(self) -> bool:
return self != (0, 0)

View File

@@ -80,9 +80,6 @@ class Screen(Widget):
"""Get a list of visible widgets."""
return list(self._compositor.visible_widgets)
def watch_dark(self, dark: bool) -> None:
pass
def render(self) -> RenderableType:
background = self.styles.background
if background.is_transparent:

View File

@@ -1739,6 +1739,7 @@ class Widget(DOMNode):
def remove(self) -> None:
"""Remove the Widget from the DOM (effectively deleting it)"""
self.display = False
self.app.post_message_no_wait(events.Remove(self, widget=self))
def render(self) -> RenderableType:

View File

@@ -75,6 +75,13 @@ def test_offset_is_origin():
assert not Offset(1, 0).is_origin
def test_clamped():
assert Offset(-10, 0).clamped == Offset(0, 0)
assert Offset(-10, -5).clamped == Offset(0, 0)
assert Offset(5, -5).clamped == Offset(5, 0)
assert Offset(5, 10).clamped == Offset(5, 10)
def test_offset_add():
assert Offset(1, 1) + Offset(2, 2) == Offset(3, 3)
assert Offset(1, 2) + Offset(3, 4) == Offset(4, 6)