############################################################################# ## This file is part of TunnelHack II. ## ##-------------------------------------------------------------------------## ## Copyright 2007-2008 Bryce Schroeder ## ## bryce.schroeder@gmail.com ## ## http://www.ferazelhosting.net/~bryce/ ## ##-------------------------------------------------------------------------## ## This program is free software: you can redistribute it and/or modify ## ## it under the terms of the GNU General Public License as published by ## ## the Free Software Foundation, either version 3 of the License, or ## ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## ## along with this program. If not, see . ## ############################################################################# from .interface import IObj, IExclusiveGroup, button from .g import g import pygame class IModal(IObj): """ Base class for modal windows. Modal windows include things you would normally think of as such, e.g. a pop-up dialog box warning the user of some cataclysm, however internally menus are also modal windows. """ def init(self): self.done = False def render_self(self, theme, target, px, py): self.draw_rect((3,2), target, px, py, self.p.w, self.p.h) return True def accept_click(self, x, y): return True # eat clicks def handle_click(self, lx, ly): return False def finish(self): self.done = True self.window_manager.remove(self) def release_focus(self): return self.done class IMenu(IModal, IExclusiveGroup): """ Class for a pop-up or pull-down menu. You shouldn't use this class directly. Use the an IMenuGenerator, either IPullDownMenu or IPopUpMenu. These objects are much friendlier to use. """ def init(self): self.done = False # where we will send the data when it changes. self.send_value = self.p.get('send_value', True) def render_self(self, theme, target, px, py): return True def render_overlay(self, theme, target, px, py): self.draw_empty_rect((1,13), target, px, py, self.p.w, self.p.h) def get_value(self): for child in self.contents: if child.state in [self.CLICKED,self.FOCUSED]: return child return None def accept_mouse(self, x, y): return True def handle_mouse(self, lx, ly): for child in self.contents: child.transition('unmouse') def process_unclick(self, x, y): for child in self.contents: if child.process_unclick(x-self.rect.x,y-self.rect.y): self.perish() return True return False def perish(self): for link in self.links: link.get_message(self, value=self.get_value().name) self.window_manager.release_modal_focus() self.window_manager.remove(self) self.done = True class IMenuItem(button.ITextButton, IObj): """ Class for menu items. """ def render_self(self, theme, target, px, py): theme_blit = theme.blit underline = self.p.get('underline', False) #if self.state in [self.CLICKED, self.FOCUSED]: # bg = (8,11) #else: # bg = (5,11) bg = (2+3*self.state,11) for x in xrange(0,self.p.w): theme_blit(bg, target, px+16*x, py) if underline: theme_blit((13,2), target, px+16*x, py) target.blit(self.text_surf, (px, py + self.base_my)) def accept_unclick(self, x, y): return self.state != self.NORMAL and self.rect.collidepoint(x,y) class IMenuGenerator(button.ITextButton): """ """ def init(self): self.value = self.p.text self.render_text() def render_text(self): font_res = g.resources.get('Font', self.p.get('font', 'Junicode')) width, height, size = self.p.w-1, self.p.h, self.p.get('size', 12) font = font_res.pygame_font(size) lines = font_res.wrap_text(size, self.value, width * 16 - 5) height_mul = font.get_height() + 2 font_height = len(lines) * height_mul - 2 self.text_surf = pygame.Surface((width * 16, font_height), pygame.SRCALPHA, 32) self.text_surf.fill((0, 0, 0, 0)) self.base_my = (height * 16 - font_height - 1) // 2 for e, line in enumerate(lines): surf = font.render(line, 1, self.p.color) mx = (width * 16 - surf.get_width()) // 2 self.text_surf.blit(surf, (mx, e * height_mul)) self.text_surf = self.text_surf.convert_alpha() # needs to rerender its text based on value! also default def render_self(self, theme, target, px, py): theme.blit((1+self.state*3,7), target, px, py) for x in xrange(1, self.p.w-1): theme.blit((2+self.state*3,7), target, px+16*x, py) theme.blit((3+self.state*3,8), target, px+(self.p.w-1)*16, py) target.blit(self.text_surf, (px, py + self.base_my)) def handle_click(self, lx, ly): if (self.archon.window_manager.modal_busy() or self.archon.drag_in_progress()): return self.make_menu(self.p.options) def make_menu(self, options): modal = IMenu(None, link=self, w=self.p.w, h=len(options)) self.transtable = {} i = 0 for name, value, underline in options: IMenuItem(modal, text=name,name=name, w=self.p.w, h=1, x=0, y=i, underline=underline) self.transtable[name] = value i += 1 # add a way to get aboslute coordinates for this x,y = self.get_absolute_position() modal.set_target(x,y) modal.add_link(self) self.archon.window_manager.add(modal) self.archon.window_manager.give_modal_focus(modal) def get_message(self, sender, **kwargs): print kwargs self.set_value(kwargs['value']) self.render_text() self.transition('unclick') def get_value(self): return self.transtable[self.value]