22
33from __future__ import annotations
44
5+ from itertools import cycle
6+
57from textual import on
68from textual .app import App , ComposeResult
9+ from textual .binding import Binding
710from textual .containers import Horizontal , Vertical , VerticalScroll
11+ from textual .message import Message
812from textual .widget import Widget
9- from textual .widgets import Button , Input , Pretty , Static
13+ from textual .widgets import Button , Input , Pretty , Static , TabbedContent , TabPane , Label
1014
1115
1216class Playground (Vertical , inherit_css = False ):
@@ -43,6 +47,58 @@ def title(widget: Widget, main_title: str | None = None) -> Widget:
4347 return widget
4448
4549
50+ class NestedContainers (Playground ):
51+ """A Playground made of nested containers."""
52+
53+ def compose (self ) -> ComposeResult :
54+ """Compose the playground."""
55+ with title (Vertical (id = "one" , classes = "foo bar" )):
56+ with title (Vertical (id = "two" )):
57+ with title (Horizontal (id = "three" , classes = "baz" )):
58+ for n in range (3 ):
59+ yield title (
60+ Vertical (id = f"three-{ n } " , classes = f"wibble wobble-{ n } " )
61+ )
62+ with title (Vertical (id = "four" )):
63+ yield title (Vertical (id = "innermost" , classes = "foo baz" ))
64+
65+
66+ class VariousWidgets (Playground ):
67+ """A playground made of some widgets."""
68+
69+ DEFAULT_CSS = """
70+ VariousWidgets Label{
71+ width: 1fr;
72+ }
73+ """
74+
75+ def compose (self ) -> ComposeResult :
76+ """Compose the playground."""
77+ with title (Horizontal ()):
78+ classes = cycle (("foo" , "bar" ))
79+ with title (Vertical (id = "input-widgets" )):
80+ for n in range (5 ):
81+ yield title (
82+ Input (
83+ placeholder = f"Example input { n } " ,
84+ id = f"input-{ n } " ,
85+ classes = next (classes ),
86+ )
87+ )
88+ with title (Vertical (id = "static-and-labels" )):
89+ for n in range (3 ):
90+ yield title (
91+ Static (
92+ "Can you find me?" , id = f"static-{ n } " , classes = next (classes )
93+ )
94+ )
95+ yield title (
96+ Label (
97+ "Can you find me?" , id = f"label-{ n } " , classes = next (classes )
98+ )
99+ )
100+
101+
46102class QuerySandboxApp (App [None ]):
47103 """A Textual CSS query sandbox application."""
48104
@@ -55,12 +111,16 @@ class QuerySandboxApp(App[None]):
55111 height: 4;
56112 }
57113
114+ TabbedContent {
115+ height: 2fr;
116+ }
117+
58118 Playground * {
59119 margin: 1;
60120 border: panel red 40%;
61121 }
62122
63- .hit {
123+ Playground .hit {
64124 border: panel green;
65125 background: green 10%;
66126 }
@@ -76,6 +136,10 @@ class QuerySandboxApp(App[None]):
76136 border: panel cornflowerblue;
77137 }
78138
139+ #output {
140+ height: 1fr;
141+ }
142+
79143 #results {
80144 width: 3fr;
81145 }
@@ -85,44 +149,67 @@ class QuerySandboxApp(App[None]):
85149 }
86150 """
87151
152+ BINDINGS = [
153+ Binding ("f1" , "playground('tab-1')" , "Nested Containers" ),
154+ Binding ("f2" , "playground('tab-2')" , "Various Widgets" ),
155+ ]
156+
88157 def compose (self ) -> ComposeResult :
89158 """Compose the DOM for the application."""
90159 with Horizontal (id = "input" ):
91160 yield Input ()
92161 yield Button ("Query" )
93- with Playground ():
94- with title (Vertical (id = "one" , classes = "foo bar" )):
95- with title (Vertical (id = "two" )):
96- with title (Horizontal (id = "three" , classes = "baz" )):
97- for n in range (3 ):
98- yield title (
99- Vertical (id = f"three-{ n } " , classes = f"wibble wobble-{ n } " )
100- )
101- with title (Vertical (id = "four" )):
102- yield title (Vertical (id = "innermost" , classes = "foo baz" ))
103- with Horizontal ():
162+ with TabbedContent ():
163+ with TabPane ("Nested Containers (F1)" ):
164+ yield NestedContainers ()
165+ with TabPane ("Various Widgets (F2)" ):
166+ yield VariousWidgets ()
167+ with Horizontal (id = "output" ):
104168 with title (VerticalScroll (id = "results" ), "Query Results" ):
105169 yield Pretty ([])
106170 with title (VerticalScroll (id = "tree" ), "Playground DOM Tree" ):
107171 yield Static ("" )
108172
109- def on_mount (self ) -> None :
110- self .query_one ("#tree > Static" , Static ).update (self .query_one (Playground ).tree )
173+ @property
174+ def input (self ) -> Input :
175+ """The main input widget."""
176+ return self .query_one ("#input Input" , Input )
177+
178+ @property
179+ def playground (self ) -> Playground :
180+ """The current playground widget."""
181+ return self .query_one (
182+ f"TabPane#{ self .query_one (TabbedContent ).active } Playground" , Playground
183+ )
111184
112185 @on (Input .Submitted )
113186 @on (Button .Pressed )
114- def do_query (self ) -> None :
187+ @on (TabbedContent .TabActivated )
188+ def do_query (self , event : Message | None = None ) -> None :
115189 """Perform the query and show the result."""
116190 self .query ("Playground *" ).remove_class ("hit" )
117191 result : list [Widget ] | Exception
118192 try :
119- hits = self .query_one ( Playground ) .query (self .query_one ( Input ) .value )
193+ hits = self .playground .query (self .input .value )
120194 hits .add_class ("hit" )
121195 result = list (hits )
122196 except Exception as error : # pylint:disable=broad-exception-caught
123197 result = error
124198 self .query_one ("#results > Pretty" , Pretty ).update (result )
125- self .query_one (Input ).focus ()
199+ self .query_one ("#tree > Static" , Static ).update (
200+ self .playground .children [0 ].tree
201+ )
202+ if not isinstance (event , TabbedContent .TabActivated ):
203+ self .input .focus ()
204+
205+ def action_playground (self , playground : str ) -> None :
206+ """Switch between different playgrounds.
207+
208+ Args:
209+ playground: The playground to switch to.
210+ """
211+ self .query_one (TabbedContent ).active = playground
212+ self .do_query ()
126213
127214
128215### sandbox.py ends here
0 commit comments