from math import ceil from renderable_sprite import UISpriteRenderable from ui_button import TEXT_CENTER, UIButton from ui_colors import UIColors from ui_element import UIElement from ui_game_menu_pulldown_item import ( GameMenuData, GameObjectMenuData, GameRoomMenuData, GameStateMenuData, GameViewMenuData, GameWorldMenuData, ) from ui_info_dialog import AboutDialog from ui_menu_pulldown_item import ( ArtMenuData, CharColorMenuData, EditMenuData, FileMenuData, FrameMenuData, HelpMenuData, LayerMenuData, ToolMenuData, ViewMenuData, ) class MenuButton(UIButton): caption = "Base Class Menu Button" caption_justify = TEXT_CENTER # menu data is just a class w/ little more than a list of items, partly # so we don't have to list all the items here in a different module menu_data = None # styling normal_bg_color = UIColors.white hovered_bg_color = UIColors.lightgrey dimmed_bg_color = UIColors.lightgrey def __init__(self, element): UIButton.__init__(self, element) self.callback = self.open_pulldown def open_pulldown(self): # don't open menus if a dialog is up if self.element.ui.active_dialog: return # if clicking the same button twice, close it if self.element.active_menu_name == self.name: self.element.close_active_menu() return # close any existing menu before opening new one if self.element.active_menu_name: self.element.close_active_menu() # tell pulldown what's opening it, it can populate its items based on # our data self.pulldown.open_at(self) self.element.active_menu_name = self.name # set button state to be dimmed until menu is closed self.dimmed = True # playscii logo button = normal UIButton, opens About screen directly class PlaysciiMenuButton(UIButton): name = "playscii" caption = " " caption_justify = TEXT_CENTER width = len(caption) + 2 normal_bg_color = MenuButton.normal_bg_color hovered_bg_color = MenuButton.hovered_bg_color dimmed_bg_color = MenuButton.dimmed_bg_color # # art mode menu buttons # class FileMenuButton(MenuButton): name = "file" caption = "File" menu_data = FileMenuData class EditMenuButton(MenuButton): name = "edit" caption = "Edit" menu_data = EditMenuData class ToolMenuButton(MenuButton): name = "tool" caption = "Tool" menu_data = ToolMenuData class ViewMenuButton(MenuButton): name = "view" caption = "View" menu_data = ViewMenuData class ArtMenuButton(MenuButton): name = "art" caption = "Art" menu_data = ArtMenuData class FrameMenuButton(MenuButton): name = "frame" caption = "Frame" menu_data = FrameMenuData class LayerMenuButton(MenuButton): name = "layer" caption = "Layer" menu_data = LayerMenuData class CharColorMenuButton(MenuButton): name = "char_color" caption = "Char/Color" menu_data = CharColorMenuData # (appears in both art and game mode menus) class HelpMenuButton(MenuButton): name = "help" caption = "Help" menu_data = HelpMenuData # # game mode menu buttons # class GameMenuButton(MenuButton): name = "game" caption = "Game" menu_data = GameMenuData class StateMenuButton(MenuButton): name = "state" caption = "State" menu_data = GameStateMenuData class GameViewMenuButton(MenuButton): name = "view" caption = "View" menu_data = GameViewMenuData class WorldMenuButton(MenuButton): name = "world" caption = "World" menu_data = GameWorldMenuData class RoomMenuButton(MenuButton): name = "room" caption = "Room" menu_data = GameRoomMenuData class ObjectMenuButton(MenuButton): name = "object" caption = "Object" menu_data = GameObjectMenuData class ModeMenuButton(UIButton): caption_justify = TEXT_CENTER normal_bg_color = UIColors.black normal_fg_color = UIColors.white # hovered_bg_color = UIColors.lightgrey # dimmed_bg_color = UIColors.lightgrey class ArtModeMenuButton(ModeMenuButton): caption = "Game Mode" width = len(caption) + 2 class GameModeMenuButton(ModeMenuButton): caption = "Art Mode" width = len(caption) + 2 class MenuBar(UIElement): "main menu bar element, has lots of buttons which control the pulldown" snap_top = True snap_left = True always_consume_input = True # buttons set in subclasses button_classes = [] # button to toggle between art and game mode mode_button_class = None # empty tiles between each button button_padding = 1 def __init__(self, ui): # bitmap icon for about menu button self.playscii_sprite = UISpriteRenderable(ui.app) self.mode_button = None UIElement.__init__(self, ui) self.active_menu_name = None # list of menu buttons that can be navigated etc self.menu_buttons = [] x = PlaysciiMenuButton.width + self.button_padding for button_class in self.button_classes: button = button_class(self) button.width = len(button.caption) + 2 button.x = x x += button.width + self.button_padding setattr(self, "{}_button".format(button.name), button) # NOTE: callback already defined in MenuButton class, # menu data for pulldown with set in MenuButton subclass button.pulldown = self.ui.pulldown self.menu_buttons.append(button) playscii_button = PlaysciiMenuButton(self) playscii_button.callback = self.open_about # implement Playscii logo menu as a normal UIButton that opens # the About screen directly self.menu_buttons.append(playscii_button) self.reset_icon() # copy from menu buttons, any buttons past this point are not menus self.buttons = self.menu_buttons[:] # toggle mode button at far right if not self.mode_button_class: return self.mode_button = self.mode_button_class(self) self.mode_button.x = ( int(self.ui.width_tiles * self.ui.scale) - self.mode_button.width ) self.mode_button.callback = self.toggle_game_mode self.buttons.append(self.mode_button) def reset_icon(self): inv_aspect = self.ui.app.window_height / self.ui.app.window_width self.playscii_sprite.scale_x = self.art.quad_height * inv_aspect self.playscii_sprite.scale_y = self.art.quad_height self.playscii_sprite.x = -1 + self.art.quad_width self.playscii_sprite.y = 1 - self.art.quad_height def open_about(self): if self.ui.active_dialog: return self.ui.open_dialog(AboutDialog) def toggle_game_mode(self): if self.ui.active_dialog: return if not self.ui.app.game_mode: self.ui.app.enter_game_mode() else: self.ui.app.exit_game_mode() self.ui.app.update_window_title() def close_active_menu(self): # un-dim active menu button for button in self.menu_buttons: if button.name == self.active_menu_name: button.dimmed = False button.set_state("normal") self.active_menu_name = None self.ui.pulldown.visible = False self.ui.keyboard_focus_element = None self.ui.refocus_keyboard() def refresh_active_menu(self): if not self.ui.pulldown.visible: return for button in self.menu_buttons: if button.name == self.active_menu_name: # don't reset keyboard nav index self.ui.pulldown.open_at(button, False) def open_menu_by_name(self, menu_name): if not self.ui.app.can_edit: return for button in self.menu_buttons: if button.name == menu_name: button.callback() def open_menu_by_index(self, index): if index > len(self.menu_buttons) - 1: return # don't navigate to the about menu # (does this mean it's not accessible via kb-only? probably, that's fine) if self.menu_buttons[index].name == "playscii": return self.menu_buttons[index].callback() def get_menu_index(self, menu_name): for i, button in enumerate(self.menu_buttons): if button.name == self.active_menu_name: return i def next_menu(self): i = self.get_menu_index(self.active_menu_name) self.open_menu_by_index(i + 1) def previous_menu(self): i = self.get_menu_index(self.active_menu_name) self.open_menu_by_index(i - 1) def reset_art(self): self.tile_width = ceil(self.ui.width_tiles * self.ui.scale) # must resize here, as window width will vary self.art.resize(self.tile_width, self.tile_height) # repaint bar contents bg = self.ui.colors.white fg = self.ui.colors.black self.art.clear_frame_layer(0, 0, bg, fg) # reposition right-justified mode switch button if self.mode_button: self.mode_button.x = ( int(self.ui.width_tiles * self.ui.scale) - self.mode_button.width ) # draw buttons, etc UIElement.reset_art(self) self.reset_icon() def render(self): UIElement.render(self) self.playscii_sprite.render() def destroy(self): UIElement.destroy(self) self.playscii_sprite.destroy() class ArtMenuBar(MenuBar): button_classes = [ FileMenuButton, EditMenuButton, ToolMenuButton, ViewMenuButton, ArtMenuButton, FrameMenuButton, LayerMenuButton, CharColorMenuButton, HelpMenuButton, ] mode_button_class = GameModeMenuButton class GameMenuBar(MenuBar): button_classes = [ GameMenuButton, StateMenuButton, GameViewMenuButton, WorldMenuButton, RoomMenuButton, ObjectMenuButton, HelpMenuButton, ] game_mode_visible = True mode_button_class = ArtModeMenuButton