218 lines
7.5 KiB
Python
218 lines
7.5 KiB
Python
#!/usr/bin/env python
|
|
|
|
# Copyright (C) 2010-2012 Sam Bull
|
|
|
|
"""
|
|
Menu widget. Creates a menu for a game.
|
|
|
|
"""
|
|
|
|
from _locals import *
|
|
from boxes import VBox
|
|
from scroll_box import ScrollBox
|
|
from . import *
|
|
|
|
class Menu(Simple):
|
|
|
|
"""
|
|
Menu
|
|
|
|
Can be indexed to access widgets by name.
|
|
|
|
Attributes:
|
|
func_dict: Assign a lambda to return a dictionary of functions for
|
|
config file to utilise.
|
|
|
|
"""
|
|
|
|
_modal = True
|
|
_layered = True
|
|
_settings_default = {"offset": (100, 50), "col": (0,0,1), "apply": False}
|
|
|
|
_menus = []
|
|
_dict = {} # Dict for indexing widgets
|
|
_old_menu = None
|
|
_curr_menu = 0
|
|
func_dict = lambda self: {}
|
|
|
|
def _config(self, **kwargs):
|
|
"""
|
|
menu: Either tuple containing menu data, to be documented.
|
|
Or file object to read config data from, in the same format.
|
|
apply: TODO ``bool`` True if an apply button should be added.
|
|
col: ``tuple`` (r,g,b), Colour used for the background.
|
|
offset: ``tuple`` (x,y) Contains position of menu widgets. y is
|
|
added to bottom of title.
|
|
|
|
"""
|
|
if "apply" in kwargs:
|
|
self._settings["apply"] = kwargs["apply"]
|
|
if "col" in kwargs:
|
|
self._settings["col"] = kwargs["col"]
|
|
if "offset" in kwargs:
|
|
self._settings["offset"] = kwargs["offset"]
|
|
if "menu" in kwargs:
|
|
self._menus = [] # Remove previous menus
|
|
self._dict = {}
|
|
# Grab function dictionary
|
|
self._funcs = self.func_dict()
|
|
|
|
# Set size to screen size
|
|
if not hasattr(self, "image"):
|
|
self._create_base_images(get_screen().rect.size)
|
|
|
|
menu = kwargs["menu"]
|
|
# If file, read config tuple
|
|
if isinstance(menu, file):
|
|
menu_data = "".join(menu.readlines())
|
|
menu = eval(menu_data)
|
|
assert isinstance(menu, tuple)
|
|
|
|
menu_data = [(menu, None)] # (data, parent)
|
|
# Create each submenu, by iterating through the menu data
|
|
while menu_data:
|
|
self._menus.append(_SubMenu(self.rect.size,
|
|
col=self._settings["col"]))
|
|
self._config_menu(menu_data, self._menus[-1])
|
|
|
|
def _config_menu(self, data_queue, menu):
|
|
"""
|
|
Configure the passed in menu, using the information from the first
|
|
item in data_queue.
|
|
|
|
New sub-menus discovered in the data will be appended to the data_queue
|
|
for later processing.
|
|
|
|
"""
|
|
data, parent = data_queue.pop(0)
|
|
widgets = []
|
|
# Parse menu data
|
|
for item in data:
|
|
# Title
|
|
if isinstance(item, str):
|
|
menu._title = Simple(Font["title"].render(item[2:], True,
|
|
Font.col))
|
|
menu._title.rect.midtop = (self.rect.centerx, 40)
|
|
# Sub-menu
|
|
elif item[0].startswith("m:"):
|
|
data_queue.append((item, len(self._menus)-1))
|
|
surf = Font["widget"].render(item[0][2:], True, Font.col)
|
|
widgets.append(Button(surf))
|
|
# Change menu on button activate
|
|
num = len(self._menus)-1 + len(data_queue)
|
|
widgets[-1].activate = lambda n=num: self.change_menu(n)
|
|
# Category/divider
|
|
elif item[0].startswith("c:"):
|
|
div = Simple(Font["widget"].render(item[0][2:], True,
|
|
Font.col))
|
|
self.get_draw().line(div.image, Font.col, (0, div.rect.h-1),
|
|
(div.rect.w, div.rect.h-1))
|
|
widgets.append(div)
|
|
# Widget
|
|
elif item[0].startswith("w:"):
|
|
args = self._get_args(item[1:])
|
|
name = args.pop("name")
|
|
f = args.pop("func") if ("func" in args) else None
|
|
if item[0].endswith("input_box"):
|
|
widget = input_box.InputBox(**args)
|
|
elif item[0].endswith("button"):
|
|
for key in args:
|
|
if key == "surf":
|
|
args[key] = eval(args[key])
|
|
widget = button.Button(**args)
|
|
elif item[0].endswith("label"):
|
|
widget = label.Label(**args)
|
|
self._dict[name] = widget
|
|
if f: widget.activate = self._funcs[f]
|
|
widgets.append(widget)
|
|
# Function
|
|
elif item[0].startswith("f:"):
|
|
surf = Font["widget"].render(item[1], True, Font.col)
|
|
widgets.append(button.Button(surf=surf))
|
|
widgets[-1].activate = self._funcs[item[0][2:]]
|
|
|
|
# Draw a back menu item
|
|
if parent is not None:
|
|
surf = Font["widget"].render("Back", True, Font.col)
|
|
widgets.append(button.Button(surf=surf))
|
|
widgets[-1].activate = lambda n=parent: self.change_menu(n)
|
|
|
|
menu._widgets = tuple(widgets)
|
|
|
|
def _draw(self, draw):
|
|
for menu in self._menus:
|
|
# Pack all widgets into a VBox
|
|
box = VBox(widgets=menu._widgets, spacing=15)
|
|
pos = (self._settings["offset"][0],
|
|
self._settings["offset"][1] + menu._title.rect.bottom)
|
|
box = ScrollBox((self.rect.w - pos[0], self.rect.h - pos[1]),
|
|
widget=box, pos=pos)
|
|
menu.config(col=self._settings["col"], menu=box)
|
|
|
|
def change_menu(self, menu_num):
|
|
"""
|
|
Change the currently displayed menu.
|
|
|
|
Args:
|
|
menu_num: ``int`` The number representing the menu.
|
|
|
|
"""
|
|
self._old_menu = self._curr_menu
|
|
self._curr_menu = menu_num
|
|
self._menus[self._curr_menu]._fade = 0
|
|
|
|
def update(self, time):
|
|
menu = self._menus[self._curr_menu]
|
|
menu.update(time)
|
|
if self._old_menu is not None:
|
|
self.image.blit(self._menus[self._old_menu].image, (0,0))
|
|
menu.image.set_alpha(menu._fade)
|
|
menu._fade += time / 3.
|
|
if menu._fade >= 255:
|
|
menu._fade = None
|
|
self._old_menu = None
|
|
menu.image.set_alpha(255)
|
|
self.image.blit(menu.image, (0,0))
|
|
|
|
def _event(self, event):
|
|
self._menus[self._curr_menu]._event(event)
|
|
|
|
def _get_args(self, args):
|
|
"""Get the arguments passed in, saving them into a dictionary."""
|
|
return {arg.split("=")[0]: arg.split("=")[1] for arg in args}
|
|
|
|
def __getitem__(self, key):
|
|
"""Return widgets by name."""
|
|
return self._dict[key]
|
|
|
|
class _SubMenu(Simple):
|
|
|
|
"""
|
|
A single menu object to be created and managed by the Menu class.
|
|
|
|
"""
|
|
_settings_default = {"col": (0,0,1), "menu": None}
|
|
|
|
_title = None
|
|
_widgets = ()
|
|
|
|
def _config(self, **kwargs):
|
|
if "col" in kwargs:
|
|
self._settings["col"] = kwargs["col"]
|
|
if "menu" in kwargs:
|
|
self._settings["menu"] = kwargs["menu"]
|
|
|
|
def _draw(self, draw):
|
|
self._images["image"].fill(self._settings["col"])
|
|
if self._title:
|
|
self._images["image"].blit(self._title.image, self._title.pos)
|
|
|
|
def update(self, time):
|
|
self.image = self._images["image"].copy()
|
|
self._settings["menu"].update(time)
|
|
self.image.blit(self._settings["menu"].image,self._settings["menu"].pos)
|
|
|
|
def _event(self, event):
|
|
"""Send events to container."""
|
|
self._settings["menu"]._event(event)
|