Remove the create_annotation module

The entire UI is being removed since all operations will be performed
via the selection bar
This commit is contained in:
Kovid Goyal 2020-08-02 21:39:29 +05:30
parent 948acd6a55
commit 1ce8b68de6
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 21 additions and 751 deletions

View File

@ -285,13 +285,10 @@ class HighlightsPanel(QWidget):
b.clicked.connect(target)
return b
self.add_button = button('plus.png', _('Add'), _('Create a new highlight'), self.add_highlight)
self.edit_button = button('edit_input.png', _('Edit'), _('Edit the selected highlight'), self.edit_highlight)
self.remove_button = button('trash.png', _('Remove'), _('Remove the selected highlights'), self.remove_highlight)
h.addWidget(self.add_button), h.addWidget(self.edit_button), h.addWidget(self.remove_button)
self.export_button = button('save.png', _('Export'), _('Export all highlights'), self.export)
l.addWidget(self.export_button)
h.addWidget(self.edit_button), h.addWidget(self.remove_button), h.addWidget(self.export_button)
self.notes_display = nd = NotesDisplay(self)
nd.notes_edited.connect(self.notes_edited)
@ -356,9 +353,6 @@ class HighlightsPanel(QWidget):
for h in highlights:
self.request_highlight_action.emit(h['uuid'], 'delete')
def add_highlight(self):
self.request_highlight_action.emit(None, 'create')
def export(self):
hl = list(self.highlights.all_highlights)
if not hl:

View File

