from config import * import string class ImageStretcher(object): def __init__(self, image=None): self.clear() self.image = image def clear(self): self._image = None self.width = 0 self.height = 0 self.size = (0, 0) self.cornerwidth = 0 self.cornerheight = 0 self.centerwidth = 0 self.centerheight = 0 self.aspectratio = 1.0 self.parts = {} def _get_image(self): return self._image def _set_image(self, image): if image is None: self.clear() return self._image = image assert isinstance(image, pygame.surface.Surface), "image must be surface or None" self.rect = rect = image.get_rect() w, h = rect.size assert w > 2 and h > 2, "width and hight must be 3 or higher" self.width, self.height, self.size = w, h, (w, h) self.centerwidth = cew = 2 - w % 2 self.centerheight = ceh = 2 - h % 2 self.cornerwidth = cow = (w - self.centerwidth) / 2 self.cornerheight = coh = (h - self.centerheight) / 2 self.aspectratio = 1.0 * w / h ############################################################### # prepare subsurfaces, saving in dictionary self.parts # cornerrects center = rect.center self.cornerrect = cornerrect = Rect(0, 0, cow, coh) cornerrect.topleft = rect.topleft self.parts[1] = image.subsurface(cornerrect) cornerrect.topright = rect.topright self.parts[3] = image.subsurface(cornerrect) cornerrect.bottomleft = rect.bottomleft self.parts[7] = image.subsurface(cornerrect) cornerrect.bottomright = rect.bottomright self.parts[9] = image.subsurface(cornerrect) # top and bottom center rects self.hrect = hrect = Rect(0, 0, cew, coh) hrect.center = center hrect.top = rect.top self.parts[2] = image.subsurface(hrect) hrect.bottom = rect.bottom self.parts[8] = image.subsurface(hrect) # left and right center rects self.vrect = vrect = Rect(0, 0, cow, ceh) vrect.center = center vrect.left = rect.left self.parts[4] = image.subsurface(vrect) vrect.right = rect.right self.parts[6] = image.subsurface(vrect) # center rect self.centerrect = centerrect = Rect(0, 0, cew, ceh) centerrect.center = center self.parts[5] = image.subsurface(centerrect) def info(self): "Prints a summary of the based image's data and splitting" print "Surface:", self._image print " measures:", self.size print " cornerrects: (%i, %i)" % (self.cornerwidth, self.cornerheight) print " centerrect: (%i, %i)" % (self.centerwidth, self.centerheight) print " aspect ratio: %.3f" % (self.aspectratio) def __call__(self, width=0, height=0, rect=None, size=None, fill="stretch"): """Calculates a resized version of the given image Note: when only one of the parameters width and height is given, the other component is calculated using the aspectratio of the source. :keywords: rect:Rect - bounding rect for the target surface size:2-Tuple - Tuple containing width and height of target surface width:int - target width in pixels height:int - target height """ if not (width or height or rect or size): raise ParameterError, "width, height, rect or size expected" ###################################################################### # analyse target size from rect/size/width/height if rect: pass elif size: rect = Rect((0, 0), size) else: if width and height: rect = Rect(0, 0, width, height) else: if width: rect = Rect(0, 0, width, width/self.aspectratio) else: rect = Rect(0, 0, height*self.aspectratio, height) # backup position and set to top left 0 pos, rect.topleft = rect.topleft, (0, 0) # create target surface surf = pygame.surface.Surface(rect.size, SRCALPHA) width, height = size = rect.size center = rect.center p = self.parts cor = self.cornerrect cor.topleft = rect.topleft surf.blit(p[1], cor) cor.topright = rect.topright surf.blit(p[3], cor) cor.bottomleft = rect.bottomleft surf.blit(p[7], cor) cor.bottomright = rect.bottomright surf.blit(p[9], cor) # top stretchpart _width = width - self.cornerwidth * 2 _surf = pygame.transform.scale(p[2], (_width, self.cornerheight)) _rect = _surf.get_rect() _rect.center = center _rect.top = rect.top surf.blit(_surf, _rect) # bottom stretchpart _surf = pygame.transform.scale(p[8], (_width, self.cornerheight)) _rect.bottom = rect.bottom surf.blit(_surf, _rect) # left stretchpart _height = height - self.cornerheight * 2 _surf = pygame.transform.scale(p[4], (self.cornerwidth, _height)) _rect = _surf.get_rect() _rect.center = center _rect.left = rect.left surf.blit(_surf, _rect) # right stretchpart _surf = pygame.transform.scale(p[6], (self.cornerwidth, _height)) _rect.right = rect.right surf.blit(_surf, _rect) # center stretchpart _size = (_width, _height) if fill == "stretch": _surf = pygame.transform.scale(p[5], _size) _rect = _surf.get_rect() _rect.center = center surf.blit(_surf, _rect) elif type(fill) is types.TupleType: _surf = pygame.surface.Surface(_size, SRCALPHA) _surf.fill(fill) _rect = _surf.get_rect() _rect.center = center surf.blit(_surf, _rect) # reset rect position rect.topleft = pos return surf image = property(_get_image, _set_image) class ImageSet(object): """ An ImageSet is a collection surfaces representing the raw templates of the various states of the widget. Default states are normal, over, down and disabled. It serves as container for better handling the complete set. The order of occurance in the surface is described by param order. """ def __init__(self, surf, order): self._surf = surf self._split_surf(order) def _split_surf(self, order): """ Split the surface into a set of subsurfaces according to the order, expecting the images in the surface from left to right. """ self._images = {} self._order = list(order) surf = self._surf rect = surf.get_rect() width, height = rect.size subwidth = width / len(self._order) subrect = Rect(0, 0, subwidth, height) for index in xrange(len(self._order)): name = self._order[index] subrect.left = index * subwidth image = surf.subsurface(subrect) self._images[name] = image def __getattr__(self, attr): if attr in self._order: return self._images.get(attr) else: return self.__dict__[attr] def __getitem__(self, item): return self._images.get(item) def _get_contents(self): keys = sorted(self._images.keys()) return keys def __call__(self, name=None): """Return the image with state name. If omitted, return a list of all""" if name: return self._images.get(name) else: return self._images.get(self._order[0]) ## names of all available states contents = property(_get_contents) class ImageSetLoader(object): """ Loader for a complete set of widget image sets. The surfaces for the ImageSet instances is saved in folder given in parameter imageset_name. """ ## elements of a standard set SET_ITEMS = ["button", "checkbutton", "radiobutton", "closebutton", "minimizebutton", "maximizebutton", "normalizebutton", "combobutton"] def __init__(self, imageset_name="standard"): """Initialize the ImageSetLoader :Parameters: :Keywords: imageset_name:str - name of the ./images/-subdir holding the image set :Return: None """ self.path = "" ## path to the imageset files self.images = {} ## images of the widgets self.meta = {} ## information about the widgets self.imageset_name = imageset_name def __getattr__(self, attr): print "erfrage", attr if attr in self.SET_ITEMS: return self.images.get(attr) else: return self.__dict__[attr] def __getitem__(self, item): if item in self.SET_ITEMS: return self.images.get(item) else: raise KeyError, "Item %s is unknown!" % item def _set_imageset_name(self, imageset_name): self._imageset_name = imageset_name self._load_images() def _get_imageset_name(self): return self.imageset_name def _load_metadata(self): """Load meta-data from file "index.csv" of the imageset-path Returns a list of dicts representing a set of widget data each. """ self.path = os.path.join(IMAGE_PATH, self._imageset_name) fname = os.path.join(self.path, "index.csv") f_in = open(fname) ## remove lines without data sets csv_data = filter(None, map(string.strip, f_in.readlines())) ## remove comments (starting with #) csv_data = filter(lambda s: not s.startswith("#"), csv_data) data_sets = [] for line in csv_data: widgetname, filename, stretch, states = line.split(";", 3) states = states.split(";") data_sets.append({"widgetname":widgetname, "filename":filename, "stretch":eval(stretch), "states":states}) self.meta = dict([(dset["widgetname"], dset) for dset in data_sets]) return data_sets def _load_images(self): # data_sets => data of file index.csv # list of data set dictionaries with # - "widgetname" : name of widget, like "button" # - "filename" : name of file containing the images # - "stretch" : value - if True: the tiles are stretchable # if False: images are used as the are # - "states" : the names of the states the tiles describe, # like "normal", "over", "down", "disabled" ## load meta data and create self.meta data_sets = self._load_metadata() for dset in data_sets: # extract data of dict for easier handling widgetname, filename, stretch, states = map(dset.get, ("widgetname", "filename", "stretch", "states")) # create absolute filename fname = os.path.join(self.path, filename) # load image into surface surf = pygame.image.load(fname) self.images[widgetname] = ImageSet(surf, order=states) imageset_name = property(_get_imageset_name, _set_imageset_name)