953 lines
30 KiB
Python
953 lines
30 KiB
Python
from . import ClientConstants as CC
|
|
from . import ClientData
|
|
from . import ClientGUICommon
|
|
from . import ClientGUIFunctions
|
|
from . import HydrusConstants as HC
|
|
from . import HydrusData
|
|
from . import HydrusGlobals as HG
|
|
from . import HydrusSerialisable
|
|
from qtpy import QtCore as QC
|
|
from qtpy import QtWidgets as QW
|
|
from qtpy import QtGui as QG
|
|
from . import QtPorting as QP
|
|
|
|
# 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 ):
|
|
|
|
if key_qt in CC.special_key_shortcut_enum_lookup:
|
|
|
|
key_ord = CC.special_key_shortcut_enum_lookup[ key_qt ]
|
|
|
|
return ( CC.SHORTCUT_TYPE_KEYBOARD_SPECIAL, key_ord )
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
key_ord = int( key_qt )
|
|
|
|
key_chr = chr( key_ord )
|
|
|
|
# this is turbo lower() that converts Scharfes S (beta) to 'ss'
|
|
key_chr = key_chr.casefold()[0]
|
|
|
|
casefold_key_ord = ord( key_chr )
|
|
|
|
return ( CC.SHORTCUT_TYPE_KEYBOARD_CHARACTER, casefold_key_ord )
|
|
|
|
except:
|
|
|
|
return ( CC.SHORTCUT_TYPE_NOT_ALLOWED, key_ord )
|
|
|
|
|
|
|
|
def ConvertKeyEventToShortcut( event ):
|
|
|
|
key_qt = event.key()
|
|
|
|
( shortcut_type, key_ord ) = ConvertQtKeyToShortcutKey( key_qt )
|
|
|
|
if shortcut_type != CC.SHORTCUT_TYPE_NOT_ALLOWED:
|
|
|
|
modifiers = []
|
|
|
|
if event.modifiers() & QC.Qt.AltModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_ALT )
|
|
|
|
|
|
if HC.PLATFORM_MACOS:
|
|
|
|
ctrl = QC.Qt.MetaModifier
|
|
|
|
else:
|
|
|
|
ctrl = QC.Qt.ControlModifier
|
|
|
|
|
|
if event.modifiers() & ctrl:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_CTRL )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.ShiftModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_SHIFT )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.GroupSwitchModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_GROUP_SWITCH )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.KeypadModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_KEYPAD )
|
|
|
|
|
|
shortcut = Shortcut( shortcut_type, key_ord, modifiers )
|
|
|
|
if HG.gui_report_mode:
|
|
|
|
HydrusData.ShowText( 'key event caught: ' + repr( shortcut ) )
|
|
|
|
|
|
return shortcut
|
|
|
|
|
|
return None
|
|
|
|
def ConvertKeyEventToSimpleTuple( event ):
|
|
|
|
modifier = QC.Qt.NoModifier
|
|
|
|
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
|
|
|
|
key = event.key()
|
|
|
|
return ( modifier, key )
|
|
|
|
def ConvertMouseEventToShortcut( event ):
|
|
|
|
key = None
|
|
|
|
if ( event.type() == QC.QEvent.MouseButtonPress and event.buttons() & QC.Qt.LeftButton ) or ( event.type() == QC.QEvent.MouseButtonDblClick and event.button() == QC.Qt.LeftButton ):
|
|
|
|
key = CC.SHORTCUT_MOUSE_LEFT
|
|
|
|
elif ( event.type() == QC.QEvent.MouseButtonPress and event.buttons() & QC.Qt.MiddleButton ) or ( event.type() == QC.QEvent.MouseButtonDblClick and event.button() == QC.Qt.MiddleButton ):
|
|
|
|
key = CC.SHORTCUT_MOUSE_MIDDLE
|
|
|
|
elif ( event.type() == QC.QEvent.MouseButtonPress and event.buttons() & QC.Qt.RightButton ) or ( event.type() == QC.QEvent.MouseButtonDblClick and event.button() == QC.Qt.RightButton ):
|
|
|
|
key = CC.SHORTCUT_MOUSE_RIGHT
|
|
|
|
elif event.type() == QC.QEvent.Wheel and event.angleDelta().y() > 0:
|
|
|
|
key = CC.SHORTCUT_MOUSE_SCROLL_UP
|
|
|
|
elif event.type() == QC.QEvent.Wheel and event.angleDelta().y() < 0:
|
|
|
|
key = CC.SHORTCUT_MOUSE_SCROLL_DOWN
|
|
|
|
|
|
if key is not None:
|
|
|
|
modifiers = []
|
|
|
|
if event.modifiers() & QC.Qt.AltModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_ALT )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.ControlModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_CTRL )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.ShiftModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_SHIFT )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.GroupSwitchModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_GROUP_SWITCH )
|
|
|
|
|
|
if event.modifiers() & QC.Qt.KeypadModifier:
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_KEYPAD )
|
|
|
|
|
|
shortcut = Shortcut( CC.SHORTCUT_TYPE_MOUSE, key, modifiers )
|
|
|
|
if HG.gui_report_mode:
|
|
|
|
HydrusData.ShowText( 'mouse event caught: ' + repr( shortcut ) )
|
|
|
|
|
|
return shortcut
|
|
|
|
|
|
return None
|
|
|
|
def IShouldCatchShortcutEvent( evt_handler, event = None, child_tlw_classes_who_can_pass_up = None ):
|
|
|
|
do_focus_test = True
|
|
|
|
if event is not None and isinstance( event, QG.QWheelEvent ):
|
|
|
|
do_focus_test = False
|
|
|
|
|
|
|
|
if do_focus_test:
|
|
|
|
if not ClientGUIFunctions.TLWIsActive( evt_handler ):
|
|
|
|
if child_tlw_classes_who_can_pass_up is not None:
|
|
|
|
child_tlw_has_focus = ClientGUIFunctions.WidgetOrAnyTLWChildHasFocus( evt_handler ) and isinstance( QW.QApplication.activeWindow(), child_tlw_classes_who_can_pass_up )
|
|
|
|
if not child_tlw_has_focus:
|
|
|
|
return False
|
|
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
class Shortcut( HydrusSerialisable.SerialisableBase ):
|
|
|
|
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT
|
|
SERIALISABLE_NAME = 'Shortcut'
|
|
SERIALISABLE_VERSION = 2
|
|
|
|
def __init__( self, shortcut_type = None, shortcut_key = None, modifiers = None ):
|
|
|
|
if shortcut_type is None:
|
|
|
|
shortcut_type = CC.SHORTCUT_TYPE_KEYBOARD_SPECIAL
|
|
|
|
|
|
if shortcut_key is None:
|
|
|
|
shortcut_key = CC.SHORTCUT_KEY_SPECIAL_F7
|
|
|
|
|
|
if modifiers is None:
|
|
|
|
modifiers = []
|
|
|
|
|
|
if shortcut_type == CC.SHORTCUT_TYPE_KEYBOARD_CHARACTER and ClientData.OrdIsAlphaUpper( shortcut_key ):
|
|
|
|
shortcut_key += 32 # convert A to a
|
|
|
|
|
|
modifiers.sort()
|
|
|
|
HydrusSerialisable.SerialisableBase.__init__( self )
|
|
|
|
self._shortcut_type = shortcut_type
|
|
self._shortcut_key = shortcut_key
|
|
self._modifiers = modifiers
|
|
|
|
|
|
def __eq__( self, other ):
|
|
|
|
if isinstance( other, Shortcut ):
|
|
|
|
return self.__hash__() == other.__hash__()
|
|
|
|
|
|
return NotImplemented
|
|
|
|
|
|
def __hash__( self ):
|
|
|
|
return ( self._shortcut_type, self._shortcut_key, tuple( self._modifiers ) ).__hash__()
|
|
|
|
|
|
def __repr__( self ):
|
|
|
|
return 'Shortcut: ' + self.ToString()
|
|
|
|
|
|
def _GetSerialisableInfo( self ):
|
|
|
|
return ( self._shortcut_type, self._shortcut_key, self._modifiers )
|
|
|
|
|
|
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
|
|
|
|
( self._shortcut_type, self._shortcut_key, self._modifiers ) = serialisable_info
|
|
|
|
|
|
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 = {
|
|
32 : CC.SHORTCUT_KEY_SPECIAL_SPACE,
|
|
8 : CC.SHORTCUT_KEY_SPECIAL_BACKSPACE,
|
|
9 : CC.SHORTCUT_KEY_SPECIAL_TAB,
|
|
13 : CC.SHORTCUT_KEY_SPECIAL_RETURN,
|
|
310 : CC.SHORTCUT_KEY_SPECIAL_PAUSE,
|
|
27 : CC.SHORTCUT_KEY_SPECIAL_ESCAPE,
|
|
322 : CC.SHORTCUT_KEY_SPECIAL_INSERT,
|
|
127 : CC.SHORTCUT_KEY_SPECIAL_DELETE,
|
|
315 : CC.SHORTCUT_KEY_SPECIAL_UP,
|
|
317 : CC.SHORTCUT_KEY_SPECIAL_DOWN,
|
|
314 : CC.SHORTCUT_KEY_SPECIAL_LEFT,
|
|
316 : CC.SHORTCUT_KEY_SPECIAL_RIGHT,
|
|
313 : CC.SHORTCUT_KEY_SPECIAL_HOME,
|
|
312 : CC.SHORTCUT_KEY_SPECIAL_END,
|
|
367 : CC.SHORTCUT_KEY_SPECIAL_PAGE_DOWN,
|
|
366 : CC.SHORTCUT_KEY_SPECIAL_PAGE_UP,
|
|
340 : CC.SHORTCUT_KEY_SPECIAL_F1,
|
|
341 : CC.SHORTCUT_KEY_SPECIAL_F2,
|
|
342 : CC.SHORTCUT_KEY_SPECIAL_F3,
|
|
343 : CC.SHORTCUT_KEY_SPECIAL_F4,
|
|
344 : CC.SHORTCUT_KEY_SPECIAL_F5,
|
|
345 : CC.SHORTCUT_KEY_SPECIAL_F6,
|
|
346 : CC.SHORTCUT_KEY_SPECIAL_F7,
|
|
347 : CC.SHORTCUT_KEY_SPECIAL_F8,
|
|
348 : CC.SHORTCUT_KEY_SPECIAL_F9,
|
|
349 : CC.SHORTCUT_KEY_SPECIAL_F10,
|
|
350 : CC.SHORTCUT_KEY_SPECIAL_F11,
|
|
351 : CC.SHORTCUT_KEY_SPECIAL_F12
|
|
}
|
|
|
|
# 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' ),
|
|
333 : ord( '9' ),
|
|
388 : ord( '+' ),
|
|
392 : ord( '/' ),
|
|
390 : ord( '-' ),
|
|
387 : ord( '*' ),
|
|
391 : ord( '.' )
|
|
}
|
|
|
|
wx_to_qt_numpad_conversion = {
|
|
377 : CC.SHORTCUT_KEY_SPECIAL_UP,
|
|
379 : CC.SHORTCUT_KEY_SPECIAL_DOWN,
|
|
376 : CC.SHORTCUT_KEY_SPECIAL_LEFT,
|
|
378 : CC.SHORTCUT_KEY_SPECIAL_RIGHT,
|
|
375 : CC.SHORTCUT_KEY_SPECIAL_HOME,
|
|
382 : CC.SHORTCUT_KEY_SPECIAL_END,
|
|
381 : CC.SHORTCUT_KEY_SPECIAL_PAGE_DOWN,
|
|
380 : CC.SHORTCUT_KEY_SPECIAL_PAGE_UP,
|
|
385 : CC.SHORTCUT_KEY_SPECIAL_DELETE,
|
|
370 : CC.SHORTCUT_KEY_SPECIAL_ENTER
|
|
}
|
|
|
|
( shortcut_type, shortcut_key, modifiers ) = old_serialisable_info
|
|
|
|
if shortcut_type == CC.SHORTCUT_TYPE_KEYBOARD_CHARACTER:
|
|
|
|
if shortcut_key in wx_to_qt_flat_conversion:
|
|
|
|
shortcut_type = CC.SHORTCUT_TYPE_KEYBOARD_SPECIAL
|
|
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 )
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_KEYPAD )
|
|
|
|
modifiers.sort()
|
|
|
|
elif shortcut_key in wx_to_qt_numpad_conversion:
|
|
|
|
shortcut_type = CC.SHORTCUT_TYPE_KEYBOARD_SPECIAL
|
|
shortcut_key = wx_to_qt_numpad_conversion[ shortcut_key ]
|
|
|
|
modifiers = list( modifiers )
|
|
|
|
modifiers.append( CC.SHORTCUT_MODIFIER_KEYPAD )
|
|
|
|
modifiers.sort()
|
|
|
|
|
|
|
|
if shortcut_type == CC.SHORTCUT_TYPE_KEYBOARD_CHARACTER:
|
|
|
|
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 )
|
|
|
|
|
|
|
|
def GetShortcutType( self ):
|
|
|
|
return self._shortcut_type
|
|
|
|
|
|
def ToString( self ):
|
|
|
|
components = []
|
|
|
|
if CC.SHORTCUT_MODIFIER_CTRL in self._modifiers:
|
|
|
|
components.append( 'ctrl' )
|
|
|
|
|
|
if CC.SHORTCUT_MODIFIER_ALT in self._modifiers:
|
|
|
|
components.append( 'alt' )
|
|
|
|
|
|
if CC.SHORTCUT_MODIFIER_SHIFT in self._modifiers:
|
|
|
|
components.append( 'shift' )
|
|
|
|
|
|
if CC.SHORTCUT_MODIFIER_GROUP_SWITCH in self._modifiers:
|
|
|
|
components.append( 'Mode_switch' )
|
|
|
|
|
|
if self._shortcut_type == CC.SHORTCUT_TYPE_MOUSE and self._shortcut_key in CC.shortcut_mouse_string_lookup:
|
|
|
|
components.append( CC.shortcut_mouse_string_lookup[ self._shortcut_key ] )
|
|
|
|
elif self._shortcut_type == CC.SHORTCUT_TYPE_KEYBOARD_SPECIAL and self._shortcut_key in CC.special_key_shortcut_str_lookup:
|
|
|
|
components.append( CC.special_key_shortcut_str_lookup[ self._shortcut_key ] )
|
|
|
|
elif self._shortcut_type == CC.SHORTCUT_TYPE_KEYBOARD_CHARACTER:
|
|
|
|
try:
|
|
|
|
if ClientData.OrdIsAlphaUpper( self._shortcut_key ):
|
|
|
|
components.append( chr( self._shortcut_key + 32 ) ) # + 32 for converting ascii A -> a
|
|
|
|
else:
|
|
|
|
components.append( chr( self._shortcut_key ) )
|
|
|
|
|
|
except:
|
|
|
|
components.append( 'unknown key: {}'.format( repr( self._shortcut_key ) ) )
|
|
|
|
|
|
else:
|
|
|
|
components.append( 'unknown key: {}'.format( repr( self._shortcut_key ) ) )
|
|
|
|
|
|
s = '+'.join( components )
|
|
|
|
if CC.SHORTCUT_MODIFIER_KEYPAD in self._modifiers:
|
|
|
|
s += ' (on numpad)'
|
|
|
|
|
|
return s
|
|
|
|
|
|
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT ] = Shortcut
|
|
|
|
class ShortcutPanel( QW.QWidget ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
QW.QWidget.__init__( self, parent )
|
|
|
|
self._mouse_radio = QW.QRadioButton( 'mouse', self )
|
|
self._mouse_shortcut = ShortcutMouse( self, self._mouse_radio )
|
|
|
|
self._keyboard_radio = QW.QRadioButton( 'keyboard', self )
|
|
self._keyboard_shortcut = ShortcutKeyboard( self, self._keyboard_radio )
|
|
|
|
#
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( vbox, ClientGUICommon.BetterStaticText(self,'Mouse events only work for the duplicate and archive/delete filters atm!'), CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
gridbox = QP.GridLayout( cols = 2 )
|
|
|
|
gridbox.setColumnStretch( 1, 1 )
|
|
|
|
QP.AddToLayout( gridbox, self._mouse_radio, CC.FLAGS_VCENTER )
|
|
QP.AddToLayout( gridbox, self._mouse_shortcut, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( gridbox, self._keyboard_radio, CC.FLAGS_VCENTER )
|
|
QP.AddToLayout( gridbox, self._keyboard_shortcut, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.setLayout( vbox )
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
if self._mouse_radio.isChecked():
|
|
|
|
return self._mouse_shortcut.GetValue()
|
|
|
|
else:
|
|
|
|
return self._keyboard_shortcut.GetValue()
|
|
|
|
|
|
|
|
def SetValue( self, shortcut ):
|
|
|
|
if shortcut.GetShortcutType() == CC.SHORTCUT_TYPE_MOUSE:
|
|
|
|
self._mouse_radio.setChecked( True )
|
|
self._mouse_shortcut.SetValue( shortcut )
|
|
|
|
else:
|
|
|
|
self._keyboard_radio.setChecked( True )
|
|
self._keyboard_shortcut.SetValue( shortcut )
|
|
|
|
|
|
|
|
class ShortcutKeyboard( QW.QLineEdit ):
|
|
|
|
def __init__( self, parent, related_radio = None ):
|
|
|
|
self._shortcut = Shortcut()
|
|
|
|
self._related_radio = related_radio
|
|
|
|
QW.QLineEdit.__init__( self, parent )
|
|
|
|
self._SetShortcutString()
|
|
|
|
|
|
def _SetShortcutString( self ):
|
|
|
|
display_string = self._shortcut.ToString()
|
|
|
|
self.setText( display_string )
|
|
|
|
|
|
def keyPressEvent( self, event ):
|
|
|
|
shortcut = ConvertKeyEventToShortcut( event )
|
|
|
|
if shortcut is not None:
|
|
|
|
self._shortcut = shortcut
|
|
|
|
if self._related_radio is not None:
|
|
|
|
self._related_radio.setChecked( True )
|
|
|
|
|
|
self._SetShortcutString()
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
return self._shortcut
|
|
|
|
|
|
def SetValue( self, shortcut ):
|
|
|
|
self._shortcut = shortcut
|
|
|
|
self._SetShortcutString()
|
|
|
|
|
|
class ShortcutMouse( QW.QPushButton ):
|
|
|
|
def __init__( self, parent, related_radio = None ):
|
|
|
|
self._shortcut = Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_LEFT, [] )
|
|
|
|
self._related_radio = related_radio
|
|
|
|
QW.QPushButton.__init__( self, parent )
|
|
|
|
self._SetShortcutString()
|
|
|
|
|
|
def _SetShortcutString( self ):
|
|
|
|
display_string = self._shortcut.ToString()
|
|
|
|
self.setText( display_string )
|
|
|
|
|
|
def mousePressEvent( self, event ):
|
|
|
|
self.EventMouse( event )
|
|
|
|
def mouseDoubleClickEvent( self, event ):
|
|
|
|
self.EventMouse( event )
|
|
|
|
def EventMouse( self, event ):
|
|
|
|
self.setFocus( QC.Qt.OtherFocusReason )
|
|
|
|
shortcut = ConvertMouseEventToShortcut( event )
|
|
|
|
if shortcut is not None:
|
|
|
|
self._shortcut = shortcut
|
|
|
|
if self._related_radio is not None:
|
|
|
|
self._related_radio.setChecked( True )
|
|
|
|
|
|
self._SetShortcutString()
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
return self._shortcut
|
|
|
|
|
|
def SetValue( self, shortcut ):
|
|
|
|
self._shortcut = shortcut
|
|
|
|
self._SetShortcutString()
|
|
|
|
|
|
|
|
class ShortcutSet( HydrusSerialisable.SerialisableBaseNamed ):
|
|
|
|
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT_SET
|
|
SERIALISABLE_NAME = 'Shortcut Set'
|
|
SERIALISABLE_VERSION = 2
|
|
|
|
def __init__( self, name ):
|
|
|
|
HydrusSerialisable.SerialisableBaseNamed.__init__( self, name )
|
|
|
|
self._shortcuts_to_commands = {}
|
|
|
|
|
|
def __iter__( self ):
|
|
|
|
for ( shortcut, command ) in list( self._shortcuts_to_commands.items() ):
|
|
|
|
yield ( shortcut, command )
|
|
|
|
|
|
|
|
def __len__( self ):
|
|
|
|
return len( self._shortcuts_to_commands )
|
|
|
|
|
|
def _GetSerialisableInfo( self ):
|
|
|
|
return [ ( shortcut.GetSerialisableTuple(), command.GetSerialisableTuple() ) for ( shortcut, command ) in list(self._shortcuts_to_commands.items()) ]
|
|
|
|
|
|
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:
|
|
|
|
# no longer updating modifier, as that was wx legacy
|
|
|
|
modifiers = []
|
|
|
|
shortcut = Shortcut( CC.SHORTCUT_TYPE_KEYBOARD_CHARACTER, key, modifiers )
|
|
|
|
if serialisable_service_key is None:
|
|
|
|
command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, data )
|
|
|
|
else:
|
|
|
|
service_key = bytes.fromhex( serialisable_service_key )
|
|
|
|
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()
|
|
|
|
if service_type in HC.TAG_SERVICES:
|
|
|
|
content_type = HC.CONTENT_TYPE_MAPPINGS
|
|
|
|
elif service_type in HC.RATINGS_SERVICES:
|
|
|
|
content_type = HC.CONTENT_TYPE_RATINGS
|
|
|
|
else:
|
|
|
|
continue
|
|
|
|
|
|
command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, content_type, action, value ) )
|
|
|
|
|
|
shortcuts_to_commands[ shortcut ] = command
|
|
|
|
|
|
new_serialisable_info = ( ( shortcut.GetSerialisableTuple(), command.GetSerialisableTuple() ) for ( shortcut, command ) in list(shortcuts_to_commands.items()) )
|
|
|
|
return ( 2, new_serialisable_info )
|
|
|
|
|
|
|
|
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 ):
|
|
|
|
shortcuts = []
|
|
|
|
for ( shortcut, command ) in self._shortcuts_to_commands.items():
|
|
|
|
if command.GetCommandType() == CC.APPLICATION_COMMAND_TYPE_SIMPLE and command.GetData() == simple_command:
|
|
|
|
shortcuts.append( shortcut )
|
|
|
|
|
|
|
|
return shortcuts
|
|
|
|
|
|
def SetCommand( self, shortcut, command ):
|
|
|
|
self._shortcuts_to_commands[ shortcut ] = command
|
|
|
|
|
|
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT_SET ] = ShortcutSet
|
|
|
|
class ShortcutsHandler( QC.QObject ):
|
|
|
|
def __init__( self, parent, initial_shortcuts_names = None ):
|
|
|
|
QC.QObject.__init__( self, parent )
|
|
|
|
if initial_shortcuts_names is None:
|
|
|
|
initial_shortcuts_names = []
|
|
|
|
|
|
self._parent = parent
|
|
self._parent.installEventFilter( self )
|
|
self._shortcuts_names = list( initial_shortcuts_names )
|
|
|
|
|
|
def _ProcessShortcut( self, shortcut ):
|
|
|
|
shortcut_processed = False
|
|
|
|
command = HG.client_controller.GetCommandFromShortcut( self._shortcuts_names, shortcut )
|
|
|
|
if command is not None:
|
|
|
|
command_processed = self._parent.ProcessApplicationCommand( command )
|
|
|
|
if command_processed:
|
|
|
|
shortcut_processed = True
|
|
|
|
|
|
if HG.shortcut_report_mode:
|
|
|
|
message = 'Shortcut "' + shortcut.ToString() + '" matched to command "' + command.ToString() + '" on ' + repr( self._parent ) + '.'
|
|
|
|
if command_processed:
|
|
|
|
message += ' It was processed.'
|
|
|
|
else:
|
|
|
|
message += ' It was not processed.'
|
|
|
|
|
|
HydrusData.ShowText( message )
|
|
|
|
|
|
|
|
return shortcut_processed
|
|
|
|
|
|
def eventFilter( self, watched, event ):
|
|
|
|
if event.type() == QC.QEvent.KeyPress:
|
|
|
|
shortcut = ConvertKeyEventToShortcut( event )
|
|
|
|
if shortcut is not None:
|
|
|
|
if HG.shortcut_report_mode:
|
|
|
|
message = 'Key shortcut "' + shortcut.ToString() + '" passing through ' + repr( self._parent ) + '.'
|
|
|
|
if IShouldCatchShortcutEvent( self._parent, event = 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 IShouldCatchShortcutEvent( self._parent, event = event ):
|
|
|
|
shortcut_processed = self._ProcessShortcut( shortcut )
|
|
|
|
if shortcut_processed:
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
def AddShortcuts( self, shortcut_set_name ):
|
|
|
|
if shortcut_set_name not in self._shortcuts_names:
|
|
|
|
self._shortcuts_names.append( shortcut_set_name )
|
|
|
|
|
|
|
|
def RemoveShortcuts( self, shortcut_set_name ):
|
|
|
|
if shortcut_set_name in self._shortcuts_names:
|
|
|
|
self._shortcuts_names.remove( shortcut_set_name )
|
|
|
|
|
|
|
|
class ShortcutsManager( object ):
|
|
|
|
def __init__( self, controller ):
|
|
|
|
self._controller = controller
|
|
|
|
self._shortcuts = {}
|
|
|
|
self._RefreshShortcuts()
|
|
|
|
self._controller.sub( self, 'RefreshShortcuts', 'notify_new_shortcuts_data' )
|
|
|
|
|
|
def _RefreshShortcuts( self ):
|
|
|
|
self._shortcuts = {}
|
|
|
|
all_shortcuts = HG.client_controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT_SET )
|
|
|
|
for shortcuts in all_shortcuts:
|
|
|
|
self._shortcuts[ shortcuts.GetName() ] = shortcuts
|
|
|
|
|
|
|
|
def GetCommand( self, shortcuts_names, shortcut ):
|
|
|
|
for name in shortcuts_names:
|
|
|
|
if name in self._shortcuts:
|
|
|
|
command = self._shortcuts[ name ].GetCommand( shortcut )
|
|
|
|
if command is not None:
|
|
|
|
if HG.gui_report_mode:
|
|
|
|
HydrusData.ShowText( 'command matched: ' + repr( command ) )
|
|
|
|
|
|
return command
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
def GetNamesToShortcuts( self, simple_command ):
|
|
|
|
names_to_shortcuts = {}
|
|
|
|
for ( name, shortcut_set ) in self._shortcuts.items():
|
|
|
|
shortcuts = shortcut_set.GetShortcuts( simple_command )
|
|
|
|
if len( shortcuts ) > 0:
|
|
|
|
names_to_shortcuts[ name ] = shortcuts
|
|
|
|
|
|
|
|
return names_to_shortcuts
|
|
|
|
|
|
def RefreshShortcuts( self ):
|
|
|
|
self._RefreshShortcuts()
|
|
|
|
HG.client_controller.pub( 'notify_new_shortcuts_gui' )
|
|
|
|
|