Exemple #1
0
def test_toggle_multiple():
    """
	Alternately toggle two windows and make sure we have only
	once instance of each window in the stack.
	"""
    windows = WindowManager()
    window1 = DummyWindow(windows)
    window2 = DummyWindow(windows)
    assert not window1.visible
    assert not window2.visible

    windows.toggle(window1)
    assert window1.visible
    assert not window2.visible

    windows.toggle(window2)
    assert not window1.visible
    assert window2.visible

    windows.toggle(window1)
    assert window1.visible
    assert not window2.visible

    windows.close()
    windows.close()
    assert not windows.visible
Exemple #2
0
	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 test_toggle_single_window():
	windows = WindowManager()
	window1 = DummyWindow(windows)
	assert not window1.visible

	windows.toggle(window1)
	assert window1.visible
	windows.toggle(window1)
	assert not window1.visible
Exemple #4
0
    def __init__(self, session):
        self.session = session

        self.which = None
        self.cursor = None
        self.coordinates_tooltip = None
        self.keylistener = IngameKeyListener(self.session)
        # used by NavigationTool
        LastActivePlayerSettlementManager.create_instance(self.session)

        # Mocks needed to act like the real IngameGui
        self.show_menu = mock.Mock()
        self.hide_menu = mock.Mock()
        # this is necessary for message_widget to work
        self.logbook = mock.Mock()

        self.mainhud = load_uh_widget('minimap.xml')
        self.mainhud.position_technique = "right+0:top+0"

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

        self.mainhud.mapEvents({
            'zoomIn':
            self.session.view.zoom_in,
            'zoomOut':
            self.session.view.zoom_out,
            'rotateRight':
            Callback.ChainedCallbacks(self.session.view.rotate_right,
                                      self.minimap.update_rotation),
            'rotateLeft':
            Callback.ChainedCallbacks(self.session.view.rotate_left,
                                      self.minimap.update_rotation),
            'gameMenuButton':
            self.toggle_pause,
        })

        self.mainhud.show()
        ZoomChanged.subscribe(self._update_zoom)

        # Hide unnecessary buttons in hud
        for widget in ("build", "speedUp", "speedDown", "destroy_tool",
                       "diplomacyButton", "logbook"):
            self.mainhud.findChild(name=widget).hide()

        self.windows = WindowManager()
        self.message_widget = MessageWidget(self.session)
        self.pausemenu = PauseMenu(self.session,
                                   self,
                                   self.windows,
                                   in_editor_mode=True)
        self.help_dialog = HelpDialog(self.windows)
def test_toggle_multiple():
	"""
	Alternately toggle two windows and make sure we have only
	once instance of each window in the stack.
	"""
	windows = WindowManager()
	window1 = DummyWindow(windows)
	window2 = DummyWindow(windows)
	assert not window1.visible
	assert not window2.visible

	windows.toggle(window1)
	assert window1.visible
	assert not window2.visible

	windows.toggle(window2)
	assert not window1.visible
	assert window2.visible

	windows.toggle(window1)
	assert window1.visible
	assert not window2.visible

	windows.close()
	windows.close()
	assert not windows.visible
def test_open_hide():
	windows = WindowManager()
	window1 = DummyWindow(windows)
	windows.open(window1)
	assert windows.visible
	assert window1.visible

	window2 = DummyWindow(windows)
	windows.open(window2)
	assert windows.visible
	assert not window1.visible
	assert window2.visible
Exemple #7
0
	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()
Exemple #8
0
	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()
Exemple #9
0
	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

		self._background = 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()
Exemple #10
0
def test_toggle_single_window():
    windows = WindowManager()
    window1 = DummyWindow(windows)
    assert not window1.visible

    windows.toggle(window1)
    assert window1.visible
    windows.toggle(window1)
    assert not window1.visible
Exemple #11
0
def test_close():
    windows = WindowManager()
    window1 = DummyWindow(windows)
    window2 = DummyWindow(windows)
    windows.open(window1)
    windows.open(window2)
    assert not window1.visible
    assert window2.visible

    windows.close()
    assert window1.visible
    assert not window2.visible

    windows.close()
    assert not window1.visible
    assert not window2.visible
    assert not windows.visible
	def __init__(self):
		self.mainlistener = MainListener(self)
		self.current = None # currently active window
		self.session = None

		self.windows = WindowManager()
		# temporary aliases for compatibility with rest of the code
		self.show_dialog = self.windows.show_dialog
		self.show_popup = self.windows.show_popup
		self.show_error_popup = self.windows.show_error_popup

		self.__pause_displayed = False

		self._background = pychan.Icon(image=self._get_random_background(),
		                               position_technique='center:center')
		self._background.show()

		self.subscribe()

		self.singleplayermenu = SingleplayerMenu(self)
		self.multiplayermenu = MultiplayerMenu(self)
		self.help_dialog = HelpDialog(self)
		self.selectsavegame_dialog = SelectSavegameDialog(self)
		self.show_select_savegame = self.selectsavegame_dialog.show_select_savegame
		self.loadingscreen = LoadingScreen()

		self.mainmenu = load_uh_widget('mainmenu.xml', 'menu')
		self.mainmenu.mapEvents({
			'single_button': self.singleplayermenu.show,
			'single_label' : self.singleplayermenu.show,
			'multi_button': self.multiplayermenu.show,
			'multi_label' : self.multiplayermenu.show,
			'settings_button': self.show_settings,
			'settings_label' : self.show_settings,
			'help_button': self.on_help,
			'help_label' : self.on_help,
			'quit_button': self.show_quit,
			'quit_label' : self.show_quit,
			'editor_button': self.show_editor_start_menu,
			'editor_label' : self.show_editor_start_menu,
			'credits_button': self.show_credits,
			'credits_label' : self.show_credits,
			'load_button': self.load_game,
			'load_label' : self.load_game,
			'changeBackground' : self.randomize_background
		})

		self.fps_display = FPSDisplay()
Exemple #13
0
    def __init__(self, session):
        self.session = session

        self.cursor = None
        self.coordinates_tooltip = None
        self.keylistener = IngameKeyListener(self.session)
        # used by NavigationTool
        LastActivePlayerSettlementManager.create_instance(self.session)

        # Mocks needed to act like the real IngameGui
        self.show_menu = Dummy
        self.hide_menu = Dummy
        # a logbook Dummy is necessary for message_widget to work
        self.logbook = Dummy

        self.mainhud = load_uh_widget("minimap.xml")
        self.mainhud.position_technique = "right+0:top+0"

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

        self.mainhud.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),
                "gameMenuButton": self.toggle_pause,
            }
        )

        self.mainhud.show()
        ZoomChanged.subscribe(self._update_zoom)

        # Hide unnecessary buttons in hud
        for widget in ("build", "speedUp", "speedDown", "destroy_tool", "diplomacyButton", "logbook"):
            self.mainhud.findChild(name=widget).hide()

        self.windows = WindowManager()
        self.message_widget = MessageWidget(self.session)
        self.pausemenu = PauseMenu(self.session, self, self.windows, in_editor_mode=True)
        self.help_dialog = HelpDialog(self.windows)
Exemple #14
0
    def _init_gui(self, session):
        self._gui = load_uh_widget("stringpreviewwidget.xml")
        self._gui.mapEvents({'load': self.load})
        self.scenarios = SavegameManager.get_scenarios()
        self.listbox = self._gui.findChild(name="scenario_list")
        self.listbox.items = self.scenarios[1]
        self.listbox.distributeData({'scenario_list': 0})
        self.listbox.capture(self.update_infos)

        self.statslabel = self._gui.findChild(name="stats")

        self.windows = WindowManager()
        self.logbook = LogBook(session, self.windows)
        self.logbook._gui.mapEvents({
            OkButton.DEFAULT_NAME: self.logbook.hide,
        })
        self.update_infos()
