예제 #1
0
class ProgressBar(ABox):
    """The ProgressBar is a pychan widget. It can be used in xml files like this:
	<ProgressBar />
	It is used to display a ProgressBar with a certain progress ;). Set the
	widgets progress attribute to set the progress. Pretty straight forward.
	The progress is a value from 0 to 100. Think of it as percent.
	"""
    ATTRIBUTES = ABox.ATTRIBUTES + [
        IntAttr('progress'),
        Attr('fill'),
        Attr('background'),
    ]

    def __init__(self, progress=0, fill=None, background=None, **kwargs):
        super().__init__(**kwargs)
        if self.max_size == Widget.DEFAULT_MAX_SIZE:
            self.max_size = (100, 16)
        self.__progress = progress
        self.__fill = fill
        self.__background = background
        self.tiles = None
        self.bg_icon = None

    def _set_progress(self, progress):
        self.__progress = progress
        if self.bg_icon is None:
            self.background = "content/gui/images/background/bar_bg.png"
        if self.tiles is None:
            self.fill = "content/gui/images/background/widgets/progressbar_fill.png"
        self.tiles.size = (int(self.max_size[0] * progress / 100.0),
                           self.max_size[1])
        self.adaptLayout()

    def _get_progress(self):
        return self.__progress

    def _set_fill_image(self, image):
        self.__fill = image
        self.tiles = Icon(image=image, scale=True)
        self.addChild(self.tiles)

    def _get_fill_image(self):
        return self.__fill

    def _set_background(self, background):
        self.__background = background
        self.bg_icon = Icon(image=background, scale=True)
        self.bg_icon.min_size = self.bg_icon.size = self.max_size
        self.addChild(self.bg_icon)

    def _get_background(self):
        return self.__background

    progress = property(_get_progress, _set_progress)
    fill = property(_get_fill_image, _set_fill_image)
    background = property(_get_background, _set_background)
예제 #2
0
class TabBG(VBox, TilingBackground):
	"""Intended to be used for any tab we display.
	Uses content/gui/images/tabwidget/main_bg_*.png.
	@param amount: amount of 50px tiles/panels in between top and bottom icon
	"""
	ATTRIBUTES = VBox.ATTRIBUTES + [IntAttr('amount')]
	def __init__(self, **kwargs):
		VBox.__init__(self, name='tab_background_icons', padding=0)
		TilingBackground.__init__(self,
			amount=0,
			base_path="content/gui/images/tabwidget/main_bg_",
			start_img="top.png", tiles_img="fill.png", final_img="bottom.png",
			**kwargs)
예제 #3
0
class TilingHBox(HBox, TilingBackground):
	"""Currently mostly used by cityinfo, thus using its arguments as defaults.

	Another use case is the TilingProgressBar.
	@param amount: amount of 10px tiles/panels in between left and right icon
	"""
	ATTRIBUTES = HBox.ATTRIBUTES + [IntAttr('amount')]
	def __init__(self, **kwargs):
		HBox.__init__(self, name='city_info_background', padding=0)
		TilingBackground.__init__(self,
			amount=0,
			base_path="content/gui/images/background/widgets/cityinfo_",
			start_img="left.png", tiles_img="fill.png", final_img="right.png",
			**kwargs)
예제 #4
0
class TilingHBox(TilingBackground, HBox):
    """Currently only used by cityinfo, thus using its arguments as defaults.
	@param amount: amount of 10px tiles/panels in between left and right icon
	"""
    ATTRIBUTES = HBox.ATTRIBUTES + [IntAttr('amount')]

    def __init__(self, **kwargs):
        super(TilingHBox, self).__init__(
            amount=0,
            name='tab_background_icons',
            base_path="content/gui/images/background/widgets/cityinfo_",
            start_img="left.png",
            tiles_img="fill.png",
            final_img="right.png",
            **kwargs)
