#!/usr/bin/env python
##
##  This file is part of pyFormex 1.0.5  (Sat Feb 16 10:40:32 CET 2019)
##  pyFormex is a tool for generating, manipulating and transforming 3D
##  geometrical models by sequences of mathematical operations.
##  Home page: http://pyformex.org
##  Project page:  http://savannah.nongnu.org/projects/pyformex/
##  Copyright 2004-2018 (C) Benedict Verhegghe (benedict.verhegghe@ugent.be)
##  Distributed under the GNU General Public License version 3 or later.
##
##  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 3 of the License, or
##  (at your option) 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.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see http://www.gnu.org/licenses/.
##
"""A general image viewer

Part of this code was borrowed from the TrollTech Qt examples.
"""
from __future__ import absolute_import, division, print_function


caption = "pyFormex Image Viewer"

from pyformex.gui import QtCore, QtGui, QtWidgets


def tr(s):
    return QtCore.QCoreApplication.translate('ImageViewer', s)


class ImageViewer(QtWidgets.QMainWindow):
    """pyFormex image viewer

    The pyFormex image viewer was shaped after the Image Viewer from the
    TrollTech Qt documentation.

    It can be use as stand alone application, as well as from inside
    pyFormex. The viewer allows browsing through directories, selecting
    an image to be displayed. The image can be resized to fit a window.

    Parameters:

    - `parent`: The parent Qt4 widget (the Qt4 app in the stand alone case).
    - `path`: string: the full path to the image to be initially displayed.
    """

    def __init__(self,parent=None,path=None):
        QtGui.QMainWindow.__init__(self)

        self.parent = parent
        self.filename = path
        self.image = QtGui.QLabel()
        self.image.setBackgroundRole(QtGui.QPalette.Base)
        self.image.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored)
        #self.image.setScaledContents(True)

        self.scroll = QtGui.QScrollArea()
        self.scroll.setBackgroundRole(QtGui.QPalette.Dark)
        self.scroll.setWidget(self.image)
        self.scroll.setWidgetResizable(True)
        self.setCentralWidget(self.scroll)

        self.createActions()
        self.createMenus()

        self.setWindowTitle(tr(caption))
        self.resize(500, 400)
        self.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)

        if path:
            self.openfile(path)


    def openfile(self,filename=None):
        if filename is None:
            filename = self.filename
            if filename is None:
                filename = QtCore.QDir.currentPath()
            filename = QtGui.QFileDialog.getOpenFileName(self, tr("Open File"), filename)
            if not filename:
                return

        image = QtGui.QImage(filename)
        if image.isNull():
            QtGui.QMessageBox.information(self, tr(caption), tr("Cannot load %1.").arg(filename))
            return

        #print("Size %sx%s" % (image.width(),image.height()))
        self.filename = str(filename)
        self.image.setPixmap(QtGui.QPixmap.fromImage(image))
        self.scaleFactor = 1.0

        self.printAct.setEnabled(True)
        self.fitToWindowAct.setEnabled(True)
        self.updateActions()

        ## if not self.fitToWindowAct.isChecked():
        self.image.adjustSize()
        self.normalSize()


    def print_(self):
        if not self.image.pixmap():
            return

        self.printer = QtGui.QPrinter()
        dialog = QtGui.QPrintDialog(self.printer, self)
        if dialog.exec_():
            painter = QtGui.QPainter(self.printer)
            rect = painter.viewport()
            size = self.image.pixmap().size()
            size.scale(rect.size(), QtCore.Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
            painter.setWindow(self.image.pixmap().rect())
            painter.drawPixmap(0, 0, self.image.pixmap())


    def zoomIn(self):
        self.scaleImage(1.25)

    def zoomOut(self):
        self.scaleImage(0.8)

    def normalSize(self):
        self.image.resize(self.image.pixmap().size())
        #self.image.adjustSize()
        self.scaleFactor = 1.0

    def fitToWindow(self):
        fitToWindow = self.fitToWindowAct.isChecked()
        self.scroll.setWidgetResizable(fitToWindow)
        if not fitToWindow:
            self.normalSize()
        self.updateActions()

    def fitToImage(self):
        self.normalSize()
        self.scroll.resize(self.image.size())


    def about(self):
        QtGui.QMessageBox.about(self, tr("About pyFormex Image Viewer"), tr("""
<p>The <b>pyFormex Image Viewer</b> was shaped after the
<b>Image Viewer</b> from the TrollTech Qt documentation.</p>
<p>The example shows how to combine QLabel
and QScrollArea to display an image. QLabel is typically used
for displaying a text,but it can also display an image.
QScrollArea provides a scrolling view around another widget.
If the child widget exceeds the size of the frame,QScrollArea
automatically provides scroll bars. </p>
<p>The example
demonstrates how QLabel's ability to scale its contents
(QLabel.scaledContents),and QScrollArea's ability to
automatically resize its contents
(QScrollArea.widgetResizable),can be used to implement
zooming and scaling features. </p>
<p>In addition the example
shows how to use QPainter to print an image.</p>
"""))


    def createActions(self):
        self.openAct = QtGui.QAction(tr("&Open..."), self)
        self.openAct.setShortcut(tr("Ctrl+O"))
        self.openAct.triggered.connect(self.openfile)

        self.printAct = QtGui.QAction(tr("&Print..."), self)
        self.printAct.setShortcut(tr("Ctrl+P"))
        self.printAct.setEnabled(False)
        self.printAct.triggered.connect(self.print_)


        self.zoomInAct = QtGui.QAction(tr("Zoom &In (25%)"), self)
        self.zoomInAct.setShortcut(tr("Ctrl++"))
        self.zoomInAct.setEnabled(False)
        self.zoomInAct.triggered.connect(self.zoomIn)

        self.zoomOutAct = QtGui.QAction(tr("Zoom &Out (25%)"), self)
        self.zoomOutAct.setShortcut(tr("Ctrl+-"))
        self.zoomOutAct.setEnabled(False)
        self.zoomOutAct.triggered.connect(self.zoomOut)

        self.normalSizeAct = QtGui.QAction(tr("&Normal Size"), self)
        self.normalSizeAct.setShortcut(tr("Ctrl+S"))
        self.normalSizeAct.setEnabled(False)
        self.normalSizeAct.triggered.connect(self.normalSize)

        self.fitToImageAct = QtGui.QAction(tr("Fit &Window to Image"), self)
        self.fitToImageAct.setShortcut(tr("Ctrl+W"))
        self.fitToImageAct.setEnabled(False)
        #self.fitToImageAct.setCheckable(True)
        self.fitToImageAct.triggered.connect(self.fitToImage)

        self.fitToWindowAct = QtGui.QAction(tr("&Fit Image to Window"), self)
        self.fitToWindowAct.setShortcut(tr("Ctrl+F"))
        self.fitToWindowAct.setEnabled(False)
        self.fitToWindowAct.setCheckable(True)
        self.fitToWindowAct.triggered.connect(self.fitToWindow)

        self.aboutAct = QtGui.QAction(tr("&About"), self)
        self.aboutAct.triggered.connect(self.about)

        if isinstance(self.parent, QtGui.QApplication):

            self.exitAct = QtGui.QAction(tr("E&xit"), self)
            self.exitAct.setShortcut(tr("Ctrl+Q"))
            self.exitAct.triggered.connect(self.close)

            self.aboutQtAct = QtGui.QAction(tr("About &Qt"), self)
            self.aboutQtAct.triggered.connect(self.parent.aboutQt)

        elif isinstance(self.parent, QtWidgets.QDialog):

            self.acceptAct = QtGui.QAction(tr("&Accept"), self)
            self.acceptAct.setShortcut(tr("Ctrl+A"))
            self.acceptAct.triggered.connect(self.parent.accept)

            self.rejectAct = QtGui.QAction(tr("&Reject"), self)
            self.rejectAct.setShortcut(tr("Ctrl+Q"))
            self.rejectAct.triggered.connect(self.parent.reject)


    def createMenus(self):
        self.fileMenu = QtGui.QMenu(tr("&File"), self)
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.printAct)
        self.fileMenu.addSeparator()

        self.viewMenu = QtGui.QMenu(tr("&View"), self)
        self.viewMenu.addAction(self.zoomInAct)
        self.viewMenu.addAction(self.zoomOutAct)
        self.viewMenu.addAction(self.normalSizeAct)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.fitToImageAct)
        self.viewMenu.addAction(self.fitToWindowAct)

        self.helpMenu = QtGui.QMenu(tr("&Help"), self)
        self.helpMenu.addAction(self.aboutAct)

        self.menuBar().addMenu(self.fileMenu)
        self.menuBar().addMenu(self.viewMenu)
        self.menuBar().addMenu(self.helpMenu)

        if isinstance(self.parent, QtGui.QApplication):
            self.fileMenu.addAction(self.exitAct)
            self.helpMenu.addAction(self.aboutQtAct)
        elif isinstance(self.parent, QtWidgets.QDialog):
            self.fileMenu.addAction(self.acceptAct)
            self.fileMenu.addAction(self.rejectAct)


    def updateActions(self):
        self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.fitToImageAct.setEnabled(not self.fitToWindowAct.isChecked())


    def scaleImage(self, factor):
        if not self.image.pixmap():
            return
        self.scaleFactor *= factor
        self.image.resize(self.scaleFactor * self.image.pixmap().size())

        self.adjustScrollBar(self.scroll.horizontalScrollBar(), factor)
        self.adjustScrollBar(self.scroll.verticalScrollBar(), factor)

        self.zoomInAct.setEnabled(self.scaleFactor < 3.0)
        self.zoomOutAct.setEnabled(self.scaleFactor > 0.333)


    def adjustScrollBar(self, scrollBar, factor):
        scrollBar.setValue(int(factor * scrollBar.value() + ((factor - 1) * scrollBar.pageStep()/2)))


def main():
    import sys
    global app
    app = QtGui.QApplication(sys.argv)
    if len(sys.argv) > 1:
        path = sys.argv[1]
    else:
        path = None
    viewer = ImageViewer(app, path)
    viewer.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