class IngameGui(LivingObject):
	"""Class handling all the ingame gui events.
	Assumes that only 1 instance is used (class variables)"""

	message_widget = livingProperty()
	minimap = livingProperty()
	keylistener = livingProperty()

	def __init__(self, session):
		super(IngameGui, self).__init__()
		self.session = session
		assert isinstance(self.session, horizons.session.Session)
		self.settlement = None
		self._old_menu = None

		self.cursor = None
		self.coordinates_tooltip = None

		self.keylistener = IngameKeyListener(self.session)

		self.cityinfo = CityInfo(self)
		LastActivePlayerSettlementManager.create_instance(self.session)

		self.message_widget = MessageWidget(self.session)

		# Windows
		self.windows = WindowManager()
		self.show_popup = self.windows.show_popup
		self.show_error_popup = self.windows.show_error_popup

		self.logbook = LogBook(self.session, self.windows)
		self.players_overview = PlayersOverview(self.session)
		self.players_settlements = PlayersSettlements(self.session)
		self.players_ships = PlayersShips(self.session)

		self.chat_dialog = ChatDialog(self.windows, self.session)
		self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
		self.pausemenu = PauseMenu(self.session, self, self.windows, in_editor_mode=False)
		self.help_dialog = HelpDialog(self.windows, session=self.session)

		# Icon manager
		self.status_icon_manager = StatusIconManager(
			renderer=self.session.view.renderer['GenericRenderer'],
			layer=self.session.view.layers[LAYERS.OBJECTS]
		)
		self.production_finished_icon_manager = ProductionFinishedIconManager(
			renderer=self.session.view.renderer['GenericRenderer'],
			layer=self.session.view.layers[LAYERS.OBJECTS]
		)

		# 'minimap' is the guichan gui around the actual minimap, which is saved
		# in self.minimap
		self.mainhud = load_uh_widget('minimap.xml')
		self.mainhud.position_technique = "right:top"

		icon = self.mainhud.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)

		self.mainhud.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.toggle_destroy_tool,
			'build' : self.show_build_menu,
			'diplomacyButton' : self.show_diplomacy_menu,
			'gameMenuButton' : self.toggle_pause,
			'logbook' : lambda: self.windows.toggle(self.logbook)
		})
		self.mainhud.show()

		hotkey_replacements = {
			'rotateRight': 'ROTATE_RIGHT',
			'rotateLeft': 'ROTATE_LEFT',
			'speedUp': 'SPEED_UP',
			'speedDown': 'SPEED_DOWN',
			'destroy_tool': 'DESTROY_TOOL',
			'build': 'BUILD_TOOL',
			'gameMenuButton': 'ESCAPE',
			'logbook': 'LOGBOOK',
		}
		for (widgetname, action) in hotkey_replacements.iteritems():
			widget = self.mainhud.findChild(name=widgetname)
			keys = horizons.globals.fife.get_keys_for_action(action)
			# No `.upper()` here: "Pause" looks better than "PAUSE".
			keyname = HOTKEYS.DISPLAY_KEY.get(keys[0], keys[0].capitalize())
			widget.helptext = widget.helptext.format(key=keyname)

		self.resource_overview = ResourceOverviewBar(self.session)

		# Register for messages
		SpeedChanged.subscribe(self._on_speed_changed)
		NewDisaster.subscribe(self._on_new_disaster)
		NewSettlement.subscribe(self._on_new_settlement)
		PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
		MineEmpty.subscribe(self._on_mine_empty)
		ZoomChanged.subscribe(self._update_zoom)

		self._display_speed(self.session.timer.ticks_per_second)

	def end(self):
		# unsubscribe early, to avoid messages coming in while we're shutting down
		SpeedChanged.unsubscribe(self._on_speed_changed)
		NewDisaster.unsubscribe(self._on_new_disaster)
		NewSettlement.unsubscribe(self._on_new_settlement)
		PlayerLevelUpgrade.unsubscribe(self._on_player_level_upgrade)
		MineEmpty.unsubscribe(self._on_mine_empty)
		ZoomChanged.unsubscribe(self._update_zoom)

		self.mainhud.mapEvents({
			'zoomIn' : None,
			'zoomOut' : None,
			'rotateRight' : None,
			'rotateLeft': None,

			'destroy_tool' : None,
			'build' : None,
			'diplomacyButton' : None,
			'gameMenuButton' : None
		})
		self.mainhud.hide()
		self.mainhud = None

		self.windows.close_all()
		self.message_widget = None
		self.minimap = None
		self.resource_overview.end()
		self.resource_overview = None
		self.keylistener = None
		self.cityinfo.end()
		self.cityinfo = None
		self.hide_menu()

		if self.cursor:
			self.cursor.remove()
			self.cursor.end()
			self.cursor = None

		LastActivePlayerSettlementManager().remove()
		LastActivePlayerSettlementManager.destroy_instance()

		self.production_finished_icon_manager.end()
		self.production_finished_icon_manager = None
		self.status_icon_manager.end()
		self.status_icon_manager = None

		super(IngameGui, self).end()

	def show_select_savegame(self, mode):
		window = SelectSavegameDialog(mode, self.windows)
		return self.windows.show(window)

	def toggle_pause(self):
		self.windows.toggle(self.pausemenu)

	def toggle_help(self):
		self.windows.toggle(self.help_dialog)

	def minimap_to_front(self):
		"""Make sure the full right top gui is visible and not covered by some dialog"""
		self.mainhud.hide()
		self.mainhud.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.windows.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, instances):
		tab = TabWidget(self, tabs=[SelectMultiTab(instances)], name='select_multi')
		self.show_menu(tab)

	def show_build_menu(self, update=False):
		"""
		@param update: set when build possibilities change (e.g. after inhabitant tier 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.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.set_cursor('building', cls, None if unit is None else unit())

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

	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 = 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 save(self, db):
		self.message_widget.save(db)
		self.logbook.save(db)
		self.resource_overview.save(db)
		LastActivePlayerSettlementManager().save(db)
		self.save_selection(db)

	def save_selection(self, db):
		# Store instances that are selected right now.
		for instance in self.session.selected_instances:
			db("INSERT INTO selected (`group`, id) VALUES (NULL, ?)", instance.worldid)

		# If a single instance is selected, also store the currently displayed tab.
		# (Else, upon restoring, we display a multi-selection tab.)
		tabname = None
		if len(self.session.selected_instances) == 1:
			tabclass = self.get_cur_menu().current_tab
			tabname = tabclass.__class__.__name__
		db("INSERT INTO metadata (name, value) VALUES (?, ?)", 'selected_tab', tabname)

		# Store user defined unit selection groups (Ctrl+number)
		for (number, group) in enumerate(self.session.selection_groups):
			for instance in group:
				db("INSERT INTO selected (`group`, id) VALUES (?, ?)", number, instance.worldid)

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

		if self.session.is_game_loaded():
			LastActivePlayerSettlementManager().load(db)
			cur_settlement = LastActivePlayerSettlementManager().get_current_settlement()
			self.cityinfo.set_settlement(cur_settlement)

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

		self.current_cursor = 'default'
		self.cursor = mousetools.SelectionTool(self.session)
		# Set cursor correctly, menus might need to be opened.
		# Open menus later; they may need unit data not yet inited
		self.cursor.apply_select()

		self.load_selection(db)

		if not self.session.is_game_loaded():
			# Fire a message for new world creation
			self.message_widget.add('NEW_WORLD')

		# Show message when the relationship between players changed
		def notify_change(caller, old_state, new_state, a, b):
			player1 = u"%s" % a.name
			player2 = u"%s" % b.name

			data = {'player1' : player1, 'player2' : player2}

			string_id = 'DIPLOMACY_STATUS_{old}_{new}'.format(old=old_state.upper(),
			                                                  new=new_state.upper())
			self.message_widget.add(string_id=string_id, message_dict=data)

		self.session.world.diplomacy.add_diplomacy_status_changed_listener(notify_change)

	def load_selection(self, db):
		# Re-select old selected instance
		for (instance_id, ) in db("SELECT id FROM selected WHERE `group` IS NULL"):
			obj = WorldObject.get_object_by_id(instance_id)
			self.session.selected_instances.add(obj)
			obj.get_component(SelectableComponent).select()

		# Re-show old tab (if there was one) or multiselection
		if len(self.session.selected_instances) == 1:
			tabname = db("SELECT value FROM metadata WHERE name = ?",
			             'selected_tab')[0][0]
			# This can still be None due to old savegames not storing the information
			tabclass = None if tabname is None else resolve_tab(tabname)
			obj.get_component(SelectableComponent).show_menu(jump_to_tabclass=tabclass)
		elif self.session.selected_instances:
			self.show_multi_select_tab(self.session.selected_instances)

		# Load user defined unit selection groups (Ctrl+number)
		for (num, group) in enumerate(self.session.selection_groups):
			for (instance_id, ) in db("SELECT id FROM selected WHERE `group` = ?", num):
				obj = WorldObject.get_object_by_id(instance_id)
				group.add(obj)

	def show_change_name_dialog(self, instance):
		"""Shows a dialog where the user can change the name of an object."""
		self.windows.show(self.change_name_dialog, instance=instance)

	def on_escape(self):
		if self.windows.visible:
			self.windows.on_escape()
		elif hasattr(self.cursor, 'on_escape'):
			self.cursor.on_escape()
		else:
			self.toggle_pause()

		return True

	def on_return(self):
		if self.windows.visible:
			self.windows.on_return()

		return True

	def _on_speed_changed(self, message):
		self._display_speed(message.new)

	def _display_speed(self, tps):
		text = u''
		up_icon = self.mainhud.findChild(name='speedUp')
		down_icon = self.mainhud.findChild(name='speedDown')
		if tps == 0: # pause
			text = u'0x'
			up_icon.set_inactive()
			down_icon.set_inactive()
		else:
			if tps != GAME_SPEED.TICKS_PER_SECOND:
				text = u"%1gx" % (tps * 1.0/GAME_SPEED.TICKS_PER_SECOND)
				#%1g: displays 0.5x, but 2x instead of 2.0x
			index = GAME_SPEED.TICK_RATES.index(tps)
			if index + 1 >= len(GAME_SPEED.TICK_RATES):
				up_icon.set_inactive()
			else:
				up_icon.set_active()
			if index > 0:
				down_icon.set_active()
			else:
				down_icon.set_inactive()

		wdg = self.mainhud.findChild(name="speed_text")
		wdg.text = text
		wdg.resizeToContent()
		self.mainhud.show()

	def on_key_press(self, action, evt):
		"""Handle a key press in-game.

		Returns True if the key was acted upon.
		"""
		_Actions = KeyConfig._Actions
		keyval = evt.getKey().getValue()

		if action == _Actions.ESCAPE:
			return self.on_escape()		
		elif keyval == fife.Key.ENTER:
			return self.on_return()

		if action == _Actions.GRID:
			gridrenderer = self.session.view.renderer['GridRenderer']
			gridrenderer.setEnabled( not gridrenderer.isEnabled() )
		elif action == _Actions.COORD_TOOLTIP:
			self.coordinates_tooltip.toggle()
		elif action == _Actions.DESTROY_TOOL:
			self.toggle_destroy_tool()
		elif action == _Actions.REMOVE_SELECTED:
			message = _(u"Are you sure you want to delete these objects?")
			if self.windows.show_popup(_(u"Delete"), message, show_cancel_button=True):
				self.session.remove_selected()
			else:
				self.deselect_all()
		elif action == _Actions.ROAD_TOOL:
			self.toggle_road_tool()
		elif action == _Actions.SPEED_UP:
			SpeedUpCommand().execute(self.session)
		elif action == _Actions.SPEED_DOWN:
			SpeedDownCommand().execute(self.session)
		elif action == _Actions.PAUSE:
			TogglePauseCommand().execute(self.session)
		elif action == _Actions.PLAYERS_OVERVIEW:
			self.logbook.toggle_stats_visibility(widget='players')
		elif action == _Actions.SETTLEMENTS_OVERVIEW:
			self.logbook.toggle_stats_visibility(widget='settlements')
		elif action == _Actions.SHIPS_OVERVIEW:
			self.logbook.toggle_stats_visibility(widget='ships')
		elif action == _Actions.LOGBOOK:
			self.windows.toggle(self.logbook)
		elif action == _Actions.DEBUG and VERSION.IS_DEV_VERSION:
			import pdb; pdb.set_trace()
		elif action == _Actions.BUILD_TOOL:
			self.show_build_menu()
		elif action == _Actions.ROTATE_RIGHT:
			if hasattr(self.cursor, "rotate_right"):
				# used in e.g. build preview to rotate building instead of map
				self.cursor.rotate_right()
			else:
				self.session.view.rotate_right()
				self.minimap.rotate_right()
		elif action == _Actions.ROTATE_LEFT:
			if hasattr(self.cursor, "rotate_left"):
				self.cursor.rotate_left()
			else:
				self.session.view.rotate_left()
				self.minimap.rotate_left()
		elif action == _Actions.CHAT:
			self.windows.show(self.chat_dialog)
		elif action == _Actions.TRANSLUCENCY:
			self.session.world.toggle_translucency()
		elif action == _Actions.TILE_OWNER_HIGHLIGHT:
			self.session.world.toggle_owner_highlight()
		elif fife.Key.NUM_0 <= keyval <= fife.Key.NUM_9:
			num = int(keyval - fife.Key.NUM_0)
			self.handle_selection_group(num, evt.isControlPressed())
		elif action == _Actions.QUICKSAVE:
			self.session.quicksave()
		# Quickload is only handled by the MainListener.
		elif action == _Actions.PIPETTE:
			# Mode that allows copying buildings.
			self.toggle_cursor('pipette')
		elif action == _Actions.HEALTH_BAR:
			# Show health bar of every instance with a health component.
			self.session.world.toggle_health_for_all_health_instances()
		elif action == _Actions.SHOW_SELECTED:
			if self.session.selected_instances:
				# Scroll to first one, we can never guarantee to display all selected units.
				instance = iter(self.session.selected_instances).next()
				self.session.view.center( * instance.position.center.to_tuple())
				for instance in self.session.selected_instances:
					if hasattr(instance, "path") and instance.owner.is_local_player:
						self.minimap.show_unit_path(instance)
		elif action == _Actions.HELP:
			self.toggle_help()
		else:
			return False

		return True

	def handle_selection_group(self, num, ctrl_pressed):
		"""Select existing or assign new unit selection group.

		Ctrl+number creates or overwrites the group of number `num`
		with the currently selected units.
		Pressing the associated key selects a group and centers the
		camera around these units.
		"""
		if ctrl_pressed:
			# Only consider units owned by the player.
			units = set(u for u in self.session.selected_instances
			            if u.owner.is_local_player)
			self.session.selection_groups[num] = units
			# Drop units of the new group from all other groups.
			for group in self.session.selection_groups:
				current_group = self.session.selection_groups[num]
				if group != current_group:
					group -= current_group
		else:
			# We need to make sure to have a cursor capable of selection
			# for apply_select() to work.
			# This handles deselection implicitly in the destructor.
			self.set_cursor('selection')
			# Apply new selection.
			for instance in self.session.selection_groups[num]:
				instance.get_component(SelectableComponent).select(reset_cam=True)
			# Assign copy since it will be randomly changed in selection code.
			# The unit group itself should only be changed on Ctrl events.
			self.session.selected_instances = self.session.selection_groups[num].copy()
			# Show correct tabs depending on what's selected.
			if self.session.selected_instances:
				self.cursor.apply_select()
			else:
				# Nothing is selected here. Hide the menu since apply_select
				# doesn't handle that case.
				self.show_menu(None)

	def toggle_cursor(self, which):
		"""Alternate between the cursor *which* and the default cursor."""
		if which == self.current_cursor:
			self.set_cursor()
		else:
			self.set_cursor(which)

	def set_cursor(self, which='default', *args, **kwargs):
		"""Sets the mousetool (i.e. cursor).
		This is done here for encapsulation and control over destructors.
		Further arguments are passed to the mouse tool constructor."""
		self.cursor.remove()
		self.current_cursor = which
		klass = {
			'default'        : mousetools.SelectionTool,
			'selection'      : mousetools.SelectionTool,
			'tearing'        : mousetools.TearingTool,
			'pipette'        : mousetools.PipetteTool,
			'attacking'      : mousetools.AttackingTool,
			'building'       : mousetools.BuildingTool,
		}[which]
		self.cursor = klass(self.session, *args, **kwargs)

	def toggle_destroy_tool(self):
		"""Initiate the destroy tool"""
		self.toggle_cursor('tearing')

	def _update_zoom(self, message):
		"""Enable/disable zoom buttons"""
		in_icon = self.mainhud.findChild(name='zoomIn')
		out_icon = self.mainhud.findChild(name='zoomOut')
		if message.zoom == VIEW.ZOOM_MIN:
			out_icon.set_inactive()
		else:
			out_icon.set_active()
		if message.zoom == VIEW.ZOOM_MAX:
			in_icon.set_inactive()
		else:
			in_icon.set_active()

	def _on_new_disaster(self, message):
		"""Called when a building is 'infected' with a disaster."""
		if message.building.owner.is_local_player and len(message.disaster._affected_buildings) == 1:
			pos = message.building.position.center
			self.message_widget.add(point=pos, string_id=message.disaster_class.NOTIFICATION_TYPE)

	def _on_new_settlement(self, message):
		player = message.settlement.owner
		self.message_widget.add(
			string_id='NEW_SETTLEMENT',
			point=message.warehouse_position,
			message_dict={'player': player.name},
			play_sound=player.is_local_player
		)

	def _on_player_level_upgrade(self, message):
		"""Called when a player's population reaches a new level."""
		if not message.sender.is_local_player:
			return

		# show notification
		self.message_widget.add(
			point=message.building.position.center,
			string_id='SETTLER_LEVEL_UP',
			message_dict={'level': message.level + 1}
		)

		# update build menu to show new buildings
		menu = self.get_cur_menu()
		if hasattr(menu, "name") and menu.name == "build_menu_tab_widget":
			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 _on_mine_empty(self, message):
		self.message_widget.add(point=message.mine.position.center, string_id='MINE_EMPTY')
