133 lines
4.6 KiB
Python
133 lines
4.6 KiB
Python
#!/usr/bin/env python
|
|
|
|
# Copyright (C) 2010-2012 Sam Bull
|
|
|
|
"""
|
|
Container widget, can be inherited to implement more complex behaviour.
|
|
|
|
"""
|
|
|
|
import pygame.sprite
|
|
from pygame.locals import *
|
|
|
|
from _locals import *
|
|
from _locals import Focus
|
|
from base_widget import Simple
|
|
|
|
class Container(Simple):
|
|
|
|
"""
|
|
Container widget. Handles focus and events of a group
|
|
of widgets packed into a single container.
|
|
|
|
If ``surf`` is not given, container will be the right size to fit all
|
|
widgets.
|
|
|
|
"""
|
|
|
|
_can_focus = True
|
|
_settings_default = {"border": 0, "col": 0, "widgets": None}
|
|
|
|
_focus = None
|
|
_order = None
|
|
|
|
def _config(self, **kwargs):
|
|
"""
|
|
widgets: ``list`` Contains widgets to be added at creation time.
|
|
The order of widgets in the list denotes order they receive
|
|
focus when user hits :kbd:`TAB`.
|
|
border: ``int`` Number of pixels to space around edges when ``surf``
|
|
is not given.
|
|
col: ``tuple`` (r,g,b) Colour for background, 0 is transparent.
|
|
|
|
"""
|
|
if "border" in kwargs:
|
|
self._settings["border"] = kwargs["border"]
|
|
if "col" in kwargs:
|
|
self._settings["col"] = kwargs["col"]
|
|
if "widgets" in kwargs:
|
|
self._settings["widgets"] = pygame.sprite.Group()
|
|
self._focus = Focus()
|
|
self._order = []
|
|
pad = self._settings["border"]
|
|
for w in kwargs["widgets"]:
|
|
w._parent = self
|
|
w.pos = (w.rect.x + pad, w.rect.y + pad)
|
|
self._settings["widgets"].add(w)
|
|
if w._can_focus: self._order.append(w)
|
|
if not hasattr(self, "image"):
|
|
width = max(kwargs["widgets"], key=lambda w: w.rect.right)
|
|
width = width.rect.right + pad
|
|
height = max(kwargs["widgets"], key=lambda w: w.rect.bottom)
|
|
height = height.rect.bottom + pad
|
|
self._create_base_images((width, height))
|
|
|
|
def update(self, time):
|
|
"""Update widgets each frame."""
|
|
self.image.fill(self._settings["col"])
|
|
self._settings["widgets"].update(time)
|
|
for w in self._settings["widgets"]:
|
|
self.image.blit(w.image, w.pos)
|
|
|
|
def _event(self, event):
|
|
"""Handle focus and send events to sub-widgets."""
|
|
if event.type == MOUSEBUTTONDOWN:
|
|
hit = False
|
|
for widget in self._settings["widgets"]:
|
|
# Check if user clicked a widget
|
|
if widget._can_focus:
|
|
if widget.rect_abs.collidepoint(event.pos):
|
|
self._focus.add(2, widget)
|
|
hit = True
|
|
break
|
|
# Lose focus if clicking away from widgets
|
|
if not hit:
|
|
self._focus.empty()
|
|
elif event.type == KEYDOWN and event.key == K_TAB:
|
|
# Focus number for current focused widget
|
|
if self._focus.sprite not in self._order:
|
|
curr_num = None
|
|
else:
|
|
curr_num = self._order.index(self._focus.sprite)
|
|
if not event.mod & KMOD_SHIFT: # Move focus to next widget
|
|
# Next focus number in the list
|
|
if curr_num is None:
|
|
# If nothing focused, focus first widget
|
|
new_num = 0
|
|
elif not self._focus.sprite._change_focus(True):
|
|
# Test for container widgets
|
|
new_num = curr_num
|
|
elif curr_num >= len(self._order)-1:
|
|
new_num = 0
|
|
else:
|
|
new_num = curr_num + 1
|
|
else: # Shift key - move focus to previous widget
|
|
if curr_num is None:
|
|
new_num = -1
|
|
elif not self._focus.sprite._change_focus(False):
|
|
new_num = curr_num
|
|
elif curr_num <= 0:
|
|
new_num = -1
|
|
else:
|
|
new_num = curr_num - 1
|
|
if curr_num != new_num:
|
|
self._focus.add(1, self._order[new_num])
|
|
if self._focus:
|
|
self._focus.sprite._event(event)
|
|
|
|
def _change_focus(self, forward=True):
|
|
"""Override Simple and check if focus should leave yet."""
|
|
if self._focus and not self._focus.sprite._change_focus(forward):
|
|
return False
|
|
if not self._focus:
|
|
return False
|
|
num = self._order.index(self._focus.sprite)
|
|
if forward and num < len(self._order)-1:
|
|
return False
|
|
if not forward and num > 0:
|
|
return False
|
|
return True
|
|
|
|
def _focus_exit(self):
|
|
self._focus.empty()
|