Skip to content

Commit b4b8449

Browse files
committed
clipping widgets
1 parent 245033e commit b4b8449

File tree

6 files changed

+41
-76
lines changed

6 files changed

+41
-76
lines changed

poetry.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/textual/app.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,8 @@ async def action_toggle_sidebar(self) -> None:
386386
self.animator.animate(
387387
self.bar,
388388
"layout_offset_x",
389-
20 if self.side else 0,
390-
speed=30,
389+
-40 if self.side else 0,
390+
speed=60,
391391
easing="in_out_cubic",
392392
)
393393

@@ -403,7 +403,9 @@ async def on_startup(self, event: events.Startup) -> None:
403403

404404
await view.dock(header, edge="top")
405405
await view.dock(footer, edge="bottom")
406-
await view.dock(self.bar, edge="left", size=30, z=1)
406+
await view.dock(self.bar, edge="left", size=40, z=1)
407+
408+
# await view.dock(Placeholder(), Placeholder(), edge="top")
407409

408410
sub_view = DockView()
409411
await sub_view.dock(Placeholder(), Placeholder(), edge="top")

src/textual/layout.py

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class MapRegion(NamedTuple):
3636
order: tuple[int, int]
3737

3838

39+
class ReflowResult(NamedTuple):
40+
hidden: set[Widget]
41+
shown: set[Widget]
42+
43+
3944
class LayoutUpdate:
4045
def __init__(self, lines: Lines, x: int, y: int) -> None:
4146
self.lines = lines
@@ -70,10 +75,16 @@ def reset(self) -> None:
7075
self.renders.clear()
7176
self._cuts = None
7277

73-
def reflow(self, width: int, height: int) -> None:
78+
def reflow(self, width: int, height: int) -> ReflowResult:
7479
self.reset()
7580

7681
map = self.generate_map(width, height)
82+
83+
old_widgets = set(self._layout_map.keys())
84+
new_widgets = set(map.keys())
85+
shown_widgets = new_widgets - old_widgets
86+
hidden_widgets = old_widgets - new_widgets
87+
7788
self._layout_map = map
7889
self.width = width
7990
self.height = height
@@ -84,6 +95,7 @@ def reflow(self, width: int, height: int) -> None:
8495
new_renders[widget] = (region, self.renders[widget][1])
8596

8697
self.renders = new_renders
98+
return ReflowResult(hidden_widgets, shown_widgets)
8799

