class SmallProductionOverviewTab(ProductionOverviewTab):
    """Only display productions for which we have a related 'field' in range.
	Requires the building class using this tab to implement get_providers().
	"""
    widget = 'overview_farm.xml'
    helptext = LazyT("Production overview")
    production_line_gui_xml = "overview_farmproductionline.xml"

    # the farm uses small buttons
    ACTIVE_PRODUCTION_ANIM_DIR = "content/gui/images/animations/cogs/small"
    BUTTON_BACKGROUND = "content/gui/images/buttons/msg_button_small.png"

    def get_displayed_productions(self):
        possible_res = {
            res
            for field in self.instance.get_providers()
            for res in field.provided_resources
        }
        all_farm_productions = self.instance.get_component(
            Producer).get_productions()
        productions = {
            p
            for p in all_farm_productions
            for res in p.get_consumed_resources().keys() if res in possible_res
        }
        return sorted(productions,
                      key=operator.methodcaller('get_production_line_id'))
class MainSquareOverviewTab(AccountTab):
	helptext = LazyT('Main square overview')

	def init_widget(self):
		super(MainSquareOverviewTab, self).init_widget()
		self.widget.child_finder('headline').text = self.settlement.get_component(NamedComponent).name
		self.widget.child_finder('headline').helptext = T('Click to change the name of your settlement')
示例#3
0
	def test_gettext_lazy(self):
		text = LazyT('McAvoy or Stewart? These timelines are confusing.')

		self.assertEqual(str(text), 'McAvoy or Stewart? These timelines are confusing.')

		change_language('de')
		self.assertEqual(str(text), 'McAvoy oder Stewart? Diese Zeitlinien sind verwirrend.')
class InventoryTab(TabInterface):
    widget = 'island_inventory.xml'
    icon_path = 'icons/tabwidget/common/inventory'
    helptext = LazyT("Settlement inventory")

    def __init__(self, instance=None):
        self.instance = instance
        super(InventoryTab, self).__init__()

    def init_widget(self):
        self.widget.child_finder('inventory').init(
            self.instance.session.db,
            self.instance.get_component(StorageComponent).inventory)

    def refresh(self):
        """This function is called by the TabWidget to redraw the widget."""
        self.widget.child_finder('inventory').update()

    def show(self):
        # run once now
        ExtScheduler().add_new_object(self.refresh, self, run_in=0, loops=1)
        # and every sec later
        ExtScheduler().add_new_object(self.refresh, self, run_in=1, loops=-1)
        super(InventoryTab, self).show()

    def hide(self):
        ExtScheduler().rem_call(self, self.refresh)
        super(InventoryTab, self).hide()
class TowerOverviewTab(OverviewTab): # defensive tower
	widget = 'overview_tower.xml'
	helptext = LazyT("Tower overview")

	def init_widget(self):
		super(TowerOverviewTab, self).init_widget()
		self.widget.findChild(name="headline").text = self.instance.settlement.get_component(NamedComponent).name
class EnemyWarehouseOverviewTab(OverviewTab):
    widget = 'overview_enemywarehouse.xml'
    helptext = LazyT("Warehouse overview")

    def init_widget(self):
        super().init_widget()
        self.widget.findChild(
            name="headline").text = self.instance.settlement.get_component(
                NamedComponent).name

    def refresh(self):
        settlement = self.instance.settlement
        self.widget.findChild(name="headline").text = settlement.get_component(
            NamedComponent).name

        selling_inventory = self.widget.findChild(name='selling_inventory')
        selling_inventory.init(
            self.instance.session.db,
            settlement.get_component(StorageComponent).inventory,
            settlement.get_component(TradePostComponent).sell_list, True)

        buying_inventory = self.widget.findChild(name='buying_inventory')
        buying_inventory.init(
            self.instance.session.db,
            settlement.get_component(StorageComponent).inventory,
            settlement.get_component(TradePostComponent).buy_list, False)

        super().refresh()
示例#7
0
class TradeShipOverviewTab(ShipOverviewTab):
	widget = 'overview_trade_ship.xml'
	icon_path = 'icons/tabwidget/ship/ship_inv'
	helptext = LazyT("Ship overview")

	def _refresh_discard_resources(self):
		if self.ship_inv.get_sum_of_stored_resources() == 0:
			self.widget.findChild(name='discard_res_bg').set_inactive()
			self.widget.findChild(name='discard_res').set_inactive()
		else:
			self.widget.findChild(name='discard_res_bg').set_active()
			self.widget.findChild(name='discard_res').set_active()

	def _discard_resources(self):
		self.ship_inv.reset_all()
		self.widget.child_finder('inventory').update()

	def refresh(self):
		super(TradeShipOverviewTab, self).refresh()
		events = {

		        'discard_res/mouseClicked': Callback(self._discard_resources)
		}
		self.widget.mapEvents(events)
		self._refresh_discard_resources()
		super(TradeShipOverviewTab, self).refresh()
示例#8
0
class BarracksSwordmanTab(BarracksSelectTab):
    icon_path = 'icons/tabwidget/barracks/swordman'
    helptext = LazyT("Swordman")

    groundunits = [
        (UNITS.SWORDSMAN, PRODUCTIONLINES.SWORDSMAN),
    ]
示例#9
0
def test_gettext_lazy():
	text = LazyT('McAvoy or Stewart? These timelines are confusing.')

	assert str(text) == 'McAvoy or Stewart? These timelines are confusing.'

	change_language('de')
	assert str(text) == 'McAvoy oder Stewart? Diese Zeitlinien sind verwirrend.'
示例#10
0
class EnemyShipOverviewTab(OverviewTab):
	widget = 'overview_enemyunit.xml'
	icon_path = 'icons/tabwidget/ship/ship_inv'
	helptext = LazyT("Ship overview")

	def init_widget(self):
		super(EnemyShipOverviewTab, self).init_widget()
		self.widget.findChild(name="headline").text = self.instance.owner.name
示例#11
0
class BoatbuilderFisherTab(BoatbuilderSelectTab):
    icon_path = 'icons/tabwidget/boatbuilder/fisher'
    helptext = LazyT("Fisher boats")

    ships = [
        #(UNITS.FISHER_BOAT, PRODUCTIONLINES.FISHING_BOAT),
        #(UNITS.CUTTER, PRODUCTIONLINES.xxx),
        #(UNITS.HERRING_FISHER, PRODUCTIONLINES.xxx),
        #(UNITS.WHALER, PRODUCTIONLINES.xxx),
    ]  # type: List[Tuple[int, int]]
示例#12
0
class SignalFireOverviewTab(OverviewTab):
    widget = 'overview_signalfire.xml'
    helptext = LazyT("Overview")

    def init_widget(self):
        super(SignalFireOverviewTab, self).init_widget()
        action_set = ActionSetLoader.get_set(self.instance._action_set_id)
        action_gfx = list(action_set.items())[0][1]
        image = list(action_gfx[45].keys())[0]
        self.widget.findChild(name="building_image").image = image
示例#13
0
class BoatbuilderTradeTab(BoatbuilderSelectTab):
    icon_path = 'icons/tabwidget/boatbuilder/trade'
    helptext = LazyT("Trade boats")

    ships = [
        (UNITS.HUKER_SHIP, PRODUCTIONLINES.HUKER),
        #(UNITS.COURIER_BOAT, PRODUCTIONLINES.xxx),
        #(UNITS.SMALL_MERCHANT, PRODUCTIONLINES.xxx),
        #(UNITS.BIG_MERCHANT, PRODUCTIONLINES.xxx),
    ]
示例#14
0
class BoatbuilderWar2Tab(BoatbuilderSelectTab):
    icon_path = 'icons/tabwidget/boatbuilder/war2'
    helptext = LazyT("War ships")

    ships = [
        #(UNITS.GALLEY, PRODUCTIONLINES.GALLEY),
        #(UNITS.BIG_GUNBOAT, PRODUCTIONLINES.BIG_GUNBOAT),
        #(UNITS.CORVETTE, PRODUCTIONLINES.CORVETTE),
        (UNITS.FRIGATE, PRODUCTIONLINES.FRIGATE),
    ]
