Update of /cvsroot/freevo/freevo/src/gui/backends/sdl
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19978/backends/sdl

Added Files:
        .cvsignore __init__.py font.py keyboard.py layer.py 
        renderer.py screen.py 
Log Message:
move renderer into backend subdir

--- NEW FILE: .cvsignore ---
*.pyc *.pyo

--- NEW FILE: layer.py ---
import copy


class Layer:
    """
    This is a layer implementation for pygame. You can add objects from
    basic.py to it and they will be drawn.
    """
    def __init__(self, name, renderer, alpha=False):
        self.name     = name
        self.renderer = renderer
        self.alpha    = alpha
        if alpha:
            self.screen = self.renderer.screen.convert_alpha()
            self.screen.fill((0,0,0,0))
        else:
            self.screen = self.renderer.screen.convert()

        # some Surface functions from pygame
        self.fill = self.screen.fill
        self.lock = self.screen.lock
        self.lock = self.screen.unlock

        self.update_rect = []
        self.objects     = []
        self.width       = self.renderer.width
        self.height      = self.renderer.height
        

    def __str__(self):
        """
        Debug output for this layer
        """
        return '%s layer [%s]' % (self.name, len(self.objects))

    
    def blit(self, layer, *arg1, **arg2):
        """
        Interface for the objects to blit something on the layer
        """
        try:
            return self.screen.blit(layer.screen, *arg1, **arg2)
        except AttributeError:
            return self.screen.blit(layer, *arg1, **arg2)
            

    def drawroundbox(self, *arg1, **arg2):
        """
        Interface for the objects draw a round box
        """
        arg2['layer'] = self.screen
        return self.renderer.drawroundbox(*arg1, **arg2)


    def drawstringframed(self, *arg1, **arg2):
        """
        Interface for the objects draw a string
        """
        arg2['layer'] = self.screen
        return self.renderer.drawstringframed(*arg1, **arg2)


    def in_update(self, x1, y1, x2, y2, update_area, full=False):
        """
        Helper function to check if we need to update or not
        """
        if full:
            for ux1, uy1, ux2, uy2 in update_area:
                # check if x1, y1, x2, y2 are completly inside the rect
                if ux1 <= x1 <= x2 <= ux2 and uy1 <= y1 <= y2 <= uy2:
                    return True
            return False

        for ux1, uy1, ux2, uy2 in update_area:
            # check if x1, y1, x2, y2 is somewere inside the rect
            if not (x2 < ux1 or y2 < uy1 or x1 > ux2 or y1 > uy2):
                return True
        return False


    def add_to_update_rect(self, x1, y1, x2, y2):
        """
        Add (x1,y1,x2,y2) to the list of rectangles we need to update
        """
        if not self.in_update(x1, y1, x2, y2, self.update_rect, True):
            self.update_rect.append((x1, y1, x2, y2))


    def expand_update_rect(self, update_area):
        """
        Add all rectangles in update_area to the list of rectangles we need
        to update
        """
        old_rect = self.update_rect
        self.update_rect = copy.copy(update_area)
        for x1, y1, x2, y2 in old_rect:
            self.add_to_update_rect(x1, y1, x2, y2)
        return self.update_rect

    
    def add(self, object):
        """
        Add an object to this layer
        """
        object.layer = self
        self.objects.append(object)
        self.add_to_update_rect(object.x1, object.y1, object.x2, object.y2)


    def remove(self, object):
        """
        Add an object from this layer
        """
        self.objects.remove(object)
        object.layer = None
        self.add_to_update_rect(object.x1, object.y1, object.x2, object.y2)
        return True


    def clear(self):
        """
        Clear this layer
        """
        self.update_rect = []
        self.objects     = []
        if self.alpha:
            self.screen.fill((0,0,0,0))
        else:
            self.screen.fill((0,0,0))


    def draw(self):
        """
        Draw all objects on this layer
        """
        rect = (self.width, self.height, 0, 0)

        if not self.update_rect:
            return self.update_rect, rect

        for x0, y0, x1, y1 in self.update_rect:
            rect = ( min(x0, rect[0]), min(y0, rect[1]),
                     max(x1, rect[2]), max(y1, rect[3]))
            
        self.objects.sort(lambda  l, o: cmp(l.position, o.position))
        for o in self.objects:
            if self.in_update(o.x1, o.y1, o.x2, o.y2, self.update_rect):
                o.draw(rect)

        ret = self.update_rect
        self.update_rect = []
        return ret, rect
    
        


