mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Re-organize code to get anchor visibility
This commit is contained in:
parent
e6208a3c18
commit
a93f02ee29
40
src/pyj/read_book/anchor_visibility.pyj
Normal file
40
src/pyj/read_book/anchor_visibility.pyj
Normal 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
|
@ -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)
|
||||
|
@ -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}
|
||||
|
Loading…
x
Reference in New Issue
Block a user