@ -1,708 +0,0 @@
# 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 gettext import gettext as _
from uuid import short_uuid
from book_list.globals import get_session_data
from book_list.theme import cached_color_to_rgba, get_color
from dom import clear, ensure_id, svgicon, unique_id
from modals import error_dialog, question_dialog
from read_book.globals import ui_operations
from read_book.shortcuts import shortcut_for_key_event
from widgets import create_button
WAITING_FOR_CLICK = 1
WAITING_FOR_DRAG = 2
DRAGGING_LEFT = 3
DRAGGING_RIGHT = 4
dark_fg = '#111'
light_fg = '#eee'
builtin_highlight_colors = {
'#fce2ae': dark_fg,
'#b6ffea': dark_fg,
'#ffb3b3': dark_fg,
'#ffdcf7': dark_fg,
'#cae8d5': dark_fg,
'#204051': light_fg,
'#3b6978': light_fg,
'#2b580c': light_fg,
'#512b58': light_fg,
}
default_highlight_color = '#fce2ae'
def default_highlight_style():
return {
'background-color': default_highlight_color,
'color': builtin_highlight_colors[default_highlight_color]
}
def selection_handle(invert, style):
ans = svgicon('selection-handle')
use = ans.querySelector('use')
use.style.stroke = style['color']
use.style.fill = style['background-color']
s = ans.style
if invert:
s.transform = 'scaleX(-1)'
s.position = 'absolute'
s.boxSizing = 'border-box'
s.touchAction = 'none'
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
def map_to_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
BAR_SIZE = 32
DRAG_SCROLL_ZONE_MIN_HEIGHT = 10
def create_bar():
style = f'min-height: 1px; min-width: 1px; max-height: {BAR_SIZE}px; height: {BAR_SIZE}px'
ans = E.div(
id=unique_id('annot-bar'),
style=f'height: {BAR_SIZE}px; max-height: {BAR_SIZE}px; width: 100vw; display: flex; justify-content: space-between;',
E.div(style=style), E.div(style=style), E.div(style=style),
)
return ans
class EditNotesAndColors: # {{{
def __init__(self, container, hide_middle, accept, current_notes, current_style):
self.initial_style = current_style
def separator():
return E.hr(style='max-width: 80em; width: 80vw; border-top: solid 1px; margin: auto; margin-top: 2ex; margin-bottom: 2ex')
def finish():
hide_middle()
accept()
def handle_keypress(ev):
ev.stopPropagation()
if ev.key is 'Escape':
hide_middle()
elif ev.key is 'Enter' and ev.ctrlKey:
finish()
c = E.div(
style=f'background: {get_color("window-background")}; margin: auto; padding: 1rem',
onclick=def(ev): ev.stopPropagation();,
id=unique_id(),
E.h3(_('Add notes for this highlight')),
E.textarea(
current_notes or '',
rows='10', spellcheck='true', style='resize: none; width: 80vw; max-width: 80em; margin: 1ex',
onkeydown=handle_keypress,
),
E.div(
style='margin: 1ex; font-size: smaller',
_('Double click or long tap on a highlight to see its notes')
),
separator(),
E.h3(_('Choose the color for this highlight'), style='margin-bottom: 2ex'),
E.div(
class_='color-block',
style=f'display: flex; flex-wrap: wrap; max-width: calc({BAR_SIZE}px * 8); margin: auto',
),
E.div(
style='max-width: 80em; width: 80vw; margin: auto; margin-top: 2ex; display: flex; justify-content: space-between; align-items: center',
E.div(
E.label(_('New color:'), ' ', E.input(type='color', onchange=self.add_custom_color))
),
E.div(
E.a(_('Remove color'), class_='simple-link remove-custom-color', onclick=self.remove_custom_color),
),
),
separator(),
E.div(
style='max-width: 80em; width: 80vw; margin: auto; display: flex; justify-content: space-between',
create_button(_('Adjust selection'), 'arrows-h', hide_middle, _('Accept changes and then adjust the selected text') + ' [Esc]'),
create_button(_('Finish'), 'check', finish, _('Finish editing highlight') + ' [Ctrl+Enter]', True),
)
)
self.container_id = c.id
container.appendChild(c)
self.seen_colors = {}
custom_highlight_colors = get_session_data().get('custom_highlight_colors')
for bg in custom_highlight_colors:
self.add_color(bg).classList.add('custom-color')
for bg in builtin_highlight_colors:
self.add_color(bg)
if not c.querySelector('.current-swatch'):
self.add_color(self.initial_style['background-color'])
self.set_visibility_of_remove_button()
self.notes_edit.focus()
def set_visibility_of_remove_button(self):
c = self.container
item = c.querySelector('.current-swatch.custom-color')
visibility = 'unset' if item else 'hidden'
c.querySelector('.remove-custom-color').style.visibility = visibility
def add_color(self, bg, at_start):
if self.seen_colors[bg]:
return
self.seen_colors[bg] = True
ic = svgicon('swatch', BAR_SIZE, BAR_SIZE)
ic.classList.add('simple-link')
is_current = bg.lower() is self.initial_style['background-color'].lower()
sqbg = get_color('window-background2') if is_current else 'unset'
ic.querySelector('use').style.fill = bg
item = E.div(
ic, style=f'padding: 4px; background-color: {sqbg}; margin: 4px',
onclick=self.change_color
)
if is_current:
item.classList.add('current-swatch')
item.dataset.bg = bg
parent = self.container.getElementsByClassName('color-block')[0]
if at_start:
parent.insertBefore(item, parent.firstChild)
else:
parent.appendChild(item)
return item
def add_custom_color(self):
bg = self.container.querySelector('input[type=color]').value
item = self.add_color(bg, True)
item.classList.add('custom-color')
self.make_swatch_current(item)
sd = get_session_data()
custom_highlight_colors = sd.get('custom_highlight_colors')
custom_highlight_colors.unshift(bg)
sd.set('custom_highlight_colors', custom_highlight_colors)
def remove_custom_color(self):
item = self.container.getElementsByClassName('current-swatch')[0]
bg = item.dataset.bg
p = item.parentNode
p.removeChild(item)
self.make_swatch_current(p.firstChild)
sd = get_session_data()
custom_highlight_colors = sd.get('custom_highlight_colors')
idx = custom_highlight_colors.indexOf(bg)
if idx > -1:
custom_highlight_colors.splice(idx, 1)
sd.set('custom_highlight_colors', custom_highlight_colors)
@property
def container(self):
return document.getElementById(self.container_id)
@property
def notes_edit(self):
return self.container.getElementsByTagName('textarea')[0]
def change_color(self, evt):
evt.stopPropagation()
self.make_swatch_current(evt.currentTarget)
def make_swatch_current(self, item):
for child in item.parentNode.childNodes:
child.style.backgroundColor = 'unset'
child.classList.remove('current-swatch')
item.style.backgroundColor = get_color('window-background2')
item.classList.add('current-swatch')
self.notes_edit.focus()
self.set_visibility_of_remove_button()
@property
def current_notes(self):
return self.notes_edit.value or ''
@property
def current_style(self):
bg = self.container.getElementsByClassName('current-swatch')[0].dataset.bg
fg = builtin_highlight_colors[bg]
if not fg:
rgba = cached_color_to_rgba(bg)
is_dark = max(rgba[0], rgba[1], rgba[2]) < 115
fg = light_fg if is_dark else dark_fg
return {'background-color': bg, 'color': fg}
# }}}
class CreateAnnotation: # {{{
container_id = 'create-annotation-overlay'
def __init__(self, view):
self.view = view
self.active_touch = None
self.drag_scroll_timer = None
self.last_drag_scroll_at = -100000
self.editing_annot_uuid = None
self.current_notes = ''
self.annotations_manager = self.view.annotations_manager
self.state = WAITING_FOR_CLICK
self.left_line_height = self.right_line_height = 8
self.in_flow_mode = False
container = self.container
container.style.flexDirection = 'column'
container.style.justifyContent = 'space-between'
self.position_in_handle = {'x': 0, 'y': 0}
def button(name, bar, icon, tt, action):
cb = svgicon(icon, bar.style.height, bar.style.height, tt)
cb.setAttribute('title', tt)
cb.style.backgroundColor = get_color('window-background')
cb.style.boxSizing = 'border-box'
cb.style.padding = '2px'
cb.style.border = 'solid 2px currentColor'
cb.style.borderRadius = '4px'
cb.style.marginLeft = '0.5rem'
cb.style.marginRight = '0.5rem'
cb.classList.add('simple-link')
cb.classList.add('adjust-button')
cb.classList.add(f'button-{name}')
cb.addEventListener('click', def(ev):
ev.preventDefault(), ev.stopPropagation()
action()
)
bar.appendChild(cb)
return cb
tb = create_bar()
container.appendChild(tb)
button('close', tb.firstChild, 'close', _('Cancel creation of highlight') + ' [Esc]', self.hide)
button('up', tb.firstChild.nextSibling, 'chevron-up', _('Scroll up') + ' [Up]', self.button_scroll.bind(None, True))
button('copy', tb.lastChild, 'copy', _('Copy to clipboard'), self.copy_to_clipboard)
button('finish', tb.lastChild, 'check', _('Finish creation of highlight') + ' [Enter]', self.accept)
middle = E.div(id=unique_id('middle'), style='display: none; text-align: center; z-index: 90000')
self.middle_id = middle.id
container.appendChild(middle)
bb = create_bar()
container.appendChild(bb)
button('remove', bb.firstChild, 'trash', _('Remove this highlight'), self.delete_highlight)
button('down', bb.firstChild.nextSibling, 'chevron-down', _('Scroll down') + ' [Down]', self.button_scroll)
button('edit', bb.lastChild, 'pencil', _('Edit notes and change highlight color') + ' [e]', self.edit_notes_and_colors)
sd = get_session_data()
style = sd.get('highlight_style') or default_highlight_style()
if not style['background-color'] or not style['color']:
style = default_highlight_style()
self.current_highlight_style = style
lh = selection_handle(False, style)
self.left_handle_id = ensure_id(lh, 'handle')
lh.addEventListener('mousedown', self.mousedown_on_handle, {'passive': False})
lh.addEventListener('touchstart', self.touchstart_on_handle, {'passive': False})
container.appendChild(lh)
rh = selection_handle(True, style)
self.right_handle_id = ensure_id(rh, 'handle')
rh.addEventListener('mousedown', self.mousedown_on_handle, {'passive': False})
rh.addEventListener('touchstart', self.touchstart_on_handle, {'passive': False})
container.appendChild(rh)
container.addEventListener('click', self.container_clicked, {'passive': False})
container.addEventListener('mouseup', self.mouseup_on_container, {'passive': False})
container.addEventListener('mousemove', self.mousemove_on_container, {'passive': False})
container.addEventListener('touchmove', self.touchmove_on_container, {'passive': False})
container.addEventListener('touchend', self.touchend_on_container, {'passive': False})
container.addEventListener('touchcancel', self.touchend_on_container, {'passive': False})
container.addEventListener('keydown', self.on_keydown, {'passive': False})
def copy_to_clipboard(self):
ui_operations.copy_selection(self.view.currently_showing.selection.text or '')
@property
def middle(self):
return document.getElementById(self.middle_id)
def edit_notes_and_colors(self):
if self.editor:
return
current_notes = self.current_notes
if not current_notes and self.editing_annot_uuid:
current_notes = self.annotations_manager.notes_for_highlight(self.editing_annot_uuid)
current_style = self.current_highlight_style
self.show_middle(self.editing_done)
container = self.middle
clear(container)
self.editor = EditNotesAndColors(container, self.hide_middle, self.accept, current_notes, current_style)
def editing_done(self):
self.current_notes = self.editor.current_notes
new_highlight_style = self.editor.current_style
self.editor = None
if self.current_highlight_style['background-color'] is not new_highlight_style['background_color']:
self.current_highlight_style = new_highlight_style
self.send_message('set-highlight-style', style=self.current_highlight_style)
get_session_data().set('highlight_style', self.current_highlight_style)
self.update_handle_colors()
return True
def update_handle_colors(self):
fill = self.current_highlight_style['background-color']
stroke = self.view.current_color_scheme.foreground
for handle in (self.left_handle, self.right_handle):
use = handle.querySelector('use')
use.style.stroke = stroke
use.style.fill = fill
def show_middle(self, pre_close_callback):
self.pre_middle_close_callback = pre_close_callback
for h in (self.left_handle, self.right_handle):
h.style.visibility = 'hidden'
for button in self.container.querySelectorAll('.adjust-button'):
button.style.visibility = 'hidden'
self.middle.style.display = 'block'
def hide_middle(self):
m = self.middle
if m.style.display is not 'none':
if self.pre_middle_close_callback:
if not self.pre_middle_close_callback():
return
self.pre_middle_close_callback = None
for button in self.container.querySelectorAll('.adjust-button'):
button.style.visibility = 'unset'
for h in (self.left_handle, self.right_handle):
h.style.visibility = 'unset'
m.style.display = 'none'
self.container.focus()
def accept(self):
s = self.current_highlight_style
style = ''
for k in Object.keys(self.current_highlight_style):
style += f'{k}: {s[k]}; '
self.send_message(
'apply-highlight', style=style, uuid=short_uuid(), existing=self.editing_annot_uuid
)
self.hide()
def quick_create(self):
s = self.current_highlight_style
style = ''
for k in Object.keys(self.current_highlight_style):
style += f'{k}: {s[k]}; '
self.send_message(
'apply-highlight', style=style, uuid=short_uuid()
)
def on_keydown(self, ev):
ev.stopPropagation(), ev.preventDefault()
if ev.key is 'Enter':
return self.accept()
if ev.key is 'e' or ev.key is 'E':
return self.edit_notes_and_colors()
sc_name = shortcut_for_key_event(ev, self.view.keyboard_shortcut_map)
if sc_name is 'show_chrome':
self.hide()
elif sc_name in ('up', 'down', 'pageup', 'pagedown'):
backwards = 'up' in sc_name
if 'page' in sc_name or not self.in_flow_mode:
self.paged_scroll(backwards)
else:
self.send_drag_scroll_message(backwards, 'left' if backwards else 'right', False)
elif sc_name in ('left', 'right'):
if self.in_flow_mode:
self.send_message('perp-scroll', backwards=bool(sc_name is 'left'))
else:
self.paged_scroll(sc_name is 'left')
def container_clicked(self, ev):
ev.stopPropagation(), ev.preventDefault()
if self.middle.style.display is not 'none':
self.hide_middle()
self.accept()
return
if self.state is WAITING_FOR_CLICK:
pt = map_to_iframe_coords({'x': ev.clientX, 'y': ev.clientY})
self.send_message('position-handles-at-point', x=pt.x, y=pt.y)
def start_handle_drag(self, ev, q):
if q is self.left_handle_id:
self.state = DRAGGING_LEFT
handle = self.left_handle
elif q is self.right_handle_id:
self.state = DRAGGING_RIGHT
handle = self.right_handle
r = handle.getBoundingClientRect()
self.position_in_handle.x = Math.round(ev.clientX - r.left)
self.position_in_handle.y = Math.round(ev.clientY - r.top)
def mousedown_on_handle(self, ev):
ev.stopPropagation(), ev.preventDefault()
if self.state is WAITING_FOR_CLICK:
return
self.start_handle_drag(ev, ev.currentTarget.id)
def touchstart_on_handle(self, ev):
ev.stopPropagation(), ev.preventDefault()
if self.state is WAITING_FOR_CLICK:
return
for touch in ev.changedTouches:
self.active_touch = touch.identifier
self.start_handle_drag(touch, ev.currentTarget.id)
break
def button_scroll(self, backwards):
if self.in_flow_mode:
self.send_drag_scroll_message(backwards, 'left' if backwards else 'right', False)
else:
self.paged_scroll(backwards)
def paged_scroll(self, backwards):
self.send_message('paged-scroll', backwards=backwards)
def run_drag_scroll(self, mouse_y, top, bottom):
backwards = mouse_y <= top
self.do_one_drag_scroll(backwards, top - mouse_y if backwards else mouse_y - bottom)
def do_one_drag_scroll(self, backwards, distance_from_boundary):
window.clearTimeout(self.drag_scroll_timer)
self.drag_scroll_timer = None
if self.state not in (DRAGGING_RIGHT, DRAGGING_LEFT):
return
sd = get_session_data()
interval = 1000/sd.get('lines_per_sec_smooth') if self.in_flow_mode else 1200
self.drag_scroll_timer = window.setTimeout(self.do_one_drag_scroll.bind(None, backwards, distance_from_boundary), interval)
now = window.performance.now()
if now - self.last_drag_scroll_at > interval:
self.send_drag_scroll_message(backwards, 'left' if self.state is DRAGGING_LEFT else 'right', True)
self.last_drag_scroll_at = now
def send_drag_scroll_message(self, backwards, handle, extend_selection):
self.send_message(
'drag-scroll', backwards=backwards, handle=handle, extents=self.current_handle_position,
extend_selection=extend_selection)
def end_drag_scroll(self):
if self.drag_scroll_timer is not None:
window.clearTimeout(self.drag_scroll_timer)
self.drag_scroll_timer = None
self.last_drag_scroll_at = -10000
def mouseup_on_container(self, ev):
if self.state in (DRAGGING_RIGHT, DRAGGING_LEFT):
self.state = WAITING_FOR_DRAG
self.end_drag_scroll()
ev.preventDefault(), ev.stopPropagation()
def touchend_on_container(self, ev):
if self.state in (DRAGGING_RIGHT, DRAGGING_LEFT):
ev.preventDefault(), ev.stopPropagation()
for touch in ev.changedTouches:
if touch.identifier is self.active_touch:
self.active_touch = None
self.state = WAITING_FOR_DRAG
self.end_drag_scroll()
return
def handle_moved(self, ev):
handle = self.left_handle if self.state is DRAGGING_LEFT else self.right_handle
s = handle.style
s.left = (ev.clientX - self.position_in_handle.x) + 'px'
s.top = (ev.clientY - self.position_in_handle.y) + 'px'
pos = self.current_handle_position
pos.start = map_to_iframe_coords(pos.start)
pos.end = map_to_iframe_coords(pos.end)
self.send_message('set-selection', extents=pos)
c = self.container
rect = c.getBoundingClientRect()
t = document.getElementById('book-top-margin').offsetHeight
top = rect.top + max(t, DRAG_SCROLL_ZONE_MIN_HEIGHT)
t = document.getElementById('book-bottom-margin').offsetHeight
bottom = rect.bottom - max(t, DRAG_SCROLL_ZONE_MIN_HEIGHT)
if ev.clientY < top or ev.clientY > bottom:
self.run_drag_scroll(ev.clientY, top, bottom)
else:
self.end_drag_scroll()
def mousemove_on_container(self, ev):
if self.state not in (DRAGGING_RIGHT, DRAGGING_LEFT):
return
ev.stopPropagation(), ev.preventDefault()
self.handle_moved(ev)
def touchmove_on_container(self, ev):
if self.state not in (DRAGGING_RIGHT, DRAGGING_LEFT):
return
ev.stopPropagation(), ev.preventDefault()
for touch in ev.changedTouches:
if touch.identifier is self.active_touch:
self.handle_moved(touch)
return
@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'
@property
def current_handle_position(self):
lh, rh = self.left_handle, self.right_handle
lbr, rbr = self.left_handle.getBoundingClientRect(), self.right_handle.getBoundingClientRect()
return {
'start': {
'onscreen': lh.style.display is not 'none',
'x': Math.round(lbr.right), 'y': Math.round(lbr.bottom - self.left_line_height // 2)
},
'end': {
'onscreen': rh.style.display is not 'none',
'x': Math.round(rbr.left), 'y': Math.round(rbr.bottom - self.right_line_height // 2)
}
}
def show(self):
self.middle.style.display = 'none'
c = self.container
c.style.display = 'flex'
c.focus()
self.update_handle_colors()
self.view.selection_bar.hide()
def hide(self):
if self.is_visible:
self.container.style.display = 'none'
self.view.focus_iframe()
self.send_message('set-highlight-style', style=None)
self.view.selection_bar.update_position()
def send_message(self, type, **kw):
self.view.iframe_wrapper.send_message('annotations', type=type, **kw)
def initiate_create_annotation(self, start_in_notes_edit):
self.send_message('create', start_in_notes_edit=v'!!start_in_notes_edit')
def edit_highlight(self, uuid):
self.send_message('edit-highlight', uuid=uuid)
self.show()
def remove_highlight(self, uuid):
self.send_message('remove-highlight', uuid=uuid)
self.annotations_manager.delete_highlight(uuid)
self.hide()
def delete_highlight(self):
uuid = self.editing_annot_uuid
question_dialog(_('Are you sure?'), _('Are you sure you want to delete this highlight permanently?'),
def (yes):
if yes:
self.remove_highlight(uuid) if uuid else self.hide()
)
def handle_message(self, msg):
if msg.type is 'create-annotation':
self.editing_annot_uuid = msg.existing or None
self.current_notes = ''
if self.editing_annot_uuid:
self.current_notes = self.annotations_manager.notes_for_highlight(self.editing_annot_uuid) or ''
hs = self.annotations_manager.style_for_highlight(self.editing_annot_uuid)
if hs:
self.current_highlight_style = hs
get_session_data().set('highlight_style', self.current_highlight_style)
if not self.is_visible:
self.view.hide_overlays()
self.state = WAITING_FOR_CLICK
self.show()
self.hide_handles()
if msg.extents and not msg.extents.start.is_empty:
self.place_handles(msg.extents)
self.in_flow_mode = msg.in_flow_mode
self.send_message('set-highlight-style', style=self.current_highlight_style)
if msg.start_in_notes_edit:
self.edit_notes_and_colors()
elif msg.type is 'position-handles':
if self.state is WAITING_FOR_CLICK:
self.place_handles(msg.extents)
self.editing_annot_uuid = msg.existing or None
if self.editing_annot_uuid:
self.current_notes = self.annotations_manager.notes_for_highlight(self.editing_annot_uuid) or ''
elif msg.type is 'scrolled':
self.place_handles_after_scroll(msg.extents, msg.handle, msg.extended)
elif msg.type is 'update-handles':
self.place_handles(msg.extents)
elif msg.type is 'highlight-applied':
if not msg.ok:
return error_dialog(
_('Highlighting failed'),
_('Failed to apply highlighting, try adjusting extent of highlight')
)
self.annotations_manager.add_highlight(msg, self.current_highlight_style, self.current_notes)
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_single_handle(self, handle, data):
map_from_iframe_coords(data)
s = handle.style
s.display = 'block' if data.onscreen else 'none'
height = data.height * 3
width = data.height * 2
s.width = f'{width}px'
s.height = f'{height}px'
bottom = data.y + data.height
top = bottom - height
s.top = f'{top}px'
if handle.id is self.left_handle_id:
s.left = (data.x - width) + 'px'
else:
s.left = data.x + 'px'
def place_handles(self, extents):
self.place_single_handle(self.left_handle, extents.start)
self.place_single_handle(self.right_handle, extents.end)
self.state = WAITING_FOR_DRAG
self.left_line_height = extents.start.height
self.right_line_height = extents.end.height
def place_handles_after_scroll(self, extents, handle, extended):
if extended:
if handle is 'right':
h = self.left_handle
data = extents.start
else:
h = self.right_handle
data = extents.end
self.place_single_handle(h, data)
else:
self.place_single_handle(self.left_handle, extents.start)
self.place_single_handle(self.right_handle, extents.end)
# }}}

View File

@ -316,17 +316,12 @@ class MainOverlay: # {{{
actions_div.appendChild(E.ul(*full_screen_actions))
no_selection_bar = not sd.get('show_selection_bar')
if no_selection_bar:
highlight_action = ac(_('Highlight'), _('Highlight text in the book'),
def(): self.overlay.hide(), self.overlay.view.initiate_create_annotation();, 'highlight')
if runtime.is_standalone_viewer:
if no_selection_bar:
actions_div.appendChild(E.ul(
ac(_('Lookup/search word'), _('Lookup or search for the currently selected word'),
def(): self.overlay.hide(), ui_operations.toggle_lookup(True);, 'library')
))
actions_div.lastChild.appendChild(highlight_action)
actions_div.lastChild.appendChild(
ac(_('Browse highlights'), _('Browse all highlights'),
def(): self.overlay.hide(), ui_operations.toggle_highlights();, 'image')
@ -355,8 +350,7 @@ class MainOverlay: # {{{
def(): self.overlay.hide(), ui_operations.quit();, 'remove'),
))
else:
if no_selection_bar:
actions_div.appendChild(E.ul(highlight_action))
pass
container.appendChild(set_css(E.div(class_=MAIN_OVERLAY_TS_CLASS, # top section
onclick=def (evt):evt.stopPropagation();,

View File

@ -156,7 +156,7 @@ def all_actions():
'copy': a('copy', _('Copy to clipboard'), 'copy_to_clipboard'),
'lookup': a('library', _('Lookup/search selected word'), 'lookup'),
'quick_highlight': a('highlight', _('Quick highlight in current color'), 'quick_highlight'),
'highlight': a('highlight', _('Highlight selection in notes mode'), 'create_highlight'),
'highlight': a('highlight', _('Highlight selection'), 'create_highlight'),
'search_net': a('search', _('Search for selection on the net'), 'internet_search'),
'remove_highlight': a('trash', _('Remove this highlight'), 'remove_highlight', True),
'clear': a('close', _('Clear selection'), 'clear_selection'),
@ -617,20 +617,27 @@ class SelectionBar:
self.hide()
def create_highlight(self):
self.view.initiate_create_annotation(True)
pass # TODO: Implement this
def quick_highlight(self):
cs = self.view.currently_showing.selection
if cs.text:
# TODO: Implement this
if cs.annot_id:
self.view.initiate_create_annotation(True)
pass
else:
self.view.create_annotation.quick_create()
pass
def remove_highlight(self):
annot_id = self.view.currently_showing.selection.annot_id
if annot_id:
self.view.create_annotation.remove_highlight(annot_id)
self.remove_highlight_with_id(annot_id)
def remove_highlight_with_id(self, annot_id):
pass # TODO: Implement this
def edit_highlight(self, annot_id):
pass # TODO: Implement this
# }}}
# Interact with iframe {{{
@ -638,4 +645,7 @@ class SelectionBar:
def send_message(self, type, **kw):
self.view.iframe_wrapper.send_message('annotations', type=type, **kw)
def handle_message(self, data):
pass # TODO: Implement this
# }}}

View File

@ -328,12 +328,6 @@ def shortcuts_definition():
_('Auto scroll slower'),
),
'create_annotation': desc(
"Ctrl+h",
'ui',
_('Create a highlight'),
),
}
return ans
@ -396,7 +390,7 @@ def add_standalone_viewer_shortcuts():
)
sc['toggle_highlights'] = desc(
"Ctrl+Alt+h",
"Ctrl+h",
'ui',
_('Toggle the highlights panel')
)