Exemple #16
0
class Gui:
	"""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.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 show_main(self):
		"""Shows the main menu"""
		GuiAction.subscribe(self._on_gui_click_action)
		GuiHover.subscribe(self._on_gui_hover_action)
		GuiCancelAction.subscribe(self._on_gui_cancel_action)

		if not self._background.isVisible():
			self._background.show()

		self.windows.open(self.mainmenu)

	def show_select_savegame(self, mode):
		window = SelectSavegameDialog(mode, self.windows)
		return self.windows.open(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.open(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_click_action)
		GuiHover.discard(self._on_gui_hover_action)
		GuiCancelAction.discard(self._on_gui_cancel_action)
		self.windows.close_all()
		self._background.hide()

	def show_loading_screen(self):
		if not self._background.isVisible():
			self._background.show()
		self.windows.open(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(1)
		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_click_action(self, msg):
		"""Make a sound when a button is clicked"""
		AmbientSoundComponent.play_special('click', gain=10)

	def _on_gui_cancel_action(self, msg):
		"""Make a sound when a cancelButton is clicked"""
		AmbientSoundComponent.play_special('success', gain=10)

	def _on_gui_hover_action(self, msg):
		"""Make a sound when the mouse hovers over a button"""
		AmbientSoundComponent.play_special('refresh', position=None, gain=1)

	def show_editor_start_menu(self):
		editor_start_menu = EditorStartMenu(self.windows)
		self.windows.open(editor_start_menu)
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.current = None # currently active window
		self.session = None

		self.windows = WindowManager()
		# temporary aliases for compatibility with rest of the code
		self.show_dialog = self.windows.show_dialog
		self.show_popup = self.windows.show_popup
		self.show_error_popup = self.windows.show_error_popup

		self.__pause_displayed = False

		self._background = pychan.Icon(image=self._get_random_background(),
		                               position_technique='center:center')
		self._background.show()

		self.subscribe()

		self.singleplayermenu = SingleplayerMenu(self)
		self.multiplayermenu = MultiplayerMenu(self)
		self.help_dialog = HelpDialog(self)
		self.selectsavegame_dialog = SelectSavegameDialog(self)
		self.show_select_savegame = self.selectsavegame_dialog.show_select_savegame
		self.loadingscreen = LoadingScreen()

		self.mainmenu = load_uh_widget('mainmenu.xml', 'menu')
		self.mainmenu.mapEvents({
			'single_button': self.singleplayermenu.show,
			'single_label' : self.singleplayermenu.show,
			'multi_button': self.multiplayermenu.show,
			'multi_label' : self.multiplayermenu.show,
			'settings_button': self.show_settings,
			'settings_label' : self.show_settings,
			'help_button': self.on_help,
			'help_label' : self.on_help,
			'quit_button': self.show_quit,
			'quit_label' : self.show_quit,
			'editor_button': self.show_editor_start_menu,
			'editor_label' : self.show_editor_start_menu,
			'credits_button': self.show_credits,
			'credits_label' : self.show_credits,
			'load_button': self.load_game,
			'load_label' : self.load_game,
			'changeBackground' : self.randomize_background
		})

		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)

# basic menu widgets
	def show_main(self):
		"""Shows the main menu """
		if not self._background.isVisible():
			self._background.show()

		self.hide()
		self.on_escape = self.show_quit
		self.current = self.mainmenu
		self.current.show()

	def load_game(self):
		saved_game = self.show_select_savegame(mode='load')
		if saved_game is None:
			return False # user aborted dialog

		self.show_loading_screen()
		options = StartGameOptions(saved_game)
		horizons.main.start_singleplayer(options)
		return True

# what happens on button clicks

	def save_game(self):
		"""Wrapper for saving for separating gui messages from save logic
		"""
		success = self.session.save()
		if not success:
			# There was a problem during the 'save game' procedure.
			self.show_popup(_('Error'), _('Failed to save.'))

	def show_settings(self):
		"""Displays settings gui derived from the FIFE settings module."""
		horizons.globals.fife.show_settings()

	def on_help(self):
		self.help_dialog.toggle()

	def show_quit(self):
		"""Shows the quit dialog. Closes the game unless the dialog is cancelled."""
		message = _("Are you sure you want to quit Unknown Horizons?")
		if self.show_popup(_("Quit Game"), message, show_cancel_button=True):
			horizons.main.quit()

	def quit_session(self, force=False):
		"""Quits the current session. Usually returns to main menu afterwards.
		@param force: whether to ask for confirmation"""
		message = _("Are you sure you want to abort the running session?")

		if force or self.show_popup(_("Quit Session"), message, show_cancel_button=True):
			if self.current is not None:
				# this can be None if not called from gui (e.g. scenario finished)
				self.hide()
				self.current = None
			if self.session is not None:
				self.session.end()
				self.session = None

			self.show_main()
			return True
		else:
			return False

	def show_credits(self):
		"""Shows the credits dialog. """
		widget = CreditsPickbeltWidget().get_widget()
		self.show_dialog(widget, {OkButton.DEFAULT_NAME: True})

# display

	def on_escape(self):
		pass

	def show(self):
		self.log.debug("Gui: showing current: %s", self.current)
		if self.current is not None:
			self.current.show()

	def hide(self):
		self.log.debug("Gui: hiding current: %s", self.current)
		if self.current is not None:
			self.current.hide()
			self.windows.hide_modal_background()

	def hide_all(self):
		self.hide()
		self._background.hide()

	def is_visible(self):
		return self.current is not None and self.current.isVisible()

	def show_loading_screen(self):
		self.hide()
		self.current = self.loadingscreen
		self.current.show()

	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, from_main_menu=True):
		editor_start_menu = EditorStartMenu(self, from_main_menu)
		self.hide()
		self.current = editor_start_menu
		self.current.show()
		return True
Exemple #18
0
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 __init__(self, session, gui):
		super(IngameGui, self).__init__()
		self.session = session
		assert isinstance(self.session, horizons.session.Session)
		self.main_gui = gui
		self.settlement = None
		self._old_menu = None

		self.cursor = None
		self.coordinates_tooltip = None

		self.keylistener = IngameKeyListener(self.session)

		self.cityinfo = CityInfo(self)
		LastActivePlayerSettlementManager.create_instance(self.session)

		self.message_widget = MessageWidget(self.session)

		# Windows
		self.windows = WindowManager()

		self.logbook = LogBook(self.session, self.windows)
		self.players_overview = PlayersOverview(self.session)
		self.players_settlements = PlayersSettlements(self.session)
		self.players_ships = PlayersShips(self.session)

		self.chat_dialog = ChatDialog(self.windows, self.session)
		self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
		self.pausemenu = PauseMenu(self.session, self, self.windows, in_editor_mode=False)
		self.help_dialog = HelpDialog(self.windows, session=self.session)

		# Icon manager
		self.status_icon_manager = StatusIconManager(
			renderer=self.session.view.renderer['GenericRenderer'],
			layer=self.session.view.layers[LAYERS.OBJECTS]
		)
		self.production_finished_icon_manager = ProductionFinishedIconManager(
			renderer=self.session.view.renderer['GenericRenderer'],
			layer=self.session.view.layers[LAYERS.OBJECTS]
		)

		# 'minimap' is the guichan gui around the actual minimap, which is saved
		# in self.minimap
		self.mainhud = load_uh_widget('minimap.xml')
		self.mainhud.position_technique = "right+0:top+0"

		icon = self.mainhud.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)

		self.mainhud.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.toggle_destroy_tool,
			'build' : self.show_build_menu,
			'diplomacyButton' : self.show_diplomacy_menu,
			'gameMenuButton' : self.toggle_pause,
			'logbook' : lambda: self.windows.toggle(self.logbook)
		})
		self.mainhud.show()

		self.resource_overview = ResourceOverviewBar(self.session)

		# Register for messages
		SpeedChanged.subscribe(self._on_speed_changed)
		NewDisaster.subscribe(self._on_new_disaster)
		NewSettlement.subscribe(self._on_new_settlement)
		PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
		MineEmpty.subscribe(self._on_mine_empty)
		self.session.view.add_change_listener(self._update_zoom)

		self._display_speed(self.session.timer.ticks_per_second)
Exemple #20
0
def test_trivial():
    windows = WindowManager()
    assert not windows.visible
Exemple #21
0
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.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 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)
Exemple #22
0
class IngameGui(LivingObject):
	minimap = livingProperty()
	keylistener = livingProperty()
	message_widget = livingProperty()

	def __init__(self, session):
		self.session = session

		self.cursor = None
		self.coordinates_tooltip = None
		self.keylistener = IngameKeyListener(self.session)
		# used by NavigationTool
		LastActivePlayerSettlementManager.create_instance(self.session)

		# Mocks needed to act like the real IngameGui
		self.show_menu = lambda x: 0
		self.hide_menu = lambda: 0
		# a logbook Dummy is necessary for message_widget to work
		self.logbook = DummyLogbook()

		self.mainhud = load_uh_widget('minimap.xml')
		self.mainhud.position_technique = "right+0:top+0"

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

		self.mainhud.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),
			'gameMenuButton': self.toggle_pause,
		})

		self.mainhud.show()
		ZoomChanged.subscribe(self._update_zoom)

		# Hide unnecessary buttons in hud
		for widget in ("build", "speedUp", "speedDown", "destroy_tool", "diplomacyButton", "logbook"):
			self.mainhud.findChild(name=widget).hide()

		self.windows = WindowManager()
		self.message_widget = MessageWidget(self.session)
		self.pausemenu = PauseMenu(self.session, self, self.windows, in_editor_mode=True)
		self.help_dialog = HelpDialog(self.windows)

	def end(self):
		self.mainhud.mapEvents({
			'zoomIn': None,
			'zoomOut': None,
			'rotateRight': None,
			'rotateLeft': None,
			'gameMenuButton': None
		})
		self.mainhud.hide()
		self.mainhud = None
		self._settings_tab.hide()
		self._settings_tab = None

		self.windows.close_all()
		self.minimap = None
		self.keylistener = None
		LastActivePlayerSettlementManager().remove()
		LastActivePlayerSettlementManager.destroy_instance()
		ZoomChanged.unsubscribe(self._update_zoom)

		if self.cursor:
			self.cursor.remove()
			self.cursor.end()
			self.cursor = None

		super(IngameGui, self).end()

	def handle_selection_group(self, num, ctrl_pressed):
		# Someday, maybe cool stuff will be possible here.
		# That day is not today, I'm afraid.
		pass

	def toggle_pause(self):
		self.windows.toggle(self.pausemenu)

	def toggle_help(self):
		self.windows.toggle(self.help_dialog)

	def load(self, savegame):
		self.minimap.draw()

		self.cursor = SelectionTool(self.session)

	def setup(self):
		"""Called after the world editor was initialized."""
		self._settings_tab = TabWidget(self, tabs=[SettingsTab(self.session.world_editor, self)])
		self._settings_tab.show()

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

	def show_save_map_dialog(self):
		"""Shows a dialog where the user can set the name of the saved map."""
		window = SelectSavegameDialog('editor-save', self.windows)
		savegamename = self.windows.open(window)
		if savegamename is None:
			return False # user aborted dialog
		success = self.session.save(savegamename)
		if success:
				self.message_widget.add('SAVED_GAME')

	def on_escape(self):
		pass

	def on_key_press(self, action, evt):
		_Actions = KeyConfig._Actions
		if action == _Actions.QUICKSAVE:
			self.session.quicksave()
		if action == _Actions.ESCAPE:
			if self.windows.visible:
				self.windows.on_escape()
			elif hasattr(self.cursor, 'on_escape'):
				self.cursor.on_escape()
			else:
				self.toggle_pause()
		elif action == _Actions.HELP:
			self.toggle_help()
		else:
			return False
		return True

	def set_cursor(self, which='default', *args, **kwargs):
		"""Sets the mousetool (i.e. cursor).
		This is done here for encapsulation and control over destructors.
		Further arguments are passed to the mouse tool constructor.
		"""
		self.cursor.remove()
		klass = {
			'default': SelectionTool,
			'tile_layer': TileLayingTool
		}[which]
		self.cursor = klass(self.session, *args, **kwargs)

	def _update_zoom(self, message):
		"""Enable/disable zoom buttons"""
		in_icon = self.mainhud.findChild(name='zoomIn')
		out_icon = self.mainhud.findChild(name='zoomOut')
		if message.zoom == VIEW.ZOOM_MIN:
			out_icon.set_inactive()
		else:
			out_icon.set_active()
		if message.zoom == VIEW.ZOOM_MAX:
			in_icon.set_inactive()
		else:
			in_icon.set_active()
Exemple #23
0
class Gui:
	"""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.open_popup = self.windows.open_popup
		self.open_error_popup = self.windows.open_error_popup

		self._background = 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 show_main(self):
		"""Shows the main menu"""
		GuiAction.subscribe(self._on_gui_click_action)
		GuiHover.subscribe(self._on_gui_hover_action)
		GuiCancelAction.subscribe(self._on_gui_cancel_action)

		if not self._background.visible:
			self._background.show()

		self.windows.open(self.mainmenu)

	def show_select_savegame(self, mode):
		window = SelectSavegameDialog(mode, self.windows)
		return self.windows.open(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.open(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_click_action)
		GuiHover.discard(self._on_gui_hover_action)
		GuiCancelAction.discard(self._on_gui_cancel_action)
		self.windows.close_all()
		self._background.hide()

	def show_loading_screen(self):
		if not self._background.visible:
			self._background.show()
		self.windows.open(self.loadingscreen)

	def _on_gui_click_action(self, msg):
		"""Make a sound when a button is clicked"""
		AmbientSoundComponent.play_special('click', gain=10)

	def _on_gui_cancel_action(self, msg):
		"""Make a sound when a cancelButton is clicked"""
		AmbientSoundComponent.play_special('success', gain=10)

	def _on_gui_hover_action(self, msg):
		"""Make a sound when the mouse hovers over a button"""
		AmbientSoundComponent.play_special('refresh', position=None, gain=1)

	def show_editor_start_menu(self):
		editor_start_menu = EditorStartMenu(self.windows)
		self.windows.open(editor_start_menu)
	def __init__(self, session):
		super(IngameGui, self).__init__()
		self.session = session
		assert isinstance(self.session, horizons.session.Session)
		self.settlement = None
		self._old_menu = None

		self.cursor = None
		self.coordinates_tooltip = None

		self.keylistener = IngameKeyListener(self.session)

		self.cityinfo = CityInfo(self)
		LastActivePlayerSettlementManager.create_instance(self.session)

		self.message_widget = MessageWidget(self.session)

		# Windows
		self.windows = WindowManager()
		self.show_popup = self.windows.show_popup
		self.show_error_popup = self.windows.show_error_popup

		self.logbook = LogBook(self.session, self.windows)
		self.players_overview = PlayersOverview(self.session)
		self.players_settlements = PlayersSettlements(self.session)
		self.players_ships = PlayersShips(self.session)

		self.chat_dialog = ChatDialog(self.windows, self.session)
		self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
		self.pausemenu = PauseMenu(self.session, self, self.windows, in_editor_mode=False)
		self.help_dialog = HelpDialog(self.windows, session=self.session)

		# Icon manager
		self.status_icon_manager = StatusIconManager(
			renderer=self.session.view.renderer['GenericRenderer'],
			layer=self.session.view.layers[LAYERS.OBJECTS]
		)
		self.production_finished_icon_manager = ProductionFinishedIconManager(
			renderer=self.session.view.renderer['GenericRenderer'],
			layer=self.session.view.layers[LAYERS.OBJECTS]
		)

		# 'minimap' is the guichan gui around the actual minimap, which is saved
		# in self.minimap
		self.mainhud = load_uh_widget('minimap.xml')
		self.mainhud.position_technique = "right:top"

		icon = self.mainhud.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)

		self.mainhud.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.toggle_destroy_tool,
			'build' : self.show_build_menu,
			'diplomacyButton' : self.show_diplomacy_menu,
			'gameMenuButton' : self.toggle_pause,
			'logbook' : lambda: self.windows.toggle(self.logbook)
		})
		self.mainhud.show()

		hotkey_replacements = {
			'rotateRight': 'ROTATE_RIGHT',
			'rotateLeft': 'ROTATE_LEFT',
			'speedUp': 'SPEED_UP',
			'speedDown': 'SPEED_DOWN',
			'destroy_tool': 'DESTROY_TOOL',
			'build': 'BUILD_TOOL',
			'gameMenuButton': 'ESCAPE',
			'logbook': 'LOGBOOK',
		}
		for (widgetname, action) in hotkey_replacements.iteritems():
			widget = self.mainhud.findChild(name=widgetname)
			keys = horizons.globals.fife.get_keys_for_action(action)
			# No `.upper()` here: "Pause" looks better than "PAUSE".
			keyname = HOTKEYS.DISPLAY_KEY.get(keys[0], keys[0].capitalize())
			widget.helptext = widget.helptext.format(key=keyname)

		self.resource_overview = ResourceOverviewBar(self.session)

		# Register for messages
		SpeedChanged.subscribe(self._on_speed_changed)
		NewDisaster.subscribe(self._on_new_disaster)
		NewSettlement.subscribe(self._on_new_settlement)
		PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
		MineEmpty.subscribe(self._on_mine_empty)
		ZoomChanged.subscribe(self._update_zoom)

		self._display_speed(self.session.timer.ticks_per_second)
