Implement full screen

This commit is contained in:
Kovid Goyal 2019-08-07 11:51:54 +05:30
parent 146b5dc6e3
commit 0c7bcb0f8c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 71 additions and 14 deletions

View File

@ -169,7 +169,7 @@ def main(args=sys.argv):
if opts.raise_window: if opts.raise_window:
main.raise_() main.raise_()
if opts.full_screen: if opts.full_screen:
main.showFullScreen() main.set_full_screen(True)
app.exec_() app.exec_()
if listener is not None: if listener is not None:

View File

@ -11,7 +11,9 @@ from collections import defaultdict
from hashlib import sha256 from hashlib import sha256
from threading import Thread from threading import Thread
from PyQt5.Qt import QDockWidget, QModelIndex, Qt, QVBoxLayout, QWidget, pyqtSignal from PyQt5.Qt import (
QDockWidget, QEvent, QModelIndex, Qt, QVBoxLayout, QWidget, pyqtSignal
)
from calibre import prints from calibre import prints
from calibre.constants import config_dir from calibre.constants import config_dir
@ -43,6 +45,7 @@ class EbookViewer(MainWindow):
def __init__(self): def __init__(self):
MainWindow.__init__(self, None) MainWindow.__init__(self, None)
self.in_full_screen_mode = None
try: try:
os.makedirs(annotations_dir) os.makedirs(annotations_dir)
except EnvironmentError: except EnvironmentError:
@ -73,11 +76,13 @@ class EbookViewer(MainWindow):
self.web_view.reload_book.connect(self.reload_book) self.web_view.reload_book.connect(self.reload_book)
self.web_view.toggle_toc.connect(self.toggle_toc) self.web_view.toggle_toc.connect(self.toggle_toc)
self.web_view.update_current_toc_nodes.connect(self.toc.update_current_toc_nodes) self.web_view.update_current_toc_nodes.connect(self.toc.update_current_toc_nodes)
self.web_view.toggle_full_screen.connect(self.toggle_full_screen)
self.setCentralWidget(self.web_view) self.setCentralWidget(self.web_view)
state = vprefs['main_window_state'] state = vprefs['main_window_state']
if state: if state:
self.restoreState(state, self.MAIN_WINDOW_STATE_VERSION) self.restoreState(state, self.MAIN_WINDOW_STATE_VERSION)
# IPC {{{
def handle_commandline_arg(self, arg): def handle_commandline_arg(self, arg):
if arg: if arg:
if os.path.isfile(arg) and os.access(arg, os.R_OK): if os.path.isfile(arg) and os.access(arg, os.R_OK):
@ -92,7 +97,28 @@ class EbookViewer(MainWindow):
return return
self.load_ebook(path, open_at=open_at) self.load_ebook(path, open_at=open_at)
self.raise_() self.raise_()
# }}}
# Fullscreen {{{
def set_full_screen(self, on):
if on:
self.showFullScreen()
else:
self.showNormal()
def changeEvent(self, ev):
if ev.type() == QEvent.WindowStateChange:
in_full_screen_mode = self.isFullScreen()
if self.in_full_screen_mode is None or self.in_full_screen_mode != in_full_screen_mode:
self.in_full_screen_mode = in_full_screen_mode
self.web_view.notify_full_screen_state_change(self.in_full_screen_mode)
return MainWindow.changeEvent(self, ev)
def toggle_full_screen(self):
self.set_full_screen(not self.isFullScreen())
# }}}
# ToC {{{
def toggle_toc(self): def toggle_toc(self):
if self.toc_dock.isVisible(): if self.toc_dock.isVisible():
self.toc_dock.setVisible(False) self.toc_dock.setVisible(False)
@ -106,6 +132,9 @@ class EbookViewer(MainWindow):
def toc_searched(self, index): def toc_searched(self, index):
item = self.toc_model.itemFromIndex(index) item = self.toc_model.itemFromIndex(index)
self.web_view.goto_toc_node(item.node_id) self.web_view.goto_toc_node(item.node_id)
# }}}
# Load book {{{
def load_ebook(self, pathtoebook, open_at=None, reload_book=False): def load_ebook(self, pathtoebook, open_at=None, reload_book=False):
# TODO: Implement open_at # TODO: Implement open_at
@ -166,7 +195,9 @@ class EbookViewer(MainWindow):
with open(path, 'rb') as f: with open(path, 'rb') as f:
raw = f.read() raw = f.read()
merge_annotations(parse_annotations(raw), amap) merge_annotations(parse_annotations(raw), amap)
# }}}
# CFI management {{{
def initial_cfi_for_current_book(self): def initial_cfi_for_current_book(self):
lrp = self.current_book_data['annotations_map']['last-read'] lrp = self.current_book_data['annotations_map']['last-read']
if lrp: if lrp:
@ -179,7 +210,9 @@ class EbookViewer(MainWindow):
return return
self.current_book_data['annotations_map']['last-read'] = [{ self.current_book_data['annotations_map']['last-read'] = [{
'pos': cfi, 'pos_type': 'epubcfi', 'timestamp': utcnow()}] 'pos': cfi, 'pos_type': 'epubcfi', 'timestamp': utcnow()}]
# }}}
# State serialization {{{
def save_annotations(self): def save_annotations(self):
if not self.current_book_data: if not self.current_book_data:
return return
@ -201,3 +234,4 @@ class EbookViewer(MainWindow):
self.save_annotations() self.save_annotations()
self.save_state() self.save_state()
return MainWindow.closeEvent(self, ev) return MainWindow.closeEvent(self, ev)
# }}}

