# PyUI
# Copyright (C) 2001-2002 Sean C. Riley
# 
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
# 
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from Tkinter import *
from tkFont import Font
import pyui.core
from pyui.locals import *
import string

from pyui.desktop import getDesktop

class rendererTk(pyui.core.RendererBase):
    """Tkinter renderer.
    """
    def __init__(self, w, h, fullscreen):
        pyui.core.RendererBase.__init__(self, w, h, fullscreen)
        root=Tk()
        self.root=root
        def options(**o):return o
        if fullscreen:
            self.options = options(width=root.winfo_screenwidth(),height=root.winfo_screenheight(),background="#000000")
        else:
            self.options= options(width=w,height=h,background="#000000")
        self.screen=None
        self.lastID = 1000
        self.windows = {}
        self.images = {}
        self.clip = None
        root.bind("<Button-1>",self.mouse1Down)
        root.bind("<Button-3>",self.mouse3Down)
        root.bind("<ButtonRelease-1>",self.mouse1Up)
        root.bind("<ButtonRelease-3>",self.mouse3Up)
        root.bind("<B1-Motion>",self.mouseMotion)
        root.bind("<B3-Motion>",self.mouseMotion)
        root.bind("<Key>",self.keyDown)
        self.clip=[0,0,w,h]
        self.default_clip=self.clip
        self.items=[]

    def draw(self, windows, widgets):
        if self.screen and self.mustFill:
            # faster to destroy and recreate the Canvas than to delete all objects
            self.screen.destroy()
            self.screen=None
        if not self.screen:
            self.screen=apply(Canvas,(self.root,),self.options)
            self.screen.pack()
        else:
            for x,y,w,h in self.dirtyRects:
                items=self.screen.find_overlapping(x,y,x+w,y+h)
                self.screen.delete(items)
        self.dirtyRects=[]
        for w in windows:
            w.setDirty(1)
            n =  w.drawWindow(self)
            if n:
                for command in w.drawCommands:
                    self.doDrawCommand(command)
        self.mustFill = 0


    ###############################################################################
    ### Draw Primatives functions
    ###############################################################################
        
    def drawRect(self, color, rect):
        """Fills a rectangle with the specified color."""
        self.drawList.append( [RECT, rect, color] )

    def drawText(self, text, pos, color):
        """Draws the text on the screen in the specified position"""
        self.drawList.append( [TEXT, text, pos, color] )

    def drawGradient(self, rect, c1, c2, c3, c4):
        """Draws a gradient rectangle"""
        self.drawList.append( [GRADIENT, rect, c1, c2, c3, c4 ] )

    def drawImage(self, rect, filename):
        """Draws an image at a position"""
        self.drawList.append( [IMAGE, rect, filename] )

    def loadImage(self, filename, handle = None):
        try:
            img = PhotoImage(self.screen,file=filename)
            if handle:
                self.images[handle] = img
            else:
                self.images[filename] = img
        except:
            print "Failed to load image: ", filename

    def setClipping(self, rect = None):
        """set the clipping rectangle for the main screen. defaults to clearing the clipping rectangle."""
        self.drawList.append( [CLIP, rect] )

    ###############################################################################
    ### actual drawing functions
    ###############################################################################

    def doDrawCommand(self, command):
        cmd = command[0]
        if cmd == RECT:
            #print "RECT: " ,command[1], command[2]
            rect,color=command[1:]
            color=self.getTkColor(color)
            rect=self.containedRect(rect,self.clip)
            if not rect: return
            x,y,w,h=rect
            self.screen.create_rectangle(x,y,x+w,y+h,fill=color,outline="",width=0)
            return 2
        elif cmd == TEXT:
            if len(command[1]) == 0:
                return
            text,pos,color=command[1:]
            f=Font(size=10)
            ourlen=f.measure(text)
            rect=[pos[0]+10,pos[1]+1,ourlen,20-1]
            rect=self.containedRect(rect,self.clip)
            if not rect: return
            l=1
            while 1:
                if f.measure(text[:l])<=rect[2] and l<=len(text): l=l+1
                else: break
            text=text[:l-1]
            color=self.getTkColor(color)
            self.screen.create_text(rect[0],rect[1],text=text,fill=color,anchor=NW,font=f)
            return len(command[1])
        elif cmd == IMAGE:
            rect,image=command[1:]
            self.screen.create_image(rect[0],rect[1],self.images[image])
            return 2
        elif cmd == GRADIENT:
            rect,c1,c2,c3,c4=command[1:]
            color=self.getTkColor(c1)
            rect=self.containedRect(rect,self.clip)
            if not rect: return
            x,y,w,h=rect
            self.screen.create_rectangle(x,y,x+w,y+h,fill=color,outline="",width=0)
            return 2
        elif cmd == CLIP:
            self.clip=command[1]
            if self.clip==None:
                self.clip=self.default_clip
        return 0
 
    def update(self):
        ## process all pending system events.
        self.root.update()
        return

    def mouse1Down(self,e):
        getDesktop().postUserEvent(LMOUSEBUTTONDOWN, e.x, e.y)
    def mouse3Down(self,e):
        getDesktop().postUserEvent(RMOUSEBUTTONDOWN, e.x, e.y)
    def mouse1Up(self,e):
        getDesktop().postUserEvent(LMOUSEBUTTONUP, e.x, e.y)
    def mouse3Up(self,e):
        getDesktop().postUserEvent(RMOUSEBUTTONUP, e.x, e.y)
    def mouseMotion(self,e):
        getDesktop().postUserEvent(MOUSEMOVE, e.x, e.y)
    def keyDown(self,e):
        try:
            k=ord(e.char)
        except:
            if TKTOSDLKEYS.has_key(e.keysym):
                k=TKTOSDLKEYS[e.keysym]
            else:
                return
        m=0
        if CTRL&e.state: m=m+MOD_CONTROL
        if ALT&e.state: m=m+MOD_ALT
        if SHIFT&e.state: m=m+MOD_SHIFT
            
        getDesktop().postUserEvent(KEYDOWN,0,0,k,m)

    def quit(self):
        self.root.quit()

    def packColor(self, r, g, b, a=255):
        """pack the rgb triplet into a color
        """
        return (r, g, b, a)

    def getTkColor(self, color):
        c="#%02x%02x%02x"%(color[0],color[1],color[2])
        return c

    def containedRect(self, small, big):
        x1,y1,w1,h1=small
        x2,y2,w2,h2=big
        if x1>x2+w2: return
        if y1>y2+h2: return
        if x1+w1<x2: return
        if y1+h1<y2: return
        if x1<x2:
            w1=(x1+w1)-x2
            x1=x2
        if y1<y2:
            h1=(y1+h1)-y2
            y1=y2
        if x1+w1>x2+w2:
            w1=(x2+w2)-x1
        if y1+h1>y2+h2:
            h1=(y2+h2)-y1
        return [x1,y1,w1,h1]

TKTOSDLKEYS={}
TKTOSDLKEYS["Left"]=K_LEFT
TKTOSDLKEYS["Right"]=K_RIGHT
TKTOSDLKEYS["Up"]=K_UP
TKTOSDLKEYS["Down"]=K_DOWN
TKTOSDLKEYS["Backspace"]=K_BACKSPACE
TKTOSDLKEYS["Delete"]=K_DELETE
TKTOSDLKEYS["Return"]=K_RETURN
CTRL=1<<2
ALT=1<<17
SHIFT=1