Exemple #25
0
class IngameGui(LivingObject):
    """Class handling all the ingame gui events.
	Assumes that only 1 instance is used (class variables)"""

    message_widget = livingProperty()
    minimap = livingProperty()
    keylistener = livingProperty()

    def __init__(self, session):
        super(IngameGui, self).__init__()
        self.session = session
        assert isinstance(self.session, horizons.session.Session)
        self.settlement = None
        self._old_menu = None

        self.cursor = None
        self.coordinates_tooltip = None

        self.keylistener = IngameKeyListener(self.session)

        self.cityinfo = CityInfo(self)
        LastActivePlayerSettlementManager.create_instance(self.session)

        self.message_widget = MessageWidget(self.session)

        # Windows
        self.windows = WindowManager()
        self.show_popup = self.windows.show_popup
        self.show_error_popup = self.windows.show_error_popup

        self.logbook = LogBook(self.session, self.windows)
        self.players_overview = PlayersOverview(self.session)
        self.players_settlements = PlayersSettlements(self.session)
        self.players_ships = PlayersShips(self.session)

        self.chat_dialog = ChatDialog(self.windows, self.session)
        self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
        self.pausemenu = PauseMenu(self.session,
                                   self,
                                   self.windows,
                                   in_editor_mode=False)
        self.help_dialog = HelpDialog(self.windows, session=self.session)

        # Icon manager
        self.status_icon_manager = StatusIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])
        self.production_finished_icon_manager = ProductionFinishedIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])

        # 'minimap' is the guichan gui around the actual minimap, which is saved
        # in self.minimap
        self.mainhud = load_uh_widget('minimap.xml')
        self.mainhud.position_technique = "right:top"

        icon = self.mainhud.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)

        self.mainhud.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.toggle_destroy_tool,
            'build':
            self.show_build_menu,
            'diplomacyButton':
            self.show_diplomacy_menu,
            'gameMenuButton':
            self.toggle_pause,
            'logbook':
            lambda: self.windows.toggle(self.logbook)
        })
        self.mainhud.show()

        self.resource_overview = ResourceOverviewBar(self.session)

        # Register for messages
        SpeedChanged.subscribe(self._on_speed_changed)
        NewDisaster.subscribe(self._on_new_disaster)
        NewSettlement.subscribe(self._on_new_settlement)
        PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
        MineEmpty.subscribe(self._on_mine_empty)
        self.session.view.add_change_listener(self._update_zoom)

        self._display_speed(self.session.timer.ticks_per_second)

    def end(self):
        # unsubscribe early, to avoid messages coming in while we're shutting down
        SpeedChanged.unsubscribe(self._on_speed_changed)
        NewDisaster.unsubscribe(self._on_new_disaster)
        NewSettlement.unsubscribe(self._on_new_settlement)
        PlayerLevelUpgrade.unsubscribe(self._on_player_level_upgrade)
        MineEmpty.unsubscribe(self._on_mine_empty)
        self.session.view.remove_change_listener(self._update_zoom)

        self.mainhud.mapEvents({
            'zoomIn': None,
            'zoomOut': None,
            'rotateRight': None,
            'rotateLeft': None,
            'destroy_tool': None,
            'build': None,
            'diplomacyButton': None,
            'gameMenuButton': None
        })
        self.mainhud.hide()
        self.mainhud = None

        self.windows.close_all()
        self.message_widget = None
        self.minimap = None
        self.resource_overview.end()
        self.resource_overview = None
        self.keylistener = None
        self.cityinfo.end()
        self.cityinfo = None
        self.hide_menu()

        if self.cursor:
            self.cursor.remove()
            self.cursor.end()
            self.cursor = None

        LastActivePlayerSettlementManager().remove()
        LastActivePlayerSettlementManager.destroy_instance()

        self.production_finished_icon_manager.end()
        self.production_finished_icon_manager = None
        self.status_icon_manager.end()
        self.status_icon_manager = None

        super(IngameGui, self).end()

    def show_select_savegame(self, mode):
        window = SelectSavegameDialog(mode, self.windows)
        return self.windows.show(window)

    def toggle_pause(self):
        self.windows.toggle(self.pausemenu)

    def toggle_help(self):
        self.windows.toggle(self.help_dialog)

    def minimap_to_front(self):
        """Make sure the full right top gui is visible and not covered by some dialog"""
        self.mainhud.hide()
        self.mainhud.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.windows.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, instances):
        tab = TabWidget(self,
                        tabs=[SelectMultiTab(instances)],
                        name='select_multi')
        self.show_menu(tab)

    def show_build_menu(self, update=False):
        """
		@param update: set when build possibilities change (e.g. after inhabitant tier 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.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.set_cursor('building', cls, None if unit is None else unit())

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

    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 = 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 save(self, db):
        self.message_widget.save(db)
        self.logbook.save(db)
        self.resource_overview.save(db)
        LastActivePlayerSettlementManager().save(db)

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

        if self.session.is_game_loaded():
            LastActivePlayerSettlementManager().load(db)
            cur_settlement = LastActivePlayerSettlementManager(
            ).get_current_settlement()
            self.cityinfo.set_settlement(cur_settlement)

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

        self.current_cursor = 'default'
        self.cursor = mousetools.SelectionTool(self.session)
        # Set cursor correctly, menus might need to be opened.
        # Open menus later; they may need unit data not yet inited
        self.cursor.apply_select()

        if not self.session.is_game_loaded():
            # Fire a message for new world creation
            self.session.ingame_gui.message_widget.add('NEW_WORLD')

        # Show message when the relationship between players changed
        def notify_change(caller, old_state, new_state, a, b):
            player1 = u"%s" % a.name
            player2 = u"%s" % b.name

            data = {'player1': player1, 'player2': player2}

            string_id = 'DIPLOMACY_STATUS_{old}_{new}'.format(
                old=old_state.upper(), new=new_state.upper())
            self.message_widget.add(string_id=string_id, message_dict=data)

        self.session.world.diplomacy.add_diplomacy_status_changed_listener(
            notify_change)

    def show_change_name_dialog(self, instance):
        """Shows a dialog where the user can change the name of an object."""
        self.windows.show(self.change_name_dialog, instance=instance)

    def on_escape(self):
        if self.windows.visible:
            self.windows.on_escape()
        elif hasattr(self.cursor, 'on_escape'):
            self.cursor.on_escape()
        else:
            self.toggle_pause()

        return True

    def on_return(self):
        if self.windows.visible:
            self.windows.on_return()

        return True

    def _on_speed_changed(self, message):
        self._display_speed(message.new)

    def _display_speed(self, tps):
        text = u''
        up_icon = self.mainhud.findChild(name='speedUp')
        down_icon = self.mainhud.findChild(name='speedDown')
        if tps == 0:  # pause
            text = u'0x'
            up_icon.set_inactive()
            down_icon.set_inactive()
        else:
            if tps != GAME_SPEED.TICKS_PER_SECOND:
                text = unicode("%1gx" %
                               (tps * 1.0 / GAME_SPEED.TICKS_PER_SECOND))
                #%1g: displays 0.5x, but 2x instead of 2.0x
            index = GAME_SPEED.TICK_RATES.index(tps)
            if index + 1 >= len(GAME_SPEED.TICK_RATES):
                up_icon.set_inactive()
            else:
                up_icon.set_active()
            if index > 0:
                down_icon.set_active()
            else:
                down_icon.set_inactive()

        wdg = self.mainhud.findChild(name="speed_text")
        wdg.text = text
        wdg.resizeToContent()
        self.mainhud.show()

    def on_key_press(self, action, evt):
        """Handle a key press in-game.

		Returns True if the key was acted upon.
		"""
        _Actions = KeyConfig._Actions
        keyval = evt.getKey().getValue()

        if action == _Actions.ESCAPE:
            return self.on_escape()
        elif keyval == fife.Key.ENTER:
            return self.on_return()

        if action == _Actions.GRID:
            gridrenderer = self.session.view.renderer['GridRenderer']
            gridrenderer.setEnabled(not gridrenderer.isEnabled())
        elif action == _Actions.COORD_TOOLTIP:
            self.coordinates_tooltip.toggle()
        elif action == _Actions.DESTROY_TOOL:
            self.toggle_destroy_tool()
        elif action == _Actions.REMOVE_SELECTED:
            self.session.remove_selected()
        elif action == _Actions.ROAD_TOOL:
            self.toggle_road_tool()
        elif action == _Actions.SPEED_UP:
            SpeedUpCommand().execute(self.session)
        elif action == _Actions.SPEED_DOWN:
            SpeedDownCommand().execute(self.session)
        elif action == _Actions.PAUSE:
            TogglePauseCommand().execute(self.session)
        elif action == _Actions.PLAYERS_OVERVIEW:
            self.logbook.toggle_stats_visibility(widget='players')
        elif action == _Actions.SETTLEMENTS_OVERVIEW:
            self.logbook.toggle_stats_visibility(widget='settlements')
        elif action == _Actions.SHIPS_OVERVIEW:
            self.logbook.toggle_stats_visibility(widget='ships')
        elif action == _Actions.LOGBOOK:
            self.windows.toggle(self.logbook)
        elif action == _Actions.DEBUG and VERSION.IS_DEV_VERSION:
            import pdb
            pdb.set_trace()
        elif action == _Actions.BUILD_TOOL:
            self.show_build_menu()
        elif action == _Actions.ROTATE_RIGHT:
            if hasattr(self.cursor, "rotate_right"):
                # used in e.g. build preview to rotate building instead of map
                self.cursor.rotate_right()
            else:
                self.session.view.rotate_right()
                self.minimap.rotate_right()
        elif action == _Actions.ROTATE_LEFT:
            if hasattr(self.cursor, "rotate_left"):
                self.cursor.rotate_left()
            else:
                self.session.view.rotate_left()
                self.minimap.rotate_left()
        elif action == _Actions.CHAT:
            self.windows.show(self.chat_dialog)
        elif action == _Actions.TRANSLUCENCY:
            self.session.world.toggle_translucency()
        elif action == _Actions.TILE_OWNER_HIGHLIGHT:
            self.session.world.toggle_owner_highlight()
        elif keyval in (fife.Key.NUM_0, fife.Key.NUM_1, fife.Key.NUM_2,
                        fife.Key.NUM_3, fife.Key.NUM_4, fife.Key.NUM_5,
                        fife.Key.NUM_6, fife.Key.NUM_7, fife.Key.NUM_8,
                        fife.Key.NUM_9):
            num = int(keyval - fife.Key.NUM_0)
            if evt.isControlPressed():
                # create new group (only consider units owned by the player)
                self.session.selection_groups[num] = \
                    set(filter(lambda unit : unit.owner.is_local_player,
                               self.session.selected_instances))
                # drop units of the new group from all other groups
                for group in self.session.selection_groups:
                    if group is not self.session.selection_groups[num]:
                        group -= self.session.selection_groups[num]
            else:
                # deselect
                # we need to make sure to have a cursor capable of selection (for apply_select())
                # this handles deselection implicitly in the destructor
                self.set_cursor('selection')

                # apply new selection
                for instance in self.session.selection_groups[num]:
                    instance.get_component(SelectableComponent).select(
                        reset_cam=True)
                # assign copy since it will be randomly changed, the unit should only be changed on ctrl-events
                self.session.selected_instances = self.session.selection_groups[
                    num].copy()
                # show menu depending on the entities selected
                if self.session.selected_instances:
                    self.cursor.apply_select()
                else:
                    # nothing is selected here, we need to hide the menu since apply_select doesn't handle that case
                    self.show_menu(None)
        elif action == _Actions.QUICKSAVE:
            self.session.quicksave(
            )  # load is only handled by the MainListener
        elif action == _Actions.PIPETTE:
            # copy mode: pipette tool
            self.toggle_cursor('pipette')
        elif action == _Actions.HEALTH_BAR:
            # shows health bar of every instance with an health component
            self.session.world.toggle_health_for_all_health_instances()
        elif action == _Actions.SHOW_SELECTED:
            if self.session.selected_instances:
                # scroll to first one, we can never guarantee to display all selected units
                instance = iter(self.session.selected_instances).next()
                self.session.view.center(*instance.position.center.to_tuple())
                for instance in self.session.selected_instances:
                    if hasattr(instance,
                               "path") and instance.owner.is_local_player:
                        self.minimap.show_unit_path(instance)
        elif action == _Actions.HELP:
            self.toggle_help()
        else:
            return False

        return True

    def toggle_cursor(self, which, *args, **kwargs):
        """Alternate between the cursor which and default.
		args and kwargs are used to construct which."""
        if self.current_cursor == which:
            self.set_cursor()
        else:
            self.set_cursor(which, *args, **kwargs)

    def set_cursor(self, which='default', *args, **kwargs):
        """Sets the mousetool (i.e. cursor).
		This is done here for encapsulation and control over destructors.
		Further arguments are passed to the mouse tool constructor."""
        self.cursor.remove()
        self.current_cursor = which
        klass = {
            'default': mousetools.SelectionTool,
            'selection': mousetools.SelectionTool,
            'tearing': mousetools.TearingTool,
            'pipette': mousetools.PipetteTool,
            'attacking': mousetools.AttackingTool,
            'building': mousetools.BuildingTool,
        }[which]
        self.cursor = klass(self.session, *args, **kwargs)

    def toggle_destroy_tool(self):
        """Initiate the destroy tool"""
        self.toggle_cursor('tearing')

    def _update_zoom(self):
        """Enable/disable zoom buttons"""
        zoom = self.session.view.get_zoom()
        in_icon = self.mainhud.findChild(name='zoomIn')
        out_icon = self.mainhud.findChild(name='zoomOut')
        if zoom == VIEW.ZOOM_MIN:
            out_icon.set_inactive()
        else:
            out_icon.set_active()
        if zoom == VIEW.ZOOM_MAX:
            in_icon.set_inactive()
        else:
            in_icon.set_active()

    def _on_new_disaster(self, message):
        """Called when a building is 'infected' with a disaster."""
        if message.building.owner.is_local_player and len(
                message.disaster._affected_buildings) == 1:
            pos = message.building.position.center
            self.message_widget.add(
                point=pos, string_id=message.disaster_class.NOTIFICATION_TYPE)

    def _on_new_settlement(self, message):
        player = message.settlement.owner
        self.message_widget.add(string_id='NEW_SETTLEMENT',
                                point=message.warehouse_position,
                                message_dict={'player': player.name},
                                play_sound=player.is_local_player)

    def _on_player_level_upgrade(self, message):
        """Called when a player's population reaches a new level."""
        if not message.sender.is_local_player:
            return

        # show notification
        self.message_widget.add(point=message.building.position.center,
                                string_id='SETTLER_LEVEL_UP',
                                message_dict={'level': message.level + 1})

        # update build menu to show new buildings
        menu = self.get_cur_menu()
        if hasattr(menu, "name") and menu.name == "build_menu_tab_widget":
            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 _on_mine_empty(self, message):
        self.message_widget.add(point=message.mine.position.center,
                                string_id='MINE_EMPTY')
