mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Start work on displaying selection bar
This commit is contained in:
parent
05516bfd54
commit
2f9c735d2f
@ -507,7 +507,7 @@ class IframeBoss:
|
||||
'update_progress_frac', progress_frac=pf, file_progress_frac=fpf)
|
||||
sel = window.getSelection()
|
||||
if sel and not sel.isCollapsed:
|
||||
self.send_message('update_selection_position', selection_extents=selection_extents(current_layout_mode() is 'flow'))
|
||||
self.send_message('update_selection_position', selection_extents=selection_extents(current_layout_mode() is 'flow', True))
|
||||
|
||||
def onresize(self):
|
||||
self.send_message('request_size')
|
||||
@ -528,7 +528,7 @@ class IframeBoss:
|
||||
text = sel.toString()
|
||||
self.send_message(
|
||||
'selectionchange', text=text, empty=v'!!collapsed',
|
||||
selection_extents=selection_extents(current_layout_mode() is 'flow'))
|
||||
selection_extents=selection_extents(current_layout_mode() is 'flow', True))
|
||||
|
||||
def onresize_stage2(self):
|
||||
if scroll_viewport.width() is self.last_window_width and scroll_viewport.height() is self.last_window_height:
|
||||
|
81
src/pyj/read_book/selection_bar.pyj
Normal file
81
src/pyj/read_book/selection_bar.pyj
Normal file
@ -0,0 +1,81 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __python__ import bound_methods, hash_literals
|
||||
|
||||
from elementmaker import E
|
||||
|
||||
from book_list.theme import get_color
|
||||
|
||||
|
||||
class SelectionBar:
|
||||
|
||||
def __init__(self, view):
|
||||
self.view = view
|
||||
c = self.container
|
||||
bar = E.div(
|
||||
style='position: absolute; left: 0; top: 0; height: 3ex; border: solid 1px currentColor; border-radius: 5px; overflow: hidden;'
|
||||
'pointer-events: auto; min-width: 50px; padding: 5px; background-color: {}'.format(get_color("window-background"))
|
||||
)
|
||||
c.appendChild(bar)
|
||||
|
||||
@property
|
||||
def container(self):
|
||||
return document.getElementById('book-selection-bar-overlay')
|
||||
|
||||
@property
|
||||
def bar(self):
|
||||
return self.container.firstChild
|
||||
|
||||
def hide(self):
|
||||
self.container.style.display = 'none'
|
||||
|
||||
def show(self):
|
||||
self.container.style.display = 'block'
|
||||
|
||||
@property
|
||||
def is_visible(self):
|
||||
return self.container.style.display is not 'none'
|
||||
|
||||
def update_position(self):
|
||||
cs = self.view.currently_showing
|
||||
if not cs.has_selection:
|
||||
return self.hide()
|
||||
|
||||
margins = {
|
||||
'top': document.getElementById('book-top-margin').offsetHeight,
|
||||
'bottom': document.getElementById('book-bottom-margin').offsetHeight,
|
||||
'left': document.getElementById('book-left-margin').offsetWidth,
|
||||
'right': document.getElementById('book-right-margin').offsetWidth,
|
||||
}
|
||||
|
||||
def map_boundary(x):
|
||||
return {'x': x.x + margins.left, 'y': x.y + margins.top, 'height': x.height, 'onscreen': x.onscreen}
|
||||
|
||||
start = map_boundary(cs.selection_start)
|
||||
end = map_boundary(cs.selection_end)
|
||||
if not start.onscreen and not end.onscreen:
|
||||
return self.hide()
|
||||
|
||||
self.show()
|
||||
end_after_start = start.y < end.y or (start.y is end.y and start.x < end.x)
|
||||
container = self.container
|
||||
bar = self.bar
|
||||
|
||||
# vertical position
|
||||
bar_height = bar.offsetHeight
|
||||
buffer = 2
|
||||
if end_after_start:
|
||||
has_space_below = end.y + end.height < container.offsetHeight - bar_height - buffer
|
||||
put_below = has_space_below
|
||||
else:
|
||||
has_space_above = end.y + bar_height - buffer > 0
|
||||
put_below = not has_space_above
|
||||
top = (end.y + end.height + buffer) if put_below else (end.y - bar_height - buffer)
|
||||
top = max(buffer, min(top, container.offsetHeight - bar_height - buffer))
|
||||
bar.style.top = top + 'px'
|
||||
|
||||
# horizontal position
|
||||
bar_width = bar.offsetWidth
|
||||
left = end.x - bar_width // 2
|
||||
left = max(buffer, min(left, container.offsetWidth - bar_width - buffer))
|
||||
bar.style.left = left + 'px'
|
@ -32,6 +32,7 @@ from read_book.prefs.scrolling import (
|
||||
from read_book.resources import load_resources
|
||||
from read_book.scrollbar import BookScrollbar
|
||||
from read_book.search import SearchOverlay, find_in_spine
|
||||
from read_book.selection_bar import SelectionBar
|
||||
from read_book.shortcuts import create_shortcut_map
|
||||
from read_book.timers import Timers
|
||||
from read_book.toc import get_current_toc_nodes, update_visible_toc_nodes
|
||||
@ -222,6 +223,7 @@ class View:
|
||||
),
|
||||
right_margin,
|
||||
self.book_scrollbar.create(),
|
||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none; pointer-events: none', id='book-selection-bar-overlay'), # selection bar overlay
|
||||
E.div(style='position: absolute; top:0; left:0; width: 100%; pointer-events:none; display:none', id='book-search-overlay'), # search overlay
|
||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='book-content-popup-overlay'), # content popup overlay
|
||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; overflow: auto; display:none', id='book-overlay'), # main overlay
|
||||
@ -292,6 +294,7 @@ class View:
|
||||
self.search_overlay = SearchOverlay(self)
|
||||
self.content_popup_overlay = ContentPopupOverlay(self)
|
||||
self.overlay = Overlay(self)
|
||||
self.selection_bar = SelectionBar(self)
|
||||
self.processing_spine_item_display = False
|
||||
self.pending_load = None
|
||||
self.currently_showing = {}
|
||||
@ -519,10 +522,12 @@ class View:
|
||||
self.currently_showing.selection_end = data.selection_extents.end
|
||||
if ui_operations.selection_changed:
|
||||
ui_operations.selection_changed(self.currently_showing.selected_text)
|
||||
self.selection_bar.update_position()
|
||||
|
||||
def update_selection_position(self, data):
|
||||
self.currently_showing.selection_start = data.selection_extents.start
|
||||
self.currently_showing.selection_end = data.selection_extents.end
|
||||
self.selection_bar.update_position()
|
||||
|
||||
def on_columns_per_screen_changed(self, data):
|
||||
sd = get_session_data()
|
||||
@ -1168,6 +1173,7 @@ class View:
|
||||
)
|
||||
|
||||
def on_content_loaded(self, data):
|
||||
self.selection_bar.hide()
|
||||
self.processing_spine_item_display = False
|
||||
self.currently_showing.loading = False
|
||||
self.hide_loading()
|
||||
|
@ -73,12 +73,20 @@ def range_extents(start, end, in_flow_mode):
|
||||
|
||||
|
||||
|
||||
def selection_extents(in_flow_mode):
|
||||
def selection_extents(in_flow_mode, end_must_be_focus):
|
||||
sel = window.getSelection()
|
||||
if not sel or not sel.rangeCount or sel.isCollapsed:
|
||||
return range_extents()
|
||||
start = sel.getRangeAt(0)
|
||||
end = sel.getRangeAt(sel.rangeCount - 1)
|
||||
if end_must_be_focus:
|
||||
start = document.createRange()
|
||||
start.setStart(sel.anchorNode, sel.anchorOffset)
|
||||
start.setEnd(sel.anchorNode, sel.anchorOffset)
|
||||
end = document.createRange()
|
||||
end.setStart(sel.focusNode, sel.focusOffset)
|
||||
end.setEnd(sel.focusNode, sel.focusOffset)
|
||||
else:
|
||||
start = sel.getRangeAt(0)
|
||||
end = sel.getRangeAt(sel.rangeCount - 1)
|
||||
return range_extents(start, end, in_flow_mode)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user