diff options
author | Ian Ward <ian@excess.org> | 2012-10-10 16:33:37 -0400 |
---|---|---|
committer | Ian Ward <ian@excess.org> | 2012-10-10 16:33:37 -0400 |
commit | 68ee140b2d0e2730aef2d230f02c401cf46e76ae (patch) | |
tree | b64e12ee91d2444d6474a96fdce51118cb15b59b /docs/tutorial | |
parent | 05182dfb128a24d0f5ec32b706fdfee96998d6c2 (diff) | |
download | urwid-68ee140b2d0e2730aef2d230f02c401cf46e76ae.tar.gz |
tutorial: menu3/4 examples updated and described
--HG--
branch : feature-sphinx
Diffstat (limited to 'docs/tutorial')
-rw-r--r-- | docs/tutorial/index.rst | 39 | ||||
-rw-r--r-- | docs/tutorial/menu3.py | 20 | ||||
-rw-r--r-- | docs/tutorial/menu4.py | 43 | ||||
-rw-r--r-- | docs/tutorial/menu44.png | bin | 1480 -> 1312 bytes |
4 files changed, 61 insertions, 41 deletions
diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst index b0987bd..b9b4dc2 100644 --- a/docs/tutorial/index.rst +++ b/docs/tutorial/index.rst @@ -357,18 +357,25 @@ and new widget classes are used instead of factory functions. * *MenuButton* is a customized :class:`Button` widget. :class:`Button` uses :class:`WidgetWrap` to create its appearance and this class replaces the - display widget created by :class:`Button` by assigning to ``self._w`` in its - constructor. + display widget created by :class:`Button` by the wrapped widget in + *self._w*. * *SubMenu* is implemented with a *MenuButton* but uses :class:`WidgetWrap` to hide the implementation instead of inheriting from *MenuButton*. - Storing the menu that will be opened by this button as an attribute is a - good alternative to using factory functions and closures. -* *Menu* is implemented with a :class:`ListBox` hidden with :class:`WidgetWrap`. - This will make the implementation opaque to outside users so things like - setting the focus or iterating over children will not work as it would - if a simple factory function was used. This might make sense if you want - to add a whole new interface to your class or control how its children are - accessed. + The constructor builds a widget for the menu that this button will open + and stores it in *self.menu*. +* *Choice* is like *SubMenu* but displays the item chosen instead of + another menu. + +The *palette* used in this example includes an entry with the special name +``None``. The foreground and background specified in this entry are used +as a default when no other display attribute is specified. + +* *HorizontalBoxes* arranges the menus displayed similar to the previous + example. There is no special handling required for going to previous + menus here because :class:`Columns` already handles switching focus + when *LEFT* or *RIGHT* is pressed. :class:`AttrMap` with the *focus_map* + dict is used to change the appearance of a number of the display attributes + when a menu is in focus. .. image:: menu31.png .. image:: menu32.png @@ -378,9 +385,21 @@ and new widget classes are used instead of factory functions. Adventure Game -------------- +We can use the same sort of code to build a simple adventure game. Instead +of menus we have "places" and instead of submenus and parent menus we just +have "exits". This example scrolls previous places off the top of the +screen, allowing you to scroll back to view but not interact with previous +places. + .. literalinclude:: menu4.py :linenos: +This example starts to show some separation between the application logic +and the widgets that have been created. The *AdventureGame* class is +responsible for all the changes that happen through the game and manages +the topmost widget, but isn't a widget itself. This is a good pattern to +follow as your application grows larger. + .. image:: menu41.png .. image:: menu42.png .. image:: menu43.png diff --git a/docs/tutorial/menu3.py b/docs/tutorial/menu3.py index eefedc9..c48f42b 100644 --- a/docs/tutorial/menu3.py +++ b/docs/tutorial/menu3.py @@ -11,20 +11,16 @@ class SubMenu(urwid.WidgetWrap): def __init__(self, caption, choices): super(SubMenu, self).__init__(MenuButton( [caption, u"\N{HORIZONTAL ELLIPSIS}"], self.open_menu)) - self.menu = Menu(caption, choices) + line = urwid.Divider(u'\N{LOWER ONE QUARTER BLOCK}') + listbox = urwid.ListBox(urwid.SimpleFocusListWalker([ + urwid.AttrMap(urwid.Text([u"\n ", caption]), 'heading'), + urwid.AttrMap(line, 'line'), + urwid.Divider()] + choices + [urwid.Divider()])) + self.menu = urwid.AttrMap(listbox, 'options') def open_menu(self, button): top.open_box(self.menu) -class Menu(urwid.WidgetWrap): - def __init__(self, title, choices): - line = urwid.AttrMap(urwid.Divider(u'\N{LOWER ONE QUARTER BLOCK}'), - 'line') - listbox = urwid.ListBox(urwid.SimpleFocusListWalker([ - urwid.AttrMap(urwid.Text([u"\n ", title]), 'heading'), - line, urwid.Divider()] + choices + [urwid.Divider()])) - super(Menu, self).__init__(urwid.AttrMap(listbox, 'options')) - class Choice(urwid.WidgetWrap): def __init__(self, caption): super(Choice, self).__init__( @@ -40,7 +36,7 @@ class Choice(urwid.WidgetWrap): def exit_program(key): raise urwid.ExitMainLoop() -menu_top = Menu(u'Main Menu', [ +menu_top = SubMenu(u'Main Menu', [ SubMenu(u'Applications', [ SubMenu(u'Accessories', [ Choice(u'Text Editor'), @@ -81,5 +77,5 @@ class HorizontalBoxes(urwid.Columns): self.focus_position = len(self.contents) - 1 top = HorizontalBoxes() -top.open_box(menu_top) +top.open_box(menu_top.menu) urwid.MainLoop(urwid.Filler(top, 'middle', 10), palette).run() diff --git a/docs/tutorial/menu4.py b/docs/tutorial/menu4.py index 7d07688..129ff50 100644 --- a/docs/tutorial/menu4.py +++ b/docs/tutorial/menu4.py @@ -1,7 +1,5 @@ import urwid -inventory = set() - class ActionButton(urwid.Button): def __init__(self, caption, callback): super(ActionButton, self).__init__("") @@ -20,7 +18,7 @@ class Place(urwid.WidgetWrap): getattr(child, 'choices', []).insert(0, self) def enter_place(self, button): - top.move_to(self) + game.update_place(self) class Thing(urwid.WidgetWrap): def __init__(self, name): @@ -29,13 +27,8 @@ class Thing(urwid.WidgetWrap): self.name = name def take_thing(self, button): - loop.process_input(["up"]) # move focus off this widget self._w = urwid.Text(u" - %s (taken)" % self.name) - inventory.add(self.name) - if inventory >= set([u'sugar', u'lemon', u'jug']): - response = urwid.Text(u'You can make lemonade!\n') - done = ActionButton(u' - Joy', exit_program) - loop.widget = urwid.Filler(urwid.Pile([response, done])) + game.take_thing(self) def exit_program(button): raise urwid.ExitMainLoop() @@ -63,16 +56,28 @@ map_top = Place(u'porch', [ ]), ]) -class AdventureLog(urwid.ListBox): +class AdventureGame(object): def __init__(self): - log = urwid.SimpleFocusListWalker([]) - super(AdventureLog, self).__init__(log) + self.log = urwid.SimpleFocusListWalker([]) + self.top = urwid.ListBox(self.log) + self.inventory = set() + self.update_place(map_top) - def move_to(self, place): - self.body.append(urwid.Pile([place.heading] + place.choices)) - self.focus_position = len(self.body) - 1 + def update_place(self, place): + if self.log: # disable interaction with previous place + self.log[-1] = urwid.WidgetDisable(self.log[-1]) + self.log.append(urwid.Pile([place.heading] + place.choices)) + self.top.focus_position = len(self.log) - 1 + self.place = place + + def take_thing(self, thing): + self.inventory.add(thing.name) + if self.inventory >= set([u'sugar', u'lemon', u'jug']): + response = urwid.Text(u'You can make lemonade!\n') + done = ActionButton(u' - Joy', exit_program) + self.log[:] = [response, done] + else: + self.update_place(self.place) -top = AdventureLog() -top.move_to(map_top) -loop = urwid.MainLoop(top, palette=[('reversed', 'standout', '')]) -loop.run() +game = AdventureGame() +urwid.MainLoop(game.top, palette=[('reversed', 'standout', '')]).run() diff --git a/docs/tutorial/menu44.png b/docs/tutorial/menu44.png Binary files differindex 2efacc7..7988daa 100644 --- a/docs/tutorial/menu44.png +++ b/docs/tutorial/menu44.png |