View File

@ -171,11 +171,13 @@ class ViewerBridge(Bridge):
reload_book = from_js() reload_book = from_js()
toggle_toc = from_js() toggle_toc = from_js()
update_current_toc_nodes = from_js(object, object) update_current_toc_nodes = from_js(object, object)
toggle_full_screen = from_js()
create_view = to_js() create_view = to_js()
show_preparing_message = to_js() show_preparing_message = to_js()
start_book_load = to_js() start_book_load = to_js()
goto_toc_node = to_js() goto_toc_node = to_js()
full_screen_state_changed = to_js()
class WebPage(QWebEnginePage): class WebPage(QWebEnginePage):
@ -252,6 +254,7 @@ class WebView(RestartingWebEngineView):
reload_book = pyqtSignal() reload_book = pyqtSignal()
toggle_toc = pyqtSignal() toggle_toc = pyqtSignal()
update_current_toc_nodes = pyqtSignal(object, object) update_current_toc_nodes = pyqtSignal(object, object)
toggle_full_screen = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
self._host_widget = None self._host_widget = None
@ -267,6 +270,7 @@ class WebView(RestartingWebEngineView):
self.bridge.reload_book.connect(self.reload_book) self.bridge.reload_book.connect(self.reload_book)
self.bridge.toggle_toc.connect(self.toggle_toc) self.bridge.toggle_toc.connect(self.toggle_toc)
self.bridge.update_current_toc_nodes.connect(self.update_current_toc_nodes) self.bridge.update_current_toc_nodes.connect(self.update_current_toc_nodes)
self.bridge.toggle_full_screen.connect(self.toggle_full_screen)
self.pending_bridge_ready_actions = {} self.pending_bridge_ready_actions = {}
self.setPage(self._page) self.setPage(self._page)
self.setAcceptDrops(False) self.setAcceptDrops(False)
@ -343,6 +347,9 @@ class WebView(RestartingWebEngineView):
def goto_toc_node(self, node_id): def goto_toc_node(self, node_id):
self.execute_when_ready('goto_toc_node', node_id) self.execute_when_ready('goto_toc_node', node_id)
def notify_full_screen_state_change(self, in_fullscreen_mode):
self.execute_when_ready('full_screen_state_changed', in_fullscreen_mode)
def set_session_data(self, key, val): def set_session_data(self, key, val):
if key == '*' and val is None: if key == '*' and val is None:
vprefs['session_data'] = {} vprefs['session_data'] = {}

View File

@ -62,7 +62,8 @@ register_callback(def():
) )
runtime = { runtime = {
'is_standalone_viewer': False 'is_standalone_viewer': False,
'viewer_in_full_screen': False,
} }

View File

