class Popup(Container): """ Popup Menu class """ def __init__(self, items, util, bounding_box, update_parent, callback, default_selection=None): """ Initializer :param items: list of item names :param util: utility object :param bounding_box: bounding box :param update_parent: redraw parent function :param callback: menu selection callback """ Container.__init__(self, util, bounding_box, (0, 0, 0)) self.util = util self.factory = Factory(util) self.config = util.config self.update_parent = update_parent self.callback = callback self.popup = True c = Component(self.util) w = self.config[SCREEN_INFO][WIDTH] h = self.config[SCREEN_INFO][HEIGHT] c.content = pygame.Rect(0, 0, w, h) c.content_x = 0 c.content_y = 0 c.bounding_box = c.content c.bgr = (0, 0, 0, 0) c.name = "popup.overlay.bgr" c.handle_event = self.handle_outside_event self.add_component(c) c = Component(self.util) c.content = pygame.Rect(bounding_box.x, bounding_box.y, bounding_box.w, bounding_box.h - 1) c.content_x = 0 c.content_y = 0 c.bounding_box = c.content c.bgr = self.config[COLORS][COLOR_BRIGHT] c.name = "popup.bgr" self.add_component(c) self.cols = 1 self.rows = len(items) m = self.create_popup_menu_button b = pygame.Rect(bounding_box.x, bounding_box.y, bounding_box.w, bounding_box.h - 2) self.menu = Menu(util, None, b, self.rows, self.cols, create_item_method=m) layout = GridLayout(self.menu.bb) layout.set_pixel_constraints(self.rows, self.cols, 1, 1) bounding_box = layout.get_next_constraints() self.modes = self.util.load_menu(items, NAME, [], V_ALIGN_TOP, bb=bounding_box, scale=IMAGE_SCALE) if not default_selection: selection = self.modes[items[0]] else: selection = self.modes[default_selection] self.menu.set_items(self.modes, 0, self.select_item, False) self.menu.visible = False self.menu.item_selected(selection) self.add_component(self.menu) self.redraw_observer = None self.clicked = False self.visible = False def create_popup_menu_button(self, s, constr, action, scale, font_size=0): """ Create Popup Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :return: home menu button """ return self.factory.create_menu_button(s, constr, action, scale=True, show_label=False, ignore_bgr_opacity=True) def handle_outside_event(self, event): """ Handle popup event :param event: the event to handle """ if not self.visible: return mouse_events = [pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN] if event.type in mouse_events and event.button == 1 and not self.menu.bb.collidepoint( event.pos): if event.type == pygame.MOUSEBUTTONDOWN: self.clicked = True elif event.type == pygame.MOUSEBUTTONUP and self.clicked: self.clicked = False self.set_visible(False) self.update_parent() if self.redraw_observer: self.redraw_observer() elif event.type == USER_EVENT_TYPE: valid_keys = [ pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT ] if event.sub_type == SUB_TYPE_KEYBOARD and event.keyboard_key not in valid_keys and event.action == pygame.KEYUP: self.set_visible(False) self.update_parent() def select_item(self, state): """ Select menu item :param state: button state """ self.set_visible(False) self.update_parent() self.callback(state) def update_popup(self, state): if not self.visible: return self.clean_draw_update() def add_menu_observers(self, update_observer, redraw_observer): """ Add menu observer :param update_observer: observer for updating menu :param redraw_observer: observer to redraw the whole screen """ for b in self.menu.buttons.values(): b.add_press_listener(update_observer) b.add_release_listener(redraw_observer) self.menu.add_move_listener(redraw_observer) self.menu.add_listener(redraw_observer) self.redraw_observer = redraw_observer