diff --git a/src/calibre/gui2/tweak_book/__init__.py b/src/calibre/gui2/tweak_book/__init__.py index f9ebd3217b..7f365ba5ed 100644 --- a/src/calibre/gui2/tweak_book/__init__.py +++ b/src/calibre/gui2/tweak_book/__init__.py @@ -38,6 +38,7 @@ d['preview_standard_font_family'] = 'serif' d['preview_base_font_size'] = 18 d['preview_mono_font_size'] = 14 d['preview_minimum_font_size'] = 8 +d['preview_sync_context'] = 0 d['preview_background'] = 'auto' d['preview_foreground'] = 'auto' d['preview_link_color'] = 'auto' diff --git a/src/calibre/gui2/tweak_book/preferences.py b/src/calibre/gui2/tweak_book/preferences.py index 39e0d2a128..82042a597c 100644 --- a/src/calibre/gui2/tweak_book/preferences.py +++ b/src/calibre/gui2/tweak_book/preferences.py @@ -381,6 +381,11 @@ class PreviewSettings(BasicSettings): # {{{ w = self('preview_minimum_font_size') w.setMinimum(4), w.setMaximum(100), w.setSuffix(' px') l.addRow(_('Mi&nimum font size:'), w) + w = self('preview_sync_context') + w.setMinimum(0), w.setMaximum(10), w.setSuffix(' ' + _('lines')) + w.setToolTip('

' + _( + 'Number of lines that are shown above the current line when syncing the text shown in the preview panel to the cursor position in the code view')) + l.addRow(_('Visible lines above s&ync point:'), w) l.addRow(_('Background color:'), self.color_override('preview_background')) l.addRow(_('Foreground color:'), self.color_override('preview_foreground')) l.addRow(_('Link color:'), self.color_override('preview_link_color')) diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py index fae4d4b9fa..acd9692222 100644 --- a/src/calibre/gui2/tweak_book/preview.py +++ b/src/calibre/gui2/tweak_book/preview.py @@ -341,7 +341,7 @@ class WebPage(QWebEnginePage): if lnum is None: return tags = [x.lower() for x in tags] - self.bridge.go_to_sourceline_address.emit(lnum, tags) + self.bridge.go_to_sourceline_address.emit(lnum, tags, tprefs['preview_sync_context']) def split_mode(self, enabled): if self.bridge.ready: diff --git a/src/pyj/editor.pyj b/src/pyj/editor.pyj index 2070cdcb0d..a03d886752 100644 --- a/src/pyj/editor.pyj +++ b/src/pyj/editor.pyj @@ -40,34 +40,53 @@ def find_containing_block(elem): elem = elem.parentNode return elem -def scroll_to_node(node): + +def line_height(): + ans = line_height.ans + if not ans: + ds = window.getComputedStyle(document.body) + try: + # will fail if line-height = "normal" + lh = float(ds.lineHeight) + except: + try: + lh = 1.2 * float(ds.fontSize) + except: + lh = 15 + ans = line_height.ans = max(5, lh) + return ans + + +def scroll_to_node(node, sync_context): if node is document.body: window.scrollTo(0, 0) else: node.scrollIntoView() + if sync_context: + window.scrollBy(0, -sync_context * line_height()) state = {'blocks_found': False, 'in_split_mode': False} -def go_to_line(lnum): +def go_to_line(lnum, sync_context): for node in document.querySelectorAll(f'[data-lnum="{lnum}"]'): if is_hidden(node): continue - scroll_to_node(node) + scroll_to_node(node, sync_context) break @from_python -def go_to_sourceline_address(sourceline, tags): +def go_to_sourceline_address(sourceline, tags, sync_context): nodes = document.querySelectorAll(f'[data-lnum="{sourceline}"]') for index in range(nodes.length): node = nodes[index] if index >= tags.length or node.tagName.toLowerCase() is not tags[index]: break if index == tags.length - 1 and not is_hidden(node): - return scroll_to_node(node) - go_to_line(sourceline) + return scroll_to_node(node, sync_context) + go_to_line(sourceline, sync_context) def line_numbers(): found_body = False