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)
|
'update_progress_frac', progress_frac=pf, file_progress_frac=fpf)
|
||||||
sel = window.getSelection()
|
sel = window.getSelection()
|
||||||
if sel and not sel.isCollapsed:
|
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):
|
def onresize(self):
|
||||||
self.send_message('request_size')
|
self.send_message('request_size')
|
||||||
@ -528,7 +528,7 @@ class IframeBoss:
|
|||||||
text = sel.toString()
|
text = sel.toString()
|
||||||
self.send_message(
|
self.send_message(
|
||||||
'selectionchange', text=text, empty=v'!!collapsed',
|
'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):
|
def onresize_stage2(self):
|
||||||
if scroll_viewport.width() is self.last_window_width and scroll_viewport.height() is self.last_window_height:
|
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.resources import load_resources
|
||||||
from read_book.scrollbar import BookScrollbar
|
from read_book.scrollbar import BookScrollbar
|
||||||
from read_book.search import SearchOverlay, find_in_spine
|
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.shortcuts import create_shortcut_map
|
||||||
from read_book.timers import Timers
|
from read_book.timers import Timers
|
||||||
from read_book.toc import get_current_toc_nodes, update_visible_toc_nodes
|
from read_book.toc import get_current_toc_nodes, update_visible_toc_nodes
|
||||||
@ -222,6 +223,7 @@ class View:
|
|||||||
),
|
),
|
||||||
right_margin,
|
right_margin,
|
||||||
self.book_scrollbar.create(),
|
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%; 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%; 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
|
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.search_overlay = SearchOverlay(self)
|
||||||
self.content_popup_overlay = ContentPopupOverlay(self)
|
self.content_popup_overlay = ContentPopupOverlay(self)
|
||||||
self.overlay = Overlay(self)
|
self.overlay = Overlay(self)
|
||||||
|
self.selection_bar = SelectionBar(self)
|
||||||
self.processing_spine_item_display = False
|
self.processing_spine_item_display = False
|
||||||
self.pending_load = None
|
self.pending_load = None
|
||||||
self.currently_showing = {}
|
self.currently_showing = {}
|
||||||
@ -519,10 +522,12 @@ class View:
|
|||||||
self.currently_showing.selection_end = data.selection_extents.end
|
self.currently_showing.selection_end = data.selection_extents.end
|
||||||
if ui_operations.selection_changed:
|
if ui_operations.selection_changed:
|
||||||
ui_operations.selection_changed(self.currently_showing.selected_text)
|
ui_operations.selection_changed(self.currently_showing.selected_text)
|
||||||
|
self.selection_bar.update_position()
|
||||||
|
|
||||||
def update_selection_position(self, data):
|
def update_selection_position(self, data):
|
||||||
self.currently_showing.selection_start = data.selection_extents.start
|
self.currently_showing.selection_start = data.selection_extents.start
|
||||||
self.currently_showing.selection_end = data.selection_extents.end
|
self.currently_showing.selection_end = data.selection_extents.end
|
||||||
|
self.selection_bar.update_position()
|
||||||
|
|
||||||
def on_columns_per_screen_changed(self, data):
|
def on_columns_per_screen_changed(self, data):
|
||||||
sd = get_session_data()
|
sd = get_session_data()
|
||||||
@ -1168,6 +1173,7 @@ class View:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def on_content_loaded(self, data):
|
def on_content_loaded(self, data):
|
||||||
|
self.selection_bar.hide()
|
||||||
self.processing_spine_item_display = False
|
self.processing_spine_item_display = False
|
||||||
self.currently_showing.loading = False
|
self.currently_showing.loading = False
|
||||||
self.hide_loading()
|
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()
|
sel = window.getSelection()
|
||||||
if not sel or not sel.rangeCount or sel.isCollapsed:
|
if not sel or not sel.rangeCount or sel.isCollapsed:
|
||||||
return range_extents()
|
return range_extents()
|
||||||
start = sel.getRangeAt(0)
|
if end_must_be_focus:
|
||||||
end = sel.getRangeAt(sel.rangeCount - 1)
|
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)
|
return range_extents(start, end, in_flow_mode)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user