Source code for albow.menu
# ---------------------------------------------------------------------------
#
# Albow - Pull-down or pop-up menu
#
#---------------------------------------------------------------------------
#-# Modified by D.C.-G. for translation purpose
import sys
from root import get_root, get_focus
from dialogs import Dialog
from theme import ThemeProperty
from pygame import Rect, draw
from translate import _
#---------------------------------------------------------------------------
[docs]class MenuItem(object):
keyname = ""
keycode = None
shift = False
alt = False
enabled = False
if sys.platform.startswith('darwin') or sys.platform.startswith('mac'):
cmd_name = "Cmd "
option_name = "Opt "
else:
cmd_name = "Ctrl "
option_name = "Alt "
def __init__(self, text="", command=None, doNotTranslate=False):
self.command = command
if "/" in text:
text, key = text.split("/", 1)
else:
key = ""
self.text = _(text, doNotTranslate=doNotTranslate)
if key:
keyname = key[-1]
mods = key[:-1]
self.keycode = ord(keyname.lower())
if "^" in mods:
self.shift = True
keyname = "Shift " + keyname
if "@" in mods:
self.alt = True
keyname = self.option_name + keyname
self.keyname = self.cmd_name + keyname
#---------------------------------------------------------------------------
[docs]class Menu(Dialog):
disabled_color = ThemeProperty('disabled_color')
click_outside_response = -1
scroll_button_size = ThemeProperty('scroll_button_size')
scroll_button_color = ThemeProperty('scroll_button_color')
scroll = 0
def __init__(self, title, items, scrolling=False, scroll_items=30,
scroll_page=5, handler=None, **kwds):
self.handler = handler
self.title = _(title, doNotTranslate=kwds.get('doNotTranslate', False))
self.items = items
self._items = [MenuItem(*item, doNotTranslate=kwds.get('doNotTranslate', False)) for item in items]
self.scrolling = scrolling and len(self._items) > scroll_items
self.scroll_items = scroll_items
self.scroll_page = scroll_page
Dialog.__init__(self, **kwds)
self.root = self.get_root()
self.calc_size()
#&#
[docs] def set_items(self, items):
self.items = items
self._items = [MenuItem(*item, doNotTranslate=self.doNotTranslate) for item in items]
[docs] def set_scroll_items(self, scroll_items):
if scroll_items < len(self.items):
self.scroll_items = scroll_items
else:
self.scroll_items = len(self.items)
self.calc_size()
#&#
[docs] def calc_size(self):
h = self.font.get_linesize()
if self.scrolling:
self.height = h * self.scroll_items + h
else:
self.height = h * len(self._items) + h
[docs] def set_update_ui(self, v):
if v:
self._items = [MenuItem(*item, doNotTranslate=self.doNotTranslate) for item in self.items]
Dialog.set_update_ui(self, v)
[docs] def present(self, client, pos):
client = client or self.root
self.topleft = client.local_to_global(pos)
focus = self.handler or get_focus()
font = self.font
h = font.get_linesize()
items = self._items
margin = self.margin
if self.scrolling:
height = h * self.scroll_items + h
else:
height = h * len(items) + h
w1 = w2 = 0
for item in items:
item.enabled = self.command_is_enabled(item, focus)
w1 = max(w1, font.size(item.text)[0])
w2 = max(w2, font.size(item.keyname)[0])
width = w1 + 2 * margin
self._key_margin = width
if w2 > 0:
width += w2 + margin
if self.scrolling:
width += self.scroll_button_size
self.size = (width, height)
self._hilited = None
self.rect.clamp_ip(self.root.rect)
return Dialog.present(self, centered=False)
@staticmethod
[docs] def command_is_enabled(item, focus):
cmd = item.command
if cmd:
enabler_name = cmd + '_enabled'
handler = focus
while handler:
enabler = getattr(handler, enabler_name, None)
if enabler:
return enabler()
handler = handler.next_handler()
return True
[docs] def scroll_up_rect(self):
d = self.scroll_button_size
r = Rect(0, 0, d, d)
m = self.margin
r.top = m
r.right = self.width - m
r.inflate_ip(-4, -4)
return r
[docs] def scroll_down_rect(self):
d = self.scroll_button_size
r = Rect(0, 0, d, d)
m = self.margin
r.bottom = self.height - m
r.right = self.width - m
r.inflate_ip(-4, -4)
return r
[docs] def draw(self, surf):
font = self.font
h = font.get_linesize()
sep = surf.get_rect()
sep.height = 1
if self.scrolling:
sep.width -= self.margin + self.scroll_button_size
colors = [self.disabled_color, self.fg_color]
bg = self.bg_color
xt = self.margin
xk = self._key_margin
y = h // 2
hilited = self._hilited
if self.scrolling:
items = self._items[self.scroll:self.scroll + self.scroll_items]
else:
items = self._items
for item in items:
text = item.text
if not text:
sep.top = y + h // 2
surf.fill(colors[0], sep)
else:
if item is hilited:
rect = surf.get_rect()
rect.top = y
rect.height = h
if self.scrolling:
rect.width -= xt + self.scroll_button_size
surf.fill(colors[1], rect)
color = bg
else:
color = colors[item.enabled]
buf = font.render(item.text, True, color)
surf.blit(buf, (xt, y))
keyname = item.keyname
if keyname:
buf = font.render(keyname, True, color)
surf.blit(buf, (xk, y))
y += h
if self.scrolling:
if self.can_scroll_up():
self.draw_scroll_up_button(surf)
if self.can_scroll_down():
self.draw_scroll_down_button(surf)
[docs] def draw_scroll_up_button(self, surface):
r = self.scroll_up_rect()
c = self.scroll_button_color
draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])
[docs] def draw_scroll_down_button(self, surface):
r = self.scroll_down_rect()
c = self.scroll_button_color
draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])
[docs] def mouse_drag(self, e):
item = self.find_enabled_item(e)
if item is not self._hilited:
self._hilited = item
self.invalidate()
[docs] def mouse_up(self, e):
if 1 <= e.button <= 3:
item = self.find_enabled_item(e)
if item:
self.dismiss(self._items.index(item))
[docs] def find_enabled_item(self, e):
x, y = e.local
if 0 <= x < (self.width - self.margin - self.scroll_button_size
if self.scrolling else self.width):
h = self.font.get_linesize()
i = (y - h // 2) // h + self.scroll
items = self._items
if 0 <= i < len(items):
item = items[i]
if item.enabled:
return item
[docs] def mouse_down(self, event):
if event.button == 1:
if self.scrolling:
p = event.local
if self.scroll_up_rect().collidepoint(p):
self.scroll_up()
return
elif self.scroll_down_rect().collidepoint(p):
self.scroll_down()
return
if event.button == 4:
self.scroll_up()
if event.button == 5:
self.scroll_down()
Dialog.mouse_down(self, event)
[docs] def scroll_up(self):
if self.can_scroll_up():
self.scroll = max(self.scroll - self.scroll_page, 0)
[docs] def scroll_down(self):
if self.can_scroll_down():
self.scroll = min(self.scroll + self.scroll_page,
len(self._items) - self.scroll_items)
[docs] def can_scroll_down(self):
return (self.scrolling and
self.scroll + self.scroll_items < len(self._items))
[docs] def find_item_for_key(self, e):
for item in self._items:
if item.keycode == e.key \
and item.shift == e.shift and item.alt == e.alt:
focus = get_focus()
if self.command_is_enabled(item, focus):
return self._items.index(item)
else:
return -1
return -1
[docs] def get_command(self, i):
if i >= 0:
item = self._items[i]
cmd = item.command
if cmd:
return cmd + '_cmd'