示例#15
0
class BoatbuilderWar1Tab(BoatbuilderSelectTab):
    icon_path = 'icons/tabwidget/boatbuilder/war1'
    helptext = LazyT("War boats")

    ships = [
        #(UNITS.SMALL_GUNBOAT, PRODUCTIONLINES.SMALL_GUNBOAT),
        #(UNITS.NAVAL_CUTTER, PRODUCTIONLINES.NAVAL_CUTTER),
        #(UNITS.BOMBADIERE, PRODUCTIONLINES.BOMBADIERE),
        #(UNITS.SLOOP_O_WAR, PRODUCTIONLINES.SLOOP_O_WAR),
    ]  # type: List[Tuple[int, int]]
示例#16
0
class InventoryFullStatus(StatusIcon):
    priority = 1200
    icon = 'as_inventory_full+idle+45'
    helptext = LazyT("The inventory of this building is full.")

    def __init__(self, instance, reslist):
        """
		@param reslist: list of integers describing the resources
		"""
        super(InventoryFullStatus, self).__init__(instance)
        self.reslist = reslist
示例#17
0
class BoatbuilderConfirmTab(ProducerOverviewTabBase):
    widget = 'boatbuilder_confirm.xml'
    helptext = LazyT("Confirm order")

    def init_widget(self):
        super().init_widget()
        events = {'create_unit': self.start_production}
        self.widget.mapEvents(events)

    def start_production(self):
        AddProduction(self.producer, 15).execute(self.instance.session)
示例#18
0
    def __init__(self, instance):
        self.max_inhabitants = instance.session.db.get_tier_inhabitants_max(
            self.__class__.LEVEL)
        self.min_inhabitants = instance.session.db.get_tier_inhabitants_min(
            self.__class__.LEVEL)
        self.helptext = LazyT(
            instance.session.db.get_settler_name(self.__class__.LEVEL))

        icon_path = 'icons/tabwidget/mainsquare/inhabitants{tier}'.format(
            tier=self.__class__.LEVEL)
        super().__init__(instance=instance, icon_path=icon_path)
示例#19
0
	def _init_settings(self):
		"""Init the settings with the stored values."""
		languages = list(find_available_languages().keys())
		language_names = [LANGUAGENAMES[x] for x in sorted(languages)]

		fps = {0: LazyT("Disabled"), 30: 30, 45: 45, 60: 60, 90: 90, 120: 120}

		FIFE = SETTINGS.FIFE_MODULE
		UH = SETTINGS.UH_MODULE

		def get_resolutions():
			return get_screen_resolutions(self._settings.get(FIFE, 'ScreenResolution'))

		self._options = [
			# Graphics/Sound/Input
			Setting(FIFE, 'ScreenResolution', 'screen_resolution', get_resolutions, restart=True),
			Setting(FIFE, 'FullScreen', 'enable_fullscreen', restart=True),
			Setting(FIFE, 'FrameLimit', 'fps_rate', fps, restart=True, callback=self._apply_FrameLimit),

			Setting(UH, 'VolumeMusic', 'volume_music', callback=self._apply_VolumeMusic,
				on_change=self._on_slider_changed),
			Setting(UH, 'VolumeEffects', 'volume_effects', callback=self._apply_VolumeEffects,
				on_change=self._on_slider_changed),
			Setting(FIFE, 'PlaySounds', 'enable_sound', callback=self._apply_PlaySounds),
			Setting(UH, 'EdgeScrolling', 'edgescrolling'),
			Setting(UH, 'CursorCenteredZoom', 'cursor_centered_zoom'),
			Setting(UH, 'MiddleMousePan', 'middle_mouse_pan'),
			Setting(FIFE, 'MouseSensitivity', 'mousesensitivity', restart=True,
				on_change=self._on_slider_changed),

			# Game
			Setting(UH, 'AutosaveInterval', 'autosaveinterval', on_change=self._on_slider_changed),
			Setting(UH, 'AutosaveMaxCount', 'autosavemaxcount', on_change=self._on_slider_changed),
			Setting(UH, 'QuicksaveMaxCount', 'quicksavemaxcount', on_change=self._on_slider_changed),
			Setting(UH, 'Language', 'uni_language', language_names,
				callback=self._apply_Language, on_change=self._on_Language_changed),

			Setting(UH, 'MinimapRotation', 'minimaprotation'),
			Setting(UH, 'UninterruptedBuilding', 'uninterrupted_building'),
			Setting(UH, 'AutoUnload', 'auto_unload'),
			Setting(UH, 'DebugLog', 'debug_log', callback=self._apply_DebugLog),
			Setting(UH, 'ShowResourceIcons', 'show_resource_icons'),
			Setting(UH, 'ScrollSpeed', 'scrollspeed', on_change=self._on_slider_changed),
			Setting(UH, 'QuotesType', 'quotestype', QUOTES_SETTINGS),
			Setting(UH, 'NetworkPort', 'network_port', callback=self._apply_NetworkPort),
		]

		self._fill_widgets()

		# key configuration
		self.hotkey_interface = HotkeyConfiguration()
		number = self.sections.index(('hotkeys_settings', T('Hotkeys')))
		self.page_widgets[number].removeAllChildren()
		self.page_widgets[number].addChild(self.hotkey_interface.widget)
示例#20
0
class BarrierOverviewTab(OverviewTab):
    widget = 'overview_barrier.xml'
    helptext = LazyT("Overview")

    def init_widget(self):
        super(BarrierOverviewTab, self).init_widget()
        action_set = ActionSetLoader.get_sets()[self.instance._action_set_id]
        action_gfx = action_set.get('single', 'abcd')
        image = action_gfx[45].keys()[0]
        self.widget.findChild(name="building_image").image = image
        health_widget = self.widget.findChild(name='health')
        health_widget.init(self.instance)
        self.add_remove_listener(health_widget.remove)
class AccountTab(MainSquareTab):
	"""Display basic income and expenses of a settlement"""
	widget = 'tab_account.xml'
	icon_path = 'icons/tabwidget/warehouse/account'
	helptext = LazyT("Account")

	def init_widget(self):
		super(AccountTab, self).init_widget()
		self.widget.mapEvents({
		  'show_production_overview/mouseClicked': self.show_production_overview,
		})

		# FIXME having to access the WindowManager this way is pretty ugly
		self._windows = self.instance.session.ingame_gui.windows
		self.prod_overview = ProductionOverview(self._windows, self.settlement)

		self.widget.child_finder('headline').text = self.settlement.get_component(NamedComponent).name
		self.widget.child_finder('headline').helptext = T('Click to change the name of your settlement')

		path = 'icons/widgets/cityinfo/settlement_{}'.format(self.settlement.owner.color.name)
		self.widget.child_finder('show_production_overview').path = path

	def show_production_overview(self):
		self._windows.toggle(self.prod_overview)

	def refresh(self):
		super(AccountTab, self).refresh()
		self.refresh_collector_utilization()
		taxes = self.settlement.cumulative_taxes
		running_costs = self.settlement.cumulative_running_costs
		buy_expenses = self.settlement.get_component(TradePostComponent).buy_expenses
		sell_income = self.settlement.get_component(TradePostComponent).sell_income
		balance = self.settlement.balance
		sign = '+' if balance >= 0 else '-'
		self.widget.child_finder('taxes').text = str(taxes)
		self.widget.child_finder('running_costs').text = str(running_costs)
		self.widget.child_finder('buying').text = str(buy_expenses)
		self.widget.child_finder('sale').text = str(sell_income)
		self.widget.child_finder('balance').text = str(sign + ' ' + str(abs(balance)))
		self.widget.child_finder('headline').text = self.settlement.get_component(NamedComponent).name
		rename = Callback(self.instance.session.ingame_gui.show_change_name_dialog, self.settlement)
		self.widget.mapEvents({'headline': rename})

	def refresh_collector_utilization(self):
		if self.instance.has_component(CollectingComponent):
			utilization = int(round(self.instance.get_collector_utilization() * 100))
			utilization = str(utilization) + '%'
		else:
			utilization = '---'
		self.widget.findChild(name="collector_utilization").text = utilization
