2019-01-09 22:59:03 +00:00
from . import ClientConstants as CC
from . import ClientData
from . import ClientGUICommon
from . import HydrusConstants as HC
from . import HydrusData
from . import HydrusGlobals as HG
from . import HydrusSerialisable
2017-03-29 19:39:34 +00:00
import wx
2017-11-22 21:03:07 +00:00
FLASHWIN_OK = False
2017-05-31 21:50:53 +00:00
if HC . PLATFORM_WINDOWS :
2017-11-22 21:03:07 +00:00
try :
import wx . lib . flashwin
FLASHWIN_OK = True
except Exception as e :
pass
2017-05-31 21:50:53 +00:00
2018-05-16 20:09:50 +00:00
def ConvertKeyEventToShortcut ( event ) :
key = event . KeyCode
2019-01-09 22:59:03 +00:00
if ClientData . OrdIsSensibleASCII ( key ) or key in list ( CC . wxk_code_string_lookup . keys ( ) ) :
2018-05-16 20:09:50 +00:00
modifiers = [ ]
if event . AltDown ( ) :
modifiers . append ( CC . SHORTCUT_MODIFIER_ALT )
if event . CmdDown ( ) :
modifiers . append ( CC . SHORTCUT_MODIFIER_CTRL )
if event . ShiftDown ( ) :
modifiers . append ( CC . SHORTCUT_MODIFIER_SHIFT )
shortcut = Shortcut ( CC . SHORTCUT_TYPE_KEYBOARD , key , modifiers )
if HG . gui_report_mode :
HydrusData . ShowText ( ' key event caught: ' + repr ( shortcut ) )
return shortcut
return None
def ConvertKeyEventToSimpleTuple ( event ) :
modifier = wx . ACCEL_NORMAL
if event . AltDown ( ) : modifier = wx . ACCEL_ALT
elif event . CmdDown ( ) : modifier = wx . ACCEL_CTRL
elif event . ShiftDown ( ) : modifier = wx . ACCEL_SHIFT
key = event . KeyCode
return ( modifier , key )
def ConvertMouseEventToShortcut ( event ) :
key = None
if event . LeftDown ( ) or event . LeftDClick ( ) :
key = CC . SHORTCUT_MOUSE_LEFT
elif event . MiddleDown ( ) or event . MiddleDClick ( ) :
key = CC . SHORTCUT_MOUSE_MIDDLE
elif event . RightDown ( ) or event . RightDClick ( ) :
key = CC . SHORTCUT_MOUSE_RIGHT
elif event . GetWheelRotation ( ) > 0 :
key = CC . SHORTCUT_MOUSE_SCROLL_UP
elif event . GetWheelRotation ( ) < 0 :
key = CC . SHORTCUT_MOUSE_SCROLL_DOWN
if key is not None :
modifiers = [ ]
if event . AltDown ( ) :
modifiers . append ( CC . SHORTCUT_MODIFIER_ALT )
if event . CmdDown ( ) :
modifiers . append ( CC . SHORTCUT_MODIFIER_CTRL )
if event . ShiftDown ( ) :
modifiers . append ( CC . SHORTCUT_MODIFIER_SHIFT )
shortcut = Shortcut ( CC . SHORTCUT_TYPE_MOUSE , key , modifiers )
if HG . gui_report_mode :
HydrusData . ShowText ( ' mouse event caught: ' + repr ( shortcut ) )
return shortcut
return None
2017-04-19 20:58:30 +00:00
def IShouldCatchCharHook ( evt_handler ) :
2017-11-22 21:03:07 +00:00
if HC . PLATFORM_WINDOWS and FLASHWIN_OK :
2017-05-31 21:50:53 +00:00
window = wx . FindWindowAtPointer ( )
if window is not None and isinstance ( window , wx . lib . flashwin . FlashWindow ) :
return False
2017-04-19 20:58:30 +00:00
if not ClientGUICommon . WindowOrSameTLPChildHasFocus ( evt_handler ) :
return False
return True
2018-05-16 20:09:50 +00:00
class Shortcut ( HydrusSerialisable . SerialisableBase ) :
SERIALISABLE_TYPE = HydrusSerialisable . SERIALISABLE_TYPE_SHORTCUT
SERIALISABLE_NAME = ' Shortcut '
SERIALISABLE_VERSION = 1
def __init__ ( self , shortcut_type = None , shortcut_key = None , modifiers = None ) :
if shortcut_type is None :
shortcut_type = CC . SHORTCUT_TYPE_KEYBOARD
if shortcut_key is None :
shortcut_key = wx . WXK_F7
if modifiers is None :
modifiers = [ ]
modifiers . sort ( )
HydrusSerialisable . SerialisableBase . __init__ ( self )
self . _shortcut_type = shortcut_type
self . _shortcut_key = shortcut_key
self . _modifiers = modifiers
def __eq__ ( self , other ) :
return self . __hash__ ( ) == other . __hash__ ( )
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 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 self . _shortcut_type == CC . SHORTCUT_TYPE_KEYBOARD :
if self . _shortcut_key in CC . wxk_code_string_lookup :
components . append ( CC . wxk_code_string_lookup [ self . _shortcut_key ] )
elif ClientData . OrdIsAlphaUpper ( self . _shortcut_key ) :
components . append ( chr ( self . _shortcut_key + 32 ) ) # + 32 for converting ascii A -> a
elif ClientData . OrdIsSensibleASCII ( self . _shortcut_key ) :
components . append ( chr ( self . _shortcut_key ) )
else :
components . append ( ' unknown key ' )
elif self . _shortcut_type == CC . SHORTCUT_TYPE_MOUSE :
components . append ( CC . shortcut_mouse_string_lookup [ self . _shortcut_key ] )
return ' + ' . join ( components )
HydrusSerialisable . SERIALISABLE_TYPES_TO_OBJECT_TYPES [ HydrusSerialisable . SERIALISABLE_TYPE_SHORTCUT ] = Shortcut
class ShortcutPanel ( wx . Panel ) :
def __init__ ( self , parent ) :
wx . Panel . __init__ ( self , parent )
self . _mouse_radio = wx . RadioButton ( self , style = wx . RB_GROUP , label = ' mouse ' )
self . _mouse_shortcut = ShortcutMouse ( self , self . _mouse_radio )
self . _keyboard_radio = wx . RadioButton ( self , label = ' keyboard ' )
self . _keyboard_shortcut = ShortcutKeyboard ( self , self . _keyboard_radio )
#
vbox = wx . BoxSizer ( wx . VERTICAL )
vbox . Add ( ClientGUICommon . BetterStaticText ( self , ' Mouse events only work for the duplicate and archive/delete filters atm! ' ) , CC . FLAGS_EXPAND_PERPENDICULAR )
gridbox = wx . FlexGridSizer ( 2 )
gridbox . AddGrowableCol ( 1 , 1 )
gridbox . Add ( self . _mouse_radio , CC . FLAGS_VCENTER )
gridbox . Add ( self . _mouse_shortcut , CC . FLAGS_EXPAND_BOTH_WAYS )
gridbox . Add ( self . _keyboard_radio , CC . FLAGS_VCENTER )
gridbox . Add ( self . _keyboard_shortcut , CC . FLAGS_EXPAND_BOTH_WAYS )
vbox . Add ( gridbox , CC . FLAGS_EXPAND_BOTH_WAYS )
self . SetSizer ( vbox )
def GetValue ( self ) :
if self . _mouse_radio . GetValue ( ) == True :
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 . SetValue ( True )
self . _mouse_shortcut . SetValue ( shortcut )
else :
self . _keyboard_radio . SetValue ( True )
self . _keyboard_shortcut . SetValue ( shortcut )
class ShortcutKeyboard ( wx . TextCtrl ) :
def __init__ ( self , parent , related_radio = None ) :
self . _shortcut = Shortcut ( CC . SHORTCUT_TYPE_KEYBOARD , wx . WXK_F7 , [ ] )
self . _related_radio = related_radio
wx . TextCtrl . __init__ ( self , parent , style = wx . TE_PROCESS_ENTER )
self . Bind ( wx . EVT_KEY_DOWN , self . EventKeyDown )
self . _SetShortcutString ( )
def _SetShortcutString ( self ) :
display_string = self . _shortcut . ToString ( )
wx . TextCtrl . SetValue ( self , display_string )
def EventKeyDown ( self , event ) :
shortcut = ConvertKeyEventToShortcut ( event )
if shortcut is not None :
self . _shortcut = shortcut
if self . _related_radio is not None :
self . _related_radio . SetValue ( True )
self . _SetShortcutString ( )
def GetValue ( self ) :
return self . _shortcut
def SetValue ( self , shortcut ) :
self . _shortcut = shortcut
self . _SetShortcutString ( )
class ShortcutMouse ( wx . Button ) :
def __init__ ( self , parent , related_radio = None ) :
self . _shortcut = Shortcut ( CC . SHORTCUT_TYPE_MOUSE , CC . SHORTCUT_MOUSE_LEFT , [ ] )
self . _related_radio = related_radio
wx . Button . __init__ ( self , parent )
self . Bind ( wx . EVT_MOUSE_EVENTS , self . EventMouse )
self . _SetShortcutString ( )
def _SetShortcutString ( self ) :
display_string = self . _shortcut . ToString ( )
self . SetLabel ( display_string )
def EventMouse ( self , event ) :
self . SetFocus ( )
shortcut = ConvertMouseEventToShortcut ( event )
if shortcut is not None :
self . _shortcut = shortcut
if self . _related_radio is not None :
self . _related_radio . SetValue ( True )
self . _SetShortcutString ( )
def GetValue ( self ) :
return self . _shortcut
def SetValue ( self , shortcut ) :
self . _shortcut = shortcut
self . _SetShortcutString ( )
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 :
if modifier not in CC . shortcut_wx_to_hydrus_lookup :
modifiers = [ ]
else :
modifiers = [ CC . shortcut_wx_to_hydrus_lookup [ modifier ] ]
shortcut = Shortcut ( CC . SHORTCUT_TYPE_KEYBOARD , key , modifiers )
if serialisable_service_key is None :
command = ClientData . ApplicationCommand ( CC . APPLICATION_COMMAND_TYPE_SIMPLE , data )
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 ( )
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
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 )
def GetCommand ( self , shortcut ) :
if shortcut in self . _shortcuts_to_commands :
return self . _shortcuts_to_commands [ shortcut ]
else :
return None
2019-06-05 19:42:39 +00:00
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
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
2017-03-29 19:39:34 +00:00
class ShortcutsHandler ( object ) :
2018-03-14 21:01:02 +00:00
def __init__ ( self , parent , initial_shortcuts_names = None ) :
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
if initial_shortcuts_names is None :
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
initial_shortcuts_names = [ ]
2017-03-29 19:39:34 +00:00
self . _parent = parent
2018-03-14 21:01:02 +00:00
self . _shortcuts_names = list ( initial_shortcuts_names )
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
self . _parent . Bind ( wx . EVT_CHAR_HOOK , self . EventCharHook )
#self._parent.Bind( wx.EVT_MOUSE_EVENTS, self.EventMouse ) # let's not mess with this until we are doing something clever with it
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 )
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 :
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 )
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
def EventCharHook ( self , event ) :
2018-05-16 20:09:50 +00:00
shortcut = ConvertKeyEventToShortcut ( event )
2018-03-22 00:03:33 +00:00
if shortcut is not None :
2018-03-14 21:01:02 +00:00
2018-03-22 00:03:33 +00:00
if HG . shortcut_report_mode :
message = ' Key shortcut " ' + shortcut . ToString ( ) + ' " passing through ' + repr ( self . _parent ) + ' . '
if IShouldCatchCharHook ( self . _parent ) :
message + = ' I am in a state to catch it. '
else :
message + = ' I am not in a state to catch it. '
HydrusData . ShowText ( message )
2018-03-14 21:01:02 +00:00
2018-03-22 00:03:33 +00:00
if IShouldCatchCharHook ( self . _parent ) :
2018-03-14 21:01:02 +00:00
shortcut_processed = self . _ProcessShortcut ( shortcut )
if shortcut_processed :
return
2017-03-29 19:39:34 +00:00
event . Skip ( )
def EventMouse ( self , event ) :
2018-05-16 20:09:50 +00:00
shortcut = ConvertMouseEventToShortcut ( event )
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
if shortcut is not None :
shortcut_processed = self . _ProcessShortcut ( shortcut )
if shortcut_processed :
return
2017-03-29 19:39:34 +00:00
event . Skip ( )
2018-03-14 21:01:02 +00:00
def AddShortcuts ( self , shortcuts_name ) :
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
if shortcuts_name not in self . _shortcuts_names :
self . _shortcuts_names . append ( shortcuts_name )
2017-03-29 19:39:34 +00:00
def RemoveShortcuts ( self , shortcuts_name ) :
2018-03-14 21:01:02 +00:00
if shortcuts_name in self . _shortcuts_names :
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
self . _shortcuts_names . remove ( shortcuts_name )
2017-03-29 19:39:34 +00:00
2018-05-16 20:09:50 +00:00
2019-06-05 19:42:39 +00:00
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 ' )