button widget

This commit is contained in:
Will McGugan
2021-07-10 15:56:55 +01:00
parent ae81b98f35
commit 57038c2393
15 changed files with 52 additions and 30 deletions

View File

@@ -1,7 +1,7 @@
from textual.app import App
from textual import events
from textual.view import View
from textual.widgets import Placeholder
from textual.widgets import Button, Placeholder
from textual.layouts.grid import GridLayout
@@ -15,7 +15,7 @@ class GridTest(App):
await self.push_view(View(layout=layout))
layout.add_column("col", max_size=20, repeat=4)
layout.add_row("numbers", max_size=10)
layout.add_row("numbers", min_size=3, max_size=10)
layout.add_row("row", max_size=10, repeat=4)
layout.add_areas(
@@ -27,9 +27,9 @@ class GridTest(App):
layout.place(
numbers=Placeholder(name="numbers"),
zero=Placeholder(name="0"),
dot=Placeholder(name="."),
equals=Placeholder(name="="),
zero=Button("0"),
dot=Button("."),
equals=Button("="),
)

View File

@@ -22,15 +22,19 @@ class GridTest(App):
layout.add_row(fraction=2, name="middle")
layout.add_row(fraction=1, name="bottom")
layout.add_area("area1", "left", "top")
layout.add_area("area2", "center", "middle")
layout.add_area("area3", ("left-start", "right-end"), "bottom")
layout.add_area("area4", "right", ("top-start", "middle-end"))
layout.add_areas(
area1="left,top",
area2="center,middle",
area3="left-start|right-end,bottom",
area4="right,top-start|middle-end",
)
await view.mount(layout.add_widget(Placeholder(name="area1"), "area1"))
await view.mount(layout.add_widget(Placeholder(name="area2"), "area2"))
await view.mount(layout.add_widget(Placeholder(name="area3"), "area3"))
await view.mount(layout.add_widget(Placeholder(name="area4"), "area4"))
layout.place(
area1=Placeholder(name="area1"),
area2=Placeholder(name="area2"),
area3=Placeholder(name="area3"),
area4=Placeholder(name="area4"),
)
GridTest.run(title="Grid Test")

0
examples/live.py Normal file
View File

View File

@@ -19,7 +19,7 @@ class Edge(Protocol):
def layout_resolve(total: int, edges: Sequence[Edge]) -> List[int]:
"""Divide total space to satisfy size, ratio, and minimum_size, constraints.
"""Divide total space to satisfy size, fraction, and min_size, constraints.
The returned list of integers should add up to total in most cases, unless it is
impossible to satisfy all the constraints. For instance, if there are two edges

View File

@@ -122,6 +122,10 @@ class Layout(ABC):
hidden=hidden_widgets, shown=shown_widgets, resized=resized_widgets
)
@abstractmethod
def get_widgets(self) -> Iterable[Widget]:
...
@abstractmethod
def generate_map(
self, width: int, height: int, offset: Point = Point(0, 0)

View File

@@ -4,7 +4,7 @@ import sys
from collections import defaultdict
from dataclasses import dataclass
import logging
from typing import TYPE_CHECKING, Sequence
from typing import Iterable, TYPE_CHECKING, Sequence
from .._layout_resolve import layout_resolve
from ..geometry import Region, Point
@@ -29,8 +29,7 @@ DockEdge = Literal["top", "right", "bottom", "left"]
class DockOptions:
size: int | None = None
fraction: int = 1
minimum_size: int = 1
maximim_size: int | None = None
min_size: int = 1
@dataclass
@@ -45,6 +44,10 @@ class DockLayout(Layout):
self.docks: list[Dock] = docks or []
super().__init__()
def get_widgets(self) -> Iterable[Widget]:
for dock in self.docks:
yield from dock.widgets
def generate_map(
self, width: int, height: int, offset: Point = Point(0, 0)
) -> dict[Widget, OrderedRegion]:
@@ -67,9 +70,7 @@ class DockLayout(Layout):
for index, dock in enumerate(self.docks):
dock_options = [
DockOptions(
widget.layout_size,
widget.layout_fraction,
widget.layout_minimim_size,
widget.layout_size, widget.layout_fraction, widget.layout_min_size
)
for widget in dock.widgets
]

View File

@@ -210,13 +210,15 @@ class GridLayout(Layout):
offset = (container - size) // 2
return offset
size = region.size
offset_x = align(grid_size.width, container.width, col_align)
offset_y = align(grid_size.height, container.height, row_align)
region = region.translate(offset_x, offset_y)
return region
def get_widgets(self) -> Iterable[Widget]:
return self.widgets.keys()
def generate_map(
self, width: int, height: int, offset: Point = Point(0, 0)
) -> dict[Widget, OrderedRegion]:

View File

@@ -110,6 +110,7 @@ class Page(Widget):
self._page.update(renderable)
else:
self._page.clear()
self.require_repaint()
@property
def virtual_size(self) -> Dimensions:

View File

@@ -96,7 +96,6 @@ class ScrollBarRender:
blank = " " * width_thickness
foreground_meta = {"@mouse.up": "release", "@mouse.down": "grab"}
if window_size and size and virtual_size:
step_size = virtual_size / size
@@ -143,6 +142,7 @@ class ScrollBarRender:
def __rich_console__(
self, console: Console, options: ConsoleOptions
) -> RenderResult:
log.debug("SCROLLBAR RENDER")
size = (
(options.height or console.height)
if self.vertical
@@ -254,4 +254,6 @@ if __name__ == "__main__":
console = Console()
bar = ScrollBarRender()
console.print(ScrollBarRender(position=15.3, thickness=5, vertical=False))
console.print(
ScrollBarRender(position=15.3, window_size=100, thickness=5, vertical=True)
)

View File

@@ -97,6 +97,10 @@ class View(Widget):
hidden, shown, resized = self.layout.reflow(width, height)
self.app.refresh()
for widget in self.layout.get_widgets():
if not self.is_mounted(widget):
await self.mount(widget)
for widget in hidden:
widget.post_message_no_wait(events.Hide(self))
for widget in shown:
@@ -104,9 +108,8 @@ class View(Widget):
send_resize = shown
send_resize.update(resized)
for widget, region in self.layout:
if not self.is_mounted(widget):
await self.mount(widget)
if widget in send_resize:
widget.post_message_no_wait(
events.Resize(self, region.width, region.height)

View File

@@ -66,7 +66,7 @@ class Widget(MessagePump):
visible: Reactive[bool] = Reactive(True, layout=True)
layout_size: Reactive[int | None] = Reactive(None)
layout_fraction: Reactive[int] = Reactive(1)
layout_minimim_size: Reactive[int] = Reactive(1)
layout_min_size: Reactive[int] = Reactive(1)
layout_offset_x: Reactive[float] = Reactive(0, layout=True)
layout_offset_y: Reactive[float] = Reactive(0, layout=True)

View File

@@ -1,5 +1,6 @@
from ._footer import Footer
from ._header import Header
from ._button import Button
from ._placeholder import Placeholder
from ._scroll_view import ScrollView
from ._static import Static

View File

@@ -1,18 +1,19 @@
from rich.console import Console, ConsoleOptions, RenderableType
from rich.repr import rich_repr, RichReprResult
from rich.console import RenderableType
from rich.text import Text
import rich.repr
from .. import events
from ..widget import Widget
@rich.repr.auto
class Footer(Widget):
def __init__(self) -> None:
self.keys: list[tuple[str, str]] = []
super().__init__()
self.layout_size = 1
def __rich_repr__(self) -> RichReprResult:
def __rich_repr__(self) -> rich.repr.RichReprResult:
yield "footer"
def add_key(self, key: str, label: str) -> None:

View File

@@ -7,7 +7,6 @@ from rich.style import StyleType
from .. import events
from ..geometry import Dimensions
from ..message import Message
from ..scrollbar import ScrollTo, ScrollBar
from ..geometry import clamp

View File

@@ -11,3 +11,7 @@ class Static(Widget):
def render(self) -> RenderableType:
return self.renderable
async def update(self, renderable: RenderableType) -> None:
self.renderable = renderable
self.require_repaint()