mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
startup
This commit is contained in:
@@ -17,7 +17,7 @@ class BasicApp(App):
|
||||
}
|
||||
|
||||
#widget1 {
|
||||
text: on blue;
|
||||
text-background: blue;
|
||||
dock-group: widgets;
|
||||
}
|
||||
|
||||
@@ -30,10 +30,11 @@ class BasicApp(App):
|
||||
|
||||
async def on_mount(self) -> None:
|
||||
"""Build layout here."""
|
||||
|
||||
self.log("MOUNT")
|
||||
await self.view.mount(
|
||||
sidebar=Placeholder(), widget1=Placeholder(), widget2=Placeholder()
|
||||
)
|
||||
self.log("MOUNTED CHILDREN", self.view.children)
|
||||
|
||||
|
||||
BasicApp.run(log="textual.log")
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
from typing import Any
|
||||
|
||||
from rich.console import RenderableType
|
||||
|
||||
__all__ = ["log", "panic"]
|
||||
|
||||
|
||||
def log(*args: Any, verbosity: int = 0, **kwargs) -> None:
|
||||
def log(*args: object, verbosity: int = 0, **kwargs) -> None:
|
||||
from ._context import active_app
|
||||
|
||||
app = active_app.get()
|
||||
app.log(*args, verbosity=verbosity, **kwargs)
|
||||
|
||||
|
||||
def panic(*args: Any) -> None:
|
||||
def panic(*args: RenderableType) -> None:
|
||||
from ._context import active_app
|
||||
|
||||
app = active_app.get()
|
||||
|
||||
@@ -30,6 +30,7 @@ from ._event_broker import extract_handler_actions, NoHandler
|
||||
from .driver import Driver
|
||||
from .layouts.dock import DockLayout, Dock
|
||||
from ._linux_driver import LinuxDriver
|
||||
from ._types import MessageTarget
|
||||
from .message_pump import MessagePump
|
||||
from ._profile import timer
|
||||
from .view import View
|
||||
@@ -53,6 +54,10 @@ else:
|
||||
uvloop.install()
|
||||
|
||||
|
||||
class AppError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ActionError(Exception):
|
||||
pass
|
||||
|
||||
@@ -90,7 +95,7 @@ class App(DOMNode):
|
||||
self.driver_class = driver_class or LinuxDriver
|
||||
self._title = title
|
||||
self._layout = DockLayout()
|
||||
self._view_stack: list[DockView] = []
|
||||
self._view_stack: list[View] = []
|
||||
|
||||
self.focused: Widget | None = None
|
||||
self.mouse_over: Widget | None = None
|
||||
@@ -211,7 +216,6 @@ class App(DOMNode):
|
||||
asyncio.run(run_app())
|
||||
|
||||
async def push_view(self, view: ViewType) -> ViewType:
|
||||
self.register(view, self)
|
||||
self._view_stack.append(view)
|
||||
return view
|
||||
|
||||
@@ -311,17 +315,19 @@ class App(DOMNode):
|
||||
self._print_error_renderables()
|
||||
return
|
||||
|
||||
self._running = True
|
||||
try:
|
||||
load_event = events.Load(sender=self)
|
||||
await self.dispatch_message(load_event)
|
||||
view = DockView()
|
||||
await self.mount(view)
|
||||
await self.push_view(view)
|
||||
await self.post_message(events.Mount(self))
|
||||
|
||||
# Wait for the load event to be processed, so we don't go in to application mode beforehand
|
||||
await load_event.wait()
|
||||
|
||||
await self.post_message(events.Mount(sender=self))
|
||||
|
||||
view = DockView()
|
||||
await self.mount(self, view)
|
||||
await self.push_view(view)
|
||||
|
||||
driver = self._driver = self.driver_class(self.console, self)
|
||||
|
||||
driver.start_application_mode()
|
||||
@@ -340,31 +346,42 @@ class App(DOMNode):
|
||||
except:
|
||||
self.panic()
|
||||
finally:
|
||||
self._running = False
|
||||
if self._exit_renderables:
|
||||
self._print_error_renderables()
|
||||
if self.log_file is not None:
|
||||
self.log_file.close()
|
||||
|
||||
def register(self, child: DOMNode, parent: DOMNode) -> bool:
|
||||
def _register(self, parent: DOMNode, child: DOMNode) -> bool:
|
||||
if child not in self.registry:
|
||||
parent.children._append(child)
|
||||
self.registry.add(child)
|
||||
child.set_parent(parent)
|
||||
child.start_messages()
|
||||
child.post_message_no_wait(events.Mount(sender=parent))
|
||||
parent.children._append(child)
|
||||
return True
|
||||
return False
|
||||
|
||||
async def mount(self, *anon_widgets: Widget, **widgets: Widget) -> None:
|
||||
async def mount(
|
||||
self, parent: DOMNode, *anon_widgets: Widget, **widgets: Widget
|
||||
) -> None:
|
||||
"""Mount widget(s) so they may receive events.
|
||||
|
||||
Args:
|
||||
parent (Widget): Parent Widget
|
||||
"""
|
||||
if not anon_widgets and not widgets:
|
||||
raise AppError(
|
||||
"Nothing to mount, did you forget parent as first positional arg?"
|
||||
)
|
||||
name_widgets: Iterable[tuple[str | None, Widget]]
|
||||
name_widgets = [*((None, widget) for widget in anon_widgets), *widgets.items()]
|
||||
apply_stylesheet = self.stylesheet.apply
|
||||
for widget_id, widget in name_widgets:
|
||||
if widget_id is not None:
|
||||
widget.id = widget_id
|
||||
self.register(widget, self)
|
||||
apply_stylesheet(widget)
|
||||
if widget not in self.registry:
|
||||
if widget_id is not None:
|
||||
widget.id = widget_id
|
||||
apply_stylesheet(widget)
|
||||
widget.post_message_no_wait(events.Mount(sender=parent))
|
||||
|
||||
def is_mounted(self, widget: Widget) -> bool:
|
||||
return widget in self.registry
|
||||
|
||||
@@ -174,7 +174,7 @@ class StyleProperty:
|
||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||
|
||||
self._color_name = f"_rule_{name}_color"
|
||||
self._bgcolor_name = f"_rule_{name}_bgcolor"
|
||||
self._bgcolor_name = f"_rule_{name}_background"
|
||||
self._style_name = f"_rule_{name}_style"
|
||||
|
||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style:
|
||||
|
||||
@@ -260,11 +260,11 @@ class StylesBuilder:
|
||||
name, token, f"unexpected token {token.value!r} in declaration"
|
||||
)
|
||||
|
||||
def process_text_bgcolor(self, name: str, tokens: list[Token]) -> None:
|
||||
def process_text_background(self, name: str, tokens: list[Token]) -> None:
|
||||
for token in tokens:
|
||||
if token.name in ("color", "token"):
|
||||
try:
|
||||
self.styles._rule_text_bgcolor = Color.parse(token.value)
|
||||
self.styles._rule_text_background = Color.parse(token.value)
|
||||
except Exception as error:
|
||||
self.error(
|
||||
name, token, f"failed to parse color {token.value!r}; {error}"
|
||||
|
||||
@@ -37,6 +37,7 @@ from ._style_properties import (
|
||||
from .types import Display, Visibility
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
@dataclass
|
||||
class Styles:
|
||||
|
||||
@@ -45,7 +46,7 @@ class Styles:
|
||||
_rule_layout: str | None = None
|
||||
|
||||
_rule_text_color: Color | None = None
|
||||
_rule_text_bgcolor: Color | None = None
|
||||
_rule_text_background: Color | None = None
|
||||
_rule_text_style: Style | None = None
|
||||
|
||||
_rule_padding: Spacing | None = None
|
||||
@@ -84,7 +85,7 @@ class Styles:
|
||||
|
||||
text = StyleProperty()
|
||||
text_color = ColorProperty()
|
||||
text_bgcolor = ColorProperty()
|
||||
text_background = ColorProperty()
|
||||
text_style = StyleFlagsProperty()
|
||||
|
||||
padding = SpacingProperty()
|
||||
@@ -250,7 +251,7 @@ class Styles:
|
||||
append_declaration("layers", " ".join(self.layers))
|
||||
if self._rule_layer is not None:
|
||||
append_declaration("layer", self.layer)
|
||||
if self._rule_text_color or self._rule_text_bgcolor or self._rule_text_style:
|
||||
if self._rule_text_color or self._rule_text_background or self._rule_text_style:
|
||||
append_declaration("text", str(self.text))
|
||||
|
||||
if self._rule_width is not None:
|
||||
|
||||
@@ -168,7 +168,9 @@ class Layout(ABC):
|
||||
"""
|
||||
|
||||
async def mount_all(self, view: "View") -> None:
|
||||
await view.mount(*self.get_widgets(view))
|
||||
widgets = list(self.get_widgets(view))
|
||||
if widgets:
|
||||
await view.mount(*widgets)
|
||||
|
||||
@property
|
||||
def map(self) -> LayoutMap | None:
|
||||
|
||||
@@ -5,8 +5,8 @@ from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, TYPE_CHECKING, Sequence
|
||||
|
||||
from ..app import active_app
|
||||
|
||||
from .. import log
|
||||
from ..dom import DOMNode
|
||||
from .._layout_resolve import layout_resolve
|
||||
from ..geometry import Offset, Region, Size
|
||||
@@ -48,14 +48,18 @@ class DockLayout(Layout):
|
||||
self._docks: list[Dock] | None = None
|
||||
|
||||
def get_docks(self, view: View) -> list[Dock]:
|
||||
log("CHILDREN", view.children)
|
||||
groups: dict[str, list[Widget]] = defaultdict(list)
|
||||
for child in view.children:
|
||||
assert isinstance(child, Widget)
|
||||
groups[child.styles.dock_group].append(child)
|
||||
log("GROUPS", groups)
|
||||
docks: list[Dock] = []
|
||||
append_dock = docks.append
|
||||
log("STYLES.DOCKS", view.styles)
|
||||
for name, edge in view.styles.docks:
|
||||
append_dock(Dock(edge, groups[name], 0))
|
||||
log("DOCKS", docks)
|
||||
return docks
|
||||
|
||||
def get_widgets(self, view: View) -> Iterable[DOMNode]:
|
||||
|
||||
@@ -138,7 +138,7 @@ class View(Widget):
|
||||
self.app.refresh()
|
||||
|
||||
async def mount(self, *anon_widgets: Widget, **widgets: Widget) -> None:
|
||||
await self.app.mount(*anon_widgets, **widgets)
|
||||
await self.app.mount(self, *anon_widgets, **widgets)
|
||||
self.refresh()
|
||||
|
||||
async def refresh_layout(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user