示例#22
0
class GroundUnitOverviewTab(OverviewTab):
    widget = 'overview_groundunit.xml'
    helptext = LazyT("Unit overview")

    has_stance = True

    def init_widget(self):
        super(GroundUnitOverviewTab, self).init_widget()
        health_widget = self.widget.findChild(name='health')
        health_widget.init(self.instance)
        self.add_remove_listener(health_widget.remove)
        weapon_storage_widget = self.widget.findChild(name='weapon_storage')
        weapon_storage_widget.init(self.instance)
        self.add_remove_listener(weapon_storage_widget.remove)
示例#23
0
	def _strip_translation_marks(self, string):
		"""Converts object translation `string` to translated object for in-game display.

		Object properties supposed to be translated are recognized by the
		(subsequently stripped) leading `_ `.
		If `string` is supposed to be translated, returns lazy translation object of `string`.
		If `string` is not supposed to be translated, returns `string` unchanged.
		If `string` is None (not defined or empty in yaml), returns empty unicode.
		"""
		if not string:
			return u''
		if string.startswith("_ "):
			return LazyT(string[2:])
		else:
			return string
示例#24
0
class LogBook(PickBeltWidget, Window):
	"""Implementation of the logbook as described here:
	http://wiki.unknown-horizons.org/w/Message_System

	It displays longer messages, which are essential for scenarios.
	Headings can be specified for each entry.
	"""
	log = logging.getLogger('gui.widgets.logbook')

	widget_xml = 'captains_log.xml'
	page_pos = (170, 38)
	sections = (('logbook', LazyT('Logbook')),
	            ('statistics', LazyT('Statistics')),
	            ('chat_overview', LazyT('Chat')))

	def __init__(self, session, windows):
		self.statistics_index = [i for i, sec in self.sections].index('statistics')
		self.logbook_index = [i for i, sec in self.sections].index('logbook')
		self._page_ids = {} # dict mapping self._cur_entry to message.msgcount
		super().__init__()
		self.session = session
		self._windows = windows
		self._parameters = [] # list of lists of all parameters added to a logbook page
		self._message_log = [] # list of all messages that have been displayed
		self._messages_to_display = [] # list messages to display on page close
		self._displayed_messages = [] # list of messages that were already displayed
		self._cur_entry = 0 # remember current location; 0 to len(messages)-1
		self._hiding_widget = False # True if and only if the widget is currently in the process of being hidden
		self.stats_visible = None
		self.last_stats_widget = 'players'
		self.current_mode = 0 # used to determine if the logbook is on the statistics page
		self._init_gui()

#		self.add_captainslog_entry([
#		  ['Headline', "Heading"],
#		  ['Image', "content/gui/images/background/hr.png"],
#		  ['Label', "Welcome to the Captain's log"],
#		  ['Label', "\n\n"],
#			]) # test code

	def _init_gui(self):
		"""Initial gui setup for all subpages accessible through pickbelts."""
		self._gui = self.get_widget()
		self._gui.mapEvents({
		  OkButton.DEFAULT_NAME : self._windows.close,
		  'backwardButton' : Callback(self._scroll, -2),
		  'forwardButton' : Callback(self._scroll, 2),
		  'stats_players' : Callback(self.show_statswidget, widget='players'),
		  'stats_settlements' : Callback(self.show_statswidget, widget='settlements'),
		  'stats_ships' : Callback(self.show_statswidget, widget='ships'),
		  'chatTextField' : self._send_chat_message,
		  })

		# stuff in the game message / chat history subwidget
		self.textfield = self._gui.findChild(name="chatTextField")
		self.textfield.capture(self._chatfield_onfocus, 'mouseReleased', 'default')
		self.chatbox = self._gui.findChild(name="chatbox")
		self.messagebox = self._gui.findChild(name="game_messagebox")
		#self._display_chat_history() # initially print all loaded messages
		#self._display_message_history()

		# these buttons flip pages in the captain's log if there are more than two
		self.backward_button = self._gui.findChild(name="backwardButton")
		self.forward_button = self._gui.findChild(name="forwardButton")
		self._redraw_captainslog()

	def update_view(self, number=0):
		""" update_view from PickBeltWidget, cleaning up the logbook subwidgets
		"""
		self.current_mode = number

		# self.session might not exist yet during callback setup for pickbelts
		if hasattr(self, 'session'):
			self._hide_statswidgets()
		if self.statistics_index == number:
			self.show_statswidget(self.last_stats_widget)
		super().update_view(number)

	def save(self, db):
		db("INSERT INTO logbook(widgets) VALUES(?)", json.dumps(self._parameters))
		for message in self._message_log:
			db("INSERT INTO logbook_messages(message) VALUES(?)", message)
		db("INSERT INTO metadata(name, value) VALUES(?, ?)",
		   "logbook_cur_entry", self._cur_entry)

	def load(self, db):
		db_data = db("SELECT widgets FROM logbook")
		widget_list = json.loads(db_data[0][0] if db_data else "[]")
		for widgets in widget_list:
			self.add_captainslog_entry(widgets, show_logbook=False)

		for msg in db("SELECT message FROM logbook_messages"):
			self._message_log.append(msg[0]) # each line of the table is one tuple
		# wipe self._messages_to_display on load, otherwise all previous messages get displayed
		self._messages_to_display = []
		self._displayed_messages = []

		value = db('SELECT value FROM metadata WHERE name = "logbook_cur_entry"')
		if (value and value[0] and value[0][0]):
			self.set_cur_entry(int(value[0][0])) # this also redraws

		self.display_messages()

	def show(self, msg_id=None):
		if not hasattr(self, '_gui'):
			self._init_gui()
		if msg_id:
			self._cur_entry = self._page_ids[msg_id]
		if not self.is_visible():
			self._gui.show()
			self._redraw_captainslog()
			if self.current_mode == self.statistics_index:
				self.show_statswidget(self.last_stats_widget)

	def display_messages(self):
		"""Display all messages in self._messages_to_display and map the to the current logbook page"""
		for message in self._messages_to_display:
			if message in self._displayed_messages:
				continue
			for msg_id in show_message(self.session, "logbook", message):
				self._page_ids[msg_id] = self._cur_entry
				self._displayed_messages.append(message)

	def hide(self):
		if not self._hiding_widget:
			self._hiding_widget = True
			self._hide_statswidgets()
			self._gui.hide()
			self._hiding_widget = False

			self.display_messages()
			self._message_log.extend(self._messages_to_display)
			self._messages_to_display = []
		# Make sure the game is unpaused always and in any case
		UnPauseCommand(suggestion=False).execute(self.session)

	def is_visible(self):
		return hasattr(self, '_gui') and self._gui.isVisible()

	def _redraw_captainslog(self):
		"""Redraws gui. Necessary when current message has changed."""
		if self._parameters: # there is something to display if this has items
			self._display_parameters_on_page(self._parameters[self._cur_entry], 'left')
			if self._cur_entry + 1 < len(self._parameters): # check for content on right page
				self._display_parameters_on_page(self._parameters[self._cur_entry + 1], 'right')
			else:
				self._display_parameters_on_page([], 'right') # display empty page
		else:
			self._display_parameters_on_page([
			  ['Headline', T("Emptiness")],
			  ['Image', "content/gui/images/background/hr.png"],
			  ['Label', "\n\n"],
			  ['Label', T('There is nothing written in your logbook yet!')],
				], 'left')
		self.backward_button.set_active()
		self.forward_button.set_active()
		if not self._parameters or self._cur_entry == 0:
			self.backward_button.set_inactive()
		if not self._parameters or self._cur_entry >= len(self._parameters) - 2:
			self.forward_button.set_inactive()
		self._gui.adaptLayout()