Exemple #26
0
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)
	def setUp(self):
		self.windows = WindowManager()
class TestWindowManager(unittest.TestCase):

	def setUp(self):
		self.windows = WindowManager()

	def test_trivial(self):
		assert not self.windows.visible

	def test_show_hide(self):
		window1 = DummyWindow(self.windows)
		self.windows.show(window1)
		assert self.windows.visible
		assert window1.visible

		window2 = DummyWindow(self.windows)
		self.windows.show(window2)
		assert self.windows.visible
		assert not window1.visible
		assert window2.visible

	def test_close(self):
		window1 = DummyWindow(self.windows)
		window2 = DummyWindow(self.windows)
		self.windows.show(window1)
		self.windows.show(window2)
		assert not window1.visible
		assert window2.visible

		self.windows.close()
		assert window1.visible
		assert not window2.visible

		self.windows.close()
		assert not window1.visible
		assert not window2.visible
		assert not self.windows.visible

	def test_toggle_single_window(self):
		window1 = DummyWindow(self.windows)
		assert not window1.visible

		self.windows.toggle(window1)
		assert window1.visible
		self.windows.toggle(window1)
		assert not window1.visible

	def test_toggle_multiple(self):
		"""
		Alternately toggle two windows and make sure we have only
		once instance of each window in the stack.
		"""
		window1 = DummyWindow(self.windows)
		window2 = DummyWindow(self.windows)
		assert not window1.visible
		assert not window2.visible

		self.windows.toggle(window1)
		assert window1.visible
		assert not window2.visible

		self.windows.toggle(window2)
		assert not window1.visible
		assert window2.visible

		self.windows.toggle(window1)
		assert window1.visible
		assert not window2.visible

		self.windows.close()
		self.windows.close()
		assert not self.windows.visible
