mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
virtual size
This commit is contained in:
@@ -29,7 +29,9 @@ class MyApp(App):
|
|||||||
|
|
||||||
await self.view.dock(Header(), edge="top")
|
await self.view.dock(Header(), edge="top")
|
||||||
await self.view.dock(Footer(), edge="bottom")
|
await self.view.dock(Footer(), edge="bottom")
|
||||||
await self.view.dock(self.directory, edge="left", size=32, name="sidebar")
|
await self.view.dock(
|
||||||
|
ScrollView(self.directory), edge="left", size=32, name="sidebar"
|
||||||
|
)
|
||||||
await self.view.dock(self.body, edge="right")
|
await self.view.dock(self.body, edge="right")
|
||||||
|
|
||||||
async def message_file_click(self, message: FileClick) -> None:
|
async def message_file_click(self, message: FileClick) -> None:
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class Show(Event):
|
|||||||
|
|
||||||
|
|
||||||
class Hide(Event):
|
class Hide(Event):
|
||||||
"""Send when a widget has been hidden.
|
"""Sent when a widget has been hidden.
|
||||||
|
|
||||||
A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout,
|
A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout,
|
||||||
or if it has been offset beyond the edges of the terminal.
|
or if it has been offset beyond the edges of the terminal.
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ class RenderRegion(NamedTuple):
|
|||||||
|
|
||||||
class LayoutMap:
|
class LayoutMap:
|
||||||
def __init__(self, size: Dimensions) -> None:
|
def __init__(self, size: Dimensions) -> None:
|
||||||
self.region = size.region
|
self.size = size
|
||||||
|
self.contents_region = Region(0, 0, 0, 0)
|
||||||
self.widgets: dict[Widget, RenderRegion] = {}
|
self.widgets: dict[Widget, RenderRegion] = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self) -> Dimensions:
|
def virtual_size(self) -> Dimensions:
|
||||||
return self.region.size
|
return self.contents_region.size
|
||||||
|
|
||||||
def __getitem__(self, widget: Widget) -> RenderRegion:
|
def __getitem__(self, widget: Widget) -> RenderRegion:
|
||||||
return self.widgets[widget]
|
return self.widgets[widget]
|
||||||
@@ -51,7 +52,7 @@ class LayoutMap:
|
|||||||
|
|
||||||
region += widget.layout_offset
|
region += widget.layout_offset
|
||||||
self.widgets[widget] = RenderRegion(region, order, clip)
|
self.widgets[widget] = RenderRegion(region, order, clip)
|
||||||
self.region = self.region.union(region)
|
self.contents_region = self.contents_region.union(region)
|
||||||
|
|
||||||
if isinstance(widget, View):
|
if isinstance(widget, View):
|
||||||
sub_map = widget.layout.generate_map(
|
sub_map = widget.layout.generate_map(
|
||||||
|
|||||||
@@ -56,9 +56,11 @@ class View(Widget):
|
|||||||
def scroll(self) -> Offset:
|
def scroll(self) -> Offset:
|
||||||
return Offset(self.scroll_x, self.scroll_y)
|
return Offset(self.scroll_x, self.scroll_y)
|
||||||
|
|
||||||
@property
|
virtual_size: Reactive[Dimensions] = Reactive(Dimensions(0, 0))
|
||||||
def virtual_size(self) -> Dimensions:
|
|
||||||
return self.layout.map.size if self.layout.map else Dimensions(0, 0)
|
# @property
|
||||||
|
# def virtual_size(self) -> Dimensions:
|
||||||
|
# return self.layout.map.size if self.layout.map else Dimensions(0, 0)
|
||||||
|
|
||||||
# virtual_width: Reactive[int | None] = Reactive(None)
|
# virtual_width: Reactive[int | None] = Reactive(None)
|
||||||
# virtual_height: Reactive[int | None] = Reactive(None)
|
# virtual_height: Reactive[int | None] = Reactive(None)
|
||||||
@@ -157,6 +159,7 @@ class View(Widget):
|
|||||||
hidden, shown, resized = self.layout.reflow(
|
hidden, shown, resized = self.layout.reflow(
|
||||||
self.console, width, height, self.scroll
|
self.console, width, height, self.scroll
|
||||||
)
|
)
|
||||||
|
self.virtual_size = self.layout.map.virtual_size
|
||||||
self.app.refresh()
|
self.app.refresh()
|
||||||
|
|
||||||
for widget in hidden:
|
for widget in hidden:
|
||||||
|
|||||||
@@ -2,12 +2,18 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from rich.console import RenderableType
|
from rich.console import RenderableType
|
||||||
|
|
||||||
|
from ..geometry import Offset, Dimensions
|
||||||
from ..layouts.vertical import VerticalLayout
|
from ..layouts.vertical import VerticalLayout
|
||||||
from ..view import View
|
from ..view import View
|
||||||
|
from ..message import Message
|
||||||
from ..widget import Widget
|
from ..widget import Widget
|
||||||
from ..widgets import Static
|
from ..widgets import Static
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualSizeChange(Message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class WindowView(View, layout=VerticalLayout):
|
class WindowView(View, layout=VerticalLayout):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -26,4 +32,8 @@ class WindowView(View, layout=VerticalLayout):
|
|||||||
assert isinstance(layout, VerticalLayout)
|
assert isinstance(layout, VerticalLayout)
|
||||||
layout.clear()
|
layout.clear()
|
||||||
layout.add(widget if isinstance(widget, Widget) else Static(widget))
|
layout.add(widget if isinstance(widget, Widget) else Static(widget))
|
||||||
|
await self.refresh_layout()
|
||||||
self.require_layout()
|
self.require_layout()
|
||||||
|
|
||||||
|
async def watch_virtual_size(self, size: Dimensions) -> None:
|
||||||
|
await self.emit(VirtualSizeChange(self))
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ from .. import events
|
|||||||
from ..layouts.grid import GridLayout
|
from ..layouts.grid import GridLayout
|
||||||
from ..message import Message
|
from ..message import Message
|
||||||
from ..scrollbar import ScrollTo, ScrollBar
|
from ..scrollbar import ScrollTo, ScrollBar
|
||||||
from ..geometry import clamp
|
from ..geometry import clamp, Offset, Dimensions
|
||||||
from ..page import Page
|
from ..page import Page
|
||||||
|
from ..reactive import watch
|
||||||
from ..view import View
|
from ..view import View
|
||||||
from ..widgets import Placeholder
|
from ..widget import Widget
|
||||||
|
|
||||||
|
|
||||||
from ..reactive import Reactive
|
from ..reactive import Reactive
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ from ..reactive import Reactive
|
|||||||
class ScrollView(View):
|
class ScrollView(View):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
renderable: RenderableType | None = None,
|
contents: RenderableType | Widget | None = None,
|
||||||
*,
|
*,
|
||||||
name: str | None = None,
|
name: str | None = None,
|
||||||
style: StyleType = "",
|
style: StyleType = "",
|
||||||
@@ -32,7 +32,7 @@ class ScrollView(View):
|
|||||||
self.fluid = fluid
|
self.fluid = fluid
|
||||||
self.vscroll = ScrollBar(vertical=True)
|
self.vscroll = ScrollBar(vertical=True)
|
||||||
self.hscroll = ScrollBar(vertical=False)
|
self.hscroll = ScrollBar(vertical=False)
|
||||||
self.window = WindowView("" if renderable is None else renderable)
|
self.window = WindowView("" if contents is None else contents)
|
||||||
layout = GridLayout()
|
layout = GridLayout()
|
||||||
layout.add_column("main")
|
layout.add_column("main")
|
||||||
layout.add_column("vscroll", size=1)
|
layout.add_column("vscroll", size=1)
|
||||||
@@ -70,9 +70,11 @@ class ScrollView(View):
|
|||||||
async def watch_y(self, new_value: float) -> None:
|
async def watch_y(self, new_value: float) -> None:
|
||||||
self.window.scroll_y = round(new_value)
|
self.window.scroll_y = round(new_value)
|
||||||
self.vscroll.position = round(new_value)
|
self.vscroll.position = round(new_value)
|
||||||
|
# self.window.require_repaint()
|
||||||
|
self.window.require_layout()
|
||||||
|
|
||||||
async def update(self, renderabe: RenderableType) -> None:
|
async def update(self, renderable: RenderableType) -> None:
|
||||||
await self.window.update(renderabe)
|
await self.window.update(renderable)
|
||||||
|
|
||||||
async def on_mount(self, event: events.Mount) -> None:
|
async def on_mount(self, event: events.Mount) -> None:
|
||||||
assert isinstance(self.layout, GridLayout)
|
assert isinstance(self.layout, GridLayout)
|
||||||
@@ -172,19 +174,17 @@ class ScrollView(View):
|
|||||||
self.animate("x", self.target_x, speed=150, easing="out_cubic")
|
self.animate("x", self.target_x, speed=150, easing="out_cubic")
|
||||||
self.animate("y", self.target_y, speed=150, easing="out_cubic")
|
self.animate("y", self.target_y, speed=150, easing="out_cubic")
|
||||||
|
|
||||||
async def message_page_update(self, message: Message) -> None:
|
async def message_virtual_size_change(self, message: Message) -> None:
|
||||||
|
virtual_size = self.window.virtual_size
|
||||||
|
self.log("VIRTUAL_SIZE", self.size, virtual_size)
|
||||||
self.x = self.validate_x(self.x)
|
self.x = self.validate_x(self.x)
|
||||||
self.y = self.validate_y(self.y)
|
self.y = self.validate_y(self.y)
|
||||||
self.vscroll.virtual_size = self.window.virtual_size.height
|
self.vscroll.virtual_size = virtual_size.height
|
||||||
self.vscroll.window_size = self.size.height
|
self.vscroll.window_size = self.size.height
|
||||||
|
|
||||||
assert isinstance(self.layout, GridLayout)
|
assert isinstance(self.layout, GridLayout)
|
||||||
|
|
||||||
if self.layout.show_column(
|
if self.layout.show_column("vscroll", virtual_size.height > self.size.height):
|
||||||
"vscroll", self.window.virtual_size.height > self.size.height
|
|
||||||
):
|
|
||||||
self.require_layout()
|
self.require_layout()
|
||||||
if self.layout.show_row(
|
if self.layout.show_row("hscroll", virtual_size.width > self.size.width):
|
||||||
"hscroll", self.window.virtual_size.width > self.size.width
|
|
||||||
):
|
|
||||||
self.require_layout()
|
self.require_layout()
|
||||||
|
|||||||
Reference in New Issue
Block a user