hydrus/hydrus/client/gui/ClientGUIShortcuts.py

1435 lines
55 KiB
Python
Raw Normal View History

2020-04-22 21:00:35 +00:00
import typing
2019-11-14 03:56:30 +00:00
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from qtpy import QtGui as QG
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusSerialisable
2020-07-29 20:52:44 +00:00
from hydrus.client import ClientApplicationCommand as CAC
2020-04-22 21:00:35 +00:00
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientData
from hydrus.client.gui import ClientGUICore as CGC
from hydrus.client.gui import ClientGUIFunctions
2019-12-11 23:18:37 +00:00
2020-02-19 21:48:36 +00:00
SHORTCUT_TYPE_KEYBOARD_CHARACTER = 0
SHORTCUT_TYPE_MOUSE = 1
SHORTCUT_TYPE_KEYBOARD_SPECIAL = 2
SHORTCUT_TYPE_NOT_ALLOWED = 3
SHORTCUT_PRESS_TYPE_PRESS = 0
SHORTCUT_PRESS_TYPE_RELEASE = 1
SHORTCUT_PRESS_TYPE_DOUBLE_CLICK = 2
SHORTCUT_PRESS_TYPE_DRAG = 3
shortcut_press_type_str_lookup = {}
shortcut_press_type_str_lookup[ SHORTCUT_PRESS_TYPE_PRESS ] = 'press'
shortcut_press_type_str_lookup[ SHORTCUT_PRESS_TYPE_RELEASE ] = 'release'
shortcut_press_type_str_lookup[ SHORTCUT_PRESS_TYPE_DOUBLE_CLICK ] = 'double'
shortcut_press_type_str_lookup[ SHORTCUT_PRESS_TYPE_DRAG ] = 'drag'
SHORTCUT_MODIFIER_CTRL = 0
SHORTCUT_MODIFIER_ALT = 1
SHORTCUT_MODIFIER_SHIFT = 2
SHORTCUT_MODIFIER_KEYPAD = 3
SHORTCUT_MODIFIER_GROUP_SWITCH = 4
2020-11-11 22:20:16 +00:00
SHORTCUT_MODIFIER_META = 5 # This is 'Control' in macOS, which is for system level stuff. They use 'Command' for Control stuff, which is helpfully mapped to Control in Qt. Just name nonsense
2020-02-19 21:48:36 +00:00
SHORTCUT_KEY_SPECIAL_SPACE = 0
SHORTCUT_KEY_SPECIAL_BACKSPACE = 1
SHORTCUT_KEY_SPECIAL_TAB = 2
SHORTCUT_KEY_SPECIAL_RETURN = 3
SHORTCUT_KEY_SPECIAL_ENTER = 4
SHORTCUT_KEY_SPECIAL_PAUSE = 5
SHORTCUT_KEY_SPECIAL_ESCAPE = 6
SHORTCUT_KEY_SPECIAL_INSERT = 7
SHORTCUT_KEY_SPECIAL_DELETE = 8
SHORTCUT_KEY_SPECIAL_UP = 9
SHORTCUT_KEY_SPECIAL_DOWN = 10
SHORTCUT_KEY_SPECIAL_LEFT = 11
SHORTCUT_KEY_SPECIAL_RIGHT = 12
SHORTCUT_KEY_SPECIAL_HOME = 13
SHORTCUT_KEY_SPECIAL_END = 14
SHORTCUT_KEY_SPECIAL_PAGE_UP = 15
SHORTCUT_KEY_SPECIAL_PAGE_DOWN = 16
SHORTCUT_KEY_SPECIAL_F1 = 17
SHORTCUT_KEY_SPECIAL_F2 = 18
SHORTCUT_KEY_SPECIAL_F3 = 19
SHORTCUT_KEY_SPECIAL_F4 = 20
SHORTCUT_KEY_SPECIAL_F5 = 21
SHORTCUT_KEY_SPECIAL_F6 = 22
SHORTCUT_KEY_SPECIAL_F7 = 23
SHORTCUT_KEY_SPECIAL_F8 = 24
SHORTCUT_KEY_SPECIAL_F9 = 25
SHORTCUT_KEY_SPECIAL_F10 = 26
SHORTCUT_KEY_SPECIAL_F11 = 27
SHORTCUT_KEY_SPECIAL_F12 = 28
if HC.PLATFORM_MACOS:
2020-05-27 21:27:52 +00:00
DELETE_KEYS_QT = ( QC.Qt.Key_Backspace, QC.Qt.Key_Delete )
DELETE_KEYS_HYDRUS = ( SHORTCUT_KEY_SPECIAL_BACKSPACE, SHORTCUT_KEY_SPECIAL_DELETE )
2020-02-19 21:48:36 +00:00
else:
2020-05-27 21:27:52 +00:00
DELETE_KEYS_QT = ( QC.Qt.Key_Delete, )
DELETE_KEYS_HYDRUS = ( SHORTCUT_KEY_SPECIAL_DELETE, )
2020-02-19 21:48:36 +00:00
special_key_shortcut_enum_lookup = {}
special_key_shortcut_enum_lookup[ QC.Qt.Key_Space ] = SHORTCUT_KEY_SPECIAL_SPACE
special_key_shortcut_enum_lookup[ QC.Qt.Key_Backspace ] = SHORTCUT_KEY_SPECIAL_BACKSPACE
special_key_shortcut_enum_lookup[ QC.Qt.Key_Tab ] = SHORTCUT_KEY_SPECIAL_TAB
special_key_shortcut_enum_lookup[ QC.Qt.Key_Return ] = SHORTCUT_KEY_SPECIAL_RETURN
special_key_shortcut_enum_lookup[ QC.Qt.Key_Enter ] = SHORTCUT_KEY_SPECIAL_ENTER
special_key_shortcut_enum_lookup[ QC.Qt.Key_Pause ] = SHORTCUT_KEY_SPECIAL_PAUSE
special_key_shortcut_enum_lookup[ QC.Qt.Key_Escape ] = SHORTCUT_KEY_SPECIAL_ESCAPE
special_key_shortcut_enum_lookup[ QC.Qt.Key_Insert ] = SHORTCUT_KEY_SPECIAL_INSERT
special_key_shortcut_enum_lookup[ QC.Qt.Key_Delete ] = SHORTCUT_KEY_SPECIAL_DELETE
special_key_shortcut_enum_lookup[ QC.Qt.Key_Up ] = SHORTCUT_KEY_SPECIAL_UP
special_key_shortcut_enum_lookup[ QC.Qt.Key_Down ] = SHORTCUT_KEY_SPECIAL_DOWN
special_key_shortcut_enum_lookup[ QC.Qt.Key_Left ] = SHORTCUT_KEY_SPECIAL_LEFT
special_key_shortcut_enum_lookup[ QC.Qt.Key_Right ] = SHORTCUT_KEY_SPECIAL_RIGHT
special_key_shortcut_enum_lookup[ QC.Qt.Key_Home ] = SHORTCUT_KEY_SPECIAL_HOME
special_key_shortcut_enum_lookup[ QC.Qt.Key_End ] = SHORTCUT_KEY_SPECIAL_END
special_key_shortcut_enum_lookup[ QC.Qt.Key_PageUp ] = SHORTCUT_KEY_SPECIAL_PAGE_UP
special_key_shortcut_enum_lookup[ QC.Qt.Key_PageDown ] = SHORTCUT_KEY_SPECIAL_PAGE_DOWN
special_key_shortcut_enum_lookup[ QC.Qt.Key_F1 ] = SHORTCUT_KEY_SPECIAL_F1
special_key_shortcut_enum_lookup[ QC.Qt.Key_F2 ] = SHORTCUT_KEY_SPECIAL_F2
special_key_shortcut_enum_lookup[ QC.Qt.Key_F3 ] = SHORTCUT_KEY_SPECIAL_F3
special_key_shortcut_enum_lookup[ QC.Qt.Key_F4 ] = SHORTCUT_KEY_SPECIAL_F4
special_key_shortcut_enum_lookup[ QC.Qt.Key_F5 ] = SHORTCUT_KEY_SPECIAL_F5
special_key_shortcut_enum_lookup[ QC.Qt.Key_F6 ] = SHORTCUT_KEY_SPECIAL_F6
special_key_shortcut_enum_lookup[ QC.Qt.Key_F7 ] = SHORTCUT_KEY_SPECIAL_F7
special_key_shortcut_enum_lookup[ QC.Qt.Key_F8 ] = SHORTCUT_KEY_SPECIAL_F8
special_key_shortcut_enum_lookup[ QC.Qt.Key_F9 ] = SHORTCUT_KEY_SPECIAL_F9
special_key_shortcut_enum_lookup[ QC.Qt.Key_F10 ] = SHORTCUT_KEY_SPECIAL_F10
special_key_shortcut_enum_lookup[ QC.Qt.Key_F11 ] = SHORTCUT_KEY_SPECIAL_F11
special_key_shortcut_enum_lookup[ QC.Qt.Key_F12 ] = SHORTCUT_KEY_SPECIAL_F12
special_key_shortcut_str_lookup = {}
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_SPACE ] = 'space'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_BACKSPACE ] = 'backspace'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_TAB ] = 'tab'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_RETURN ] = 'return'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_ENTER ] = 'enter'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_PAUSE ] = 'pause'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_ESCAPE ] = 'escape'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_INSERT ] = 'insert'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_DELETE ] = 'delete'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_UP ] = 'up'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_DOWN ] = 'down'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_LEFT ] = 'left'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_RIGHT ] = 'right'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_HOME ] = 'home'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_END ] = 'end'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_PAGE_DOWN ] = 'page down'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_PAGE_UP ] = 'page up'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F1 ] = 'f1'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F2 ] = 'f2'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F3 ] = 'f3'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F4 ] = 'f4'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F5 ] = 'f5'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F6 ] = 'f6'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F7 ] = 'f7'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F8 ] = 'f8'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F9 ] = 'f9'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F10 ] = 'f10'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F11 ] = 'f11'
special_key_shortcut_str_lookup[ SHORTCUT_KEY_SPECIAL_F12 ] = 'f12'
SHORTCUT_MOUSE_LEFT = 0
SHORTCUT_MOUSE_RIGHT = 1
SHORTCUT_MOUSE_MIDDLE = 2
SHORTCUT_MOUSE_SCROLL_UP = 3
SHORTCUT_MOUSE_SCROLL_DOWN = 4
SHORTCUT_MOUSE_SCROLL_LEFT = 5
SHORTCUT_MOUSE_SCROLL_RIGHT = 6
2020-04-29 21:44:12 +00:00
SHORTCUT_MOUSE_BACK = 7
SHORTCUT_MOUSE_FORWARD = 8
SHORTCUT_MOUSE_CLICKS = { SHORTCUT_MOUSE_LEFT, SHORTCUT_MOUSE_MIDDLE, SHORTCUT_MOUSE_RIGHT, SHORTCUT_MOUSE_BACK, SHORTCUT_MOUSE_FORWARD }
qt_mouse_buttons_to_hydrus_mouse_buttons = {}
qt_mouse_buttons_to_hydrus_mouse_buttons[ QC.Qt.LeftButton ] = SHORTCUT_MOUSE_LEFT
qt_mouse_buttons_to_hydrus_mouse_buttons[ QC.Qt.MiddleButton ] = SHORTCUT_MOUSE_MIDDLE
qt_mouse_buttons_to_hydrus_mouse_buttons[ QC.Qt.RightButton ] = SHORTCUT_MOUSE_RIGHT
qt_mouse_buttons_to_hydrus_mouse_buttons[ QC.Qt.BackButton ] = SHORTCUT_MOUSE_BACK
qt_mouse_buttons_to_hydrus_mouse_buttons[ QC.Qt.ForwardButton ] = SHORTCUT_MOUSE_FORWARD
2020-02-19 21:48:36 +00:00
shortcut_mouse_string_lookup = {}
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_LEFT ] = 'left-click'
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_RIGHT ] = 'right-click'
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_MIDDLE ] = 'middle-click'
2020-04-29 21:44:12 +00:00
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_BACK ] = 'back'
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_FORWARD ] = 'forward'
2020-02-19 21:48:36 +00:00
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_SCROLL_UP ] = 'scroll up'
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_SCROLL_DOWN ] = 'scroll down'
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_SCROLL_LEFT ] = 'scroll left'
shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_SCROLL_RIGHT ] = 'scroll right'
2020-05-06 21:31:41 +00:00
shortcut_names_to_pretty_names = {}
shortcut_names_to_pretty_names[ 'global' ] = 'global'
shortcut_names_to_pretty_names[ 'main_gui' ] = 'the main window'
2021-01-27 22:14:03 +00:00
shortcut_names_to_pretty_names[ 'tags_autocomplete' ] = 'tag autocomplete'
2020-05-06 21:31:41 +00:00
shortcut_names_to_pretty_names[ 'media' ] = 'media actions, either thumbnails or the viewer'
shortcut_names_to_pretty_names[ 'media_viewer' ] = 'media viewers - all (zoom and pan)'
shortcut_names_to_pretty_names[ 'media_viewer_browser' ] = 'media viewer - \'normal\' browser'
shortcut_names_to_pretty_names[ 'archive_delete_filter' ] = 'media viewer - archive/delete filter'
shortcut_names_to_pretty_names[ 'duplicate_filter' ] = 'media viewer - duplicate filter'
shortcut_names_to_pretty_names[ 'preview_media_window' ] = 'media viewer - the preview window'
shortcut_names_to_pretty_names[ 'media_viewer_media_window' ] = 'the actual media in a media viewer'
2021-01-27 22:14:03 +00:00
shortcut_names_sorted = [
'global',
'main_gui',
'tags_autocomplete',
'media',
'media_viewer',
'media_viewer_browser',
'archive_delete_filter',
'duplicate_filter',
'preview_media_window',
'media_viewer_media_window'
]
2020-05-06 21:31:41 +00:00
2020-02-19 21:48:36 +00:00
shortcut_names_to_descriptions = {}
shortcut_names_to_descriptions[ 'global' ] = 'Actions for the whole program. Should work in the main gui or a media viewer.'
shortcut_names_to_descriptions[ 'archive_delete_filter' ] = 'Navigation actions for the media viewer during an archive/delete filter. Mouse shortcuts should work.'
shortcut_names_to_descriptions[ 'duplicate_filter' ] = 'Navigation actions for the media viewer during a duplicate filter. Mouse shortcuts should work.'
shortcut_names_to_descriptions[ 'media' ] = 'Actions to alter metadata for media in the media viewer or the thumbnail grid.'
shortcut_names_to_descriptions[ 'main_gui' ] = 'Actions to control pages in the main window of the program.'
2021-01-27 22:14:03 +00:00
shortcut_names_to_descriptions[ 'tags_autocomplete' ] = 'Actions to control tag autocomplete when its input text box is focused.'
2020-02-19 21:48:36 +00:00
shortcut_names_to_descriptions[ 'media_viewer_browser' ] = 'Navigation actions for the regular browsable media viewer.'
shortcut_names_to_descriptions[ 'media_viewer' ] = 'Zoom and pan and player actions for any media viewer.'
shortcut_names_to_descriptions[ 'media_viewer_media_window' ] = 'Actions for any video or audio player in a media viewer window.'
shortcut_names_to_descriptions[ 'preview_media_window' ] = 'Actions for any video or audio player in a preview window.'
# shortcut commands
2021-01-27 22:14:03 +00:00
SHORTCUTS_RESERVED_NAMES = [ 'global', 'archive_delete_filter', 'duplicate_filter', 'media', 'tags_autocomplete', 'main_gui', 'media_viewer_browser', 'media_viewer', 'media_viewer_media_window', 'preview_media_window' ]
2020-02-19 21:48:36 +00:00
SHORTCUTS_GLOBAL_ACTIONS = [ CAC.SIMPLE_GLOBAL_AUDIO_MUTE, CAC.SIMPLE_GLOBAL_AUDIO_UNMUTE, CAC.SIMPLE_GLOBAL_AUDIO_MUTE_FLIP, CAC.SIMPLE_EXIT_APPLICATION, CAC.SIMPLE_EXIT_APPLICATION_FORCE_MAINTENANCE, CAC.SIMPLE_RESTART_APPLICATION, CAC.SIMPLE_HIDE_TO_SYSTEM_TRAY ]
SHORTCUTS_MEDIA_ACTIONS = [ CAC.SIMPLE_MANAGE_FILE_TAGS, CAC.SIMPLE_MANAGE_FILE_RATINGS, CAC.SIMPLE_MANAGE_FILE_URLS, CAC.SIMPLE_MANAGE_FILE_NOTES, CAC.SIMPLE_ARCHIVE_FILE, CAC.SIMPLE_INBOX_FILE, CAC.SIMPLE_DELETE_FILE, CAC.SIMPLE_UNDELETE_FILE, CAC.SIMPLE_EXPORT_FILES, CAC.SIMPLE_EXPORT_FILES_QUICK_AUTO_EXPORT, CAC.SIMPLE_REMOVE_FILE_FROM_VIEW, CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM, CAC.SIMPLE_OPEN_SELECTION_IN_NEW_PAGE, CAC.SIMPLE_LAUNCH_THE_ARCHIVE_DELETE_FILTER, CAC.SIMPLE_COPY_BMP, CAC.SIMPLE_COPY_BMP_OR_FILE_IF_NOT_BMPABLE, CAC.SIMPLE_COPY_FILE, CAC.SIMPLE_COPY_PATH, CAC.SIMPLE_COPY_SHA256_HASH, CAC.SIMPLE_COPY_MD5_HASH, CAC.SIMPLE_COPY_SHA1_HASH, CAC.SIMPLE_COPY_SHA512_HASH, CAC.SIMPLE_GET_SIMILAR_TO_EXACT, CAC.SIMPLE_GET_SIMILAR_TO_VERY_SIMILAR, CAC.SIMPLE_GET_SIMILAR_TO_SIMILAR, CAC.SIMPLE_GET_SIMILAR_TO_SPECULATIVE, CAC.SIMPLE_DUPLICATE_MEDIA_SET_ALTERNATE, CAC.SIMPLE_DUPLICATE_MEDIA_SET_ALTERNATE_COLLECTIONS, CAC.SIMPLE_DUPLICATE_MEDIA_SET_CUSTOM, CAC.SIMPLE_DUPLICATE_MEDIA_SET_FOCUSED_BETTER, CAC.SIMPLE_DUPLICATE_MEDIA_SET_FOCUSED_KING, CAC.SIMPLE_DUPLICATE_MEDIA_SET_SAME_QUALITY, CAC.SIMPLE_OPEN_KNOWN_URL ]
SHORTCUTS_MEDIA_VIEWER_ACTIONS = [ CAC.SIMPLE_PAUSE_MEDIA, CAC.SIMPLE_PAUSE_PLAY_MEDIA, CAC.SIMPLE_MOVE_ANIMATION_TO_PREVIOUS_FRAME, CAC.SIMPLE_MOVE_ANIMATION_TO_NEXT_FRAME, CAC.SIMPLE_SWITCH_BETWEEN_FULLSCREEN_BORDERLESS_AND_REGULAR_FRAMED_WINDOW, CAC.SIMPLE_PAN_UP, CAC.SIMPLE_PAN_DOWN, CAC.SIMPLE_PAN_LEFT, CAC.SIMPLE_PAN_RIGHT, CAC.SIMPLE_PAN_TOP_EDGE, CAC.SIMPLE_PAN_BOTTOM_EDGE, CAC.SIMPLE_PAN_LEFT_EDGE, CAC.SIMPLE_PAN_RIGHT_EDGE, CAC.SIMPLE_PAN_VERTICAL_CENTER, CAC.SIMPLE_PAN_HORIZONTAL_CENTER, CAC.SIMPLE_ZOOM_IN, CAC.SIMPLE_ZOOM_OUT, CAC.SIMPLE_SWITCH_BETWEEN_100_PERCENT_AND_CANVAS_ZOOM, CAC.SIMPLE_FLIP_DARKMODE, CAC.SIMPLE_CLOSE_MEDIA_VIEWER ]
SHORTCUTS_MEDIA_VIEWER_BROWSER_ACTIONS = [ CAC.SIMPLE_VIEW_NEXT, CAC.SIMPLE_VIEW_FIRST, CAC.SIMPLE_VIEW_LAST, CAC.SIMPLE_VIEW_PREVIOUS, CAC.SIMPLE_PAUSE_PLAY_SLIDESHOW, CAC.SIMPLE_SHOW_MENU, CAC.SIMPLE_CLOSE_MEDIA_VIEWER ]
2021-01-27 22:14:03 +00:00
SHORTCUTS_MAIN_GUI_ACTIONS = [ CAC.SIMPLE_REFRESH, CAC.SIMPLE_REFRESH_ALL_PAGES, CAC.SIMPLE_REFRESH_PAGE_OF_PAGES_PAGES, CAC.SIMPLE_NEW_PAGE, CAC.SIMPLE_NEW_PAGE_OF_PAGES, CAC.SIMPLE_NEW_DUPLICATE_FILTER_PAGE, CAC.SIMPLE_NEW_GALLERY_DOWNLOADER_PAGE, CAC.SIMPLE_NEW_URL_DOWNLOADER_PAGE, CAC.SIMPLE_NEW_SIMPLE_DOWNLOADER_PAGE, CAC.SIMPLE_NEW_WATCHER_DOWNLOADER_PAGE, CAC.SIMPLE_SET_MEDIA_FOCUS, CAC.SIMPLE_SHOW_HIDE_SPLITTERS, CAC.SIMPLE_SET_SEARCH_FOCUS, CAC.SIMPLE_UNCLOSE_PAGE, CAC.SIMPLE_CLOSE_PAGE, CAC.SIMPLE_REDO, CAC.SIMPLE_UNDO, CAC.SIMPLE_FLIP_DARKMODE, CAC.SIMPLE_RUN_ALL_EXPORT_FOLDERS, CAC.SIMPLE_CHECK_ALL_IMPORT_FOLDERS, CAC.SIMPLE_FLIP_DEBUG_FORCE_IDLE_MODE_DO_NOT_SET_THIS, CAC.SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_FAVOURITE_TAGS, CAC.SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_RELATED_TAGS, CAC.SIMPLE_REFRESH_RELATED_TAGS, CAC.SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_FILE_LOOKUP_SCRIPT_TAGS, CAC.SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_RECENT_TAGS, CAC.SIMPLE_FOCUS_MEDIA_VIEWER, CAC.SIMPLE_MOVE_PAGES_SELECTION_LEFT, CAC.SIMPLE_MOVE_PAGES_SELECTION_RIGHT, CAC.SIMPLE_MOVE_PAGES_SELECTION_HOME, CAC.SIMPLE_MOVE_PAGES_SELECTION_END ]
SHORTCUTS_TAGS_AUTOCOMPLETE_ACTIONS = [ CAC.SIMPLE_SYNCHRONISED_WAIT_SWITCH, CAC.SIMPLE_AUTOCOMPLETE_FORCE_FETCH, CAC.SIMPLE_AUTOCOMPLETE_IME_MODE ]
SHORTCUTS_DUPLICATE_FILTER_ACTIONS = [ CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER, CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_BUT_KEEP_BOTH, CAC.SIMPLE_DUPLICATE_FILTER_EXACTLY_THE_SAME, CAC.SIMPLE_DUPLICATE_FILTER_ALTERNATES, CAC.SIMPLE_DUPLICATE_FILTER_FALSE_POSITIVE, CAC.SIMPLE_DUPLICATE_FILTER_CUSTOM_ACTION, CAC.SIMPLE_DUPLICATE_FILTER_SKIP, CAC.SIMPLE_DUPLICATE_FILTER_BACK, CAC.SIMPLE_CLOSE_MEDIA_VIEWER ]
SHORTCUTS_ARCHIVE_DELETE_FILTER_ACTIONS = [ CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP, CAC.SIMPLE_ARCHIVE_DELETE_FILTER_DELETE, CAC.SIMPLE_ARCHIVE_DELETE_FILTER_SKIP, CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK, CAC.SIMPLE_CLOSE_MEDIA_VIEWER ]
SHORTCUTS_MEDIA_VIEWER_VIDEO_AUDIO_PLAYER_ACTIONS = [ CAC.SIMPLE_PAUSE_MEDIA, CAC.SIMPLE_PAUSE_PLAY_MEDIA, CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM, CAC.SIMPLE_CLOSE_MEDIA_VIEWER ]
SHORTCUTS_PREVIEW_VIDEO_AUDIO_PLAYER_ACTIONS = [ CAC.SIMPLE_PAUSE_MEDIA, CAC.SIMPLE_PAUSE_PLAY_MEDIA, CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM, CAC.SIMPLE_LAUNCH_MEDIA_VIEWER ]
2020-02-19 21:48:36 +00:00
simple_shortcut_name_to_action_lookup = {}
simple_shortcut_name_to_action_lookup[ 'global' ] = SHORTCUTS_GLOBAL_ACTIONS
simple_shortcut_name_to_action_lookup[ 'media' ] = SHORTCUTS_MEDIA_ACTIONS
simple_shortcut_name_to_action_lookup[ 'media_viewer' ] = SHORTCUTS_MEDIA_VIEWER_ACTIONS
simple_shortcut_name_to_action_lookup[ 'media_viewer_browser' ] = SHORTCUTS_MEDIA_VIEWER_BROWSER_ACTIONS
simple_shortcut_name_to_action_lookup[ 'main_gui' ] = SHORTCUTS_MAIN_GUI_ACTIONS
2021-01-27 22:14:03 +00:00
simple_shortcut_name_to_action_lookup[ 'tags_autocomplete' ] = SHORTCUTS_TAGS_AUTOCOMPLETE_ACTIONS
2020-02-19 21:48:36 +00:00
simple_shortcut_name_to_action_lookup[ 'duplicate_filter' ] = SHORTCUTS_DUPLICATE_FILTER_ACTIONS + SHORTCUTS_MEDIA_ACTIONS + SHORTCUTS_MEDIA_VIEWER_ACTIONS
simple_shortcut_name_to_action_lookup[ 'archive_delete_filter' ] = SHORTCUTS_ARCHIVE_DELETE_FILTER_ACTIONS
simple_shortcut_name_to_action_lookup[ 'media_viewer_media_window' ] = SHORTCUTS_MEDIA_VIEWER_VIDEO_AUDIO_PLAYER_ACTIONS
simple_shortcut_name_to_action_lookup[ 'preview_media_window' ] = SHORTCUTS_PREVIEW_VIDEO_AUDIO_PLAYER_ACTIONS
simple_shortcut_name_to_action_lookup[ 'custom' ] = SHORTCUTS_MEDIA_ACTIONS + SHORTCUTS_MEDIA_VIEWER_ACTIONS
2019-12-11 23:18:37 +00:00
# ok, the problem here is that I get key codes that are converted, so if someone does shift+1 on a US keyboard, this ends up with Shift+! same with ctrl+alt+ to get accented characters
# it isn't really a big deal since everything still lines up, but the QGuiApplicationPrivate::platformIntegration()->possibleKeys(e) to get some variant of 'yeah this is just !' seems unavailable for python
# it is basically a display bug, but it'd be nice to have it working right
def ConvertQtKeyToShortcutKey( key_qt ):
2017-05-31 21:50:53 +00:00
2020-02-19 21:48:36 +00:00
if key_qt in special_key_shortcut_enum_lookup:
2019-11-14 03:56:30 +00:00
2020-02-19 21:48:36 +00:00
key_ord = special_key_shortcut_enum_lookup[ key_qt ]
2019-12-11 23:18:37 +00:00
2020-02-19 21:48:36 +00:00
return ( SHORTCUT_TYPE_KEYBOARD_SPECIAL, key_ord )
2019-12-11 23:18:37 +00:00
else:
try:
2019-11-14 03:56:30 +00:00
2019-12-11 23:18:37 +00:00
key_ord = int( key_qt )
2019-11-14 03:56:30 +00:00
2019-12-11 23:18:37 +00:00
key_chr = chr( key_ord )
2019-11-14 03:56:30 +00:00
2019-12-11 23:18:37 +00:00
# this is turbo lower() that converts Scharfes S (beta) to 'ss'
key_chr = key_chr.casefold()[0]
2019-11-14 03:56:30 +00:00
2019-12-11 23:18:37 +00:00
casefold_key_ord = ord( key_chr )
2020-02-19 21:48:36 +00:00
return ( SHORTCUT_TYPE_KEYBOARD_CHARACTER, casefold_key_ord )
2019-12-11 23:18:37 +00:00
except:
2020-02-19 21:48:36 +00:00
return ( SHORTCUT_TYPE_NOT_ALLOWED, key_ord )
2019-12-11 23:18:37 +00:00
def ConvertKeyEventToShortcut( event ):
key_qt = event.key()
( shortcut_type, key_ord ) = ConvertQtKeyToShortcutKey( key_qt )
2020-02-19 21:48:36 +00:00
if shortcut_type != SHORTCUT_TYPE_NOT_ALLOWED:
2018-05-16 20:09:50 +00:00
modifiers = []
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.AltModifier:
2018-05-16 20:09:50 +00:00
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_ALT )
2018-05-16 20:09:50 +00:00
2020-11-11 22:20:16 +00:00
if event.modifiers() & QC.Qt.ControlModifier:
2019-11-14 03:56:30 +00:00
2020-11-11 22:20:16 +00:00
modifiers.append( SHORTCUT_MODIFIER_CTRL )
2019-11-14 03:56:30 +00:00
2020-11-11 22:20:16 +00:00
if event.modifiers() & QC.Qt.MetaModifier:
2018-05-16 20:09:50 +00:00
2020-11-11 22:20:16 +00:00
modifiers.append( SHORTCUT_MODIFIER_META )
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.ShiftModifier:
2018-05-16 20:09:50 +00:00
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_SHIFT )
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.GroupSwitchModifier:
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_GROUP_SWITCH )
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.KeypadModifier:
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_KEYPAD )
2019-11-14 03:56:30 +00:00
2020-02-19 21:48:36 +00:00
shortcut_press_type = SHORTCUT_PRESS_TYPE_PRESS
2020-02-12 22:50:37 +00:00
shortcut = Shortcut( shortcut_type, key_ord, shortcut_press_type, modifiers )
2018-05-16 20:09:50 +00:00
if HG.gui_report_mode:
HydrusData.ShowText( 'key event caught: ' + repr( shortcut ) )
return shortcut
return None
def ConvertKeyEventToSimpleTuple( event ):
2019-11-14 03:56:30 +00:00
modifier = QC.Qt.NoModifier
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.AltModifier: modifier = QC.Qt.AltModifier
elif event.modifiers() & QC.Qt.ControlModifier: modifier = QC.Qt.ControlModifier
elif event.modifiers() & QC.Qt.ShiftModifier: modifier = QC.Qt.ShiftModifier
elif event.modifiers() & QC.Qt.KeypadModifier: modifier = QC.Qt.KeypadModifier
elif event.modifiers() & QC.Qt.GroupSwitchModifier: modifier = QC.Qt.GroupSwitchModifier
2020-11-11 22:20:16 +00:00
elif event.modifiers() & QC.Qt.MetaModifier: modifier = QC.Qt.MetaModifier
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
key = event.key()
2018-05-16 20:09:50 +00:00
return ( modifier, key )
2020-11-11 22:20:16 +00:00
GLOBAL_MOUSE_SCROLL_DELTA_FOR_TRACKPADS = 0
ONE_TICK_ON_A_NORMAL_MOUSE_IN_DEGREES = 15 * 8 # fifteen degrees, in eighths of a degree
2020-04-29 21:44:12 +00:00
def ConvertMouseEventToShortcut( event: QG.QMouseEvent ):
2018-05-16 20:09:50 +00:00
key = None
2020-02-19 21:48:36 +00:00
shortcut_press_type = SHORTCUT_PRESS_TYPE_PRESS
2020-02-12 22:50:37 +00:00
if event.type() == QC.QEvent.MouseButtonPress:
2018-05-16 20:09:50 +00:00
2020-04-29 21:44:12 +00:00
for ( qt_button, hydrus_button ) in qt_mouse_buttons_to_hydrus_mouse_buttons.items():
2020-02-12 22:50:37 +00:00
2020-04-29 21:44:12 +00:00
if event.buttons() & qt_button:
key = hydrus_button
break
2020-02-12 22:50:37 +00:00
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
elif event.type() in ( QC.QEvent.MouseButtonDblClick, QC.QEvent.MouseButtonRelease ):
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
if event.type() == QC.QEvent.MouseButtonRelease:
2020-02-19 21:48:36 +00:00
shortcut_press_type = SHORTCUT_PRESS_TYPE_RELEASE
2020-02-12 22:50:37 +00:00
elif event.type() == QC.QEvent.MouseButtonDblClick:
2020-02-19 21:48:36 +00:00
shortcut_press_type = SHORTCUT_PRESS_TYPE_DOUBLE_CLICK
2020-02-12 22:50:37 +00:00
2018-05-16 20:09:50 +00:00
2020-04-29 21:44:12 +00:00
for ( qt_button, hydrus_button ) in qt_mouse_buttons_to_hydrus_mouse_buttons.items():
2020-02-12 22:50:37 +00:00
2020-04-29 21:44:12 +00:00
if event.button() == qt_button:
key = hydrus_button
break
2020-02-12 22:50:37 +00:00
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
elif event.type() == QC.QEvent.Wheel:
2018-05-16 20:09:50 +00:00
2020-11-11 22:20:16 +00:00
angle_delta_point = event.angleDelta()
if angle_delta_point is None:
return None
angle_delta = angle_delta_point.y()
if event.source() == QC.Qt.MouseEventSynthesizedBySystem:
if abs( angle_delta ) < ONE_TICK_ON_A_NORMAL_MOUSE_IN_DEGREES:
# likely using a trackpad to generate artificial wheel events
global GLOBAL_MOUSE_SCROLL_DELTA_FOR_TRACKPADS
GLOBAL_MOUSE_SCROLL_DELTA_FOR_TRACKPADS += angle_delta
if abs( GLOBAL_MOUSE_SCROLL_DELTA_FOR_TRACKPADS ) > ONE_TICK_ON_A_NORMAL_MOUSE_IN_DEGREES:
angle_delta = GLOBAL_MOUSE_SCROLL_DELTA_FOR_TRACKPADS
GLOBAL_MOUSE_SCROLL_DELTA_FOR_TRACKPADS = 0
else:
return None
if angle_delta > 0:
2020-02-12 22:50:37 +00:00
2020-02-19 21:48:36 +00:00
key = SHORTCUT_MOUSE_SCROLL_UP
2020-02-12 22:50:37 +00:00
2020-11-11 22:20:16 +00:00
elif angle_delta < 0:
2020-02-12 22:50:37 +00:00
2020-02-19 21:48:36 +00:00
key = SHORTCUT_MOUSE_SCROLL_DOWN
2020-02-12 22:50:37 +00:00
2018-05-16 20:09:50 +00:00
if key is not None:
modifiers = []
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.AltModifier:
2018-05-16 20:09:50 +00:00
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_ALT )
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.ControlModifier:
2018-05-16 20:09:50 +00:00
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_CTRL )
2018-05-16 20:09:50 +00:00
2020-11-11 22:20:16 +00:00
if event.modifiers() & QC.Qt.MetaModifier:
modifiers.append( SHORTCUT_MODIFIER_META )
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.ShiftModifier:
2018-05-16 20:09:50 +00:00
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_SHIFT )
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.GroupSwitchModifier:
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_GROUP_SWITCH )
2019-11-14 03:56:30 +00:00
if event.modifiers() & QC.Qt.KeypadModifier:
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_KEYPAD )
2019-11-14 03:56:30 +00:00
2020-02-19 21:48:36 +00:00
shortcut = Shortcut( SHORTCUT_TYPE_MOUSE, key, shortcut_press_type, modifiers )
2018-05-16 20:09:50 +00:00
if HG.gui_report_mode:
HydrusData.ShowText( 'mouse event caught: ' + repr( shortcut ) )
return shortcut
return None
2020-02-19 21:48:36 +00:00
def AncestorShortcutsHandlers( widget: QW.QWidget ):
shortcuts_handlers = []
window = widget.window()
if window == widget:
return shortcuts_handlers
2020-04-08 21:10:11 +00:00
widget = widget.parentWidget()
if widget is None:
return shortcuts_handlers
2020-02-19 21:48:36 +00:00
while True:
child_shortcuts_handlers = [ child for child in widget.children() if isinstance( child, ShortcutsHandler ) ]
shortcuts_handlers.extend( child_shortcuts_handlers )
if widget == window:
break
2020-04-08 21:10:11 +00:00
widget = widget.parentWidget()
2020-02-19 21:48:36 +00:00
if widget is None:
break
return shortcuts_handlers
def IShouldCatchShortcutEvent( event_handler_owner: QC.QObject, event_catcher: QW.QWidget, event: typing.Optional[ QC.QEvent ] = None, child_tlw_classes_who_can_pass_up: typing.Optional[ typing.Collection[ type ] ] = None ):
2017-04-19 20:58:30 +00:00
2019-07-03 22:49:27 +00:00
do_focus_test = True
2020-05-27 21:27:52 +00:00
if event is not None:
2019-11-20 23:10:46 +00:00
2020-05-27 21:27:52 +00:00
# the event happened to somewhere else, most likely a hover window of a media viewer
# should we intercept that event that happened somewhere else?
if event_handler_owner != event_catcher:
# don't pass clicks up
if event.type() in ( QC.QEvent.MouseButtonPress, QC.QEvent.MouseButtonRelease, QC.QEvent.MouseButtonDblClick ):
return False
# don't pass wheels that happen to legit controls that want to eat it, like a list, when the catcher is a window
if event.type() == QC.QEvent.Wheel:
widget_under_mouse = event_catcher.childAt( event_catcher.mapFromGlobal( QG.QCursor.pos() ) )
if widget_under_mouse is not None:
mouse_scroll_over_window_greyspace = widget_under_mouse == event_catcher and event_catcher.isWindow()
if not mouse_scroll_over_window_greyspace:
return False
2019-11-20 23:10:46 +00:00
2020-05-27 21:27:52 +00:00
if event.type() == QC.QEvent.Wheel:
do_focus_test = False
2019-07-03 22:49:27 +00:00
2020-07-15 20:52:09 +00:00
do_focus_test = False # lmao, why this here? I guess it got turned off
2020-05-27 21:27:52 +00:00
2019-07-03 22:49:27 +00:00
if do_focus_test:
2020-05-27 21:27:52 +00:00
if not ClientGUIFunctions.TLWIsActive( event_handler_owner ):
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
if child_tlw_classes_who_can_pass_up is not None:
2019-07-03 22:49:27 +00:00
2020-05-27 21:27:52 +00:00
child_tlw_has_focus = ClientGUIFunctions.WidgetOrAnyTLWChildHasFocus( event_handler_owner ) and isinstance( QW.QApplication.activeWindow(), child_tlw_classes_who_can_pass_up )
2019-07-03 22:49:27 +00:00
2019-12-11 23:18:37 +00:00
if not child_tlw_has_focus:
2019-07-03 22:49:27 +00:00
return False
else:
2019-06-26 21:27:18 +00:00
return False
2017-04-19 20:58:30 +00:00
return True
2018-05-16 20:09:50 +00:00
class Shortcut( HydrusSerialisable.SerialisableBase ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT
SERIALISABLE_NAME = 'Shortcut'
2020-02-12 22:50:37 +00:00
SERIALISABLE_VERSION = 3
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
def __init__( self, shortcut_type = None, shortcut_key = None, shortcut_press_type = None, modifiers = None ):
2018-05-16 20:09:50 +00:00
if shortcut_type is None:
2020-02-19 21:48:36 +00:00
shortcut_type = SHORTCUT_TYPE_KEYBOARD_SPECIAL
2018-05-16 20:09:50 +00:00
if shortcut_key is None:
2020-02-19 21:48:36 +00:00
shortcut_key = SHORTCUT_KEY_SPECIAL_F7
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
if shortcut_press_type is None:
2020-02-19 21:48:36 +00:00
shortcut_press_type = SHORTCUT_PRESS_TYPE_PRESS
2020-02-12 22:50:37 +00:00
2018-05-16 20:09:50 +00:00
if modifiers is None:
modifiers = []
2020-02-19 21:48:36 +00:00
if shortcut_type == SHORTCUT_TYPE_KEYBOARD_CHARACTER and ClientData.OrdIsAlphaUpper( shortcut_key ):
2019-11-14 03:56:30 +00:00
shortcut_key += 32 # convert A to a
2020-05-13 19:03:16 +00:00
modifiers = sorted( modifiers )
2018-05-16 20:09:50 +00:00
HydrusSerialisable.SerialisableBase.__init__( self )
2020-02-12 22:50:37 +00:00
self.shortcut_type = shortcut_type
self.shortcut_key = shortcut_key
self.shortcut_press_type = shortcut_press_type
self.modifiers = modifiers
2018-05-16 20:09:50 +00:00
def __eq__( self, other ):
2020-01-22 21:04:43 +00:00
if isinstance( other, Shortcut ):
return self.__hash__() == other.__hash__()
return NotImplemented
2018-05-16 20:09:50 +00:00
def __hash__( self ):
2020-02-12 22:50:37 +00:00
return ( self.shortcut_type, self.shortcut_key, self.shortcut_press_type, tuple( self.modifiers ) ).__hash__()
2018-05-16 20:09:50 +00:00
def __repr__( self ):
return 'Shortcut: ' + self.ToString()
def _GetSerialisableInfo( self ):
2020-02-12 22:50:37 +00:00
return ( self.shortcut_type, self.shortcut_key, self.shortcut_press_type, self.modifiers )
2018-05-16 20:09:50 +00:00
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
2020-02-12 22:50:37 +00:00
( self.shortcut_type, self.shortcut_key, self.shortcut_press_type, self.modifiers ) = serialisable_info
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
def _UpdateSerialisableInfo( self, version, old_serialisable_info ):
if version == 1:
# these are dicts that convert fixed wx enums to new stuff
wx_to_qt_flat_conversion = {
2020-02-19 21:48:36 +00:00
32 : SHORTCUT_KEY_SPECIAL_SPACE,
8 : SHORTCUT_KEY_SPECIAL_BACKSPACE,
9 : SHORTCUT_KEY_SPECIAL_TAB,
13 : SHORTCUT_KEY_SPECIAL_RETURN,
310 : SHORTCUT_KEY_SPECIAL_PAUSE,
27 : SHORTCUT_KEY_SPECIAL_ESCAPE,
322 : SHORTCUT_KEY_SPECIAL_INSERT,
127 : SHORTCUT_KEY_SPECIAL_DELETE,
315 : SHORTCUT_KEY_SPECIAL_UP,
317 : SHORTCUT_KEY_SPECIAL_DOWN,
314 : SHORTCUT_KEY_SPECIAL_LEFT,
316 : SHORTCUT_KEY_SPECIAL_RIGHT,
313 : SHORTCUT_KEY_SPECIAL_HOME,
312 : SHORTCUT_KEY_SPECIAL_END,
367 : SHORTCUT_KEY_SPECIAL_PAGE_DOWN,
366 : SHORTCUT_KEY_SPECIAL_PAGE_UP,
340 : SHORTCUT_KEY_SPECIAL_F1,
341 : SHORTCUT_KEY_SPECIAL_F2,
342 : SHORTCUT_KEY_SPECIAL_F3,
343 : SHORTCUT_KEY_SPECIAL_F4,
344 : SHORTCUT_KEY_SPECIAL_F5,
345 : SHORTCUT_KEY_SPECIAL_F6,
346 : SHORTCUT_KEY_SPECIAL_F7,
347 : SHORTCUT_KEY_SPECIAL_F8,
348 : SHORTCUT_KEY_SPECIAL_F9,
349 : SHORTCUT_KEY_SPECIAL_F10,
350 : SHORTCUT_KEY_SPECIAL_F11,
351 : SHORTCUT_KEY_SPECIAL_F12
2019-11-14 03:56:30 +00:00
}
# regular keys, but numpad, that are tracked in wx by combined unique enum
wx_to_qt_numpad_ascii_conversion = {
324 : ord( '0' ),
325 : ord( '1' ),
326 : ord( '2' ),
327 : ord( '3' ),
328 : ord( '4' ),
329 : ord( '5' ),
330 : ord( '6' ),
331 : ord( '7' ),
332 : ord( '8' ),
2019-12-11 23:18:37 +00:00
333 : ord( '9' ),
2019-11-14 03:56:30 +00:00
388 : ord( '+' ),
392 : ord( '/' ),
390 : ord( '-' ),
387 : ord( '*' ),
391 : ord( '.' )
}
wx_to_qt_numpad_conversion = {
2020-02-19 21:48:36 +00:00
377 : SHORTCUT_KEY_SPECIAL_UP,
379 : SHORTCUT_KEY_SPECIAL_DOWN,
376 : SHORTCUT_KEY_SPECIAL_LEFT,
378 : SHORTCUT_KEY_SPECIAL_RIGHT,
375 : SHORTCUT_KEY_SPECIAL_HOME,
382 : SHORTCUT_KEY_SPECIAL_END,
381 : SHORTCUT_KEY_SPECIAL_PAGE_DOWN,
380 : SHORTCUT_KEY_SPECIAL_PAGE_UP,
385 : SHORTCUT_KEY_SPECIAL_DELETE,
370 : SHORTCUT_KEY_SPECIAL_ENTER
2019-11-14 03:56:30 +00:00
}
( shortcut_type, shortcut_key, modifiers ) = old_serialisable_info
2020-02-19 21:48:36 +00:00
if shortcut_type == SHORTCUT_TYPE_KEYBOARD_CHARACTER:
2019-11-14 03:56:30 +00:00
if shortcut_key in wx_to_qt_flat_conversion:
2020-02-19 21:48:36 +00:00
shortcut_type = SHORTCUT_TYPE_KEYBOARD_SPECIAL
2019-11-14 03:56:30 +00:00
shortcut_key = wx_to_qt_flat_conversion[ shortcut_key ]
elif shortcut_key in wx_to_qt_numpad_ascii_conversion:
shortcut_key = wx_to_qt_numpad_ascii_conversion[ shortcut_key ]
modifiers = list( modifiers )
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_KEYPAD )
2019-11-14 03:56:30 +00:00
modifiers.sort()
elif shortcut_key in wx_to_qt_numpad_conversion:
2020-02-19 21:48:36 +00:00
shortcut_type = SHORTCUT_TYPE_KEYBOARD_SPECIAL
2019-11-14 03:56:30 +00:00
shortcut_key = wx_to_qt_numpad_conversion[ shortcut_key ]
modifiers = list( modifiers )
2020-02-19 21:48:36 +00:00
modifiers.append( SHORTCUT_MODIFIER_KEYPAD )
2019-11-14 03:56:30 +00:00
modifiers.sort()
2020-02-19 21:48:36 +00:00
if shortcut_type == SHORTCUT_TYPE_KEYBOARD_CHARACTER:
2019-11-14 03:56:30 +00:00
if ClientData.OrdIsAlphaUpper( shortcut_key ):
shortcut_key += 32 # convert 'A' to 'a'
new_serialisable_info = ( shortcut_type, shortcut_key, modifiers )
return ( 2, new_serialisable_info )
2020-02-12 22:50:37 +00:00
if version == 2:
( shortcut_type, shortcut_key, modifiers ) = old_serialisable_info
2020-02-19 21:48:36 +00:00
shortcut_press_type = SHORTCUT_PRESS_TYPE_PRESS
2020-02-12 22:50:37 +00:00
new_serialisable_info = ( shortcut_type, shortcut_key, shortcut_press_type, modifiers )
return ( 3, new_serialisable_info )
2019-11-14 03:56:30 +00:00
2020-02-19 21:48:36 +00:00
def ConvertToSingleClick( self ):
if self.IsDoubleClick():
new_shortcut = self.Duplicate()
new_shortcut.shortcut_press_type = SHORTCUT_PRESS_TYPE_PRESS
return new_shortcut
return self
2018-05-16 20:09:50 +00:00
def GetShortcutType( self ):
2020-02-12 22:50:37 +00:00
return self.shortcut_type
2018-05-16 20:09:50 +00:00
def IsAppropriateForPressRelease( self ):
return self.shortcut_key in SHORTCUT_MOUSE_CLICKS and self.shortcut_press_type != SHORTCUT_PRESS_TYPE_DOUBLE_CLICK
2020-02-19 21:48:36 +00:00
def IsDoubleClick( self ):
return self.shortcut_type == SHORTCUT_TYPE_MOUSE and self.shortcut_press_type == SHORTCUT_PRESS_TYPE_DOUBLE_CLICK
2018-05-16 20:09:50 +00:00
def ToString( self ):
components = []
2020-11-11 22:20:16 +00:00
if SHORTCUT_MODIFIER_META in self.modifiers:
components.append( 'control' )
2020-02-19 21:48:36 +00:00
if SHORTCUT_MODIFIER_CTRL in self.modifiers:
2018-05-16 20:09:50 +00:00
2020-11-11 22:20:16 +00:00
if HC.PLATFORM_MACOS:
components.append( 'command' )
else:
components.append( 'ctrl' )
2018-05-16 20:09:50 +00:00
2020-02-19 21:48:36 +00:00
if SHORTCUT_MODIFIER_ALT in self.modifiers:
2018-05-16 20:09:50 +00:00
components.append( 'alt' )
2020-02-19 21:48:36 +00:00
if SHORTCUT_MODIFIER_SHIFT in self.modifiers:
2018-05-16 20:09:50 +00:00
components.append( 'shift' )
2020-02-19 21:48:36 +00:00
if SHORTCUT_MODIFIER_GROUP_SWITCH in self.modifiers:
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
components.append( 'Mode_switch' )
2020-02-19 21:48:36 +00:00
if self.shortcut_press_type != SHORTCUT_PRESS_TYPE_PRESS:
2020-02-12 22:50:37 +00:00
2020-02-19 21:48:36 +00:00
action_name = '{} '.format( shortcut_press_type_str_lookup[ self.shortcut_press_type ] )
2019-11-14 03:56:30 +00:00
2020-02-12 22:50:37 +00:00
else:
2019-11-14 03:56:30 +00:00
2020-02-12 22:50:37 +00:00
action_name = ''
2020-02-19 21:48:36 +00:00
if self.shortcut_type == SHORTCUT_TYPE_MOUSE and self.shortcut_key in shortcut_mouse_string_lookup:
2019-11-14 03:56:30 +00:00
2020-02-19 21:48:36 +00:00
action_name += shortcut_mouse_string_lookup[ self.shortcut_key ]
2019-11-14 03:56:30 +00:00
2020-02-19 21:48:36 +00:00
elif self.shortcut_type == SHORTCUT_TYPE_KEYBOARD_SPECIAL and self.shortcut_key in special_key_shortcut_str_lookup:
2020-02-12 22:50:37 +00:00
2020-02-19 21:48:36 +00:00
action_name += special_key_shortcut_str_lookup[ self.shortcut_key ]
2020-02-12 22:50:37 +00:00
2020-02-19 21:48:36 +00:00
elif self.shortcut_type == SHORTCUT_TYPE_KEYBOARD_CHARACTER:
2019-11-14 03:56:30 +00:00
2019-12-18 22:06:34 +00:00
try:
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
if ClientData.OrdIsAlphaUpper( self.shortcut_key ):
2019-12-18 22:06:34 +00:00
2020-02-12 22:50:37 +00:00
action_name += chr( self.shortcut_key + 32 ) # + 32 for converting ascii A -> a
2019-12-18 22:06:34 +00:00
else:
2020-02-12 22:50:37 +00:00
action_name += chr( self.shortcut_key )
2019-12-18 22:06:34 +00:00
2018-05-16 20:09:50 +00:00
2019-12-18 22:06:34 +00:00
except:
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
action_name += 'unknown key: {}'.format( repr( self.shortcut_key ) )
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
else:
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
action_name += 'unknown key: {}'.format( repr( self.shortcut_key ) )
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
components.append( action_name )
2019-11-14 03:56:30 +00:00
s = '+'.join( components )
2020-02-19 21:48:36 +00:00
if SHORTCUT_MODIFIER_KEYPAD in self.modifiers:
2019-11-14 03:56:30 +00:00
s += ' (on numpad)'
return s
2018-05-16 20:09:50 +00:00
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT ] = Shortcut
2019-06-05 19:42:39 +00:00
class ShortcutSet( HydrusSerialisable.SerialisableBaseNamed ):
2018-05-16 20:09:50 +00:00
2019-06-05 19:42:39 +00:00
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT_SET
SERIALISABLE_NAME = 'Shortcut Set'
2018-05-16 20:09:50 +00:00
SERIALISABLE_VERSION = 2
def __init__( self, name ):
HydrusSerialisable.SerialisableBaseNamed.__init__( self, name )
self._shortcuts_to_commands = {}
def __iter__( self ):
2019-05-22 22:35:06 +00:00
for ( shortcut, command ) in list( self._shortcuts_to_commands.items() ):
2018-05-16 20:09:50 +00:00
yield ( shortcut, command )
def __len__( self ):
return len( self._shortcuts_to_commands )
def _GetSerialisableInfo( self ):
2019-01-09 22:59:03 +00:00
return [ ( shortcut.GetSerialisableTuple(), command.GetSerialisableTuple() ) for ( shortcut, command ) in list(self._shortcuts_to_commands.items()) ]
2018-05-16 20:09:50 +00:00
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
for ( serialisable_shortcut, serialisable_command ) in serialisable_info:
shortcut = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_shortcut )
command = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_command )
self._shortcuts_to_commands[ shortcut ] = command
def _UpdateSerialisableInfo( self, version, old_serialisable_info ):
if version == 1:
( serialisable_mouse_actions, serialisable_keyboard_actions ) = old_serialisable_info
shortcuts_to_commands = {}
# this never stored mouse actions, so skip
services_manager = HG.client_controller.services_manager
for ( modifier, key, ( serialisable_service_key, data ) ) in serialisable_keyboard_actions:
2019-11-14 03:56:30 +00:00
# no longer updating modifier, as that was wx legacy
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
modifiers = []
2020-02-19 21:48:36 +00:00
shortcut = Shortcut( SHORTCUT_TYPE_KEYBOARD_CHARACTER, key, SHORTCUT_PRESS_TYPE_PRESS, modifiers )
2018-05-16 20:09:50 +00:00
if serialisable_service_key is None:
command = CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_SIMPLE, data )
2018-05-16 20:09:50 +00:00
else:
2019-01-09 22:59:03 +00:00
service_key = bytes.fromhex( serialisable_service_key )
2018-05-16 20:09:50 +00:00
if not services_manager.ServiceExists( service_key ):
continue
action = HC.CONTENT_UPDATE_FLIP
value = data
service = services_manager.GetService( service_key )
service_type = service.GetServiceType()
2020-03-11 21:52:11 +00:00
if service_type in HC.REAL_TAG_SERVICES:
2018-05-16 20:09:50 +00:00
content_type = HC.CONTENT_TYPE_MAPPINGS
elif service_type in HC.RATINGS_SERVICES:
content_type = HC.CONTENT_TYPE_RATINGS
else:
continue
command = CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, content_type, action, value ) )
2018-05-16 20:09:50 +00:00
shortcuts_to_commands[ shortcut ] = command
2019-01-09 22:59:03 +00:00
new_serialisable_info = ( ( shortcut.GetSerialisableTuple(), command.GetSerialisableTuple() ) for ( shortcut, command ) in list(shortcuts_to_commands.items()) )
2018-05-16 20:09:50 +00:00
return ( 2, new_serialisable_info )
2021-01-27 22:14:03 +00:00
def DeleteShortcut( self, shortcut ):
if shortcut in self._shortcuts_to_commands:
del self._shortcuts_to_commands[ shortcut ]
2018-05-16 20:09:50 +00:00
def GetCommand( self, shortcut ):
if shortcut in self._shortcuts_to_commands:
return self._shortcuts_to_commands[ shortcut ]
else:
return None
def GetShortcuts( self, simple_command: int ):
2019-06-05 19:42:39 +00:00
shortcuts = []
for ( shortcut, command ) in self._shortcuts_to_commands.items():
if command.IsSimpleCommand() and command.GetData() == simple_command:
2019-06-05 19:42:39 +00:00
shortcuts.append( shortcut )
return shortcuts
2018-05-16 20:09:50 +00:00
def SetCommand( self, shortcut, command ):
self._shortcuts_to_commands[ shortcut ] = command
2019-06-05 19:42:39 +00:00
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT_SET ] = ShortcutSet
2018-05-16 20:09:50 +00:00
2019-11-14 03:56:30 +00:00
class ShortcutsHandler( QC.QObject ):
2017-03-29 19:39:34 +00:00
2021-01-27 22:14:03 +00:00
def __init__( self, parent: QW.QWidget, initial_shortcuts_names: typing.Collection[ str ], alternate_filter_target = None, catch_mouse = False, ignore_activating_mouse_click = False ):
2017-03-29 19:39:34 +00:00
2019-11-14 03:56:30 +00:00
QC.QObject.__init__( self, parent )
2020-02-12 22:50:37 +00:00
self._catch_mouse = catch_mouse
2021-01-27 22:14:03 +00:00
filter_target = parent
if alternate_filter_target is not None:
2017-03-29 19:39:34 +00:00
2021-01-27 22:14:03 +00:00
filter_target = alternate_filter_target
2017-03-29 19:39:34 +00:00
2021-01-27 22:14:03 +00:00
self._filter_target = filter_target
2017-03-29 19:39:34 +00:00
self._parent = parent
2021-01-27 22:14:03 +00:00
self._filter_target.installEventFilter( self )
2018-03-14 21:01:02 +00:00
self._shortcuts_names = list( initial_shortcuts_names )
2017-03-29 19:39:34 +00:00
2020-03-04 22:12:53 +00:00
self._ignore_activating_mouse_click = ignore_activating_mouse_click
self._frame_activated_time = 0.0
if self._catch_mouse and self._ignore_activating_mouse_click:
self._deactivation_catcher = ShortcutsDeactivationCatcher( self, parent )
2018-03-14 21:01:02 +00:00
2020-02-19 21:48:36 +00:00
def _ProcessShortcut( self, shortcut: Shortcut ):
2018-03-14 21:01:02 +00:00
shortcut_processed = False
2020-03-25 21:15:57 +00:00
command = shortcuts_manager().GetCommand( self._shortcuts_names, shortcut )
2020-02-19 21:48:36 +00:00
if command is None and shortcut.IsDoubleClick():
# ok, so user double-clicked
# if a parent wants to catch this (for instance the media viewer when we double-click a video), then we want that parent to have it
# but if no parent wants it, we can try converting it to a single-click to see if that does anything
ancestor_shortcuts_handlers = AncestorShortcutsHandlers( self._parent )
all_ancestor_shortcut_names = HydrusData.MassUnion( [ ancestor_shortcuts_handler.GetShortcutNames() for ancestor_shortcuts_handler in ancestor_shortcuts_handlers ] )
2020-03-25 21:15:57 +00:00
ancestor_command = shortcuts_manager().GetCommand( all_ancestor_shortcut_names, shortcut )
2020-02-19 21:48:36 +00:00
if ancestor_command is None:
if HG.shortcut_report_mode:
message = 'Shortcut "' + shortcut.ToString() + '" did not match any command. The single click version is now being attempted.'
HydrusData.ShowText( message )
shortcut = shortcut.ConvertToSingleClick()
2020-03-25 21:15:57 +00:00
command = shortcuts_manager().GetCommand( self._shortcuts_names, shortcut )
2020-02-19 21:48:36 +00:00
else:
if HG.shortcut_report_mode:
message = 'Shortcut "' + shortcut.ToString() + '" did not match any command. A parent seems to want it, however, so the single click version will not be attempted.'
HydrusData.ShowText( message )
2018-03-14 21:01:02 +00:00
if command is not None:
command_processed = self._parent.ProcessApplicationCommand( command )
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
if command_processed:
shortcut_processed = True
2017-03-29 19:39:34 +00:00
2018-03-22 00:03:33 +00:00
if HG.shortcut_report_mode:
2021-01-27 22:14:03 +00:00
message = 'Shortcut "{}" matched to command "{}" on {}.'.format( shortcut.ToString(), command.ToString(), repr( self._parent ) )
2018-03-22 00:03:33 +00:00
if command_processed:
message += ' It was processed.'
else:
message += ' It was not processed.'
HydrusData.ShowText( message )
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
return shortcut_processed
2017-03-29 19:39:34 +00:00
2020-04-29 21:44:12 +00:00
def AddWindowToFilter( self, win: QW.QWidget ):
win.installEventFilter( self )
2019-11-14 03:56:30 +00:00
def eventFilter( self, watched, event ):
2018-03-22 00:03:33 +00:00
2019-11-14 03:56:30 +00:00
if event.type() == QC.QEvent.KeyPress:
2018-03-14 21:01:02 +00:00
2021-01-27 22:14:03 +00:00
i_should_catch_shortcut_event = IShouldCatchShortcutEvent( self._filter_target, watched, event = event )
2020-02-12 22:50:37 +00:00
2019-11-14 03:56:30 +00:00
shortcut = ConvertKeyEventToShortcut( event )
if shortcut is not None:
2018-03-22 00:03:33 +00:00
2019-11-14 03:56:30 +00:00
if HG.shortcut_report_mode:
2018-03-22 00:03:33 +00:00
2021-01-27 22:14:03 +00:00
message = 'Key shortcut "{}" passing through {}.'.format( shortcut.ToString(), repr( self._parent ) )
2018-03-22 00:03:33 +00:00
2020-02-12 22:50:37 +00:00
if i_should_catch_shortcut_event:
2019-11-14 03:56:30 +00:00
message += ' I am in a state to catch it.'
else:
message += ' I am not in a state to catch it.'
2018-03-22 00:03:33 +00:00
2019-11-14 03:56:30 +00:00
HydrusData.ShowText( message )
2018-03-22 00:03:33 +00:00
2020-02-12 22:50:37 +00:00
if i_should_catch_shortcut_event:
2018-03-14 21:01:02 +00:00
2019-11-14 03:56:30 +00:00
shortcut_processed = self._ProcessShortcut( shortcut )
if shortcut_processed:
2020-02-12 22:50:37 +00:00
event.accept()
2019-11-14 03:56:30 +00:00
return True
2018-03-14 21:01:02 +00:00
2020-02-12 22:50:37 +00:00
elif self._catch_mouse:
if event.type() in ( QC.QEvent.MouseButtonPress, QC.QEvent.MouseButtonRelease, QC.QEvent.MouseButtonDblClick, QC.QEvent.Wheel ):
2020-05-27 21:27:52 +00:00
if event.type() != QC.QEvent.Wheel and self._ignore_activating_mouse_click and not HydrusData.TimeHasPassedPrecise( self._frame_activated_time + 0.017 ):
2020-03-04 22:12:53 +00:00
if event.type() == QC.QEvent.MouseButtonRelease:
self._frame_activated_time = 0.0
return False
2021-01-27 22:14:03 +00:00
i_should_catch_shortcut_event = IShouldCatchShortcutEvent( self._filter_target, watched, event = event )
2020-02-12 22:50:37 +00:00
shortcut = ConvertMouseEventToShortcut( event )
if shortcut is not None:
if HG.shortcut_report_mode:
message = 'Mouse Press shortcut "' + shortcut.ToString() + '" passing through ' + repr( self._parent ) + '.'
if i_should_catch_shortcut_event:
message += ' I am in a state to catch it.'
else:
message += ' I am not in a state to catch it.'
HydrusData.ShowText( message )
if i_should_catch_shortcut_event:
shortcut_processed = self._ProcessShortcut( shortcut )
if shortcut_processed:
event.accept()
return True
2019-11-14 03:56:30 +00:00
return False
2017-03-29 19:39:34 +00:00
2019-09-11 21:51:09 +00:00
def AddShortcuts( self, shortcut_set_name ):
2017-03-29 19:39:34 +00:00
2019-09-11 21:51:09 +00:00
if shortcut_set_name not in self._shortcuts_names:
2018-03-14 21:01:02 +00:00
2020-02-19 21:48:36 +00:00
reserved_names = [ name for name in self._shortcuts_names if name in SHORTCUTS_RESERVED_NAMES ]
custom_names = [ name for name in self._shortcuts_names if name not in SHORTCUTS_RESERVED_NAMES ]
if shortcut_set_name in SHORTCUTS_RESERVED_NAMES:
reserved_names.append( shortcut_set_name )
else:
custom_names.append( shortcut_set_name )
self._shortcuts_names = reserved_names + custom_names
def FlipShortcuts( self, shortcut_set_name ):
if shortcut_set_name in self._shortcuts_names:
self.RemoveShortcuts( shortcut_set_name )
else:
self.AddShortcuts( shortcut_set_name )
2018-03-14 21:01:02 +00:00
2017-03-29 19:39:34 +00:00
2020-02-19 21:48:36 +00:00
def GetCustomShortcutNames( self ):
2020-05-13 19:03:16 +00:00
custom_names = sorted( ( name for name in self._shortcuts_names if name not in SHORTCUTS_RESERVED_NAMES ) )
2020-02-19 21:48:36 +00:00
return custom_names
def GetShortcutNames( self ):
return list( self._shortcuts_names )
def HasShortcuts( self, shortcut_set_name ):
return shortcut_set_name in self._shortcuts_names
def ProcessShortcut( self, shortcut ):
return self._ProcessShortcut( shortcut )
2019-09-11 21:51:09 +00:00
def RemoveShortcuts( self, shortcut_set_name ):
2017-03-29 19:39:34 +00:00
2019-09-11 21:51:09 +00:00
if shortcut_set_name in self._shortcuts_names:
2017-03-29 19:39:34 +00:00
2019-09-11 21:51:09 +00:00
self._shortcuts_names.remove( shortcut_set_name )
2017-03-29 19:39:34 +00:00
2018-05-16 20:09:50 +00:00
2020-02-12 22:50:37 +00:00
def SetShortcuts( self, shortcut_set_names ):
self._shortcuts_names = list( shortcut_set_names )
2020-03-04 22:12:53 +00:00
def FrameActivated( self ):
self._frame_activated_time = HydrusData.GetNowPrecise()
class ShortcutsDeactivationCatcher( QC.QObject ):
def __init__( self, shortcuts_handler: ShortcutsHandler, widget: QW.QWidget ):
QC.QObject.__init__( self, shortcuts_handler )
self._shortcuts_handler = shortcuts_handler
widget.window().installEventFilter( self )
def eventFilter( self, watched, event ):
if event.type() == QC.QEvent.WindowActivate:
self._shortcuts_handler.FrameActivated()
return False
2020-03-25 21:15:57 +00:00
class ShortcutsManager( QC.QObject ):
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
shortcutsChanged = QC.Signal()
my_instance = None
def __init__( self, shortcut_sets = None ):
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
parent = CGC.core()
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
QC.QObject.__init__( self, parent )
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
self._names_to_shortcut_sets = {}
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
if shortcut_sets is not None:
self.SetShortcutSets( shortcut_sets )
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
ShortcutsManager.my_instance = self
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
@staticmethod
def instance() -> 'ShortcutsManager':
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
if ShortcutsManager.my_instance is None:
raise Exception( 'ShortcutsManager is not yet initialised!' )
else:
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
return ShortcutsManager.my_instance
2019-06-05 19:42:39 +00:00
2020-04-29 21:44:12 +00:00
def GetCommand( self, shortcuts_names: typing.Iterable[ str ], shortcut: Shortcut ):
2019-06-05 19:42:39 +00:00
2020-02-19 21:48:36 +00:00
# process more specific shortcuts with higher priority
shortcuts_names = list( shortcuts_names )
shortcuts_names.reverse()
2019-06-05 19:42:39 +00:00
for name in shortcuts_names:
2020-03-25 21:15:57 +00:00
if name in self._names_to_shortcut_sets:
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
command = self._names_to_shortcut_sets[ name ].GetCommand( shortcut )
2019-06-05 19:42:39 +00:00
if command is not None:
2020-02-19 21:48:36 +00:00
if HG.shortcut_report_mode:
2019-06-05 19:42:39 +00:00
2020-02-19 21:48:36 +00:00
HydrusData.ShowText( 'Shortcut "{}" matched on "{}" set to "{}" command.'.format( shortcut.ToString(), name, repr( command ) ) )
2019-06-05 19:42:39 +00:00
return command
return None
def GetNamesToShortcuts( self, simple_command: int ):
2019-06-05 19:42:39 +00:00
names_to_shortcuts = {}
2020-03-25 21:15:57 +00:00
for ( name, shortcut_set ) in self._names_to_shortcut_sets.items():
2019-06-05 19:42:39 +00:00
shortcuts = shortcut_set.GetShortcuts( simple_command )
if len( shortcuts ) > 0:
names_to_shortcuts[ name ] = shortcuts
return names_to_shortcuts
2020-03-25 21:15:57 +00:00
def GetShortcutSets( self ) -> typing.List[ ShortcutSet ]:
return list( self._names_to_shortcut_sets.values() )
2020-04-29 21:44:12 +00:00
def SetShortcutSets( self, shortcut_sets: typing.Iterable[ ShortcutSet ] ):
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
self._names_to_shortcut_sets = { shortcut_set.GetName() : shortcut_set for shortcut_set in shortcut_sets }
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
self.shortcutsChanged.emit()
2019-06-05 19:42:39 +00:00
2020-03-25 21:15:57 +00:00
shortcuts_manager = ShortcutsManager.instance
shortcuts_manager_initialised = lambda: ShortcutsManager.my_instance is not None