mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Improve order of focus
This commit is contained in:
@@ -1,6 +1,61 @@
|
|||||||
#box {
|
Screen {
|
||||||
height: 50%;
|
height: 100vh;
|
||||||
width: 50%;
|
width: 100%;
|
||||||
align: center middle;
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#horizontal {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
height: 5;
|
||||||
|
width: 5;
|
||||||
|
margin: 1 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left_pane {
|
||||||
|
width: 1fr;
|
||||||
|
background: $background;
|
||||||
|
}
|
||||||
|
|
||||||
|
#middle_pane {
|
||||||
|
margin-top: 4;
|
||||||
|
width: 1fr;
|
||||||
|
background: #173f5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#middle_pane:focus {
|
||||||
|
outline: #8bc34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right_pane {
|
||||||
|
width: 1fr;
|
||||||
|
background: #f6d55c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:focus {
|
||||||
|
outline: #8bc34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#box1 {
|
||||||
background: green;
|
background: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#box2 {
|
||||||
|
offset-y: 3;
|
||||||
|
background: hotpink;
|
||||||
|
}
|
||||||
|
|
||||||
|
#box3 {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#box4 {
|
||||||
|
background: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#box5 {
|
||||||
|
background: darkviolet;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ from rich.console import RenderableType
|
|||||||
from rich.panel import Panel
|
from rich.panel import Panel
|
||||||
|
|
||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
|
from textual.layout import Horizontal, Vertical
|
||||||
from textual.widget import Widget
|
from textual.widget import Widget
|
||||||
|
|
||||||
|
|
||||||
class Box(Widget):
|
class Box(Widget, can_focus=True):
|
||||||
CSS = "#box {background: blue;}"
|
CSS = "#box {background: blue;}"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -20,8 +21,25 @@ class Box(Widget):
|
|||||||
|
|
||||||
|
|
||||||
class JustABox(App):
|
class JustABox(App):
|
||||||
|
dark = True
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
yield Box(id="box")
|
yield Horizontal(
|
||||||
|
Vertical(
|
||||||
|
Box(id="box1", classes="box"),
|
||||||
|
Box(id="box2", classes="box"),
|
||||||
|
Box(id="box3", classes="box"),
|
||||||
|
id="left_pane",
|
||||||
|
),
|
||||||
|
Box(id="middle_pane"),
|
||||||
|
Vertical(
|
||||||
|
Box(id="box", classes="box"),
|
||||||
|
Box(id="box4", classes="box"),
|
||||||
|
Box(id="box5", classes="box"),
|
||||||
|
id="right_pane",
|
||||||
|
),
|
||||||
|
id="horizontal",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -19,15 +19,14 @@ from .css.errors import StyleValueError
|
|||||||
from .css.parse import parse_declarations
|
from .css.parse import parse_declarations
|
||||||
from .css.styles import Styles, RenderStyles
|
from .css.styles import Styles, RenderStyles
|
||||||
from .css.query import NoMatchingNodesError
|
from .css.query import NoMatchingNodesError
|
||||||
from .geometry import Region
|
|
||||||
from .message_pump import MessagePump
|
from .message_pump import MessagePump
|
||||||
from .widget import Widget
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .app import App
|
from .app import App
|
||||||
from .css.styles import StylesBase
|
from .css.styles import StylesBase
|
||||||
from .css.query import DOMQuery
|
from .css.query import DOMQuery
|
||||||
from .screen import Screen
|
from .screen import Screen
|
||||||
|
from .widget import Widget
|
||||||
|
|
||||||
|
|
||||||
class NoParent(Exception):
|
class NoParent(Exception):
|
||||||
@@ -430,11 +429,11 @@ class DOMNode(MessagePump):
|
|||||||
@property
|
@property
|
||||||
def focusable_children(self) -> list[DOMNode]:
|
def focusable_children(self) -> list[DOMNode]:
|
||||||
"""Get the children which may be focused."""
|
"""Get the children which may be focused."""
|
||||||
# TODO: This may be the place to define order, other focus related rules
|
|
||||||
focusable = [
|
focusable = [
|
||||||
child for child in self.children if child.display and child.visible
|
child for child in self.children if child.display and child.visible
|
||||||
]
|
]
|
||||||
return sorted(focusable, key=_focus_sort_key)
|
sorted_focusable = sorted(focusable, key=_focus_sort_key)
|
||||||
|
return sorted_focusable
|
||||||
|
|
||||||
def get_pseudo_classes(self) -> Iterable[str]:
|
def get_pseudo_classes(self) -> Iterable[str]:
|
||||||
"""Get any pseudo classes applicable to this Node, e.g. hover, focus.
|
"""Get any pseudo classes applicable to this Node, e.g. hover, focus.
|
||||||
@@ -604,5 +603,5 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
|
|
||||||
def _focus_sort_key(widget: Widget) -> tuple[int, int]:
|
def _focus_sort_key(widget: Widget) -> tuple[int, int]:
|
||||||
x, y = widget.content_offset
|
x, y, _, _ = widget.region_with_margin
|
||||||
return y, x
|
return y, x
|
||||||
|
|||||||
@@ -494,6 +494,16 @@ class Widget(DOMNode):
|
|||||||
window_region = self.region.at_offset(self.scroll_offset)
|
window_region = self.region.at_offset(self.scroll_offset)
|
||||||
return window_region
|
return window_region
|
||||||
|
|
||||||
|
@property
|
||||||
|
def region_with_margin(self) -> Region:
|
||||||
|
"""The widget region relative to its container (*including margin*), which may not be visible,
|
||||||
|
depending on the scroll offset.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Region: The virtual region of the Widget, inclusive of its margin.
|
||||||
|
"""
|
||||||
|
return self.virtual_region.grow(self.styles.margin)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scroll_offset(self) -> Offset:
|
def scroll_offset(self) -> Offset:
|
||||||
return Offset(int(self.scroll_x), int(self.scroll_y))
|
return Offset(int(self.scroll_x), int(self.scroll_y))
|
||||||
@@ -736,7 +746,7 @@ class Widget(DOMNode):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Grow the region by the margin so to keep the margin in view.
|
# Grow the region by the margin so to keep the margin in view.
|
||||||
region = widget.virtual_region.grow(widget.styles.margin)
|
region = widget.region_with_margin
|
||||||
scrolled = False
|
scrolled = False
|
||||||
|
|
||||||
while isinstance(widget.parent, Widget) and widget is not self:
|
while isinstance(widget.parent, Widget) and widget is not self:
|
||||||
|
|||||||
Reference in New Issue
Block a user