Initial positioning of selection handles works

This commit is contained in:
Kovid Goyal 2020-03-18 09:28:19 +05:30
parent cdb8e6025f
commit 18a7ad73a4
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 119 additions and 5 deletions

View File

@ -0,0 +1,7 @@
<svg width="64" height="96" viewBox="0 0 16.933333 25.4" version="1.1">
<path
style="fill:#3cef3d;fill-opacity:1;stroke:#000000;stroke-width:0.48521861;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.24260931,23.981882 3.1289727,19.087752 5.0532146,13.214802 15.636548,8.32069 V 0.49006772 H 0.24260931 Z"
id="selection-handle-path"
/>
</svg>

After

Width:  |  Height:  |  Size: 426 B

View File

@ -2,6 +2,31 @@
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from dom import svgicon, ensure_id
WAITING_FOR_CLICK = 0
WAITING_FOR_DRAG = 1
DRAGGING_LEFT = 2
DRAGGING_RIGHT = 3
def selection_handle(invert):
ans = svgicon('selection-handle')
s = ans.style
if invert:
s.transform = 'scaleX(-1)'
s.position = 'absolute'
s.boxSizing = 'border-box'
return ans
def map_from_iframe_coords(point):
l = document.getElementById('book-left-margin')
point.x += l.offsetWidth
t = document.getElementById('book-top-margin')
point.y += t.offsetHeight
return point
class CreateAnnotation:
@ -9,11 +34,28 @@ class CreateAnnotation:
def __init__(self, view):
self.view = view
self.state = WAITING_FOR_CLICK
container = self.container
lh = selection_handle()
self.left_handle_id = ensure_id(lh, 'handle')
container.appendChild(lh)
rh = selection_handle(True)
self.right_handle_id = ensure_id(rh, 'handle')
container.appendChild(rh)
@property
def container(self):
return document.getElementById(self.container_id)
@property
def left_handle(self):
return document.getElementById(self.left_handle_id)
@property
def right_handle(self):
return document.getElementById(self.right_handle_id)
@property
def is_visible(self):
return self.container.style.display is not 'none'
@ -29,6 +71,38 @@ class CreateAnnotation:
def handle_message(self, msg):
if msg.type is 'create-annotation':
if not self.is_visible:
self.view.hide_overlays()
self.state = WAITING_FOR_CLICK
self.show()
self.hide_handles()
if msg.extents.start.x is not None:
self.place_handles(msg.extents)
else:
print('Ignoring annotations message with unknown type:', msg.type)
def hide_handles(self):
self.left_handle.style.display = 'none'
self.right_handle.style.display = 'none'
def place_handles(self, extents):
lh, rh = self.left_handle, self.right_handle
def do_it(handle, data):
map_from_iframe_coords(data)
s = handle.style
s.display = 'block'
height = data.height * 3
width = data.height * 2
s.width = f'{width}px'
s.height = f'{height}px'
bottom = min(max(0, data.y + data.height), window.innerHeight)
top = bottom - height
s.top = f'{top}px'
return s, width
style, width = do_it(lh, extents.start)
style.left = min(max(0, extents.start.x), window.innerWidth - width // 2) + 'px'
style, width = do_it(rh, extents.end)
style.left = (min(max(width // 2, extents.end.x), window.innerWidth) - width) + 'px'
self.state = WAITING_FOR_DRAG

View File

@ -12,9 +12,9 @@ from read_book.extract import get_elements
from read_book.find import reset_find_caches, select_search_result
from read_book.flow_mode import (
anchor_funcs as flow_anchor_funcs, auto_scroll_action as flow_auto_scroll_action,
flow_onwheel, flow_to_scroll_fraction, handle_gesture as flow_handle_gesture,
handle_shortcut as flow_handle_shortcut, layout as flow_layout,
scroll_by_page as flow_scroll_by_page, ensure_selection_visible
ensure_selection_visible, flow_onwheel, flow_to_scroll_fraction,
handle_gesture as flow_handle_gesture, handle_shortcut as flow_handle_shortcut,
layout as flow_layout, scroll_by_page as flow_scroll_by_page
)
from read_book.footnotes import is_footnote_link
from read_book.globals import (
@ -50,7 +50,7 @@ from read_book.touch import (
create_handlers as create_touch_handlers, reset_handlers as reset_touch_handlers
)
from read_book.viewport import scroll_viewport
from utils import debounce, html_escape, is_ios
from utils import debounce, html_escape, is_ios, selection_extents
FORCE_FLOW_MODE = False
CALIBRE_VERSION = '__CALIBRE_VERSION__'
@ -495,7 +495,7 @@ class IframeBoss:
if self.handle_navigation_shortcut(sc_name, evt):
evt.preventDefault()
elif sc_name is 'create_annotation':
self.send_message('annotations', type='create-annotation')
self.initiate_creation_of_annotation()
else:
self.send_message('handle_shortcut', name=sc_name)
@ -600,6 +600,14 @@ class IframeBoss:
else:
end_reference_mode()
def initiate_creation_of_annotation(self):
self.send_message(
'annotations',
type='create-annotation',
in_flow_mode=current_layout_mode() is 'flow',
extents=selection_extents(),
)
def main():
main.boss = IframeBoss()

View File

@ -560,6 +560,7 @@ class View:
self.search_overlay.hide()
self.content_popup_overlay.hide()
self.reference_mode_overlay.style.display = 'none'
self.create_annotation.hide()
self.focus_iframe()
def focus_iframe(self):

View File

@ -252,6 +252,30 @@ def sandboxed_html(html, style, sandbox):
return ans
def selection_extents():
ans = {'start': {'x': None, 'y': None, 'height': None}, 'end': {'x': None, 'y': None, 'height': None}}
sel = window.getSelection()
if not sel or not sel.rangeCount:
return ans
start = sel.getRangeAt(0).cloneRange()
end = sel.getRangeAt(sel.rangeCount - 1).cloneRange()
start.collapse(True)
end.collapse(False)
def for_boundary(r, ans):
rects = r.getClientRects()
if not rects.length:
return
rect = rects[0]
ans.x = rect.left
ans.y = rect.top
ans.height = rect.bottom - rect.top
for_boundary(start, ans.start)
for_boundary(end, ans.end)
return ans
if __name__ is '__main__':
from pythonize import strings
strings()