mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Fixing vertical layout
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
/* CSS file for dev_sandbox.py */
|
/* CSS file for dev_sandbox.py */
|
||||||
|
|
||||||
App > View {
|
App > View {
|
||||||
docks: side=left/1;
|
layout: vertical;
|
||||||
text: on #20639b;
|
text: on #6e06c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget:hover {
|
Widget:hover {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from textual.widget import Widget
|
|||||||
|
|
||||||
class PanelWidget(Widget):
|
class PanelWidget(Widget):
|
||||||
def render(self) -> RenderableType:
|
def render(self) -> RenderableType:
|
||||||
return Panel("hello world!", title="Title")
|
return Panel("hello world!", title="Title", height=4)
|
||||||
|
|
||||||
|
|
||||||
class BasicApp(App):
|
class BasicApp(App):
|
||||||
@@ -21,12 +21,8 @@ class BasicApp(App):
|
|||||||
|
|
||||||
def on_mount(self):
|
def on_mount(self):
|
||||||
"""Build layout here."""
|
"""Build layout here."""
|
||||||
self.mount(
|
self.mount(header=PanelWidget(), content=PanelWidget(), footer=PanelWidget())
|
||||||
header=Widget(),
|
self.view.refresh_layout()
|
||||||
content=PanelWidget(),
|
|
||||||
footer=Widget(),
|
|
||||||
sidebar=Widget(),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
BasicApp.run(css_file="test_app.css", watch_css=True, log="textual.log")
|
BasicApp.run(log="textual.log")
|
||||||
|
|||||||
@@ -254,7 +254,6 @@ class App(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
widget (Widget): [description]
|
widget (Widget): [description]
|
||||||
"""
|
"""
|
||||||
log("set_focus", widget)
|
|
||||||
if widget == self.focused:
|
if widget == self.focused:
|
||||||
# Widget is already focused
|
# Widget is already focused
|
||||||
return
|
return
|
||||||
@@ -380,7 +379,7 @@ class App(DOMNode):
|
|||||||
if self.log_file is not None:
|
if self.log_file is not None:
|
||||||
self.log_file.close()
|
self.log_file.close()
|
||||||
|
|
||||||
def _register(self, parent: DOMNode, child: DOMNode) -> bool:
|
def _register_child(self, parent: DOMNode, child: DOMNode) -> bool:
|
||||||
if child not in self.registry:
|
if child not in self.registry:
|
||||||
parent.children._append(child)
|
parent.children._append(child)
|
||||||
self.registry.add(child)
|
self.registry.add(child)
|
||||||
@@ -409,7 +408,7 @@ class App(DOMNode):
|
|||||||
if widget not in self.registry:
|
if widget not in self.registry:
|
||||||
if widget_id is not None:
|
if widget_id is not None:
|
||||||
widget.id = widget_id
|
widget.id = widget_id
|
||||||
self._register(parent, widget)
|
self._register_child(parent, child=widget)
|
||||||
apply_stylesheet(widget)
|
apply_stylesheet(widget)
|
||||||
|
|
||||||
for _widget_id, widget in name_widgets:
|
for _widget_id, widget in name_widgets:
|
||||||
@@ -432,7 +431,7 @@ class App(DOMNode):
|
|||||||
driver.disable_input()
|
driver.disable_input()
|
||||||
await self.close_messages()
|
await self.close_messages()
|
||||||
|
|
||||||
def refresh(self, repaint: bool = True, layout: bool = False) -> None:
|
def refresh(self) -> None:
|
||||||
sync_available = os.environ.get("TERM_PROGRAM", "") != "Apple_Terminal"
|
sync_available = os.environ.get("TERM_PROGRAM", "") != "Apple_Terminal"
|
||||||
if not self._closed:
|
if not self._closed:
|
||||||
console = self.console
|
console = self.console
|
||||||
@@ -627,51 +626,3 @@ class App(DOMNode):
|
|||||||
self.reset_styles()
|
self.reset_styles()
|
||||||
self.stylesheet.update(self)
|
self.stylesheet.update(self)
|
||||||
self.view.refresh(layout=True)
|
self.view.refresh(layout=True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from .widgets import Header
|
|
||||||
from .widgets import Footer
|
|
||||||
|
|
||||||
from .widgets import Placeholder
|
|
||||||
|
|
||||||
# from .widgets.scroll_view import ScrollView
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
class MyApp(App):
|
|
||||||
"""Just a test app."""
|
|
||||||
|
|
||||||
async def on_load(self, event: events.Load) -> None:
|
|
||||||
await self.bind("ctrl+c", "quit", show=False)
|
|
||||||
await self.bind("q", "quit", "Quit")
|
|
||||||
await self.bind("x", "bang", "Test error handling")
|
|
||||||
await self.bind("b", "toggle_sidebar", "Toggle sidebar")
|
|
||||||
|
|
||||||
show_bar: Reactive[bool] = Reactive(False)
|
|
||||||
|
|
||||||
async def watch_show_bar(self, show_bar: bool) -> None:
|
|
||||||
self.animator.animate(self.bar, "layout_offset_x", 0 if show_bar else -40)
|
|
||||||
|
|
||||||
async def action_toggle_sidebar(self) -> None:
|
|
||||||
self.show_bar = not self.show_bar
|
|
||||||
|
|
||||||
async def on_mount(self, event: events.Mount) -> None:
|
|
||||||
view = await self.push_view(DockView())
|
|
||||||
|
|
||||||
header = Header()
|
|
||||||
footer = Footer()
|
|
||||||
self.bar = Placeholder(name="left")
|
|
||||||
|
|
||||||
await view.dock(header, edge="top")
|
|
||||||
await view.dock(footer, edge="bottom")
|
|
||||||
await view.dock(self.bar, edge="left", size=40, z=1)
|
|
||||||
self.bar.layout_offset_x = -40
|
|
||||||
|
|
||||||
sub_view = DockView()
|
|
||||||
await sub_view.dock(Placeholder(), Placeholder(), edge="top")
|
|
||||||
await view.dock(sub_view, edge="left")
|
|
||||||
|
|
||||||
MyApp.run(log="textual.log")
|
|
||||||
|
|||||||
@@ -159,9 +159,9 @@ class Layout(ABC):
|
|||||||
"""Generate a layout map that defines where on the screen the widgets will be drawn.
|
"""Generate a layout map that defines where on the screen the widgets will be drawn.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
console (Console): Console instance.
|
view (View): The View instance.
|
||||||
size (Dimensions): Size of container.
|
size (Size): Size of container.
|
||||||
viewport (Region): Screen relative viewport.
|
scroll (Offset): Offset to apply to the Widget placements.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Iterable[WidgetPlacement]: An iterable of widget location
|
Iterable[WidgetPlacement]: An iterable of widget location
|
||||||
|
|||||||
@@ -22,25 +22,15 @@ class VerticalLayout(Layout):
|
|||||||
self.auto_width = auto_width
|
self.auto_width = auto_width
|
||||||
self.z = z
|
self.z = z
|
||||||
self.gutter = Spacing.unpack(gutter)
|
self.gutter = Spacing.unpack(gutter)
|
||||||
self._widgets: list[Widget] = []
|
|
||||||
self._max_widget_width = 0
|
self._max_widget_width = 0
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def add(self, widget: Widget) -> None:
|
def get_widgets(self, view: View) -> Iterable[Widget]:
|
||||||
self._widgets.append(widget)
|
return view.children
|
||||||
self._max_widget_width = max(widget.app.measure(widget), self._max_widget_width)
|
|
||||||
|
|
||||||
def clear(self) -> None:
|
|
||||||
del self._widgets[:]
|
|
||||||
self._max_widget_width = 0
|
|
||||||
|
|
||||||
def get_widgets(self) -> Iterable[Widget]:
|
|
||||||
return self._widgets
|
|
||||||
|
|
||||||
def arrange(
|
def arrange(
|
||||||
self, view: View, size: Size, scroll: Offset
|
self, view: View, size: Size, scroll: Offset
|
||||||
) -> Iterable[WidgetPlacement]:
|
) -> Iterable[WidgetPlacement]:
|
||||||
index = 0
|
|
||||||
width, _height = size
|
width, _height = size
|
||||||
gutter = self.gutter
|
gutter = self.gutter
|
||||||
x, y = self.gutter.top_left
|
x, y = self.gutter.top_left
|
||||||
@@ -51,10 +41,9 @@ class VerticalLayout(Layout):
|
|||||||
)
|
)
|
||||||
|
|
||||||
total_width = render_width
|
total_width = render_width
|
||||||
|
|
||||||
gutter_height = max(gutter.top, gutter.bottom)
|
gutter_height = max(gutter.top, gutter.bottom)
|
||||||
|
|
||||||
for last, widget in loop_last(self._widgets):
|
for last, widget in loop_last(view.children):
|
||||||
if (
|
if (
|
||||||
not widget.render_cache
|
not widget.render_cache
|
||||||
or widget.render_cache.size.width != render_width
|
or widget.render_cache.size.width != render_width
|
||||||
@@ -63,7 +52,7 @@ class VerticalLayout(Layout):
|
|||||||
assert widget.render_cache is not None
|
assert widget.render_cache is not None
|
||||||
render_height = widget.render_cache.size.height
|
render_height = widget.render_cache.size.height
|
||||||
region = Region(x, y, render_width, render_height)
|
region = Region(x, y, render_width, render_height)
|
||||||
yield WidgetPlacement(region, widget, (self.z, index))
|
yield WidgetPlacement(region, widget, self.z)
|
||||||
y += render_height + (gutter.bottom if last else gutter_height)
|
y += render_height + (gutter.bottom if last else gutter_height)
|
||||||
|
|
||||||
yield WidgetPlacement(Region(0, 0, total_width + gutter.width, y))
|
yield WidgetPlacement(Region(0, 0, total_width + gutter.width, y))
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ from typing import (
|
|||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import log
|
|
||||||
from . import events
|
from . import events
|
||||||
|
|
||||||
from ._callback import count_parameters, invoke
|
from ._callback import count_parameters, invoke
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class View(Widget):
|
|||||||
|
|
||||||
def __init__(self, name: str | None = None, id: str | None = None) -> None:
|
def __init__(self, name: str | None = None, id: str | None = None) -> None:
|
||||||
self.mouse_over: Widget | None = None
|
self.mouse_over: Widget | None = None
|
||||||
self.widgets: set[Widget] = set()
|
|
||||||
self._mouse_style: Style = Style()
|
self._mouse_style: Style = Style()
|
||||||
self._mouse_widget: Widget | None = None
|
self._mouse_widget: Widget | None = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user