########
#        LOGBOOK  SUBWIDGET
########

	def parse_logbook_item(self, parameter):
		# Some error checking for widgets that are to be loaded.
		# This happens, for example, with outdated YAML stored in old
		# scenario savegames. Instead of crashing, display nothing.
		def _icon(image):
			try:
				# Pychan can only use str objects as file path.
				# json.loads() however returns unicode.
				return Icon(image=str(image))
			except fife.NotFound:
				return None

		def _label(text, font='default'):
			try:
				return Label(text=str(text), wrap_text=True,
				             min_size=(325, 0), max_size=(325, 1024),
				             font=font)
			except InitializationError:
				return None

		if parameter and parameter[0]: # allow empty Labels
			parameter_type = parameter[0]
		if isinstance(parameter, str):
			add = _label(parameter)
		elif parameter_type == 'Label':
			add = _label(parameter[1])
		elif parameter_type == 'Image':
			add = _icon(parameter[1])
		elif parameter_type == 'Gallery':
			add = HBox()
			for image in parameter[1]:
				new_icon = _icon(image)
				if new_icon is not None:
					add.addChild(new_icon)
		elif parameter_type == 'Headline':
			add = HBox()
			is_not_last_headline = self._parameters and self._cur_entry is not None and self._cur_entry < (len(self._parameters) - 2)
			if is_not_last_headline:
				add.addChild(_icon("content/gui/images/tabwidget/done.png"))
			add.addChild(_label(parameter[1], font='headline'))
		elif parameter_type == 'BoldLabel':
			add = _label(parameter[1], font='default_bold')
		elif parameter_type == 'Message':
			add = None
			# parameters are re-read on page reload.
			# duplicate_message stops messages from
			# being duplicated on page reload.
			message = parameter[1]
			# message is already going to be displayed or has been displayed
			# before (e.g. re-opening older logbook pages)
			duplicate_message = (message in self._messages_to_display or
								message in self._message_log)

			if not duplicate_message:
				self._messages_to_display.append(message) # the new message has not been displayed
		else:
			self.log.warning('Unknown parameter type %s in parameter %s',
			                 parameter[0], parameter)
			add = None
		return add

	def _display_parameters_on_page(self, parameters, page):
		"""
		@param parameters: parameter list, cf. docstring of add_captainslog_entry
		@param page: 'left' or 'right'
		"""
		parameterbox = self._gui.findChild(name="custom_widgets_{page}".format(page=page))
		parameterbox.removeAllChildren()
		for parameter_definition in parameters:
			add = self.parse_logbook_item(parameter_definition)
			if add is not None:
				parameterbox.addChild(add)

	def add_captainslog_entry(self, parameters, show_logbook=True):
		"""Adds an entry to the logbook VBoxes consisting of a parameter list.
		Check e.g. content/scenarios/tutorial_en.yaml for real-life usage.

		@param parameters: Each item in here is a list like the following:
		[Label, "Awesome text to be displayed as a label"]
		"Shortcut notation for a Label"
		[Headline, "Label to be styled as headline (in small caps)"]
		[BoldLabel, "Like Label but with bold font, use to highlight lines"]
		[Image, "content/gui/images/path/to/the/file.png"]
		[Gallery, ["/path/1.png", "/path/file.png", "/file/3.png"]]
		[Message, "Text to display as a notification on logbook close"]
		[Pagebreak]
		"""
		#TODO last line of message text sometimes get eaten. Ticket #535
		def _split_on_pagebreaks(parameters):
			"""This black magic splits the parameter list on each ['Pagebreak']
			>> [['a','a'], ['b','b'], ['Pagebreak'], ['c','c'], ['d','d']]
			>>>> into [[['a', 'a'], ['b', 'b']], [['c', 'c'], ['d', 'd']]]
			#TODO n successive pagebreaks should insert (n-1) blank pages (currently 0 are inserted)
			"""
			return [list(l[1]) for l in groupby(parameters, lambda x: x != ['Pagebreak']) if l[0]]

		# If a scenario goal has been completed, remove the corresponding message
		for message in self._displayed_messages:
			self.session.ingame_gui.message_widget.remove(message)

		self._displayed_messages = [] # Reset displayed messages
		for parameter_list in _split_on_pagebreaks(parameters):
			self._parameters.append(parameter_list)
			for parameter_definition in parameter_list:
				self.parse_logbook_item(parameter_definition)
		# if a new entry contains more than one page, we want to display the first
		# unread message. note that len(parameters) starts at 1 and _cur_entry at 0.
		# position always refers to the left page, so only multiples of 2 are valid
		len_old = len(self._parameters) - len(_split_on_pagebreaks(parameters))
		if len_old % 2 == 1: # uneven amount => empty last page, space for 1 new
			self._cur_entry = len_old - 1
		else: # even amount => all pages filled. we could display two new messages
			self._cur_entry = len_old
		if show_logbook and hasattr(self, "_gui"):
			self._redraw_captainslog()
			self._windows.open(self)
			self.show_logbookwidget()

	def clear(self):
		"""Remove all entries"""
		self._parameters = []
		self._cur_entry = 0

	def get_cur_entry(self):
		return self._cur_entry

	def set_cur_entry(self, cur_entry):
		if cur_entry < 0 or (cur_entry >= len(self._parameters) and len(self._parameters) != 0):
			raise ValueError("ERROR: Logbook entry out of Logbook bounds. This should never happen.")
		self._cur_entry = cur_entry
		self._redraw_captainslog()

	def _scroll(self, direction):
		"""Scroll back or forth one message.
		@param direction: -1 or 1"""
		if not self._parameters:
			return
		new_cur = self._cur_entry + direction
		if new_cur < 0 or new_cur >= len(self._parameters):
			return # invalid scroll
		self._cur_entry = new_cur
		AmbientSoundComponent.play_special('flippage')
		self._redraw_captainslog()

	def show_logbookwidget(self):
		"""Shows logbook with Logbook page selected"""
		if self.current_mode != self.logbook_index:
			self.update_view(self.logbook_index)

########
#        STATISTICS  SUBWIDGET
########
#
#TODO list:
#  [ ] Extract this stuff to extra widget class that properly handles all the
#      hide and save calls
#  [ ] fix stats show/hide mess: how is update_view called before self.__init__
#  [ ] save last shown stats widget and re-show it when clicking on Statistics
#  [ ] semantic distinction between general widget and subwidgets (log, stats)
#
########

	def show_statswidget(self, widget='players'):
		"""Shows logbook with Statistics page selected"""
		if self.current_mode != self.statistics_index:
			self.update_view(self.statistics_index)
		self._hide_statswidgets()
		if widget:
			getattr(self, '_show_{widget}'.format(widget=widget))()
			self.stats_visible = widget
			self.last_stats_widget = widget

	def toggle_stats_visibility(self, widget='players'):
		"""
		Only hides logbook if hotkey of current stats selection pressed.
		Otherwise, switch to displaying the new widget instead of hiding.
		@param widget: 'players' or 'settlements' or 'ships'
		"""
		# we're treating every statswidget as a separate window, so if the stats change,
		# close the logbook and reopen it with a different active widget
		if self.stats_visible != widget:
			if self.stats_visible:
				self._windows.close()

			self._windows.open(self)
			self.show_statswidget(widget=widget)
		else:
			self._windows.close()

	def _show_ships(self):
		self.session.ingame_gui.players_ships.show()

	def _show_settlements(self):
		self.session.ingame_gui.players_settlements.show()

	def _show_players(self):
		self.session.ingame_gui.players_overview.show()

	def _hide_statswidgets(self):
		statswidgets = [
		  self.session.ingame_gui.players_overview,
		  self.session.ingame_gui.players_ships,
		  self.session.ingame_gui.players_settlements,
		  ]
		for statswidget in statswidgets:
			# we don't care which one is shown currently (if any), just hide all of them
			statswidget.hide()
		self.stats_visible = None


