# Released under the MIT License. See LICENSE for details.
#
"""Examples/tests for using DocUI to build UIs."""
from __future__ import annotations # Docs-generation hack.
import time
import copy
from typing import TYPE_CHECKING, override
from efro.error import CleanError
import bauiv1 as bui
from bauiv1 import builtinassets
from bauiv1 import classicassets
from bauiv1lib.docui import DocUIWindow, DocUIController
if TYPE_CHECKING:
from bacommon.docui import DocUIRequest, DocUIResponse
import bacommon.docui.v2
from bacommon.langstr import LangStrSpec
from bauiv1lib.docui import DocUILocalAction
def _btex(name: str) -> str:
"""Qualified ref for a texture in the builtin asset-package."""
return f'{builtinassets.__asset_package__}:textures/{name}'
def _stex(name: str) -> str:
"""Qualified classicassets texture ref."""
return f'{classicassets.__asset_package__}:textures/{name}'
[docs]
def show_test_doc_ui_v2_window() -> None:
"""Bust out a doc-ui test window built locally on the client.
Test pages authored as language-agnostic v2 documents — text as
``LangStrSpec`` values from the ``badocuiv2testassets`` package (decoded
in the client's locale at render time), textures/meshes as typed
refs, and multi-line labels via wrap-params instead of hand-baked
newlines. The Cloud-Msg and Web buttons fetch equivalent v2 pages
from bamaster, keeping the full cloud/web resolve -> decode ->
render paths exercised.
"""
import bacommon.docui.v2 as dui2
bui.app.ui_v1.auxiliary_window_activate(
win_type=DocUIWindow,
win_create_call=bui.CallStrict(
TestDocUIV2Controller().create_window, dui2.Request('/')
),
win_extra_type_id=TestDocUIV2Controller.get_window_extra_type_id(),
)
[docs]
class TestDocUIV2Controller(DocUIController):
"""Tests/demonstrations of native (v2 / l-string) docui.
Local pages are authored client-side; the ``/cloudmsgtest/*`` and
``/webtest/*`` paths fetch equivalent v2 pages from bamaster.
"""
[docs]
@override
def fulfill_request(self, request: DocUIRequest) -> DocUIResponse:
"""Fulfill a v2 request (called in a background thread)."""
# pylint: disable=too-many-return-statements
import bacommon.docui.v2 as dui2
if not isinstance(request, dui2.Request):
raise CleanError('Invalid request version.')
# Handle some pages purely locally.
if request.path == '/':
return _test_v2_page_root(request)
if request.path == '/test2':
return _test_v2_page_2(request)
if request.path == '/slow':
return _test_v2_page_long(request)
if request.path == '/timedactions':
return _test_v2_page_timed_actions(request)
if request.path == '/displayitems':
return _test_v2_page_display_items(request)
if request.path == '/emptypage':
return _test_v2_page_empty(request)
if request.path == '/boundstests':
return _test_v2_bounds(request)
# Ship '/webtest/*' off to some webserver to handle.
if request.path.startswith('/webtest/'):
return self.fulfill_request_web(
request, 'https://www.ballistica.net/docuitest'
)
# Ship '/cloudmsgtest/*' through our cloud connection to handle.
if request.path.startswith('/cloudmsgtest/'):
return self.fulfill_request_cloud(request, 'docuitestv2')
raise CleanError('Invalid request path.')
[docs]
@override
def local_action(self, action: DocUILocalAction) -> None:
bui.screenmessage(
f'Would do {action.name!r} with args {action.args!r}.'
)
def _test_v2_page_root(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""Author the v2 (l-string) test root page purely on the client.
The full v1 test root page, with all text authored as
language-agnostic ``LangStrSpec`` values from the ``badocuiv2testassets``
package, textures/meshes as typed refs from
``builtinassets``/``classicassets``, and multi-line labels wrapped via
definition-time :class:`~bacommon.langstr.WrapParams` on the
package's string definitions (decision D-t) instead of v1's
hand-baked newlines. The client resolves the referenced packages
in its own locale, decodes, and wraps -- so this single response
renders in any language.
"""
import bacommon.clienteffect as clfx
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
strs = _docuiv2testassets.strings
# Show some specific debug bits if they ask us to.
debug = bool(request.args.get('debug', False))
response = dui2.Response(
page=dui2.Page(
title=strs.nav.test_root_title.spec,
rows=[
dui2.ButtonRow(
debug=debug,
header_height=100,
header_decorations_left=[
dui2.Text(
text=strs.common.header_left.spec,
position=(0, 10 + 20),
color=(1, 1, 1, 0.3),
size=(150, 30),
h_align=dui2.HAlign.LEFT,
debug=debug,
),
],
header_decorations_center=[
dui2.Text(
text=strs.common.hello_from_docui.spec,
position=(0, 10 + 20),
size=(300, 30),
debug=debug,
),
dui2.Text(
text=strs.common.docui_reference.spec,
scale=0.5,
position=(0, -18 + 20),
size=(600, 23),
debug=debug,
),
dui2.Image(
texture=builtinassets.textures.nub,
position=(0, -58 + 20),
size=(60, 60),
),
],
header_decorations_right=[
dui2.Text(
text=strs.common.header_right.spec,
position=(0, 10 + 20),
color=(1, 1, 1, 0.3),
size=(150, 30),
h_align=dui2.HAlign.RIGHT,
debug=debug,
),
],
title=strs.nav.some_tests.spec,
buttons=[
dui2.Button(
label=strs.nav.browse.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/test2')),
),
dui2.Button(
label=strs.nav.replace.spec,
size=(120, 80),
action=dui2.Replace(dui2.Request('/test2')),
),
dui2.Button(
label=strs.nav.close.spec,
size=(120, 80),
action=dui2.Local(close_window=True),
),
dui2.Button(
label=strs.common.invalid_request.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/invalidrequest')),
),
dui2.Button(
label=strs.effects.immediate_client_effects.spec,
size=(120, 80),
action=dui2.Local(
# V2 effect forms: l-string text decoded
# in the client's locale + a typed sound
# ref from an asset package. The page
# resolve pre-warms the referenced
# packages, so press-time runs are
# cache hits.
immediate_client_effects=[
clfx.ScreenMessageV2(
message=(
strs.effects.immediate_effects_hello
).spec,
color=(0, 1, 0),
),
clfx.PlaySoundV2(
sound=(
builtinassets.audio
).cash_register,
),
clfx.Delay(1.0),
clfx.ScreenMessageV2(
message=(
strs.effects.effect_success
).spec,
color=(0, 1, 0),
),
clfx.PlaySoundV2(
sound=(
builtinassets.audio
).cash_register,
),
]
),
),
dui2.Button(
label=strs.effects.response_client_effects.spec,
size=(120, 80),
action=dui2.Browse(
dui2.Request('/', args={'test_effects': True})
),
),
dui2.Button(
label=strs.effects.immediate_local_action.spec,
size=(120, 80),
action=dui2.Local(
immediate_local_action='testaction',
immediate_local_action_args={'testparam': 123},
),
),
dui2.Button(
label=strs.effects.response_local_action.spec,
size=(120, 80),
action=dui2.Browse(
dui2.Request('/', args={'test_action': True})
),
),
],
),
dui2.ButtonRow(
title=strs.nav.few_more_tests.spec,
buttons=[
dui2.Button(
label=(
strs.common.hide_debug.spec
if debug
else strs.common.show_debug.spec
),
size=(120, 80),
action=dui2.Replace(
dui2.Request('/', args={'debug': not debug})
),
),
dui2.Button(
label=strs.nav.slow_browse.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/slow')),
),
dui2.Button(
label=strs.nav.slow_replace.spec,
size=(120, 80),
action=dui2.Replace(dui2.Request('/slow')),
),
dui2.Button(
label=strs.common.timed_actions.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/timedactions')),
),
dui2.Button(
label=strs.web.web_get.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/webtest/get')),
),
dui2.Button(
label=strs.web.web_post.spec,
size=(120, 80),
action=dui2.Browse(
dui2.Request(
'/webtest/post',
method=dui2.RequestMethod.POST,
)
),
),
dui2.Button(
label=strs.items.display_items.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/displayitems')),
),
dui2.Button(
label=strs.layout.empty_page.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/emptypage')),
),
],
),
dui2.ButtonRow(
title=strs.nav.even_more_tests.spec,
buttons=[
dui2.Button(
label=strs.cloud.cloud_msg_get.spec,
size=(120, 80),
action=dui2.Browse(
dui2.Request('/cloudmsgtest/get')
),
),
dui2.Button(
label=strs.cloud.cloud_msg_post.spec,
size=(120, 80),
action=dui2.Browse(
dui2.Request(
'/cloudmsgtest/post',
method=dui2.RequestMethod.POST,
)
),
),
dui2.Button(
label=strs.layout.bounds_tests.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/boundstests')),
),
],
),
dui2.ButtonRow(title=strs.layout.empty_row.spec, buttons=[]),
dui2.ButtonRow(
title=strs.layout.layout_tests.spec,
debug=debug,
padding_left=5.0,
buttons=[
dui2.Button(
label=strs.nav.test.spec,
size=(180, 200),
decorations=_layout_test_decos(debug),
),
dui2.Button(
label=strs.nav.test_two.spec,
size=(100, 100),
color=(1, 0, 0, 1),
label_color=(1, 1, 1, 1),
padding_right=4,
),
# Should look like the first button but
# scaled down.
dui2.Button(
label=strs.nav.test.spec,
size=(180, 200),
scale=0.6,
padding_bottom=30, # Should nudge us up.
debug=debug, # Show bounds.
decorations=_layout_test_decos(debug),
),
# Testing custom button images and opacity.
dui2.Button(
label=strs.nav.test_three.spec,
texture=builtinassets.textures.button_square_wide,
padding_left=10.0,
padding_right=10.0,
color=(1, 1, 1, 0.3),
size=(200, 100),
),
# Testing image drawing vs bounds
dui2.Button(
label=strs.layout.bounds_test.spec,
texture=builtinassets.textures.white,
color=(1, 1, 1, 0.3),
size=(150, 100),
debug=debug,
),
],
),
dui2.ButtonRow(
title=strs.layout.long_row_test.spec,
subtitle=strs.layout.look_a_subtitle.spec,
buttons=[
dui2.Button(
size=(150, 100),
decorations=[
dui2.Text(
text=strs.layout.max_width_test.spec,
position=(0, 25),
size=(150 * 0.8, 32.0),
flatness=1.0,
shadow=0.0,
debug=debug,
),
# v1 bakes a newline into this one
# ('MaxHeightTest\nSecondLine'); we ask
# for two balanced lines instead.
dui2.Text(
text=strs.layout.max_height_test.spec,
position=(0, -20),
size=(150 * 0.8, 40),
flatness=1.0,
shadow=0.0,
debug=debug,
),
],
),
dui2.Button(
size=(150, 100),
decorations=[
dui2.Image(
texture=classicassets.textures.zoe_icon,
position=(0, 0),
size=(70, 70),
tint_texture=(
classicassets.textures
).zoe_icon_color_mask,
tint_color=(1, 0, 0),
tint2_color=(0, 1, 0),
mask_texture=(
builtinassets.textures
).character_icon_mask,
),
],
),
dui2.Button(
size=(150, 100),
decorations=[
dui2.Image(
texture=(
classicassets.textures
).bridgit_preview,
position=(0, 10),
size=(120, 60),
mask_texture=(
classicassets.textures.map_preview_mask
),
mesh_opaque=(
classicassets.meshes
).level_select_button_opaque,
mesh_transparent=(
classicassets.meshes
).level_select_button_transparent,
),
],
),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(
label=strs.common.foo.spec,
size=(150, 100),
scale=0.4,
padding_left=100,
padding_right=200,
),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
dui2.Button(size=(150, 100)),
],
),
dui2.ButtonRow(
spacing_top=-15,
subtitle=strs.layout.subtitle_only.spec,
buttons=[
dui2.Button(size=(200, 120)),
],
),
dui2.ButtonRow(
buttons=[
dui2.Button(
label=strs.layout.row_with_no_title.spec,
size=(300, 80),
style=dui2.ButtonStyle.MEDIUM,
color=(0.8, 0.8, 0.8, 1),
icon=classicassets.textures.button_punch,
icon_color=(0.5, 0.3, 1.0, 1.0),
icon_scale=1.2,
),
],
),
dui2.ButtonRow(
title=strs.layout.centered_faded_title.spec,
title_color=(0.6, 0.6, 1.0, 0.3),
title_flatness=1.0,
title_shadow=1.0,
subtitle=strs.layout.testing_centered.spec,
subtitle_color=(1.0, 0.5, 1.0, 0.5),
subtitle_flatness=1.0,
subtitle_shadow=0.0,
center_content=True,
center_title=True,
buttons=[
dui2.Button(
label=strs.common.hello_there.spec,
size=(200, 120),
color=(0.7, 0.7, 0.9, 1),
),
],
),
],
)
)
# Include some client effects if they ask (the 'Response
# ClientEffects' button). V2 effect forms; see the immediate-effects
# note above.
if request.args.get('test_effects', False):
response.client_effects = [
clfx.ScreenMessageV2(
message=strs.effects.response_effects_hello.spec,
color=(0, 1, 0),
),
clfx.PlaySoundV2(sound=builtinassets.audio.cash_register),
clfx.Delay(1.0),
clfx.ScreenMessageV2(
message=strs.effects.effect_success.spec, color=(0, 1, 0)
),
clfx.PlaySoundV2(sound=builtinassets.audio.cash_register),
]
# Include a local-action if they ask (the 'Response LocalAction'
# button).
if request.args.get('test_action', False):
response.local_action = 'testaction'
response.local_action_args = {'testparam': 234}
return response
def _layout_test_decos(debug: bool) -> list[bacommon.docui.v2.Decoration]:
"""Decorations for the layout-test buttons (used on two buttons)."""
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
strs = _docuiv2testassets.strings
return [
dui2.Image(
texture=classicassets.textures.powerup_punch,
position=(-70, 0),
size=(40, 40),
h_align=dui2.HAlign.LEFT,
),
dui2.Image(
texture=classicassets.textures.powerup_speed,
position=(0, 75),
size=(35, 35),
v_align=dui2.VAlign.TOP,
),
dui2.Text(
text=strs.layout.corner_tl.spec,
position=(-70, 75),
size=(50, 50),
h_align=dui2.HAlign.LEFT,
v_align=dui2.VAlign.TOP,
debug=debug,
),
dui2.Text(
text=strs.layout.corner_tr.spec,
position=(70, 75),
size=(50, 50),
h_align=dui2.HAlign.RIGHT,
v_align=dui2.VAlign.TOP,
debug=debug,
),
dui2.Text(
text=strs.layout.corner_bl.spec,
position=(-70, -75),
size=(50, 50),
h_align=dui2.HAlign.LEFT,
v_align=dui2.VAlign.BOTTOM,
debug=debug,
),
dui2.Text(
text=strs.layout.corner_br.spec,
position=(70, -75),
size=(50, 50),
h_align=dui2.HAlign.RIGHT,
v_align=dui2.VAlign.BOTTOM,
debug=debug,
),
]
def _test_v2_page_2(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""More testing (v2 mirror of the v1 '/test2' page)."""
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
del request # Unused.
strs = _docuiv2testassets.strings
return dui2.Response(
page=dui2.Page(
title=strs.nav.test_two_title.spec,
rows=[
dui2.ButtonRow(
title=strs.nav.more_tests.spec,
buttons=[
dui2.Button(
label=strs.nav.browse.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/')),
),
dui2.Button(
label=strs.nav.replace.spec,
size=(120, 80),
action=dui2.Replace(dui2.Request('/')),
),
dui2.Button(
label=strs.nav.close.spec,
size=(120, 80),
action=dui2.Local(close_window=True),
selected=True, # Testing this
),
],
),
],
)
)
def _test_v2_page_long(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""Testing a page that takes a bit of time to load (v2 mirror)."""
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
del request # Unused.
strs = _docuiv2testassets.strings
# Simulate a slow connection or whatnot.
time.sleep(3.0)
return dui2.Response(
page=dui2.Page(
title=strs.nav.test.spec,
center_vertically=True,
rows=[
dui2.ButtonRow(
title=strs.common.that_took_a_while.spec,
center_title=True,
center_content=True,
buttons=[
dui2.Button(
label=strs.common.sure_did.spec,
size=(120, 80),
action=dui2.Browse(dui2.Request('/')),
),
],
),
],
)
)
def _test_v2_page_timed_actions(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""Testing timed actions (v2 mirror of '/timedactions')."""
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
strs = _docuiv2testassets.strings
val = request.args.get('val')
if not isinstance(val, int):
val = 5
return dui2.Response(
page=dui2.Page(
title=strs.nav.test.spec,
center_vertically=True,
rows=[
dui2.ButtonRow(
title=strs.common.hello_there_num(num=str(val)).spec,
subtitle=strs.common.each_change.spec,
center_title=True,
center_content=True,
buttons=[
dui2.Button(
label=strs.nav.done.spec,
size=(120, 80),
action=dui2.Local(close_window=True),
default=True,
),
],
),
],
),
# Refresh this page with a countdown until we hit zero and then
# close the window.
timed_action=(
dui2.Replace(dui2.Request('/timedactions', args={'val': val - 1}))
if (val - 1) > 0
else dui2.Local(close_window=True)
),
timed_action_delay=1.0,
)
def _test_v2_page_empty(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""An empty page (v2 mirror of '/emptypage')."""
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
del request # Unused.
return dui2.Response(
page=dui2.Page(
title=_docuiv2testassets.strings.layout.empty_page_title.spec,
rows=[],
)
)
def _test_v2_page_display_items(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""Testing display-items (v2 mirror of '/displayitems')."""
from bacommon.classic import ClassicChestAppearance, ClassicChestDisplayItem
import bacommon.displayitem as ditm
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
strs = _docuiv2testassets.strings
# Show some specific debug bits if they ask us to.
debug = bool(request.args.get('debug', False))
def _make_test_button(
scale: float,
wrapper: ditm.Wrapper,
) -> bacommon.docui.v2.Button:
# See how this looks when unrecognized (relying on wrapper info
# only).
uwrapper = copy.deepcopy(wrapper)
uwrapper.item = ditm.Unknown()
return dui2.Button(
size=(300, 400),
scale=scale,
decorations=[
dui2.DisplayItem(
wrapper=wrapper,
style=dui2.DisplayItemStyle.FULL,
position=(-62, 100),
size=(120, 120),
debug=debug,
),
dui2.DisplayItem(
wrapper=uwrapper,
style=dui2.DisplayItemStyle.FULL,
position=(62, 100),
size=(120, 120),
debug=debug,
),
dui2.DisplayItem(
wrapper=wrapper,
style=dui2.DisplayItemStyle.COMPACT,
position=(-55, -20),
size=(80, 80),
debug=debug,
),
dui2.DisplayItem(
wrapper=uwrapper,
style=dui2.DisplayItemStyle.COMPACT,
position=(55, -20),
size=(80, 80),
debug=debug,
),
dui2.DisplayItem(
wrapper=wrapper,
style=dui2.DisplayItemStyle.ICON,
position=(-55, -120),
size=(100, 80),
debug=debug,
),
dui2.DisplayItem(
wrapper=uwrapper,
style=dui2.DisplayItemStyle.ICON,
position=(55, -120),
size=(100, 80),
debug=debug,
),
],
)
return dui2.Response(
page=dui2.Page(
padding_left=20,
padding_right=20,
title=strs.items.display_items.spec,
rows=[
dui2.ButtonRow(
debug=debug,
padding_left=-10,
title=strs.items.display_item_tests.spec,
subtitle=strs.items.display_items_sub.spec,
buttons=[
_make_test_button(
1.0,
ditm.Wrapper.for_item(ditm.Tickets(count=213)),
),
_make_test_button(
0.47,
ditm.Wrapper.for_item(ditm.Tickets(count=213)),
),
_make_test_button(
1.0,
ditm.Wrapper.for_item(
ClassicChestDisplayItem(
appearance=ClassicChestAppearance.L3
)
),
),
_make_test_button(
1.0,
ditm.Wrapper.for_item(ditm.Tokens(count=3)),
),
_make_test_button(
1.0,
ditm.Wrapper.for_item(ditm.Tokens(count=1414287)),
),
_make_test_button(
1.0,
ditm.Wrapper.for_item(ditm.Test()),
),
],
),
dui2.ButtonRow(
buttons=[
dui2.Button(
label=(
strs.common.hide_debug.spec
if debug
else strs.common.show_debug.spec
),
style=dui2.ButtonStyle.MEDIUM,
size=(240, 60),
color=(0.6, 0.4, 0.8, 1.0),
action=dui2.Replace(
dui2.Request(
request.path, args={'debug': not debug}
)
),
)
],
),
],
)
)
def _test_v2_bounds(
request: bacommon.docui.v2.Request,
) -> bacommon.docui.v2.Response:
"""Button-style bounds tests (v2 mirror of '/boundstests')."""
import bacommon.docui.v2 as dui2
from bauiv1 import _docuiv2testassets
del request # Unused.
strs = _docuiv2testassets.strings
def _nm(style: bacommon.docui.v2.ButtonStyle) -> LangStrSpec:
# Code-literal pass-through: renders the raw enum name
# verbatim in every locale.
return strs.common.code_literal(
text=f'{type(style).__name__}.{style.name}'
).spec
def _hello_row(
title: LangStrSpec,
sizes: list[tuple[float, float]],
style: bacommon.docui.v2.ButtonStyle,
texture: bool = False,
) -> bacommon.docui.v2.ButtonRow:
return dui2.ButtonRow(
title=title,
buttons=[
dui2.Button(
label=strs.layout.hello.spec,
size=size,
style=style,
texture=(builtinassets.textures.white if texture else None),
color=(1, 0, 0, 0.3) if texture else None,
debug=True,
)
for size in sizes
],
)
styles = dui2.ButtonStyle
return dui2.Response(
page=dui2.Page(
title=strs.layout.bounds_tests_title.spec,
rows=[
_hello_row(
_nm(styles.SQUARE),
[(300, 300), (200, 200), (100, 100)],
styles.SQUARE,
),
_hello_row(
_nm(styles.SQUARE_WIDE),
[(400, 200), (200, 250), (60, 100)],
styles.SQUARE_WIDE,
),
_hello_row(
strs.layout.background_texture.spec,
[(300, 300), (200, 200), (100, 100)],
styles.SQUARE,
texture=True,
),
_hello_row(
_nm(styles.TAB),
[(400, 100), (200, 50), (100, 60)],
styles.TAB,
),
_hello_row(
_nm(styles.LARGER),
[(500, 100), (200, 50), (100, 60)],
styles.LARGER,
),
_hello_row(
_nm(styles.LARGE),
[(400, 100), (200, 50), (100, 60)],
styles.LARGE,
),
_hello_row(
_nm(styles.MEDIUM),
[(300, 100), (200, 50), (100, 60)],
styles.MEDIUM,
),
_hello_row(
_nm(styles.SMALL),
[(200, 100), (200, 50), (100, 60)],
styles.SMALL,
),
_hello_row(
_nm(styles.BACK),
[(200, 100), (200, 50), (100, 60)],
styles.BACK,
),
_hello_row(
_nm(styles.BACK_SMALL),
[(200, 100), (200, 50), (100, 60)],
styles.BACK_SMALL,
),
],
)
)
# Docs-generation hack; import some stuff that we likely only forward-declared
# in our actual source code so that docs tools can find it.
from typing import (Coroutine, Any, Literal, Callable,
Generator, Awaitable, Sequence, Self)
import asyncio
from concurrent.futures import Future
from pathlib import Path
from enum import Enum