E-book viewer: A whole new full screen mode, with no toolbars to distract from the text and the ability to set the width of the column of tet via Preferences in the ebook viewer. Fixes #959830 (Feature request for ebook viewer app)

This commit is contained in:
Kovid Goyal 2012-03-20 18:34:24 +05:30
parent c1bb1ab5c6
commit 7658a536cc
4 changed files with 139 additions and 24 deletions

View File

@ -255,7 +255,10 @@
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="max_view_width">
<widget class="QSpinBox" name="max_fs_width">
<property name="toolTip">
<string>Set the maximum width that the book's text and pictures will take when in fullscreen mode. This allows you to read the book text without it becoming too wide.</string>
</property>
<property name="suffix">
<string> px</string>
</property>
@ -270,10 +273,10 @@
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maximum &amp;view width:</string>
<string>Maximum text width in &amp;fullscreen:</string>
</property>
<property name="buddy">
<cstring>max_view_width</cstring>
<cstring>max_fs_width</cstring>
</property>
</widget>
</item>
@ -350,7 +353,7 @@
<tabstop>serif_family</tabstop>
<tabstop>sans_family</tabstop>
<tabstop>mono_family</tabstop>
<tabstop>max_view_width</tabstop>
<tabstop>max_fs_width</tabstop>
<tabstop>opt_remember_window_size</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>

View File

@ -12,7 +12,7 @@ from PyQt4.Qt import (QSize, QSizePolicy, QUrl, SIGNAL, Qt, QTimer,
QPainter, QPalette, QBrush, QFontDatabase, QDialog,
QColor, QPoint, QImage, QRegion, QVariant, QIcon,
QFont, pyqtSignature, QAction, QByteArray, QMenu,
pyqtSignal, QSwipeGesture)
pyqtSignal, QSwipeGesture, QApplication)
from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings
from calibre.utils.config import Config, StringConfig
@ -46,8 +46,10 @@ def config(defaults=None):
help=_('Remember last used window size'))
c.add_opt('user_css', default='',
help=_('Set the user CSS stylesheet. This can be used to customize the look of all books.'))
c.add_opt('max_view_width', default=6000,
help=_('Maximum width of the viewer window, in pixels.'))
c.add_opt('max_fs_width', default=800,
help=_("Set the maximum width that the book's text and pictures will take"
" when in fullscreen mode. This allows you to read the book text"
" without it becoming too wide."))
c.add_opt('fit_images', default=True,
help=_('Resize images larger than the viewer window to fit inside it'))
c.add_opt('hyphenate', default=False, help=_('Hyphenate text'))
@ -101,7 +103,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.standard_font.setCurrentIndex({'serif':0, 'sans':1, 'mono':2}[opts.standard_font])
self.css.setPlainText(opts.user_css)
self.css.setToolTip(_('Set the user CSS stylesheet. This can be used to customize the look of all books.'))
self.max_view_width.setValue(opts.max_view_width)
self.max_fs_width.setValue(opts.max_fs_width)
with zipfile.ZipFile(P('viewer/hyphenate/patterns.zip',
allow_user_override=False), 'r') as zf:
pats = [x.split('.')[0].replace('-', '_') for x in zf.namelist()]
@ -144,7 +146,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
c.set('user_css', unicode(self.css.toPlainText()))
c.set('remember_window_size', self.opt_remember_window_size.isChecked())
c.set('fit_images', self.opt_fit_images.isChecked())
c.set('max_view_width', int(self.max_view_width.value()))
c.set('max_fs_width', int(self.max_fs_width.value()))
c.set('hyphenate', self.hyphenate.isChecked())
c.set('remember_current_page', self.opt_remember_current_page.isChecked())
c.set('wheel_flips_pages', self.opt_wheel_flips_pages.isChecked())
@ -192,6 +194,8 @@ class Document(QWebPage): # {{{
self.loaded_javascript = False
self.js_loader = JavaScriptLoader(
dynamic_coffeescript=self.debug_javascript)
self.initial_left_margin = self.initial_right_margin = u''
self.in_fullscreen_mode = False
self.setLinkDelegationPolicy(self.DelegateAllLinks)
self.scroll_marks = []
@ -239,6 +243,9 @@ class Document(QWebPage): # {{{
self.enable_page_flip = self.page_flip_duration > 0.1
self.font_magnification_step = opts.font_magnification_step
self.wheel_flips_pages = opts.wheel_flips_pages
screen_width = QApplication.desktop().screenGeometry().width()
# Leave some space for the scrollbar and some border
self.max_fs_width = min(opts.max_fs_width, screen_width-50)
def fit_images(self):
if self.do_fit_images:
@ -274,6 +281,30 @@ class Document(QWebPage): # {{{
self.set_bottom_padding(0)
self.fit_images()
self.init_hyphenate()
self.initial_left_margin = unicode(self.javascript(
'document.body.style.marginLeft').toString())
self.initial_right_margin = unicode(self.javascript(
'document.body.style.marginRight').toString())
if self.in_fullscreen_mode:
self.switch_to_fullscreen_mode()
def switch_to_fullscreen_mode(self):
self.in_fullscreen_mode = True
self.javascript('''
var s = document.body.style;
s.maxWidth = "%dpx";
s.marginLeft = "auto";
s.marginRight = "auto";
'''%self.max_fs_width)
def switch_to_window_mode(self):
self.in_fullscreen_mode = False
self.javascript('''
var s = document.body.style;
s.maxWidth = "none";
s.marginLeft = "%s";
s.marginRight = "%s";
'''%(self.initial_left_margin, self.initial_right_margin))
@pyqtSignature("QString")
def debug(self, msg):
@ -581,8 +612,8 @@ class DocumentView(QWebView): # {{{
def config(self, parent=None):
self.document.do_config(parent)
if self.manager is not None:
self.manager.set_max_width()
if self.document.in_fullscreen_mode:
self.document.switch_to_fullscreen_mode()
self.setFocus(Qt.OtherFocusReason)
def bookmark(self):
@ -602,6 +633,9 @@ class DocumentView(QWebView): # {{{
menu.insertAction(list(menu.actions())[0], self.search_action)
menu.addSeparator()
menu.addAction(self.goto_location_action)
if self.document.in_fullscreen_mode and self.manager is not None:
menu.addSeparator()
menu.addAction(self.manager.toggle_toolbar_action)
menu.exec_(ev.globalPos())
def lookup(self, *args):

