diff --git a/setup/test.py b/setup/test.py index 7946186e69..4144178f41 100644 --- a/setup/test.py +++ b/setup/test.py @@ -129,7 +129,7 @@ def find_tests(which_tests=None): a(find_tests()) from calibre.ebooks.compression.palmdoc import find_tests a(find_tests()) - from calibre.gui2.viewer2.convert_book import find_tests + from calibre.gui2.viewer.convert_book import find_tests a(find_tests()) if iswindows: from calibre.utils.windows.wintest import find_tests diff --git a/src/calibre/gui2/image_popup.py b/src/calibre/gui2/image_popup.py new file mode 100644 index 0000000000..b10311b965 --- /dev/null +++ b/src/calibre/gui2/image_popup.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python2 +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai +from __future__ import absolute_import, division, print_function, unicode_literals + +__license__ = 'GPL v3' +__copyright__ = '2012, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from PyQt5.Qt import (QDialog, QPixmap, QUrl, QScrollArea, QLabel, QSizePolicy, + QDialogButtonBox, QVBoxLayout, QPalette, QApplication, QSize, QIcon, + Qt, QTransform, QSvgRenderer, QImage, QPainter) + +from calibre.gui2 import choose_save_file, gprefs, NO_URL_FORMATTING, max_available_height +from polyglot.builtins import unicode_type + + +def render_svg(widget, path): + img = QPixmap() + rend = QSvgRenderer() + if rend.load(path): + dpr = getattr(widget, 'devicePixelRatioF', widget.devicePixelRatio)() + sz = rend.defaultSize() + h = (max_available_height() - 50) + w = int(h * sz.height() / float(sz.width())) + pd = QImage(w * dpr, h * dpr, QImage.Format_RGB32) + pd.fill(Qt.white) + p = QPainter(pd) + rend.render(p) + p.end() + img = QPixmap.fromImage(pd) + img.setDevicePixelRatio(dpr) + return img + + +class ImageView(QDialog): + + def __init__(self, parent, current_img, current_url, geom_name='viewer_image_popup_geometry'): + QDialog.__init__(self) + dw = QApplication.instance().desktop() + self.avail_geom = dw.availableGeometry(parent if parent is not None else self) + self.current_img = current_img + self.current_url = current_url + self.factor = 1.0 + self.geom_name = geom_name + + self.label = l = QLabel() + l.setBackgroundRole(QPalette.Base) + l.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) + l.setScaledContents(True) + + self.scrollarea = sa = QScrollArea() + sa.setBackgroundRole(QPalette.Dark) + sa.setWidget(l) + + self.bb = bb = QDialogButtonBox(QDialogButtonBox.Close) + bb.accepted.connect(self.accept) + bb.rejected.connect(self.reject) + self.zi_button = zi = bb.addButton(_('Zoom &in'), bb.ActionRole) + self.zo_button = zo = bb.addButton(_('Zoom &out'), bb.ActionRole) + self.save_button = so = bb.addButton(_('&Save as'), bb.ActionRole) + self.rotate_button = ro = bb.addButton(_('&Rotate'), bb.ActionRole) + zi.setIcon(QIcon(I('plus.png'))) + zo.setIcon(QIcon(I('minus.png'))) + so.setIcon(QIcon(I('save.png'))) + ro.setIcon(QIcon(I('rotate-right.png'))) + zi.clicked.connect(self.zoom_in) + zo.clicked.connect(self.zoom_out) + so.clicked.connect(self.save_image) + ro.clicked.connect(self.rotate_image) + + self.l = l = QVBoxLayout() + self.setLayout(l) + l.addWidget(sa) + l.addWidget(bb) + + def zoom_in(self): + self.factor *= 1.25 + self.adjust_image(1.25) + + def zoom_out(self): + self.factor *= 0.8 + self.adjust_image(0.8) + + def save_image(self): + filters=[('Images', ['png', 'jpeg', 'jpg'])] + f = choose_save_file(self, 'viewer image view save dialog', + _('Choose a file to save to'), filters=filters, + all_files=False) + if f: + from calibre.utils.img import save_image + save_image(self.current_img.toImage(), f) + + def adjust_image(self, factor): + self.label.resize(self.factor * self.current_img.size()) + self.zi_button.setEnabled(self.factor <= 3) + self.zo_button.setEnabled(self.factor >= 0.3333) + self.adjust_scrollbars(factor) + + def adjust_scrollbars(self, factor): + for sb in (self.scrollarea.horizontalScrollBar(), + self.scrollarea.verticalScrollBar()): + sb.setValue(int(factor*sb.value()) + ((factor - 1) * sb.pageStep()/2)) + + def rotate_image(self): + pm = self.label.pixmap() + t = QTransform() + t.rotate(90) + pm = self.current_img = pm.transformed(t) + self.label.setPixmap(pm) + self.label.adjustSize() + self.factor = 1 + for sb in (self.scrollarea.horizontalScrollBar(), + self.scrollarea.verticalScrollBar()): + sb.setValue(0) + + def __call__(self, use_exec=False): + geom = self.avail_geom + self.label.setPixmap(self.current_img) + self.label.adjustSize() + self.resize(QSize(int(geom.width()/2.5), geom.height()-50)) + geom = gprefs.get(self.geom_name, None) + if geom is not None: + self.restoreGeometry(geom) + try: + self.current_image_name = unicode_type(self.current_url.toString(NO_URL_FORMATTING)).rpartition('/')[-1] + except AttributeError: + self.current_image_name = self.current_url + title = _('View image: %s')%self.current_image_name + self.setWindowTitle(title) + if use_exec: + self.exec_() + else: + self.show() + + def done(self, e): + gprefs[self.geom_name] = bytearray(self.saveGeometry()) + return QDialog.done(self, e) + + def wheelEvent(self, event): + d = event.angleDelta().y() + if abs(d) > 0 and not self.scrollarea.verticalScrollBar().isVisible(): + event.accept() + (self.zoom_out if d < 0 else self.zoom_in)() + + +class ImagePopup(object): + + def __init__(self, parent): + self.current_img = QPixmap() + self.current_url = QUrl() + self.parent = parent + self.dialogs = [] + + def __call__(self): + if self.current_img.isNull(): + return + d = ImageView(self.parent, self.current_img, self.current_url) + self.dialogs.append(d) + d.finished.connect(self.cleanup, type=Qt.QueuedConnection) + d() + + def cleanup(self): + for d in tuple(self.dialogs): + if not d.isVisible(): + self.dialogs.remove(d) + + +if __name__ == '__main__': + import sys + from calibre.gui2 import Application + app = Application([]) + p = QPixmap() + p.load(sys.argv[-1]) + u = QUrl.fromLocalFile(sys.argv[-1]) + d = ImageView(None, p, u) + d() + app.exec_() diff --git a/src/calibre/gui2/metadata/single_download.py b/src/calibre/gui2/metadata/single_download.py index 3adde555b0..4e3330df62 100644 --- a/src/calibre/gui2/metadata/single_download.py +++ b/src/calibre/gui2/metadata/single_download.py @@ -830,7 +830,7 @@ class CoversView(QListView): # {{{ if pmap is None and idx.row() == 0: pmap = self.model().cc if pmap is not None: - from calibre.gui2.viewer.image_popup import ImageView + from calibre.gui2.image_popup import ImageView d = ImageView(self, pmap, unicode_type(idx.data(Qt.DisplayRole) or ''), geom_name='metadata_download_cover_popup_geom') d(use_exec=True) diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py index eb818ec645..29c0ea8fe5 100644 --- a/src/calibre/gui2/tweak_book/preview.py +++ b/src/calibre/gui2/tweak_book/preview.py @@ -30,7 +30,7 @@ from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_MIME, serialize from calibre.ebooks.oeb.polish.parsing import parse from calibre.gui2 import NO_URL_FORMATTING, error_dialog, open_url from calibre.gui2.tweak_book import TOP, actions, current_container, editors, tprefs -from calibre.gui2.viewer2.web_view import send_reply +from calibre.gui2.viewer.web_view import send_reply from calibre.gui2.webengine import ( Bridge, RestartingWebEngineView, create_script, from_js, insert_scripts, secure_webengine, to_js diff --git a/src/calibre/gui2/viewer2/__init__.py b/src/calibre/gui2/viewer/__init__.py similarity index 100% rename from src/calibre/gui2/viewer2/__init__.py rename to src/calibre/gui2/viewer/__init__.py diff --git a/src/calibre/gui2/viewer2/convert_book.py b/src/calibre/gui2/viewer/convert_book.py similarity index 100% rename from src/calibre/gui2/viewer2/convert_book.py rename to src/calibre/gui2/viewer/convert_book.py diff --git a/src/calibre/gui2/viewer2/main.py b/src/calibre/gui2/viewer/main.py similarity index 99% rename from src/calibre/gui2/viewer2/main.py rename to src/calibre/gui2/viewer/main.py index a521d22064..cfc1831140 100644 --- a/src/calibre/gui2/viewer2/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -18,7 +18,7 @@ from calibre.constants import FAKE_PROTOCOL, VIEWER_APP_UID, islinux, iswindows from calibre.gui2 import ( Application, error_dialog, set_app_uid, setup_gui_option_parser ) -from calibre.gui2.viewer2.ui import EbookViewer +from calibre.gui2.viewer.ui import EbookViewer from calibre.ptempfile import reset_base_dir from calibre.utils.config import JSONConfig from calibre.utils.ipc import RC, viewer_socket_address diff --git a/src/calibre/gui2/viewer2/mathjax.py b/src/calibre/gui2/viewer/mathjax.py similarity index 100% rename from src/calibre/gui2/viewer2/mathjax.py rename to src/calibre/gui2/viewer/mathjax.py diff --git a/src/calibre/gui2/viewer2/ui.py b/src/calibre/gui2/viewer/ui.py similarity index 95% rename from src/calibre/gui2/viewer2/ui.py rename to src/calibre/gui2/viewer/ui.py index 9739aefe09..587d895c2d 100644 --- a/src/calibre/gui2/viewer2/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -11,8 +11,8 @@ from PyQt5.Qt import QDockWidget, Qt, pyqtSignal from calibre.gui2 import error_dialog from calibre.gui2.main_window import MainWindow -from calibre.gui2.viewer2.convert_book import prepare_book -from calibre.gui2.viewer2.web_view import WebView, set_book_path +from calibre.gui2.viewer.convert_book import prepare_book +from calibre.gui2.viewer.web_view import WebView, set_book_path from calibre.utils.ipc.simple_worker import WorkerError diff --git a/src/calibre/gui2/viewer2/web_view.py b/src/calibre/gui2/viewer/web_view.py similarity index 99% rename from src/calibre/gui2/viewer2/web_view.py rename to src/calibre/gui2/viewer/web_view.py index 448c798d35..88c1417821 100644 --- a/src/calibre/gui2/viewer2/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -115,7 +115,7 @@ class UrlSchemeHandler(QWebEngineUrlSchemeHandler): data = b'[' + manifest + b',' + metadata + b']' send_reply(rq, mime_type, data) elif name.startswith('mathjax/'): - from calibre.gui2.viewer2.mathjax import monkeypatch_mathjax + from calibre.gui2.viewer.mathjax import monkeypatch_mathjax if name == 'mathjax/manifest.json': if self.mathjax_manifest is None: import json