########
#        MESSAGE  AND  CHAT  HISTORY  SUBWIDGET
########
#
#TODO list:
#  [ ] use message bus to check for new updates
#  [ ] only display new message on update, not reload whole history
#  [x] update message history on new game messages. not on sending a chat line
#  [ ] implement word wrapping for message history display
#
########

	def _send_chat_message(self):
		"""Sends a chat message. Called when user presses enter in the input field"""
		msg = self.textfield.text
		if msg:
			Chat(msg).execute(self.session)
			self.textfield.text = ''
		self._display_chat_history()

	def display_message_history(self):
		self.messagebox.items = []
		messages = self.session.ingame_gui.message_widget.active_messages + \
		        self.session.ingame_gui.message_widget.archive
		for msg in sorted(messages, key=lambda m: m.created):
			if msg.id != 'CHAT': # those get displayed in the chat window instead
				self.messagebox.items.append(msg.message)
		self.messagebox.selected = len(self.messagebox.items) - 1 # scroll to bottom

	def _display_chat_history(self):
		self.chatbox.items = []
		messages = self.session.ingame_gui.message_widget.chat
		for msg in sorted(messages, key=lambda m: m.created):
			self.chatbox.items.append(msg.message)
		self.chatbox.selected = len(self.chatbox.items) - 1 # scroll to bottom

	def _chatfield_onfocus(self):
		"""Removes text in chat input field when it gets focused."""
		self.textfield.text = ''
		self.textfield.capture(None, 'mouseReleased', 'default')
class BuildRelatedTab(OverviewTab):
    """
	Adds a special tab to each production building with at least one entry in
	the table related_buildings. This tab acts as modified build menu tab and
	only displays those buildings actually related to the selected building.
	Examples: tree for lumberjack; pavilion, school, etc. for inhabitants.
	"""
    widget = 'related_buildings.xml'
    icon_path = 'icons/tabwidget/production/related'
    helptext = LazyT("Build related buildings")
    template_gui_xml = 'related_buildings_container.xml'

    def refresh(self):
        """
		This function is called by the TabWidget to redraw the widget.
		"""
        # remove old data
        parent_container = self.widget.child_finder('related_buildings')
        while parent_container.children:
            parent_container.removeChild(parent_container.children[0])

        # load all related buildings from DB
        building_ids = self.instance.session.db.get_related_building_ids_for_menu(
            self.instance.id)
        sorted_ids = sorted([(b, Entities.buildings[b].settler_level)
                             for b in building_ids],
                            key=lambda x: x[1])
        container = self.__get_new_container()
        for i, (building_id, level) in enumerate(sorted_ids):
            if level > self.instance.owner.settler_level:
                break

            button = self._create_build_buttons(building_id, container)
            # check whether to start new line (currently only 4 fit per line)
            if i and i % 4 == 0:
                parent_container.addChild(container)
                container = self.__get_new_container()
            container.findChild(name="build_button_container").addChild(button)
            button_bg = Icon(
                image="content/gui/images/buttons/buildmenu_button_bg.png")
            container.findChild(
                name="build_button_bg_container").addChild(button_bg)
        # Still need to add last container
        parent_container.addChild(container)
        super(BuildRelatedTab, self).refresh()

    def __get_new_container(self):
        """
		Loads a background container xml file. Returns the loaded widget.
		"""
        gui = load_uh_widget(self.template_gui_xml)
        return gui.findChild(name="buildings_container")

    def _create_build_buttons(self, building_id, container):
        # {{mode}} in double braces because it is replaced as a second step
        building_type = Entities.buildings[building_id]
        build_button = ImageButton(name="build{id}".format(id=building_id),
                                   helptext=building_type.get_tooltip())
        build_button.path = "icons/buildmenu/{id:03d}".format(id=building_id)
        build_button.capture(Callback(self.build_related, building_id))
        return build_button

    def build_related(self, building_id):
        self.hide()
        # deselect all
        for instance in self.instance.session.selected_instances:
            instance.get_component(SelectableComponent).deselect()
        self.instance.session.selected_instances.clear()

        self.instance.session.ingame_gui.set_cursor(
            'building',
            Entities.buildings[building_id],
            ship=None,
            build_related=self.instance)