88100
@abstractmethod
89101
def generate_map(
@@ -150,37 +162,6 @@ def cuts(self) -> list[list[int]]:
150162
self._cuts = [sorted(cut_set) for cut_set in cuts_sets]
151163
return self._cuts
152164

153-
@classmethod
154-
def _compare_lines(cls, lines1: Lines, lines2: Lines) -> Iterable[list[Segment]]:
155-
"""Compares two renders and produce 'diff'"""
156-
delta_line: list[Segment] = [Control.home().segment]
157-
add_delta_segment = delta_line.append
158-
move_to_column = Control.move_to_column
159-
160-
for y, (line1, line2) in enumerate(zip(lines1, lines2)):
161-
if line1 == line2:
162-
continue
163-
164-
add_delta_segment(Control.move_to(0, y).segment)
165-
start_skip: int | None = None
166-
x1 = 0
167-
x2 = 0
168-
for segment1, segment2 in zip(line1, line2):
169-
if x1 == x2 and segment1 == segment2:
170-
if start_skip is None:
171-
start_skip = x1
172-
else:
173-
if start_skip is not None:
174-
add_delta_segment(move_to_column(x2).segment)
175-
start_skip = None
176-
add_delta_segment(segment2)
177-
x1 += segment1.cell_length
178-
x2 += segment2.cell_length
179-
180-
if delta_line:
181-
yield delta_line[:]
182-
del delta_line[:]
183-
184165
def _get_renders(self, console: Console) -> Iterable[tuple[Region, Lines]]:
185166
width = self.width
186167
height = self.height
@@ -213,11 +194,13 @@ def render(widget: Widget, width: int, height: int) -> Lines:
213194
new_region = region.clip(width, height)
214195
delta_x = new_region.x - region.x
215196
delta_y = new_region.y - region.y
216-
# region = new_region
217-
lines = lines[delta_y : delta_y + region.height]
197+
region = new_region
198+
199+
splits = [delta_x, delta_x + region.width]
200+
divide = Segment.divide
218201
lines = [
219-
list(Segment.divide(line, [delta_x, delta_x + region.width]))[1]
220-
for line in lines
202+
list(divide(line, splits))[1]
203+
for line in lines[delta_y : delta_y + region.height]
221204
]
222205
self.renders[widget] = (region, lines)
223206
yield region, lines
@@ -279,9 +262,8 @@ def render(
279262
if final_cuts == [region.x, region.x + region.width]:
280263
cut_segments = [line]
281264
else:
282-
_, *cut_segments = divide(
283-
line, [cut - region.x for cut in final_cuts]
284-
)
265+
relative_cuts = [cut - region.x for cut in final_cuts]
266+
_, *cut_segments = divide(line, relative_cuts)
285267
for cut, segments in zip(final_cuts, cut_segments):
286268
if chops[y][cut] is None:
287269
chops[y][cut] = segments

src/textual/layouts/dock.py

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ def generate_map(
6161
layers: dict[int, Region] = defaultdict(lambda: layout_region)
6262

6363
def add_widget(widget: Widget, region: Region, order: tuple[int, int]):
64-
region = region + offset
64+
region = region + offset + widget.layout_offset
6565
if isinstance(widget, View):
6666
sub_map = widget.layout.generate_map(
6767
region.width, region.height, offset=region.origin
6868
)
6969
map.update(sub_map)
7070
else:
71-
map[widget] = MapRegion(region + widget.layout_offset, order)
71+
map[widget] = MapRegion(region, order)
7272

7373
for index, dock in enumerate(self.docks):
7474
dock_options = [
@@ -99,11 +99,7 @@ def add_widget(widget: Widget, region: Region, order: tuple[int, int]):
9999
if not size:
100100
break
101101
total += size
102-
add_widget(
103-
widget,
104-
Region(x, render_y, width, size) + widget.layout_offset,
105-
order,
106-
)
102+
add_widget(widget, Region(x, render_y, width, size), order)
107103
render_y += size
108104
remaining = max(0, remaining - size)
109105
region = Region(x, y + total, width, height - total)
@@ -120,11 +116,7 @@ def add_widget(widget: Widget, region: Region, order: tuple[int, int]):
120116
if not size:
121117
break
122118
total += size
123-
add_widget(
124-
widget,
125-
Region(x, render_y - size, width, size) + widget.layout_offset,
126-
order,
127-
)
119+
add_widget(widget, Region(x, render_y - size, width, size), order)
128120
render_y -= size
129121
remaining = max(0, remaining - size)
130122
region = Region(x, y, width, height - total)
@@ -141,11 +133,7 @@ def add_widget(widget: Widget, region: Region, order: tuple[int, int]):
141133
if not size:
142134
break
143135
total += size
144-
add_widget(
145-
widget,
146-
Region(render_x, y, size, height) + widget.layout_offset,
147-
order,
148-
)
136+
add_widget(widget, Region(render_x, y, size, height), order)
149137
render_x += size
150138
remaining = max(0, remaining - size)
151139
region = Region(x + total, y, width - total, height)
@@ -162,11 +150,7 @@ def add_widget(widget: Widget, region: Region, order: tuple[int, int]):
162150
if not size:
163151
break
164152
total += size
165-
add_widget(
166-
widget,
167-
Region(render_x - size, y, size, height) + widget.layout_offset,
168-
order,
169-
)
153+
add_widget(widget, Region(render_x - size, y, size, height), order)
170154
render_x -= size
171155
remaining = max(0, remaining - size)
172156
region = Region(x, y, width - total, height)

src/textual/view.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ async def message_update(self, message: UpdateMessage) -> None:
6969
self.app.display(display_update)
7070

7171
async def message_layout(self, message: LayoutMessage) -> None:
72-
log.debug("MESSAGE_LAYOUT %r", self.root_view)
7372

7473
await self.root_view.refresh_layout()
7574

@@ -102,14 +101,13 @@ async def refresh_layout(self) -> None:
102101
self.layout.reflow(width, height)
103102
self.app.refresh()
104103

105-
for widget, region in self.layout:
106-
if isinstance(widget, Widget):
107-
await widget.post_message(
108-
events.Resize(self, region.width, region.height)
109-
)
104+
# for widget, region in self.layout:
105+
# if isinstance(widget, Widget):
106+
# await widget.post_message(
107+
# events.Resize(self, region.width, region.height)
108+
# )
110109

111-
async def on_resize(self, event: events.Resize) -> None:
112-
log.debug("view.on_resize")
110+
async def on_resize(self, event: events.Resize) -> None:
113111
self.size = Dimensions(event.width, event.height)
114112
await self.refresh_layout()
115113

src/textual/widget.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,7 @@ async def on_event(self, event: events.Event) -> None:
223223
await super().on_event(event)
224224

225225
async def on_idle(self, event: events.Idle) -> None:
226-
if self.check_layout():
227-
log.debug("LAYING OUT")
226+
if self.check_layout():
228227
self.reset_check_repaint()
229228
self.reset_check_layout()
230229
await self.update_layout()

0 commit comments

Comments
 (0)