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)
class TilingProgressBar(ProgressBar): """ProgressBar that tiles its fill image instead of stretching. Also supports distinct left and right border/frame images which count towards the displayed progress value and fill images of width > 1px. """ ATTRIBUTES = ProgressBar.ATTRIBUTES + [Attr('left'), Attr('right')] def __init__(self, left=None, right=None, **kwargs): super().__init__(**kwargs) self.__left = left self.__right = right self.tiles = TilingHBox() self.addChild(self.tiles) self.tiles_width = 1 self.left_width = 0 self.right_width = 0 def _get_progress(self): return self.__progress def _set_progress(self, progress): self.__progress = progress fill_width = (progress / 100.0) * (self.max_size[0] / self.tiles_width) self.tiles.amount = int( fill_width) - self.left_width - self.right_width self.adaptLayout() def _get_left_image(self): return self.__left def _set_left_image(self, image): self.__left = image self.left_width = Icon(image=image).size[0] self.tiles.start_img = image def _get_fill_image(self): return self.__fill def _set_fill_image(self, image): self.__fill = image self.tiles_width = Icon(image=image).size[0] self.tiles.tiles_img = image def _get_right_image(self): return self.__right def _set_right_image(self, image): self.__right = image self.right_width = Icon(image=image).size[0] self.tiles.final_img = image progress = property(_get_progress, _set_progress) left = property(_get_left_image, _set_left_image) fill = property(_get_fill_image, _set_fill_image) right = property(_get_right_image, _set_right_image)
class ToggleImageButton(tooltip.TooltipButton): """The ToggleImageButton is an extended ImageButton (Think decorator pattern). It adds one extra attribute inactive_image. You can then set the button active or inactive (only in code for now). Setting the ToggleImageButton to inactive will change all images (up, down and hover) to the inactive image. If you set it active again, everything will be reset. @param inactive_image The image that is to be used as inactive image. """ ATTRIBUTES = pychan.widgets.ImageButton.ATTRIBUTES + [ Attr('inactive_image') ] + [UnicodeAttr('tooltip')] # These two constants are used to describe the state of the widget. ACTIVE = 0 INACTIVE = 1 def __init__(self, inactive_image="", **kwargs): self.state = None super(ToggleImageButton, self).__init__(**kwargs) self.state = self.ACTIVE self.inactive_image = inactive_image def toggle(self): if self.state == self.ACTIVE: self.set_inactive() else: self.set_active() def set_active(self): """Sets the button active. Restores up, down and hover image to previous state.""" if self.state != self.ACTIVE: self.up_image, self.down_image, self.hover_image = self.old_images self.state = self.ACTIVE def set_inactive(self): """Sets the button inactive. Overrides up, down and hover image with inactive image.""" if self.state != self.INACTIVE: self.old_images = (self.up_image, self.down_image, self.hover_image) self.up_image = self.inactive_image self.down_image = self.inactive_image self.hover_image = self.inactive_image self.state = self.INACTIVE def _get_inactive_image(self): return self.__inactiveimage def _set_inactive_image(self, inactive_image): self.__inactiveimage = inactive_image inactive_image = property(_get_inactive_image, _set_inactive_image)
class MainmenuButton(ImageButton): """For use in main menu. bw: whether to use greyscale or color.""" ATTRIBUTES = ImageButton.ATTRIBUTES + [Attr('icon')] ICON = "content/gui/icons/mainmenu/{icon}{bw}.png" def __init__(self, icon='door', **kwargs): super(MainmenuButton, self).__init__(is_focusable=False, **kwargs) self.icon = icon def _get_icon(self): return self.__icon def _set_icon(self, icon): self.__icon = icon self.up_image = self.ICON.format(icon=icon, bw='_bw') self.hover_image = self.down_image = self.ICON.format(icon=icon, bw='') icon = property(_get_icon, _set_icon)
class ImageButton(FifeImageButton): """Extends ImageButton functionality by providing a new path= attribute. Unless manually overridden, specifying path="path/to/file" (note: no .png extension) will interpret that as these attributes: up_image = "content/gui/path/to/file.png" down_image = "content/gui/path/to/file_d.png" hover_image = "content/gui/path/to/file_h.png" inactive_image = "content/gui/path/to/file_bw.png" ("black/white") Other possible names also checked are up_image = "content/gui/path/to/file_u.png" ("up", for tabwidget) inactive_image = "content/gui/path/to/file_gr.png" ("grayscale") If some of those files could not be found, we use up_image instead. Sets is_focusable to False unless overridden. You can set the button active or inactive (only in code for now). Setting to inactive will change *all* images (up, down and hover) to the inactive image. If you set it active again, everything will be reset. """ ATTRIBUTES = FifeImageButton.ATTRIBUTES + [ Attr('path'), Attr('inactive_image') ] IMAGE = "content/gui/{path}{{mode}}.png" # These two constants are used to describe the toggle state of the widget. ACTIVE = 0 INACTIVE = 1 def __init__(self, path='', inactive_image=None, is_focusable=False, **kwargs): super(ImageButton, self).__init__(is_focusable=is_focusable, **kwargs) self.old_images = (None, None, None) if path: # initializing from python, not xml, so path is available here # and should be set self.path = path if inactive_image: self.inactive_image = inactive_image self.state = self.ACTIVE def toggle(self): if self.is_active: self.set_inactive() else: self.set_active() def set_active(self): """Sets the button active. Restores up, down and hover image to previous state.""" if self.is_active: return self.up_image, self.down_image, self.hover_image = self.old_images self.state = self.ACTIVE def set_inactive(self): """Sets the button inactive. Overrides up, down and hover image with inactive image.""" if not self.is_active: # running this with inactive state would overwrite all elements # of old_images with inactive_image return # store old images to be reloaded when button is set active again self.old_images = (self.up_image, self.down_image, self.hover_image) self.up_image = self.down_image = self.hover_image = self.inactive_image self.state = self.INACTIVE @property def is_active(self): return (self.state == self.ACTIVE) def _get_path(self): return self.__path def _set_path(self, path): self.__path = path image_path = self.IMAGE.format(path=path) try: self.up_image = image_path.format(mode='') except RuntimeError: # RuntimeError: _[NotFound]_ , Something was searched, but not found #TODO Temporarily try to find _u for the tabwidget self.up_image = image_path.format(mode='_u') try: self.hover_image = image_path.format(mode='_h') except RuntimeError: # By default, guichan/pychan will set hover_image to be the same as # up_image even if it is not explicitly set here (the following line # just reading `pass` instead of setting hover_image to up_image). # This however is stored internally in a way that would segfault FIFE # when trying to restore images from self.old_images that were set # like that implicitly (see #2000). self.hover_image = self.up_image try: self.down_image = image_path.format(mode='_d') except RuntimeError: self.down_image = self.up_image # Since inactive_image is no image attribute in pychan, it would # not be validated upon setting self.inactive_image (which works # for ImageButton.{up,down,hover}_image and Icon.image). # Instead, we try to load an Icon with that image and manually # set inactive_image to the path that worked, if there is any. try: image = image_path.format(mode='_bw') Icon(image=image).hide( ) # hide will remove Icon from widgets of pychan.internals.manager self.inactive_image = image except RuntimeError: try: image = image_path.format(mode='_gr') Icon(image=image).hide( ) # hide will remove Icon from widgets of pychan.internals.manager self.inactive_image = image except RuntimeError: self.inactive_image = self.up_image path = property(_get_path, _set_path)