示例#26
0
class SettingsDialog(PickBeltWidget, Window):
    """Widget for Options dialog with pickbelt style pages"""

    widget_xml = 'settings.xml'
    sections = (
        ('graphics_settings', LazyT('Graphics')),
        ('hotkeys_settings', LazyT('Hotkeys')),
        ('game_settings', LazyT('Game')),
    )

    def __init__(self, windows):
        Window.__init__(self, windows)
        PickBeltWidget.__init__(self)

        self._settings = horizons.globals.fife._setting

        self.widget.mapEvents({
            'okButton': self.apply_settings,
            'defaultButton': self.set_defaults,
            'cancelButton': self._windows.close,
        })

    def _init_settings(self):
        """Init the settings with the stored values."""
        languages = list(find_available_languages().keys())
        language_names = [LANGUAGENAMES[x] for x in sorted(languages)]

        fps = {0: LazyT("Disabled"), 30: 30, 45: 45, 60: 60, 90: 90, 120: 120}

        FIFE = SETTINGS.FIFE_MODULE
        UH = SETTINGS.UH_MODULE

        def get_resolutions():
            return get_screen_resolutions(
                self._settings.get(FIFE, 'ScreenResolution'))

        self._options = [
            # Graphics/Sound/Input
            Setting(FIFE,
                    'ScreenResolution',
                    'screen_resolution',
                    get_resolutions,
                    restart=True),
            Setting(FIFE, 'FullScreen', 'enable_fullscreen', restart=True),
            Setting(FIFE,
                    'FrameLimit',
                    'fps_rate',
                    fps,
                    restart=True,
                    callback=self._apply_FrameLimit),
            Setting(UH,
                    'VolumeMusic',
                    'volume_music',
                    callback=self._apply_VolumeMusic,
                    on_change=self._on_slider_changed),
            Setting(UH,
                    'VolumeEffects',
                    'volume_effects',
                    callback=self._apply_VolumeEffects,
                    on_change=self._on_slider_changed),
            Setting(FIFE,
                    'PlaySounds',
                    'enable_sound',
                    callback=self._apply_PlaySounds),
            Setting(UH, 'EdgeScrolling', 'edgescrolling'),
            Setting(UH, 'CursorCenteredZoom', 'cursor_centered_zoom'),
            Setting(UH, 'MiddleMousePan', 'middle_mouse_pan'),
            Setting(FIFE,
                    'MouseSensitivity',
                    'mousesensitivity',
                    restart=True,
                    on_change=self._on_slider_changed),

            # Game
            Setting(UH,
                    'AutosaveInterval',
                    'autosaveinterval',
                    on_change=self._on_slider_changed),
            Setting(UH,
                    'AutosaveMaxCount',
                    'autosavemaxcount',
                    on_change=self._on_slider_changed),
            Setting(UH,
                    'QuicksaveMaxCount',
                    'quicksavemaxcount',
                    on_change=self._on_slider_changed),
            Setting(UH,
                    'Language',
                    'uni_language',
                    language_names,
                    callback=self._apply_Language,
                    on_change=self._on_Language_changed),
            Setting(UH, 'UninterruptedBuilding', 'uninterrupted_building'),
            Setting(UH, 'AutoUnload', 'auto_unload'),
            Setting(UH, 'DebugLog', 'debug_log',
                    callback=self._apply_DebugLog),
            Setting(UH, 'ShowResourceIcons', 'show_resource_icons'),
            Setting(UH,
                    'ScrollSpeed',
                    'scrollspeed',
                    on_change=self._on_slider_changed),
            Setting(UH, 'QuotesType', 'quotestype', QUOTES_SETTINGS),
            Setting(UH,
                    'NetworkPort',
                    'network_port',
                    callback=self._apply_NetworkPort),
        ]

        self._fill_widgets()

        # key configuration
        self.hotkey_interface = HotkeyConfiguration()
        number = self.sections.index(('hotkeys_settings', T('Hotkeys')))
        self.page_widgets[number].removeAllChildren()
        self.page_widgets[number].addChild(self.hotkey_interface.widget)

    def show(self):
        self._init_settings()
        self.widget.show()

    def hide(self):
        self.widget.hide()

    def restart_promt(self):
        headline = T("Restart required")
        message = T(
            "Some of your changes require a restart of Unknown Horizons. Do you want to restart Unknown Horizons now?"
        )
        if self._windows.open_popup(headline, message,
                                    show_cancel_button=True):
            return True

    def set_defaults(self):
        title = T("Restore default settings")
        msg = T("Restoring the default settings will delete all changes to the settings you made so far.") + \
          " " + T("Do you want to continue?")

        if self._windows.open_popup(title, msg, show_cancel_button=True):
            self.hotkey_interface.reset_to_default()
            self._settings.set_defaults()
            self.restart_prompt()
            self._windows.close()

    def apply_settings(self):
        restart_required = False

        for entry in self._options:
            widget = self.widget.findChild(name=entry.widget_name)
            new_value = widget.getData()

            if callable(entry.initial_data):
                initial_data = entry.initial_data()
            else:
                initial_data = entry.initial_data

            if isinstance(initial_data, list):
                new_value = initial_data[new_value]
            elif isinstance(initial_data, dict):
                new_value = list(initial_data.keys())[new_value]

            old_value = self._settings.get(entry.module, entry.name)

            # Store new setting
            self._settings.set(entry.module, entry.name, new_value)

            # If setting changed, allow applying of new value and sanity checks
            if new_value != old_value:
                if entry.restart:
                    restart_required = True

                if entry.callback:
                    entry.callback(old_value, new_value)

        self.hotkey_interface.save_settings()
        self._settings.apply()
        self._settings.save()

        if restart_required:
            if self.restart_promt():
                horizons.globals.fife.engine.destroy()
                os.execv(sys.executable, [sys.executable] + sys.argv)

        self._windows.close()

    def _fill_widgets(self):
        for entry in self._options:
            value = self._settings.get(entry.module, entry.name)
            widget = self.widget.findChild(name=entry.widget_name)

            if entry.initial_data:
                if callable(entry.initial_data):
                    initial_data = entry.initial_data()
                else:
                    initial_data = entry.initial_data

                if isinstance(initial_data, dict):
                    widget.setInitialData(list(initial_data.values()))
                    value = list(initial_data.keys()).index(value)
                elif isinstance(initial_data, list):
                    widget.setInitialData(initial_data)
                    value = initial_data.index(value)
                else:
                    widget.setInitialData(initial_data)

            widget.setData(value)

            if entry.on_change:
                cb = Callback(entry.on_change, widget)
                cb()
                widget.capture(cb)

    def _on_slider_changed(self, widget):
        """Callback for updating value label of a slider after dragging it.

		As the numeric values under the hood often do not represent mental
		models of what the setting achieves very well, depending on the
		setting in question we display a modified value, sometimes with
		a '%' suffix."""
        value_label = self.widget.findChild(name=widget.name + '_value')
        value = {
            'volume_music': lambda x: '{:d}%'.format(int(500 * x)),
            'volume_effects': lambda x: '{:d}%'.format(int(200 * x)),
            'mousesensitivity': lambda x: '{:.1f}x'.format(10 * x),
            'autosaveinterval': lambda x: '{:.1f}'.format(x),
            'autosavemaxcount': lambda x: '{:d}'.format(int(x)),
            'quicksavemaxcount': lambda x: '{:d}'.format(int(x)),
            'scrollspeed': lambda x: '{:.1f}'.format(x),
        }[widget.name](widget.value)
        value_label.text = value

    # callbacks for changes of settings

    def _apply_PlaySounds(self, old, new):
        horizons.globals.fife.sound.setup_sound()

    def _apply_VolumeMusic(self, old, new):
        horizons.globals.fife.sound.set_volume_bgmusic(new)

    def _apply_VolumeEffects(self, old, new):
        horizons.globals.fife.sound.set_volume_effects(new)

    def _apply_FrameLimit(self, old, new):
        # handling value 0 for framelimit to disable limiter
        if new == 0:
            self._settings.set(SETTINGS.FIFE_MODULE, 'FrameLimitEnabled',
                               False)
        else:
            self._settings.set(SETTINGS.FIFE_MODULE, 'FrameLimitEnabled', True)

    def _apply_NetworkPort(self, old, new):
        """Sets a new value for client network port"""
        # port is saved as string due to pychan limitations
        try:
            # 0 is not a valid port, but a valid value here (used for default)
            parse_port(new)
        except ValueError:
            headline = T("Invalid network port")
            descr = T(
                "The port you specified is not valid. It must be a number between 1 and 65535."
            )
            advice = T(
                "Please check the port you entered and make sure it is in the specified range."
            )
            self._windows.open_error_popup(headline, descr, advice)
            # reset value and reshow settings dlg
            self._settings.set(SETTINGS.UH_MODULE, 'NetworkPort', "0")
        else:
            # port is valid
            try:
                if NetworkInterface() is None:
                    NetworkInterface.create_instance()
                NetworkInterface().network_data_changed()
            except Exception as e:
                headline = T("Failed to apply new network settings.")
                descr = T(
                    "Network features could not be initialized with the current configuration."
                )
                advice = T(
                    "Check the settings you specified in the network section.")
                if 0 < parse_port(new) < 1024:
                    #i18n This is advice for players seeing a network error with the current config
                    advice += " " + \
                     T("Low port numbers sometimes require special access privileges, try 0 or a number greater than 1024.")
                details = str(e)
                self._windows.open_error_popup(headline, descr, advice,
                                               details)

    def _apply_Language(self, old, new):
        language = LANGUAGENAMES.get_by_value(new)
        change_language(language)

    def _on_Language_changed(self, widget):
        value = widget.items[widget.getData()]
        language_code = LANGUAGENAMES.get_by_value(value)

        status_label = self.widget.findChild(
            name='language_translation_status')
        if not language_code or language_code == 'en':
            status_label.text = ''
        else:
            value = get_language_translation_stats(language_code)
            if value:
                status_label.text = T('Translation {percentage}% completed'
                                      ).format(percentage=value)
            else:
                status_label.text = ''

    def _apply_DebugLog(self, old, new):
        horizons.main.set_debug_log(new)