View File

@ -6,10 +6,10 @@ from functools import partial
from threading import Thread
from PyQt4.Qt import (QApplication, Qt, QIcon, QTimer, SIGNAL, QByteArray,
QDoubleSpinBox, QLabel, QTextBrowser,
QPainter, QBrush, QColor, QStandardItemModel, QPalette,
QStandardItem, QUrl, QRegExpValidator, QRegExp, QLineEdit,
QToolButton, QMenu, QInputDialog, QAction, QKeySequence)
QSize, QDoubleSpinBox, QLabel, QTextBrowser, QPropertyAnimation,
QPainter, QBrush, QColor, QStandardItemModel, QPalette, QStandardItem,
QUrl, QRegExpValidator, QRegExp, QLineEdit, QToolButton, QMenu,
QInputDialog, QAction, QKeySequence)
from calibre.gui2.viewer.main_ui import Ui_EbookViewer
from calibre.gui2.viewer.printing import Printing
@ -55,8 +55,6 @@ class TOC(QStandardItemModel):
self.appendRow(TOCItem(t))
self.setHorizontalHeaderItem(0, QStandardItem(_('Table of Contents')))
class Worker(Thread):
def run(self):
@ -292,6 +290,37 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.tool_bar2.setContextMenuPolicy(Qt.PreventContextMenu)
self.tool_bar.widgetForAction(self.action_bookmark).setPopupMode(QToolButton.MenuButtonPopup)
self.action_full_screen.setCheckable(True)
self.full_screen_label = QLabel('''
<center>
<h1>%s</h1>
<h3>%s</h3>
<h3>%s</h3>
</center>
'''%(_('Full screen mode'),
_('Right click to show controls'),
_('Press Esc to quit')),
self)
self.full_screen_label.setVisible(False)
self.full_screen_label.setStyleSheet('''
QLabel {
text-align: center;
background-color: white;
color: black;
border-width: 1px;
border-style: solid;
border-radius: 20px;
}
''')
self.toggle_toolbar_action = QAction(_('Show/hide controls'), self)
self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars)
self.addAction(self.toggle_toolbar_action)
self.full_screen_label_anim = QPropertyAnimation(
self.full_screen_label, 'size')
self.esc_full_screen_action = a = QAction(self)
self.addAction(a)
a.setShortcut(Qt.Key_Escape)
a.setEnabled(False)
a.triggered.connect(self.action_full_screen.trigger)
self.print_menu = QMenu()
self.print_menu.addAction(QIcon(I('print-preview.png')), _('Print Preview'))
@ -299,7 +328,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.tool_bar.widgetForAction(self.action_print).setPopupMode(QToolButton.MenuButtonPopup)
self.connect(self.action_print, SIGNAL("triggered(bool)"), partial(self.print_book, preview=False))
self.connect(self.print_menu.actions()[0], SIGNAL("triggered(bool)"), partial(self.print_book, preview=True))
self.set_max_width()
ca = self.view.copy_action
ca.setShortcut(QKeySequence.Copy)
self.addAction(ca)
@ -313,6 +341,13 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
w = self.tool_bar.widgetForAction(self.action_open_ebook)
w.setPopupMode(QToolButton.MenuButtonPopup)
for x in ('tool_bar', 'tool_bar2'):
x = getattr(self, x)
for action in x.actions():
# So that the keyboard shortcuts for these actions will
# continue to function even when the toolbars are hidden
self.addAction(action)
self.restore_state()
def set_toc_visible(self, yes):
@ -339,12 +374,17 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
def closeEvent(self, e):
if self.isFullScreen():
self.showNormal()
self.action_full_screen.trigger()
e.ignore()
return
self.save_state()
return MainWindow.closeEvent(self, e)
def toggle_toolbars(self):
for x in ('tool_bar', 'tool_bar2'):
x = getattr(self, x)
x.setVisible(not x.isVisible())
def save_state(self):
state = bytearray(self.saveState(self.STATE_VERSION))
vprefs['viewer_toolbar_state'] = state
@ -386,11 +426,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self._lookup = None
self.dictionary_view.setHtml(html)
def set_max_width(self):
from calibre.gui2.viewer.documentview import config
c = config().parse()
self.frame.setMaximumWidth(c.max_view_width)
def get_remember_current_page_opt(self):
from calibre.gui2.viewer.documentview import config
c = config().parse()
@ -405,6 +440,46 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
else:
self.showFullScreen()
def showFullScreen(self):
self.tool_bar.setVisible(False)
self.tool_bar2.setVisible(False)
self._original_frame_margins = (
self.centralwidget.layout().contentsMargins(),
self.frame.layout().contentsMargins())
self.frame.layout().setContentsMargins(0, 0, 0, 0)
self.centralwidget.layout().setContentsMargins(0, 0, 0, 0)
super(EbookViewer, self).showFullScreen()
QTimer.singleShot(10, self.show_full_screen_label)
def show_full_screen_label(self):
f = self.full_screen_label
self.esc_full_screen_action.setEnabled(True)
f.setVisible(True)
height = 200
width = int(0.7*self.view.width())
f.resize(width, height)
f.move((self.view.width() - width)//2, (self.view.height()-height)//2)
a = self.full_screen_label_anim
a.setDuration(500)
a.setStartValue(QSize(width, 0))
a.setEndValue(QSize(width, height))
a.start()
QTimer.singleShot(2750, self.full_screen_label.hide)
self.view.document.switch_to_fullscreen_mode()
def showNormal(self):
self.esc_full_screen_action.setEnabled(False)
self.tool_bar.setVisible(True)
self.tool_bar2.setVisible(True)
self.full_screen_label.setVisible(False)
if hasattr(self, '_original_frame_margins'):
om = self._original_frame_margins
self.centralwidget.layout().setContentsMargins(om[0])
self.frame.layout().setContentsMargins(om[1])
super(EbookViewer, self).showNormal()
self.view.document.switch_to_window_mode()
def goto(self, ref):
if ref:
tokens = ref.split('.')

View File

@ -284,6 +284,9 @@
<property name="text">
<string>Toggle full screen</string>
</property>
<property name="toolTip">
<string>Toggle full screen (F11)</string>
</property>
</action>
<action name="action_print">
<property name="icon">