#!/usr/bin/python

#   Copyright (C) 2002-2003 Yannick Gingras <ygingras@ygingras.net>
#   Copyright (C) 2002-2003 Vincent Barbin <vbarbin@openbeatbox.org>

#   This file is part of Open Beat Box.

#   Open Beat Box 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.

#   Open Beat Box 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 General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with Open Beat Box; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


from qt import *
from OBBFuncts import *

ORIGIN = QPoint(0, 0)

NO_BORDER_FLAGS = Qt.WStyle_Customize \
                  + Qt.WStyle_NoBorder \
                  + Qt.WRepaintNoErase \
                  + Qt.NoBackground \
                  + Qt.WType_TopLevel

MIN_MOVE_REDRAW_MAGNITUDE = 4

class Floater(QWidget):
    def __init__(self, parent=None, name="Floater"):
        QWidget.__init__(self, parent, name, NO_BORDER_FLAGS)
        self.subWidgets = []
        self.revChildList = []
        self.setDrag(0)
        self.mouseReleaseAction = None
        self.setBackgroundMode(Qt.NoBackground)

    def addSubWidget(self, widget):
        # stacking order for repaints
        self.subWidgets.append(widget)
        self.updateMask()

        # inverse order for events
        self.revChildList = list(self.subWidgets)
        self.revChildList.reverse()

    def updateMask(self):
        # set size and mask of the 1st(lower) widget
        size = self.subWidgets[0].size()
        self.setMinimumSize(size)
        self.setMaximumSize(size)
        self.region = self.subWidgets[0].opaqueRegion()
        self.setMask(self.region)
        
        # add the rest on top of it
        for widget in self.subWidgets[1:]:
            opaqueRegion = self.region
            widgetRegion = widget.opaqueRegion()
            newRegion = opaqueRegion.unite(widgetRegion)
            self.setMask(newRegion)
            self.region = newRegion
            
            size = newRegion.boundingRect().size()
            self.setMinimumSize(size)
            self.setMaximumSize(size)

        # for repaint double buffering
        self.paintBuffer = QPixmap(self.size())

    def repaintWidget(self, widget, region):
        self.update(region.boundingRect())

    def paintEvent(self, event):
        # It was a hard desision I had to take, 
        # leave the repaint slow and readable or
        # fast and ugly.
        #                        -- YGingras
        selfRect = self.rect()
        painter = QPainter()
        painter.begin(self.paintBuffer)
        
        eventRect = event.rect()
        x = eventRect.x()
        y = eventRect.y()
        width = eventRect.width()
        height = eventRect.height()

        for widget in self.subWidgets:
            if widget.intersectsXY( x,
                                    y,
                                    width,
                                    height ):
                widgetX = widget.topLeft().x()
                widgetY = widget.topLeft().y()
                widgetRect = widget.boundingRect()
        
                invalidRectX = max(x, widgetX)
                invalidRectY = max(y, widgetY)
                invalidRectX2 = min(x+width, widgetX+widgetRect.width())
                invalidRectY2 = min(y+height, widgetY+widgetRect.height())
                invalidRectWidth = invalidRectX2 - invalidRectX
                invalidRectHeight = invalidRectY2 - invalidRectY

                mappedX = invalidRectX - widgetX
                mappedY = invalidRectY - widgetY

                widget.paintCurPixmapXY( mappedX,
                                         mappedY,
                                         invalidRectWidth,
                                         invalidRectHeight,
                                         0,
                                         0,
                                         painter )

        painter.end()
        painter.begin(self)
        painter.drawPixmap( event.rect().topLeft(),
                            self.paintBuffer,
                            event.rect())

    def reCenter(self):
        desktop = QApplication.desktop()
        point = QPoint( (desktop.width() - self.width())/2,
                        (desktop.height() - self.height())/2 )
        self.move(point)

    def setDrag(self, isDraged=1):
        self.draged = isDraged

    def isDraged(self):
        return self.draged

    def drag(self, event):
        selfGeoPos = self.geometry().topLeft()
        frameGeoPos = self.frameGeometry().topLeft()
        
        geometryOffsetX = selfGeoPos.x() - frameGeoPos.x()
        geometryOffsetY = selfGeoPos.y() - frameGeoPos.y()

        mappedX = event.pos().x() - geometryOffsetX
        mappedY = event.pos().y() - geometryOffsetY
        
        if self.isDraged() and not qApp.hasPendingEvents():
            newPosX = event.globalPos().x() - self.lastMovePos.x()
            newPosY = event.globalPos().y() - self.lastMovePos.y()

            self.move(newPosX, newPosY)
            self.moved = 1

    def startDrag(self, event):
        self.setDrag(1)
        self.dragOrigin = QPoint( event.globalPos() )
        mappedPoint = addOffset( event.pos(),
                                 pointOffset( self.geometry().topLeft(),
                                              self.frameGeometry().topLeft()))
        self.lastMovePos = mappedPoint
        self.clickPos = mappedPoint
        self.grabMouse()

    def captureMouse(self, func):
        """captureMouse : like QWidget.grabMouse() but call func when the
        mouse is released"""
        self.mouseReleaseAction = func
        self.grabMouse()


    # events
    def mouseMoveEvent(self, e):
        if self.isDraged():
            return self.drag(e)

        for widget in self.revChildList:
            if widget.containsPoint(e.pos()):
                return widget.mouseMoveEvent(e)

    def mouseReleaseEvent(self, e):
        self.setDrag(0)

        self.releaseMouse()
        
        for widget in self.revChildList:
            if widget.containsPoint(e.pos()):
                widget.mouseReleaseEvent(e)
                break # we're done when we find the 1st matching child
            
        if self.mouseReleaseAction:
            self.mouseReleaseAction()
            self.mouseReleaseAction = None


    def mousePressEvent(self, e):
        # TODO handle the right click
        self.moved = 0
        for widget in self.revChildList:
            if widget.containsPoint(e.pos()):
                return widget.mousePressEvent(e)

    def mouseDoubleClickEvent(self, e):
        for widget in self.revChildList:
            if widget.containsPoint(e.pos()):
                return widget.mouseDoubleClickEvent(e)

    def keyPressEvent(self, e):
        pass

    def keyReleaseEvent(self, e):
        pass

    def wheelEvent(self, e):
        for widget in self.revChildList:
            if widget.containsPoint(e.pos()):
                return widget.wheelEvent(e)
        
