removed old version of widgets

This commit is contained in:
Will McGugan
2022-08-13 11:53:14 +01:00
parent f00e2d22d4
commit 5b7dd4b576
6 changed files with 42 additions and 99 deletions

View File

@@ -179,13 +179,15 @@ class BasicApp(App, css_path="basic.css"):
self.log(query)
self.log(query.nodes)
query.set_styles("outline: solid red;")
query = query.exclude(".scroll-horizontal")
self.log(query)
self.log(query.nodes)
query = query.filter(".rubbish")
self.log(query)
self.log(query.first())
# query = query.filter(".rubbish")
# self.log(query)
# self.log(query.first())
async def key_q(self):
await self.shutdown()

View File

@@ -78,6 +78,9 @@ class HelpText:
self.summary = summary
self.bullets = bullets or []
def __str__(self) -> str:
return self.summary
def __rich_console__(
self, console: Console, options: ConsoleOptions
) -> RenderResult:

View File

@@ -9,11 +9,11 @@ from .tokenizer import TokenError
class DeclarationError(Exception):
def __init__(self, name: str, token: Token, message: str) -> None:
def __init__(self, name: str, token: Token, message: str | HelpText) -> None:
self.name = name
self.token = token
self.message = message
super().__init__(message)
super().__init__(str(message))
class StyleTypeError(TypeError):

View File

@@ -16,14 +16,14 @@ a method which evaluates the query, such as first() and last().
from __future__ import annotations
from typing import TYPE_CHECKING, Iterator, TypeVar, overload
import rich.repr
from typing import Iterator, overload, TypeVar, TYPE_CHECKING
from .errors import DeclarationError
from .match import match
from .parse import parse_selectors
from .model import SelectorSet
from .parse import parse_declarations, parse_selectors
if TYPE_CHECKING:
from ..dom import DOMNode
@@ -106,6 +106,9 @@ class DOMQuery:
def __iter__(self) -> Iterator[Widget]:
return iter(self.nodes)
def __reversed__(self) -> Iterator[Widget]:
return reversed(self.nodes)
@overload
def __getitem__(self, index: int) -> Widget:
...
@@ -229,14 +232,24 @@ class DOMQuery:
node.remove()
return self
def set_styles(self, css: str | None = None, **styles: str) -> DOMQuery:
def set_styles(self, css: str | None = None, **update_styles) -> DOMQuery:
"""Set styles on matched nodes.
Args:
css (str, optional): CSS declarations to parser, or None. Defaults to None.
"""
_rich_traceback_omit = True
for node in self.nodes:
node.set_styles(css, **styles)
node.set_styles(**update_styles)
if css is not None:
try:
new_styles = parse_declarations(css, path="set_styles")
except DeclarationError as error:
raise DeclarationError(error.name, error.token, error.message) from None
for node in self.nodes:
node._inline_styles.merge(new_styles)
node.refresh(layout=True)
return self
def refresh(self, *, repaint: bool = True, layout: bool = False) -> DOMQuery:

View File

@@ -15,7 +15,7 @@ from ._node_list import NodeList
from .color import Color, WHITE, BLACK
from .css._error_tools import friendly_list
from .css.constants import VALID_DISPLAY, VALID_VISIBILITY
from .css.errors import StyleValueError
from .css.errors import StyleValueError, DeclarationError
from .css.parse import parse_declarations
from .css.styles import Styles, RenderStyles
from .css.query import NoMatchingNodesError
@@ -23,7 +23,6 @@ from .message_pump import MessagePump
if TYPE_CHECKING:
from .app import App
from .css.styles import StylesBase
from .css.query import DOMQuery
from .screen import Screen
from .widget import Widget
@@ -603,16 +602,20 @@ class DOMNode(MessagePump):
else:
return query.first(expect_type)
def set_styles(self, css: str | None = None, **styles) -> None:
def set_styles(self, css: str | None = None, **update_styles) -> None:
"""Set custom styles on this object."""
# TODO: This can be done more efficiently
kwarg_css = "\n".join(
f"{key.replace('_', '-')}: {value}" for key, value in styles.items()
)
apply_css = f"{css or ''}\n{kwarg_css}\n"
new_styles = parse_declarations(apply_css, f"<custom styles for ${self!r}>")
self.styles.merge(new_styles)
self.refresh()
if css is not None:
try:
new_styles = parse_declarations(css, path="set_styles")
except DeclarationError as error:
raise DeclarationError(error.name, error.token, error.message) from None
self._inline_styles.merge(new_styles)
self.refresh(layout=True)
styles = self.styles
for key, value in update_styles.items():
setattr(styles, key, value)
def has_class(self, *class_names: str) -> bool:
"""Check if the Node has all the given class names.

View File

@@ -1,78 +0,0 @@
from __future__ import annotations
from datetime import datetime
from logging import getLogger
from rich.console import RenderableType
from rich.panel import Panel
from rich.repr import Result
from rich.style import StyleType, Style
from rich.table import Table
from .. import events
from ..reactive import watch, Reactive
from ..widget import Widget
log = getLogger("rich")
class Header(Widget):
def __init__(
self,
*,
tall: bool = True,
style: StyleType = "white on dark_green",
clock: bool = True,
) -> None:
super().__init__()
self.tall = tall
self.style = style
self.clock = clock
tall: Reactive[bool] = Reactive(True, layout=True)
style: Reactive[StyleType] = Reactive("white on blue")
clock: Reactive[bool] = Reactive(True)
title: Reactive[str] = Reactive("")
sub_title: Reactive[str] = Reactive("")
@property
def full_title(self) -> str:
return f"{self.title} - {self.sub_title}" if self.sub_title else self.title
def __rich_repr__(self) -> Result:
yield from super().__rich_repr__()
yield "title", self.title
async def watch_tall(self, tall: bool) -> None:
self.layout_size = 3 if tall else 1
def get_clock(self) -> str:
return datetime.now().time().strftime("%X")
def render(self) -> RenderableType:
header_table = Table.grid(padding=(0, 1), expand=True)
header_table.style = self.style
header_table.add_column(justify="left", ratio=0, width=8)
header_table.add_column("title", justify="center", ratio=1)
header_table.add_column("clock", justify="right", width=8)
header_table.add_row(
"🐞", self.full_title, self.get_clock() if self.clock else ""
)
header: RenderableType
header = Panel(header_table, style=self.style) if self.tall else header_table
return header
async def on_mount(self, event: events.Mount) -> None:
self.set_interval(1.0, callback=self.refresh)
async def set_title(title: str) -> None:
self.title = title
async def set_sub_title(sub_title: str) -> None:
self.sub_title = sub_title
watch(self.app, "title", set_title)
watch(self.app, "sub_title", set_sub_title)
async def on_click(self, event: events.Click) -> None:
self.tall = not self.tall