def _init_tab_buttons(self): """Add enough tabbuttons for all widgets.""" def on_tab_removal(tabwidget): # called when a tab is being removed (via weakref since tabs shouldn't have references to the parent tabwidget) # If one tab is removed, the whole tabwidget will die.. # This is easy usually the desired behavior. if tabwidget(): tabwidget().on_remove() # Load buttons for index, tab in enumerate(self._tabs): # don't add a reference to the tab.add_remove_listener(Callback(on_tab_removal, weakref.ref(self))) container = Container(name="container_{}".format(index)) background = Icon(name="bg_{}".format(index)) button = ImageButton(name=str(index), size=(50, 50)) if self.current_tab is tab: background.image = tab.button_background_image_active button.path = tab.path_active else: background.image = tab.button_background_image button.path = tab.path button.capture(Callback(self.show_tab, index)) if hasattr(tab, 'helptext') and tab.helptext: button.helptext = tab.helptext container.size = (50, 52) container.addChild(background) container.addChild(button) self.content.addChild(container) self.widget.size = (54, 55 * len(self._tabs)) self.widget.adaptLayout() self._apply_layout_hack()
def refresh(self): """This function is called by the TabWidget to redraw the widget.""" self._refresh_utilisation() # remove old production line data parent_container = self.widget.child_finder('production_lines') while parent_container.children: child = parent_container.children[-1] if hasattr(child, "anim"): child.anim.stop() del child.anim parent_container.removeChild( child ) # create a container for each production # sort by production line id to have a consistent (basically arbitrary) order for production in self.get_displayed_productions(): # we need to be notified of small production changes # that aren't passed through the instance production.add_change_listener(self._schedule_refresh, no_duplicates=True) gui = load_uh_widget(self.production_line_gui_xml) # fill in values to gui reflecting the current game state container = gui.findChild(name="production_line_container") self._set_resource_amounts(container, production) if production.is_paused(): container.removeChild( container.findChild(name="toggle_active_active") ) toggle_icon = container.findChild(name="toggle_active_inactive") toggle_icon.name = "toggle_active" else: container.removeChild( container.findChild(name="toggle_active_inactive") ) toggle_icon = container.findChild(name="toggle_active_active") toggle_icon.name = "toggle_active" if production.get_state() == PRODUCTION.STATES.producing: bg = Icon(image=self.__class__.BUTTON_BACKGROUND) bg.position = toggle_icon.position container.addChild(bg) container.removeChild(toggle_icon) # fix z-ordering container.addChild(toggle_icon) anim = PychanAnimation(toggle_icon, self.__class__.ACTIVE_PRODUCTION_ANIM_DIR) container.anim = anim anim.start(1.0/12, -1) # always start anew, people won't notice self._animations.append( weakref.ref( anim ) ) # fill it with input and output resources in_res_container = container.findChild(name="input_res") self._add_resource_icons(in_res_container, production.get_consumed_resources(), marker=True) out_res_container = container.findChild(name="output_res") self._add_resource_icons(out_res_container, production.get_produced_resources()) # active toggle_active button toggle_active = ToggleActive(self.instance.get_component(Producer), production) container.mapEvents({ 'toggle_active': Callback(toggle_active.execute, self.instance.session) }) # NOTE: this command causes a refresh, so we needn't change the toggle_active-button-image container.stylize('menu_black') parent_container.addChild(container) super(ProductionOverviewTab, self).refresh()
def __init__(self, cursor_tool, **kwargs): super(CoordsTooltip, self).__init__(**kwargs) cursor_tool.session.ingame_gui.coordinates_tooltip = self self.cursor_tool = cursor_tool self.enabled = False self.icon = Icon(position=(1, 1)) # 0, 0 is currently not supported by tooltips
def _draw(self): """Draws the icon + bar.""" # hash buttons by creation function call # NOTE: there may be problems with multiple buttons with the same # images and helptext at the same time create_btn = Callback(ImageButton, path=self.path, helptext=self.helptext) self.button = None if self.uncached: self.button = create_btn() else: self.button = self.__widget_cache.get(create_btn, None) if self.button is None: # create button self.__widget_cache[create_btn] = self.button = create_btn() else: # disconnect button from earlier layout if self.button.parent: self.button.parent.removeChild(self.button) # can't cache the other instances, because we need multiple instances # with the same data active at the same time self.label = Label(text=self.text) self.label.position = self.text_position self.fill_bar = Icon(image="content/gui/images/tabwidget/green_line.png") fill_level = (self.button.height * self.filled) // 100 self.fill_bar.size = ((2 * self.fill_bar.size[0]) // 3, fill_level) # move fillbar down after resizing, since its origin is top aligned self.fill_bar.position = (self.button.width, self.button.height - fill_level) self.addChildren(self.button, self.fill_bar, self.label) if self.marker > 0: marker_icon = Icon(image="content/gui/icons/templates/production/marker.png") marker_level = (self.button.height * self.marker) // 100 marker_icon.position = (self.button.width - 1, self.button.height - marker_level) marker_icon.max_size = (5, 1) self.addChild(marker_icon)
def show_tooltip(self): if not self.helptext: return # recreate full tooltip since new text needs to be relayouted if self.gui is None: self.gui = load_uh_widget('tooltip.xml') else: self.gui.removeAllChildren() translated_tooltip = _(self.helptext) #HACK this looks better than splitting into several lines & joining # them. works because replace_whitespace in fill defaults to True: replaced = translated_tooltip.replace(r'\n', self.CHARS_PER_LINE * ' ') replaced = replaced.replace('[br]', self.CHARS_PER_LINE * ' ') tooltip = textwrap.fill(replaced, self.CHARS_PER_LINE) line_count = len(tooltip.splitlines()) - 1 top_image = Icon(image=self.TOP_IMAGE, position=(0, 0)) self.gui.addChild(top_image) top_x, top_y = top_image.position top_y += self.SIZE_BG_TOP for i in xrange(0, line_count): middle_image = Icon(image=self.MIDDLE_IMAGE) middle_image.position = (top_x, top_y + self.LINE_HEIGHT * i) self.gui.addChild(middle_image) bottom_image = Icon(image=self.BOTTOM_IMAGE) bottom_image.position = (top_x, top_y + self.LINE_HEIGHT * line_count) self.gui.addChild(bottom_image) label = Label(text=tooltip, position=(10, 5)) self.gui.addChild(label) self.gui.stylize('tooltip') size_y = self.SIZE_BG_TOP + self.LINE_HEIGHT * line_count + self.SIZE_BG_BOTTOM self.gui.size = (145, size_y) self.gui.show()
def create_resource_icon(res_id, db): """Creates a pychan Icon for a resource. Helptext is set to name of *res_id*. @param res_id: resource id @param db: dbreader for main db""" widget = Icon(image=get_res_icon_path(res_id)) widget.helptext = db.get_res_name(res_id) return widget
def _set_tile_amount(self, amount): self.__tile_amount = amount for i in xrange(self.amount): mid = Icon(image=self.tiles_img, name=self.name + str(i + 1)) self.addChild(mid) self.addChild( Icon(image=self.final_img, name=self.name + str(self.amount + 1)))
def update_queue(self, container_active): """ Update the queue display""" queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.UNIT_THUMBNAIL.format(type_id=unit_type) helptext = T("{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue + 1) # people don't count properly, always starting at 1.. icon_name = "queue_elem_" + str(place_in_queue) try: icon = Icon(name=icon_name, image=image, helptext=helptext) except fife.NotFound as e: # It's possible that this error was raised from a missing thumbnail asset, # so we check against that now and use a fallback thumbnail instead if 'content/gui/icons/thumbnails/' in e.what(): # actually load the fallback unit image image = self.__class__.UNIT_THUMBNAIL.format(type_id="unknown_unit") icon = Icon(name=icon_name, image=image, helptext=helptext) else: raise rm_from_queue_cb = Callback(RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild(icon)
def _init_tabs(self): """Add enough tabbuttons for all widgets.""" def on_tab_removal(tabwidget): # called when a tab is being removed (via weakref since tabs shouldn't have references to the parent tabwidget) # If one tab is removed, the whole tabwidget will die.. # This is easy usually the desired behavior. if tabwidget(): tabwidget().on_remove() # Load buttons for index, tab in enumerate(self._tabs): # don't add a reference to the tab.add_remove_listener(Callback(on_tab_removal, weakref.ref(self))) container = Container(name="container_%s" % index) background = Icon(name="bg_%s" % index) button = ImageButton(name=str(index), size=(50, 50)) if self.current_tab is tab: background.image = tab.button_background_image_active button.path = tab.path_active else: background.image = tab.button_background_image button.path = tab.path button.capture(Callback(self._show_tab, index)) if hasattr(tab, 'helptext') and tab.helptext is not None: button.helptext = tab.helptext container.size = background.size container.addChild(background) container.addChild(button) self.content.addChild(container) self.widget.size = (50, 55*len(self._tabs)) self.widget.adaptLayout() self._apply_layout_hack()
def update_queue(self, container_active): """ Update the queue display""" queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.UNIT_THUMBNAIL.format(type_id=unit_type) helptext = T("{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue + 1 ) # people don't count properly, always starting at 1.. icon_name = "queue_elem_" + str(place_in_queue) try: icon = Icon(name=icon_name, image=image, helptext=helptext) except RuntimeError, e: # It's possible that this error was raised from a missing thumbnail asset, # so we check against that now and use a fallback thumbnail instead # TODO string matching for runtime errors is nightmare fuel # Better: Replace RuntimeError in fife with a more precise error class if possible # and only catch that class here if e.message.startswith( "_[NotFound]_ , Something was searched, but not found :: content/gui/icons/thumbnails/" ): # actually load the fallback unit image image = self.__class__.UNIT_THUMBNAIL.format(type_id="unknown_unit") icon = Icon(name=icon_name, image=image, helptext=helptext) else: raise rm_from_queue_cb = Callback(RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild(icon)
def __init__(self): self.mainlistener = MainListener(self) self.windows = WindowManager() # temporary aliases for compatibility with rest of the code self.open_popup = self.windows.open_popup self.open_error_popup = self.windows.open_error_popup # Main menu background image setup. available_images = glob.glob('content/gui/images/background/mainmenu/bg_*.png') self.bg_images = deque(available_images) latest_bg = horizons.globals.fife.get_uh_setting("LatestBackground") try: # If we know the current background from an earlier session, # show all other available ones before picking that one again. self.bg_images.remove(latest_bg) self.bg_images.append(latest_bg) except ValueError: pass self._background = Icon(position_technique='center:center') self.rotate_background() self._background.show() # Initialize menu dialogs and widgets that are accessed from `gui`. self.singleplayermenu = SingleplayerMenu(self.windows) self.multiplayermenu = MultiplayerMenu(self, self.windows) self.help_dialog = HelpDialog(self.windows) self.loadingscreen = LoadingScreen() self.settings_dialog = SettingsDialog(self.windows) self.mainmenu = MainMenu(self, self.windows) self.fps_display = FPSDisplay()
def set_construction_mode(self, resource_source_instance, build_costs): """Show resources relevant to construction and build costs @param resource_source_instance: object with StorageComponent @param build_costs: dict, { res : amount } """ if resource_source_instance is None: # Build moved out of settlement. This is usually not sane and an interaction error. # Use this heuristically computed settlement to fix preconditions. resource_source_instance = LastActivePlayerSettlementManager().get() if self.construction_mode and \ resource_source_instance == self.current_instance() and \ build_costs == self._last_build_costs: return # now that's not an update self._last_build_costs = build_costs self.construction_mode = True self.set_inventory_instance(resource_source_instance, keep_construction_mode=True) # label background icons cost_icon_gold = "content/gui/images/background/widgets/resbar_stats_bottom.png" cost_icon_res = "content/gui/images/background/widgets/res_extra_bg.png" res_list = self._get_current_resources() # remove old one before, avoids duplicates self._drop_cost_labels() for res, amount in build_costs.iteritems(): assert res in res_list or res == RES.GOLD cost_label = Label(text=u"-"+unicode(amount)) cost_label.stylize( self.__class__.STYLE ) # add icon below end of background icon if res in res_list: entry = res_list.index(res) cur_gui = self.gui[ entry ] reference_icon = cur_gui.findChild(name="background_icon") below = reference_icon.size[1] cost_icon = Icon(image=cost_icon_res, position=(0, below)) cost_label.position = (15, below) # TODO: centering cur_gui.addChild(cost_icon) cur_gui.addChild(cost_label) cur_gui.cost_gui = [cost_label, cost_icon] cur_gui.resizeToContent() # container needs to be bigger now else: # must be gold # there is an icon with scales there, use its positioning reference_icon = self.gold_gui.child_finder("balance_background") cost_icon = Icon(image=cost_icon_gold, position=(reference_icon.x, reference_icon.y)) cost_label.position = (23, 74) # TODO: centering self.gold_gui.addChild(cost_icon) self.gold_gui.addChild(cost_label) self.gold_gui.cost_gui = [cost_label, cost_icon] self.gold_gui.resizeToContent()
def build_ship_info(self, index, ship, prodline): size = (260, 90) widget = Container(name='showcase_%s' % index, position=(0, 20 + index * 90), min_size=size, max_size=size, size=size) bg_icon = Icon(image='content/gui/images/background/square_80.png', name='bg_%s' % index) widget.addChild(bg_icon) image = 'content/gui/images/objects/ships/76/{unit_id}.png'.format( unit_id=ship) helptext = self.instance.session.db.get_ship_tooltip(ship) unit_icon = Icon(image=image, name='icon_%s' % index, position=(2, 2), helptext=helptext) widget.addChild(unit_icon) # if not buildable, this returns string with reason why to be displayed as helptext #ship_unbuildable = self.is_ship_unbuildable(ship) ship_unbuildable = False if not ship_unbuildable: button = OkButton(position=(60, 50), name='ok_%s' % index, helptext=_('Build this ship!')) button.capture(Callback(self.start_production, prodline)) else: button = CancelButton(position=(60, 50), name='ok_%s' % index, helptext=ship_unbuildable) widget.addChild(button) # Get production line info production = self.producer.create_production_line(prodline) # consumed == negative, reverse to sort in *ascending* order: costs = sorted(production.consumed_res.iteritems(), key=itemgetter(1)) for i, (res, amount) in enumerate(costs): xoffset = 103 + (i % 2) * 55 yoffset = 20 + (i // 2) * 20 icon = create_resource_icon(res, self.instance.session.db) icon.max_size = icon.min_size = icon.size = (16, 16) icon.position = (xoffset, yoffset) label = Label(name='cost_%s_%s' % (index, i)) if res == RES.GOLD: label.text = unicode(-amount) else: label.text = u'{amount:02}t'.format(amount=-amount) label.position = (22 + xoffset, yoffset) widget.addChild(icon) widget.addChild(label) return widget
def create_resource_icon(res_id, db, size=50): """Creates a pychan Icon for a resource. Helptext is set to name of *res_id*. Returns None if *size* parameter is invalid (not one of 16, 24, 32, 50). @param res_id: resource id @param db: dbreader for main db @param size: Size of icon in px. Valid: 16, 24, 32, 50.""" widget = None if size in (16, 24, 32, 50): widget = Icon(image=get_res_icon_path(res_id, size)) widget.helptext = db.get_res_name(res_id) return widget
def _set_tile_amount(self, amount): if amount == self.__tile_amount and amount > 0: # Default amount of 0 should still add top/bottom graphics once return self.__tile_amount = amount self.removeAllChildren() start_img = Icon(image=self.start_img, name=self.name + '0') self.addChild(start_img) for i in xrange(self.amount): mid = Icon(image=self.tiles_img, name=self.name + str(i+1)) self.addChild(mid) self.addChild(Icon(image=self.final_img, name=self.name + str(self.amount+1)))
def _show_modal_background(self): """ Loads transparent background that de facto prohibits access to other gui elements by eating all input events. """ height = horizons.globals.fife.engine_settings.getScreenHeight() width = horizons.globals.fife.engine_settings.getScreenWidth() image = horizons.globals.fife.imagemanager.loadBlank(width, height) image = fife.GuiImage(image) self._modal_background = Icon(image=image) self._modal_background.position = (0, 0) self._modal_background.show()
class Background: """ Display a centered background image on top of a black screen. """ def __init__(self): available_images = glob.glob( 'content/gui/images/background/mainmenu/bg_*.png') self.bg_images = deque(available_images) latest_bg = horizons.globals.fife.get_uh_setting("LatestBackground") try: # If we know the current background from an earlier session, # show all other available ones before picking that one again. self.bg_images.remove(latest_bg) self.bg_images.append(latest_bg) except ValueError: pass (res_width, res_height) = horizons.globals.fife.get_fife_setting( 'ScreenResolution').split('x') self._black_box = Container() self._black_box.size = int(res_width), int(res_height) self._black_box.base_color = (0, 0, 0, 255) self._image = Icon(position_technique='center:center') self.rotate_image() def rotate_image(self): """Select next background image to use in the game menu. Triggered by the "Change background" main menu button. """ self.bg_images.rotate(1) self._image.image = self.bg_images[0] # Save current background choice to settings. # This keeps the background image consistent between sessions. horizons.globals.fife.set_uh_setting("LatestBackground", self.bg_images[0]) horizons.globals.fife.save_settings() def show(self): self._black_box.show() self._image.show() def hide(self): self._image.hide() self._black_box.hide() @property def visible(self): return self._image.isVisible()
class CoordsTooltip: @classmethod def get_instance(cls, cursor_tool): if cursor_tool.session.ingame_gui.coordinates_tooltip is not None: inst = cursor_tool.session.ingame_gui.coordinates_tooltip inst.cursor_tool = cursor_tool return inst else: return CoordsTooltip(cursor_tool) def __init__(self, cursor_tool, **kwargs): super().__init__(**kwargs) cursor_tool.session.ingame_gui.coordinates_tooltip = self self.cursor_tool = cursor_tool self.enabled = False self.icon = Icon(position=(1, 1)) # 0, 0 is currently not supported by tooltips def toggle(self): self.enabled = not self.enabled if not self.enabled and self.icon.tooltip_shown: self.icon.hide_tooltip() def show_evt(self, evt): if self.enabled: if evt.isConsumedByWidgets(): if self.icon.tooltip_shown: self.icon.hide_tooltip() return x, y = self.cursor_tool.get_world_location(evt).to_tuple() self.icon.helptext = '{:d}, {:d} '.format(x, y) + T("Press H to remove this hint") self.icon.position_tooltip(evt) self.icon.show_tooltip()
class CoordsTooltip: @classmethod def get_instance(cls, cursor_tool): if cursor_tool.session.ingame_gui.coordinates_tooltip is not None: inst = cursor_tool.session.ingame_gui.coordinates_tooltip inst.cursor_tool = cursor_tool return inst else: return CoordsTooltip(cursor_tool) def __init__(self, cursor_tool, **kwargs): super().__init__(**kwargs) cursor_tool.session.ingame_gui.coordinates_tooltip = self self.cursor_tool = cursor_tool self.enabled = False self.icon = Icon(position=( 1, 1)) # 0, 0 is currently not supported by tooltips def toggle(self): self.enabled = not self.enabled if not self.enabled and self.icon.tooltip_shown: self.icon.hide_tooltip() def show_evt(self, evt): if self.enabled: if evt.isConsumedByWidgets(): if self.icon.tooltip_shown: self.icon.hide_tooltip() return x, y = self.cursor_tool.get_world_location(evt).to_tuple() self.icon.helptext = '{:d}, {:d} '.format( x, y) + T("Press H to remove this hint") self.icon.position_tooltip(evt) self.icon.show_tooltip()
def parse_logbook_item(self, parameter): # json.loads() returns unicode, thus convert strings and compare to unicode # Image works with str() since pychan can only use str objects as file path if parameter and parameter[0]: # allow empty Labels parameter_type = parameter[0] if isinstance(parameter, basestring): add = Label(text=unicode(parameter), wrap_text=True, min_size=(335, 0), max_size=(335, 508)) elif parameter_type == u'Label': add = Label(text=unicode(parameter[1]), wrap_text=True, min_size=(335, 0), max_size=(335, 508)) elif parameter_type == u'Image': add = Icon(image=str(parameter[1])) elif parameter_type == u'Gallery': add = HBox() for image in parameter[1]: add.addChild(Icon(image=str(image))) elif parameter_type == u'Headline': add = Label(text=unicode(parameter[1]), wrap_text=True, min_size=(335, 0), max_size=(335, 508), font='headline') elif parameter_type == u'BoldLabel': add = Label(text=unicode(parameter[1]), wrap_text=True, min_size=(335, 0), max_size=(335, 508), font='14_bold') elif parameter_type == u'Message': add = None # parameters are re-read on page reload. # duplicate_message stops messages from # being duplicated on page reload. message = parameter[1] duplicate_message = message in self._messages_to_display # message is already going to be displayed if not duplicate_message: self._messages_to_display.append( message) # the new message has not been displayed else: print '[WW] Warning: Unknown parameter type {typ} in parameter {prm}'.format( typ=parameter[0], prm=parameter) add = None return add
class Background: """ Display a centered background image on top of a black screen. """ def __init__(self): available_images = glob.glob('content/gui/images/background/mainmenu/bg_*.png') self.bg_images = deque(available_images) latest_bg = horizons.globals.fife.get_uh_setting("LatestBackground") try: # If we know the current background from an earlier session, # show all other available ones before picking that one again. self.bg_images.remove(latest_bg) self.bg_images.append(latest_bg) except ValueError: pass (res_width, res_height) = horizons.globals.fife.get_fife_setting('ScreenResolution').split('x') self._black_box = Container() self._black_box.size = int(res_width), int(res_height) self._black_box.base_color = (0, 0, 0, 255) self._image = Icon(position_technique='center:center') self.rotate_image() def rotate_image(self): """Select next background image to use in the game menu. Triggered by the "Change background" main menu button. """ self.bg_images.rotate(1) self._image.image = self.bg_images[0] # Save current background choice to settings. # This keeps the background image consistent between sessions. horizons.globals.fife.set_uh_setting("LatestBackground", self.bg_images[0]) horizons.globals.fife.save_settings() def show(self): self._black_box.show() self._image.show() def hide(self): self._image.hide() self._black_box.hide() @property def visible(self): return self._image.isVisible()
def update_queue(self, container_active): """ Update the queue display""" queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.UNIT_THUMBNAIL.format(type_id=unit_type) helptext = _("{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue + 1 ) # people don't count properly, always starting at 1.. icon_name = "queue_elem_" + str(place_in_queue) icon = Icon(name=icon_name, image=image, helptext=helptext) rm_from_queue_cb = Callback(RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild(icon)
def show_text(self, index): """Shows the text for a button. @param index: index of button""" assert isinstance(index, int) ExtScheduler().rem_call( self, self.hide_text) # stop hiding if a new text has been shown label = self.text_widget.findChild(name='text') text = self.active_messages[self.item + index].message text = text.replace(r'\n', self.CHARS_PER_LINE * ' ') text = text.replace(r'[br]', self.CHARS_PER_LINE * ' ') text = textwrap.fill(text, self.CHARS_PER_LINE) self.bg_middle = self.text_widget.findChild(name='msg_bg_middle') self.bg_middle.removeAllChildren() line_count = len(text.splitlines()) - 1 for i in xrange(line_count * self.LINE_HEIGHT // self.IMG_HEIGHT): middle_icon = Icon(image=self.BG_IMAGE_MIDDLE) self.bg_middle.addChild(middle_icon) message_container = self.text_widget.findChild(name='message') message_container.size = (300, 21 + self.IMG_HEIGHT * line_count + 21) self.bg_middle.adaptLayout() label.text = text label.adaptLayout() self.text_widget.show()
def __init__(self): self.mainlistener = MainListener(self) self.windows = WindowManager() # temporary aliases for compatibility with rest of the code self.show_popup = self.windows.show_popup self.show_error_popup = self.windows.show_error_popup # Main menu background image setup. available_images = glob.glob('content/gui/images/background/mainmenu/bg_*.png') self.bg_images = deque(available_images) latest_bg = horizons.globals.fife.get_uh_setting("LatestBackground") try: # If we know the current background from an earlier session, # show all other available ones before picking that one again. self.bg_images.remove(latest_bg) self.bg_images.append(latest_bg) except ValueError: pass self._background = Icon(position_technique='center:center') self.rotate_background() self._background.show() self.singleplayermenu = SingleplayerMenu(self.windows) self.multiplayermenu = MultiplayerMenu(self, self.windows) self.help_dialog = HelpDialog(self.windows) self.loadingscreen = LoadingScreen() self.settings_dialog = SettingsDialog(self.windows) self.mainmenu = MainMenu(self, self.windows) self.fps_display = FPSDisplay()
def update(self): self.removeAllChildren() weapons_added = False if hasattr(self.instance, 'get_weapon_storage'): storage = self.instance.get_weapon_storage() for weapon, amount in storage: weapons_added = True icon_image = get_res_icon_path(weapon, 24) icon_tooltip = self.instance.session.db.get_res_name( weapon) + ': ' + str(amount) icon = Icon(image=icon_image, helptext=icon_tooltip) self.addChild(icon) if not weapons_added: icon_image = "content/gui/icons/resources/none.png" icon = Icon(image=icon_image, helptext=_("none")) self.addChild(icon)
def get_res_icon_path(res, size=32, greyscale=False, full_path=True): """Returns path of a resource icon or placeholder path, if icon does not exist. @param res: resource id. Pass 'placeholder' to get placeholder path. @param full_path: whether to return full icon path or a stub path suitable for ImageButton path= """ icon_path = 'content/gui/icons/resources/{size}/'.format(size=size) if greyscale: icon_path = icon_path + 'greyscale/' if res == 'placeholder': icon_path = icon_path + 'placeholder.png' else: icon_path = icon_path + '{res:03d}.png'.format(res=res) try: Icon(image=icon_path).hide() except fife.NotFound: # ImageManager: image not found, use placeholder or die if res == 'placeholder': raise Exception('Image not found: {icon_path}'.format(icon_path=icon_path)) else: log = logging.getLogger('gui') log.warning('Image not found: %s', icon_path) icon_path = get_res_icon_path('placeholder', size) if full_path: return icon_path else: # remove 'content/gui/' and '.png' return icon_path[12:][:-4]
def init(self, db, inventory, ordinal=None): """ @param ordinal: {res: (min, max)} Display ordinal scale with these boundaries instead of numbers for a particular resource. Currently implemented via ImageFillStatusButton. """ # check if we must init everything anew if self.init_needed(inventory): # this inits the logic of the inventory. @see __init__(). self._inited = True self.db = db self._inventory = inventory # specific to Inventory self.ordinal = ordinal self._res_order = sorted(self._inventory.iterslots()) self.legend = Label(name="legend") self.__icon = Icon(name="legend_icon") self.__icon.image = "content/gui/icons/ship/civil_16.png" if isinstance(self._inventory, TotalStorage): self.__icon.position = (130, 53) self.legend.position = (150, 53) elif isinstance(self._inventory, PositiveSizedSlotStorage): self.__icon.position = ( 0, 248) self.legend.position = (20, 248) self.update()
def _icon(image): try: # Pychan can only use str objects as file path. # json.loads() however returns unicode. return Icon(image=str(image)) except RuntimeError: return None
def __init__(self, cursor_tool, **kwargs): super(CoordsTooltip, self).__init__(**kwargs) cursor_tool.session.coordinates_tooltip = self self.cursor_tool = cursor_tool self.enabled = False self.icon = Icon()
def _icon(image): try: # Pychan can only use str objects as file path. # json.loads() however returns unicode. return Icon(image=str(image)) except fife.NotFound: return None
def refresh(self): """ This function is called by the TabWidget to redraw the widget. """ # remove old data parent_container = self.widget.child_finder('related_buildings') while parent_container.children: parent_container.removeChild(parent_container.children[0]) # load all related buildings from DB building_ids = self.instance.session.db.get_related_building_ids_for_menu( self.instance.id) sorted_ids = sorted([(b, Entities.buildings[b].settler_level) for b in building_ids], key=lambda x: x[1]) container = self.__get_new_container() for i, (building_id, level) in enumerate(sorted_ids): if level > self.instance.owner.settler_level: break button = self._create_build_buttons(building_id, container) # check whether to start new line (currently only 4 fit per line) if i and i % 4 == 0: parent_container.addChild(container) container = self.__get_new_container() container.findChild(name="build_button_container").addChild(button) button_bg = Icon( image="content/gui/images/buttons/buildmenu_button_bg.png") container.findChild( name="build_button_bg_container").addChild(button_bg) # Still need to add last container parent_container.addChild(container) super(BuildRelatedTab, self).refresh()
def show_text(self, index): """Shows the text for a button. @param index: index of button""" assert isinstance(index, int) # stop hiding if a new text has been shown ExtScheduler().rem_call(self, self.hide_text) text = self.active_messages[index].message text = text.replace(r'\n', self.CHARS_PER_LINE * ' ') text = text.replace('[br]', self.CHARS_PER_LINE * ' ') text = textwrap.fill(text, self.CHARS_PER_LINE) self.bg_middle = self.text_widget.findChild(name='msg_bg_middle') self.bg_middle.removeAllChildren() line_count = len(text.splitlines()) - 1 for i in range(line_count * self.LINE_HEIGHT // self.IMG_HEIGHT): middle_icon = Icon(image=self.BG_IMAGE_MIDDLE) self.bg_middle.addChild(middle_icon) button = self.widget.findChild(name=str(index)) # y position relative to parent button_y = button.position[1] # Show text next to corresponding icon x, y = self.reference_text_widget_position self.text_widget.position = (x, y + button_y) message_container = self.text_widget.findChild(name='message') message_container.size = (300, 21 + self.IMG_HEIGHT * line_count + 21) self.bg_middle.adaptLayout() label = self.text_widget.findChild(name='text') label.text = text label.adaptLayout() self.text_widget.show()
def _connect_input_res(self, centered_container, container, production): """Draws incoming arrows for production line container.""" input_amount = len(production.get_consumed_resources()) if input_amount == 0: # Do not draw input arrows if there is no input return # center the production line icon_height = ImageFillStatusButton.CELL_SIZE[1] + ImageFillStatusButton.PADDING center_y = (icon_height // 2) * (input_amount - 1) centered_container.position = (0, center_y) if input_amount % 2: # Add center arrow for 1, 3, 5, ... but not 2, 4, ... mid_arrow = Icon(image=self.__class__.ARROW_MID) mid_arrow.position = (58, 17 + center_y) container.insertChild(mid_arrow, 0) for res in xrange(input_amount // 2): # --\ <= placed for res = 1 # --\| <= place connector <= placed for res = 0 # ---O--> <= placed above (mid_arrow) # --/| <= place connector <= placed for res = 0 # --/ <= placed for res = 1 offset = -17 + (icon_height // 2) * (2 * res + (input_amount % 2) + 1) top_arrow = Icon(image=self.__class__.ARROW_TOP) top_arrow.position = (58, center_y - offset) container.insertChild(top_arrow, 0) bottom_arrow = Icon(image=self.__class__.ARROW_BOTTOM) bottom_arrow.position = (58, center_y + offset) container.insertChild(bottom_arrow, 0) # Place a connector image (the | in above sketch) that vertically connects # the input resource arrows. We need those if the production line has more # than three input resources. Connectors are placed in the inner loop parts. place_connectors = (1 + 2 * res) < (input_amount // 2) if place_connectors: # the connector downwards connects top_arrows down_connector = Icon(image=self.__class__.ARROW_CONNECT_DOWN) down_connector.position = (98, center_y - offset) container.insertChild(down_connector, 0) # the connector upwards connects up_arrows up_connector = Icon(image=self.__class__.ARROW_CONNECT_UP) up_connector.position = (98, center_y + offset) container.insertChild(up_connector, 0)
def update(self): self.removeAllChildren() weapons_added = False if hasattr(self.instance, 'get_weapon_storage'): storage = self.instance.get_weapon_storage() for weapon, amount in storage: weapons_added = True icon_image = get_res_icon_path(weapon, 24) weapon_name = self.instance.session.db.get_res_name(weapon) # You usually do not need to change anything here when translating helptext = T('{weapon}: {amount}').format(weapon=weapon_name, amount=amount) icon = Icon(image=icon_image, helptext=helptext) self.addChild(icon) if not weapons_added: icon_image = "content/gui/icons/resources/none.png" icon = Icon(image=icon_image, helptext=T("none")) self.addChild(icon)
def create_resource_icon(res_id, db, size=50): """Creates a pychan Icon for a resource. Helptext is set to res name. Returns None if size parameter is invalid. @param res_id: resource id @param db: dbreader for main db @param size: Size of icon in px. Valid: 16, 24, 32, 50.""" from fife.extensions.pychan.widgets import Icon widget = None if size in (16, 24, 32, 50): icon_path = get_res_icon_path(res_id, size) try: widget = Icon(image=icon_path) except RuntimeError: # ImageManager: image not found, use placeholder print '[WW] Image not found: {icon_path}'.format(icon_path=icon_path) widget = Icon(image=get_res_icon_path('placeholder', size)) widget.helptext = db.get_res_name(res_id) return widget
def show_tooltip(self): if not self.helptext: return # recreate full tooltip since new text needs to be relayouted if self.gui is None: self.gui = load_uh_widget('tooltip.xml') else: self.gui.removeAllChildren() translated_tooltip = _(self.helptext) #HACK this looks better than splitting into several lines & joining # them. works because replace_whitespace in fill defaults to True: replaced = translated_tooltip.replace(r'\n', self.CHARS_PER_LINE*' ') replaced = replaced.replace(r'[br]', self.CHARS_PER_LINE*' ') tooltip = textwrap.fill(replaced, self.CHARS_PER_LINE) line_count = len(tooltip.splitlines()) - 1 top_image = Icon(image=self.TOP_IMAGE, position=(0, 0)) self.gui.addChild(top_image) top_x, top_y = top_image.position top_y += self.SIZE_BG_TOP for i in xrange(0, line_count): middle_image = Icon(image=self.MIDDLE_IMAGE) middle_image.position = (top_x, top_y + self.LINE_HEIGHT * i) self.gui.addChild(middle_image) bottom_image = Icon(image=self.BOTTOM_IMAGE) bottom_image.position = (top_x, top_y + self.LINE_HEIGHT * line_count) self.gui.addChild(bottom_image) label = Label(text=tooltip, position=(10, 5)) self.gui.addChild(label) self.gui.stylize('tooltip') size_y = self.SIZE_BG_TOP + self.LINE_HEIGHT * line_count + self.SIZE_BG_BOTTOM self.gui.size = (145, size_y) self.gui.show()
def init_widget(self): super(LumberjackOverviewTab, self).init_widget() container = AutoResizeContainer(position=(20, 210)) icon = Icon(name='build_all_bg') button = ImageButton(name='build_all_button') container.addChild(icon) container.addChild(button) self.widget.addChild(container) self.update_data()
def update_queue(self, container_active): """ Update the queue display""" queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.UNIT_THUMBNAIL.format(type_id=unit_type) helptext = _("{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue + 1) # people don't count properly, always starting at 1.. icon_name = "queue_elem_" + str(place_in_queue) icon = Icon(name=icon_name, image=image, helptext=helptext) rm_from_queue_cb = Callback( RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild(icon)
def init_widget(self): super().init_widget() container = ABox(position=(20, 210)) icon = Icon(name='build_all_bg') button = ImageButton(name='build_all_button') container.addChild(icon) container.addChild(button) self.widget.addChild(container) self.update_data()
def __init__(self): self.mainlistener = MainListener(self) self.windows = WindowManager() # temporary aliases for compatibility with rest of the code self.show_popup = self.windows.show_popup self.show_error_popup = self.windows.show_error_popup self._background = Icon(image=self._get_random_background(), position_technique='center:center') self._background.show() self.singleplayermenu = SingleplayerMenu(self.windows) self.multiplayermenu = MultiplayerMenu(self, self.windows) self.help_dialog = HelpDialog(self.windows) self.loadingscreen = LoadingScreen() self.settings_dialog = SettingsDialog(self.windows) self.mainmenu = MainMenu(self, self.windows) self.fps_display = FPSDisplay()
def __init__(self, renderer, layer): """ @param renderer: Renderer used to render the icons @param layer: map layer, needed to place icon """ self.layer = layer self.renderer = renderer # {instance: [list of icons]} self.icons = {} self.tooltip_instance = None # no weakref: # we need to remove the tooltip always anyway, and along with it the entry here self.tooltip_icon = Icon(position=(1, 1)) # 0, 0 is currently not supported by tooltips AddStatusIcon.subscribe(self.on_add_icon_message) HoverInstancesChanged.subscribe(self.on_hover_instances_changed) RemoveStatusIcon.subscribe(self.on_remove_icon_message) WorldObjectDeleted.subscribe(self.on_worldobject_deleted_message)
def get_unit_thumbnail(self, unit_id): """Returns path of the thumbnail icon for unit with id *unit_id*.""" template = "content/gui/icons/thumbnails/{unit_id}.png" path = template.format(unit_id=unit_id) try: Icon(image=path) except RuntimeError: self.log.warning('Missing unit thumbnail {0}'.format(path)) path = template.format(unit_id='unknown_unit') return path
def _add_player_line(player): pname = Label(name="pname_%s" % player['name']) pname.helptext = _("Click here to change your name and/or color") pname.text = player['name'] if player['name'] == NetworkInterface().get_client_name(): pname.capture(Callback( self.__show_change_player_details_popup)) pname.min_size = pname.max_size = (130, 15) pcolor = Label(name="pcolor_%s" % player['name'], text=u" ") pcolor.helptext = _("Click here to change your name and/or color") pcolor.background_color = player['color'] if player['name'] == NetworkInterface().get_client_name(): pcolor.capture( Callback(self.__show_change_player_details_popup)) pcolor.min_size = pcolor.max_size = (15, 15) pstatus = Label(name="pstatus_%s" % player['name']) pstatus.text = "\t\t\t" + player['status'] pstatus.min_size = pstatus.max_size = (120, 15) picon = Icon(name="picon_%s" % player['name']) picon.image = "content/gui/images/background/hr.png" hbox = HBox() hbox.addChild(pname) hbox.addChild(pcolor) hbox.addChild(pstatus) if NetworkInterface().get_client_name() == game.get_creator( ) and player['name'] != game.get_creator(): pkick = CancelButton(name="pkick_%s" % player['name']) pkick.helptext = _("Kick {player}").format( player=player['name']) pkick.capture(Callback(NetworkInterface().kick, player['sid'])) pkick.up_image = "content/gui/images/buttons/delete_small.png" pkick.down_image = "content/gui/images/buttons/delete_small.png" pkick.hover_image = "content/gui/images/buttons/delete_small_h.png" pkick.min_size = pkick.max_size = (20, 15) hbox.addChild(pkick) players_vbox.addChild(hbox) players_vbox.addChild(picon)
def _add_player_line(player): pname = Label(name="pname_%s" % player['name']) pname.helptext = _("Click here to change your name and/or color") pname.text = player['name'] pname.min_size = pname.max_size = (130, 15) if player['name'] == NetworkInterface().get_client_name(): pname.capture(Callback(self._show_change_player_details_popup, game)) pcolor = Label(name="pcolor_%s" % player['name'], text=u" ") pcolor.helptext = _("Click here to change your name and/or color") pcolor.background_color = player['color'] pcolor.min_size = pcolor.max_size = (15, 15) if player['name'] == NetworkInterface().get_client_name(): pcolor.capture(Callback(self._show_change_player_details_popup, game)) pstatus = Label(name="pstatus_%s" % player['name']) pstatus.text = "\t\t\t" + player['status'] pstatus.min_size = pstatus.max_size = (120, 15) picon = Icon(name="picon_%s" % player['name']) picon.image = "content/gui/images/background/hr.png" hbox = HBox() hbox.addChild(pname) hbox.addChild(pcolor) hbox.addChild(pstatus) if NetworkInterface().get_client_name() == game.creator and player['name'] != game.creator: pkick = CancelButton(name="pkick_%s" % player['name']) pkick.helptext = _("Kick {player}").format(player=player['name']) pkick.capture(Callback(NetworkInterface().kick, player['sid'])) pkick.up_image = "content/gui/images/buttons/delete_small.png" pkick.down_image = "content/gui/images/buttons/delete_small.png" pkick.hover_image = "content/gui/images/buttons/delete_small_h.png" pkick.min_size = pkick.max_size = (20, 15) hbox.addChild(pkick) players_vbox.addChild(hbox) players_vbox.addChild(picon)
class CoordsTooltip(object): @classmethod def get_instance(cls, cursor_tool): if cursor_tool.session.coordinates_tooltip is not None: inst = cursor_tool.session.coordinates_tooltip inst.cursor_tool = cursor_tool return inst else: return CoordsTooltip(cursor_tool) def __init__(self, cursor_tool, **kwargs): super(CoordsTooltip, self).__init__(**kwargs) cursor_tool.session.coordinates_tooltip = self self.cursor_tool = cursor_tool self.enabled = False self.icon = Icon() def toggle(self): self.enabled = not self.enabled if not self.enabled and self.icon.tooltip_shown: self.icon.hide_tooltip() def show_evt(self, evt): if self.enabled: x, y = self.cursor_tool.get_world_location_from_event(evt).to_tuple() self.icon.helptext = str(x) + ', ' + str(y) + " "+_("Press H to remove this hint") self.icon.position_tooltip(evt) self.icon.show_tooltip()
def __init__(self, session): self.session = session # {instance: [list of icons]} self.icons = {} # Renderer used to render the icons self.renderer = self.session.view.renderer['GenericRenderer'] self.tooltip_instance = None # no weakref: # we need to remove the tooltip always anyway, and along with it the entry here self.tooltip_icon = Icon(position=(1,1)) # 0, 0 is currently not supported by tooltips AddStatusIcon.subscribe(self.on_add_icon_message) HoverInstancesChanged.subscribe(self.on_hover_instances_changed) RemoveStatusIcon.subscribe(self.on_remove_icon_message) WorldObjectDeleted.subscribe(self.on_worldobject_deleted_message)
def __init__(self, session): self.session = session # {instance: [list of icons]} self.icons = {} # Renderer used to render the icons self.renderer = self.session.view.renderer['GenericRenderer'] self.tooltip_instance = None # no weakref: # we need to remove the tooltip always anyway, and along with it the entry here self.tooltip_icon = Icon() self.session.message_bus.subscribe_globally(AddStatusIcon, self.on_add_icon_message) self.session.message_bus.subscribe_globally(HoverInstancesChanged, self.on_hover_instances_changed) self.session.message_bus.subscribe_globally(RemoveStatusIcon, self.on_remove_icon_message) self.session.message_bus.subscribe_globally(WorldObjectDeleted, self.on_worldobject_deleted_message)
def __init__(self): available_images = glob.glob('content/gui/images/background/mainmenu/bg_*.png') self.bg_images = deque(available_images) latest_bg = horizons.globals.fife.get_uh_setting("LatestBackground") try: # If we know the current background from an earlier session, # show all other available ones before picking that one again. self.bg_images.remove(latest_bg) self.bg_images.append(latest_bg) except ValueError: pass (res_width, res_height) = horizons.globals.fife.get_fife_setting('ScreenResolution').split('x') self._black_box = Container() self._black_box.size = int(res_width), int(res_height) self._black_box.base_color = (0, 0, 0, 255) self._image = Icon(position_technique='center:center') self.rotate_image()
class Gui(object): """This class handles all the out of game menu, like the main and pause menu, etc. """ log = logging.getLogger("gui") def __init__(self): self.mainlistener = MainListener(self) self.windows = WindowManager() # temporary aliases for compatibility with rest of the code self.show_popup = self.windows.show_popup self.show_error_popup = self.windows.show_error_popup # Main menu background image setup. available_images = glob.glob('content/gui/images/background/mainmenu/bg_*.png') self.bg_images = deque(available_images) latest_bg = horizons.globals.fife.get_uh_setting("LatestBackground") try: # If we know the current background from an earlier session, # show all other available ones before picking that one again. self.bg_images.remove(latest_bg) self.bg_images.append(latest_bg) except ValueError: pass self._background = Icon(position_technique='center:center') self.rotate_background() self._background.show() self.singleplayermenu = SingleplayerMenu(self.windows) self.multiplayermenu = MultiplayerMenu(self, self.windows) self.help_dialog = HelpDialog(self.windows) self.loadingscreen = LoadingScreen() self.settings_dialog = SettingsDialog(self.windows) self.mainmenu = MainMenu(self, self.windows) self.fps_display = FPSDisplay() def show_main(self): """Shows the main menu """ GuiAction.subscribe(self._on_gui_action) if not self._background.isVisible(): self._background.show() self.windows.show(self.mainmenu) def show_select_savegame(self, mode): window = SelectSavegameDialog(mode, self.windows) return self.windows.show(window) def load_game(self): saved_game = self.show_select_savegame(mode='load') if saved_game is None: return False # user aborted dialog options = StartGameOptions(saved_game) horizons.main.start_singleplayer(options) return True def on_help(self): self.windows.toggle(self.help_dialog) def show_credits(self): """Shows the credits dialog. """ window = CreditsPickbeltWidget(self.windows) self.windows.show(window) def on_escape(self): self.windows.on_escape() def on_return(self): self.windows.on_return() def close_all(self): GuiAction.discard(self._on_gui_action) self.windows.close_all() self._background.hide() def show_loading_screen(self): if not self._background.isVisible(): self._background.show() self.windows.show(self.loadingscreen) def rotate_background(self): """Select next background image to use in the game menu. Triggered by the "Change background" main menu button. """ # Note: bg_images is a deque. self.bg_images.rotate() self._background.image = self.bg_images[0] # Save current background choice to settings. # This keeps the background image consistent between sessions. horizons.globals.fife.set_uh_setting("LatestBackground", self.bg_images[0]) horizons.globals.fife.save_settings() def _on_gui_action(self, msg): AmbientSoundComponent.play_special('click') def show_editor_start_menu(self): editor_start_menu = EditorStartMenu(self.windows) self.windows.show(editor_start_menu)
class StatusIconManager(object): """Manager class that manages all status icons. It listenes to AddStatusIcon and RemoveStatusIcon messages on the main message bus""" def __init__(self, session): self.session = session # {instance: [list of icons]} self.icons = {} # Renderer used to render the icons self.renderer = self.session.view.renderer['GenericRenderer'] self.tooltip_instance = None # no weakref: # we need to remove the tooltip always anyway, and along with it the entry here self.tooltip_icon = Icon(position=(1,1)) # 0, 0 is currently not supported by tooltips AddStatusIcon.subscribe(self.on_add_icon_message) HoverInstancesChanged.subscribe(self.on_hover_instances_changed) RemoveStatusIcon.subscribe(self.on_remove_icon_message) WorldObjectDeleted.subscribe(self.on_worldobject_deleted_message) def end(self): self.tooltip_instance = None self.tooltip_icon.hide_tooltip() self.tooltip_icon = None self.renderer = None self.icons = None self.session = None AddStatusIcon.unsubscribe(self.on_add_icon_message) HoverInstancesChanged.unsubscribe(self.on_hover_instances_changed) RemoveStatusIcon.unsubscribe(self.on_remove_icon_message) WorldObjectDeleted.unsubscribe(self.on_worldobject_deleted_message) def on_add_icon_message(self, message): """This is called by the message bus with AddStatusIcon messages""" assert isinstance(message, AddStatusIcon) icon_instance = message.icon.instance if not icon_instance in self.icons: self.icons[icon_instance] = [] assert not message.icon in self.icons[icon_instance] self.icons[icon_instance].append(message.icon) # Sort, make sure highest icon is at top self.icons[icon_instance] = sorted(self.icons[icon_instance], key=StatusIcon.get_sorting_key(), reverse=True) # Now render the most important one self.__render_status(icon_instance, self.icons[icon_instance][0]) def on_worldobject_deleted_message(self, message): assert isinstance(message, WorldObjectDeleted) # remove icon if message.worldobject in self.icons: self.renderer.removeAll(self.get_status_string(message.worldobject)) del self.icons[message.worldobject] # remove icon tooltip if message.worldobject is self.tooltip_instance: self.on_hover_instances_changed( HoverInstancesChanged(self, set()) ) def on_remove_icon_message(self, message): """Called by the MessageBus with RemoveStatusIcon messages.""" assert isinstance(message, RemoveStatusIcon) icon_instance = message.instance if icon_instance in self.icons: for registered_icon in self.icons[icon_instance][:]: if message.icon_class is registered_icon.__class__: self.icons[icon_instance].remove(registered_icon) if len(self.icons[icon_instance]) == 0: # No icon left for this building, remove it self.renderer.removeAll(self.get_status_string(icon_instance)) del self.icons[icon_instance] else: # Render next icon self.__render_status(icon_instance, self.icons[icon_instance][0]) return def __render_status(self, instance, status): status_string = self.get_status_string(instance) # Clean icons self.renderer.removeAll(status_string) # pixel-offset on screen (will be constant across zoom-levels) rel = fife.Point(0, -30) layer = self.session.view.layers[LAYERS.OBJECTS] pos = instance.position # trial and error has brought me to this (it's supposed to hit the center) loc = fife.Location(layer) loc.setExactLayerCoordinates( fife.ExactModelCoordinate( pos.origin.x + float(pos.width) / 4, pos.origin.y + float(pos.height) / 4, ) ) node = fife.RendererNode(loc, rel) try: # to load an animation anim = horizons.main.fife.animationloader.loadResource(status.icon) self.renderer.addAnimation(status_string, node, anim) except ValueError: img = horizons.main.fife.imagemanager.load(status.icon) self.renderer.addImage(status_string, node, img) def get_status_string(self, instance): """Returns render name for status icons of this instance""" status_string = "status_"+ str(id(instance)) return status_string def on_hover_instances_changed(self, msg): """Check if we need to display a tooltip""" instances = msg.instances # only those that have icons instances = (i for i in instances if i in self.icons) # and belong to the player instances = [i for i in instances if \ hasattr(i, "owner" ) and \ hasattr(i.owner, "is_local_player") and \ i.owner.is_local_player] if not instances: # hide self.tooltip_instance = None self.tooltip_icon.hide_tooltip() else: # get tooltip text, set, position and show self.tooltip_instance = instances[0] # pick any (usually ordered by fife) icons_of_instance = self.icons[self.tooltip_instance] icon = max(icons_of_instance, key=StatusIcon.get_sorting_key()) self.tooltip_icon.helptext = icon.helptext pos = self.session.cursor.last_event_pos self.tooltip_icon.position_tooltip( (pos.x, pos.y) ) self.tooltip_icon.show_tooltip()
def refresh(self): """This function is called by the TabWidget to redraw the widget.""" super(BoatbuilderTab, self).refresh() main_container = self.widget.findChild(name="BB_main_tab") container_active = main_container.findChild(name="container_active") container_inactive = main_container.findChild(name="container_inactive") progress_container = main_container.findChild(name="BB_progress_container") cancel_container = main_container.findChild(name="BB_cancel_container") needed_res_container = self.widget.findChild(name="BB_needed_resources_container") # a boatbuilder is considered active here if it build sth, no matter if it's paused production_lines = self.producer.get_production_lines() if production_lines: cancel_container.parent.showChild(cancel_container) # Set progress progress_container.parent.showChild(progress_container) progress = math.floor(self.producer.get_production_progress() * 100) self.widget.findChild(name='progress').progress = progress progress_perc = self.widget.findChild(name='BB_progress_perc') progress_perc.text = u'{progress}%'.format(progress=progress) container_active.parent.showChild(container_active) if not container_inactive in container_inactive.parent.hidden_children: container_inactive.parent.hideChild(container_inactive) # Update boatbuilder queue queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.SHIP_THUMBNAIL.format(type_id=unit_type) helptext = _(u"{ship} (place in queue: {place})") #xgettext:python-format helptext.format(ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue+1) # people don't count properly, always starting at 1.. icon_name = "queue_elem_"+str(place_in_queue) icon = Icon(name=icon_name, image=image, helptext=helptext) rm_from_queue_cb = Callback(RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild( icon ) # Set built ship info production_line = self.producer._get_production(production_lines[0]) produced_unit_id = production_line.get_produced_units().keys()[0] name = self.instance.session.db.get_unit_type_name(produced_unit_id) container_active.findChild(name="headline_BB_builtship_label").text = _(name) ship_icon = container_active.findChild(name="BB_cur_ship_icon") ship_icon.helptext = self.instance.session.db.get_ship_tooltip(produced_unit_id) ship_icon.image = self.__class__.SHIP_PREVIEW_IMG.format(type_id=produced_unit_id) button_active = container_active.findChild(name="toggle_active_active") button_inactive = container_active.findChild(name="toggle_active_inactive") to_active = not self.producer.is_active() if not to_active: # swap what we want to show and hide button_active, button_inactive = button_inactive, button_active if not button_active in button_active.parent.hidden_children: button_active.parent.hideChild(button_active) button_inactive.parent.showChild(button_inactive) set_active_cb = Callback(self.producer.set_active, active=to_active) button_inactive.capture(set_active_cb, event_name="mouseClicked") upgrades_box = container_active.findChild(name="BB_upgrades_box") upgrades_box.removeAllChildren() # upgrades_box.addChild(Label(text=u"+ love")) # upgrades_box.addChild(Label(text=u"+ affection")) # no upgrades in 2010.1 release ---^ upgrades_box.stylize('menu_black') # Update needed resources production = self.producer.get_productions()[0] needed_res = production.get_consumed_resources() # Now sort! -amount is the positive value, drop unnecessary res (amount 0) needed_res = dict((res, -amount) for res, amount in needed_res.iteritems() if amount < 0) needed_res = sorted(needed_res.iteritems(), key=itemgetter(1), reverse=True) needed_res_container.removeAllChildren() for i, (res, amount) in enumerate(needed_res): icon = create_resource_icon(res, self.instance.session.db) icon.max_size = icon.min_size = icon.size = (16, 16) label = Label(name="needed_res_lbl_%s" % i) label.text = u'{amount}t'.format(amount=amount) new_hbox = HBox(name="needed_res_box_%s" % i) new_hbox.addChildren(icon, label) needed_res_container.addChild(new_hbox) cancel_button = self.widget.findChild(name="BB_cancel_button") cancel_cb = Callback(CancelCurrentProduction(self.producer).execute, self.instance.session) cancel_button.capture(cancel_cb, event_name="mouseClicked") else: # display sth when nothing is produced container_inactive.parent.showChild(container_inactive) for w in (container_active, progress_container, cancel_container): if not w in w.parent.hidden_children: w.parent.hideChild(w) self.widget.adaptLayout()
class Window(object): def __init__(self, windows=None): # Reference to the window manager. Use it to show new windows or close # this window. self._windows = windows self._modal_background = None def show(self, **kwargs): """Show the window. After this call, the window should be visible. If you decide to not show the window here (e.g. an error occurred), you'll need to call `self._windows.close()` to remove the window from the manager. """ raise NotImplementedError def hide(self): """Hide the window. After this call, the window should not be visible anymore. However, it remains in the stack of open windows and will be visible once it becomes the topmost window again. You should *never* call this directly in your code, other than in `close()` when you overwrote it in your subclass. """ raise NotImplementedError def close(self): """Closes the window. You should *never* call this directly in your code. Use `self._windows.close()` to ask the WindowManager to remove the window instead. """ self.hide() def on_escape(self): """Define what happens when ESC is pressed. By default, the window will be closed. """ self._windows.close() def on_return(self): """Define what happens when RETURN is pressed.""" pass def _show_modal_background(self): """ Loads transparent background that de facto prohibits access to other gui elements by eating all input events. """ height = horizons.globals.fife.engine_settings.getScreenHeight() width = horizons.globals.fife.engine_settings.getScreenWidth() image = horizons.globals.fife.imagemanager.loadBlank(width, height) image = fife.GuiImage(image) self._modal_background = Icon(image=image) self._modal_background.position = (0, 0) self._modal_background.show() def _hide_modal_background(self): self._modal_background.hide()
class Gui(object): """This class handles all the out of game menu, like the main and pause menu, etc. """ log = logging.getLogger("gui") def __init__(self): self.mainlistener = MainListener(self) self.windows = WindowManager() # temporary aliases for compatibility with rest of the code self.show_popup = self.windows.show_popup self.show_error_popup = self.windows.show_error_popup self._background = Icon(image=self._get_random_background(), position_technique='center:center') self._background.show() self.subscribe() self.singleplayermenu = SingleplayerMenu(self.windows) self.multiplayermenu = MultiplayerMenu(self, self.windows) self.help_dialog = HelpDialog(self.windows) self.loadingscreen = LoadingScreen() self.settings_dialog = SettingsDialog(self.windows) self.mainmenu = MainMenu(self, self.windows) self.fps_display = FPSDisplay() def subscribe(self): """Subscribe to the necessary messages.""" GuiAction.subscribe(self._on_gui_action) def unsubscribe(self): GuiAction.unsubscribe(self._on_gui_action) def show_main(self): """Shows the main menu """ if not self._background.isVisible(): self._background.show() self.windows.show(self.mainmenu) def show_select_savegame(self, mode): window = SelectSavegameDialog(mode, self.windows) return self.windows.show(window) def load_game(self): saved_game = self.show_select_savegame(mode='load') if saved_game is None: return False # user aborted dialog options = StartGameOptions(saved_game) horizons.main.start_singleplayer(options) return True def on_help(self): self.windows.toggle(self.help_dialog) def show_credits(self): """Shows the credits dialog. """ window = CreditsPickbeltWidget(self.windows) self.windows.show(window) def on_escape(self): self.windows.on_escape() def close_all(self): self.windows.close_all() self._background.hide() def show_loading_screen(self): if not self._background.isVisible(): self._background.show() self.windows.show(self.loadingscreen) def randomize_background(self): """Randomly select a background image to use. This function is triggered by change background button from main menu.""" self._background.image = self._get_random_background() def _get_random_background(self): """Randomly select a background image to use through out the game menu.""" available_images = glob.glob('content/gui/images/background/mainmenu/bg_*.png') #get latest background latest_background = horizons.globals.fife.get_uh_setting("LatestBackground") #if there is a latest background then remove it from available list if latest_background is not None: available_images.remove(latest_background) background_choice = random.choice(available_images) #save current background choice horizons.globals.fife.set_uh_setting("LatestBackground", background_choice) horizons.globals.fife.save_settings() return background_choice def _on_gui_action(self, msg): AmbientSoundComponent.play_special('click') def show_editor_start_menu(self): editor_start_menu = EditorStartMenu(self.windows) self.windows.show(editor_start_menu)
def refresh(self): """This function is called by the TabWidget to redraw the widget.""" super(BoatbuilderTab, self).refresh() main_container = self.widget.findChild(name="BB_main_tab") container_active = main_container.findChild(name="container_active") container_inactive = main_container.findChild(name="container_inactive") progress_container = main_container.findChild(name="BB_progress_container") cancel_container = main_container.findChild(name="BB_cancel_container") needed_res_container = self.widget.findChild(name="BB_needed_resources_container") # a boatbuilder is considered active here if it build sth, no matter if it's paused production_lines = self.producer.get_production_lines() if production_lines: if cancel_container is None: main_container.addChild(main_container.cancel_container) cancel_container = main_container.cancel_container if needed_res_container is None: main_container.insertChildBefore(main_container.needed_res_container, cancel_container) needed_res_container = main_container.needed_res_container # Set progress if progress_container is None: main_container.insertChildBefore( main_container.progress_container, self.widget.findChild(name="BB_needed_resources_container")) progress_container = main_container.progress_container progress = math.floor(self.producer.get_production_progress() * 100) self.widget.findChild(name='progress').progress = progress self.widget.findChild(name='BB_progress_perc').text = u'{progress}%'.format(progress=progress) # remove other container, but save it if container_inactive is not None: main_container.container_inactive = container_inactive main_container.removeChild( container_inactive ) if container_active is None: main_container.insertChildBefore( main_container.container_active, progress_container) container_active = main_container.container_active # Update boatbuilder queue queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.SHIP_THUMBNAIL.format(type_id=unit_type) #xgettext:python-format helptext = _(u"{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue+1 ) # people don't count properly, always starting at 1.. icon_name = "queue_elem_"+str(place_in_queue) icon = Icon(name=icon_name, image=image, helptext=helptext) icon.capture( Callback(RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session), event_name="mouseClicked" ) queue_container.addChild( icon ) # Set built ship info produced_unit_id = self.producer._get_production(production_lines[0]).get_produced_units().keys()[0] produced_unit_id = self.producer._get_production(production_lines[0]).get_produced_units().keys()[0] (name,) = self.instance.session.db.cached_query("SELECT name FROM unit WHERE id = ?", produced_unit_id)[0] container_active.findChild(name="headline_BB_builtship_label").text = _(name) container_active.findChild(name="BB_cur_ship_icon").helptext = "Storage: 4 slots, 120t \nHealth: 100" container_active.findChild(name="BB_cur_ship_icon").image = "content/gui/images/objects/ships/116/%s.png" % (produced_unit_id) button_active = container_active.findChild(name="toggle_active_active") button_inactive = container_active.findChild(name="toggle_active_inactive") if not self.producer.is_active(): # if production is paused # remove active button, if it's there, and save a reference to it if button_active is not None: container_active.button_active = button_active container_active.removeChild( button_active ) # restore inactive button, if it isn't in the gui if button_inactive is None: # insert at the end container_active.insertChild(container_active.button_inactive, \ len(container_active.children)) container_active.mapEvents({ 'toggle_active_inactive' : Callback(self.producer.set_active, active=True) }) # TODO: make this button do sth else: # remove inactive button, if it's there, and save a reference to it if button_inactive is not None: container_active.button_inactive = button_inactive container_active.removeChild( button_inactive ) # restore active button, if it isn't in the gui if button_active is None: # insert at the end container_active.insertChild(container_active.button_active, \ len(container_active.children)) container_active.mapEvents({ 'toggle_active_active' : Callback(self.producer.set_active, active=False) }) upgrades_box = container_active.findChild(name="BB_upgrades_box") for child in upgrades_box.children[:]: upgrades_box.removeChild(child) # upgrades_box.addChild( pychan.widgets.Label(text=u"+ love") ) # upgrades_box.addChild( pychan.widgets.Label(text=u"+ affection") ) # no upgrades in 2010.1 release ---^ upgrades_box.stylize('menu_black') # Update needed resources production = self.producer.get_productions()[0] still_needed_res = production.get_consumed_resources() # Now sort! still_needed_res = sorted(still_needed_res.iteritems(), key=operator.itemgetter(1)) main_container.findChild(name="BB_needed_res_label").text = _('Resources still needed:') i = 0 for res, amount in still_needed_res: if amount == 0: continue # Don't show res that are not really needed anymore assert i <= 3, "Only 3 still needed res for ships are currently supported" icon_path = get_res_icon_path(res, 16) needed_res_container.findChild(name="BB_needed_res_icon_"+str(i+1)).image = icon_path needed_res_container.findChild(name="BB_needed_res_lbl_"+str(i+1)).text = unicode(-1*amount)+u't' # -1 makes them positive i += 1 if i >= 3: break for j in xrange(i, 3): # these are not filled by a resource, so we need to make it invisible needed_res_container.findChild(name="BB_needed_res_icon_"+str(j+1)).image = None needed_res_container.findChild(name="BB_needed_res_lbl_"+str(j+1)).text = u"" cancel_button = self.widget.findChild(name="BB_cancel_button") cancel_button.capture( Callback(CancelCurrentProduction(self.producer).execute, self.instance.session), event_name="mouseClicked" ) else: # display sth when nothing is produced # remove other container, but save it if container_active is not None: main_container.container_active = container_active main_container.removeChild( container_active ) if container_inactive is None: main_container.insertChildBefore( main_container.container_inactive, progress_container) container_inactive = main_container.container_inactive if progress_container is not None: main_container.progress_container = progress_container main_container.removeChild(progress_container) if needed_res_container is not None: main_container.needed_res_container = needed_res_container main_container.removeChild(needed_res_container) if cancel_container is not None: main_container.cancel_container = cancel_container main_container.removeChild(cancel_container) self.widget.adaptLayout()