<gh_stars>0
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import QRect, QPoint, Qt
from PyQt5.QtGui import QPixmap

_global_sync = None

def setGlobalSynchronizer(synchronizer):
    global _global_sync
    _global_sync = synchronizer

def synchronizer():
    global _global_sync
    return _global_sync

class Synchronizer(QWidget):
    def __init__(self):
        super().__init__()
        self._views = []
        self._previewEnabled = False
        self._point = QPoint(550, 100)
        self._previewSize = 32
        self.setAttribute(Qt.WA_TransparentForMouseEvents)

    def registerView(self, view):
        self._views.append(view)

    def startPreview(self):
        self._previewEnabled = True

    def stopPreview(self):
        self._previewEnabled = False
        self.update()

    def changePreviewSize(self, delta):
        if self._previewEnabled:
            diff = 1.0 + (-delta.y())/360/10
            self._previewSize *= diff
            if self._previewSize < 32:
                self._previewSize = 32
            if self._previewSize > 2048:
                self._previewSize = 2048
            self.update()

    def paintEvent(self, e):
        super().paintEvent(e)

        if self._point is None or self._previewEnabled == False:
            return

        painter = QPainter(self)
        painter.setBrush(Qt.NoBrush);
        painter.setPen(QColor(0xFF, 0, 0))

        for view in self._views:
            if view.data() is None or view.isHidden():
                continue

            s = min(view.width(), view.height()) * 0.66

            pixmap = view.makePreview(self._point, self._previewSize)
            w = min(int(pixmap.width() / self._previewSize * s), s)
            h = min(int(pixmap.height() / self._previewSize * s), s)
            if w == 0 or h == 0:
                continue

            gp = view.mapToGlobal(self._point)
            lp = self.mapFromGlobal(gp)
            rect = QRect(lp.x()-w/2, lp.y()-h/2, w, h)
            painter.drawPixmap(rect, pixmap)

            overlay = QPixmap(rect.width(), rect.height())
            ov_painter = QPainter()
            ov_painter.begin(overlay)
            ov_painter.setPen(QColor(0x55, 0x55, 0x55))
            ov_painter.fillRect(overlay.rect(), Qt.black)
            x = overlay.rect().width()//2
            y = overlay.rect().height()//2
            ov_painter.drawLine(x, 0, x, overlay.rect().height() - 1)
            ov_painter.drawLine(0, y, overlay.rect().width() - 1, y)
            ov_painter.end()

            old_mode = painter.compositionMode()
            painter.setCompositionMode(QPainter.RasterOp_SourceXorDestination)
            painter.drawPixmap(rect, overlay)
            painter.setCompositionMode(old_mode)

            painter.drawRect(rect)

    def preview(self, point):
        if self._point == point:
            return

        self._point = point

        if self._previewEnabled:
            self.update()

from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import QRect, QPoint, Qt
from PyQt5.QtGui import QPixmap

_global_sync = None

def setGlobalSynchronizer(synchronizer):
    global _global_sync
    _global_sync = synchronizer

def synchronizer():
    global _global_sync
    return _global_sync

class Synchronizer(QWidget):
    def __init__(self):
        super().__init__()
        self._views = []
        self._previewEnabled = False
        self._point = QPoint(550, 100)
        self._previewSize = 32
        self.setAttribute(Qt.WA_TransparentForMouseEvents)

    def registerView(self, view):
        self._views.append(view)

    def startPreview(self):
        self._previewEnabled = True

    def stopPreview(self):
        self._previewEnabled = False
        self.update()

    def changePreviewSize(self, delta):
        if self._previewEnabled:
            diff = 1.0 + (-delta.y())/360/10
            self._previewSize *= diff
            if self._previewSize < 32:
                self._previewSize = 32
            if self._previewSize > 2048:
                self._previewSize = 2048
            self.update()

    def paintEvent(self, e):
        super().paintEvent(e)

        if self._point is None or self._previewEnabled == False:
            return

        painter = QPainter(self)
        painter.setBrush(Qt.NoBrush);
        painter.setPen(QColor(0xFF, 0, 0))

        for view in self._views:
            if view.data() is None or view.isHidden():
                continue

            s = min(view.width(), view.height()) * 0.66

            pixmap = view.makePreview(self._point, self._previewSize)
            w = min(int(pixmap.width() / self._previewSize * s), s)
            h = min(int(pixmap.height() / self._previewSize * s), s)
            if w == 0 or h == 0:
                continue

            gp = view.mapToGlobal(self._point)
            lp = self.mapFromGlobal(gp)
            rect = QRect(lp.x()-w/2, lp.y()-h/2, w, h)
            painter.drawPixmap(rect, pixmap)

            overlay = QPixmap(rect.width(), rect.height())
            ov_painter = QPainter()
            ov_painter.begin(overlay)
            ov_painter.setPen(QColor(0x55, 0x55, 0x55))
            ov_painter.fillRect(overlay.rect(), Qt.black)
            x = overlay.rect().width()//2
            y = overlay.rect().height()//2
            ov_painter.drawLine(x, 0, x, overlay.rect().height() - 1)
            ov_painter.drawLine(0, y, overlay.rect().width() - 1, y)
            ov_painter.end()

            old_mode = painter.compositionMode()
            painter.setCompositionMode(QPainter.RasterOp_SourceXorDestination)
            painter.drawPixmap(rect, overlay)
            painter.setCompositionMode(old_mode)

            painter.drawRect(rect)

    def preview(self, point):
        if self._point == point:
            return

        self._point = point

        if self._previewEnabled:
            self.update()