mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
auto widget placement
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
from rich.text import Text
|
||||
|
||||
from textual.app import App
|
||||
from textual import events
|
||||
from textual.view import View
|
||||
from textual.widgets import Button, Placeholder
|
||||
from textual.layouts.grid import GridLayout
|
||||
|
||||
try:
|
||||
from pyfiglet import Figlet
|
||||
except ImportError:
|
||||
print("Please install pyfiglet to run this example")
|
||||
|
||||
font = Figlet(font="small")
|
||||
|
||||
|
||||
class GridTest(App):
|
||||
async def on_load(self, event: events.Load) -> None:
|
||||
@@ -25,11 +34,19 @@ class GridTest(App):
|
||||
equals="col4,row4",
|
||||
)
|
||||
|
||||
def make_button(text: str) -> Button:
|
||||
label = Text(font.renderText(text).rstrip("\n"), style="bold")
|
||||
return Button(label)
|
||||
|
||||
buttons = {
|
||||
name: make_button(name)
|
||||
for name in "AC,+/-,%,/,7,8,9,X,4,5,6,-,1,2,3,+,.,=".split(",")
|
||||
}
|
||||
|
||||
layout.place(
|
||||
*buttons.values(),
|
||||
numbers=Placeholder(name="numbers"),
|
||||
zero=Button("0"),
|
||||
dot=Button("."),
|
||||
equals=Button("="),
|
||||
zero=make_button("0"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from itertools import cycle
|
||||
from itertools import cycle, product
|
||||
import sys
|
||||
from typing import Iterable, NamedTuple
|
||||
|
||||
@@ -23,11 +23,11 @@ GridAlign = Literal["start", "end", "center", "stretch"]
|
||||
|
||||
@dataclass
|
||||
class GridOptions:
|
||||
name: str
|
||||
size: int | None = None
|
||||
fraction: int = 1
|
||||
min_size: int = 1
|
||||
max_size: int | None = None
|
||||
name: str | None = None
|
||||
|
||||
|
||||
class GridArea(NamedTuple):
|
||||
@@ -76,7 +76,7 @@ class GridLayout(Layout):
|
||||
|
||||
def add_column(
|
||||
self,
|
||||
name: str | None = None,
|
||||
name: str,
|
||||
*,
|
||||
size: int | None = None,
|
||||
fraction: int = 1,
|
||||
@@ -93,17 +93,17 @@ class GridLayout(Layout):
|
||||
for name in names:
|
||||
append(
|
||||
GridOptions(
|
||||
name,
|
||||
size=size,
|
||||
fraction=fraction,
|
||||
min_size=min_size,
|
||||
max_size=max_size,
|
||||
name=name,
|
||||
)
|
||||
)
|
||||
|
||||
def add_row(
|
||||
self,
|
||||
name: str | None = None,
|
||||
name: str,
|
||||
*,
|
||||
size: int | None = None,
|
||||
fraction: int = 1,
|
||||
@@ -120,11 +120,11 @@ class GridLayout(Layout):
|
||||
for name in names:
|
||||
append(
|
||||
GridOptions(
|
||||
name,
|
||||
size=size,
|
||||
fraction=fraction,
|
||||
min_size=min_size,
|
||||
max_size=max_size,
|
||||
name=name,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -222,6 +222,17 @@ class GridLayout(Layout):
|
||||
def generate_map(
|
||||
self, width: int, height: int, offset: Point = Point(0, 0)
|
||||
) -> dict[Widget, OrderedRegion]:
|
||||
"""[summary]
|
||||
|
||||
Args:
|
||||
width (int): [description]
|
||||
height (int): [description]
|
||||
offset (Point, optional): [description]. Defaults to Point(0, 0).
|
||||
|
||||
Returns:
|
||||
dict[Widget, OrderedRegion]: [description]
|
||||
"""
|
||||
|
||||
def resolve(
|
||||
size: int, edges: list[GridOptions], gap: int, repeat: bool
|
||||
) -> Iterable[tuple[int, int]]:
|
||||
@@ -240,17 +251,17 @@ class GridLayout(Layout):
|
||||
|
||||
def resolve_tracks(
|
||||
grid: list[GridOptions], size: int, gap: int, repeat: bool
|
||||
) -> tuple[dict[str, list[int]], int]:
|
||||
) -> tuple[dict[str, list[tuple[int, int]]], int]:
|
||||
spans = (
|
||||
(options.name, span)
|
||||
for options, span in zip(cycle(grid), resolve(size, grid, gap, repeat))
|
||||
)
|
||||
max_size = 0
|
||||
tracks: dict[str, list[int]] = defaultdict(list)
|
||||
for name, (start, end) in spans:
|
||||
tracks: dict[str, list[tuple[int, int]]] = defaultdict(list)
|
||||
for index, (name, (start, end)) in enumerate(spans):
|
||||
max_size = max(max_size, end)
|
||||
tracks[f"{name}-start"].append(start)
|
||||
tracks[f"{name}-end"].append(end)
|
||||
tracks[f"{name}-start"].append((index, start))
|
||||
tracks[f"{name}-end"].append((index, end))
|
||||
return tracks, max_size
|
||||
|
||||
container = Dimensions(
|
||||
@@ -270,6 +281,11 @@ class GridLayout(Layout):
|
||||
if area and widget.visible
|
||||
)
|
||||
|
||||
free_slots = {
|
||||
(col, row)
|
||||
for col, row in product(range(len(self.columns)), range(len(self.rows)))
|
||||
}
|
||||
|
||||
map = {}
|
||||
order = 1
|
||||
from_corners = Region.from_corners
|
||||
@@ -277,13 +293,17 @@ class GridLayout(Layout):
|
||||
for widget, area in widget_areas:
|
||||
column_start, column_end, row_start, row_end = self.areas[area]
|
||||
try:
|
||||
x1 = column_tracks[column_start][0]
|
||||
x2 = column_tracks[column_end][0]
|
||||
y1 = row_tracks[row_start][0]
|
||||
y2 = row_tracks[row_end][0]
|
||||
col1, x1 = column_tracks[column_start][0]
|
||||
col2, x2 = column_tracks[column_end][0]
|
||||
row1, y1 = row_tracks[row_start][0]
|
||||
row2, y2 = row_tracks[row_end][0]
|
||||
except (KeyError, IndexError):
|
||||
continue
|
||||
|
||||
free_slots -= {
|
||||
(col, row) for col, row in product(range(col1, col2), range(row1, row2))
|
||||
}
|
||||
|
||||
region = self._align(
|
||||
from_corners(x1, y1, x2, y2),
|
||||
grid_size,
|
||||
@@ -297,6 +317,11 @@ class GridLayout(Layout):
|
||||
# Widgets with no area assigned.
|
||||
auto_widgets = [widget for widget, area in self.widgets.items() if area is None]
|
||||
|
||||
# for (widget, area) in widget_areas:
|
||||
# if widget in map:
|
||||
# col1, col2, row1, row2 = area
|
||||
# for col in range()
|
||||
|
||||
return map
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user