diff --git a/setzer.in b/setzer.in index cff3a384..9f9013c3 100755 --- a/setzer.in +++ b/setzer.in @@ -205,9 +205,15 @@ class MainApplicationController(Adw.Application): argparser = argparse.ArgumentParser(usage='%(prog)s [OPTION...] [FILE...]') argparser.add_argument('-V', '--version', action='version', version='@setzer_version@') +argparser.add_argument('-c', '--config', help='JSON config file for keybinds') argparser.add_argument('file', nargs='*', help=argparse.SUPPRESS) -argparser.parse_args() +args, unknown = argparser.parse_known_args() + +if args.config: + ServiceLocator.set_keymap_config_path(args.config) + +new_argv = [sys.argv[0]] + unknown + args.file main_controller = MainApplicationController() -exit_status = main_controller.run(sys.argv) +exit_status = main_controller.run(new_argv) sys.exit(exit_status) diff --git a/setzer/app/service_locator.py b/setzer/app/service_locator.py index b91f8f0a..2d93e3de 100644 --- a/setzer/app/service_locator.py +++ b/setzer/app/service_locator.py @@ -35,11 +35,18 @@ class ServiceLocator(): setzer_version = None resources_path = None app_icons_path = None + keymap_config_path = '/etc/setzer.config.json' increments = dict() regexes = dict() source_language_manager = None source_style_scheme_manager = None + def set_keymap_config_path(path): + ServiceLocator.keymap_config_path = path + + def get_keymap_config_path(): + return ServiceLocator.keymap_config_path + def set_main_window(main_window): ServiceLocator.main_window = main_window diff --git a/setzer/dialogs/keyboard_shortcuts/keyboard_shortcuts.py b/setzer/dialogs/keyboard_shortcuts/keyboard_shortcuts.py index 31d0d577..11e2204f 100644 --- a/setzer/dialogs/keyboard_shortcuts/keyboard_shortcuts.py +++ b/setzer/dialogs/keyboard_shortcuts/keyboard_shortcuts.py @@ -21,7 +21,7 @@ from gi.repository import Gtk import os.path - +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class KeyboardShortcutsDialog(object): @@ -30,93 +30,103 @@ def __init__(self, main_window): data = list() + def add_item(section, title, action_name, category=None): + shortcut_array = KeybindParser.get_shortcut(action_name, category) + if shortcut_array: + shortcut = KeybindParser.to_gtk_display(shortcut_array) + section['items'].append({'title': title, 'shortcut': shortcut}) + section = {'title': _('Documents'), 'items': list()} - section['items'].append({'title': _('Create new document'), 'shortcut': '<ctrl>N'}) - section['items'].append({'title': _('Open a document'), 'shortcut': '<ctrl>O'}) - section['items'].append({'title': _('Show recent documents'), 'shortcut': '<ctrl><shift>O'}) - section['items'].append({'title': _('Show open documents'), 'shortcut': '<ctrl>T'}) - section['items'].append({'title': _('Switch to the next open document'), 'shortcut': '<ctrl>Tab'}) - section['items'].append({'title': _('Save the current document'), 'shortcut': '<ctrl>S'}) - section['items'].append({'title': _('Save the document with a new filename'), 'shortcut': '<ctrl><shift>S'}) - section['items'].append({'title': _('Close the current document'), 'shortcut': '<ctrl>W'}) + add_item(section, _('Create new document'), 'new-latex-document', 'app') + add_item(section, _('Open a document'), 'open-document-dialog', 'app') + add_item(section, _('Show recent documents'), 'shortcut_show_document_chooser', 'app') + add_item(section, _('Show open documents'), 'shortcut_show_open_docs', 'app') + add_item(section, _('Switch to the next open document'), 'shortcut_switch_document', 'app') + add_item(section, _('Save the current document'), 'save', 'app') + add_item(section, _('Save the document with a new filename'), 'save-as', 'app') + add_item(section, _('Close the current document'), 'close-active-document', 'app') data.append(section) section = {'title': _('Tools'), 'items': list()} - section['items'].append({'title': _('Save and build .pdf-file from document'), 'shortcut': 'F5'}) - section['items'].append({'title': _('Build .pdf-file from document'), 'shortcut': 'F6'}) - section['items'].append({'title': _('Show current position in preview'), 'shortcut': 'F7'}) + add_item(section, _('Save and build .pdf-file from document'), 'save-and-build', 'app') + add_item(section, _('Build .pdf-file from document'), 'build', 'app') + add_item(section, _('Show current position in preview'), 'forward-sync', 'app') data.append(section) section = {'title': 'Windows and Panels', 'items': list()} - section['items'].append({'title': _('Show help panel'), 'shortcut': 'F1'}) - section['items'].append({'title': _('Show build log'), 'shortcut': 'F8'}) - section['items'].append({'title': _('Show preview panel'), 'shortcut': 'F9'}) - section['items'].append({'title': _('Show global menu'), 'shortcut': 'F10'}) - section['items'].append({'title': _('Show context menu'), 'shortcut': 'F12'}) - section['items'].append({'title': _('Show keyboard shortcuts'), 'shortcut': '<ctrl>question'}) - section['items'].append({'title': _('Close Application'), 'shortcut': '<ctrl>Q'}) + add_item(section, _('Show help panel'), 'shortcut_help', 'app') + add_item(section, _('Show document structure'), 'shortcut_document_structure_toggle', 'app') + add_item(section, _('Show symbols'), 'shortcut_symbols_toggle', 'app') + add_item(section, _('Show build log'), 'shortcut_build_log', 'app') + add_item(section, _('Show preview panel'), 'shortcut_preview', 'app') + add_item(section, _('Show global menu'), 'shortcut_show_hamburger', 'app') + add_item(section, _('Show context menu'), 'show-context-menu', 'document') + add_item(section, _('Show keyboard shortcuts'), 'show-shortcuts-dialog', 'app') + add_item(section, _('Close Application'), 'quit', 'app') data.append(section) section = {'title': _('Find and Replace'), 'items': list()} - section['items'].append({'title': _('Find'), 'shortcut': '<ctrl>F'}) - section['items'].append({'title': _('Find the next match'), 'shortcut': '<ctrl>G'}) - section['items'].append({'title': _('Find the previous match'), 'shortcut': '<ctrl><shift>G'}) - section['items'].append({'title': _('Find and Replace'), 'shortcut': '<ctrl>H'}) + add_item(section, _('Find'), 'start-search', 'app') + add_item(section, _('Find the next match'), 'search-next', 'document') + add_item(section, _('Find the previous match'), 'search-previous', 'document') + add_item(section, _('Find and Replace'), 'start-search-and-replace', 'app') data.append(section) section = {'title': _('Zoom'), 'items': list()} - section['items'].append({'title': _('Zoom in'), 'shortcut': '<ctrl>plus'}) - section['items'].append({'title': _('Zoom out'), 'shortcut': '<ctrl>minus'}) - section['items'].append({'title': _('Reset zoom'), 'shortcut': '<ctrl>0'}) + add_item(section, _('Zoom in'), 'zoom-in', 'app') + add_item(section, _('Zoom out'), 'zoom-out', 'app') + add_item(section, _('Reset zoom'), 'reset-zoom', 'app') data.append(section) section = {'title': 'Copy and Paste', 'items': list()} - section['items'].append({'title': _('Copy selected text to clipboard'), 'shortcut': '<ctrl>C'}) - section['items'].append({'title': _('Cut selected text to clipboard'), 'shortcut': '<ctrl>X'}) - section['items'].append({'title': _('Paste text from clipboard'), 'shortcut': '<ctrl>V'}) + add_item(section, _('Copy selected text to clipboard'), 'copy', 'document') + add_item(section, _('Cut selected text to clipboard'), 'cut', 'document') + add_item(section, _('Paste text from clipboard'), 'paste', 'document') data.append(section) section = {'title': _('Undo and Redo'), 'items': list()} - section['items'].append({'title': _('Undo previous text edit'), 'shortcut': '<ctrl>Z'}) - section['items'].append({'title': _('Redo previous text edit'), 'shortcut': '<ctrl><shift>Z'}) + add_item(section, _('Undo previous text edit'), 'undo', 'document') + add_item(section, _('Redo previous text edit'), 'redo', 'document') data.append(section) section = {'title': _('Selection'), 'items': list()} - section['items'].append({'title': _('Select all text'), 'shortcut': '<ctrl>A'}) + add_item(section, _('Select all text'), 'select-all', 'document') data.append(section) section = {'title': _('Editing'), 'items': list()} - section['items'].append({'title': _('Toggle insert / overwrite'), 'shortcut': 'Insert'}) - section['items'].append({'title': _('Move current line up'), 'shortcut': '<Alt>Up'}) - section['items'].append({'title': _('Move current line down'), 'shortcut': '<Alt>Down'}) - section['items'].append({'title': _('Move current word left'), 'shortcut': '<Alt>Left'}) - section['items'].append({'title': _('Move current word right'), 'shortcut': '<Alt>Right'}) - section['items'].append({'title': _('Increment number at cursor'), 'shortcut': '<ctrl><shift>A'}) - section['items'].append({'title': _('Decrement number at cursor'), 'shortcut': '<ctrl><shift>X'}) + add_item(section, _('Toggle insert / overwrite'), 'toggle-insert', 'document') + add_item(section, _('Move current line up'), 'move-line-up', 'document') + add_item(section, _('Move current line down'), 'move-line-down', 'document') + add_item(section, _('Move current word left'), 'move-word-left', 'document') + add_item(section, _('Move current word right'), 'move-word-right', 'document') + add_item(section, _('Select next placeholder'), 'select-next-placeholder', 'document') + add_item(section, _('Select previous placeholder'), 'select-previous-placeholder', 'document') + add_item(section, _('Increment number at cursor'), 'increment-number', 'document') + add_item(section, _('Decrement number at cursor'), 'decrement-number', 'document') data.append(section) section = {'title': _('LaTeX Shortcuts'), 'items': list()} - section['items'].append({'title': _('Comment / Uncomment current line(s)'), 'shortcut': '<ctrl>K'}) - section['items'].append({'title': _('New Line') + ' (\\\\)', 'shortcut': '<ctrl>Return'}) - section['items'].append({'title': _('Bold Text'), 'shortcut': '<ctrl>B'}) - section['items'].append({'title': _('Italic Text'), 'shortcut': '<ctrl>I'}) - section['items'].append({'title': _('Underlined Text'), 'shortcut': '<ctrl>U'}) - section['items'].append({'title': _('Typewriter Text'), 'shortcut': '<ctrl><shift>T'}) - section['items'].append({'title': _('Emphasized Text'), 'shortcut': '<ctrl><shift>E'}) - section['items'].append({'title': _('Quotation Marks'), 'shortcut': '<ctrl>quotedbl'}) - section['items'].append({'title': _('List Item'), 'shortcut': '<ctrl><shift>I'}) - section['items'].append({'title': _('Environment'), 'shortcut': '<ctrl>E'}) + add_item(section, _('Comment / Uncomment current line(s)'), 'toggle-comment', 'latex') + add_item(section, _('Quotation Marks'), 'shortcut_quotes', 'latex') + add_item(section, _('New Line') + ' (\\\\)', '\\\\\\\\\\n', 'latex-symbol') + add_item(section, _('Bold Text'), '\\\\textbf{@@}', 'latex-before-after') + add_item(section, _('Italic Text'), '\\\\textit{@@}', 'latex-before-after') + add_item(section, _('Underlined Text'), '\\\\underline{@@}', 'latex-before-after') + add_item(section, _('Typewriter Text'), '\\\\texttt{@@}', 'latex-before-after') + add_item(section, _('Emphasized Text'), '\\\\emph{@@}', 'latex-before-after') + add_item(section, _('List Item'), '\\\\item •', 'latex-symbol') + add_item(section, _('Environment'), '\\\\begin{•}\\n\\t@@\\n\\\\end{•}', 'latex-before-after') data.append(section) section = {'title': _('Math Shortcuts'), 'items': list()} - section['items'].append({'title': _('Inline Math Section'), 'shortcut': '<ctrl>M'}) - section['items'].append({'title': _('Display Math Section'), 'shortcut': '<ctrl><shift>M'}) - section['items'].append({'title': _('Equation'), 'shortcut': '<ctrl><shift>N'}) - section['items'].append({'title': _('Subscript'), 'shortcut': '<ctrl><shift>D'}) - section['items'].append({'title': _('Superscript'), 'shortcut': '<ctrl><shift>U'}) - section['items'].append({'title': _('Fraction'), 'shortcut': '<alt><shift>F'}) - section['items'].append({'title': '\\left', 'shortcut': '<ctrl><shift>L'}) - section['items'].append({'title': '\\right', 'shortcut': '<ctrl><shift>R'}) + add_item(section, _('Inline Math Section'), '$ @@ $', 'latex-before-after') + add_item(section, _('Display Math Section'), '\\\\[ @@ \\\\]', 'latex-before-after') + add_item(section, _('Equation'), '\\\\begin{equation}\\n\\t@@\\n\\\\end{equation}', 'latex-before-after') + add_item(section, _('Subscript'), '_{@@}', 'latex-before-after') + add_item(section, _('Superscript'), '^{@@}', 'latex-before-after') + add_item(section, _('Fraction'), '\\\\frac{•}{•}', 'latex-symbol') + add_item(section, '\\left', '\\\\left •', 'latex-symbol') + add_item(section, '\\right', '\\\\right •', 'latex-symbol') data.append(section) self.data = data diff --git a/setzer/document/build_widget/build_widget_viewgtk.py b/setzer/document/build_widget/build_widget_viewgtk.py index 9ecc9aa7..2eeb25e1 100644 --- a/setzer/document/build_widget/build_widget_viewgtk.py +++ b/setzer/document/build_widget/build_widget_viewgtk.py @@ -18,6 +18,7 @@ import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, GObject +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class BuildWidgetView(Gtk.Box): @@ -34,7 +35,8 @@ def __init__(self): self.build_button = Gtk.Button() self.build_button.set_child(Gtk.Image.new_from_icon_name('builder-build-symbolic')) - self.build_button.set_tooltip_text(_('Save and build .pdf-file from document') + ' (F5)') + build_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('save-and-build', 'app')) + self.build_button.set_tooltip_text(_('Save and build .pdf-file from document') + ' (' + build_shortcut + ')') self.build_button.set_action_name('win.save-and-build') self.stop_button = Gtk.Button() diff --git a/setzer/document/document_controller.py b/setzer/document/document_controller.py index 48d8302e..a6e26adc 100644 --- a/setzer/document/document_controller.py +++ b/setzer/document/document_controller.py @@ -80,12 +80,8 @@ def on_secondary_buttonpress(self, controller, n_press, x, y): def on_keypress(self, controller, keyval, keycode, state): modifiers = Gtk.accelerator_get_default_mod_mask() - if keyval in [Gdk.keyval_from_name('Tab'), Gdk.keyval_from_name('ISO_Left_Tab')]: + if keyval in [Gdk.keyval_from_name('Tab')]: if state & modifiers == 0: - self.document.select_next_placeholder() - if self.document.dot_selected(): - return True - if not self.document.settings.get_value('preferences', 'tab_jump_brackets'): return False chars_at_cursor = self.document.get_chars_at_cursor(2) if chars_at_cursor in ['\\}', '\\)', '\\]']: forward_chars = 2 @@ -97,11 +93,6 @@ def on_keypress(self, controller, keyval, keycode, state): self.document.source_buffer.place_cursor(insert_iter) return True - if (state & modifiers, keyval) == (Gdk.ModifierType.SHIFT_MASK, Gdk.keyval_from_name('ISO_Left_Tab')): - self.document.select_previous_placeholder() - if self.document.dot_selected(): - return True - return False def on_scroll(self, controller, dx, dy): diff --git a/setzer/document/search/search_viewgtk.py b/setzer/document/search/search_viewgtk.py index 3bf8af93..329bd486 100644 --- a/setzer/document/search/search_viewgtk.py +++ b/setzer/document/search/search_viewgtk.py @@ -20,6 +20,7 @@ from gi.repository import Gtk from setzer.widgets.search_entry.search_entry import SearchEntry +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class SearchBar(Gtk.Revealer): @@ -51,10 +52,12 @@ def __init__(self): self.prev_button = Gtk.Button.new_from_icon_name('go-up-symbolic') self.prev_button.set_can_focus(False) - self.prev_button.set_tooltip_text(_('Previous result') + ' (Ctrl+Shift+G)') + prev_result_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('find-previous', 'app')) + self.prev_button.set_tooltip_text(_('Previous result') + ' (' + prev_result_shortcut + ')') self.next_button = Gtk.Button.new_from_icon_name('go-down-symbolic') self.next_button.set_can_focus(False) - self.next_button.set_tooltip_text(_('Next result') + ' (Ctrl+G)') + next_result_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('find-next', 'app')) + self.next_button.set_tooltip_text(_('Next result') + ' (' + next_result_shortcut + ')') self.replace_button = Gtk.Button.new_with_label(_('Replace')) self.replace_button.set_can_focus(False) self.replace_button.set_tooltip_text(_('Replace selected result')) diff --git a/setzer/keyboard_shortcuts/defaults.py b/setzer/keyboard_shortcuts/defaults.py new file mode 100644 index 00000000..4821cb89 --- /dev/null +++ b/setzer/keyboard_shortcuts/defaults.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +# Note: For non-literal characters, use their descriptive names. +# This is required for correct parsing by the GTK shortcut system. +# +# | Character | Name | +# | ----------- | ---------- | +# | ? | question | +# | / | slash | +# | + | plus | +# | = | equal | +# | - | minus | +# | " | quotedbl | +# | Tab | Tab | +# | Enter | Return | +# | Esc | Escape | +# | Space (` `) | space | + +DEFAULT_KEYBINDS = { + 'app': { + 'new-latex-document': ['Ctrl', 'N'], + 'open-document-dialog': ['Ctrl', 'O'], + 'save': ['Ctrl', 'S'], + 'save-as': ['Ctrl', 'Shift', 'S'], + 'close-active-document': ['Ctrl', 'W'], + 'quit': ['Ctrl', 'Q'], + 'show-shortcuts-dialog': ['Ctrl', 'question'], + 'shortcut_show_open_docs': ['Ctrl', 'P'], + 'shortcut_switch_document': ['Ctrl', 'Tab'], + 'shortcut_show_document_chooser': ['Ctrl', 'Shift', 'P'], + 'zoom-in': ['Ctrl', 'equal'], # As in US keyboard, shift + equal is plus + 'zoom-out': ['Ctrl', 'minus'], + 'reset-zoom': ['Ctrl', '0'], + 'start-search': ['Ctrl', 'F'], + 'start-search-and-replace': ['Ctrl', 'H'], + 'find-next': ['F3'], + 'find-previous': ['Shift', 'F3'], + 'shortcut_help': ['F1'], + 'shortcut_document_structure_toggle': ['F2'], + 'shortcut_symbols_toggle': ['Alt', 'Y'], + 'save-and-build': ['Ctrl', 'Alt', 'B'], + 'build': ['F6'], + 'forward-sync': ['Ctrl', 'Alt', 'J'], + 'shortcut_build_log': ['F8'], + 'shortcut_preview': ['Ctrl', 'Alt', 'V'], + 'shortcut_show_hamburger': ['F10'] + }, + 'document': { + 'cut': ['Ctrl', 'X'], + 'copy': ['Ctrl', 'C'], + 'paste': ['Ctrl', 'V'], + 'select-all': ['Ctrl', 'A'], + 'undo': ['Ctrl', 'Z'], + 'redo': ['Ctrl', 'Shift', 'Z'], + 'redo_alt': ['Ctrl', 'Y'], + 'show-context-menu': ['F12'], + 'toggle-insert': ['Insert'], + 'move-line-up': ['Alt', 'Up'], + 'move-line-down': ['Alt', 'Down'], + 'move-word-left': ['Alt', 'Left'], + 'move-word-right': ['Alt', 'Right'], + 'increment-number': ['Ctrl', 'Shift', 'A'], + 'decrement-number': ['Ctrl', 'Shift', 'X'], + 'search-next': ['Ctrl', 'G'], + 'search-previous': ['Ctrl', 'Shift', 'G'], + 'select-next-placeholder': ['Tab'], + 'select-previous-placeholder': ['Shift', 'Tab'] + }, + 'latex': { + 'toggle-comment': ['Ctrl', 'slash'], + 'shortcut_quotes': ['Ctrl', 'quotedbl'] + }, + 'latex-before-after': { + '\\\\textbf{@@}': ['Ctrl', 'B'], + '\\\\textit{@@}': ['Ctrl', 'I'], + '\\\\underline{@@}': ['Ctrl', 'U'], + '\\\\texttt{@@}': ['Ctrl', 'Shift', 'T'], + '\\\\emph{@@}': ['Ctrl', 'Shift', 'E'], + '$ @@ $': ['Ctrl', 'M'], + '\\\\[ @@ \\\\]': ['Ctrl', 'Shift', 'M'], + '\\\\begin{equation}\\n\\t@@\\n\\\\end{equation}': ['Ctrl', 'Shift', 'N'], + '\\\\begin{•}\\n\\t@@\\n\\\\end{•}': ['Ctrl', 'E'], + '_{@@}': ['Ctrl', 'Shift', 'D'], + '^{@@}': ['Ctrl', 'Shift', 'U'] + }, + 'latex-symbol': { + '\\\\frac{•}{•}': ['Alt', 'Shift', 'F'], + '\\\\left •': ['Ctrl', 'Shift', 'L'], + '\\\\right •': ['Ctrl', 'Shift', 'R'], + '\\\\item •': ['Ctrl', 'Shift', 'I'], + '\\\\\\\\\\n': ['Ctrl', 'Return'] + } +} diff --git a/setzer/keyboard_shortcuts/keybind_parser.py b/setzer/keyboard_shortcuts/keybind_parser.py new file mode 100644 index 00000000..67b08410 --- /dev/null +++ b/setzer/keyboard_shortcuts/keybind_parser.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import json +import os +from setzer.app.service_locator import ServiceLocator +from setzer.keyboard_shortcuts.defaults import DEFAULT_KEYBINDS + +class KeybindParser: + _keybinds = None + + @classmethod + def load_keybinds(cls): + if cls._keybinds is not None: + return + + try: + # Initialize with a deep copy of defaults + cls._keybinds = {cat: dict(binds) for cat, binds in DEFAULT_KEYBINDS.items()} + except Exception: + cls._keybinds = {} + return + + config_path = ServiceLocator.get_keymap_config_path() + if config_path and os.path.exists(config_path): + try: + with open(config_path, 'r', encoding='utf-8') as f: + data = json.load(f) + if 'keybinds' in data and isinstance(data['keybinds'], dict): + # Merge config into defaults + for category, binds in data['keybinds'].items(): + if category in cls._keybinds and isinstance(binds, dict): + cls._keybinds[category].update(binds) + except Exception as e: + print(f"Failed to load keybinds from config file {config_path}: {e}") + # Reset to defaults if merging partially failed or corrupted state + cls._keybinds = {cat: dict(binds) for cat, binds in DEFAULT_KEYBINDS.items()} + + @classmethod + def get_category_keybinds(cls, category): + cls.load_keybinds() + return cls._keybinds.get(category, {}) + + @classmethod + def get_shortcut(cls, action_name, category=None): + cls.load_keybinds() + if category: + return cls._keybinds.get(category, {}).get(action_name) + + for cat_binds in cls._keybinds.values(): + if action_name in cat_binds: + return cat_binds[action_name] + return None + + @classmethod + def to_gtk(cls, shortcut): + """Converts ['Ctrl', 'S'] to 's'""" + if not isinstance(shortcut, list): + return shortcut + + result = "" + for key in shortcut: + if key == 'Ctrl': + result += '' + elif key == 'Shift': + result += '' + elif key == 'Alt': + result += '' + elif key == 'Super': + result += '' + else: + result += key + return result + + @classmethod + def to_gtk_display(cls, shortcut): + """Converts ['Ctrl', 'S'] to 's'""" + if not isinstance(shortcut, list): + return shortcut + + result = KeybindParser.to_gtk(shortcut).replace('<', '<').replace('>', '>') + return result + + @classmethod + def to_display(cls, shortcut): + """Converts a shortcut array like ['Ctrl', 'slash'] to 'Ctrl+'/'""" + if not isinstance(shortcut, list): + return str(shortcut) + + formatted_keys = [] + for i, key in enumerate(shortcut): + display_key = key + original_key_val = key # Store original to check for replacements later + + # Apply specific key name conversions + display_key = display_key.replace('slash', "'/'") + display_key = display_key.replace('question', "'?'") + display_key = display_key.replace('plus', "'+'") + display_key = display_key.replace('minus', "'-'") + display_key = display_key.replace('quotedbl', "'\"'") + display_key = display_key.replace('Return', _('Enter')) + + # Capitalize single letters after a modifier, if not a modifier itself + # Modifiers are typically 'Ctrl', 'Shift', 'Alt', 'Super' + if len(display_key) == 1 and display_key.isalpha() and i > 0 and \ + shortcut[i-1] in ['Ctrl', 'Shift', 'Alt', 'Super']: + formatted_keys.append(display_key.upper()) + else: + formatted_keys.append(display_key) + + return "+".join(formatted_keys) diff --git a/setzer/keyboard_shortcuts/shortcut_controller.py b/setzer/keyboard_shortcuts/shortcut_controller.py index f4236473..bcd2c730 100644 --- a/setzer/keyboard_shortcuts/shortcut_controller.py +++ b/setzer/keyboard_shortcuts/shortcut_controller.py @@ -38,5 +38,3 @@ def create_and_add_shortcut(self, trigger_string, callback): def action(self, a, b, callback): callback() return True - - diff --git a/setzer/keyboard_shortcuts/shortcut_controller_app.py b/setzer/keyboard_shortcuts/shortcut_controller_app.py index 1b3f4673..bc1248c8 100644 --- a/setzer/keyboard_shortcuts/shortcut_controller_app.py +++ b/setzer/keyboard_shortcuts/shortcut_controller_app.py @@ -22,6 +22,7 @@ from setzer.app.service_locator import ServiceLocator from setzer.keyboard_shortcuts.shortcut_controller import ShortcutController from setzer.popovers.popover_manager import PopoverManager +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class ShortcutControllerApp(ShortcutController): @@ -35,32 +36,13 @@ def __init__(self): self.set_propagation_phase(Gtk.PropagationPhase.CAPTURE) - self.create_and_add_shortcut('n', self.actions.new_latex_document) - self.create_and_add_shortcut('o', self.actions.open_document_dialog) - self.create_and_add_shortcut('s', self.actions.save) - self.create_and_add_shortcut('s', self.actions.save_as) - self.create_and_add_shortcut('w', self.actions.close_active_document) - self.create_and_add_shortcut('q', self.actions.actions['quit'].activate) - self.create_and_add_shortcut('question', self.actions.show_shortcuts_dialog) - self.create_and_add_shortcut('t', self.shortcut_show_open_docs) - self.create_and_add_shortcut('Tab', self.shortcut_switch_document) - self.create_and_add_shortcut('o', self.shortcut_show_document_chooser) - self.create_and_add_shortcut('plus', self.actions.zoom_in) - self.create_and_add_shortcut('minus', self.actions.zoom_out) - self.create_and_add_shortcut('0', self.actions.reset_zoom) - self.create_and_add_shortcut('f', self.actions.start_search) - self.create_and_add_shortcut('h', self.actions.start_search_and_replace) - self.create_and_add_shortcut('g', self.actions.find_next) - self.create_and_add_shortcut('g', self.actions.find_previous) - self.create_and_add_shortcut('F1', self.shortcut_help) - self.create_and_add_shortcut('F2', self.shortcut_document_structure_toggle) - self.create_and_add_shortcut('F3', self.shortcut_symbols_toggle) - self.create_and_add_shortcut('F5', self.actions.save_and_build) - self.create_and_add_shortcut('F6', self.actions.build) - self.create_and_add_shortcut('F7', self.actions.forward_sync) - self.create_and_add_shortcut('F8', self.shortcut_build_log) - self.create_and_add_shortcut('F9', self.shortcut_preview) - self.create_and_add_shortcut('F10', self.shortcut_show_hamburger) + app_keybinds = KeybindParser.get_category_keybinds('app') + for action_name, shortcut_array in app_keybinds.items(): + shortcut = KeybindParser.to_gtk(shortcut_array) + if action_name in self.actions.actions: + self.create_and_add_shortcut(shortcut, self.actions.actions[action_name].activate) + elif hasattr(self, action_name): + self.create_and_add_shortcut(shortcut, getattr(self, action_name)) def shortcut_show_document_chooser(self): if self.main_window.headerbar.open_document_button.get_sensitive(): @@ -104,5 +86,3 @@ def shortcut_symbols_toggle(self, accel_group=None, window=None, key=None, mask= def shortcut_show_hamburger(self, accel_group=None, window=None, key=None, mask=None): PopoverManager.popup_at_button('hamburger_menu') return True - - diff --git a/setzer/keyboard_shortcuts/shortcut_controller_document.py b/setzer/keyboard_shortcuts/shortcut_controller_document.py index b1b80d87..a2dac042 100644 --- a/setzer/keyboard_shortcuts/shortcut_controller_document.py +++ b/setzer/keyboard_shortcuts/shortcut_controller_document.py @@ -21,6 +21,7 @@ from setzer.app.service_locator import ServiceLocator from setzer.keyboard_shortcuts.shortcut_controller import ShortcutController +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class ShortcutControllerDocument(ShortcutController): @@ -34,11 +35,12 @@ def __init__(self): self.set_propagation_phase(Gtk.PropagationPhase.CAPTURE) - self.create_and_add_shortcut('x', self.actions.cut) - self.create_and_add_shortcut('c', self.actions.copy) - self.create_and_add_shortcut('v', self.actions.paste) - self.create_and_add_shortcut('z', self.actions.undo) - self.create_and_add_shortcut('z', self.actions.redo) - self.create_and_add_shortcut('F12', self.actions.show_context_menu) - - + doc_keybinds = KeybindParser.get_category_keybinds('document') + for action_name, shortcut_array in doc_keybinds.items(): + shortcut = KeybindParser.to_gtk(shortcut_array) + # Handle alternative actions (like redo_alt) + real_action_name = action_name.split('_alt')[0] + if real_action_name in self.actions.actions: + self.create_and_add_shortcut(shortcut, self.actions.actions[real_action_name].activate) + elif hasattr(self, real_action_name): + self.create_and_add_shortcut(shortcut, getattr(self, real_action_name)) diff --git a/setzer/keyboard_shortcuts/shortcut_controller_latex.py b/setzer/keyboard_shortcuts/shortcut_controller_latex.py index 0d94f95c..05c1015b 100644 --- a/setzer/keyboard_shortcuts/shortcut_controller_latex.py +++ b/setzer/keyboard_shortcuts/shortcut_controller_latex.py @@ -22,6 +22,7 @@ from setzer.app.service_locator import ServiceLocator from setzer.keyboard_shortcuts.shortcut_controller import ShortcutController from setzer.popovers.popover_manager import PopoverManager +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class ShortcutControllerLaTeX(ShortcutController): @@ -35,25 +36,33 @@ def __init__(self): self.set_propagation_phase(Gtk.PropagationPhase.CAPTURE) - self.set_accels_for_insert_before_after_action(['\\textbf{', '}'], ['b']) - self.set_accels_for_insert_before_after_action(['\\textit{', '}'], ['i']) - self.set_accels_for_insert_before_after_action(['\\underline{', '}'], ['u']) - self.set_accels_for_insert_before_after_action(['\\texttt{', '}'], ['t']) - self.set_accels_for_insert_before_after_action(['\\emph{', '}'], ['e']) - self.set_accels_for_insert_before_after_action(['$ ', ' $'], ['m']) - self.set_accels_for_insert_before_after_action(['\\[ ', ' \\]'], ['m']) - self.set_accels_for_insert_before_after_action(['\\begin{equation}\n\t', '\n\\end{equation}'], ['n']) - self.set_accels_for_insert_before_after_action(['\\begin{•}\n\t', '\n\\end{•}'], ['e']) - self.set_accels_for_insert_before_after_action(['_{', '}'], ['d']) - self.set_accels_for_insert_before_after_action(['^{', '}'], ['u']) - self.set_accels_for_insert_symbol_action(['\\frac{•}{•}'], ['f']) - self.set_accels_for_insert_symbol_action(['\\left •'], ['l']) - self.set_accels_for_insert_symbol_action(['\\right •'], ['r']) - self.set_accels_for_insert_symbol_action(['\\item •'], ['i']) - self.set_accels_for_insert_symbol_action(['\\\\\n'], ['Return']) + # Register before-after expansions + before_after_keybinds = KeybindParser.get_category_keybinds('latex-before-after') + for expansion, shortcut_array in before_after_keybinds.items(): + shortcut = KeybindParser.to_gtk(shortcut_array) + # Replace escaped newlines and tabs + expansion = expansion.replace('\\n', '\n').replace('\\t', '\t') + # Split by @@ to get before and after parts + parts = expansion.split('@@') + if len(parts) == 2: + self.set_accels_for_insert_before_after_action(parts, [shortcut]) - self.create_and_add_shortcut('k', self.actions.toggle_comment) - self.create_and_add_shortcut('quotedbl', self.shortcut_quotes) + # Register symbol expansions + symbol_keybinds = KeybindParser.get_category_keybinds('latex-symbol') + for symbol, shortcut_array in symbol_keybinds.items(): + shortcut = KeybindParser.to_gtk(shortcut_array) + # Replace escaped newlines and tabs + symbol = symbol.replace('\\n', '\n').replace('\\t', '\t') + self.set_accels_for_insert_symbol_action([symbol], [shortcut]) + + # Register standard latex shortcuts + latex_keybinds = KeybindParser.get_category_keybinds('latex') + for action_name, shortcut_array in latex_keybinds.items(): + shortcut = KeybindParser.to_gtk(shortcut_array) + if action_name in self.actions.actions: + self.create_and_add_shortcut(shortcut, self.actions.actions[action_name].activate) + elif hasattr(self, action_name): + self.create_and_add_shortcut(shortcut, getattr(self, action_name)) def set_accels_for_insert_before_after_action(self, parameter, accels): self.main_window.app.set_accels_for_action(Gio.Action.print_detailed_name('win.insert-before-after', GLib.Variant('as', parameter)), accels) @@ -63,5 +72,3 @@ def set_accels_for_insert_symbol_action(self, parameter, accels): def shortcut_quotes(self, accel_group=None, window=None, key=None, mask=None): PopoverManager.popup_at_button('quotes_menu') - - diff --git a/setzer/widgets/search_entry/search_entry.py b/setzer/widgets/search_entry/search_entry.py index 2f2503f4..79d2b8db 100644 --- a/setzer/widgets/search_entry/search_entry.py +++ b/setzer/widgets/search_entry/search_entry.py @@ -52,18 +52,10 @@ def on_keypress(self, controller, keyval, keycode, state): self.emit('next_match') return True - if (state & modifiers, keyval) == (Gdk.ModifierType.CONTROL_MASK, Gdk.keyval_from_name('g')): - self.emit('next_match') - return True - if (state & modifiers, keyval) == (0, Gdk.keyval_from_name('Up')): self.emit('previous_match') return True - if (state & modifiers, keyval) == (Gdk.ModifierType.CONTROL_MASK & Gdk.ModifierType.SHIFT_MASK, Gdk.keyval_from_name('g')): - self.emit('previous_match') - return True - if (state & modifiers, keyval) == (0, Gdk.keyval_from_name('Escape')): self.emit('stop_search') return True diff --git a/setzer/workspace/actions/actions.py b/setzer/workspace/actions/actions.py index 946a5152..0e79f910 100644 --- a/setzer/workspace/actions/actions.py +++ b/setzer/workspace/actions/actions.py @@ -73,6 +73,19 @@ def __init__(self, workspace): self.add_action('undo', self.undo) self.add_action('redo', self.redo) + self.add_action('toggle-insert', self.toggle_insert) + self.add_action('move-line-up', self.move_line_up) + self.add_action('move-line-down', self.move_line_down) + self.add_action('move-word-left', self.move_word_left) + self.add_action('move-word-right', self.move_word_right) + self.add_action('increment-number', self.increment_number) + self.add_action('decrement-number', self.decrement_number) + + self.add_action('search-next', self.find_next) + self.add_action('search-previous', self.find_previous) + self.add_action('select-next-placeholder', self.select_next_placeholder) + self.add_action('select-previous-placeholder', self.select_previous_placeholder) + self.add_action('zoom-in', self.zoom_in) self.add_action('zoom-out', self.zoom_out) self.add_action('reset-zoom', self.reset_zoom) @@ -164,6 +177,17 @@ def update_actions(self): self.actions['cut'].set_enabled(has_selection) self.actions['copy'].set_enabled(has_selection) self.actions['delete-selection'].set_enabled(has_selection) + self.actions['toggle-insert'].set_enabled(document_active) + self.actions['move-line-up'].set_enabled(document_active) + self.actions['move-line-down'].set_enabled(document_active) + self.actions['move-word-left'].set_enabled(document_active) + self.actions['move-word-right'].set_enabled(document_active) + self.actions['increment-number'].set_enabled(document_active) + self.actions['decrement-number'].set_enabled(document_active) + self.actions['search-next'].set_enabled(document_active) + self.actions['search-previous'].set_enabled(document_active) + self.actions['select-next-placeholder'].set_enabled(document_active) + self.actions['select-previous-placeholder'].set_enabled(document_active) self.actions['start-search'].set_enabled(document_active) self.actions['start-search-and-replace'].set_enabled(document_active) self.actions['find-next'].set_enabled(document_active) @@ -525,6 +549,42 @@ def redo(self, action=None, parameter=None): self.workspace.get_active_document().source_buffer.redo() + def toggle_insert(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('toggle-overwrite') + + def move_line_up(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('move-lines', False) + + def move_line_down(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('move-lines', True) + + def move_word_left(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('move-words', -1) + + def move_word_right(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('move-words', 1) + + def increment_number(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('change-number', 1) + + def decrement_number(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().source_view.emit('change-number', -1) + + def select_next_placeholder(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().select_next_placeholder() + + def select_previous_placeholder(self, action=None, parameter=None): + if self.workspace.get_active_document() == None: return + self.workspace.get_active_document().select_previous_placeholder() + def zoom_in(self, action=None, parameter=''): font_desc = Pango.FontDescription.from_string(FontManager.font_string) font_desc.set_size(min(font_desc.get_size() * 1.1, 24 * Pango.SCALE)) diff --git a/setzer/workspace/headerbar/headerbar_viewgtk.py b/setzer/workspace/headerbar/headerbar_viewgtk.py index 765503cc..3fa6a391 100644 --- a/setzer/workspace/headerbar/headerbar_viewgtk.py +++ b/setzer/workspace/headerbar/headerbar_viewgtk.py @@ -22,6 +22,7 @@ from setzer.popovers.helpers.popover_menu_builder import MenuBuilder from setzer.app.service_locator import ServiceLocator from setzer.popovers.popover_manager import PopoverManager +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class HeaderBar(Gtk.HeaderBar): @@ -33,12 +34,14 @@ def __init__(self): self.document_structure_toggle = Gtk.ToggleButton() self.document_structure_toggle.set_child(Gtk.Image.new_from_icon_name('document-structure-symbolic')) self.document_structure_toggle.set_can_focus(False) - self.document_structure_toggle.set_tooltip_text(_('Toggle document structure') + ' (F2)') + doc_structure_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_document_structure_toggle', 'app')) + self.document_structure_toggle.set_tooltip_text(_('Toggle document structure') + ' (' + doc_structure_shortcut + ')') self.symbols_toggle = Gtk.ToggleButton() self.symbols_toggle.set_child(Gtk.Image.new_from_icon_name('own-symbols-misc-text-symbolic')) self.symbols_toggle.set_can_focus(False) - self.symbols_toggle.set_tooltip_text(_('Toggle symbols') + ' (F3)') + symbols_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_symbols_toggle', 'app')) + self.symbols_toggle.set_tooltip_text(_('Toggle symbols') + ' (' + symbols_shortcut + ')') self.sidebar_toggles_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.sidebar_toggles_box.append(self.document_structure_toggle) @@ -49,7 +52,8 @@ def __init__(self): # open document buttons self.open_document_blank_button = Gtk.Button.new_with_label(_('Open') + '...') - self.open_document_blank_button.set_tooltip_text(_('Open a document') + ' (' + _('Ctrl') + '+O)') + open_doc_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('open-document-dialog', 'app')) + self.open_document_blank_button.set_tooltip_text(_('Open a document') + ' (' + open_doc_shortcut + ')') self.open_document_blank_button.set_action_name('win.open-document-dialog') self.open_document_popover = PopoverManager.create_popover('open_document') @@ -59,7 +63,8 @@ def __init__(self): self.open_document_button = PopoverManager.create_popover_button('open_document') self.open_document_button.set_child(box) self.open_document_button.set_can_focus(False) - self.open_document_button.set_tooltip_text(_('Open a document') + ' (' + _('Shift') + '+' + _('Ctrl') + '+O)') + show_recent_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_show_document_chooser', 'app')) + self.open_document_button.set_tooltip_text(_('Show recent documents') + ' (' + show_recent_shortcut + ')') # new document self.new_document_popover = PopoverManager.create_popover('new_document') @@ -82,13 +87,15 @@ def __init__(self): self.menu_button = PopoverManager.create_popover_button('hamburger_menu') self.menu_button.set_child(Gtk.Image.new_from_icon_name('open-menu-symbolic')) self.menu_button.set_can_focus(False) - self.menu_button.set_tooltip_text(_('Main Menu') + ' (F10)') + main_menu_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_show_hamburger', 'app')) + self.menu_button.set_tooltip_text(_('Main Menu') + ' (' + main_menu_shortcut + ')') self.pack_end(self.menu_button) # save document button self.save_document_button = Gtk.Button.new_with_label(_('Save')) self.save_document_button.set_can_focus(False) - self.save_document_button.set_tooltip_text(_('Save the current document') + ' (' + _('Ctrl') + '+S)') + save_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('save', 'app')) + self.save_document_button.set_tooltip_text(_('Save the current document') + ' (' + save_shortcut + ')') self.save_document_button.set_action_name('win.save') self.pack_end(self.save_document_button) @@ -97,12 +104,14 @@ def __init__(self): self.preview_toggle = Gtk.ToggleButton() self.preview_toggle.set_child(Gtk.Image.new_from_icon_name('view-paged-symbolic')) self.preview_toggle.set_can_focus(False) - self.preview_toggle.set_tooltip_text(_('Toggle preview') + ' (F9)') + preview_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_preview', 'app')) + self.preview_toggle.set_tooltip_text(_('Toggle preview') + ' (' + preview_shortcut + ')') box.append(self.preview_toggle) self.help_toggle = Gtk.ToggleButton() self.help_toggle.set_child(Gtk.Image.new_from_icon_name('help-browser-symbolic')) self.help_toggle.set_can_focus(False) - self.help_toggle.set_tooltip_text(_('Toggle help') + ' (F1)') + help_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_help', 'app')) + self.help_toggle.set_tooltip_text(_('Toggle help') + ' (' + help_shortcut + ')') box.append(self.help_toggle) box.get_style_context().add_class('linked') self.pack_end(box) @@ -133,7 +142,8 @@ def __init__(self): self.center_button = PopoverManager.create_popover_button('document_switcher') self.center_button.get_style_context().add_class('flat') self.center_button.get_style_context().add_class('open-docs-popover-button') - self.center_button.set_tooltip_text(_('Show open documents') + ' (' + _('Ctrl') + '+T)') + show_open_docs_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_show_open_docs', 'app')) + self.center_button.set_tooltip_text(_('Show open documents') + ' (' + show_open_docs_shortcut + ')') self.center_button.set_can_focus(False) self.center_button.set_child(hbox) self.center_button.set_valign(Gtk.Align.FILL) diff --git a/setzer/workspace/shortcutsbar/shortcutsbar_viewgtk.py b/setzer/workspace/shortcutsbar/shortcutsbar_viewgtk.py index 43e48b15..6d7f179b 100644 --- a/setzer/workspace/shortcutsbar/shortcutsbar_viewgtk.py +++ b/setzer/workspace/shortcutsbar/shortcutsbar_viewgtk.py @@ -24,6 +24,7 @@ from setzer.popovers.helpers.popover_menu_builder import MenuBuilder from setzer.app.service_locator import ServiceLocator from setzer.popovers.popover_manager import PopoverManager +from setzer.keyboard_shortcuts.keybind_parser import KeybindParser class Shortcutsbar(Gtk.Box): @@ -50,7 +51,8 @@ def __init__(self): self.italic_button.set_action_target_value(GLib.Variant('as', ['\\textit{', '}'])) self.italic_button.get_style_context().add_class('flat') self.italic_button.get_style_context().add_class('scbar') - self.italic_button.set_tooltip_text(_('Italic') + ' (' + _('Ctrl') + '+I)') + italic_shortcut = KeybindParser.to_display(['Ctrl', 'i']) + self.italic_button.set_tooltip_text(_('Italic') + ' (' + italic_shortcut + ')') self.top_icons.prepend(self.italic_button) self.bold_button = Gtk.Button() @@ -59,7 +61,8 @@ def __init__(self): self.bold_button.set_action_target_value(GLib.Variant('as', ['\\textbf{', '}'])) self.bold_button.get_style_context().add_class('flat') self.bold_button.get_style_context().add_class('scbar') - self.bold_button.set_tooltip_text(_('Bold') + ' (' + _('Ctrl') + '+B)') + bold_shortcut = KeybindParser.to_display(['Ctrl', 'b']) + self.bold_button.set_tooltip_text(_('Bold') + ' (' + bold_shortcut + ')') self.top_icons.prepend(self.bold_button) self.insert_quotes_button() @@ -76,14 +79,16 @@ def __init__(self): self.button_search = Gtk.ToggleButton() self.button_search.set_icon_name('edit-find-symbolic') - self.button_search.set_tooltip_text(_('Find') + ' (' + _('Ctrl') + '+F)') + search_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('start-search', 'app')) + self.button_search.set_tooltip_text(_('Find') + ' (' + search_shortcut + ')') self.button_search.get_style_context().add_class('flat') self.button_search.get_style_context().add_class('scbar') self.right_icons.append(self.button_search) self.button_replace = Gtk.ToggleButton() self.button_replace.set_icon_name('edit-find-replace-symbolic') - self.button_replace.set_tooltip_text(_('Find and Replace') + ' (' + _('Ctrl') + '+H)') + replace_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('start-search-and-replace', 'app')) + self.button_replace.set_tooltip_text(_('Find and Replace') + ' (' + replace_shortcut + ')') self.button_replace.get_style_context().add_class('flat') self.button_replace.get_style_context().add_class('scbar') self.right_icons.append(self.button_replace) @@ -92,12 +97,14 @@ def __init__(self): self.button_more.set_icon_name('view-more-symbolic') self.button_more.get_style_context().add_class('flat') self.button_more.get_style_context().add_class('scbar') - self.button_more.set_tooltip_text(_('Context Menu') + ' (F12)') + context_menu_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('show-context-menu', 'document')) + self.button_more.set_tooltip_text(_('Context Menu') + ' (' + context_menu_shortcut + ')') self.right_icons.append(self.button_more) self.button_build_log = Gtk.ToggleButton() self.button_build_log.set_icon_name('build-log-symbolic') - self.button_build_log.set_tooltip_text(_('Build log') + ' (F8)') + build_log_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_build_log', 'app')) + self.button_build_log.set_tooltip_text(_('Build log') + ' (' + build_log_shortcut + ')') self.button_build_log.get_style_context().add_class('flat') self.button_build_log.get_style_context().add_class('scbar') self.right_icons.append(self.button_build_log) @@ -180,7 +187,8 @@ def insert_quotes_button(self): self.quotes_button = PopoverManager.create_popover_button('quotes_menu') self.quotes_button.set_icon_name('own-quotes-symbolic') - self.quotes_button.set_tooltip_text(_('Quotes') + ' (' + _('Ctrl') + '+")') + quotes_shortcut = KeybindParser.to_display(KeybindParser.get_shortcut('shortcut_quotes', 'latex')) + self.quotes_button.set_tooltip_text(_('Quotes') + ' (' + quotes_shortcut + ')') self.quotes_button.get_style_context().add_class('flat') self.quotes_button.get_style_context().add_class('scbar')