class IngameGui(LivingObject):
    """Class handling all the ingame gui events.
	Assumes that only 1 instance is used (class variables)

	@type session: horizons.session.Session
	@param session: instance of session the world belongs to.
	"""

    message_widget = livingProperty()
    minimap = livingProperty()
    keylistener = livingProperty()

    def __init__(self, session):
        super().__init__()
        self.session = session
        assert isinstance(self.session, horizons.session.Session)
        self.settlement = None
        self._old_menu = None

        self.cursor = None
        self.coordinates_tooltip = None

        self.keylistener = IngameKeyListener(self.session)

        self.cityinfo = CityInfo(self)
        LastActivePlayerSettlementManager.create_instance(self.session)

        self.message_widget = MessageWidget(self.session)

        # Windows
        self.windows = WindowManager()
        self.open_popup = self.windows.open_popup
        self.open_error_popup = self.windows.open_error_popup

        self.logbook = LogBook(self.session, self.windows)
        self.players_overview = PlayersOverview(self.session)
        self.players_settlements = PlayersSettlements(self.session)
        self.players_ships = PlayersShips(self.session)

        self.chat_dialog = ChatDialog(self.windows, self.session)
        self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
        self.pausemenu = PauseMenu(self.session,
                                   self,
                                   self.windows,
                                   in_editor_mode=False)
        self.help_dialog = HelpDialog(self.windows)

        # Icon manager
        self.status_icon_manager = StatusIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])
        self.production_finished_icon_manager = ProductionFinishedIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])

        # 'minimap' is the guichan gui around the actual minimap, which is saved
        # in self.minimap
        self.mainhud = load_uh_widget('minimap.xml')
        self.mainhud.position_technique = "right:top"

        icon = self.mainhud.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)

        self.mainhud.mapEvents({
            'zoomIn':
            self.session.view.zoom_in,
            'zoomOut':
            self.session.view.zoom_out,
            'rotateRight':
            Callback.ChainedCallbacks(self.session.view.rotate_right,
                                      self.minimap.update_rotation),
            'rotateLeft':
            Callback.ChainedCallbacks(self.session.view.rotate_left,
                                      self.minimap.update_rotation),
            'speedUp':
            speed_up,
            'speedDown':
            speed_down,
            'destroy_tool':
            self.toggle_destroy_tool,
            'build':
            self.show_build_menu,
            'diplomacyButton':
            self.show_diplomacy_menu,
            'gameMenuButton':
            self.toggle_pause,
            'logbook':
            lambda: self.windows.toggle(self.logbook)
        })
        self.mainhud.show()

        self._replace_hotkeys_in_widgets()

        self.resource_overview = ResourceOverviewBar(self.session)

        # Register for messages
        SpeedChanged.subscribe(self._on_speed_changed)
        NewDisaster.subscribe(self._on_new_disaster)
        NewSettlement.subscribe(self._on_new_settlement)
        PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
        MineEmpty.subscribe(self._on_mine_empty)
        ZoomChanged.subscribe(self._update_zoom)
        GuiAction.subscribe(self._on_gui_click_action)
        GuiHover.subscribe(self._on_gui_hover_action)
        GuiCancelAction.subscribe(self._on_gui_cancel_action)
        # NOTE: This has to be called after the text is replaced!
        LanguageChanged.subscribe(self._on_language_changed)

        self._display_speed(self.session.timer.ticks_per_second)

    def end(self):
        # unsubscribe early, to avoid messages coming in while we're shutting down
        SpeedChanged.unsubscribe(self._on_speed_changed)
        NewDisaster.unsubscribe(self._on_new_disaster)
        NewSettlement.unsubscribe(self._on_new_settlement)
        PlayerLevelUpgrade.unsubscribe(self._on_player_level_upgrade)
        MineEmpty.unsubscribe(self._on_mine_empty)
        ZoomChanged.unsubscribe(self._update_zoom)
        GuiAction.unsubscribe(self._on_gui_click_action)
        GuiHover.unsubscribe(self._on_gui_hover_action)
        GuiCancelAction.unsubscribe(self._on_gui_cancel_action)

        self.mainhud.mapEvents({
            'zoomIn': None,
            'zoomOut': None,
            'rotateRight': None,
            'rotateLeft': None,
            'destroy_tool': None,
            'build': None,
            'diplomacyButton': None,
            'gameMenuButton': None
        })
        self.mainhud.hide()
        self.mainhud = None

        self.windows.close_all()
        self.message_widget = None
        self.minimap = None
        self.resource_overview.end()
        self.resource_overview = None
        self.keylistener = None
        self.cityinfo.end()
        self.cityinfo = None
        self.hide_menu()

        if self.cursor:
            self.cursor.remove()
            self.cursor.end()
            self.cursor = None

        LastActivePlayerSettlementManager().remove()
        LastActivePlayerSettlementManager.destroy_instance()

        self.production_finished_icon_manager.end()
        self.production_finished_icon_manager = None
        self.status_icon_manager.end()
        self.status_icon_manager = None

        super().end()

    def show_select_savegame(self, mode):
        window = SelectSavegameDialog(mode, self.windows)
        return self.windows.open(window)

    def toggle_pause(self):
        self.set_cursor('default')
        self.windows.toggle(self.pausemenu)

    def toggle_help(self):
        self.windows.toggle(self.help_dialog)

    def minimap_to_front(self):
        """Make sure the full right top gui is visible and not covered by some dialog"""
        self.mainhud.hide()
        self.mainhud.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.windows.open_popup(
                T("No diplomacy possible"),
                T("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, instances):
        tab = TabWidget(self,
                        tabs=[SelectMultiTab(instances)],
                        name='select_multi')
        self.show_menu(tab)

    def show_build_menu(self, update=False):
        """
		@param update: set when build possibilities change (e.g. after inhabitant tier 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.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.set_cursor('building', cls, None if unit is None else unit())

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

    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 = 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 save(self, db):
        self.message_widget.save(db)
        self.logbook.save(db)
        self.resource_overview.save(db)
        LastActivePlayerSettlementManager().save(db)
        self.save_selection(db)

    def save_selection(self, db):
        # Store instances that are selected right now.
        for instance in self.session.selected_instances:
            db("INSERT INTO selected (`group`, id) VALUES (NULL, ?)",
               instance.worldid)

        # If a single instance is selected, also store the currently displayed tab.
        # (Else, upon restoring, we display a multi-selection tab.)
        tabname = None
        if len(self.session.selected_instances) == 1:
            tabclass = self.get_cur_menu().current_tab
            tabname = tabclass.__class__.__name__
        db("INSERT INTO metadata (name, value) VALUES (?, ?)", 'selected_tab',
           tabname)

        # Store user defined unit selection groups (Ctrl+number)
        for (number, group) in enumerate(self.session.selection_groups):
            for instance in group:
                db("INSERT INTO selected (`group`, id) VALUES (?, ?)", number,
                   instance.worldid)

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

        if self.session.is_game_loaded():
            LastActivePlayerSettlementManager().load(db)
            cur_settlement = LastActivePlayerSettlementManager(
            ).get_current_settlement()
            self.cityinfo.set_settlement(cur_settlement)

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

        self.current_cursor = 'default'
        self.cursor = mousetools.SelectionTool(self.session)
        # Set cursor correctly, menus might need to be opened.
        # Open menus later; they may need unit data not yet inited
        self.cursor.apply_select()

        self.load_selection(db)

        if not self.session.is_game_loaded():
            # Fire a message for new world creation
            self.message_widget.add('NEW_WORLD')

        # Show message when the relationship between players changed
        def notify_change(caller, old_state, new_state, a, b):
            player1 = "{0!s}".format(a.name)
            player2 = "{0!s}".format(b.name)

            data = {'player1': player1, 'player2': player2}

            string_id = 'DIPLOMACY_STATUS_{old}_{new}'.format(
                old=old_state.upper(), new=new_state.upper())
            self.message_widget.add(string_id=string_id, message_dict=data)

        self.session.world.diplomacy.add_diplomacy_status_changed_listener(
            notify_change)

    def load_selection(self, db):
        # Re-select old selected instance
        for (instance_id,
             ) in db("SELECT id FROM selected WHERE `group` IS NULL"):
            obj = WorldObject.get_object_by_id(instance_id)
            self.session.selected_instances.add(obj)
            obj.get_component(SelectableComponent).select()

        # Re-show old tab (if there was one) or multiselection
        if len(self.session.selected_instances) == 1:
            tabname = db("SELECT value FROM metadata WHERE name = ?",
                         'selected_tab')[0][0]
            # This can still be None due to old savegames not storing the information
            tabclass = None if tabname is None else resolve_tab(tabname)
            obj.get_component(SelectableComponent).show_menu(
                jump_to_tabclass=tabclass)
        elif self.session.selected_instances:
            self.show_multi_select_tab(self.session.selected_instances)

        # Load user defined unit selection groups (Ctrl+number)
        for (num, group) in enumerate(self.session.selection_groups):
            for (instance_id, ) in db(
                    "SELECT id FROM selected WHERE `group` = ?", num):
                obj = WorldObject.get_object_by_id(instance_id)
                group.add(obj)

    def show_change_name_dialog(self, instance):
        """Shows a dialog where the user can change the name of an object."""
        self.windows.open(self.change_name_dialog, instance=instance)

    def on_escape(self):
        if self.windows.visible:
            self.windows.on_escape()
        elif hasattr(self.cursor, 'on_escape'):
            self.cursor.on_escape()
        else:
            self.toggle_pause()

        return True

    def on_return(self):
        if self.windows.visible:
            self.windows.on_return()

        return True

    def _on_speed_changed(self, message):
        self._display_speed(message.new)

    def _display_speed(self, tps):
        text = ''
        up_icon = self.mainhud.findChild(name='speedUp')
        down_icon = self.mainhud.findChild(name='speedDown')
        if tps == 0:  # pause
            text = '0x'
            up_icon.set_inactive()
            down_icon.set_inactive()
        else:
            if tps != GAME_SPEED.TICKS_PER_SECOND:
                text = "{0:1g}x".format(tps * 1.0 /
                                        GAME_SPEED.TICKS_PER_SECOND)
                #%1g: displays 0.5x, but 2x instead of 2.0x
            index = GAME_SPEED.TICK_RATES.index(tps)
            if index + 1 >= len(GAME_SPEED.TICK_RATES):
                up_icon.set_inactive()
            else:
                up_icon.set_active()
            if index > 0:
                down_icon.set_active()
            else:
                down_icon.set_inactive()

        wdg = self.mainhud.findChild(name="speed_text")
        wdg.text = text
        wdg.resizeToContent()
        self.mainhud.show()

    def on_key_press(self, action, evt):
        """Handle a key press in-game.

		Returns True if the key was acted upon.
		"""
        _Actions = KeyConfig._Actions
        keyval = evt.getKey().getValue()

        if action == _Actions.ESCAPE:
            return self.on_escape()
        elif keyval == fife.Key.ENTER:
            return self.on_return()

        if action == _Actions.GRID:
            gridrenderer = self.session.view.renderer['GridRenderer']
            gridrenderer.setEnabled(not gridrenderer.isEnabled())
        elif action == _Actions.COORD_TOOLTIP:
            self.coordinates_tooltip.toggle()
        elif action == _Actions.DESTROY_TOOL:
            self.toggle_destroy_tool()
        elif action == _Actions.REMOVE_SELECTED:
            message = T("Are you sure you want to delete these objects?")
            if self.windows.open_popup(T("Delete"),
                                       message,
                                       show_cancel_button=True):
                self.session.remove_selected()
            else:
                self.deselect_all()
        elif action == _Actions.ROAD_TOOL:
            self.toggle_road_tool()
        elif action == _Actions.SPEED_UP:
            SpeedUpCommand().execute(self.session)
        elif action == _Actions.SPEED_DOWN:
            SpeedDownCommand().execute(self.session)
        elif action == _Actions.ZOOM_IN:
            self.session.view.zoom_in()
        elif action == _Actions.ZOOM_OUT:
            self.session.view.zoom_out()
        elif action == _Actions.PAUSE:
            TogglePauseCommand().execute(self.session)
        elif action == _Actions.PLAYERS_OVERVIEW:
            self.logbook.toggle_stats_visibility(widget='players')
        elif action == _Actions.SETTLEMENTS_OVERVIEW:
            self.logbook.toggle_stats_visibility(widget='settlements')
        elif action == _Actions.SHIPS_OVERVIEW:
            self.logbook.toggle_stats_visibility(widget='ships')
        elif action == _Actions.LOGBOOK:
            self.windows.toggle(self.logbook)
        elif action == _Actions.DEBUG and VERSION.IS_DEV_VERSION:
            import pdb
            pdb.set_trace()
        elif action == _Actions.BUILD_TOOL:
            self.show_build_menu()
        elif action == _Actions.ROTATE_RIGHT:
            if hasattr(self.cursor, "rotate_right"):
                # used in e.g. build preview to rotate building instead of map
                self.cursor.rotate_right()
            else:
                self.session.view.rotate_right()
                self.minimap.update_rotation()
        elif action == _Actions.ROTATE_LEFT:
            if hasattr(self.cursor, "rotate_left"):
                self.cursor.rotate_left()
            else:
                self.session.view.rotate_left()
                self.minimap.update_rotation()
        elif action == _Actions.CHAT:
            self.windows.open(self.chat_dialog)
        elif action == _Actions.TRANSLUCENCY:
            self.session.world.toggle_translucency()
        elif action == _Actions.TILE_OWNER_HIGHLIGHT:
            self.session.world.toggle_owner_highlight()
        elif fife.Key.NUM_0 <= keyval <= fife.Key.NUM_9:
            num = int(keyval - fife.Key.NUM_0)
            self.handle_selection_group(num, evt.isControlPressed())
        elif action == _Actions.QUICKSAVE:
            self.session.quicksave()
        # Quickload is only handled by the MainListener.
        elif action == _Actions.PIPETTE:
            # Mode that allows copying buildings.
            self.toggle_cursor('pipette')
        elif action == _Actions.HEALTH_BAR:
            # Show health bar of every instance with a health component.
            self.session.world.toggle_health_for_all_health_instances()
        elif action == _Actions.SHOW_SELECTED:
            if self.session.selected_instances:
                # Scroll to first one, we can never guarantee to display all selected units.
                instance = next(iter(self.session.selected_instances))
                self.session.view.center(*instance.position.center.to_tuple())
                for instance in self.session.selected_instances:
                    if hasattr(instance,
                               "path") and instance.owner.is_local_player:
                        self.minimap.show_unit_path(instance)
        elif action == _Actions.HELP:
            self.toggle_help()
        else:
            return False

        return True

    def handle_selection_group(self, num, ctrl_pressed):
        """Select existing or assign new unit selection group.

		Ctrl+number creates or overwrites the group of number `num`
		with the currently selected units.
		Pressing the associated key selects a group and centers the
		camera around these units.
		"""
        if ctrl_pressed:
            # Only consider units owned by the player.
            units = {
                u
                for u in self.session.selected_instances
                if u.owner.is_local_player
            }
            self.session.selection_groups[num] = units
            # Drop units of the new group from all other groups.
            for group in self.session.selection_groups:
                current_group = self.session.selection_groups[num]
                if group != current_group:
                    group -= current_group
        else:
            # We need to make sure to have a cursor capable of selection
            # for apply_select() to work.
            # This handles deselection implicitly in the destructor.
            self.set_cursor('selection')
            # Apply new selection.
            for instance in self.session.selection_groups[num]:
                instance.get_component(SelectableComponent).select(
                    reset_cam=True)
            # Assign copy since it will be randomly changed in selection code.
            # The unit group itself should only be changed on Ctrl events.
            self.session.selected_instances = self.session.selection_groups[
                num].copy()
            # Show correct tabs depending on what's selected.
            if self.session.selected_instances:
                self.cursor.apply_select()
            else:
                # Nothing is selected here. Hide the menu since apply_select
                # doesn't handle that case.
                self.show_menu(None)

    def toggle_cursor(self, which):
        """Alternate between the cursor *which* and the default cursor."""
        if which == self.current_cursor:
            self.set_cursor()
        else:
            self.set_cursor(which)

    def set_cursor(self, which='default', *args, **kwargs):
        """Sets the mousetool (i.e. cursor).
		This is done here for encapsulation and control over destructors.
		Further arguments are passed to the mouse tool constructor."""
        self.cursor.remove()
        self.current_cursor = which
        klass = {
            'default': mousetools.SelectionTool,
            'selection': mousetools.SelectionTool,
            'tearing': mousetools.TearingTool,
            'pipette': mousetools.PipetteTool,
            'attacking': mousetools.AttackingTool,
            'building': mousetools.BuildingTool,
        }[which]
        self.cursor = klass(self.session, *args, **kwargs)

    def toggle_destroy_tool(self):
        """Initiate the destroy tool"""
        self.toggle_cursor('tearing')

    def _update_zoom(self, message):
        """Enable/disable zoom buttons"""
        in_icon = self.mainhud.findChild(name='zoomIn')
        out_icon = self.mainhud.findChild(name='zoomOut')
        if message.zoom == VIEW.ZOOM_MIN:
            out_icon.set_inactive()
        else:
            out_icon.set_active()
        if message.zoom == VIEW.ZOOM_MAX:
            in_icon.set_inactive()
        else:
            in_icon.set_active()

    def _on_new_disaster(self, message):
        """Called when a building is 'infected' with a disaster."""
        if message.building.owner.is_local_player and len(
                message.disaster._affected_buildings) == 1:
            pos = message.building.position.center
            self.message_widget.add(
                point=pos, string_id=message.disaster_class.NOTIFICATION_TYPE)

    def _on_new_settlement(self, message):
        player = message.settlement.owner
        self.message_widget.add(string_id='NEW_SETTLEMENT',
                                point=message.warehouse_position,
                                message_dict={'player': player.name},
                                play_sound=player.is_local_player)

    def _on_player_level_upgrade(self, message):
        """Called when a player's population reaches a new level."""
        if not message.sender.is_local_player:
            return

        # show notification
        self.message_widget.add(point=message.building.position.center,
                                string_id='SETTLER_LEVEL_UP',
                                message_dict={'level': message.level + 1})

        # update build menu to show new buildings
        menu = self.get_cur_menu()
        if hasattr(menu, "name") and menu.name == "build_menu_tab_widget":
            self.show_build_menu(update=True)

    def _on_mine_empty(self, message):
        self.message_widget.add(point=message.mine.position.center,
                                string_id='MINE_EMPTY')

    def _on_gui_click_action(self, msg):
        """Make a sound when a button is clicked"""
        AmbientSoundComponent.play_special('click', gain=10)

    def _on_gui_cancel_action(self, msg):
        """Make a sound when a cancelButton is clicked"""
        AmbientSoundComponent.play_special('success', gain=10)

    def _on_gui_hover_action(self, msg):
        """Make a sound when the mouse hovers over a button"""
        AmbientSoundComponent.play_special('refresh', position=None, gain=1)

    def _replace_hotkeys_in_widgets(self):
        """Replaces the `{key}` in the (translated) widget helptext with the actual hotkey"""
        hotkey_replacements = {
            'rotateRight': 'ROTATE_RIGHT',
            'rotateLeft': 'ROTATE_LEFT',
            'speedUp': 'SPEED_UP',
            'speedDown': 'SPEED_DOWN',
            'destroy_tool': 'DESTROY_TOOL',
            'build': 'BUILD_TOOL',
            'gameMenuButton': 'ESCAPE',
            'logbook': 'LOGBOOK',
        }
        for (widgetname, action) in hotkey_replacements.items():
            widget = self.mainhud.findChild(name=widgetname)
            keys = horizons.globals.fife.get_keys_for_action(action)
            # No `.upper()` here: "Pause" looks better than "PAUSE".
            keyname = HOTKEYS.DISPLAY_KEY.get(keys[0], keys[0].capitalize())
            widget.helptext = widget.helptext.format(key=keyname)

    def _on_language_changed(self, msg):
        """Replace the hotkeys after translation.

		NOTE: This should be called _after_ the texts are replaced. This
		currently relies on import order with `horizons.gui`.
		"""
        self._replace_hotkeys_in_widgets()
Exemple #30
0
class TestWindowManager(unittest.TestCase):

	def setUp(self):
		self.windows = WindowManager()

	def test_trivial(self):
		assert not self.windows.visible

	def test_open_hide(self):
		window1 = DummyWindow(self.windows)
		self.windows.open(window1)
		assert self.windows.visible
		assert window1.visible

		window2 = DummyWindow(self.windows)
		self.windows.open(window2)
		assert self.windows.visible
		assert not window1.visible
		assert window2.visible

	def test_close(self):
		window1 = DummyWindow(self.windows)
		window2 = DummyWindow(self.windows)
		self.windows.open(window1)
		self.windows.open(window2)
		assert not window1.visible
		assert window2.visible

		self.windows.close()
		assert window1.visible
		assert not window2.visible

		self.windows.close()
		assert not window1.visible
		assert not window2.visible
		assert not self.windows.visible

	def test_toggle_single_window(self):
		window1 = DummyWindow(self.windows)
		assert not window1.visible

		self.windows.toggle(window1)
		assert window1.visible
		self.windows.toggle(window1)
		assert not window1.visible

	def test_toggle_multiple(self):
		"""
		Alternately toggle two windows and make sure we have only
		once instance of each window in the stack.
		"""
		window1 = DummyWindow(self.windows)
		window2 = DummyWindow(self.windows)
		assert not window1.visible
		assert not window2.visible

		self.windows.toggle(window1)
		assert window1.visible
		assert not window2.visible

		self.windows.toggle(window2)
		assert not window1.visible
		assert window2.visible

		self.windows.toggle(window1)
		assert window1.visible
		assert not window2.visible

		self.windows.close()
		self.windows.close()
		assert not self.windows.visible
Exemple #31
0
class IngameGui(LivingObject):
    minimap = livingProperty()
    keylistener = livingProperty()
    message_widget = livingProperty()

    def __init__(self, session):
        self.session = session

        self.cursor = None
        self.coordinates_tooltip = None
        self.keylistener = IngameKeyListener(self.session)
        # used by NavigationTool
        LastActivePlayerSettlementManager.create_instance(self.session)

        # Mocks needed to act like the real IngameGui
        self.show_menu = Dummy
        self.hide_menu = Dummy
        # a logbook Dummy is necessary for message_widget to work
        self.logbook = Dummy()

        self.mainhud = load_uh_widget('minimap.xml')
        self.mainhud.position_technique = "right+0:top+0"

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

        self.mainhud.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),
            'gameMenuButton':
            self.toggle_pause,
        })

        self.mainhud.show()
        ZoomChanged.subscribe(self._update_zoom)

        # Hide unnecessary buttons in hud
        for widget in ("build", "speedUp", "speedDown", "destroy_tool",
                       "diplomacyButton", "logbook"):
            self.mainhud.findChild(name=widget).hide()

        self.windows = WindowManager()
        self.message_widget = MessageWidget(self.session)
        self.pausemenu = PauseMenu(self.session,
                                   self,
                                   self.windows,
                                   in_editor_mode=True)
        self.help_dialog = HelpDialog(self.windows)

    def end(self):
        self.mainhud.mapEvents({
            'zoomIn': None,
            'zoomOut': None,
            'rotateRight': None,
            'rotateLeft': None,
            'gameMenuButton': None
        })
        self.mainhud.hide()
        self.mainhud = None
        self._settings_tab.hide()
        self._settings_tab = None

        self.windows.close_all()
        self.minimap = None
        self.keylistener = None
        LastActivePlayerSettlementManager().remove()
        LastActivePlayerSettlementManager.destroy_instance()
        ZoomChanged.unsubscribe(self._update_zoom)

        if self.cursor:
            self.cursor.remove()
            self.cursor.end()
            self.cursor = None

        super(IngameGui, self).end()

    def handle_selection_group(self, num, ctrl_pressed):
        # Someday, maybe cool stuff will be possible here.
        # That day is not today, I'm afraid.
        pass

    def toggle_pause(self):
        self.windows.toggle(self.pausemenu)

    def toggle_help(self):
        self.windows.toggle(self.help_dialog)

    def load(self, savegame):
        self.minimap.draw()

        self.cursor = SelectionTool(self.session)

    def setup(self):
        """Called after the world editor was initialized."""
        self._settings_tab = TabWidget(
            self, tabs=[SettingsTab(self.session.world_editor, self)])
        self._settings_tab.show()

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

    def show_save_map_dialog(self):
        """Shows a dialog where the user can set the name of the saved map."""
        window = SelectSavegameDialog('editor-save', self.windows)
        savegamename = self.windows.open(window)
        if savegamename is None:
            return False  # user aborted dialog
        success = self.session.save(savegamename)
        if success:
            self.message_widget.add('SAVED_GAME')

    def on_escape(self):
        pass

    def on_key_press(self, action, evt):
        _Actions = KeyConfig._Actions
        if action == _Actions.QUICKSAVE:
            self.session.quicksave()
        if action == _Actions.ESCAPE:
            if self.windows.visible:
                self.windows.on_escape()
            elif hasattr(self.cursor, 'on_escape'):
                self.cursor.on_escape()
            else:
                self.toggle_pause()
        elif action == _Actions.HELP:
            self.toggle_help()
        else:
            return False
        return True

    def set_cursor(self, which='default', *args, **kwargs):
        """Sets the mousetool (i.e. cursor).
		This is done here for encapsulation and control over destructors.
		Further arguments are passed to the mouse tool constructor.
		"""
        self.cursor.remove()
        klass = {'default': SelectionTool, 'tile_layer': TileLayingTool}[which]
        self.cursor = klass(self.session, *args, **kwargs)

    def _update_zoom(self, message):
        """Enable/disable zoom buttons"""
        in_icon = self.mainhud.findChild(name='zoomIn')
        out_icon = self.mainhud.findChild(name='zoomOut')
        if message.zoom == VIEW.ZOOM_MIN:
            out_icon.set_inactive()
        else:
            out_icon.set_active()
        if message.zoom == VIEW.ZOOM_MAX:
            in_icon.set_inactive()
        else:
            in_icon.set_active()
