| 
							- #!/usr/bin/env python3
 - # -*- coding: utf-8 -*-
 - 
 - # Custom Mini Canvas Preview, a custom Qt widget
 - # Copyright (C) 2011-2020 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 doc/GPL.txt file.
 - 
 - # ---------------------------------------------------------------------------------------------------------------------
 - # Imports (Global)
 - 
 - from math import floor, ceil
 - 
 - from PyQt5.QtCore import pyqtSignal, Qt, QRectF, QTimer, QEvent, QPoint
 - from PyQt5.QtGui import QBrush, QColor, QCursor, QPainter, QPainterPath, QPen, QPixmap
 - from PyQt5.QtWidgets import QFrame, QGraphicsScene
 - 
 - # ---------------------------------------------------------------------------------------------------------------------
 - # Antialiasing settings
 - 
 - from patchcanvas import options, ANTIALIASING_FULL
 - 
 - # ---------------------------------------------------------------------------------------------------------------------
 - # Widget Class
 - 
 - class CanvasPreviewFrame(QFrame):
 -     miniCanvasMoved = pyqtSignal(float, float)
 - 
 -     # x = 2
 -     # y = 2
 -     # w = width - 4
 -     # h = height - 3
 -     # bounds -1 px
 - 
 -     _kRectX = 0
 -     _kRectY = 1
 -     _kRectWidth = 2
 -     _kRectHeight = 3
 - 
 -     _kCursorName = 0
 -     _kCursorZoom = 1
 -     _kCursorZoomIn = 2
 -     _kCursorZoomOut = 3
 -     _kCursorZoomCount = 4
 - 
 -     _MOUSE_MODE_NONE = 0
 -     _MOUSE_MODE_MOVE = 1
 -     _MOUSE_MODE_SCALE = 2
 - 
 -     _RUBBERBAND_BLENDING_DEFAULT = 0
 -     _RUBBERBAND_BLENDING_PLUS = 1
 -     _RUBBERBAND_BLENDING_DIFF = 2
 - 
 -     # -----------------------------------------------------------------------------------------------------------------
 - 
 -     def __init__(self, parent):
 -         QFrame.__init__(self, parent)
 - 
 -         #self.setMinimumWidth(210)
 -         #self.setMinimumHeight(162)
 -         #self.setMaximumHeight(162)
 - 
 -         self.fRealParent = None
 -         self.fInternalWidth  = 210-6 # -4 for width + -1px*2 bounds
 -         self.fInternalHeight = 162-5 # -3 for height + -1px*2 bounds
 -         self.fInternalRatio  = self.fInternalWidth / self.fInternalHeight
 - 
 -         self.fScene = None
 -         self.fRenderSource   = QRectF(0.0, 0.0, 0.0, 0.0)
 -         self.fRenderTarget   = QRectF(0.0, 0.0, 0.0, 0.0)
 -         self.fUseCustomPaint = False
 -         self.fFrameWidth = 0.0
 - 
 -         self.fInitialX = 0.0
 -         self.fInitialY = 0.0
 -         self.fScale    = 1.0
 - 
 -         self.fViewBg    = QColor(0, 0, 0)
 -         self.fViewBrush = QBrush(QColor(75, 75, 255, 30))
 -         self.fViewPen   = QPen(Qt.blue, 1)
 -         self.fViewRect  = [3.0, 3.0, 10.0, 10.0]
 - 
 -         self.fMouseMode = self._MOUSE_MODE_NONE
 -         self.fMouseLeftDown = False
 -         self.fMouseRightDown = False
 -         self.fMouseInitialZoomPos = None
 - 
 -         self.fRubberBandBlending = self._RUBBERBAND_BLENDING_DEFAULT
 - 
 -         self.fZoomCursors = [None for _ in range(self._kCursorZoomCount)]
 -         self.fZoomCursors[self._kCursorName] = "black"
 -         self.fZoomCursors[self._kCursorZoom] = QCursor(QPixmap(":/cursors/zoom_black.png"), 8, 7)
 -         self.fZoomCursors[self._kCursorZoomIn] = QCursor(QPixmap(":/cursors/zoom-in_black.png"), 8, 7)
 -         self.fZoomCursors[self._kCursorZoomOut] = QCursor(QPixmap(":/cursors/zoom-out_black.png"), 8, 7)
 - 
 -     def init(self, scene: QGraphicsScene, realWidth: float, realHeight: float, useCustomPaint: bool = False):
 -         self.fScene = scene
 -         self.fRenderSource = QRectF(0.0, 0.0, realWidth, realHeight)
 -         self.fInternalRatio = realWidth / realHeight
 -         self._updateStyle()
 - 
 -         if self.fUseCustomPaint != useCustomPaint:
 -             self.fUseCustomPaint = useCustomPaint
 -             self.repaint()
 - 
 -     def setRealParent(self, parent):
 -         self.fRealParent = parent
 - 
 -     # -----------------------------------------------------------------------------------------------------------------
 - 
 -     def setViewPosX(self, xp: float):
 -         self.fViewRect[self._kRectX] = xp * (self.fInternalWidth - self.fViewRect[self._kRectWidth]/self.fScale)
 -         self.update()
 - 
 -     def setViewPosY(self, yp: float):
 -         self.fViewRect[self._kRectY] = yp * (self.fInternalHeight - self.fViewRect[self._kRectHeight]/self.fScale)
 -         self.update()
 - 
 -     def setViewScale(self, scale: float):
 -         self.fScale = scale
 - 
 -         if self.fRealParent is not None:
 -             QTimer.singleShot(0, self.fRealParent.slot_miniCanvasCheckAll)
 - 
 -     def setViewSize(self, width: float, height: float):
 -         self.fViewRect[self._kRectWidth] = width * self.fInternalWidth
 -         self.fViewRect[self._kRectHeight] = height * self.fInternalHeight
 -         self.update()
 - 
 -     def setViewTheme(self, bgColor, brushColor, penColor):
 -         bg_black      = bgColor.blackF()
 -         brush_black   = brushColor.blackF()
 -         r0, g0, b0, _ = bgColor.getRgb()
 -         r1, g1, b1, _ = brushColor.getRgb()
 - 
 -         if brush_black < bg_black:
 -             self.fRubberBandBlending = self._RUBBERBAND_BLENDING_PLUS
 -             brushColor = QColor(r1-r0, g1-g0, b1-b0, 40)
 -         elif bg_black < brush_black:
 -             self.fRubberBandBlending = self._RUBBERBAND_BLENDING_DIFF
 -             brushColor = QColor(r0-r1, g0-g1, b0-b1, 40)
 -         else:
 -             bgColor.setAlpha(40)
 -             self.fRubberBandBlending = self._RUBBERBAND_BLENDING_DEFAULT
 - 
 -         penColor.setAlpha(100)
 -         self.fViewBg    = bgColor
 -         self.fViewBrush = QBrush(brushColor)
 -         self.fViewPen   = QPen(penColor, 1)
 - 
 -         cursorName = "black" if bg_black < 0.5 else "white"
 -         if self.fZoomCursors[self._kCursorName] != cursorName:
 -             prefix = ":/cursors/zoom"
 -             self.fZoomCursors[self._kCursorName] = cursorName
 -             self.fZoomCursors[self._kCursorZoom] = QCursor(QPixmap(f"{prefix}_{cursorName}.png"), 8, 7)
 -             self.fZoomCursors[self._kCursorZoomIn] = QCursor(QPixmap(f"{prefix}-in_{cursorName}.png"), 8, 7)
 -             self.fZoomCursors[self._kCursorZoomOut] = QCursor(QPixmap(f"{prefix}-out_{cursorName}.png"), 8, 7)
 - 
 -     # -----------------------------------------------------------------------------------------------------------------
 - 
 -     def changeEvent(self, event):
 -         if event.type() in (QEvent.StyleChange, QEvent.PaletteChange):
 -             self._updateStyle()
 -         QFrame.changeEvent(self, event)
 - 
 -     def mousePressEvent(self, event):
 -         if event.button() == Qt.LeftButton:
 -             event.accept()
 -             self.fMouseLeftDown = True
 -             self._updateMouseMode(event)
 -             return
 -         if event.button() == Qt.RightButton:
 -             event.accept()
 -             self.fMouseRightDown = True
 -             self._updateMouseMode(event)
 -             return
 -         if event.button() == Qt.MidButton:
 -             event.accept()
 -             self.fMouseLeftDown = True
 -             self.fMouseRightDown = True
 -             self._updateMouseMode(event)
 -             return
 -         QFrame.mouseMoveEvent(self, event)
 - 
 -     def mouseMoveEvent(self, event):
 -         if self.fMouseMode == self._MOUSE_MODE_MOVE:
 -             event.accept()
 -             self._moveViewRect(event.x(), event.y())
 -             return
 -         if self.fMouseMode == self._MOUSE_MODE_SCALE:
 -             event.accept()
 -             self._scaleViewRect(event.globalY())
 -             return
 -         QFrame.mouseMoveEvent(self, event)
 - 
 -     def mouseReleaseEvent(self, event):
 -         if event.button() == Qt.LeftButton:
 -             event.accept()
 -             self.fMouseLeftDown = False
 -             self._updateMouseMode()
 -             return
 -         if event.button() == Qt.RightButton:
 -             event.accept()
 -             self.fMouseRightDown = False
 -             self._updateMouseMode(event)
 -             return
 -         if event.button() == Qt.MidButton:
 -             event.accept()
 -             self.fMouseLeftDown = event.buttons() & Qt.LeftButton
 -             self.fMouseRightDown = event.buttons() & Qt.RightButton
 -             self._updateMouseMode(event)
 -             return
 -         QFrame.mouseReleaseEvent(self, event)
 - 
 -     def wheelEvent(self, event):
 -         if self.fScene is None:
 -             QFrame.wheelEvent(self, event)
 -             return
 - 
 -         event.accept()
 -         self.fScene.zoom_wheel(event.angleDelta().y())
 - 
 -     def paintEvent(self, event):
 -         if self.fScene is None:
 -             QFrame.paintEvent(self, event)
 -             return
 - 
 -         painter = QPainter(self)
 -         painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing == ANTIALIASING_FULL))
 - 
 -         # Brightness-aware out-of-canvas shading
 -         bg_color = self.fViewBg
 -         bg_black = bg_color.black()
 -         bg_shade = -12 if bg_black < 127 else 12
 -         r,g,b,_ = bg_color.getRgb()
 -         bg_color = QColor(r+bg_shade, g+bg_shade, b+bg_shade)
 - 
 -         frameWidth = self.fFrameWidth
 -         if self.fUseCustomPaint:
 -             # Inner shadow
 -             color = QColor.fromHsv(40, 0, 255-max(210, bg_color.black(), bg_black))
 -             painter.setBrush(Qt.transparent)
 -             painter.setPen(color)
 -             painter.drawRect(QRectF(0.5, 0.5, self.width()-1, self.height()-1))
 - 
 -             # Background
 -             painter.setBrush(bg_color)
 -             painter.setPen(bg_color)
 -             painter.drawRect(QRectF(1.5, 1.5, self.width()-3, self.height()-3))
 -         else:
 -             use_rounding = int(frameWidth > 1)
 - 
 -             rounding = 0.5 * use_rounding
 -             painter.setBrush(bg_color)
 -             painter.setPen(bg_color)
 -             painter.drawRoundedRect(QRectF(0.5+frameWidth,
 -                                            0.5+frameWidth,
 -                                            self.width()-1-frameWidth*2,
 -                                            self.height()-1-frameWidth*2), rounding, rounding)
 - 
 -             clipPath = QPainterPath()
 -             rounding = 1.0 * use_rounding
 -             clipPath.addRoundedRect(QRectF(frameWidth,
 -                                            frameWidth,
 -                                            self.width()-frameWidth*2,
 -                                            self.height()-frameWidth*2), rounding, rounding)
 -             painter.setClipPath(clipPath)
 - 
 -         self.fScene.render(painter, self.fRenderTarget, self.fRenderSource, Qt.KeepAspectRatio)
 - 
 -         # Allow cursor frame to look joined with minicanvas frame
 -         painter.setClipping(False)
 - 
 -         width  = self.fViewRect[self._kRectWidth]/self.fScale
 -         height = self.fViewRect[self._kRectHeight]/self.fScale
 - 
 -         # cursor
 -         lineHinting = self.fViewPen.widthF() / 2
 -         x = self.fViewRect[self._kRectX]+self.fInitialX
 -         y = self.fViewRect[self._kRectY]+self.fInitialY
 -         scr_x = floor(x)
 -         scr_y = floor(y)
 -         rect = QRectF(
 -             scr_x+lineHinting,
 -             scr_y+lineHinting,
 -             ceil(width+x-scr_x)-lineHinting*2,
 -             ceil(height+y-scr_y)-lineHinting*2 )
 - 
 -         if self.fRubberBandBlending == self._RUBBERBAND_BLENDING_PLUS:
 -             painter.setCompositionMode(QPainter.CompositionMode_Plus)
 -         elif self.fRubberBandBlending == self._RUBBERBAND_BLENDING_DIFF:
 -             painter.setCompositionMode(QPainter.CompositionMode_Difference)
 - 
 -         painter.setBrush(self.fViewBrush)
 -         painter.setPen(Qt.NoPen)
 -         painter.drawRect(rect)
 - 
 -         painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
 -         painter.setBrush(Qt.NoBrush)
 -         painter.setPen(self.fViewPen)
 -         painter.drawRect(rect)
 - 
 -         if self.fUseCustomPaint:
 -             event.accept()
 -         else:
 -             QFrame.paintEvent(self, event)
 - 
 -     def resizeEvent(self, event):
 -         size = event.size()
 -         width = size.width()
 -         height = size.height()
 -         extRatio = (width - self.fFrameWidth * 2) / (height - self.fFrameWidth * 2)
 -         if extRatio >= self.fInternalRatio:
 -             self.fInternalHeight = floor(height - self.fFrameWidth * 2)
 -             self.fInternalWidth  = floor(self.fInternalHeight * self.fInternalRatio)
 -             self.fInitialX       = floor(float(width - self.fInternalWidth) / 2.0)
 -             self.fInitialY       = self.fFrameWidth
 -         else:
 -             self.fInternalWidth  = floor(width - self.fFrameWidth * 2)
 -             self.fInternalHeight = floor(self.fInternalWidth / self.fInternalRatio)
 -             self.fInitialX       = self.fFrameWidth
 -             self.fInitialY       = floor(float(height - self.fInternalHeight) / 2.0)
 - 
 -         self.fRenderTarget = QRectF(self.fInitialX,
 -                                     self.fInitialY,
 -                                     float(self.fInternalWidth),
 -                                     float(self.fInternalHeight))
 - 
 -         if self.fRealParent is not None:
 -             QTimer.singleShot(0, self.fRealParent.slot_miniCanvasCheckAll)
 - 
 -         QFrame.resizeEvent(self, event)
 - 
 -     # -----------------------------------------------------------------------------------------------------------------
 - 
 -     def _moveViewRect(self, x: float, y: float):
 -         if self.fScene is None:
 -             return
 - 
 -         x -= self.fInitialX
 -         y -= self.fInitialY
 - 
 -         fixPos = False
 -         rCentX = self.fViewRect[self._kRectWidth] / self.fScale / 2
 -         rCentY = self.fViewRect[self._kRectHeight] / self.fScale / 2
 -         if x < rCentX:
 -             x = rCentX
 -             fixPos = True
 -         elif x > self.fInternalWidth - rCentX:
 -             x = self.fInternalWidth - rCentX
 -             fixPos = True
 - 
 -         if y < rCentY:
 -             y = rCentY
 -             fixPos = True
 -         elif y > self.fInternalHeight - rCentY:
 -             y = self.fInternalHeight - rCentY
 -             fixPos = True
 - 
 -         if fixPos:
 -             globalPos = self.mapToGlobal(QPoint(self.fInitialX + x, self.fInitialY + y))
 -             self.cursor().setPos(globalPos)
 - 
 -         x = self.fRenderSource.width() * x / self.fInternalWidth
 -         y = self.fRenderSource.height() * y / self.fInternalHeight
 -         self.fScene.m_view.centerOn(x, y)
 - 
 -     def _scaleViewRect(self, globalY: int):
 -         if self.fScene is None:
 -             return
 - 
 -         dy = self.fMouseInitialZoomPos.y() - globalY
 -         if dy != 0:
 -             self.setCursor(self.fZoomCursors[self._kCursorZoomIn if dy > 0 else self._kCursorZoomOut])
 -             self.fScene.zoom_wheel(dy)
 - 
 -         self.cursor().setPos(self.fMouseInitialZoomPos)
 - 
 -     def _updateMouseMode(self, event = None):
 -         if self.fMouseLeftDown and self.fMouseRightDown:
 -             self.fMouseInitialZoomPos = event.globalPos()
 -             self.setCursor(self.fZoomCursors[self._kCursorZoom])
 -             self.fMouseMode = self._MOUSE_MODE_SCALE
 - 
 -         elif self.fMouseLeftDown:
 -             self.setCursor(QCursor(Qt.SizeAllCursor))
 -             if self.fMouseMode == self._MOUSE_MODE_NONE:
 -                 self._moveViewRect(event.x(), event.y())
 -             self.fMouseMode = self._MOUSE_MODE_MOVE
 - 
 -         else:
 -             self.unsetCursor()
 -             self.fMouseMode = self._MOUSE_MODE_NONE
 - 
 -     def _updateStyle(self):
 -         self.fFrameWidth = 1 if self.fUseCustomPaint else self.frameWidth()
 - 
 - # ---------------------------------------------------------------------------------------------------------------------
 
 
  |