Example #1
0
class IngameGui(LivingObject):
	"""Class handling all the ingame gui events.
	Assumes that only 1 instance is used (class variables)"""

	gui = livingProperty()
	tabwidgets = livingProperty()
	message_widget = livingProperty()
	minimap = livingProperty()

	styles = {
		'city_info' : 'resource_bar',
		'change_name' : 'book',
		'save_map' : 'book',
		'chat' : 'book',
	}

	def __init__(self, session, gui):
		super(IngameGui, self).__init__()
		self.session = session
		assert isinstance(self.session, horizons.session.Session)
		self.main_gui = gui
		self.main_widget = None
		self.tabwidgets = {}
		self.settlement = None
		self.resource_source = None
		self.resources_needed, self.resources_usable = {}, {}
		self._old_menu = None

		self.widgets = LazyWidgetsDict(self.styles, center_widgets=False)

		self.cityinfo = self.widgets['city_info']
		self.cityinfo.child_finder = PychanChildFinder(self.cityinfo)

		self.logbook = LogBook(self.session)
		self.message_widget = MessageWidget(self.session)
		self.players_overview = PlayersOverview(self.session)
		self.players_settlements = PlayersSettlements(self.session)
		self.players_ships = PlayersShips(self.session)

		# self.widgets['minimap'] is the guichan gui around the actual minimap,
		# which is saved in self.minimap
		minimap = self.widgets['minimap']
		minimap.position_technique = "right+0:top+0"

		icon = minimap.findChild(name="minimap")
		self.minimap = Minimap(icon,
		                       targetrenderer=horizons.globals.fife.targetrenderer,
		                       imagemanager=horizons.globals.fife.imagemanager,
		                       session=self.session,
		                       view=self.session.view)

		def speed_up():
			SpeedUpCommand().execute(self.session)

		def speed_down():
			SpeedDownCommand().execute(self.session)

		minimap.mapEvents({
			'zoomIn' : self.session.view.zoom_in,
			'zoomOut' : self.session.view.zoom_out,
			'rotateRight' : Callback.ChainedCallbacks(self.session.view.rotate_right, self.minimap.rotate_right),
			'rotateLeft' : Callback.ChainedCallbacks(self.session.view.rotate_left, self.minimap.rotate_left),
			'speedUp' : speed_up,
			'speedDown' : speed_down,
			'destroy_tool' : self.session.toggle_destroy_tool,
			'build' : self.show_build_menu,
			'diplomacyButton' : self.show_diplomacy_menu,
			'gameMenuButton' : self.main_gui.toggle_pause,
			'logbook' : self.logbook.toggle_visibility
		})
		minimap.show()
		#minimap.position_technique = "right+15:top+153"

		self.widgets['tooltip'].hide()

		self.resource_overview = ResourceOverviewBar(self.session)
		ResourceBarResize.subscribe(self._on_resourcebar_resize)

		# Register for messages
		SettlerUpdate.subscribe(self._on_settler_level_change)
		SettlerInhabitantsChanged.subscribe(self._on_settler_inhabitant_change)
		HoverSettlementChanged.subscribe(self._cityinfo_set)

	def _on_resourcebar_resize(self, message):
		self._update_cityinfo_position()

	def end(self):
		self.widgets['minimap'].mapEvents({
			'zoomIn' : None,
			'zoomOut' : None,
			'rotateRight' : None,
			'rotateLeft': None,

			'destroy_tool' : None,
			'build' : None,
			'diplomacyButton' : None,
			'gameMenuButton' : None
		})

		for w in self.widgets.itervalues():
			if w.parent is None:
				w.hide()
		self.message_widget = None
		self.tabwidgets = None
		self.minimap = None
		self.resource_overview.end()
		self.resource_overview = None
		self.hide_menu()
		SettlerUpdate.unsubscribe(self._on_settler_level_change)
		ResourceBarResize.unsubscribe(self._on_resourcebar_resize)
		HoverSettlementChanged.unsubscribe(self._cityinfo_set)
		SettlerInhabitantsChanged.unsubscribe(self._on_settler_inhabitant_change)

		super(IngameGui, self).end()

	def _cityinfo_set(self, message):
		"""Sets the city name at top center of screen.

		Show/Hide is handled automatically
		To hide cityname, set name to ''
		@param message: HoverSettlementChanged message
		"""
		settlement = message.settlement
		old_was_player_settlement = False
		if self.settlement is not None:
			self.settlement.remove_change_listener(self.update_settlement)
			old_was_player_settlement = self.settlement.owner.is_local_player

		# save reference to new "current" settlement in self.settlement
		self.settlement = settlement

		if settlement is None: # we want to hide the widget now (but perhaps delayed).
			if old_was_player_settlement:
				# After scrolling away from settlement, leave name on screen for some
				# seconds. Players can still click on it to rename the settlement now.
				ExtScheduler().add_new_object(self.cityinfo.hide, self,
				      run_in=GUI.CITYINFO_UPDATE_DELAY)
				#TODO 'click to rename' tooltip of cityinfo can stay visible in
				# certain cases if cityinfo gets hidden in tooltip delay buffer.
			else:
				# hovered settlement of other player, simply hide the widget
				self.cityinfo.hide()

		else:# do not hide if settlement is hovered and a hide was previously scheduled
			ExtScheduler().rem_call(self, self.cityinfo.hide)

			self.update_settlement() # calls show()
			settlement.add_change_listener(self.update_settlement)

	def _on_settler_inhabitant_change(self, message):
		assert isinstance(message, SettlerInhabitantsChanged)
		foundlabel = self.cityinfo.child_finder('city_inhabitants')
		old_amount = int(foundlabel.text) if foundlabel.text else 0
		foundlabel.text = u' {amount:>4d}'.format(amount=old_amount+message.change)
		foundlabel.resizeToContent()

	def update_settlement(self):
		city_name_label = self.cityinfo.child_finder('city_name')
		if self.settlement.owner.is_local_player: # allow name changes
			# Update settlement on the resource overview to make sure it
			# is setup correctly for the coming calculations
			self.resource_overview.set_inventory_instance(self.settlement)
			cb = Callback(self.show_change_name_dialog, self.settlement)
			helptext = _("Click to change the name of your settlement")
			city_name_label.enable_cursor_change_on_hover()
		else: # no name changes
			cb = lambda : AmbientSoundComponent.play_special('error')
			helptext = u""
			city_name_label.disable_cursor_change_on_hover()
		self.cityinfo.mapEvents({
			'city_name': cb
		})
		city_name_label.helptext = helptext

		foundlabel = self.cityinfo.child_finder('owner_emblem')
		foundlabel.image = 'content/gui/images/tabwidget/emblems/emblem_%s.png' % (self.settlement.owner.color.name)
		foundlabel.helptext = self.settlement.owner.name

		foundlabel = self.cityinfo.child_finder('city_name')
		foundlabel.text = self.settlement.get_component(SettlementNameComponent).name
		foundlabel.resizeToContent()

		foundlabel = self.cityinfo.child_finder('city_inhabitants')
		foundlabel.text = u' {amount:>4d}'.format(amount=self.settlement.inhabitants)
		foundlabel.resizeToContent()

		self._update_cityinfo_position()

	def _update_cityinfo_position(self):
		""" Places cityinfo widget depending on resource bar dimensions.

		For a normal-sized resource bar and reasonably large resolution:
		* determine resource bar length (includes gold)
		* determine empty horizontal space between resbar end and minimap start
		* display cityinfo centered in that area if it is sufficiently large

		If too close to the minimap (cityinfo larger than length of this empty space)
		move cityinfo centered to very upper screen edge. Looks bad, works usually.
		In this case, the resbar is redrawn to put the cityinfo "behind" it visually.
		"""
		width = horizons.globals.fife.engine_settings.getScreenWidth()
		resbar = self.resource_overview.get_size()
		is_foreign = (self.settlement.owner != self.session.world.player)
		blocked = self.cityinfo.size[0] + int(1.5*self.minimap.get_size()[1])
		# minimap[1] returns width! Use 1.5*width because of the GUI around it

		if is_foreign: # other player, no resbar exists
			self.cityinfo.pos = ('center', 'top')
			xoff = 0
			yoff = 19
		elif blocked < width < resbar[0] + blocked: # large resbar / small resolution
			self.cityinfo.pos = ('center', 'top')
			xoff = 0
			yoff = 0 # upper screen edge
		else:
			self.cityinfo.pos = ('left', 'top')
			xoff = resbar[0] + (width - blocked - resbar[0]) // 2
			yoff = 24

		self.cityinfo.offset = (xoff, yoff)
		self.cityinfo.position_technique = "{pos[0]}{off[0]:+d}:{pos[1]}{off[1]:+d}".format(
				pos=self.cityinfo.pos,
				off=self.cityinfo.offset)
		self.cityinfo.hide()
		self.cityinfo.show()

	def minimap_to_front(self):
		"""Make sure the full right top gui is visible and not covered by some dialog"""
		self.widgets['minimap'].hide()
		self.widgets['minimap'].show()

	def show_diplomacy_menu(self):
		# check if the menu is already shown
		if getattr(self.get_cur_menu(), 'name', None) == "diplomacy_widget":
			self.hide_menu()
			return

		if not DiplomacyTab.is_useable(self.session.world):
			self.main_gui.show_popup(_("No diplomacy possible"),
			                         _("Cannot do diplomacy as there are no other players."))
			return

		tab = DiplomacyTab(self, self.session.world)
		self.show_menu(tab)

	def show_multi_select_tab(self):
		tab = TabWidget(self, tabs=[SelectMultiTab(self.session)], name='select_multi')
		self.show_menu(tab)

	def show_build_menu(self, update=False):
		"""
		@param update: set when build possiblities change (e.g. after settler upgrade)
		"""
		# check if build menu is already shown
		if hasattr(self.get_cur_menu(), 'name') and self.get_cur_menu().name == "build_menu_tab_widget":
			self.hide_menu()

			if not update: # this was only a toggle call, don't reshow
				return

		self.session.set_cursor() # set default cursor for build menu
		self.deselect_all()

		if not any( settlement.owner.is_local_player for settlement in self.session.world.settlements):
			# player has not built any settlements yet. Accessing the build menu at such a point
			# indicates a mistake in the mental model of the user. Display a hint.
			tab = TabWidget(self, tabs=[ TabInterface(widget="buildtab_no_settlement.xml") ])
		else:
			btabs = BuildTab.create_tabs(self.session, self._build)
			tab = TabWidget(self, tabs=btabs, name="build_menu_tab_widget",
											active_tab=BuildTab.last_active_build_tab)
		self.show_menu(tab)

	def deselect_all(self):
		for instance in self.session.selected_instances:
			instance.get_component(SelectableComponent).deselect()
		self.session.selected_instances.clear()

	def _build(self, building_id, unit=None):
		"""Calls the games buildingtool class for the building_id.
		@param building_id: int with the building id that is to be built.
		@param unit: weakref to the unit, that builds (e.g. ship for warehouse)"""
		self.hide_menu()
		self.deselect_all()
		cls = Entities.buildings[building_id]
		if hasattr(cls, 'show_build_menu'):
			cls.show_build_menu()
		self.session.set_cursor('building', cls, None if unit is None else unit())

	def toggle_road_tool(self):
		if not isinstance(self.session.cursor, BuildingTool) or self.session.cursor._class.id != BUILDINGS.TRAIL:
			self._build(BUILDINGS.TRAIL)
		else:
			self.session.set_cursor()

	def _get_menu_object(self, menu):
		"""Returns pychan object if menu is a string, else returns menu
		@param menu: str with the guiname or pychan object.
		"""
		if isinstance(menu, str):
			menu = self.widgets[menu]
		return menu

	def get_cur_menu(self):
		"""Returns menu that is currently displayed"""
		return self._old_menu

	def show_menu(self, menu):
		"""Shows a menu
		@param menu: str with the guiname or pychan object.
		"""
		if self._old_menu is not None:
			if hasattr(self._old_menu, "remove_remove_listener"):
				self._old_menu.remove_remove_listener( Callback(self.show_menu, None) )
			self._old_menu.hide()

		self._old_menu = self._get_menu_object(menu)
		if self._old_menu is not None:
			if hasattr(self._old_menu, "add_remove_listener"):
				self._old_menu.add_remove_listener( Callback(self.show_menu, None) )
			self._old_menu.show()
			self.minimap_to_front()

		TabWidgetChanged.broadcast(self)

	def hide_menu(self):
		self.show_menu(None)

	def toggle_menu(self, menu):
		"""Shows a menu or hides it if it is already displayed.
		@param menu: parameter supported by show_menu().
		"""
		if self.get_cur_menu() == self._get_menu_object(menu):
			self.hide_menu()
		else:
			self.show_menu(menu)

	def save(self, db):
		self.message_widget.save(db)
		self.logbook.save(db)
		self.resource_overview.save(db)

	def load(self, db):
		self.message_widget.load(db)
		self.logbook.load(db)
		self.resource_overview.load(db)

		cur_settlement = LastActivePlayerSettlementManager().get_current_settlement()
		self._cityinfo_set( HoverSettlementChanged(self, cur_settlement) )

		self.minimap.draw() # update minimap to new world

	def show_change_name_dialog(self, instance):
		"""Shows a dialog where the user can change the name of a NamedComponant.
		The game gets paused while the dialog is executed."""
		events = {
			OkButton.DEFAULT_NAME: Callback(self.change_name, instance),
			CancelButton.DEFAULT_NAME: self._hide_change_name_dialog
		}
		self.main_gui.on_escape = self._hide_change_name_dialog
		changename = self.widgets['change_name']
		oldname = changename.findChild(name='old_name')
		oldname.text = instance.get_component(SettlementNameComponent).name
		newname = changename.findChild(name='new_name')
		changename.mapEvents(events)
		newname.capture(Callback(self.change_name, instance))

		def forward_escape(event):
			# the textfield will eat everything, even control events
			if event.getKey().getValue() == fife.Key.ESCAPE:
				self.main_gui.on_escape()
		newname.capture( forward_escape, "keyPressed" )

		changename.show()
		newname.requestFocus()

	def _hide_change_name_dialog(self):
		"""Escapes the change_name dialog"""
		self.main_gui.on_escape = self.main_gui.toggle_pause
		self.widgets['change_name'].hide()

	def change_name(self, instance):
		"""Applies the change_name dialogs input and hides it.
		If the new name has length 0 or only contains blanks, the old name is kept.
		"""
		new_name = self.widgets['change_name'].collectData('new_name')
		self.widgets['change_name'].findChild(name='new_name').text = u''
		if not new_name or not new_name.isspace():
			# different namedcomponent classes share the name
			RenameObject(instance.get_component_by_name(NamedComponent.NAME), new_name).execute(self.session)
		self._hide_change_name_dialog()

	def show_save_map_dialog(self):
		"""Shows a dialog where the user can set the name of the saved map."""
		events = {
			OkButton.DEFAULT_NAME: self.save_map,
			CancelButton.DEFAULT_NAME: self._hide_save_map_dialog
		}
		self.main_gui.on_escape = self._hide_save_map_dialog
		dialog = self.widgets['save_map']
		name = dialog.findChild(name='map_name')
		name.text = u''
		dialog.mapEvents(events)
		name.capture(Callback(self.save_map))
		dialog.show()
		name.requestFocus()

	def _hide_save_map_dialog(self):
		"""Closes the map saving dialog."""
		self.main_gui.on_escape = self.main_gui.toggle_pause
		self.widgets['save_map'].hide()

	def save_map(self):
		"""Saves the map and hides the dialog."""
		name = self.widgets['save_map'].collectData('map_name')
		if re.match('^[a-zA-Z0-9_-]+$', name):
			self.session.save_map(name)
			self._hide_save_map_dialog()
		else:
			#xgettext:python-format
			message = _('Valid map names are in the following form: {expression}').format(expression='[a-zA-Z0-9_-]+')
			#xgettext:python-format
			advice = _('Try a name that only contains letters and numbers.')
			self.session.gui.show_error_popup(_('Error'), message, advice)

	def on_escape(self):
		if self.main_widget:
			self.main_widget.hide()
		else:
			return False
		return True

	def on_switch_main_widget(self, widget):
		"""The main widget has been switched to the given one (possibly None)."""
		if self.main_widget and self.main_widget != widget: # close the old one if it exists
			old_main_widget = self.main_widget
			self.main_widget = None
			old_main_widget.hide()
		self.main_widget = widget

	def display_game_speed(self, text):
		"""
		@param text: unicode string to display as speed value
		"""
		wdg = self.widgets['minimap'].findChild(name="speed_text")
		wdg.text = text
		wdg.resizeToContent()
		self.widgets['minimap'].show()

	def _on_settler_level_change(self, message):
		"""Gets called when the player changes"""
		if message.sender.owner.is_local_player:
			menu = self.get_cur_menu()
			if hasattr(menu, "name") and menu.name == "build_menu_tab_widget":
				# player changed and build menu is currently displayed
				self.show_build_menu(update=True)

			# TODO: Use a better measure then first tab
			# Quite fragile, makes sure the tablist in the mainsquare menu is updated
			if hasattr(menu, '_tabs') and isinstance(menu._tabs[0], MainSquareOverviewTab):
				instance = list(self.session.selected_instances)[0]
				instance.get_component(SelectableComponent).show_menu(jump_to_tabclass=type(menu.current_tab))

	def show_chat_dialog(self):
		"""Show a dialog where the user can enter a chat message"""
		events = {
			OkButton.DEFAULT_NAME: self._do_chat,
			CancelButton.DEFAULT_NAME: self._hide_chat_dialog
		}
		self.main_gui.on_escape = self._hide_chat_dialog

		self.widgets['chat'].mapEvents(events)
		def forward_escape(event):
			# the textfield will eat everything, even control events
			if event.getKey().getValue() == fife.Key.ESCAPE:
				self.main_gui.on_escape()

		self.widgets['chat'].findChild(name='msg').capture( forward_escape, "keyPressed" )
		self.widgets['chat'].findChild(name='msg').capture( self._do_chat )
		self.widgets['chat'].show()
		self.widgets['chat'].findChild(name="msg").requestFocus()

	def _hide_chat_dialog(self):
		"""Escapes the chat dialog"""
		self.main_gui.on_escape = self.main_gui.toggle_pause
		self.widgets['chat'].hide()

	def _do_chat(self):
		"""Actually initiates chatting and hides the dialog"""
		msg = self.widgets['chat'].findChild(name='msg').text
		Chat(msg).execute(self.session)
		self.widgets['chat'].findChild(name='msg').text = u''
		self._hide_chat_dialog()
