I’ve put together a Python package called fibre
. It provides helpers to make it easy to write asynchronous applications. It uses Twisted under the hood.
I’ve also made a package called fibre.ui
. It adds user interface support using pygame.
One of my main aims has been code readability. See if you can figure out what this snippet from the demo program does:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
from fibre.ui import entry_point def main(): while True: menu = MainMenu.show() action = yield menu.wait_for_action() if action == 'quit': break yield run_ball_bounce() entry_point(main) |
The entry_point()
function saves you from spelling out the __name__ == '__main__'
incantation, and also initialises all the pygame and Twisted stuff. (If this is too magic for you, you can call run_application()
which doesn’t do any stack magic.)
When yield
is used, control is returned to the reactor until the given asynchronous function is finished (technically until the deferred fires, but for basic use of fibre
you don’t have to know much about deferreds).
The code above comes with the following class definition for the menu. See if you can figure out what it means.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
from fibre.ui import Box, window, Text, Button class MainMenu(ThemedScreen): Box( top_left = window.top_left, bottom_right = window.bottom_right, fill = 'menu_background', ) Text( 'Bounce Demo', mid_top = window.mid_top, colour = 'title', font = 'title', ) begin_button = Button( 'Begin', centre_x = window.x_position(0.33), centre_y = window.y_position(0.75), background_colour = 'button_fill', action = 'begin', ) quit_button = Button( 'Quit', centre_x = window.x_position(0.67), centre_y = window.y_position(0.75), background_colour = 'button_fill', action = 'quit', ) |
(Yes, there’s some magic in there behind the scenes. But I’ve almost convinced myself it’s worth it for the sake of readability.)
You may be wondering why colours are being specified as strings. You could also specify them as (R, G, B)
or (R, G, B, A)
tuples, but using the strings allows you to set up colour schemes. Here’s the relevant code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from fibre.ui import DefaultTheme, Screen class BallBounceTheme(DefaultTheme): class Colours(DefaultTheme.Colours): title = DefaultTheme.Colours.yellow menu_background = DefaultTheme.Colours.blue game_background = DefaultTheme.Colours.white text = DefaultTheme.Colours.black button_highlight = DefaultTheme.Colours.gray85 button_shadow = DefaultTheme.Colours.gray25 button_fill = DefaultTheme.Colours.gray50 class Fonts(DefaultTheme.Fonts): title = ('sans', 48) message = ('sans', 30) class ThemedScreen(Screen): theme = BallBounceTheme caption = 'Bounce Demo' |
By this stage I’ve shown you almost all of the code of the example, so I might as well show you the last little bit. This bit bounces a ball around until you press escape.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
from fibre.ui import wait_for_next_frame, Canvas class BallBounce(ThemedScreen): Box( top_left = window.top_left, bottom_right = window.bottom_right, fill = 'game_background', ) canvas = Canvas( top_left = window.top_left, bottom_right = window.bottom_right, ) Text( 'Press Escape to Exit', centre_x = window.centre_x, top = window.y_position(0.1), colour = 'text', font = 'message', ) def run_ball_bounce(): game = BallBounce.show() x = 0 y = 0 x_vel = 1 / 50. y_vel = 1 / 70. while True: if game.get_keyboard_status('ESCAPE'): break game.canvas.clear() game.canvas.draw_circle( colour=BallBounceTheme.Colours.blue, pos=(int(x), int(y)), radius=5, ) yield wait_for_next_frame() x += x_vel * game.width y += y_vel * game.width if x >= game.width: x_vel *= -1 elif x <= 0: x_vel *= -1 if y >= game.height: y_vel *= -1 elif y <= 0: y_vel *= -1 |
Hopefully this code is all clear enough that you can read through it and easily tell what it’s meant to do. After all, that was the aim of the exercise.
Is It Complete?
At time of writing, I can still think of billions of things that could be added to fibre.ui
. So far it’s got enough stuff to write a ball bounce demo program in it, but I shall be improving it over time.
Can I Play With It?
The fibre
module is licensed under version 2 of the GPL and is available on PyPI. Go forth and play!