예제 #5
0
class TabBG(pychan.widgets.VBox):
	"""The TabBG is a shortcut for several TooltipIcons combined to one group.
	Intended to be used for any tab we display.
	Uses content/gui/images/tabwidget/main_bg_*.png. Default attributes are:
	name="background_icons"
	amount="0"
	padding="0"
	border_size="0"

	@param amount: amount of 50px tiles in between top and bottom icon
	"""
	ATTRIBUTES = pychan.widgets.VBox.ATTRIBUTES + [IntAttr('amount')]
	def __init__(self, amount=0, **kwargs):
		super(TabBG, self).__init__(
			name='background_icons',
			padding=0,
			border_size=0,
			**kwargs)
		# Note: Don't set the amount in the constructor,
		# as it will not layout correctly, blame pychan for it :-)
		self.__amount = amount
		header_path = "content/gui/images/tabwidget/main_bg_top.png"
		self.addChild(TooltipIcon(image=header_path, name='background_icon_' + '0'))

	def _get_amount(self):
		return self.__amount

	def _set_amount(self, amount):
		self.__amount = amount
		mid_path = "content/gui/images/tabwidget/main_bg_fill.png"
		footer_path = "content/gui/images/tabwidget/main_bg_bottom.png"
		for i in xrange(0,self.amount):
			mid = TooltipIcon(image=mid_path, name='background_icon_' + unicode(i+1))
			self.addChild(mid)
		self.addChild(TooltipIcon(image=footer_path, name='background_icon_' + unicode(self.amount+1)))

	amount = property(_get_amount, _set_amount)
