Work on controls for highlighting UI

This commit is contained in:
Kovid Goyal 2020-03-22 19:50:51 +05:30
parent 947f28e3cc
commit 26d405a957
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
8 changed files with 156 additions and 13 deletions

View File

@ -1,6 +1,6 @@
<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"
style="fill-opacity:1;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"
/>

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 398 B

14
imgsrc/srv/swatch.svg Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
viewBox="0 0 33.866666 33.866668"
height="128"
width="128"
>
<rect
width="31.75"
height="31.75"
x="1.0583335"
y="1.0583304"
ry="3.6852679" />
</svg>

After

Width:  |  Height:  |  Size: 262 B

View File

@ -89,13 +89,17 @@ def change_icon_image(icon_element, new_name):
else:
icon_element.firstChild.removeAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href')
def svgicon(name, height, width):
def svgicon(name, height, width, tooltip):
ans = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
ans.setAttribute('style', 'fill: currentColor; height: {}; width: {}; vertical-align: text-top'.format(height ? '2ex', width ? '2ex'))
u = document.createElementNS('http://www.w3.org/2000/svg', 'use')
ans.appendChild(u)
if name:
ans.firstChild.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-' + name)
if tooltip:
tt = document.createElementNS('http://www.w3.org/2000/svg', 'title')
tt.textContent = tooltip
ans.appendChild(tt)
return ans
def element(elem_id, child_selector):

View File

@ -2,7 +2,12 @@
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from dom import ensure_id, svgicon
from elementmaker import E
from gettext import gettext as _
from book_list.globals import get_session_data
from book_list.theme import get_color
from dom import add_extra_css, ensure_id, svgicon, unique_id
from read_book.shortcuts import shortcut_for_key_event
WAITING_FOR_CLICK = 1
@ -11,8 +16,35 @@ DRAGGING_LEFT = 3
DRAGGING_RIGHT = 4
add_extra_css(def():
ans = ''
ans += '.selection-handle { fill: #3cef3d; stroke: black }'
ans += '.selection-handle:active { fill: #FCE883; }'
return ans
)
dark_fg = '#111'
light_fg = '#eee'
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 selection_handle(invert):
ans = svgicon('selection-handle')
use = ans.querySelector('use')
use.classList.add('selection-handle')
s = ans.style
if invert:
s.transform = 'scaleX(-1)'
@ -38,6 +70,14 @@ def map_to_iframe_coords(point):
return point
def create_bar(size=32):
ans = E.div(
id=unique_id('annot-bar'),
style=f'height: {size}px; width: 100vw; display: flex; justify-content: space-between;',
)
return ans
class CreateAnnotation:
container_id = 'create-annotation-overlay'
@ -48,8 +88,40 @@ class CreateAnnotation:
self.left_line_height = self.right_line_height = 8
self.in_flow_mode = False
container = self.container
container.style.display = 'flex'
container.style.flexDirection = 'column'
container.style.justifyContent = 'space-between'
self.position_in_handle = {'x': 0, 'y': 0}
def button(bar, icon, tt, action):
cb = svgicon(icon, bar.style.height, bar.style.height, tt)
document.createElement
cb.setAttribute('title', tt)
cb.classList.add('annot-button')
cb.classList.add(f'annot-button-{icon}')
cb.style.backgroundColor = get_color('window-background')
cb.style.boxSizing = 'border-box'
cb.style.padding = '2px'
cb.classList.add('simple-link')
cb.addEventListener('click', def(ev):
ev.preventDefault(), ev.stopPropagation()
action()
)
bar.appendChild(cb)
return cb
tb = create_bar()
container.appendChild(tb)
button(tb, 'close', _('Cancel creation of highlight'), self.hide)
button(tb, 'chevron-up', _('Scroll up'), self.scroll_up)
button(tb, 'check', _('Finish creation of highlight'), self.accept)
bb = create_bar()
container.appendChild(bb)
button(bb, 'fg', _('Change highlight color'), self.choose_color)
button(bb, 'chevron-down', _('Scroll down'), self.scroll_down)
button(bb, 'pencil', _('Add a note'), self.add_text)
lh = selection_handle(True)
self.left_handle_id = ensure_id(lh, 'handle')
lh.addEventListener('mousedown', self.mousedown_on_handle, {'passive': False})
@ -64,6 +136,25 @@ class CreateAnnotation:
container.addEventListener('mousemove', self.mousemove_on_container, {'passive': False})
container.addEventListener('keydown', self.on_keydown, {'passive': False})
sd = get_session_data()
style = sd.get('highlight_style') or {
'background-color': default_highlight_color,
'color': highlight_colors[default_highlight_color]
}
self.current_highlight_style = style
def scroll_up(self):
self.send_message('scroll', backwards=True)
def scroll_down(self):
self.send_message('scroll', backwards=False)
def choose_color(self):
pass
def accept(self):
pass
def on_keydown(self, ev):
ev.stopPropagation(), ev.preventDefault()
sc_name = shortcut_for_key_event(ev, self.view.keyboard_shortcut_map)
@ -147,15 +238,25 @@ class CreateAnnotation:
}
}
@property
def current_highlight_style(self):
return JSON.parse(self.container.querySelector('.annot-button-fg').dataset.style)
@current_highlight_style.setter
def current_highlight_style(self, val):
b = self.container.querySelector('.annot-button-fg')
b.dataset.style = JSON.stringify(val)
def show(self):
c = self.container
c.style.display = 'block'
c.style.display = 'flex'
c.focus()
def hide(self):
if self.is_visible:
self.container.style.display = 'none'
self.view.focus_iframe()
self.send_message('set-highlight-style', style=None)
def send_message(self, type, **kw):
self.view.iframe_wrapper.send_message('annotations', type=type, **kw)
@ -170,6 +271,7 @@ class CreateAnnotation:
if msg.extents.start.x is not None:
self.place_handles(msg.extents)
self.in_flow_mode = msg.in_flow_mode
self.send_message('set-highlight-style', style=self.current_highlight_style)
elif msg.type is 'position-handles':
if self.state is WAITING_FOR_CLICK:
self.place_handles(msg.extents)

