[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[pygame] Minimal GUI support



I've been thinking about some small supporting tool for writing
GUI-like code in PyGame -- especially adding "widgets" to plain PyGame
applications (e.g. games), such as the buttons in SolarWolf etc.

What I came up with was the FocusGroup (pardon the pun ;)

Basically, it's a Group (I inherited RenderUpdates; perhaps I should inherit
Group instead, and use it as a mixin?) which can manage links between its
members, where each link has a test connected to it. This test is used to see
whether a specific event warrants a focus change along that link. The elements
should be sprites which implement the methods focus(), blur() and handle(). The
code is quite simple (and I'm sure there is plenty of room for improvement):

------ begin focusgroup.py ------

mport pygame.sprite

class FocusAdapter:
    def focus(self): pass
    def blur(self): pass

class FocusGroup(pygame.sprite.RenderUpdates):
    def __init__(self, *args, **kwds):
        pygame.sprite.RenderUpdates.__init__(self, *args, **kwds)
        self._links = []
        self._current_focus = FocusAdapter()
    def handle(self, event):
        for sprite1, sprite2, test in self._links:
            if sprite1 is self._current_focus and test(event):
                self.focus(sprite2)
                break
        else:
            return self._current_focus.handle(event)
        return 1
    def focus(self, sprite):
        self._current_focus.blur()
        self._current_focus = sprite
        sprite.focus()
    def blur(self):
        for sprite in self.sprites:
            sprite.blur()
    def link(self, sprite1, sprite2, test):
        self._links.append((sprite1, sprite2, test))
    def remove(self, sprite):
        self._links = [x for x in self._links if x[1] is not sprite]
        pygame.sprite.RenderUpdates.remove(self, sprite)

------- end focusgroup.py -------

Assuming the existence of some Sprites called quit_button and
next_button, one could use the group like this:

def up_test(event):
    return event.type == KEYDOWN and event.key in [K_UP, K_TAB]

def down_test(event):
    return event.type == KEYDOWN and event.key in [K_DOWN, K_TAB]

buttons = FocusGroup([quit_button, next_button])
buttons.link(next_button, quit_button, down_test)
buttons.link(quit_button, next_button, up_test)

With this setup, only the button currently in focus would receive
events through the focus group. This makes it possible to make rather
complex widget layouts that one can navigate with arrow keys, tab,
etc. (I guess I was inspired by the unpredictable behaviour of DVD
menus when I thought of the graph solution ;)

In the event loop one would do something like this:

  if buttons.handle(event):
      # ... do something
  elif ...
      ...

I was thinking of submitting it (perhaps with a more complete example)
to the code repository, but wanted some feedback on it first... Is it
really useful?

--
Magnus Lie Hetland                                  The Anygui Project
http://hetland.org                                  http://anygui.org
____________________________________
pygame mailing list
pygame-users@seul.org
http://pygame.seul.org