@ -216,17 +216,18 @@ class MainOverlay:
sync_action = ac(_('Sync'), _('Get last read position and annotations from the server'), self.overlay.sync_book, 'cloud-download') sync_action = ac(_('Sync'), _('Get last read position and annotations from the server'), self.overlay.sync_book, 'cloud-download')
delete_action = ac(_('Delete'), _('Delete this book from the device'), self.overlay.delete_book, 'trash') delete_action = ac(_('Delete'), _('Delete this book from the device'), self.overlay.delete_book, 'trash')
reload_action = ac(_('Reload'), _('Reload this book from the {}').format( _('computer') if runtime.is_standalone_viewer else _('server')), self.overlay.reload_book, 'refresh') reload_action = ac(_('Reload'), _('Reload this book from the {}').format( _('computer') if runtime.is_standalone_viewer else _('server')), self.overlay.reload_book, 'refresh')
home_action = ac(_('Home'), _('Return to list of books'), def(): home();, 'home')
back_action = ac(_('Back'), None, self.back, 'arrow-left')
forward_action = ac(_('Forward'), None, self.forward, 'arrow-right')
if runtime.is_standalone_viewer: if runtime.is_standalone_viewer:
reload_actions = E.ul(reload_action) reload_actions = E.ul(reload_action)
nav_actions = E.ul(back_action, forward_action)
else: else:
reload_actions = E.ul(sync_action, delete_action, reload_action) reload_actions = E.ul(sync_action, delete_action, reload_action)
nav_actions = E.ul(home_action, back_action, forward_action)
actions_div = E.div( # actions actions_div = E.div( # actions
E.ul( nav_actions,
ac(_('Home'), _('Return to list of books'), def(): home();, 'home'),
ac(_('Back'), None, self.back, 'arrow-left'),
ac(_('Forward'), None, self.forward, 'arrow-right'),
),
E.ul( E.ul(
ac(_('Search'), _('Search for text in this book'), self.overlay.show_search, 'search'), ac(_('Search'), _('Search for text in this book'), self.overlay.show_search, 'search'),
@ -247,12 +248,19 @@ class MainOverlay:
class_=MAIN_OVERLAY_ACTIONS_CLASS class_=MAIN_OVERLAY_ACTIONS_CLASS
) )
full_screen_actions = []
if runtime.is_standalone_viewer:
text = _('Exit full screen') if runtime.viewer_in_full_screen else _('Enter full screen')
full_screen_actions.push(
ac(text, '', def(): self.overlay.hide(), ui_operations.toggle_full_screen();, 'full-screen'))
else:
if not full_screen_element() and not is_ios: if not full_screen_element() and not is_ios:
# No fullscreen on iOS, see http://caniuse.com/#search=fullscreen # No fullscreen on iOS, see http://caniuse.com/#search=fullscreen
actions_div.appendChild( full_screen_actions.push(
E.ul( ac(_('Full screen'), _('Enter full screen mode'), def(): request_full_screen(), self.overlay.hide();, 'full-screen')
ac(_('Full screen'), _('Enter full screen mode'), def(): request_full_screen(), self.overlay.hide();, 'full-screen'), )
)) if full_screen_actions.length:
actions_div.appendChild(E.ul(*full_screen_actions))
container.appendChild(set_css(E.div(class_=MAIN_OVERLAY_TS_CLASS, # top section container.appendChild(set_css(E.div(class_=MAIN_OVERLAY_TS_CLASS, # top section
onclick=def (evt):evt.stopPropagation();, onclick=def (evt):evt.stopPropagation();,

View File

@ -198,6 +198,11 @@ def goto_toc_node(node_id):
view.goto_toc_node(node_id) view.goto_toc_node(node_id)
@from_python
def full_screen_state_changed(viewer_in_full_screen):
runtime.viewer_in_full_screen = viewer_in_full_screen
def onerror(msg, script_url, line_number, column_number, error_object): def onerror(msg, script_url, line_number, column_number, error_object):
if not error_object: if not error_object:
# cross domain error # cross domain error
@ -246,6 +251,8 @@ if window is window.top:
to_python.toggle_toc() to_python.toggle_toc()
ui_operations.update_current_toc_nodes = def(current_node_id, top_level_node_id): ui_operations.update_current_toc_nodes = def(current_node_id, top_level_node_id):
to_python.update_current_toc_nodes(current_node_id, top_level_node_id) to_python.update_current_toc_nodes(current_node_id, top_level_node_id)
ui_operations.toggle_full_screen = def():
to_python.toggle_full_screen()
document.body.appendChild(E.div(id='view')) document.body.appendChild(E.div(id='view'))
window.onerror = onerror window.onerror = onerror
create_modal_container() create_modal_container()