mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
E-book viewer: Allow viewing images in the book in a separate pop-up window by right clicking on the image. Useful if you want to keep some image, like a map to the side while reading the book.
This commit is contained in:
parent
f82db76113
commit
50089cfa3f
@ -21,6 +21,7 @@ from calibre.gui2.viewer.keys import SHORTCUTS
|
|||||||
from calibre.gui2.viewer.javascript import JavaScriptLoader
|
from calibre.gui2.viewer.javascript import JavaScriptLoader
|
||||||
from calibre.gui2.viewer.position import PagePosition
|
from calibre.gui2.viewer.position import PagePosition
|
||||||
from calibre.gui2.viewer.config import config, ConfigDialog
|
from calibre.gui2.viewer.config import config, ConfigDialog
|
||||||
|
from calibre.gui2.viewer.image_popup import ImagePopup
|
||||||
from calibre.ebooks.oeb.display.webview import load_html
|
from calibre.ebooks.oeb.display.webview import load_html
|
||||||
from calibre.constants import isxp
|
from calibre.constants import isxp
|
||||||
# }}}
|
# }}}
|
||||||
@ -470,6 +471,9 @@ class DocumentView(QWebView): # {{{
|
|||||||
self.dictionary_action.setShortcut(Qt.CTRL+Qt.Key_L)
|
self.dictionary_action.setShortcut(Qt.CTRL+Qt.Key_L)
|
||||||
self.dictionary_action.triggered.connect(self.lookup)
|
self.dictionary_action.triggered.connect(self.lookup)
|
||||||
self.addAction(self.dictionary_action)
|
self.addAction(self.dictionary_action)
|
||||||
|
self.image_popup = ImagePopup(self)
|
||||||
|
self.view_image_action = QAction(_('View &image...'), self)
|
||||||
|
self.view_image_action.triggered.connect(self.image_popup)
|
||||||
self.search_action = QAction(QIcon(I('dictionary.png')),
|
self.search_action = QAction(QIcon(I('dictionary.png')),
|
||||||
_('&Search for next occurrence'), self)
|
_('&Search for next occurrence'), self)
|
||||||
self.search_action.setShortcut(Qt.CTRL+Qt.Key_S)
|
self.search_action.setShortcut(Qt.CTRL+Qt.Key_S)
|
||||||
@ -554,6 +558,11 @@ class DocumentView(QWebView): # {{{
|
|||||||
self.manager.selection_changed(unicode(self.document.selectedText()))
|
self.manager.selection_changed(unicode(self.document.selectedText()))
|
||||||
|
|
||||||
def contextMenuEvent(self, ev):
|
def contextMenuEvent(self, ev):
|
||||||
|
mf = self.document.mainFrame()
|
||||||
|
r = mf.hitTestContent(ev.pos())
|
||||||
|
img = r.pixmap()
|
||||||
|
self.image_popup.current_img = img
|
||||||
|
self.image_popup.current_url = r.imageUrl()
|
||||||
menu = self.document.createStandardContextMenu()
|
menu = self.document.createStandardContextMenu()
|
||||||
for action in self.unimplemented_actions:
|
for action in self.unimplemented_actions:
|
||||||
menu.removeAction(action)
|
menu.removeAction(action)
|
||||||
@ -561,6 +570,8 @@ class DocumentView(QWebView): # {{{
|
|||||||
if text:
|
if text:
|
||||||
menu.insertAction(list(menu.actions())[0], self.dictionary_action)
|
menu.insertAction(list(menu.actions())[0], self.dictionary_action)
|
||||||
menu.insertAction(list(menu.actions())[0], self.search_action)
|
menu.insertAction(list(menu.actions())[0], self.search_action)
|
||||||
|
if not img.isNull():
|
||||||
|
menu.addAction(self.view_image_action)
|
||||||
menu.addSeparator()
|
menu.addSeparator()
|
||||||
menu.addAction(self.goto_location_action)
|
menu.addAction(self.goto_location_action)
|
||||||
if self.document.in_fullscreen_mode and self.manager is not None:
|
if self.document.in_fullscreen_mode and self.manager is not None:
|
||||||
|
110
src/calibre/gui2/viewer/image_popup.py
Normal file
110
src/calibre/gui2/viewer/image_popup.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from PyQt4.Qt import (QDialog, QPixmap, QUrl, QScrollArea, QLabel, QSizePolicy,
|
||||||
|
QDialogButtonBox, QVBoxLayout, QPalette, QApplication, QSize, QIcon, Qt)
|
||||||
|
|
||||||
|
from calibre.gui2 import choose_save_file
|
||||||
|
|
||||||
|
class ImageView(QDialog):
|
||||||
|
|
||||||
|
def __init__(self, parent, current_img, current_url):
|
||||||
|
QDialog.__init__(self)
|
||||||
|
dw = QApplication.instance().desktop()
|
||||||
|
self.avail_geom = dw.availableGeometry(parent)
|
||||||
|
self.current_img = current_img
|
||||||
|
self.current_url = current_url
|
||||||
|
self.factor = 1.0
|
||||||
|
|
||||||
|
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)
|
||||||
|
zi.setIcon(QIcon(I('plus.png')))
|
||||||
|
zo.setIcon(QIcon(I('minus.png')))
|
||||||
|
so.setIcon(QIcon(I('save.png')))
|
||||||
|
zi.clicked.connect(self.zoom_in)
|
||||||
|
zo.clicked.connect(self.zoom_out)
|
||||||
|
so.clicked.connect(self.save_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:
|
||||||
|
self.current_img.save(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 __call__(self):
|
||||||
|
geom = self.avail_geom
|
||||||
|
self.label.setPixmap(self.current_img)
|
||||||
|
self.label.adjustSize()
|
||||||
|
self.resize(QSize(int(geom.width()/2.5), geom.height()-50))
|
||||||
|
self.current_image_name = unicode(self.current_url.toString()).rpartition('/')[-1]
|
||||||
|
title = _('View Image: %s')%self.current_image_name
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user