Merge branch 'css' of github.com:Textualize/textual into render-style

This commit is contained in:
Darren Burns
2022-05-06 11:08:56 +01:00
6 changed files with 50 additions and 9 deletions

View File

@@ -1,3 +1,7 @@
App.-show-focus *:focus {
tint: #8bc34a 50%;
}
#uber1 {
layout: vertical;
background: green;
@@ -6,8 +10,12 @@
text-style: underline;
}
#uber1:focus-within {
background: darkslateblue;
}
.list-item {
height: 8;
height: 10;
color: #12a0;
background: #ffffff00;
}

View File

@@ -22,8 +22,9 @@ class BasicApp(App):
async def on_mount(self):
"""Build layout here."""
first_child = Placeholder(id="child1", classes="list-item")
uber1 = Widget(
Placeholder(id="child1", classes="list-item"),
first_child,
Placeholder(id="child2", classes="list-item"),
Placeholder(id="child3", classes="list-item"),
Placeholder(classes="list-item"),
@@ -32,6 +33,8 @@ class BasicApp(App):
)
self.mount(uber1=uber1)
uber1.focus()
self.first_child = first_child
self.uber = uber1
async def on_key(self, event: events.Key) -> None:
await self.dispatch_key(event)
@@ -50,8 +53,7 @@ class BasicApp(App):
"Focused widget is:",
self.focused,
)
print(1234, 5678)
sys.stdout.write("abcdef")
self.app.set_focus(None)
def action_modify_focussed(self):
"""Increment height of focussed child, randomise border and bg color"""

View File

@@ -540,16 +540,19 @@ class App(Generic[ReturnType], DOMNode):
# No focus, so blur currently focused widget if it exists
if self.focused is not None:
self.focused.post_message_no_wait(events.Blur(self))
self.focused.emit_no_wait(events.DescendantBlur(self))
self.focused = None
elif widget.can_focus:
if self.focused != widget:
if self.focused is not None:
# Blur currently focused widget
self.focused.post_message_no_wait(events.Blur(self))
self.focused.emit_no_wait(events.DescendantBlur(self))
# Change focus
self.focused = widget
# Send focus event
widget.post_message_no_wait(events.Focus(self))
widget.emit_no_wait(events.DescendantFocus(self))
async def _set_mouse_over(self, widget: Widget | None) -> None:
"""Called when the mouse is over another widget.

View File

@@ -393,3 +393,11 @@ class Focus(Event, bubble=False):
class Blur(Event, bubble=False):
pass
class DescendantFocus(Event, bubble=True):
pass
class DescendantBlur(Event, bubble=True):
pass

View File

@@ -246,7 +246,9 @@ class MessagePump:
if self._message_queue.empty():
if not self._closed:
event = events.Idle(self)
for method in self._get_dispatch_methods("on_idle", event):
for _cls, method in self._get_dispatch_methods(
"on_idle", event
):
await invoke(method, event)
log("CLOSED", self)
@@ -264,18 +266,25 @@ class MessagePump:
def _get_dispatch_methods(
self, method_name: str, message: Message
) -> Iterable[Callable[[Message], Awaitable]]:
) -> Iterable[tuple[type, Callable[[Message], Awaitable]]]:
for cls in self.__class__.__mro__:
if message._no_default_action:
break
method = cls.__dict__.get(method_name, None)
if method is not None:
yield method.__get__(self, cls)
yield cls, method.__get__(self, cls)
async def on_event(self, event: events.Event) -> None:
_rich_traceback_guard = True
for method in self._get_dispatch_methods(f"on_{event.name}", event):
log(event, ">>>", self, verbosity=event.verbosity)
for cls, method in self._get_dispatch_methods(f"on_{event.name}", event):
log(
event,
">>>",
self,
f"method=<{cls.__name__}.{method.__func__.__name__}>",
verbosity=event.verbosity,
)
await invoke(method, event)
if event.bubble and self._parent and not event._stop_propagation:

View File

@@ -99,6 +99,7 @@ class Widget(DOMNode):
auto_width = Reactive(True)
auto_height = Reactive(True)
has_focus = Reactive(False)
descendant_has_focus = Reactive(False)
mouse_over = Reactive(False)
scroll_x = Reactive(0.0, repaint=False)
scroll_y = Reactive(0.0, repaint=False)
@@ -451,6 +452,8 @@ class Widget(DOMNode):
yield "hover"
if self.has_focus:
yield "focus"
if self.descendant_has_focus:
yield "focus-within"
def watch(self, attribute_name, callback: Callable[[Any], Awaitable[None]]) -> None:
watch(self, attribute_name, callback)
@@ -753,11 +756,19 @@ class Widget(DOMNode):
self.mouse_over = True
def on_focus(self, event: events.Focus) -> None:
self.emit_no_wait(events.DescendantFocus(self))
self.has_focus = True
def on_blur(self, event: events.Blur) -> None:
self.emit_no_wait(events.DescendantBlur(self))
self.has_focus = False
def on_descendant_focus(self, event: events.DescendantFocus) -> None:
self.descendant_has_focus = True
def on_descendant_blur(self, event: events.DescendantBlur) -> None:
self.descendant_has_focus = False
def on_mouse_scroll_down(self, event) -> None:
if self.is_container:
self.scroll_down(animate=False)