Example #2
0
class IngameGui(LivingObject):
    """Class handling all the ingame gui events.
	Assumes that only 1 instance is used (class variables)"""

    gui = livingProperty()
    tabwidgets = livingProperty()
    message_widget = livingProperty()
    minimap = livingProperty()

    styles = {
        'city_info': 'resource_bar',
        'change_name': 'book',
        'save_map': 'book',
        'chat': 'book',
    }

    def __init__(self, session, gui):
        super(IngameGui, self).__init__()
        self.session = session
        assert isinstance(self.session, horizons.session.Session)
        self.main_gui = gui
        self.main_widget = None
        self.tabwidgets = {}
        self.settlement = None
        self.resource_source = None
        self.resources_needed, self.resources_usable = {}, {}
        self._old_menu = None

        self.widgets = LazyWidgetsDict(self.styles, center_widgets=False)

        self.cityinfo = self.widgets['city_info']
        self.cityinfo.child_finder = PychanChildFinder(self.cityinfo)

        self.logbook = LogBook(self.session)
        self.message_widget = MessageWidget(self.session)
        self.players_overview = PlayersOverview(self.session)
        self.players_settlements = PlayersSettlements(self.session)
        self.players_ships = PlayersShips(self.session)

        # self.widgets['minimap'] is the guichan gui around the actual minimap,
        # which is saved in self.minimap
        minimap = self.widgets['minimap']
        minimap.position_technique = "right+0:top+0"

        icon = minimap.findChild(name="minimap")
        self.minimap = Minimap(
            icon,
            targetrenderer=horizons.globals.fife.targetrenderer,
            imagemanager=horizons.globals.fife.imagemanager,
            session=self.session,
            view=self.session.view)

        def speed_up():
            SpeedUpCommand().execute(self.session)

        def speed_down():
            SpeedDownCommand().execute(self.session)

        minimap.mapEvents({
            'zoomIn':
            self.session.view.zoom_in,
            'zoomOut':
            self.session.view.zoom_out,
            'rotateRight':
            Callback.ChainedCallbacks(self.session.view.rotate_right,
                                      self.minimap.rotate_right),
            'rotateLeft':
            Callback.ChainedCallbacks(self.session.view.rotate_left,
                                      self.minimap.rotate_left),
            'speedUp':
            speed_up,
            'speedDown':
            speed_down,
            'destroy_tool':
            self.session.toggle_destroy_tool,
            'build':
            self.show_build_menu,
            'diplomacyButton':
            self.show_diplomacy_menu,
            'gameMenuButton':
            self.main_gui.toggle_pause,
            'logbook':
            self.logbook.toggle_visibility
        })
        minimap.show()
        #minimap.position_technique = "right+15:top+153"

        self.widgets['tooltip'].hide()

        self.resource_overview = ResourceOverviewBar(self.session)
        ResourceBarResize.subscribe(self._on_resourcebar_resize)

        # Register for messages
        SettlerUpdate.subscribe(self._on_settler_level_change)
        SettlerInhabitantsChanged.subscribe(self._on_settler_inhabitant_change)
        HoverSettlementChanged.subscribe(self._cityinfo_set)

    def _on_resourcebar_resize(self, message):
        self._update_cityinfo_position()

    def end(self):
        self.widgets['minimap'].mapEvents({
            'zoomIn': None,
            'zoomOut': None,
            'rotateRight': None,
            'rotateLeft': None,
            'destroy_tool': None,
            'build': None,
            'diplomacyButton': None,
            'gameMenuButton': None
        })

        for w in self.widgets.itervalues():
            if w.parent is None:
                w.hide()
        self.message_widget = None
        self.tabwidgets = None
        self.minimap = None
        self.resource_overview.end()
        self.resource_overview = None
        self.hide_menu()
        SettlerUpdate.unsubscribe(self._on_settler_level_change)
        ResourceBarResize.unsubscribe(self._on_resourcebar_resize)
        HoverSettlementChanged.unsubscribe(self._cityinfo_set)
        SettlerInhabitantsChanged.unsubscribe(
            self._on_settler_inhabitant_change)

        super(IngameGui, self).end()

    def _cityinfo_set(self, message):
        """Sets the city name at top center of screen.

		Show/Hide is handled automatically
		To hide cityname, set name to ''
		@param message: HoverSettlementChanged message
		"""
        settlement = message.settlement
        old_was_player_settlement = False
        if self.settlement is not None:
            self.settlement.remove_change_listener(self.update_settlement)
            old_was_player_settlement = self.settlement.owner.is_local_player

        # save reference to new "current" settlement in self.settlement
        self.settlement = settlement

        if settlement is None:  # we want to hide the widget now (but perhaps delayed).
            if old_was_player_settlement:
                # After scrolling away from settlement, leave name on screen for some
                # seconds. Players can still click on it to rename the settlement now.
                ExtScheduler().add_new_object(self.cityinfo.hide,
                                              self,
                                              run_in=GUI.CITYINFO_UPDATE_DELAY)
                #TODO 'click to rename' tooltip of cityinfo can stay visible in
                # certain cases if cityinfo gets hidden in tooltip delay buffer.
            else:
                # hovered settlement of other player, simply hide the widget
                self.cityinfo.hide()

        else:  # do not hide if settlement is hovered and a hide was previously scheduled
            ExtScheduler().rem_call(self, self.cityinfo.hide)

            self.update_settlement()  # calls show()
            settlement.add_change_listener(self.update_settlement)

    def _on_settler_inhabitant_change(self, message):
        assert isinstance(message, SettlerInhabitantsChanged)
        foundlabel = self.cityinfo.child_finder('city_inhabitants')
        old_amount = int(foundlabel.text) if foundlabel.text else 0
        foundlabel.text = u' {amount:>4d}'.format(amount=old_amount +
                                                  message.change)
        foundlabel.resizeToContent()

    def update_settlement(self):
        city_name_label = self.cityinfo.child_finder('city_name')
        if self.settlement.owner.is_local_player:  # allow name changes
            # Update settlement on the resource overview to make sure it
            # is setup correctly for the coming calculations
            self.resource_overview.set_inventory_instance(self.settlement)
            cb = Callback(self.show_change_name_dialog, self.settlement)
            helptext = _("Click to change the name of your settlement")
            city_name_label.enable_cursor_change_on_hover()
        else:  # no name changes
            cb = lambda: AmbientSoundComponent.play_special('error')
            helptext = u""
            city_name_label.disable_cursor_change_on_hover()
        self.cityinfo.mapEvents({'city_name': cb})
        city_name_label.helptext = helptext

        foundlabel = self.cityinfo.child_finder('owner_emblem')
        foundlabel.image = 'content/gui/images/tabwidget/emblems/emblem_%s.png' % (
            self.settlement.owner.color.name)
        foundlabel.helptext = self.settlement.owner.name

        foundlabel = self.cityinfo.child_finder('city_name')
        foundlabel.text = self.settlement.get_component(
            SettlementNameComponent).name
        foundlabel.resizeToContent()

        foundlabel = self.cityinfo.child_finder('city_inhabitants')
        foundlabel.text = u' {amount:>4d}'.format(
            amount=self.settlement.inhabitants)
        foundlabel.resizeToContent()

        self._update_cityinfo_position()

    def _update_cityinfo_position(self):
        """ Places cityinfo widget depending on resource bar dimensions.

		For a normal-sized resource bar and reasonably large resolution:
		* determine resource bar length (includes gold)
		* determine empty horizontal space between resbar end and minimap start
		* display cityinfo centered in that area if it is sufficiently large

		If too close to the minimap (cityinfo larger than length of this empty space)
		move cityinfo centered to very upper screen edge. Looks bad, works usually.
		In this case, the resbar is redrawn to put the cityinfo "behind" it visually.
		"""
        width = horizons.globals.fife.engine_settings.getScreenWidth()
        resbar = self.resource_overview.get_size()
        is_foreign = (self.settlement.owner != self.session.world.player)
        blocked = self.cityinfo.size[0] + int(1.5 * self.minimap.get_size()[1])
        # minimap[1] returns width! Use 1.5*width because of the GUI around it

        if is_foreign:  # other player, no resbar exists
            self.cityinfo.pos = ('center', 'top')
            xoff = 0
            yoff = 19
        elif blocked < width < resbar[
                0] + blocked:  # large resbar / small resolution
            self.cityinfo.pos = ('center', 'top')
            xoff = 0
            yoff = 0  # upper screen edge
        else:
            self.cityinfo.pos = ('left', 'top')
            xoff = resbar[0] + (width - blocked - resbar[0]) // 2
            yoff = 24

        self.cityinfo.offset = (xoff, yoff)
        self.cityinfo.position_technique = "{pos[0]}{off[0]:+d}:{pos[1]}{off[1]:+d}".format(
            pos=self.cityinfo.pos, off=self.cityinfo.offset)
        self.cityinfo.hide()
        self.cityinfo.show()

    def minimap_to_front(self):
        """Make sure the full right top gui is visible and not covered by some dialog"""
        self.widgets['minimap'].hide()
        self.widgets['minimap'].show()

    def show_diplomacy_menu(self):
        # check if the menu is already shown
        if getattr(self.get_cur_menu(), 'name', None) == "diplomacy_widget":
            self.hide_menu()
            return

        if not DiplomacyTab.is_useable(self.session.world):
            self.main_gui.show_popup(
                _("No diplomacy possible"),
                _("Cannot do diplomacy as there are no other players."))
            return

        tab = DiplomacyTab(self, self.session.world)
        self.show_menu(tab)

    def show_multi_select_tab(self):
        tab = TabWidget(self,
                        tabs=[SelectMultiTab(self.session)],
                        name='select_multi')
        self.show_menu(tab)

    def show_build_menu(self, update=False):
        """
		@param update: set when build possiblities change (e.g. after settler upgrade)
		"""
        # check if build menu is already shown
        if hasattr(self.get_cur_menu(), 'name') and self.get_cur_menu(
        ).name == "build_menu_tab_widget":
            self.hide_menu()

            if not update:  # this was only a toggle call, don't reshow
                return

        self.session.set_cursor()  # set default cursor for build menu
        self.deselect_all()

        if not any(settlement.owner.is_local_player
                   for settlement in self.session.world.settlements):
            # player has not built any settlements yet. Accessing the build menu at such a point
            # indicates a mistake in the mental model of the user. Display a hint.
            tab = TabWidget(
                self, tabs=[TabInterface(widget="buildtab_no_settlement.xml")])
        else:
            btabs = BuildTab.create_tabs(self.session, self._build)
            tab = TabWidget(self,
                            tabs=btabs,
                            name="build_menu_tab_widget",
                            active_tab=BuildTab.last_active_build_tab)
        self.show_menu(tab)

    def deselect_all(self):
        for instance in self.session.selected_instances:
            instance.get_component(SelectableComponent).deselect()
        self.session.selected_instances.clear()

    def _build(self, building_id, unit=None):
        """Calls the games buildingtool class for the building_id.
		@param building_id: int with the building id that is to be built.
		@param unit: weakref to the unit, that builds (e.g. ship for warehouse)"""
        self.hide_menu()
        self.deselect_all()
        cls = Entities.buildings[building_id]
        if hasattr(cls, 'show_build_menu'):
            cls.show_build_menu()
        self.session.set_cursor('building', cls,
                                None if unit is None else unit())

    def toggle_road_tool(self):
        if not isinstance(
                self.session.cursor, BuildingTool
        ) or self.session.cursor._class.id != BUILDINGS.TRAIL:
            self._build(BUILDINGS.TRAIL)
        else:
            self.session.set_cursor()

    def _get_menu_object(self, menu):
        """Returns pychan object if menu is a string, else returns menu
		@param menu: str with the guiname or pychan object.
		"""
        if isinstance(menu, str):
            menu = self.widgets[menu]
        return menu

    def get_cur_menu(self):
        """Returns menu that is currently displayed"""
        return self._old_menu

    def show_menu(self, menu):
        """Shows a menu
		@param menu: str with the guiname or pychan object.
		"""
        if self._old_menu is not None:
            if hasattr(self._old_menu, "remove_remove_listener"):
                self._old_menu.remove_remove_listener(
                    Callback(self.show_menu, None))
            self._old_menu.hide()

        self._old_menu = self._get_menu_object(menu)
        if self._old_menu is not None:
            if hasattr(self._old_menu, "add_remove_listener"):
                self._old_menu.add_remove_listener(
                    Callback(self.show_menu, None))
            self._old_menu.show()
            self.minimap_to_front()

        TabWidgetChanged.broadcast(self)

    def hide_menu(self):
        self.show_menu(None)

    def toggle_menu(self, menu):
        """Shows a menu or hides it if it is already displayed.
		@param menu: parameter supported by show_menu().
		"""
        if self.get_cur_menu() == self._get_menu_object(menu):
            self.hide_menu()
        else:
            self.show_menu(menu)

    def save(self, db):
        self.message_widget.save(db)
        self.logbook.save(db)
        self.resource_overview.save(db)

    def load(self, db):
        self.message_widget.load(db)
        self.logbook.load(db)
        self.resource_overview.load(db)

        cur_settlement = LastActivePlayerSettlementManager(
        ).get_current_settlement()
        self._cityinfo_set(HoverSettlementChanged(self, cur_settlement))

        self.minimap.draw()  # update minimap to new world

    def show_change_name_dialog(self, instance):
        """Shows a dialog where the user can change the name of a NamedComponant.
		The game gets paused while the dialog is executed."""
        events = {
            OkButton.DEFAULT_NAME: Callback(self.change_name, instance),
            CancelButton.DEFAULT_NAME: self._hide_change_name_dialog
        }
        self.main_gui.on_escape = self._hide_change_name_dialog
        changename = self.widgets['change_name']
        oldname = changename.findChild(name='old_name')
        oldname.text = instance.get_component(SettlementNameComponent).name
        newname = changename.findChild(name='new_name')
        changename.mapEvents(events)
        newname.capture(Callback(self.change_name, instance))

        def forward_escape(event):
            # the textfield will eat everything, even control events
            if event.getKey().getValue() == fife.Key.ESCAPE:
                self.main_gui.on_escape()

        newname.capture(forward_escape, "keyPressed")

        changename.show()
        newname.requestFocus()

    def _hide_change_name_dialog(self):
        """Escapes the change_name dialog"""
        self.main_gui.on_escape = self.main_gui.toggle_pause
        self.widgets['change_name'].hide()

    def change_name(self, instance):
        """Applies the change_name dialogs input and hides it.
		If the new name has length 0 or only contains blanks, the old name is kept.
		"""
        new_name = self.widgets['change_name'].collectData('new_name')
        self.widgets['change_name'].findChild(name='new_name').text = u''
        if not new_name or not new_name.isspace():
            # different namedcomponent classes share the name
            RenameObject(instance.get_component_by_name(NamedComponent.NAME),
                         new_name).execute(self.session)
        self._hide_change_name_dialog()

    def show_save_map_dialog(self):
        """Shows a dialog where the user can set the name of the saved map."""
        events = {
            OkButton.DEFAULT_NAME: self.save_map,
            CancelButton.DEFAULT_NAME: self._hide_save_map_dialog
        }
        self.main_gui.on_escape = self._hide_save_map_dialog
        dialog = self.widgets['save_map']
        name = dialog.findChild(name='map_name')
        name.text = u''
        dialog.mapEvents(events)
        name.capture(Callback(self.save_map))
        dialog.show()
        name.requestFocus()

    def _hide_save_map_dialog(self):
        """Closes the map saving dialog."""
        self.main_gui.on_escape = self.main_gui.toggle_pause
        self.widgets['save_map'].hide()

    def save_map(self):
        """Saves the map and hides the dialog."""
        name = self.widgets['save_map'].collectData('map_name')
        if re.match('^[a-zA-Z0-9_-]+$', name):
            self.session.save_map(name)
            self._hide_save_map_dialog()
        else:
            #xgettext:python-format
            message = _(
                'Valid map names are in the following form: {expression}'
            ).format(expression='[a-zA-Z0-9_-]+')
            #xgettext:python-format
            advice = _('Try a name that only contains letters and numbers.')
            self.session.gui.show_error_popup(_('Error'), message, advice)

    def on_escape(self):
        if self.main_widget:
            self.main_widget.hide()
        else:
            return False
        return True

    def on_switch_main_widget(self, widget):
        """The main widget has been switched to the given one (possibly None)."""
        if self.main_widget and self.main_widget != widget:  # close the old one if it exists
            old_main_widget = self.main_widget
            self.main_widget = None
            old_main_widget.hide()
        self.main_widget = widget

    def display_game_speed(self, text):
        """
		@param text: unicode string to display as speed value
		"""
        wdg = self.widgets['minimap'].findChild(name="speed_text")
        wdg.text = text
        wdg.resizeToContent()
        self.widgets['minimap'].show()

    def _on_settler_level_change(self, message):
        """Gets called when the player changes"""
        if message.sender.owner.is_local_player:
            menu = self.get_cur_menu()
            if hasattr(menu, "name") and menu.name == "build_menu_tab_widget":
                # player changed and build menu is currently displayed
                self.show_build_menu(update=True)

            # TODO: Use a better measure then first tab
            # Quite fragile, makes sure the tablist in the mainsquare menu is updated
            if hasattr(menu, '_tabs') and isinstance(menu._tabs[0],
                                                     MainSquareOverviewTab):
                instance = list(self.session.selected_instances)[0]
                instance.get_component(SelectableComponent).show_menu(
                    jump_to_tabclass=type(menu.current_tab))

    def show_chat_dialog(self):
        """Show a dialog where the user can enter a chat message"""
        events = {
            OkButton.DEFAULT_NAME: self._do_chat,
            CancelButton.DEFAULT_NAME: self._hide_chat_dialog
        }
        self.main_gui.on_escape = self._hide_chat_dialog

        self.widgets['chat'].mapEvents(events)

        def forward_escape(event):
            # the textfield will eat everything, even control events
            if event.getKey().getValue() == fife.Key.ESCAPE:
                self.main_gui.on_escape()

        self.widgets['chat'].findChild(name='msg').capture(
            forward_escape, "keyPressed")
        self.widgets['chat'].findChild(name='msg').capture(self._do_chat)
        self.widgets['chat'].show()
        self.widgets['chat'].findChild(name="msg").requestFocus()

    def _hide_chat_dialog(self):
        """Escapes the chat dialog"""
        self.main_gui.on_escape = self.main_gui.toggle_pause
        self.widgets['chat'].hide()

    def _do_chat(self):
        """Actually initiates chatting and hides the dialog"""
        msg = self.widgets['chat'].findChild(name='msg').text
        Chat(msg).execute(self.session)
        self.widgets['chat'].findChild(name='msg').text = u''
        self._hide_chat_dialog()