diff -ur PyUIcvs.orig/pyui/renderers/pygame2D.py PyUIcvs/pyui/renderers/pygame2D.py --- PyUIcvs.orig/pyui/renderers/pygame2D.py Sun Mar 7 23:38:19 2004 +++ PyUIcvs/pyui/renderers/pygame2D.py Tue Mar 9 00:27:59 2004 @@ -27,6 +27,51 @@ from pyui.desktop import getDesktop +# Used to cache gradients +class Cache: + def __init__( self, agedHits=100, lengthLimit=500 ): + self.cache = {} + self.agedCache = {} + self.agedHits = agedHits + self.lengthLimit = lengthLimit + self.hits = 0 + + def __len__( self ): + return len( self.cache ) + + def __getitem__(self, key): + # We can only really get an item if there is a hit + # Otherwise there will be an exception + self.hits += 1 + + if ( not self.cache.has_key( key ) ) and self.agedCache.has_key( key ): + # Promote from aged cache + item = self.agedCache[ key ] + self.cache[ key ] = item + return self.cache[key] + + def has_key( self, key ): + return self.cache.has_key( key ) or self.agedCache.has_key( key ) + + def __contains__(self, item): + return self.cache.__contains__( item ) + + def __setitem__(self, key, value): + if ( self.hits > self.agedHits or len( self.cache ) > self.lengthLimit ): + # We "age" everything by moving it into a second dictionary + # If it is reused, we promote it back into the first dictionary + # The next time this happens, the aged cache contains only unused items + # + # Performance: The limits may need to be tuned for your application to avoid too much rendering + #~ print "expiring cache. Count:", len( self.cache ) + del self.agedCache + self.agedCache = self.cache + self.cache = {} + + self.hits = 0 + self.cache[key] = value + + class Pygame2D(pyui.rendererBase.RendererBase): """Pygame 2D renderer. """ @@ -81,6 +126,10 @@ self.lastID = 1000 self.windows = {} self.images = {} + + # These values are used to maintain the gradient caches + self.gradientCache = Cache() + self.gradientPartCache = Cache() self.drawBackMethod = self.clear @@ -194,10 +243,128 @@ self.screen.blit(img, (rect[0], rect[1]) ) return 2 elif cmd == pyui.locals.GRADIENT: - (cmd, rect, c1, c2, c3, c4 ) = command - rect = (self.windowPos[0]+rect[0], self.windowPos[1]+rect[1], rect[2], rect[3]) - self.screen.fill(c3, rect) - return 2 + (cmd, rect, c1, c2, c3, c4 ) = command + # top left, top right, bottom left, bottom right + + image = None + + # TODO: For some reason these rectangles can be noninteger sizes + width = int( rect[2] + 0.5 ) + height = int( rect[3] + 0.5 ) + assert( width > 0 and height > 0 ) + + # Look in our cache for an image that matches width, height, c1, c2, c3, c4: + struct = (width, height, tuple( c1 ), tuple( c2 ), tuple( c3 ), tuple( c4 ) ) + if self.gradientCache.has_key( struct ): + image = self.gradientCache[ struct ] + else: + # Miss: render the gradient in Python code + from array import array + + # If the gradient is a pure vertical or horizontal, store the gradient "line": + # This way we can construct gradients based on that line much faster. + gStruct = None + gLine = None + gDelta = None + gCount = None + + if ( c1 == c2 and c3 == c4 ): + # Vertical gradient + gStruct = (1, height, tuple( c1 ), tuple( c3 ) ) + gLine = None + + # Search for the vertical line in the part cache + if ( self.gradientPartCache.has_key( gStruct ) ): + gLine = self.gradientPartCache[ gStruct ] + else: + gDelta = [ (c3[i] - c1[i]) / float( height ) for i in range( 4 ) ] + gCount = height + elif ( c1 == c3 and c2 == c4 ): + # Horizontal gradient + gStruct = (width, 1, tuple( c1 ), tuple( c2 ) ) + gLine = None + + # Search for the vertical line in the part cache + if ( self.gradientPartCache.has_key( gStruct ) ): + gLine = self.gradientPartCache[ gStruct ] + else: + gDelta = [ (c2[i] - c1[i]) / float( width ) for i in range( 4 ) ] + gCount = width + + if ( gStruct != None ): + # It is a horizontal or vertical gradient ... + if ( gLine == None ): + # ... but not in cache: We need to render the single line of the gradient + data = array( 'B' ) + + colour = [ float( col ) for col in c1 ] + for j in range( gCount ): + for i in range( 4 ): + data.append( int( colour[i] ) ) + colour[i] += gDelta[i] + + gLine = pygame.image.fromstring( data.tostring(), ( gStruct[0], gStruct[1] ), "RGBA" ) + self.gradientPartCache[ gStruct ] = gLine + + # We have a line: Tile it + image = pygame.Surface( (width, height), SRCALPHA, 32 ) + image.fill( (0, 0, 0, 0) ) + for y in range(0, height, gStruct[1]): + for x in range(0, width, gStruct[0]): + #~ print 'blit', (gStruct[0], gStruct[1]), 'at', (x,y), 'in rect', (width, height) + image.blit( gLine, (x, y) ) + else: + # Worst case: non linear gradient: we need to render it completely + + # Create an array of bytes + data = array( 'B' ) + + # Interpolate the left and right edge colours, then interpolate between them + # So first we calculate the deltas for each row + + startYDelta = [ 0.0, 0.0, 0.0, 0.0 ] + endYDelta = [ 0.0, 0.0, 0.0, 0.0 ] + for i in range( 4 ): + startYDelta[i] = (c3[i] - c1[i]) / float( height ) + endYDelta[i] = (c4[i] - c2[i]) / float( height ) + + #~ print 'start:', c1, 'stop:', c4, 'delta:', startYDelta, 'computed:', [ c1[i] + startYDelta[i]*height for i in range(4) ] + #~ print 'start:', c2, 'stop:', c3, 'delta:', endYDelta, 'computed:', [ c2[i] + endYDelta[i]*height for i in range(4) ] + + startColour = [ float( col ) for col in c1 ] + endColour = [ float( col ) for col in c2 ] + + for y in range( height ): + colour = list( startColour ) + + # Compute the x delta for this line and the next start/end colours + xDelta = [ 0.0, 0.0, 0.0, 0.0 ] + for i in range( 4 ): + xDelta[i] = (endColour[i] - startColour[i]) / width + startColour[i] += startYDelta[i] + endColour[i] += endYDelta[i] + + for x in range( width ): + # Store each colour component for each pixel in the line + # and compute the next colourcolour = list( startColour ) + for i in range( 4 ): + #~ print int( colour[i] ) + data.append( int( colour[i] ) ) + colour[i] += xDelta[i] + assert( len( data ) == int( 4 * width * height ) ) + + image = pygame.image.fromstring( data.tostring(), ( width, height ), "RGBA" ) + + self.gradientCache[ struct ] = image # Cache the gradient + + # At this point we have an image: draw it + self.screen.blit( image, ( self.windowPos[0] + rect[0], self.windowPos[1]+rect[1] ) ) + + # Old "not gradient" code + #~ rect = (self.windowPos[0]+rect[0], self.windowPos[1]+rect[1], rect[2], rect[3]) + #~ self.screen.fill(c3, rect) + + return 2 elif cmd == pyui.locals.CLIP: #(cmd, rect) = command #rect = (self.windowPos[0]+rect[0], self.windowPos[1]+rect[1], rect[2], rect[3]) diff -ur PyUIcvs.orig/pyui/themes/future.py PyUIcvs/pyui/themes/future.py --- PyUIcvs.orig/pyui/themes/future.py Sun Aug 17 17:19:16 2003 +++ PyUIcvs/pyui/themes/future.py Sun Mar 21 10:52:54 2004 @@ -1,4 +1,4 @@ -7# PyUI +# PyUI # Copyright (C) 2001-2002 Sean C. Riley # # This library is free software; you can redistribute it and/or