示例#27
0
class SettlerOverviewTab(OverviewTab):
    widget = 'overview_settler.xml'
    helptext = LazyT("Settler overview")

    def init_widget(self):
        super(SettlerOverviewTab, self).init_widget()
        name = self.instance.settlement.get_component(NamedComponent).name
        self.widget.findChild(name="headline").text = name
        setup_tax_slider(self.widget.child_finder('tax_slider'),
                         self.widget.child_finder('tax_val_label'),
                         self.instance.settlement, self.instance.level)

        taxes = self.instance.settlement.tax_settings[self.instance.level]
        self.widget.child_finder('tax_val_label').text = unicode(taxes)
        action_set = ActionSetLoader.get_set(self.instance._action_set_id)
        action_gfx = action_set.items()[0][1]
        image = action_gfx[45].keys()[0]
        self.widget.findChild(name="building_image").image = image

    def on_settler_level_change(self, message):
        assert isinstance(message, SettlerUpdate)
        setup_tax_slider(self.widget.child_finder('tax_slider'),
                         self.widget.child_finder('tax_val_label'),
                         self.instance.settlement, message.level)
        taxes = self.instance.settlement.tax_settings[self.instance.level]
        self.widget.child_finder('tax_val_label').text = unicode(taxes)
        imgs = ActionSetLoader.get_set(
            self.instance._action_set_id).items()[0][1]
        self.widget.findChild(name="building_image").image = imgs[45].keys()[0]

    def show(self):
        super(SettlerOverviewTab, self).show()
        SettlerUpdate.subscribe(self.on_settler_level_change,
                                sender=self.instance)

    def hide(self):
        SettlerUpdate.discard(self.on_settler_level_change,
                              sender=self.instance)
        super(SettlerOverviewTab, self).hide()

    def refresh(self):
        image, helptext = get_happiness_icon_and_helptext(
            self.instance.happiness, self.instance.session)
        self.widget.child_finder('happiness_label').image = image
        self.widget.child_finder('happiness_label').helptext = helptext
        self.widget.child_finder(
            'happiness').progress = self.instance.happiness
        self.widget.child_finder('inhabitants').text = u"%s/%s" % (
            self.instance.inhabitants, self.instance.inhabitants_max)
        self.widget.child_finder('taxes').text = unicode(
            self.instance.last_tax_payed)
        self.update_consumed_res()
        name = self.instance.settlement.get_component(NamedComponent).name
        self.widget.findChild(name="headline").text = name
        events = {
            'headline':
            Callback(self.instance.session.ingame_gui.show_change_name_dialog,
                     self.instance.settlement)
        }
        self.widget.mapEvents(events)
        super(SettlerOverviewTab, self).refresh()

    def update_consumed_res(self):
        """Updates the container that displays the needed resources of the settler"""
        container = self.widget.findChild(name="needed_res")
        # remove icons from the container
        container.removeAllChildren()

        # create new ones
        resources = self.instance.get_currently_not_consumed_resources()
        for res in resources:
            icon = create_resource_icon(res, self.instance.session.db)
            icon.max_size = icon.min_size = icon.size = (32, 32)
            container.addChild(icon)

        container.adaptLayout()