예제 #6
0
class Inventory(Container):
    """The inventory widget displays information about the goods in
	a Storage. It uses ImageFillStatusButtons to display icons and
	a fill bar for these resources.
	It can be used like any other widget in xml files, but for full
	functionality the inventory has to be manually set, or use the
	TabWidget, which will autoset it (was made to be done this way).

	XML use: <Inventory />, can take all parameters of a Container.
	"""
    ATTRIBUTES = Container.ATTRIBUTES + [
        BoolAttr('uncached'),
        BoolAttr('display_legend'),
        IntAttr("items_per_line")
    ]
    # uncached: required when resource icons should appear multiple times at any given moment
    # on the screen. this is usually not the case with single inventories, but e.g. for trading.
    # display_legend: whether to display a string explanation about slot limits

    UNUSABLE_SLOT_IMAGE = "content/gui/icons/resources/none_gray.png"

    def __init__(self,
                 uncached=False,
                 display_legend=True,
                 items_per_line=4,
                 **kwargs):
        # this inits the gui part of the inventory. @see init().
        super(Inventory, self).__init__(**kwargs)
        self._inventory = None
        self._inited = False
        self.uncached = uncached
        self.display_legend = display_legend
        self.items_per_line = items_per_line or 1  # negative values are fine, 0 is not

    def init_needed(self, inventory):
        return not self._inited or self._inventory is not inventory

    def init(self, db, inventory, ordinal=None):
        """This inits the logic of the inventory. @see __init__().
		@param ordinal: {res: (min, max)} Display ordinal scale with these boundaries instead of numbers for a particular resource. Currently implemented via ImageFillStatusButton.
		"""
        # check if we must init everything anew
        if self.init_needed(inventory):
            self._inited = True
            self.db = db
            self._inventory = inventory

            # specific to Inventory
            self.ordinal = ordinal
            self._res_order = sorted(self._inventory.iterslots())
            self.legend = Label(name="legend")
            self.__icon = Icon(name="legend_icon")
            self.__icon.image = "content/gui/icons/ship/civil_16.png"
            if isinstance(self._inventory, TotalStorage):
                self.__icon.position = (130, 53)
                self.legend.position = (150, 53)
            elif isinstance(self._inventory, PositiveSizedSlotStorage):
                self.__icon.position = (0, 248)
                self.legend.position = (20, 248)

        self.update()

    def update(self):
        self.removeAllChildren()
        if self.display_legend:
            self.addChildren(self.__icon, self.legend)
        vbox = VBox(padding=0)
        vbox.width = self.width
        current_hbox = HBox(padding=0)

        # draw the content
        self._draw(vbox, current_hbox)

        self.adaptLayout()

    def _draw(self, vbox, current_hbox, index=0):
        """Draws the inventory."""
        # add res to res order in case there are new ones
        # (never remove old ones for consistent positioning)
        new_res = sorted(resid for resid in self._inventory.iterslots()
                         if resid not in self._res_order)

        if isinstance(self._inventory, PositiveTotalNumSlotsStorage):
            # limited number of slots. We have to switch unused slots with newly added ones on overflow

            while len(
                    self._res_order) + len(new_res) > self._inventory.slotnum:
                for i in xrange(self._inventory.slotnum):
                    if len(self._res_order) <= i or self._inventory[
                            self._res_order[i]]:
                        # search empty slot
                        continue
                    # insert new res here
                    self._res_order[i] = new_res.pop(0)
                    if not new_res:
                        break  # all done

        # add remaining slots for slotstorage or just add it without consideration for other storage kinds
        self._res_order += new_res

        for resid in self._res_order:
            amount = self._inventory[resid]
            if amount == 0:
                index += 1
                continue

            # check if this res should be displayed
            if not self.db.cached_query(
                    'SELECT shown_in_inventory FROM resource WHERE id = ?',
                    resid)[0][0]:
                continue

            if self.ordinal:
                lower, upper = self.ordinal.get(resid, (0, 100))
                filled = (100 * (amount - lower)) // (upper - lower)
                amount = ""  # do not display exact information for resource deposits
            elif isinstance(self._inventory, TotalStorage):
                filled = 0
            else:
                filled = (100 * amount) // self._inventory.get_limit(resid)

            button = ImageFillStatusButton.init_for_res(self.db,
                                                        resid,
                                                        amount,
                                                        filled=filled,
                                                        uncached=self.uncached)
            button.button.name = "inventory_entry_%s" % index  # required for gui tests
            current_hbox.addChild(button)

            if index % self.items_per_line == self.items_per_line - 1:
                vbox.addChild(current_hbox)
                current_hbox = HBox(padding=0)
            index += 1
        if index <= self.items_per_line:  # Hide/Remove second line
            icons = self.parent.findChildren(name='slot')
            if len(icons) > self.items_per_line:
                self.parent.removeChildren(icons[self.items_per_line - 1:])
        vbox.addChild(current_hbox)
        self.addChild(vbox)
        height = ImageFillStatusButton.CELL_SIZE[1] * len(
            self._res_order) // self.items_per_line
        self.min_size = (self.min_size[0], height)

        if isinstance(self._inventory, TotalStorage):
            # if it's full, the additional slots have to be marked as unusable (#1686)
            # check for any res, the res type doesn't matter here
            if not self._inventory.get_free_space_for(0):
                for i in xrange(index, self.items_per_line):
                    button = Icon(image=self.__class__.UNUSABLE_SLOT_IMAGE)
                    # set min & max_size to prevent pychan to expand this dynamic widget (icon)
                    button.min_size = button.max_size = ImageFillStatusButton.ICON_SIZE
                    current_hbox.addChild(button)

        if self.display_legend:
            limit = self._inventory.get_limit(None)
            if isinstance(self._inventory, TotalStorage):
                # Add total storage indicator
                sum_stored = self._inventory.get_sum_of_stored_resources()
                self.legend.text = _('{stored}/{limit}').format(
                    stored=sum_stored, limit=limit)
            elif isinstance(self._inventory, PositiveSizedSlotStorage):
                self.legend.text = _('Limit: {amount}t per slot').format(
                    amount=limit)

    def apply_to_buttons(self, action, filt=None):
        """Applies action to all buttons shown in inventory
		@param action: function called that touches button
		@param filt: function used to filter the buttons
		both functions take one parameter which is the button
		"""
        if filt:
            assert callable(filt)
        assert callable(action)

        def _find_widget(widget):
            if isinstance(widget, ImageFillStatusButton):
                if filt is None or filt(widget):
                    action(widget)

        self.deepApply(_find_widget)