#!/usr/bin/env python

#****************************************************************************
#** $Id: qmag.py 322023 2004-06-19 20:33:37Z sedwards $
#**
#** Copyright (C) 1992-1998 Troll Tech AS.  All rights reserved.
#**
#** This file is part of an example program for PyQt.  This example
#** program may be used, distributed and modified without limitation.
#**
#*****************************************************************************/

import sys
from qt import *

TRUE  = 1
FALSE = 0

zoomfactors = ["100%","200%","300%","400%","500%","600%","700%","800%","1600%"]

refreshrates = [
    "No autorefresh", "50 per second", "4 per second", "3 per second",
    "2 per second", "Every second", "Every two seconds", "Every three seconds",
    "Every five seconds", "Every ten seconds"]

timer = (0, 20, 250, 333, 500, 1000, 2000, 3000, 5000, 10000)

class MagWidget(QWidget):
    def __init__(self, qApp, parent = None, name = None):
        self.qApp = qApp
        QWidget.__init__(self, parent, name)
        self.pm = QPixmap()     # pixmap magnified
        self.p = QPixmap()      # pixmap
        self.image = QImage()   # image of pixmap (for RGB)
        self.z = 0              # zoom factor
        self.r = 0              # autorefresh rate (index into refreshrates)
        self.grabbing = FALSE   # TRUE if currently grabbing
        self.grabx = -1
        self.graby = -1

        self.zoom = QComboBox(FALSE, self)
        self.zoom.insertStrList(zoomfactors, len(zoomfactors))
        self.connect(self.zoom, SIGNAL("activated(int)"),
                     self.setZoom)

        self.refresh = QComboBox(FALSE, self)
        self.refresh.insertStrList(refreshrates, len(refreshrates))
        self.connect(self.refresh, SIGNAL("activated(int)"),
                     self.setRefresh)

        x = 0
        w = 0
        h = 20
        for s in zoomfactors:
            cw = self.zoom.fontMetrics().width(s)
            w = max(cw, w)
        self.zoom.setGeometry(x, 2, w + 30, h)

        x = w + 34
        w = 0
        for s in refreshrates:
            cw = self.refresh.fontMetrics().width(s)
            w = max(cw, w)
        self.refresh.setGeometry(x, 2, w + 30, h)

        self.saveButton = QPushButton(self)
        self.connect(self.saveButton, SIGNAL("clicked()"), self.save)
        self.saveButton.setText("Save")
        self.saveButton.setGeometry(x + w + 30 + 2, 2,
                    10 + self.saveButton.fontMetrics().width("Save"), h)

        self.quitButton = QPushButton(self)
        self.connect(self.quitButton, SIGNAL("clicked()"), self.qApp, SLOT("quit()"))
        self.quitButton.setText("Quit")
        self.quitButton.setGeometry(self.saveButton.geometry().right() + 2, 2,
                    10 + self.quitButton.fontMetrics().width("Quit"), h)

        self.rgb = QLabel(self)
        self.rgb.setText("")
        self.rgb.setAlignment(Qt.AlignVCenter)
        self.rgb.resize(self.width(), self.rgb.fontMetrics().height() + 4)

        self.yoffset = self.zoom.height() + 4 + self.rgb.height()
        self.setMinimumSize(self.quitButton.geometry().topRight().x() + 2,
                            self.yoffset + 20)
        w = self.quitButton.geometry().topRight().x() + 2
        self.resize(w, w)

        self.setMouseTracking(TRUE)
        self.grabx = self.qApp.desktop().width() / 2
        self.graby = self.qApp.desktop().height() / 2
        self.grabAround(QPoint(self.grabx, self.graby))

        #self.zoom.setCurrentItem(1)    # grabAround sets zoom factor
        #self.setZoom(1)
        self.refresh.setCurrentItem(5)
        self.setRefresh(5)

    def setZoom(self, index):
        if index == 8:
            self.z = 16
        else:
            self.z = index + 1
        self.grab()

    def setRefresh(self, index):
        self.r = index
        self.killTimers()
        if index and not self.grabbing:
            #print "st:", timer[index]
            self.startTimer(timer[index])

    def save(self):
        if not self.p.isNull():
            self.killTimers()
            fn = QFileDialog.getSaveFileName()
            if not fn.isEmpty():
                self.p.save(fn, "BMP")
            if self.r:
                self.startTimer(timer[self.r])

    def grab(self):
        if not self.isVisible() or self.grabx < 0 or self.graby < 0:
            return

        w = (self.width() + self.z - 1) / self.z
        h = (self.height() + self.z - 1 - self.yoffset) / self.z

        if w < 1 or h < 1:
            return

        x = self.grabx - w / 2
        y = self.graby - h / 2

        if x + w > QApplication.desktop().width():
            x = QApplication.desktop().width() - w
        elif x < 0:
            x = 0

        if y + h > QApplication.desktop().height():
            y = QApplication.desktop().height() - h
        elif y < 0:
            y = 0

        self.p = QPixmap.grabWindow(QApplication.desktop().winId(), x, y, w, h)
        self.image = self.p.convertToImage()
        m = QWMatrix()
        #print "z:", self.z
        m.scale(float(self.z), float(self.z))
        self.pm = self.p.xForm(m)
        self.repaint(FALSE)

    def paintEvent(self, e):
        if not self.pm.isNull():
            paint = QPainter(self)
            paint.drawPixmap(0, self.zoom.height() + 4, self.pm,
                             0, 0, self.width(), self.height() - self.yoffset)

    def mousePressEvent(self, e):
        if not self.grabbing:
            self.grabbing = TRUE
            self.killTimers()
            self.grabMouse(Qt.crossCursor)
            self.grabx = -1
            self.graby = -1
        else:
            self.grabx = self.mapToGlobal(e.pos()).x()
            self.graby = self.mapToGlobal(e.pos()).y()

    def mouseReleaseEvent(self, e):
        if self.grabbing and self.grabx >= 0 and self.graby >= 0:
            self.grabbing = FALSE
            self.grabAround(e.pos())
            self.releaseMouse()

    def grabAround(self, pos):
        rx = self.mapToGlobal(pos).x()
        ry = self.mapToGlobal(pos).y()
        w = abs(rx - self.grabx)
        h = abs(ry - self.graby)
        if w > 10 and h > 10:
            pz = 1
            while w*pz*h*pz < self.width()*(self.height()-self.yoffset) and \
                  w*pz < QApplication.desktop().width() and \
                  h*pz < QApplication.desktop().height():
                pz += 1
            if (w*pz*h*pz - self.width()*(self.height()-self.yoffset)) > \
                (self.width()*(self.height()-self.yoffset) - w*(pz-1)*h*(pz-1)):
                pz -= 1
            if pz < 1:
                pz = 1
            elif pz > 8:
                pz = 8
            self.zoom.setCurrentItem(pz-1)
            self.z = pz
            self.grabx = min(rx, self.grabx) + w / 2
            self.graby = min(ry, self.graby) + h / 2
            #self.resize(w*self.z, h*self.z*self.yoffset)
        self.grab()

    def mouseMoveEvent(self, e):
        if self.grabbing or self.pm.isNull() or \
            e.pos().y() > self.height() - self.zoom.fontMetrics().height() - 4 or \
            e.pos().y() < self.zoom.height() + 4:
            self.rgb.setText("")
        else:
            x = e.pos().x() / self.z
            y = (e.pos().y() - self.zoom.height() - 4) / self.z
            pixelinfo = ""
            if self.image.valid(x, y):
                px = self.image.pixel(x, y)
                pixelinfo = "%3d,%3d,%3d  #%02x%02x%02x" % (
                        qRed(px), qGreen(px), qBlue(px),
                        qRed(px), qGreen(px), qBlue(px))
            self.rgb.setText("x=%d, y=%d  %s" % \
                        (x + self.grabx, y + self.graby, pixelinfo))

    def focusOutEvent(self, e):
        self.rgb.setText("")

    def timerEvent(self, e):
        self.grab()

    def resizeEvent(self, e):
        self.rgb.setGeometry(0, self.height() - self.rgb.height(),
                             self.width(), self.rgb.height())

if __name__=='__main__':
    app = QApplication( sys.argv )
    m = MagWidget(app)
    app.setMainWidget(m)
    m.show()
    app.exec_loop()