示例#28
0
class ProductionOverviewTab(OverviewTab):
	widget = 'overview_productionbuilding.xml'
	helptext = LazyT("Production overview")
	production_line_gui_xml = 'overview_productionline.xml'

	ACTIVE_PRODUCTION_ANIM_DIR = "content/gui/images/animations/cogs/large"
	BUTTON_BACKGROUND = "content/gui/images/buttons/msg_button.png"
	ARROW_TOP = "content/gui/icons/templates/production/production_arrow_top.png"
	ARROW_MID = "content/gui/icons/templates/production/production_arrow_start.png"
	ARROW_BOTTOM = "content/gui/icons/templates/production/production_arrow_bottom.png"
	ARROW_CONNECT_UP = "content/gui/icons/templates/production/production_arrow_connect_up.png"
	ARROW_CONNECT_DOWN = "content/gui/icons/templates/production/production_arrow_connect_down.png"
	ARROWHEAD_TOP = "content/gui/icons/templates/production/production_arrowhead_top.png"
	ARROWHEAD_MID = "content/gui/icons/templates/production/production_arrow_head.png"
	ARROWHEAD_BOTTOM = "content/gui/icons/templates/production/production_arrowhead_bottom.png"
	ARROWHEAD_CONNECT_UP = "content/gui/icons/templates/production/production_arrowhead_connect_up.png"
	ARROWHEAD_CONNECT_DOWN = "content/gui/icons/templates/production/production_arrowhead_connect_down.png"
	ICON_HEIGHT = ImageFillStatusButton.CELL_SIZE[1] + ImageFillStatusButton.PADDING

	def  __init__(self, instance):
		self._animations = []
		super(ProductionOverviewTab, self).__init__(instance=instance)

	def get_displayed_productions(self):
		"""List all possible productions of a buildings sorted by production line id.
		Overwritten in some child classes (e.g. farm tab).
		"""
		productions = self.instance.get_component(Producer).get_productions()
		return sorted(productions, key=operator.methodcaller('get_production_line_id'))

	def refresh(self):
		"""This function is called by the TabWidget to redraw the widget."""
		self._refresh_utilization()

		# remove old production line data
		parent_container = self.widget.child_finder('production_lines')
		while parent_container.children:
			child = parent_container.children[-1]
			if hasattr(child, "anim"):
				child.anim.stop()
				del child.anim
			parent_container.removeChild(child)

		# create a container for each production
		# sort by production line id to have a consistent (basically arbitrary) order
		for production in self.get_displayed_productions():
			# we need to be notified of small production changes
			# that aren't passed through the instance
			production.add_change_listener(self._schedule_refresh, no_duplicates=True)

			gui = load_uh_widget(self.production_line_gui_xml)
			# fill in values to gui reflecting the current game state
			container = gui.findChild(name="production_line_container")

			centered_container = container.findChild(name='centered_production_icons')
			center_y = self._center_production_line(container, production)
			centered_container.position = (centered_container.position[0], center_y - 44 // 2)
			self._set_resource_amounts(container, production)

			if production.is_paused():
				centered_container.removeChild(centered_container.findChild(name="toggle_active_active"))
				toggle_icon = centered_container.findChild(name="toggle_active_inactive")
				toggle_icon.name = "toggle_active"
			else:
				centered_container.removeChild(centered_container.findChild(name="toggle_active_inactive"))
				toggle_icon = centered_container.findChild(name="toggle_active_active")
				toggle_icon.name = "toggle_active"

				if production.get_state() == PRODUCTION.STATES.producing:
					bg = Icon(image=self.__class__.BUTTON_BACKGROUND)
					bg.position = toggle_icon.position
					centered_container.addChild(bg)
					centered_container.removeChild(toggle_icon) # fix z-ordering
					centered_container.addChild(toggle_icon)
					anim = PychanAnimation(toggle_icon, self.__class__.ACTIVE_PRODUCTION_ANIM_DIR)
					centered_container.anim = anim
					anim.start(1.0/12, -1) # always start anew, people won't notice
					self._animations.append(weakref.ref(anim))

			# fill it with input and output resources
			in_res_container = container.findChild(name="input_res")
			self._add_resource_icons(in_res_container, production.get_consumed_resources(), marker=True)
			out_res_container = container.findChild(name="output_res")
			self._add_resource_icons(out_res_container, production.get_produced_resources())

			# active toggle_active button
			toggle_active = ToggleActive(self.instance.get_component(Producer), production)
			centered_container.mapEvents({
				'toggle_active': Callback(toggle_active.execute, self.instance.session)
			})
			# NOTE: this command causes a refresh, so we needn't change the toggle_active-button-image
			parent_container.addChild(container)
		super(ProductionOverviewTab, self).refresh()

	def _center_production_line(self, parent_container, production):
		"""Centers in/out production line display for amount of resources each.

		@return: y value to center other gui parts (toggle icon etc.) around vertically.
		"""
		input_amount = len(production.get_consumed_resources())
		output_amount = len(production.get_produced_resources())
		# Center of production line arrows (where to place toggle icon).
		height_diff_y = max(1, output_amount, input_amount) - 1
		center_y = (self.ICON_HEIGHT // 2) * height_diff_y
		# Center input and output boxes of the production line if necessary.
		if input_amount != output_amount:
			height_diff_in = max(0, output_amount - max(1, input_amount))
			height_diff_out = max(0, input_amount - max(1, output_amount))
			center_y_in = (self.ICON_HEIGHT // 2) * height_diff_in
			center_y_out = (self.ICON_HEIGHT // 2) * height_diff_out
			input_container = parent_container.findChild(name='input_container')
			output_container = parent_container.findChild(name='output_container')
			input_container.position = (input_container.position[0], center_y_in)
			output_container.position = (output_container.position[0], center_y_out)
		# Draw and combine arrows for input and output.
		if input_amount > 0:
			self._draw_pretty_arrows(parent_container, input_amount, x=58, y=center_y, out=False)
		if output_amount > 0:
			self._draw_pretty_arrows(parent_container, output_amount, x=96, y=center_y, out=True)
		return center_y + self.ICON_HEIGHT // 2

	def _draw_pretty_arrows(self, parent_container, amount, x=0, y=0, out=False):
		"""Draws incoming or outgoing arrows for production line container."""
		if amount % 2:
			# Add center arrow for 1, 3, 5, ... but not 2, 4, ...
			if out:
				mid_arrow = Icon(image=self.__class__.ARROWHEAD_MID)
			else:
				mid_arrow = Icon(image=self.__class__.ARROW_MID)
			mid_arrow.position = (x, 17 + y)
			parent_container.insertChild(mid_arrow, 0)

		for res in xrange(amount // 2):
			# --\                      <= placed for res = 1
			# --\| <= place connector  <= placed for res = 0
			# ---O-->                  <= placed above (mid_arrow)
			# --/| <= place connector  <= placed for res = 0
			# --/                      <= placed for res = 1
			offset = -17 + (self.ICON_HEIGHT // 2) * (2 * res + (amount % 2) + 1)

			if out:
				top_arrow = Icon(image=self.__class__.ARROWHEAD_TOP)
			else:
				top_arrow = Icon(image=self.__class__.ARROW_TOP)
			top_arrow.position = (x, y - offset)
			parent_container.insertChild(top_arrow, 0)

			if out:
				bottom_arrow = Icon(image=self.__class__.ARROWHEAD_BOTTOM)
			else:
				bottom_arrow = Icon(image=self.__class__.ARROW_BOTTOM)
			bottom_arrow.position = (x, y + offset)
			parent_container.insertChild(bottom_arrow, 0)

			# Place a connector image (the | in above sketch) that vertically connects
			# the input resource arrows. We need those if the production line has more
			# than three input resources. Connectors are placed in the inner loop parts.
			place_connectors = amount > (3 + 2 * res)
			if place_connectors:
				# the connector downwards connects top_arrows
				if out:
					down_connector = Icon(image=self.__class__.ARROWHEAD_CONNECT_DOWN)
				else:
					down_connector = Icon(image=self.__class__.ARROW_CONNECT_DOWN)
				down_connector.position = (98, y - offset)
				parent_container.insertChild(down_connector, 0)
				# the connector upwards connects up_arrows
				if out:
					up_connector = Icon(image=self.__class__.ARROWHEAD_CONNECT_UP)
				else:
					up_connector = Icon(image=self.__class__.ARROW_CONNECT_UP)
				up_connector.position = (98, y + offset)
				parent_container.insertChild(up_connector, 0)

	def _set_resource_amounts(self, container, production):
		for res, amount in production.get_consumed_resources().iteritems():
			# consumed resources are negative!
			label = Label(text=unicode(-amount), margins=(0, 16))
			container.findChild(name='input_box').addChild(label)

		for res, amount in production.get_produced_resources().iteritems():
			label = Label(text=unicode(amount).rjust(2), margins=(0, 16))
			container.findChild(name='output_box').addChild(label)

	def destruct_building(self):
		self.instance.session.ingame_gui.hide_menu()
		Tear(self.instance).execute(self.instance.session)

	def _refresh_utilization(self):
		utilization = 0
		if self.instance.has_component(Producer):
			utilization = int(round(self.instance.get_component(Producer).capacity_utilization * 100))
		self.widget.child_finder('capacity_utilization').text = unicode(utilization) + u'%'

	def _add_resource_icons(self, container, resources, marker=False):
		calculate_position = lambda amount: (amount * 100) // inventory.get_limit(res)
		for res in resources:
			inventory = self.instance.get_component(StorageComponent).inventory
			filled = calculate_position(inventory[res])
			marker_level = calculate_position(-resources[res]) if marker else 0
			image_button = ImageFillStatusButton.init_for_res(self.instance.session.db, res,
					inventory[res], filled, marker=marker_level, use_inactive_icon=False, uncached=True)
			container.addChild(image_button)

	def show(self):
		super(ProductionOverviewTab, self).show()
		Scheduler().add_new_object(Callback(self._refresh_utilization),
		                           self, run_in=GAME_SPEED.TICKS_PER_SECOND, loops=-1)

	def hide(self):
		super(ProductionOverviewTab, self).hide()
		self._cleanup()

	def on_instance_removed(self):
		self._cleanup()
		super(ProductionOverviewTab, self).on_instance_removed()

	def _cleanup(self):
		Scheduler().rem_all_classinst_calls(self)
		for production in self.get_displayed_productions():
			production.discard_change_listener(self._schedule_refresh)
		for anim in self._animations:
			if anim():
				anim().stop()
		self._animations = []
示例#29
0
class OverviewTab(TabInterface):
    widget = 'overviewtab.xml'
    icon_path = 'icons/tabwidget/common/building_overview'
    helptext = LazyT("Overview")

    has_stance = False

    def __init__(self, instance, widget=None, icon_path=None):
        self.instance = instance
        super(OverviewTab, self).__init__(widget=widget, icon_path=icon_path)

    def init_widget(self):
        # set player emblem
        if self.widget.child_finder('player_emblem'):
            if self.instance.owner is not None:
                player_color = self.instance.owner.color.name
            else:
                player_color = 'no_player'
            emblem = 'content/gui/images/tabwidget/emblems/emblem_%s.png'
            self.widget.child_finder(
                'player_emblem').image = emblem % player_color

        if self.__class__.has_stance:
            self.init_stance_widget()

    def refresh(self):
        if (hasattr(self.instance, 'name')
                or self.instance.has_component(NamedComponent)
            ) and self.widget.child_finder('name'):
            name_widget = self.widget.child_finder('name')
            # Named objects can't be translated.
            if self.instance.has_component(NamedComponent):
                name_widget.text = self.instance.get_component(
                    NamedComponent).name
            else:
                name_widget.text = T(self.instance.name)

        if hasattr(self.instance, 'running_costs') and \
           self.widget.child_finder('running_costs'):
            self.widget.child_finder('running_costs').text = \
                unicode(self.instance.running_costs)

        self.widget.adaptLayout()

    def show(self):
        super(OverviewTab, self).show()
        if not self.instance.has_change_listener(self.refresh):
            self.instance.add_change_listener(self.refresh)
        if not self.instance.has_remove_listener(self.on_instance_removed):
            self.instance.add_remove_listener(self.on_instance_removed)
        if hasattr(self.instance, 'settlement') and \
           self.instance.settlement is not None and \
           not self.instance.settlement.has_change_listener(self._schedule_refresh):
            # listen for settlement name changes displayed as tab headlines
            self.instance.settlement.add_change_listener(
                self._schedule_refresh)

    def hide(self):
        super(OverviewTab, self).hide()
        if self.instance is not None:
            self.instance.discard_change_listener(self.refresh)
            self.instance.discard_remove_listener(self.on_instance_removed)
        if hasattr(self.instance,
                   'settlement') and self.instance.settlement is not None:
            self.instance.settlement.discard_change_listener(
                self._schedule_refresh)

    def on_instance_removed(self):
        self.on_remove()
        self.instance = None

    def init_stance_widget(self):
        """Call this for tabs with stances."""
        stance_widget = self.widget.findChild(name='stance')
        if stance_widget is not None:
            stance_widget.init(self.instance)
            self.add_remove_listener(stance_widget.remove)
示例#30
0
class BoatbuilderTab(UnitbuilderTabBase):
    widget = 'boatbuilder.xml'
    helptext = LazyT("Boat builder overview")

    UNIT_THUMBNAIL = "content/gui/icons/thumbnails/{type_id}.png"
    UNIT_PREVIEW_IMAGE = "content/gui/images/objects/ships/116/{type_id}.png"