Exemple #32
0
	def setUp(self):
		self.windows = WindowManager()
Exemple #33
0
    def __init__(self, session):
        super(IngameGui, self).__init__()
        self.session = session
        assert isinstance(self.session, horizons.session.Session)
        self.settlement = None
        self._old_menu = None

        self.cursor = None
        self.coordinates_tooltip = None

        self.keylistener = IngameKeyListener(self.session)

        self.cityinfo = CityInfo(self)
        LastActivePlayerSettlementManager.create_instance(self.session)

        self.message_widget = MessageWidget(self.session)

        # Windows
        self.windows = WindowManager()
        self.show_popup = self.windows.show_popup
        self.show_error_popup = self.windows.show_error_popup

        self.logbook = LogBook(self.session, self.windows)
        self.players_overview = PlayersOverview(self.session)
        self.players_settlements = PlayersSettlements(self.session)
        self.players_ships = PlayersShips(self.session)

        self.chat_dialog = ChatDialog(self.windows, self.session)
        self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
        self.pausemenu = PauseMenu(self.session,
                                   self,
                                   self.windows,
                                   in_editor_mode=False)
        self.help_dialog = HelpDialog(self.windows, session=self.session)

        # Icon manager
        self.status_icon_manager = StatusIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])
        self.production_finished_icon_manager = ProductionFinishedIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])

        # 'minimap' is the guichan gui around the actual minimap, which is saved
        # in self.minimap
        self.mainhud = load_uh_widget('minimap.xml')
        self.mainhud.position_technique = "right:top"

        icon = self.mainhud.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)

        self.mainhud.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.toggle_destroy_tool,
            'build':
            self.show_build_menu,
            'diplomacyButton':
            self.show_diplomacy_menu,
            'gameMenuButton':
            self.toggle_pause,
            'logbook':
            lambda: self.windows.toggle(self.logbook)
        })
        self.mainhud.show()

        self.resource_overview = ResourceOverviewBar(self.session)

        # Register for messages
        SpeedChanged.subscribe(self._on_speed_changed)
        NewDisaster.subscribe(self._on_new_disaster)
        NewSettlement.subscribe(self._on_new_settlement)
        PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
        MineEmpty.subscribe(self._on_mine_empty)
        self.session.view.add_change_listener(self._update_zoom)

        self._display_speed(self.session.timer.ticks_per_second)
    def __init__(self, session):
        super(IngameGui, self).__init__()
        self.session = session
        assert isinstance(self.session, horizons.session.Session)
        self.settlement = None
        self._old_menu = None

        self.cursor = None
        self.coordinates_tooltip = None

        self.keylistener = IngameKeyListener(self.session)

        self.cityinfo = CityInfo(self)
        LastActivePlayerSettlementManager.create_instance(self.session)

        self.message_widget = MessageWidget(self.session)

        # Windows
        self.windows = WindowManager()
        self.open_popup = self.windows.open_popup
        self.open_error_popup = self.windows.open_error_popup

        self.logbook = LogBook(self.session, self.windows)
        self.players_overview = PlayersOverview(self.session)
        self.players_settlements = PlayersSettlements(self.session)
        self.players_ships = PlayersShips(self.session)

        self.chat_dialog = ChatDialog(self.windows, self.session)
        self.change_name_dialog = ChangeNameDialog(self.windows, self.session)
        self.pausemenu = PauseMenu(self.session,
                                   self,
                                   self.windows,
                                   in_editor_mode=False)
        self.help_dialog = HelpDialog(self.windows)

        # Icon manager
        self.status_icon_manager = StatusIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])
        self.production_finished_icon_manager = ProductionFinishedIconManager(
            renderer=self.session.view.renderer['GenericRenderer'],
            layer=self.session.view.layers[LAYERS.OBJECTS])

        # 'minimap' is the guichan gui around the actual minimap, which is saved
        # in self.minimap
        self.mainhud = load_uh_widget('minimap.xml')
        self.mainhud.position_technique = "right:top"

        icon = self.mainhud.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)

        self.mainhud.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.toggle_destroy_tool,
            'build':
            self.show_build_menu,
            'diplomacyButton':
            self.show_diplomacy_menu,
            'gameMenuButton':
            self.toggle_pause,
            'logbook':
            lambda: self.windows.toggle(self.logbook)
        })
        self.mainhud.show()

        hotkey_replacements = {
            'rotateRight': 'ROTATE_RIGHT',
            'rotateLeft': 'ROTATE_LEFT',
            'speedUp': 'SPEED_UP',
            'speedDown': 'SPEED_DOWN',
            'destroy_tool': 'DESTROY_TOOL',
            'build': 'BUILD_TOOL',
            'gameMenuButton': 'ESCAPE',
            'logbook': 'LOGBOOK',
        }
        for (widgetname, action) in hotkey_replacements.iteritems():
            widget = self.mainhud.findChild(name=widgetname)
            keys = horizons.globals.fife.get_keys_for_action(action)
            # No `.upper()` here: "Pause" looks better than "PAUSE".
            keyname = HOTKEYS.DISPLAY_KEY.get(keys[0], keys[0].capitalize())
            widget.helptext = widget.helptext.format(key=keyname)

        self.resource_overview = ResourceOverviewBar(self.session)

        # Register for messages
        SpeedChanged.subscribe(self._on_speed_changed)
        NewDisaster.subscribe(self._on_new_disaster)
        NewSettlement.subscribe(self._on_new_settlement)
        PlayerLevelUpgrade.subscribe(self._on_player_level_upgrade)
        MineEmpty.subscribe(self._on_mine_empty)
        ZoomChanged.subscribe(self._update_zoom)

        self._display_speed(self.session.timer.ticks_per_second)