From e91e414687473276f6ac4b3fb7127319da2b5473 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 24 Aug 2019 07:30:14 +0530 Subject: [PATCH] Work on preferences UI for keyboard shortcuts --- src/pyj/book_list/item_list.pyj | 7 ++- src/pyj/read_book/iframe.pyj | 2 +- src/pyj/read_book/prefs/keyboard.pyj | 89 ++++++++++++++++++++++++++++ src/pyj/read_book/prefs/main.pyj | 9 +++ src/pyj/read_book/shortcuts.pyj | 13 ++-- src/pyj/read_book/view.pyj | 1 + src/pyj/session.pyj | 1 + 7 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 src/pyj/read_book/prefs/keyboard.pyj diff --git a/src/pyj/book_list/item_list.pyj b/src/pyj/book_list/item_list.pyj index 4059b1ada5..38bdda9ac8 100644 --- a/src/pyj/book_list/item_list.pyj +++ b/src/pyj/book_list/item_list.pyj @@ -48,9 +48,12 @@ def build_list(container, items, subtitle): div.appendChild(E.div(item.subtitle, class_='item-subtitle', style='padding-top:1ex')) if item.action: ul.lastChild.addEventListener('click', item.action) + if item.data: + ul.lastChild.dataset.userData = item.data -def create_item(title, action=None, subtitle=None, icon=None): - return {'title':title, 'action':action, 'subtitle':subtitle, 'icon':icon} + +def create_item(title, action=None, subtitle=None, icon=None, data=None): + return {'title':title, 'action':action, 'subtitle':subtitle, 'icon':icon, 'data': data} def create_item_list(container, items, subtitle=None): diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index 1e43c2d673..2e42f6a1c6 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -153,7 +153,7 @@ class IframeBoss: self._handle_gesture = paged_handle_gesture self.anchor_funcs = paged_anchor_funcs update_settings(data.settings) - self.keyboard_shortcut_map = create_shortcut_map() + self.keyboard_shortcut_map = create_shortcut_map(data.keyboard_shortcuts) set_current_spine_item({'name':data.name, 'is_first':index is 0, 'is_last':index is spine.length - 1, 'initial_position':data.initial_position}) self.last_cfi = None for name in self.blob_url_map: diff --git a/src/pyj/read_book/prefs/keyboard.pyj b/src/pyj/read_book/prefs/keyboard.pyj new file mode 100644 index 0000000000..10994e6597 --- /dev/null +++ b/src/pyj/read_book/prefs/keyboard.pyj @@ -0,0 +1,89 @@ +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2016, Kovid Goyal +from __python__ import bound_methods, hash_literals + +from elementmaker import E +from gettext import gettext as _ + +from book_list.globals import get_session_data +from book_list.item_list import create_item, create_item_list +from dom import unique_id +from read_book.shortcuts import GROUP_DESC, SHORTCUTS +from widgets import create_button + + +def get_container(): + return document.getElementById(get_container.id) + + +def restore_defaults(): + pass + + +def as_groups(shortcuts): + ans = {} + for sc_name in Object.keys(shortcuts): + sc = shortcuts[sc_name] + if not ans[sc.group]: + ans[sc.group] = {} + ans[sc.group][sc_name] = sc + return ans + + +def sort_group_key(group, sc_name): + return group[sc_name].short.toLowerCase() + + +def sc_as_item(sc_name, sc): + return create_item(sc.short, action=customize_shortcut.bind(None, sc_name), subtitle=sc.long, data=JSON.stringify({'name': sc_name, 'shortcuts': sc.shortcuts})) + + +def customize_shortcut(sc_name): + container = get_container() + container.firstChild.style.display = 'none' + container.lastChild.style.display = 'block' + sc = SHORTCUTS[sc_name] + container.appendChild(E.h4(sc.short)) + if sc.long: + container.appendChild(E.div(sc.long, style='font-style: italic; font-size: smaller; margin-top: 1ex')) + container.appendChild(E.div(_('Existing shortcuts:'))) + for key in sc.shortcuts: + container.appendChild(E.div(style='margin-top: 1ex', key_widget(key))) + container.appendChild(E.div(style='margin-top:1ex; display:flex; justify-content: flex-end', + create_button(_('OK'), action=close_customize_shortcut.bind(None, True)), + E.span('\xa0'), + create_button(_('Cancel'), action=close_customize_shortcut.bind(None, False)), + )) + + + +def create_keyboard_panel(container): + container.appendChild(E.div(id=unique_id('keyboard-settings'), style='margin: 1rem')) + container = container.lastChild + get_container.id = container.id + container.appendChild(E.div()) + container.appendChild(E.div(style='display: none')) + container = container.firstChild + groups = as_groups(SHORTCUTS) + items = [] + for group_name in Object.keys(groups): + container.appendChild(E.h3(GROUP_DESC[group_name])) + group = groups[group_name] + for sc_name in sorted(Object.keys(group), key=sort_group_key.bind(None, group)): + sc = group[sc_name] + items.push(sc_as_item(sc_name, sc)) + container.appendChild(E.div()) + create_item_list(container.lastChild, items) + + container.appendChild(E.div( + style='margin-top: 1rem', create_button(_('Restore defaults'), action=restore_defaults) + )) + + +develop = create_keyboard_panel + + +def commit_keyboard(onchange): + sd = get_session_data() + vals = {} + sd.set('standalone_misc_settings', vals) diff --git a/src/pyj/read_book/prefs/main.pyj b/src/pyj/read_book/prefs/main.pyj index 3dc168030c..b268dcf933 100644 --- a/src/pyj/read_book/prefs/main.pyj +++ b/src/pyj/read_book/prefs/main.pyj @@ -11,6 +11,7 @@ from read_book.globals import runtime from read_book.prefs.colors import commit_colors, create_colors_panel from read_book.prefs.fonts import commit_fonts, create_fonts_panel from read_book.prefs.head_foot import commit_head_foot, create_head_foot_panel +from read_book.prefs.keyboard import commit_keyboard, create_keyboard_panel from read_book.prefs.layout import commit_layout, create_layout_panel from read_book.prefs.misc import commit_misc, create_misc_panel from read_book.prefs.user_stylesheet import ( @@ -70,6 +71,7 @@ class Prefs: create_item(_('Page layout'), def():self.show_panel('layout');, _('Page margins and number of pages per screen')), create_item(_('User style sheet'), def():self.show_panel('user_stylesheet');, _('Style rules for text')), create_item(_('Headers and footers'), def():self.show_panel('head_foot');, _('Customize the headers and footers')), + create_item(_('Keyboard shortcuts'), def():self.show_panel('keyboard');, _('Customize the keyboard shortcuts')), ] if runtime.is_standalone_viewer: items.push(create_item( @@ -120,6 +122,13 @@ class Prefs: def close_head_foot(self): commit_head_foot(self.onchange, self.container) + def display_keyboard(self, container): + document.getElementById(self.title_id).textContent = _('Keyboard shortcuts') + create_keyboard_panel(container) + + def close_keyboard(self): + commit_keyboard(self.onchange, self.container) + def create_prefs_panel(container, close_func, on_change): Prefs(container, close_func, on_change) diff --git a/src/pyj/read_book/shortcuts.pyj b/src/pyj/read_book/shortcuts.pyj index 9cbb4c4dec..6159567340 100644 --- a/src/pyj/read_book/shortcuts.pyj +++ b/src/pyj/read_book/shortcuts.pyj @@ -31,20 +31,16 @@ def desc(sc, group, short, long): pkey = v'[]' for x in sc: pkey.push(parse_key_repr(x)) - return {'short': short, 'long': long, 'shortcuts': pkey} + return {'group': group, 'short': short, 'long': long, 'shortcuts': pkey} -def serialize_keyevent(evt): +def keyevent_as_shortcut(evt): return { 'key': evt.key, 'altKey': evt.altKey, 'ctrlKey': evt.ctrlKey, 'metaKey': evt.metaKey, 'shiftKey': evt.shiftKey } -def unserialize_keyevent(sc): - return sc - - def keyevent_to_index(evt): parts = v'[]' for mod in v"['altKey', 'ctrlKey', 'metaKey', 'shiftKey']": @@ -52,6 +48,11 @@ def keyevent_to_index(evt): return parts.join('') + evt.key +GROUP_DESC = { + 'scroll': _('Navigation') +} + + SHORTCUTS = { 'start_of_file': desc( v"['Ctrl+ArrowUp', 'Ctrl+ArrowLeft', 'Home']", diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index dc57e5f190..a89f991052 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -426,6 +426,7 @@ class View: 'color_scheme': self.get_color_scheme(True), 'base_font_size': sd.get('base_font_size'), 'user_stylesheet': sd.get('user_stylesheet'), + 'keyboard_shortcuts': sd.get('keyboard_shortcuts'), } def show_name(self, name, initial_position=None): diff --git a/src/pyj/session.pyj b/src/pyj/session.pyj index fffa7d28f7..551f00a64f 100644 --- a/src/pyj/session.pyj +++ b/src/pyj/session.pyj @@ -40,6 +40,7 @@ defaults = { 'header': {}, 'footer': {'right': 'progress'}, 'word_actions': v'[]', + 'keyboard_shortcuts': {}, 'standalone_font_settings': {}, 'standalone_misc_settings': {}, 'standalone_recently_opened': v'[]',