# 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

"""Pyui Themes.
Themes are a method of customizing the drawing of widgets in a pyui GUI.

This modules keeps NO state for the drable objects - it just draws them on demand
from the widgets themselves which hold all the state.

The constants for the theme objects live in pyui/locals.py
"""

import locals
import pyui
from pyui.desktop import getRenderer
from pyui.theme import dataTheme

class theme2k(dataTheme):
    """A theme that looks like win2k
    """

    emptyRect = [0,0,0,0]
    
    def __init__(self, renderer, w, h):
        self.frameBorderLeft = 4
        self.frameBorderRight = 4
        self.frameBorderTop = 26
        self.frameBorderBottom = 4
        self.tabsHeight = int(pyui.locals.TEXT_HEIGHT * 1.3)
        self.colorKey = (0,0,0,255)
        self.renderer = renderer

        # theme colors        
        self.fgColor = renderer.packColor(0,0,0)
        self.bgSelect = renderer.packColor(200,224,216)
        self.bgColor1 = renderer.packColor(200,224,216)
        self.bgColor2 = renderer.packColor(136,192,184)
        self.bgColor3 = renderer.packColor(220,210,222)
        self.listSelect = renderer.packColor(1,9,131)
        self.bgMenuBar = self.bgColor2
        self.bgMenuPanel = self.bgColor2
        self.bgMenuSelect = self.listSelect
        self.black = renderer.packColor(0,0,0)
        self.white = renderer.packColor(255,255,255)
        self.shadeHi0 = renderer.packColor(255,255,255,0)
        self.shadeHi1 = renderer.packColor(255,255,255,255)
        self.shadeLo0 = renderer.packColor(0,0,0,0)
        self.shadeLo1 = renderer.packColor(0,0,0,255)
        self.buttonUpA = renderer.packColor(210,200,215)
        self.buttonUpB = renderer.packColor(190,180,180)
        self.buttonRoA = renderer.packColor(150,196,189)
        self.buttonRoB = renderer.packColor(180,190,200)
        self.buttonDnA = renderer.packColor(170,170,170)
        self.buttonDnB = renderer.packColor(180,180,200)
        self.buttonFocus = renderer.packColor(128,192,255,128)
        self.captionA = renderer.packColor(0,0,100)
        self.captionB = renderer.packColor(24,180,192)
        self.frameColor = renderer.packColor(120,120,140)
        self.shadowMedium = renderer.packColor(0,0,0,128)
        self.themeConstants = {}
        self.themeConstants[locals.THEME_SCREEN_WIDTH]     = w
        self.themeConstants[locals.THEME_SCREEN_HEIGHT]    = h
        
        self.arrowCursor = None #pygame.cursors.compile(pyui.mouse.arrow_strings, ".", "X")
        self.resizeCursor = None #pygame.cursors.compile(pyui.mouse.diagResize1_strings, ".", "X")
        self.buttonCursor = None #pygame.cursors.compile(pyui.mouse.hand_strings, ".", "X")
        self.waitCursor = None #pygame.cursors.compile(pyui.mouse.hourglass_strings, ".", "X")


    def getThemeConstant(self, constantID):
        """Gets a theme constant.
        """
        if not self.themeConstants.has_key(constantID):
            return None
        return self.themeConstants[constantID]

    ### Information about the theme..
    def getFrameBorderTop(self):
        return self.frameBorderTop

    def getFrameBorderLeft(self):
        return self.frameBorderLeft
    
    def getFrameBorderRight(self):
        return self.frameBorderRight
    
    def getFrameBorderBottom(self):
        return self.frameBorderBottom
    
    def getTabsHeight(self):
        return self.tabsHeight
    
    def getColorKey(self):
        return self.colorKey

    def getFgColor(self):
        return self.fgColor

    def getBgColor(self):
        return self.bgColor1

    
    #####################################################################
    ###
    ###   Utility drawing functions not specific to any widgets
    ###
    #####################################################################    

    def draw3DRect(self, rect, color, reverse):
        """Draw a 3D rectangle to the screen or a surface. Defaults to the screen.
        (internal)
        """
        (r,g,b,a) = self.renderer.unpackColor(color)
        colorLo = pyui.colors.black #self.renderer.packColor(r/2, g/2, b/2, a)
        colorHi = pyui.colors.white #self.renderer.packColor(128 + r/2, 128 + g/2, 128 + b/2, a)

        if reverse:
            (colorLo, colorHi) = (colorHi, colorLo)
            
        (x,y,w,h) = rect
        if w < 2 or h < 2:
            return
        
        getRenderer().drawRect( colorHi, (x, y, w-1, 1) )
        getRenderer().drawRect( colorHi, (x, y+1, 1, h-2) )
        if w > 2 and h > 2:
            getRenderer().drawRect( color, (x+1, y+1, w-2, h-2) )
        getRenderer().drawRect( colorLo, (x+1, y+h-1, w-1, 1) )
        getRenderer().drawRect( colorLo, (x+w-1, y+1, 1, h-2) )

    def shadeBorder(self, rect, d, reverse):
        """Draw a 3D rectangle to the screen or a surface. Defaults to the screen.
        (internal)
        """
        (x,y,w,h) = rect
        if reverse:
            getRenderer().drawGradient((x,y,d,h), self.shadeLo1, self.shadeLo0, self.shadeLo1, self.shadeLo0)
            getRenderer().drawGradient((x,y,w,d), self.shadeLo1, self.shadeLo1, self.shadeLo0, self.shadeLo0)
            getRenderer().drawGradient((x+w-d,y,d,h), self.shadeHi0, self.shadeHi1, self.shadeHi0, self.shadeHi1)
            getRenderer().drawGradient((x,y+h-d,w,d), self.shadeHi0, self.shadeHi0, self.shadeHi1, self.shadeHi1)
        else:
            getRenderer().drawGradient((x,y,d,h), self.shadeHi1, self.shadeHi0, self.shadeHi1, self.shadeHi0)
            getRenderer().drawGradient((x,y,w,d), self.shadeHi1, self.shadeHi1, self.shadeHi0, self.shadeHi0)
            getRenderer().drawGradient((x+w-d,y,d,h), self.shadeLo0, self.shadeLo1, self.shadeLo0, self.shadeLo1)
            getRenderer().drawGradient((x,y+h-d,w,d), self.shadeLo0, self.shadeLo0, self.shadeLo1, self.shadeLo1)

    def drawOutlineRect(self, rect, color, thick=1):
        (x,y,w,h) = rect
        getRenderer().drawRect(color, (x,y,w,thick))
        getRenderer().drawRect(color, (x,y+thick,thick,h-2*thick))
        getRenderer().drawRect(color, (x+w-thick,y+thick,thick,h-2*thick))
        getRenderer().drawRect(color, (x,y+h-thick,w,thick))


    def drawGradient(self, rect, vertical, c1, c2):
        if vertical:
            getRenderer().drawGradient(rect, c1, c2, c1, c2)            
        else:
            getRenderer().drawGradient(rect, c1, c1, c2, c2)
        
    ### mouse cursor functions
    def setArrowCursor(self):
        #pygame.mouse.set_cursor( (24,24), (0,0), self.arrowCursor[0], self.arrowCursor[1])
        pass

    def setResizeCursor(self):
        #pygame.mouse.set_cursor( (24,24), (0,0), self.resizeCursor[0], self.resizeCursor[1])
        pass

    def setButtonCursor(self):
        #pygame.mouse.set_cursor( (24,24), (0,0), self.buttonCursor[0], self.buttonCursor[1])
        pass

    def setWaitCursor(self):
        #pygame.mouse.set_cursor( (24,24), (0,0), self.waitCursor[0], self.waitCursor[1])
        pass
        
    #####################################################################
    ###
    ### Widgets specific drawing functions.
    ###
    #####################################################################    
    def drawButton(self, rect, title, hasFocus, status, enabled):
        """Options are:  button title and the up/down status.
        status == 0: normal
        status == 1: rollover
        status == 2: down
        """
        (x,y,w,h) = rect
        color = self.fgColor        
        if enabled == 0:
            self.draw3DRect(rect, self.bgColor3, 0)
            color = self.buttonUpB
        elif status == 0:
            self.draw3DRect(rect, self.bgColor2, 0)
        elif status == 1:
            self.draw3DRect(rect, self.buttonRoA, 0)
        elif status == 2:
            self.draw3DRect(rect, self.buttonRoA, 1)
            x += 1
            y += 1

        #if hasFocus:
        #    self.drawOutlineRect(rect, self.buttonFocus, 1)

        size = getRenderer().getTextSize(title)
        getRenderer().drawText( title, (x + (w-size[0])/2, y + (h-size[1])/2), color)
        return rect

    def drawImageButton(self, rect, filename, title, hasFocus, status):
        if status == 2:
            self.draw3DRect(rect, self.bgColor1, 1)
        else:
            self.draw3DRect(rect, self.bgColor1, 0)
        getRenderer().drawImage((rect[0] + status, rect[1] + status, rect[2]-2, rect[3]-2), filename)
        self.shadeBorder(rect, 4, 0)
        (w,h) = getRenderer().getTextSize(title)

        if hasFocus:
            self.drawOutlineRect(rect, self.buttonFocus, 3)
        
        getRenderer().drawText( title, (rect[0] + (rect[2]-w)/2 + status, rect[1] + (rect[3]-h)/2 + status-1), self.black)
        getRenderer().drawText( title, (rect[0] + (rect[2]-w)/2 + status-1, rect[1] + (rect[3]-h)/2 + status), self.white)

    def drawLabel(self, rect, title, color = None):
        #(title, color) = options
        if not color:
            color = self.fgColor
        (w,h) = getRenderer().getTextSize(title)
        getRenderer().drawText(title, (rect[0], rect[1]), color)
        return (rect[0], rect[1], w, h)

    def drawCheckBox(self, rect, text, checkState):
        w = rect[2]
        h = rect[3]
        checkboxXpos = rect[0] + 8        
        checkboxYpos = rect[1] + (h/2) - 8

        self.draw3DRect( (checkboxXpos, checkboxYpos, 16, 16), self.bgColor1, 1)
        getRenderer().drawText( text, (checkboxXpos + 20, checkboxYpos ), self.fgColor)

        if checkState:
            getRenderer().drawLine( checkboxXpos + 2, checkboxYpos + 2, checkboxXpos + 14, checkboxYpos + 14, pyui.colors.white)
            getRenderer().drawLine( checkboxXpos + 14, checkboxYpos + 2, checkboxXpos + 2 , checkboxYpos + 14, pyui.colors.white)            

    def drawSliderBar(self, rect, range, position, BARWIDTH=8):
        interval = rect[2] / float(range)
        half = rect[1] + rect[3]/2
        getRenderer().drawRect(self.bgSelect, rect)
        ## could draw little lines here....
        getRenderer().drawLine( rect[0] + 1, half, rect[0] + rect[2] -2, half, pyui.colors.white)
        getRenderer().drawLine( rect[0] + 1, half + 2, rect[0] + rect[2] -2, half + 2, pyui.colors.black)
        diff = rect[2] - BARWIDTH
        xpos = float(diff) / range * position
        barHeight = rect[3] - 4
        if barHeight > 20:
            barHeight = 20
            
        self.draw3DRect((rect[0] + xpos, rect[1] + (rect[3]/2) - (barHeight/2), BARWIDTH, barHeight), self.bgMenuBar, 0)

        getRenderer().drawText("%s/%s" % (position,range), (rect[0] + rect[2] - 40, rect[1]), pyui.colors.red)

            
    def drawEdit(self, rect, text, hasFocus, caretPos, selectPos):
        self.draw3DRect(rect, self.bgColor1, 1)
        (x,y,w,h) = rect
        if hasFocus:
            caretX = getRenderer().getTextSize(text[0:caretPos])[0]
            if selectPos != None:
                # draw selection highlight
                selectX = getRenderer().getTextSize(text[0:selectPos])[0]
                selectX0 = min(caretX, selectX)
                selectX1 = max(caretX, selectX)
                if selectX0 < selectX1:
                    getRenderer().drawRect(self.bgSelect, (x+1+selectX0, y+1, selectX1-selectX0, locals.TEXT_HEIGHT))

        getRenderer().drawText(text, (x+1, y+1), self.fgColor)

        # draw caret        
        if hasFocus:
            getRenderer().drawRect(self.fgColor, (x+1+caretX, y+1, 1, locals.TEXT_HEIGHT))

        return rect

    def drawFrame(self, rect, title):
        """Draw frame objects.
        Frame objects are complex multi-part widgets. In order to allow the theme some flexibility of how to
        position and draw various interactive frame elements, the drawFrame() method returns a list of hit
        regions. Each element is a tuple consisting of a (region Id, rect). Region IDs are defined in locals.py.
        The hit list is in top to bottom order for easier iteration.
        """
        offset = 8
        hitList = []
        # draw caption bar        
        (x,y,w,h)=(rect[0], rect[1], rect[2], self.frameBorderTop)
        self.drawGradient((x, y, w, h), 1, self.captionA, self.captionB)
        getRenderer().drawText( title, (x + self.frameBorderLeft + 1, y + self.frameBorderTop/2 - 8), self.bgColor1)
        self.shadeBorder((x,y,w,h), 3, 0)
        hitList.append((locals.HIT_FRAME_MOVE, (x,y,w,h)))

        # draw close button        
        (x,y,w,h)=(rect[0]+rect[2]-self.frameBorderTop+6,rect[1]+5,self.frameBorderTop-12,self.frameBorderTop-10)
        self.draw3DRect((x,y,w,h), self.bgColor2,0)
        hitList.append((locals.HIT_FRAME_CLOSE, (x,y,w,h)))

        (x,y,w,h) = rect
        getRenderer().drawLine(x,y,x+w,y, self.white)
        getRenderer().drawLine(x,y,x,y+h, self.white)        
        getRenderer().drawLine(x+w,y,x+w,y+h, self.black)
        getRenderer().drawLine(x+w,y+h,x,y+h, self.black)                
        
        # left border
        (x,y,w,h)=(rect[0],
                   rect[1]+self.frameBorderTop,
                   1,
                   rect[3]-self.frameBorderTop)

        # right border                
        (x,y,w,h)=(rect[0]+rect[2]-4,
                   rect[1]+self.frameBorderTop,
                   4,
                   rect[3]-self.frameBorderTop)
        hitList.append((locals.HIT_FRAME_RESIZE_RIGHT, (x,y,w,h)))

        # bottom border
        (x,y,w,h)=(rect[0],
                   rect[1]+rect[3]-4,
                   rect[2],
                   4)
        hitList.append((locals.HIT_FRAME_RESIZE_BOTTOM, (x,y,w,h)))

        # lower right corner
        (x,y,w,h)=(rect[0]+rect[2]-self.frameBorderRight,
                   rect[1]+rect[3]-self.frameBorderBottom,
                   self.frameBorderRight,
                   self.frameBorderBottom)
        self.draw3DRect((x,y,w,h), self.bgColor2, 0)
        hitList.append((locals.HIT_FRAME_RESIZE_BOTTOM_RIGHT, (x,y,w,h)))

        hitList.reverse()        
        return hitList        
        
    def drawBack1(self, rect):
        self.drawGradient(rect, 0, self.bgColor1, self.bgColor2)
        return rect

    def drawBack2(self, rect):
        self.drawGradient(rect, 0, self.bgColor2, self.fgColor)
        return rect

    def drawBack3(self, rect):
        self.drawGradient(rect, 0, self.bgColor3, self.bgColor1)        
        return rect
    
    def drawScrollButtonUp(self, rect):
        self.draw3DRect(rect, self.bgColor2, 0)
        return rect

    def drawScrollButtonDown(self, rect):
        self.draw3DRect(rect, self.bgColor2, 0)
        return rect

    def drawScrollBar(self, rect):
        self.draw3DRect(rect, self.bgColor2, 0)
        return rect


    def drawTabItem(self, rect, title, active):
        gap = 3
        (x,y,w,h) = rect
        getRenderer().drawRect(self.black, (x, y+h-1, gap, 1))
        x += gap
        title = " " + title + " "
        w = getRenderer().getTextSize(title)[0]
        if active:
            getRenderer().drawRect(self.black, (x, y, w, 1))
            getRenderer().drawRect(self.black, (x, y, 1, h))
            getRenderer().drawRect(self.black, (x+w-1, y, 1, h))
        else:
            getRenderer().drawRect(self.bgColor2, (x, y, w, h))
            self.drawOutlineRect((x, y, w, h), self.black)
            pass
        getRenderer().drawRect(self.shadowMedium, (x+w, y+gap, gap, h-gap))

        getRenderer().drawText( title, (x, y), self.fgColor)
        return (x,y,w,h)

    def drawTabHeader(self, rect):
        (x,y,w,h) = rect
        getRenderer().drawRect(self.black, (x, y+h-1, w, 1))
        return rect

    def drawMenuBar(self, rect):
        self.draw3DRect(rect, self.bgMenuBar, 0)
        return rect

    def drawMenuBarItem(self, rect, title, selected):
        title = "   " + title + "   "
        (w,h) = getRenderer().getTextSize(title)
        if selected:
            getRenderer().drawRect(self.bgMenuSelect, (rect[0], rect[1], w, rect[3]))
            getRenderer().drawText(title, (rect[0], rect[1]), self.bgColor1)
        else:
            getRenderer().drawText(title, (rect[0], rect[1]), self.fgColor)
        return (rect[0], rect[1], w, rect[3])

    def drawMenu(self, rect):
        self.draw3DRect(rect, self.bgMenuPanel, 0)
        # draw shadow
        offset = 4
        (x,y,w,h)=(rect[0], rect[1], rect[2], rect[3])
        getRenderer().drawRect( self.shadowMedium, (x+w, y+offset, offset, h - offset) )
        getRenderer().drawRect( self.shadowMedium, (x+offset, y+h, w, offset) )
        return rect
    
    def drawMenuItem(self, rect, title, selected, icon = None):
        iconSize = 12
        color = self.fgColor
        if selected:
            getRenderer().drawRect(self.bgMenuSelect, (rect[0], rect[1], rect[2], locals.TEXT_HEIGHT))
            color = self.bgColor1
        if title == '-':
            self.draw3DRect((rect[0], rect[1] + locals.TEXT_HEIGHT / 2- 1, rect[2], 2), self.bgMenuPanel, 1)
        else:
            getRenderer().drawText(title, (rect[0] + iconSize, rect[1]), color)
        if icon:
            getRenderer().drawImage((rect[0], rect[1]+(locals.TEXT_HEIGHT - iconSize) / 2, iconSize, iconSize), icon)
        return (rect[0], rect[1], rect[2], locals.TEXT_HEIGHT)

    def drawListBoxItem(self, rect, title, selected, color):
        if selected:
            getRenderer().drawRect(self.listSelect, (rect[0] +2, rect[1] - 1, rect[2]- 1 - 3, rect[3] ))
            getRenderer().drawText(title, (rect[0], rect[1]), self.bgColor1)
        else:
            getRenderer().drawText(title, (rect[0], rect[1]), color)
        return rect
            
    def drawSplitter(self, rect):
        (x,y,w,h) = rect
        getRenderer().drawRect(self.frameColor, (x,y,w,h))
        self.shadeBorder((x,y,w,h), 2, 0)
        #self.draw3DRect(rect,self.bgColor3, 0)

    def drawToolTip(self, text, rect):
        getRenderer().drawRect(self.black, rect)
        getRenderer().drawRect(pyui.colors.yellow, (rect[0] + 1, rect[1] + 1, rect[2] - 2, rect[3] - 2))
        getRenderer().drawText(text, (rect[0] + 2, rect[1] + 2), pyui.colors.black)