View File

@ -14,7 +14,6 @@ from iframe_comm import IframeWrapper
from modals import error_dialog, warning_dialog
from read_book.annotations import AnnotationsManager
from read_book.content_popup import ContentPopupOverlay
from read_book.create_annotation import CreateAnnotation
from read_book.globals import (
current_book, rtl_page_progression, runtime, set_current_spine_item,
ui_operations
@ -243,7 +242,6 @@ class View:
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%; display:none', id='controls-help-overlay'), # controls help overlay
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none; overflow: hidden', id=CreateAnnotation.container_id, tabindex='0'), # create annotation overlay
)
),
E.div(
@ -312,7 +310,6 @@ class View:
self.currently_showing = {'selection': {'empty': True}}
self.book_scrollbar.apply_visibility()
self.annotations_manager = AnnotationsManager(self)
self.create_annotation = CreateAnnotation(self)
@property
def iframe(self):
@ -332,7 +329,7 @@ class View:
self.set_scrollbar_visibility(not sd.get('book_scrollbar'))
def on_annotations_message(self, data):
self.create_annotation.handle_message(data)
self.selection_bar.handle_message(data)
def left_margin_clicked(self, event):
if event.button is 0:
@ -451,8 +448,6 @@ class View:
ui_operations.toggle_bookmarks()
elif data.name is 'toggle_highlights':
ui_operations.toggle_highlights()
elif data.name is 'create_annotation':
self.initiate_create_annotation()
elif data.name is 'new_bookmark':
ui_operations.new_bookmark()
elif data.name is 'toggle_inspector':
@ -626,7 +621,6 @@ 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):
@ -1249,26 +1243,18 @@ class View:
else:
self.show_name(sr.file_name, initial_position={'type':'search_result', 'search_result':sr, 'replace_history':True})
def initiate_create_annotation(self, start_in_notes_edit):
self.create_annotation.initiate_create_annotation(start_in_notes_edit)
def highlight_action(self, uuid, which):
if self.create_annotation.is_visible:
return
if which is 'create':
self.initiate_create_annotation(False)
return
spine = self.book.manifest.spine
spine_index = self.annotations_manager.spine_index_for_highlight(uuid, spine)
if spine_index < 0 or spine_index >= spine.length:
return
if which is 'edit':
if self.currently_showing.spine_index is spine_index:
self.create_annotation.edit_highlight(uuid)
self.selection_bar.edit_highlight(uuid)
else:
self.show_name(spine[spine_index], initial_position={'type':'edit_annotation', 'uuid': uuid, 'replace_history':True})
elif which is 'delete':
self.create_annotation.remove_highlight(uuid)
self.selection_bar.remove_highlight_with_id(uuid)
elif which is 'goto':
cfi = self.annotations_manager.cfi_for_highlight(uuid, spine_index)
if cfi: