#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Custom Mini Canvas Preview, a custom Qt widget
# Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com>
#
# 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 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
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the COPYING file

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

if True:
    from PyQt5.QtCore import pyqtSignal, Qt, QRectF, QTimer
    from PyQt5.QtGui import QBrush, QColor, QCursor, QPainter, QPen
    from PyQt5.QtWidgets import QFrame
else:
    from PyQt4.QtCore import pyqtSignal, Qt, QRectF, QTimer
    from PyQt4.QtGui import QBrush, QColor, QCursor, QPainter, QPen
    from PyQt4.QtGui import QFrame

# ------------------------------------------------------------------------------------------------------------
# Static Variables

iX = 0
iY = 1
iWidth  = 2
iHeight = 3

# ------------------------------------------------------------------------------------------------------------
# Widget Class

class CanvasPreviewFrame(QFrame):
    miniCanvasMoved = pyqtSignal(float, float)

    def __init__(self, parent):
        QFrame.__init__(self, parent)

        self.fUseCustomPaint = False

        self.fMouseDown = False

        self.fViewBg    = QColor(0, 0, 0)
        self.fViewBrush = QBrush(QColor(75, 75, 255, 30))
        self.fViewPen   = QPen(Qt.blue, 1)

        self.fScale = 1.0
        self.fScene = None
        self.fRealParent = None
        self.fFakeWidth  = 0.0
        self.fFakeHeight = 0.0

        self.fRenderSource = self.getRenderSource()
        self.fRenderTarget = QRectF(0, 0, 0, 0)

        self.fViewPadX = 0.0
        self.fViewPadY = 0.0
        self.fViewRect = [0.0, 0.0, 10.0, 10.0]

    def init(self, scene, realWidth, realHeight, useCustomPaint = False):
        padding = 6

        self.fScene = scene
        self.fFakeWidth  = float(realWidth) / 15
        self.fFakeHeight = float(realHeight) / 15

        self.setMinimumSize(self.fFakeWidth+padding,   self.fFakeHeight+padding)
        self.setMaximumSize(self.fFakeWidth*4+padding, self.fFakeHeight+padding)

        self.fRenderTarget.setWidth(realWidth)
        self.fRenderTarget.setHeight(realHeight)

        if self.fUseCustomPaint != useCustomPaint:
            self.fUseCustomPaint = useCustomPaint
            self.repaint()

    def setRealParent(self, parent):
        self.fRealParent = parent

    def getRenderSource(self):
        xPadding = (float(self.width())  - self.fFakeWidth) / 2.0
        yPadding = (float(self.height()) - self.fFakeHeight) / 2.0
        return QRectF(xPadding, yPadding, self.fFakeWidth, self.fFakeHeight)

    def setViewPosX(self, xp):
        x = self.fFakeWidth*xp
        xRatio = (x / self.fFakeWidth) * self.fViewRect[iWidth] / self.fScale
        self.fViewRect[iX] = x - xRatio + self.fRenderSource.x()
        self.update()

    def setViewPosY(self, yp):
        y = self.fFakeHeight*yp
        yRatio = (y / self.fFakeHeight) * self.fViewRect[iHeight] / self.fScale
        self.fViewRect[iY] = y - yRatio + self.fRenderSource.y()
        self.update()

    def setViewScale(self, scale):
        self.fScale = scale
        QTimer.singleShot(0, self.fRealParent.slot_miniCanvasCheckAll)

    def setViewSize(self, width, height):
        self.fViewRect[iWidth]  = width  * self.fFakeWidth
        self.fViewRect[iHeight] = height * self.fFakeHeight
        self.update()

    def setViewTheme(self, bgColor, brushColor, penColor):
        brushColor.setAlpha(40)
        penColor.setAlpha(100)
        self.fViewBg    = bgColor
        self.fViewBrush = QBrush(brushColor)
        self.fViewPen   = QPen(penColor, 1)

    def handleMouseEvent(self, eventX, eventY):
        x = float(eventX) - self.fRenderSource.x() - (self.fViewRect[iWidth]  / self.fScale / 2)
        y = float(eventY) - self.fRenderSource.y() - (self.fViewRect[iHeight] / self.fScale / 2)

        maxWidth  = self.fViewRect[iWidth] / self.fScale
        maxHeight = self.fViewRect[iHeight] / self.fScale

        if maxWidth > self.fFakeWidth:
            maxWidth = self.fFakeWidth
        if maxHeight > self.fFakeHeight:
            maxHeight = self.fFakeHeight

        if x < 0.0:
            x = 0.0
        elif x > self.fFakeWidth - maxWidth:
            x = self.fFakeWidth - maxWidth

        if y < 0.0:
            y = 0.0
        elif y > self.fFakeHeight - maxHeight:
            y = self.fFakeHeight - maxHeight

        self.fViewRect[iX] = x + self.fRenderSource.x()
        self.fViewRect[iY] = y + self.fRenderSource.y()
        self.update()

        self.miniCanvasMoved.emit(x * self.fScale / self.fFakeWidth, y * self.fScale / self.fFakeHeight)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.fMouseDown = True
            self.setCursor(QCursor(Qt.SizeAllCursor))
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseMoveEvent(self, event):
        if self.fMouseDown:
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseReleaseEvent(self, event):
        if self.fMouseDown:
            self.setCursor(QCursor(Qt.ArrowCursor))
        self.fMouseDown = False
        QFrame.mouseReleaseEvent(self, event)

    def paintEvent(self, event):
        painter = QPainter(self)

        if self.fUseCustomPaint:
            painter.setBrush(self.fViewBg)
            painter.setPen(QColor(12, 12, 12))
            painter.drawRect(0, 0, self.width(), self.height()-2)

            painter.setBrush(QColor(36, 36, 36))
            painter.setPen(QColor(62, 62, 62))
            painter.drawRect(1, 1, self.width()-2, self.height()-4)

            painter.setBrush(self.fViewBg)
            painter.setPen(self.fViewBg)
            painter.drawRect(2, 3, self.width()-5, self.height()-7)

        else:
            painter.setBrush(self.fViewBg)
            painter.setPen(self.fViewBg)
            painter.drawRoundedRect(2, 2, self.width()-6, self.height()-6, 3, 3)

        self.fScene.render(painter, self.fRenderSource, self.fRenderTarget, Qt.KeepAspectRatio)

        maxWidth  = self.fViewRect[iWidth]  / self.fScale
        maxHeight = self.fViewRect[iHeight] / self.fScale

        if maxWidth > self.fFakeWidth:
            maxWidth = self.fFakeWidth
        if maxHeight > self.fFakeHeight:
            maxHeight = self.fFakeHeight

        painter.setBrush(self.fViewBrush)
        painter.setPen(self.fViewPen)
        painter.drawRect(self.fViewRect[iX], self.fViewRect[iY], maxWidth, maxHeight)

        if self.fUseCustomPaint:
            event.accept()
        else:
            QFrame.paintEvent(self, event)

    def resizeEvent(self, event):
        self.fRenderSource = self.getRenderSource()

        if self.fRealParent is not None:
            QTimer.singleShot(0, self.fRealParent.slot_miniCanvasCheckAll)

        QFrame.resizeEvent(self, event)