View File

@ -46,7 +46,7 @@ from read_book.referencing import (
from read_book.resources import finalize_resources, unserialize_html
from read_book.settings import (
apply_colors, apply_font_size, apply_settings, apply_stylesheet, opts,
set_color_scheme_class, update_settings
set_color_scheme_class, set_selection_style, update_settings
)
from read_book.shortcuts import (
create_shortcut_map, keyevent_as_shortcut, shortcut_for_key_event
@ -635,6 +635,8 @@ class IframeBoss:
elif data.type is 'perp-scroll':
if in_flow_mode and flow_annotation_scroll(data.backwards, True):
self.send_message('annotations', type='update-handles', extents=selection_extents(in_flow_mode))
elif data.type is 'set-highlight-style':
set_selection_style(data.style)
else:
console.log('Ignoring annotations message to iframe with unknown type: ' + data.type)

View File

@ -36,6 +36,15 @@ def apply_font_size():
document.documentElement.style.fontSize = '{}px'.format(opts.base_font_size)
def default_selection_colors():
if opts.is_dark_theme:
return dark_link_color, '#111'
return '#3297FD', '#eee'
styles_id = 'calibre-color-scheme-style-overrides'
def apply_colors():
for elem in (document.documentElement, document.body):
elem.style.color = opts.color_scheme.foreground
@ -45,7 +54,7 @@ def apply_colors():
document.documentElement.style.backgroundColor = opts.bg_image_fade
ss = document.getElementById('calibre-color-scheme-style-overrides')
if not ss:
ss = E.style(id='calibre-color-scheme-style-overrides', type='text/css')
ss = E.style(id=styles_id, type='text/css')
document.documentElement.appendChild(ss)
text = ''
if opts.override_book_colors is not 'never':
@ -64,18 +73,28 @@ def apply_colors():
# priority than the override all selectors above
text += f'\nhtml > body :link, html > body :link * {{ color: {c} !important }} html > body :visited, html > body :visited * {{ color: {c} !important }}'
if opts.is_dark_theme:
selbg = dark_link_color
selfg = 'black'
else:
selbg = '#3297FD'
selfg = 'white'
selbg, selfg = default_selection_colors()
text += f'\n::selection {{ background-color: {selbg}; color: {selfg} }}'
text += f'\n::selection:window-inactive {{ background-color: {selbg}; color: {selfg} }}'
ss.textContent = text
def set_selection_style(style):
if not style:
selbg, selfg = default_selection_colors()
style = {'color': selfg, 'background-color': selbg}
sheet = document.getElementById(styles_id)
if not sheet:
return
css_text = ''
for prop in Object.keys(style):
css_text += f'{prop}: {style[prop]}; '
for rule in sheet.sheet.cssRules:
if rule.type is rule.STYLE_RULE and rule.selectorText.indexOf('selection') > -1:
rule.style.cssText = css_text
def set_color_scheme_class():
if opts.is_dark_theme:
document.body.classList.add('calibre-viewer-dark-colors')

View File

@ -219,7 +219,7 @@ 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', id=CreateAnnotation.container_id, tabindex='0'), # create annotation 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(

View File

@ -59,6 +59,7 @@ defaults = {
'user_color_schemes': {},
'user_stylesheet': '',
'word_actions': v'[]',
'highlight_style': None,
}
is_local_setting = {
@ -85,6 +86,7 @@ is_local_setting = {
'standalone_misc_settings': True,
'standalone_recently_opened': True,
'user_stylesheet': True,
'highlight_style': True,
}