###############################################################################################
# $Id: editfield.py,v 1.2 2002/04/06 12:00:00 slmm Exp $
###############################################################################################

import pygame
import pygame.display
import pygame.surface
import pygame.key
from pygame.locals import *
from widget import Widget
import widget

class EditField(Widget):
    """
    This class defines a simple edit field where the user may input some text while the widget has
    focus. 
    """

    # static images for the frame around the editable text
    frameicons = {}

    # names for the icons
    frameiconnames = [ 'topleft', 'top', 'topright', 'right', 'botright', 'bot', 'botleft', 'left' ]

    
    def __init__ (self, font, text="", width=100, position = (0,0), cursor = None, frameicons = None, callbacks = None,
    	color = (255,255,255), background = (0,0,0)):		      
        """Initializes the widget. Renders the font using the passed data."""

        # firts call superclass constructor
        Widget.__init__ (self, position, callbacks)

        # store the text
        if text == None:
            self.text = ""
        else:
            self.text = text

        # store the cursor position
        self.cursor = len ( self.text )

        # store all needed data so that we can create new surfaces later
        self.font = font
        self.color = color
        self.background = background
        self.width = width
	self.cursor_image = cursor
       	EditField.frameicons = frameicons

       
        # render the text
        self.textrendered = font.render ( text, 1, color )
        
        # create the background surface to fit the rendered text's height
        self.textsurface = pygame.Surface ( ( width, self.textrendered.get_height () + 3),
                                            HWSURFACE ).convert ()

        # fill with the proper background color 
        self.textsurface.fill ( background ) 

         # create the surface with the border in it
        self.createBorder ()
        
        # set our internal callbacks so that we can trap keys
        self.internal = {widget.KEYDOWN : self.keyDown }


    def setText (self, text):
        """Sets a new text to be rendered."""
        # store new text
        if text == None:
            self.text = ""
        else:
            self.text = text

        # render a new surface
        self.textrendered = self.font.render ( self.text, 1, self.color )



    def getText (self):
        """Returns the text of the editfield. The text is never None, but may be empty if the
        editfield was cleared."""
        return self.text



    def paint (self, destination, force=0):
        """Method that paints the editfield. This method will simply blit out the surface of the widget
        onto the destination surface. """
        # are we dirty or not?
        if not self.dirty and not force:
            # not dirty, nothing to do here
            return 0

        # we're dirty, blit out the frame first
        destination.blit ( self.surface, (self.position [0], self.position [1]) )
        
        # now the text background
        destination.blit ( self.textsurface, (self.position [0] + self.deltax, self.position [1] + self.deltay) )

        # and the text if we have any
        if self.textrendered:
            # yep, we have it, get the width we should use
            if self.width < self.textrendered.get_size ()[0] + 3:
                width = self.width - 3
            else:
                width = self.textrendered.get_size ()[0]

            # now blit out the text
            destination.blit ( self.textrendered,
                               (self.position [0] + self.deltax + 3, self.position [1] + self.deltay+ 3) )
            
        self.dirty = 0
        

	# slm : render cursor
        if len(self.text):
                cursorx = self.font.size(self.text[0:self.cursor])[0]
                cursor_space = self.font.size(" ")[0] / 2

                destination.blit(self.cursor_image,
                        (
                                (self.position [0] + self.deltax)+(cursorx+cursor_space),
                                (self.position [1] + self.deltay+ 3)
                        )
                )

	
        # we did something, make sure the widget manager knows that
        return 1



    def keyDown (self,  event):
 	"""Callback triggered when the user presses a key inside the editfield. Gets the pressed key
        and modifies the internal string if needed. Renders a new surface too if needed. Some
        special keys are ignored."""

        # get the key and the unicode string
        key = event.key

        # Weird fix. This is required on RedHat pygame 1.5.3??
        ev_unicode = event.unicode
        if type(ev_unicode) == unicode or type(ev_unicode) == str:
            if ev_unicode == '':
                ev_unicode = 0
            else:
                ev_unicode = ord(ev_unicode)

        value = unichr(ev_unicode).encode('latin1')

        # a special key?
        if key == K_BACKSPACE:
            # remove one character
            self.text = self.text [0:self.cursor - 1]

            # update cursor position
            self.cursor -= 1
            if self.cursor < 0:
                self.cursor = 0

            # what text should we render?
            if len(self.text) == 0:
                # no text, so use something empty
                text = ' '
            else:
                # we have text, use it
                text = self.text

            # render the new surface
            self.textrendered = self.font.render ( text, 1, self.color )

            # we're dirty now
            self.dirty = 1
            return

        if key == K_DELETE:
            # remove one character from the right
            self.text = self.text [0:self.cursor] + self.text[self.cursor + 1:]

            # what text should we render?
            if len(self.text) == 0:
                # no text, so use something empty
                text = ' '
            else:
                # we have text, use it
                text = self.text

            # render the new surface
            self.textrendered = self.font.render ( text, 1, self.color )

            # we're dirty now
            self.dirty = 1
            return

        if key == K_TAB or key == K_RETURN:
            # remove one character from the right
            print "editfield.keyDown(): tab/return not handled"
            return

        # arrow handling
        elif key == K_LEFT:
            self.cursor -= 1
            if self.cursor < 0:
                self.cursor = 0

        elif key ==  K_RIGHT:
            self.cursor += 1
            if self.cursor > len(self.text):
                self.cursor = len(self.text)

        elif key == K_HOME:
            # move to the first position
            self.cursor = 0

        elif key == K_END:
            # move the the last position
            self.cursor = len(self.text)

        elif ev_unicode != 0:
            # a normal key pressed, merge in the text
            self.text = self.text [0:self.cursor] + value + self.text[self.cursor:]

            # update cursor position
            self.cursor += 1

            # do we still have any text left?
            if self.text == "":
                self.textrendered = None
                self.cursor = 0
            else:
                # set the new surface
                self.textrendered = self.font.render ( self.text, 1, self.color )

            # we're dirty now
            self.dirty = 1
	    return

    def createBorder (self):
        """Creates the border for the widget. Uses the 8 static icons and creates a surface that is
        slightly larger than the text surface (self.textsurface). This method is one ugly thing of
        coordinates and offsets. Don't touch unless you know what you do."""
        # get the delta values. These are used so that we know where to paint the text surface
        self.deltax = EditField.frameicons ['left'].get_width()
        self.deltay = EditField.frameicons ['top'].get_height()

        # get height and width of new surface
        size   = self.textsurface.get_size ()
        width  = size[0] + self.deltax + EditField.frameicons ['right'].get_width()
        height = size[1] + self.deltay + EditField.frameicons ['bot'].get_height()

        # create the needed surface
        self.surface = pygame.Surface ( (width, height), HWSURFACE ).convert ()

        # now some gory details. We need to blit stuff onto our frame surface to create the actual
        # frame. We first blit out the borders and the the corners. the corners then overpaint the
        # borders at proper positions
        top      = EditField.frameicons ['top']
        bot      = EditField.frameicons ['bot']
        left     = EditField.frameicons ['left']
        right    = EditField.frameicons ['right']
        topleft  = EditField.frameicons ['topleft']
        topright = EditField.frameicons ['topright']
        botleft  = EditField.frameicons ['botleft']
        botright = EditField.frameicons ['botright']

        # top/bottom borders
        x = 0
        while x < width:
            # what width should be used?
            if x + top.get_size ()[0] < width:
                # full width of icon
                widthx = top.get_size ()[0]
            else:
                # use only the missing part
                widthx = width - x

            # blit it all out
            self.surface.blit ( top, ( x, 0))
            self.surface.blit ( bot, ( x, height - bot.get_height () + 1 ) )
            x += widthx

        # left/right borders
        y = 0
        while y < height:
            # what height should be used?
            if y + left.get_size ()[1] < height:
                # full height of icon
                heighty = left.get_size ()[1]
            else:
                # use only the missing part
                heighty = height - y

            # blit it all out
            self.surface.blit ( left, ( 0, y ))
            self.surface.blit ( right, ( width - right.get_size ()[0], y ))
            y += heighty
        

        # top left corner
        self.surface.blit ( topleft, ( 0, 0 ))

        # top right corner
        self.surface.blit ( topright, ( width -  topright.get_width (), 0 ))

        # bottom left corner
        self.surface.blit ( botleft, ( 0, height - botleft.get_height () ))

        # bottom right corner
        self.surface.blit ( botright, ( width -  botright.get_width(), height - botright.get_height()))

#  Local Variables:
#  mode: auto-fill
#  fill-column: 100
#  End:
