Usage Examples¶
Quick Example¶
A simple counter with two buttons to increment and decrement a value:
from pyiced import (
Align, button, ButtonState, column, container, IcedApp, Length, text,
)
class ExampleApp(IcedApp):
def __init__(self):
self.__incr_button_state = ButtonState()
self.__decr_button_state = ButtonState()
self.__value = 0
def title(self):
return 'Counter'
def view(self):
increment_button = button(
self.__incr_button_state, # To track the state across redraws.
text('Increment'), # This is content on the button.
on_press='incr', # This value is received in update().
)
value_label = text(f'{self.__value}', size=50)
decerement_button = button(
self.__decr_button_state,
text('Decrement'),
on_press='decr',
)
return container(
column([
increment_button,
value_label,
decerement_button,
]),
padding=20, align_x=Align.CENTER, align_y=Align.CENTER,
width=Length.FILL, height=Length.FILL,
)
def update(self, msg, clipboard):
# When an event occurs, this method is called.
# It can optionally return a list of async functions,
# to handle the event.
match msg:
case 'incr':
self.__value += 1
case 'decr':
self.__value -= 1
if __name__ == '__main__':
# This function only returns if there is an error on start-up.
# Otherwise the program gets terminated when the window is closed.
ExampleApp().run()
Custom Styles¶
from pyiced import (
Align, button, ButtonState, ButtonStyle, Color, container,
ContainerStyle, IcedApp, Length, text,
)
class ButtonExample(IcedApp):
class settings:
class window:
size = (640, 320)
def __init__(self):
self.__button_state = ButtonState()
def title(self):
return 'A Button'
def view(self):
styled_button = button(
self.__button_state,
text('Hello, world!', size=40),
'',
style=ButtonStyle(
shadow_offset=(8, 8), border_radius=40, border_width=6,
background=Color(0.17, 0.17, 0.17),
border_color=Color(0.95, 0.87, 0.22),
text_color=Color(1.00, 0.18, 0.13)
),
padding=40,
)
return container(
styled_button,
style=ContainerStyle(background=Color(0.38, 0.60, 0.23)),
padding=20, align_x=Align.CENTER, align_y=Align.CENTER,
width=Length.FILL, height=Length.FILL,
)
if __name__ == '__main__':
ButtonExample().run()
Asychronous Messages¶
new()
and update()
can either return a Message
(or a sequence of messages in the latter case), or
a coroutine / coroutines
to asynchronously generate a messages.
from asyncio import open_connection
from contextlib import closing
from pyiced import (
Align, Color, container, ContainerStyle, Font, IcedApp, Length, text,
)
class AsyncMessageExample(IcedApp):
def __init__(self):
self.__font = None
class settings:
class window:
size = (640, 320)
def title(self):
return 'Asynchronous Messages'
def new(self):
return load_font()
def update(self, msg, clipboard):
match msg:
case ('Font', font):
self.__font = font
def view(self):
return container(
text('Hello, world!', size=80, font=self.__font),
style=ContainerStyle(
text_color=Color(0.95, 0.87, 0.22),
background=Color(0.38, 0.60, 0.23),
),
padding=20, align_x=Align.CENTER, align_y=Align.CENTER,
width=Length.FILL, height=Length.FILL,
)
async def load_font():
FONT_NAME = 'Yellowtail'
FONT_HOST = 'fonts.cdnfonts.com'
FONT_PATH = '/s/16054/Yellowtail-Regular.ttf'
query = (
f"GET {FONT_PATH} HTTP/1.0\r\n"
f"Host: {FONT_HOST}\r\n"
f"Connection: closed\r\n"
f"User-Agent: Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)\r\n"
f"\r\n"
).encode('US-ASCII')
reader, writer = await open_connection(FONT_HOST, 443, ssl=True)
with closing(writer):
writer.write(query)
await writer.drain()
while (await reader.readline()) != b'\r\n':
continue
data = await reader.read()
await writer.wait_closed()
return ('Font', Font(FONT_NAME, data))
if __name__ == '__main__':
AsyncMessageExample().run()
AsyncGenerator Generating Messages¶
An application can subscribe
to AsyncGenerator
s
to receive Message
s about asynchronously generated information, e.g. a pending web download.
from asyncio import sleep
from pyiced import column, IcedApp, stream, text
class StreamExample(IcedApp):
def __init__(self):
self.__stream = stream(self.__generator_func())
self.__index = 0
class settings:
class window:
size = (640, 40)
def title(self):
return 'Stream Example'
def view(self):
return column([text(f'Index: {self.__index / 10:.1f}')])
def subscriptions(self):
if self.__stream is not None:
return [self.__stream]
def update(self, msg, clipboard):
match msg:
case 'done':
self.__stream = None
case int(index):
self.__index = index
async def __generator_func(self):
for i in range(1, 101):
yield i
await sleep(0.1)
yield 'done'
if __name__ == '__main__':
StreamExample().run()
Capturing Keystrokes¶
To capture any keystoke (or indeed any event that original from user interaction),
you can make pyiced.IcedApp.subscriptions()
return a list
[pyced.Subscription.UNCAPTURED
].
from pyiced import (
Align, container, Message, IcedApp, Length, Subscription, text,
)
class FullscreenExample(IcedApp):
def __init__(self):
self.__fullscreen = False
self.__should_exit = False
class settings:
class window:
size = (640, 320)
def subscriptions(self):
return [Subscription.UNCAPTURED]
def fullscreen(self):
return self.__fullscreen
def should_exit(self):
return self.__should_exit
def title(self):
return self.__message
def update(self, msg, clipboard):
match msg:
case Message(keyboard='keyreleased', key_code='F11'):
self.__fullscreen = not self.__fullscreen
case Message(keyboard='keyreleased', key_code='Escape'):
self.__should_exit = True
def view(self):
return container(
text(self.__message, size=40),
padding=20, align_x=Align.CENTER, align_y=Align.CENTER,
width=Length.FILL, height=Length.FILL,
)
@property
def __message(self):
if self.__fullscreen:
return 'Fullscreen (press F11!)'
else:
return 'Windowed (press F11!)'
if __name__ == '__main__':
FullscreenExample().run()