Re-organize code to get anchor visibility

This commit is contained in:
Kovid Goyal 2023-10-20 18:13:22 +05:30
parent e6208a3c18
commit a93f02ee29
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 65 additions and 20 deletions

View File

@ -0,0 +1,40 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from read_book.globals import current_layout_mode, get_boss
from read_book.viewport import scroll_viewport
anchor_position_cache = {}
def invalidate_anchor_position_cache():
nonlocal anchor_position_cache
anchor_position_cache = {
'layout_mode': current_layout_mode(), 'width': scroll_viewport.width(), 'height': scroll_viewport.height(),
'positions': v'{}',
}
def ensure_anchor_cache_valid():
a = anchor_position_cache
if a.layout_mode is not current_layout_mode() or a.width is not scroll_viewport.width() or a.height is not scroll_viewport.height():
invalidate_anchor_position_cache()
def position_for_anchor(anchor):
ensure_anchor_cache_valid()
cache = anchor_position_cache.positions
val = cache[anchor]
if val?:
return val
anchor_funcs = get_boss().anchor_funcs
elem = document.getElementById(anchor)
val = anchor_funcs.pos_for_elem(elem) if elem else anchor_funcs.pos_for_elem()
cache[anchor] = val
return val
def is_anchor_on_screen(anchor):
pos = position_for_anchor(anchor)
anchor_funcs = get_boss().anchor_funcs
return anchor_funcs.visibility(pos) is 0

View File

@ -9,6 +9,7 @@ from range_utils import (
all_annots_in_selection, highlight_associated_with_selection, last_span_for_crw,
reset_highlight_counter, select_crw, unwrap_all_crw, unwrap_crw, wrap_text_in_range
)
from read_book.anchor_visibility import invalidate_anchor_position_cache
from read_book.cfi import cfi_for_selection, range_from_cfi
from read_book.extract import get_elements
from read_book.find import (
@ -402,6 +403,7 @@ class IframeBoss:
if cfi:
self.jump_to_cfi('/' + cfi)
self.update_cfi()
invalidate_anchor_position_cache()
self.update_toc_position(True)
def number_of_columns_changed(self, data):
@ -435,6 +437,7 @@ class IframeBoss:
self.apply_highlights_on_load(self.highlights_to_apply)
self.highlights_to_apply = None
apply_settings()
invalidate_anchor_position_cache()
fix_fullscreen_svg_images()
self.do_layout(self.is_titlepage)
if self.mathjax:
@ -549,7 +552,7 @@ class IframeBoss:
'update_progress_frac', progress_frac=pf, file_progress_frac=fpf, page_counts=page_counts())
def update_toc_position(self, recalculate_toc_anchor_positions):
visible_anchors = update_visible_toc_anchors(self.book.manifest.toc_anchor_map, self.anchor_funcs, bool(recalculate_toc_anchor_positions))
visible_anchors = update_visible_toc_anchors(self.book.manifest.toc_anchor_map, bool(recalculate_toc_anchor_positions))
self.send_message('update_toc_position', visible_anchors=visible_anchors)
def onscroll(self):
@ -815,7 +818,7 @@ class IframeBoss:
sel = window.getSelection()
if not sel.rangeCount:
return
anchor_before = find_anchor_before_range(sel.getRangeAt(0), self.book.manifest.toc_anchor_map, self.anchor_funcs)
anchor_before = find_anchor_before_range(sel.getRangeAt(0), self.book.manifest.toc_anchor_map)
text = sel.toString()
bounds = cfi_for_selection()
style = highlight_style_as_css(style, opts.is_dark_theme, opts.color_scheme.foreground)

View File

@ -2,14 +2,19 @@
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import hash_literals
from complete import create_search_bar
from dom import set_css, svgicon, ensure_id
from elementmaker import E
from complete import create_search_bar
from dom import ensure_id, set_css, svgicon
from gettext import gettext as _
from modals import error_dialog
from widgets import create_tree, find_text_in_tree, scroll_tree_item_into_view
from read_book.globals import toc_anchor_map, set_toc_anchor_map, current_spine_item, current_layout_mode, current_book
from read_book.anchor_visibility import position_for_anchor
from read_book.globals import (
current_book, current_layout_mode, current_spine_item, get_boss, set_toc_anchor_map,
toc_anchor_map
)
from read_book.viewport import scroll_viewport
from widgets import create_tree, find_text_in_tree, scroll_tree_item_into_view
def update_visible_toc_nodes(visible_anchors):
@ -198,20 +203,16 @@ def create_toc_panel(book, container, onclick):
toc_panel.style.flexShrink = '1'
toc_panel.style.overflow = 'auto'
def recalculate_toc_anchor_positions(tam, anchor_funcs):
def recalculate_toc_anchor_positions(tam):
name = current_spine_item().name
am = {}
anchors = v'[]'
pos_map = {}
for i, anchor in enumerate(tam[name] or v'[]'):
val = anchor_funcs.pos_for_elem()
if anchor.frag:
elem = document.getElementById(anchor.frag)
if elem:
val = anchor_funcs.pos_for_elem(elem)
am[anchor.id] = val
am[anchor.id] = position_for_anchor(anchor.frag)
anchors.push(anchor.id)
pos_map[anchor.id] = i
anchor_funcs = get_boss().anchor_funcs
# stable sort by position in document
anchors.sort(def (a, b): return anchor_funcs.cmp(am[a], am[b]) or (pos_map[a] - pos_map[b]);)
@ -220,20 +221,21 @@ def recalculate_toc_anchor_positions(tam, anchor_funcs):
return current_map
def current_toc_anchor_map(tam, anchor_funcs):
def current_toc_anchor_map(tam):
current_map = toc_anchor_map()
if not (current_map and current_map.layout_mode is current_layout_mode() and current_map.width is scroll_viewport.width() and current_map.height is scroll_viewport.height()):
current_map = recalculate_toc_anchor_positions(tam, anchor_funcs)
current_map = recalculate_toc_anchor_positions(tam)
return current_map
def update_visible_toc_anchors(toc_anchor_map, anchor_funcs, recalculate):
def update_visible_toc_anchors(toc_anchor_map, recalculate):
if recalculate:
recalculate_toc_anchor_positions(toc_anchor_map, anchor_funcs)
tam = current_toc_anchor_map(toc_anchor_map, anchor_funcs)
recalculate_toc_anchor_positions(toc_anchor_map)
tam = current_toc_anchor_map(toc_anchor_map)
before = after = None
visible_anchors = {}
has_visible = False
anchor_funcs = get_boss().anchor_funcs
for anchor_id in tam.sorted_anchors:
pos = tam.pos_map[anchor_id]
@ -250,10 +252,10 @@ def update_visible_toc_anchors(toc_anchor_map, anchor_funcs, recalculate):
return {'visible_anchors':visible_anchors, 'has_visible':has_visible, 'before':before, 'after':after, 'sorted_anchors':tam.sorted_anchors}
def find_anchor_before_range(r, toc_anchor_map, anchor_funcs):
def find_anchor_before_range(r, toc_anchor_map):
name = current_spine_item().name
prev_anchor = None
tam = current_toc_anchor_map(toc_anchor_map, anchor_funcs)
tam = current_toc_anchor_map(toc_anchor_map)
anchors = toc_anchor_map[name]
if anchors:
amap = {x.id: x for x in anchors}