--- NEW FILE: renderer.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
# renderer.py - interface to output using pygame
# -----------------------------------------------------------------------
# $Id: renderer.py,v 1.1 2004/07/24 12:21:06 dischi Exp $
#
# Note: Work in Progress
#
# -----------------------------------------------------------------------
# $Log: renderer.py,v $
# Revision 1.1  2004/07/24 12:21:06  dischi
# move renderer into backend subdir
#
#
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002 Krister Lagerstrom, et al. 
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------


# Python modules
import os
import stat
import Image
import re
import traceback

from types import *
from fcntl import ioctl

# Freevo modules
import config


# SDL modules
import pygame
from pygame.locals import *
from font import Font


class Renderer:
    """
    The basic render engine for gygame
    """
    # Some default colors (deprecated)
    COL_BLACK  = 0x000000
    COL_WHITE  = 0xffffff
    COL_ORANGE = 0xFF9028

    def __init__(self):
        """
        init the osd
        """
        import util
        self.fullscreen = 0 # Keep track of fullscreen state

        self.bitmapcache = util.objectcache.ObjectCache(5, desc='bitmap')
        self.font_info_cache = {}
        
        self.default_fg_color = self.COL_BLACK
        self.default_bg_color = self.COL_WHITE

        self.width  = config.CONF.width
        self.height = config.CONF.height

        if config.CONF.display == 'dxr3':
            os.environ['SDL_VIDEODRIVER'] = 'dxr3'
        elif config.CONF.display in ( 'directfb', 'dfbmga' ):
            os.environ['SDL_VIDEODRIVER'] = 'directfb'

        # sometimes this fails
        if not os.environ.has_key('SDL_VIDEODRIVER') and \
               config.CONF.display == 'x11':
            os.environ['SDL_VIDEODRIVER'] = 'x11'


        # disable term blanking for mga and fbcon and restore the
        # tty so that sdl can use it
        if config.CONF.display in ('mga', 'fbcon'):
            for i in range(0,7):
                try:
                    fd = os.open('/dev/tty%s' % i, os.O_RDONLY | os.O_NONBLOCK)
                    try:
                        # set ioctl (tty, KDSETMODE, KD_TEXT)
                        ioctl(fd, 0x4B3A, 0)
                    except:
                        pass
                    os.close(fd)
                    os.system('%s -term linux -cursor off -blank 0 -clear -powerdown 0 
' \
                              '-powersave off </dev/tty%s > /dev/tty%s 2>/dev/null' % \
                              (config.CONF.setterm, i,i))
                except:
                    pass
            
        # Initialize the PyGame modules.
        pygame.display.init()
        pygame.font.init()

        self.depth = 32
        self.hw    = 0

        if config.CONF.display == 'dxr3':
            self.depth = 32

        try:
            self.screen = pygame.display.set_mode((self.width, self.height),
                                                  self.hw, self.depth)
        except:
            self.screen = pygame.display.set_mode((self.width, self.height))

        self.depth     = self.screen.get_bitsize()
        self.must_lock = self.screen.mustlock()
        
        if config.CONF.display == 'x11' and config.START_FULLSCREEN_X == 1:
            self.toggle_fullscreen()

        help = [ _('z = Toggle Fullscreen'),
                 _('Arrow Keys = Move'),
                 _('Spacebar = Select'),
                 _('Escape = Stop/Prev. Menu'),
                 _('h = Help') ]

        help_str = '    '.join(help)

        pygame.display.set_caption('Freevo' + ' '*7 + String( help_str ) )
        icon = pygame.image.load(os.path.join(config.ICON_DIR,
                                              'misc/freevo_app.png')).convert()
        pygame.display.set_icon(icon)
        
        self.clearscreen(self.COL_BLACK)
        self.update()

        if config.OSD_SDL_EXEC_AFTER_STARTUP:
            os.system(config.OSD_SDL_EXEC_AFTER_STARTUP)

        self.sdl_driver = pygame.display.get_driver()
        _debug_('SDL Driver: %s' % (str(self.sdl_driver)),2)

        pygame.mouse.set_visible(0)
        pygame.key.set_repeat(500, 30)
        
        # Remove old screenshots
        os.system('rm -f /tmp/freevo_ss*.bmp')
        self._screenshotnum = 1
        self.active = True

        # some functions from pygame
        self.Surface = pygame.Surface
        self.polygon = pygame.draw.polygon

        pygame.time.delay(10)   # pygame.time.get_ticks don't seem to
                                # work otherwise


    def shutdown(self):
        """
        shutdown the display
        """
        pygame.quit()
        if config.OSD_SDL_EXEC_AFTER_CLOSE:
            os.system(config.OSD_SDL_EXEC_AFTER_CLOSE)
        self.active = False


    def stopdisplay(self):
        """
        stop the display to give other apps the right to use it
        """
        # backup the screen
        self.__stop_screen__ = pygame.Surface((self.width, self.height))
        self.__stop_screen__.blit(self.screen, (0,0))
        pygame.display.quit()


    def restartdisplay(self):
        """
        restores a stopped display
        """
        pygame.display.init()
        self.width  = config.CONF.width
        self.height = config.CONF.height
        self.screen = pygame.display.set_mode((self.width, self.height), self.hw,
                                              self.depth)
        if hasattr(self, '__stop_screen__'):
            self.screen.blit(self.__stop_screen__, (0,0))
            del self.__stop_screen__
            
        # We need to go back to fullscreen mode if that was the mode before the 
shutdown
        if self.fullscreen:
            pygame.display.toggle_fullscreen()
            
        
    def toggle_fullscreen(self):
        """
        toggle between window and fullscreen mode
        """
        self.fullscreen = (self.fullscreen+1) % 2
        if pygame.display.get_init():
            pygame.display.toggle_fullscreen()
        _debug_('Setting fullscreen mode to %s' % self.fullscreen)


    def get_fullscreen(self):
        """
        return 1 is fullscreen is running
        """
        return self.fullscreen
    

    def clearscreen(self, color=None):
        """
        clean the complete screen
        """
        if not pygame.display.get_init():
            return None

        if color == None:
            color = self.default_bg_color
        self.screen.fill(self._sdlcol(color))
        
    
    def loadbitmap(self, url, cache=False, width=None, height=None, vfs_save=False):
        """
        Load a bitmap and return the pygame image object.
        If width and height are given, the image is scaled to that. Setting
        only width or height will keep aspect ratio.
        If vfs_save is true, the so scaled bitmap will be stored in the vfs for
        future use.
        """
        if cache:
            # first check the cache
            if cache == True:
                cache = self.bitmapcache
            if width != None or height != None:
                key = 'scaled://%s-%s-%s' % (url, width, height)
            else:
                key = url

            s = cache[key]
            if s:
                return s
                
        if vfs_save and (width == None or height == None):
            vfs_save = False

        if not pygame.display.get_init():
            return None

        # not in cache, load it

        try:
            image = pygame.image.fromstring(url.tostring(), url.size, url.mode)
        except:

            if url[:8] == 'thumb://':
                filename = os.path.abspath(url[8:])
                thumbnail = True
            else:
                filename = os.path.abspath(url)
                thumbnail = False
            
            if vfs_save:
                vfs_save = vfs.getoverlay('%s.raw-%sx%s' % (filename, width, height))
                try:
                    if os.stat(vfs_save)[stat.ST_MTIME] > \
                           os.stat(filename)[stat.ST_MTIME]:
                        f = open(vfs_save, 'r')
                        image = pygame.image.fromstring(f.read(), (width, height), 
'RGBA')
                        f.close()
                        if cache:
                            cache[key] = image
                        return image
                except:
                    pass
                
            if not os.path.isfile(filename):
                filename = os.path.join(config.IMAGE_DIR, url[8:])

            if not os.path.isfile(filename):
                print 'osd.py: Bitmap file "%s" doesnt exist!' % filename
                return None
            
            try:
                import util
                if isstring(filename) and filename.endswith('.raw'):
                    # load cache
                    data  = util.read_thumbnail(filename)
                    # convert to pygame image
                    image = pygame.image.fromstring(data[0], data[1], data[2])

                elif thumbnail:
                    # load cache or create it
                    data = util.cache_image(filename)
                    # convert to pygame image
                    try:
                        image = pygame.image.fromstring(data[0], data[1], data[2])
                    except:
                        data = util.create_thumbnail(filename)
                        image = pygame.image.fromstring(data[0], data[1], data[2])
                else:
                    try:
                        image = pygame.image.load(filename)
                    except pygame.error, e:
                        print 'SDL image load problem: %s - trying Imaging' % e
                        i = Image.open(filename)
                        image = pygame.image.fromstring(i.tostring(), i.size, i.mode)
            
            except:
                print 'Unknown Problem while loading image %s' % String(url)
                if config.DEBUG:
                    traceback.print_exc()
                return None

        # scale the image if needed
        if width != None or height != None:
            image = self.resizebitmap(image, width, height)

        # convert the surface to speed up blitting later
        if image and image.get_alpha():
            image.set_alpha(image.get_alpha(), RLEACCEL)

        if vfs_save:
            f = vfs.open(vfs_save, 'w')
            f.write(pygame.image.tostring(image, 'RGBA'))
            f.close()
            
        if cache:
            cache[key] = image
        return image


    def resizebitmap(self, image, width=None, height=None):
        image_w, image_h = image.get_size()
        if width == None:
            # calculate width
            width = (height * float(image_w)) / float(image_h)
        if height == None:
            # calculate width
            height = (width * float(image_h)) / float(image_w)

        return pygame.transform.scale(image, (width, height))

        
    def zoombitmap(self, image, scaling=None, bbx=0, bby=0, bbw=0, bbh=0, rotation = 
0):
        """
        Zooms a Surface. It gets a Pygame Surface which is rotated and scaled according
        to the parameters.
        """
        if not image:
            return None
        
        if bbx or bby or bbw or bbh:
            imbb = pygame.Surface((bbw, bbh))
            imbb.blit(image, (0, 0), (bbx, bby, bbw, bbh))
            image = imbb

        if scaling:
            w, h = image.get_size()
            w = int(w * scaling)
            h = int(h * scaling)

            if rotation:
                image = pygame.transform.rotozoom(image, rotation, scaling)
            else:
                image = pygame.transform.scale(image, (w, h))

        elif rotation:
            image = pygame.transform.rotate(image, rotation)

        return image


    def drawbox(self, x0, y0, x1, y1, width=None, color=None, fill=0, layer=None):
        """
        draw a normal box
        """
        # Make sure the order is top left, bottom right
        x0, x1 = min(x0, x1), max(x0, x1)
        y0, y1 = min(y0, y1), max(y0, y1)
        
        if color == None:
            color = self.default_fg_color
            
        if width == None:
            width = 1

        if width == -1 or fill:
            r,g,b,a = self._sdlcol(color)
            w = x1 - x0
            h = y1 - y0
            box = pygame.Surface((int(w), int(h)))
            box.fill((r,g,b))
            box.set_alpha(a)
            if layer:
                layer.blit(box, (x0, y0))
            else:
                self.screen.blit(box, (x0, y0))
        else:
            c = self._sdlcol(color)
            if not layer:
                layer = self.screen
            for i in range(0, width):
                # looks strange, but sometimes thinkness doesn't work
                pygame.draw.rect(layer, c, (x0+i, y0+i, x1-x0-2*i, y1-y0-2*i), 1)


    def screenblit(self, source, destpos, sourcerect=None):
        """
        blit the source to the screen
        """
        if sourcerect:
            w    = sourcerect[2]
            h    = sourcerect[3]
            ret  = self.screen.blit(source, destpos, sourcerect)
        else:
            w, h = source.get_size()
            ret  = self.screen.blit(source, destpos)

        return ret



    def getfont(self, font, ptsize):
        """
        return cached font
        """
        key = (font, ptsize)
        try:
            return self.font_info_cache[key]
        except:
            fi = Font(font, ptsize)
            self.font_info_cache[key] = fi
            return fi


    def drawstringframed(self, string, x, y, width, height, font, fgcolor=None,
                         bgcolor=None, align_h='left', align_v='top', mode='hard',
                         layer=None, ellipses='...', dim=True):
        """
        draws a string (text) in a frame. This tries to fit the
        string in lines, if it can't, it truncates the text,
        draw the part that fit and returns the other that doesn't.
        This is a wrapper to drawstringframedsoft() and -hard()

        Parameters:
        - string: the string to be drawn, supports also '\n'. \t is not supported
          by pygame, you need to replace it first
        - x,y: the posistion
        - width, height: the frame dimensions,
          height == -1 defaults to the font height size
        - fgcolor, bgcolor: the color for the foreground and background
          respectively. (Supports the alpha channel: 0xAARRGGBB)
        - font, ptsize: font and font point size
        - align_h: horizontal align. Can be left, center, right, justified
        - align_v: vertical align. Can be top, bottom, center or middle
        - mode: the way we should break lines/truncate. Can be 'hard'(based on chars)
          or 'soft' (based on words)

        font can also be a skin font object. If so, this functions also supports
        shadow and border. fgcolor and bgcolor will also be taken from the skin
        font if set to None when calling this function.

        THIS FUNCTION IS DEPRECATED
        """
        from gui.base import Text
        t = Text(x, y, x+width, y+height, string, font, height, align_h, align_v, mode,
                 ellipses, dim, fgcolor, bgcolor)
        t.layer = layer
        if layer == None:
            t.layer = self.screen
        return t.__render__()

    
    def drawstring(self, string, x, y, fgcolor=None, bgcolor=None,
                   font=None, ptsize=0, align='left', layer=None):
        """
        draw a string

        THIS FUNCTION IS DEPRECATED
        """
        if not pygame.display.get_init():
            return None

        if not string:
            return None

        if fgcolor == None:
            fgcolor = self.default_fg_color

        if font == None:
            font = config.OSD_DEFAULT_FONTNAME

        if not ptsize:
            ptsize = config.OSD_DEFAULT_FONTSIZE

        tx = x
        width = self.width - tx

        if align == 'center':
            tx -= width/2
        elif align == 'right':
            tx -= width
            
        self.drawstringframed(string, x, y, width, -1, self.getfont(font, ptsize),
                              fgcolor, bgcolor, align_h = align, layer=layer,
                              ellipses='')


    def _savepixel(self, x, y, s):
        """
        help functions to save and restore a pixel
        for drawcircle
        """
        try:
            return (x, y, s.get_at((x,y)))
        except:
            return None

            
    def _restorepixel(self, save, s):
        """
        restore the saved pixel
        """
        if save:
            s.set_at((save[0],save[1]), save[2])


    def drawcircle(self, s, color, x, y, radius):
        """
        draws a circle to the surface s and fixes the borders
        pygame.draw.circle has a bug: there are some pixels where
        they don't belong. This function stores the values and
        restores them
        """
        p1 = self._savepixel(x-1, y-radius-1, s)
        p2 = self._savepixel(x,   y-radius-1, s)
        p3 = self._savepixel(x+1, y-radius-1, s)

        p4 = self._savepixel(x-1, y+radius, s)
        p5 = self._savepixel(x,   y+radius, s)
        p6 = self._savepixel(x+1, y+radius, s)

        pygame.draw.circle(s, color, (x, y), radius)
        
        self._restorepixel(p1, s)
        self._restorepixel(p2, s)
        self._restorepixel(p3, s)
        self._restorepixel(p4, s)
        self._restorepixel(p5, s)
        self._restorepixel(p6, s)
        
        
    def drawroundbox(self, x0, y0, x1, y1, color=None, border_size=0, 
border_color=None,
                     radius=0, layer=None):
        """
        draw a round box
        """
        if not pygame.display.get_init():
            return None

        # Make sure the order is top left, bottom right
        x0, x1 = min(x0, x1), max(x0, x1)
        y0, y1 = min(y0, y1), max(y0, y1)
        if color == None:
            color = self.default_fg_color

        if border_color == None:
            border_color = self.default_fg_color

        if layer:
            x = x0
            y = y0
        else:
            x = 0
            y = 0
            
        w = x1 - x0
        h = y1 - y0

        bc = self._sdlcol(border_color)
        c =  self._sdlcol(color)

        # make sure the radius fits the box
        radius = min(radius, h / 2, w / 2)
        
        if not layer:
            box = pygame.Surface((w, h), SRCALPHA)

            # clear surface
            box.fill((0,0,0,0))
        else:
            box = layer
            
        r,g,b,a = self._sdlcol(color)
        
        if border_size:
            if radius >= 1:
                self.drawcircle(box, bc, x+radius, y+radius, radius)
                self.drawcircle(box, bc, x+w-radius, y+radius, radius)
                self.drawcircle(box, bc, x+radius, y+h-radius, radius)
                self.drawcircle(box, bc, x+w-radius, y+h-radius, radius)
                pygame.draw.rect(box, bc, (x+radius, y, w-2*radius, h))
            pygame.draw.rect(box, bc, (x, y+radius, w, h-2*radius))
        
            x += border_size
            y += border_size
            h -= 2* border_size
            w -= 2* border_size
            radius -= min(0, border_size)
        
        if radius >= 1:
            self.drawcircle(box, c, x+radius, y+radius, radius)
            self.drawcircle(box, c, x+w-radius, y+radius, radius)
            self.drawcircle(box, c, x+radius, y+h-radius, radius)
            self.drawcircle(box, c, x+w-radius, y+h-radius, radius)
            pygame.draw.rect(box, c, (x+radius, y, w-2*radius, h))
        pygame.draw.rect(box, c, (x, y+radius, w, h-2*radius))
        
        if not layer:
            self.screen.blit(box, (x0, y0))



    def update(self, rect=None, blend_surface=None, blend_speed=0,
               blend_steps=0, blend_time=None, stop_busyicon=True):
        """
        update the screen
        """
        if not pygame.display.get_init():
            return None

        if config.OSD_UPDATE_COMPLETE_REDRAW:
            rect = None

        if rect:
            try:
                pygame.display.update(rect)
            except:
                _debug_('osd.update(rect) failed, bad rect? - %s' % str(rect), 1)
                _debug_('updating whole screen')
                pygame.display.flip()
        else:
            pygame.display.flip()

        

    # Convert a 32-bit TRGB color to a 4 element tuple for SDL
    def _sdlcol(self, col):
        if col==None:
            return (0,0,0,255)
        a = 255 - ((col >> 24) & 0xff)
        r = (col >> 16) & 0xff
        g = (col >> 8) & 0xff
        b = (col >> 0) & 0xff
        c = (r, g, b, a)
        return c

--- NEW FILE: font.py ---
import pygame
import os

import config


font_warning = []

class Font:
    def __init__(self, name, ptsize):
        self.font   = self.__getfont__(name, ptsize)
        self.height = max(self.font.size('A')[1], self.font.size('j')[1])
        self.chars  = {}
        self.name   = name
        self.ptsize = ptsize


    def fade_out(self, surface, pixels=30):
        """
        Helper for drawing a transparency gradient end for strings
        which don't fit it's content area.
        """
        try:
            opaque_mod = float(1)
            opaque_stp = opaque_mod/float(pixels)
            w, h       = surface.get_size()
            alpha      = pygame.surfarray.pixels_alpha(surface)

            # transform all the alpha values in x,y range
            # any speedup could help alot
            for x in range(max(w-pixels, 1), w):
                for y in range(1, h):
                    if alpha[x,y][0] != 0:
                        alpha[x,y] = int(alpha[x,y][0]*opaque_mod)
                opaque_mod -= opaque_stp
        except Exception, e:
            print e


    def render(self, txt, fgcolor, bgcolor=None, border_color=None,
               border_radius=0, dim=0):
        if bgcolor:
            # draw a box around the text if we have a bgcolor
            print 'FIXME: draw box around text'

        render = self.font.render(txt, 1, self.__sdlcol__(fgcolor))

        if not border_color == None:
            border = self.font.render(txt, 1, self.__sdlcol__(border_color))
            # draw on a tmp surface
            tmp = pygame.Surface((render.get_size()[0] + 2 * border_radius,
                                  render.get_size()[1] + 2 * 
border_radius)).convert_alpha()
            tmp.fill((0, 0, 0, 0))
                            
            for ox in (0, border_radius, border_radius*2):
                for oy in (0, border_radius, border_radius*2):
                    if ox or oy:
                        tmp.blit(border, (ox, oy))
            tmp.blit(render, (border_radius, border_radius))
            render = tmp

        if dim:
            self.fade_out(render, dim)
            
        return render

        
    def charsize(self, c):
        try:
            return self.chars[c]
        except:
            w = self.font.size(c)[0]
            self.chars[c] = w
            return w

    def stringsize(self, s):
        if not s:
            return 0
        w = 0
        for c in s:
            w += self.charsize(c)
        return w


    # Convert a 32-bit TRGB color to a 4 element tuple for SDL
    def __sdlcol__(self, col):
        if col==None:
            return (0,0,0,255)
        a = 255 - ((col >> 24) & 0xff)
        r = (col >> 16) & 0xff
        g = (col >> 8) & 0xff
        b = (col >> 0) & 0xff
        c = (r, g, b, a)
        return c

    def __loadfont__(self, filename, ptsize):
        if os.path.isfile(filename):
            try:
                return pygame.font.Font(filename, ptsize)
            except (RuntimeError, IOError):
                return None
        return None
    
        
    def __getfont__(self, filename, ptsize):
        ptsize = int(ptsize / 0.7)  # XXX pygame multiplies by 0.7 for some reason

        _debug_('Loading font "%s"' % filename, 2)
        font   = self.__loadfont__(filename, ptsize)
        if not font:
            
            # search OSD_EXTRA_FONT_PATH for this font
            fontname = os.path.basename(filename)
            for path in config.OSD_EXTRA_FONT_PATH:
                fname = os.path.join(path, fontname)
                font  = self.__loadfont__(fname, ptsize)
                if font:
                    break
                # deactivated: arialbd seems to be have a wrong height
                # font  = self.__loadfont__(fname.replace('_bold', 'bd'), ptsize)
                # if font:
                #     break
                
        if not font:
            _debug_('Couldnt load font "%s"' % os.path.basename(filename).lower())

            # Ok, see if there is an alternate font to use
            if fontname.lower() in config.OSD_FONT_ALIASES:
                alt_fname = os.path.join(config.FONT_DIR,
                                         config.OSD_FONT_ALIASES[fontname.lower()])
                _debug_('trying alternate: %s' % os.path.basename(alt_fname).lower())
                font = self.__loadfont__(alt_fname, ptsize)

        if not font:
            # not good
            global font_warning
            if not fontname in font_warning:
                print 'WARNING: No alternate found in the alias list!'
                print 'Falling back to default font, this may look very ugly'
                font_warning.append(fontname)
            font = self.__loadfont__(config.OSD_DEFAULT_FONTNAME, ptsize)

        if not font:
            print 'Couldnt load font "%s"' % config.OSD_DEFAULT_FONTNAME
            raise

        return font


--- NEW FILE: keyboard.py ---
import time
import pygame
from pygame.locals import *

import config


class Keyboard:
    def __init__(self):
        self.mousehidetime = time.time()

        
    def poll(self, map=True):
        """
        callback for SDL event (not Freevo events)
        """
        if not pygame.display.get_init():
            return None

        # Check if mouse should be visible or hidden
        mouserel = pygame.mouse.get_rel()
        mousedist = (mouserel[0]**2 + mouserel[1]**2) ** 0.5

        if mousedist > 4.0:
            pygame.mouse.set_visible(1)
            self.mousehidetime = time.time() + 1.0  # Hide the mouse in 2s
        else:
            if time.time() > self.mousehidetime:
                pygame.mouse.set_visible(0)

        # Return the next key event, or None if the queue is empty.
        # Everything else (mouse etc) is discarded.
        while 1:
            event = pygame.event.poll()

            if event.type == NOEVENT:
                return
            
            if event.type == KEYDOWN:
                if not map and event.key > 30:
                    try:
                        if event.unicode != u'':
                            return event.unicode
                    except:
                        pass
                    
                if event.key in config.KEYMAP.keys():
                    # Turn off the helpscreen if it was on
                    return config.KEYMAP[event.key]

                elif event.key == K_h:
                    print 'FIXME: add help'

                elif event.key == K_z:
                    print 'FIXME: toogle fullscreen'

                elif event.key == K_F10:
                    # Take a screenshot
                    print 'FIXME: take screenshot'

                else:
                    # don't know what this is, return it as it is
                    try:
                        if event.unicode != u'':
                            return event.unicode
                    except:
                        return None

--- NEW FILE: screen.py ---
from layer import Layer


class Screen:
    """
    The screen implementation for pygame
    """
    def __init__(self, renderer):
        self.renderer = renderer
        self.layer    = {}
        self.layer['content'] = Layer('content', self.renderer)
        self.layer['alpha']   = Layer('alpha', self.renderer, True)
        self.layer['bg']      = Layer('bg', self.renderer)
        self.complete_bg      = self.renderer.screen.convert()

        self.width  = self.renderer.width
        self.height = self.renderer.height
        

    def clear(self):
        """
        Clear the complete screen
        """
        for l in self.layer:
            self.layer[l].clear()
        self.layer['bg'].add_to_update_rect(0, 0, 800, 600)


    def add(self, layer, object):
        """
        Add object to a specific layer. Right now, this screen has
        only three layers: bg, alpha and content
        """
        return self.layer[layer].add(object)
    
            
    def remove(self, layer, object):
        """
        Remove an object from the screen
        """
        return self.layer[layer].remove(object)



    def show(self):
        """
        Show the screen using pygame
        """
        if self.renderer.must_lock:
            # only lock s_alpha layer, because only there
            # are pixel operations (round rectangle)
            self.layer['alpha'].lock()

        bg    = self.layer['bg']
        alpha = self.layer['alpha']

        update_area = bg.draw()[0]

        update_area = alpha.expand_update_rect(update_area)

        if update_area:
            alpha.screen.fill((0,0,0,0))
            alpha.draw()

        # and than blit only the changed parts of the screen
        for x0, y0, x1, y1 in update_area:
            self.complete_bg.blit(bg.screen, (x0, y0), (x0, y0, x1-x0, y1-y0))
            self.complete_bg.blit(alpha.screen, (x0, y0), (x0, y0, x1-x0, y1-y0))

        content = self.layer['content']

        update_area = content.expand_update_rect(update_area)

        for x0, y0, x1, y1 in update_area:
            content.blit(self.complete_bg, (x0, y0), (x0, y0, x1-x0, y1-y0))

        rect = content.draw()[1]

        for x0, y0, x1, y1 in update_area:
            self.renderer.screenblit(content.screen, (x0, y0), (x0, y0, x1-x0, y1-y0))

        if self.renderer.must_lock:
            self.s_alpha.unlock()

        if update_area:
            self.renderer.update([rect[0], rect[1], rect[2] - rect[0], rect[3] - 
rect[1]])

    def update(self):
        _debug_('update')
        self.show()

--- NEW FILE: __init__.py ---
from renderer import Renderer
from screen import Screen
from layer import Layer
from font import Font
from keyboard import Keyboard



-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop
FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_id=4721&alloc_id=10040&op=click
_______________________________________________
Freevo-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to