Version 252

This commit is contained in:
Hydrus Network Developer 2017-04-19 15:58:30 -05:00
parent b4049ccb7f
commit d29afc70bd
32 changed files with 2779 additions and 2268 deletions

View File

@ -50,12 +50,10 @@
<p>New files that you import will also be checked against your archive syncs, keeping you up to date.</p>
<p>You can get some archives users have created <a href="https://www.mediafire.com/folder/yoy1dx6or0tnr/tag_archives">here</a>.</p>
<p>Be careful with this tool! If you have tens of thousands of files and sync with an archive that has tens of millions of mappings, you may end up adding a whole lot of tags. It may take several minutes to initialise the sync as well. Make sure your namespaces are set exactly how you want before you click OK on the dialog.</p>
<h3>custom filter</h3>
<p>Once you are comfortable with the client's tagging and rating, you may be interested in performing a <i>custom filter</i>, which is essentially the fullscreen browser with custom shortcuts. You select it from the regular thumbnail right-click menu. First, it will show you a dialog:</p>
<p><img src="custom_filter.png" /></p>
<p>You can reassign the default shortcuts for regular things, like archive/delete and opening tag/ratings dialogs, and also add shortcuts for adding/removing a tag or setting/unsetting a rating. Shortcuts do not yet combine; they overwrite.</p>
<p>Once you hit ok on the parent dialog, the fullscreen browser will launch. Navigation and zooming happens as normal with the mouse and keyboard, unless you have overwritten a shortcut! Hitting any of the shortcuts you declared should carry out the action. Tags will pend/rescind pend or petition/rescind petition or add/delete as appropriate to the type of tag service and the tag's status for the particular file.</p>
<p>I plan to improve custom filters a lot in future. Let me know what you think!</p>
<h3>custom shortcuts</h3>
<p>Once you are comfortable with manually setting tags and ratings, you may be interested in setting some shortcuts to do it quicker. Try hitting <i>file->shortcuts</i> or clicking the keyboard icon on any media viewer window's top hover window.</p>
<p>There are two kinds of shortcuts in the program--<i>reserved</i>, which have fixed names, are undeletable, and are always active in certain contexts (related to their name), and <i>custom</i>, which you create and name and edit and are only active in a media viewer when you want them to. You can redefine some simple shortcut commands, but most importantly, you can create shortcuts for adding/removing a tag or setting/unsetting a rating.</p>
<p>Use the same 'keyboard' icon to set the current and default custom shortcuts. </p>
<h3>finding duplicates</h3>
<p>system:similar_to takes two arguments: a hash and an integer representing max hamming distance (0 means exactly the same, 64 means everything. 5 is good for finding dupes). You can quick-select it from a file's right-click menu. It returns all images that are <i>very</i> similar to the hash. For example:</p>
<p>Here are a couple of duplicates, found despite their different resolution.</p>

View File

@ -8,6 +8,50 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 252</h3></li>
<ul>
<li>the duplicate filter now processes pairs in batches and hence supports 'back' actions to revisit decisions. you will be prompted every fifty or so pairs to commit and checkpoint your progress</li>
<li>the duplicate filter now presents related pairs together, rather than picking at random</li>
<li>fixed a bug in duplicate filter shortcuts initialisation</li>
<li>simplified duplicate filter default shortcuts (these will be overwritten on update) to only use simple left- and right-click for 'this is better' and 'alternates', since those are by far the most common actions. middle-click now goes back, like the archive/delete filter</li>
<li>converted old 'main shortcuts' system to the new shortcuts system, also splitting it up into 'media', 'main_gui', 'media_viewer', and 'media_viewer_browser' constituent parts that will be applied in different contexts</li>
<li>because the change is so significant, all clients will have their old 'options' shortcuts reset to the new default--I expect to expand shortcuts further in the next few weeks, so this default-overwriting will likely happen again, so you will likely wish to wait before recustomising your basic shortcuts</li>
<li>completely eliminated the old main shortcuts system--all references now bodge with the new system to varying neatness</li>
<li>as the old main shortcuts system no longer exists, the 'shortcuts' page on file->options is gone--all shortcuts are now managed through file->shortcuts, which is a completely revamped version of the custom filter shortcuts editing dialog</li>
<li>selecting shortcut commands is significantly simpler for the reserved shortcut sets</li>
<li>all media viewers with hover windows now have a 'keyboard' shortcuts icon button on their top hover window--it links to the manage shortcuts dialog as well as the current active custom shortcut sets and default custom shortcut sets</li>
<li>as the above system supercedes the old custom filter system, custom filters are completely removed from the program! your existing custom shortcut sets will survive, but you probably want to purge them of all the redundant junk they still have</li>
<li>all the media canvases use the new shortcuts system</li>
<li>the canvas frame uses the new shortcuts system</li>
<li>the thumbnails canvas uses the new shortcuts system</li>
<li>the main gui uses the new shortcuts system</li>
<li>some other misc places use the new shortcuts system</li>
<li>most simple shortcut command actions have been renamed to be more readable</li>
<li>some shortcut actions, like zoom stuff, is no longer hardcoded!</li>
<li>mouse shortcuts are still not widely supported!</li>
<li>the shortcut command edit dialog now throws a veto-driven error message if you try to ok on an invalid command (a blank services choice or action string, that sort of thing)</li>
<li>ctrl+r is now 'remove_files_from_view' by default. the old 'show_hide_splitters' is now ctrl+shift+r by default</li>
<li>the preview canvas, if focused, now responds to many normal media viewer shortcuts (content stuff like archive/manage tags, and canvas-specific like frame back/forth, zooming and panning)</li>
<li>the new shortcut system now interprets double-clicks of any mouse button to be a second single click</li>
<li>the new shortcut system correctly 'flips' ratings on and off, rather than always 'setting' to the chosen value. optional 'set only' support will come in the near future</li>
<li>more shortcuts will correctly and reliably propagate to canvases when any part of a hover frame has focus</li>
<li>fixed a conflict between the new shortcut system and taglists, which were no longer accepting otherwise interesting keys, like enter</li>
<li>created a shortcuts manager cache that deals with a bunch of the shortcut workflow centrally</li>
<li>completely eliminated the old accelerator table/menu command system for the main gui window</li>
<li>lots of misc shortcut-related work</li>
<li>fixed wildcard file search predicates that are on a specific file service and have no namespace (like 'mar*')</li>
<li>certain routines that can cause mass refreshing of the menubar (like import folders) will now not spam (and often queue this spam up and hang the gui) the menu so much. the menubar will now always collapse multple overlapping refresh calls to reduce cpu load</li>
<li>fixed a focus-None issue in the new hover window focus detection code</li>
<li>improved some more focus detection and comparison logic--quick rating-scrolling in the media viewer should be less janked</li>
<li>improved 'touch' drag event detection and improved media canvas cursor hide/show logic in general</li>
<li>fixed '&' display in notebook page names</li>
<li>fixed '&' display in some common dialogs' text</li>
<li>wrote a new statictext class that deals with '&' better and in future will autowrap and maybe some other stuff and then switched most of the simple instances of wx.statictext over</li>
<li>updated some out-of-date server help r.e. admin service initialisation</li>
<li>converted a little of the help on custom filter->custom shortcuts. I'll do more in future</li>
<li>wrote a simple checkboxlist dialog</li>
<li>misc cleanup</li>
</ul>
<li><h3>version 251</h3></li>
<ul>
<li>started shortcut overhaul by updating shortcut storage and underlying objects</li>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@ -17,7 +17,7 @@
<p>The basic process for setting up a server is:</p>
<ul>
<li>Start the server.</li>
<li>Set up your client with its address and initialise the administration interface</li>
<li>Set up your client with its address and initialise the admin account</li>
<li>Set the server's options and services.</li>
<li>Make some accounts for your users.</li>
<li>???</li>
@ -27,16 +27,11 @@
<h3>start the server</h3>
<p>Since the server and client have so much common code, I package them together. If you have the client, you have the server. If you installed in Windows, you can hit the shortcut in your start menu. Otherwise, go straight to 'server' or 'server.exe' or 'server.pyw' in your installation directory. The program will first try to take port 45870 for its administration interface, so make sure that is free. Open your firewall as appropriate.</p>
<h3>set up the client</h3>
<p>In the <i>services->manage services</i> dialog, go to the <i>servers admin</i> tab, give your server admin interface a nickname and set the credentials to:</p>
<ul>
<li>whateveritshostnameis:45870</li>
</ul>
<p>If you are running the server on the same computer as the client, its hostname is 'localhost'.</p>
<p>Ok those changes, and go to <i>review services</i>.</p>
<p>On the page for your new server, hit the initialise button. If you have everything set right, the server should generate its first, administrator account and return the access key, which the client will automatically set to the account for you.</p>
<p class="warning">YOU'LL WANT TO SAVE THAT KEY IN A SAFE PLACE</p>
<p>In the <i>services->manage services</i> dialog, add a new 'hydrus server administration service' and set up the basic options as appropriate. If you are running the server on the same computer as the client, its hostname is 'localhost'.</p>
<p>In order to set up the first admin account and an access key, use 'init' as a registration key. This special registration key will only work to initialise this first super-account.</p>
<p class="warning">YOU'LL WANT TO SAVE YOUR ACCESS KEY IN A SAFE PLACE</p>
<p>If you lose your admin access key, there is no way to get it back, and if you are not sqlite-proficient, you'll have to restart from the beginning by deleting your server's database files.</p>
<p>If the client can't connect to the server, it is either not running or you have a firewall/port-mapping problem. If you want a quick way to test the server's visibility, just put https://host:port into your browser--if it is working, your browser will probably complain about its self-signed https certificate. Once you add a certificate exception, the server should return some simple html identifying itself.</p>
<p>If the client can't connect to the server, it is either not running or you have a firewall/port-mapping problem. If you want a quick way to test the server's visibility, just put https://host:port into your browser (make sure it is https! http will not work)--if it is working, your browser will probably complain about its self-signed https certificate. Once you add a certificate exception, the server should return some simple html identifying itself.</p>
<h3>set up the server</h3>
<p>You should have a new submenu, 'administrate services', under 'services', in the client gui. This is where you control most server and service-wide stuff.</p>
<p><i>admin->your server->manage services</i> lets you add, edit, and delete the services your server runs. Every time you add one, you will also be added as that service's first administrator, and the admin menu will gain a new entry for it.</i>

View File

@ -8,6 +8,7 @@ import HydrusConstants as HC
import HydrusExceptions
import HydrusFileHandling
import HydrusPaths
import HydrusSerialisable
import HydrusSessions
import itertools
import json
@ -2167,6 +2168,49 @@ class ServicesManager( object ):
class ShortcutsManager( object ):
def __init__( self, controller ):
self._controller = controller
self._shortcuts = {}
self.RefreshShortcuts()
self._controller.sub( self, 'RefreshShortcuts', 'new_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:
return command
return None
def RefreshShortcuts( self ):
self._shortcuts = {}
all_shortcuts = HydrusGlobals.client_controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS )
for shortcuts in all_shortcuts:
self._shortcuts[ shortcuts.GetName() ] = shortcuts
class TagCensorshipManager( object ):
def __init__( self, controller ):

View File

@ -257,11 +257,24 @@ shortcut_mouse_string_lookup[ SHORTCUT_MOUSE_SCROLL_DOWN ] = 'scroll down'
SHORTCUT_TYPE_KEYBOARD = 0
SHORTCUT_TYPE_MOUSE = 1
SHORTCUTS_RESERVED_NAMES = [ 'duplicate_filter' ]
SHORTCUTS_RESERVED_NAMES = [ 'duplicate_filter', 'media', 'main_gui', 'media_viewer_browser', 'media_viewer' ]
# shortcut commands
DUPLICATE_FILTER_ACTIONS = [ 'duplicate_filter_this_is_better', 'duplicate_filter_exactly_the_same', 'duplicate_filter_alternates', 'duplicate_filter_not_dupes', 'duplicate_filter_custom_action', 'duplicate_filter_skip' ]
SHORTCUTS_MEDIA_ACTIONS = [ 'manage_file_tags', 'manage_file_ratings', 'archive_file', 'inbox_file', 'delete_file', 'remove_file_from_view', 'open_file_in_external_program', 'launch_the_archive_delete_filter' ]
SHORTCUTS_MEDIA_VIEWER_ACTIONS = [ 'move_animation_to_previous_frame', 'move_animation_to_next_frame', 'switch_between_fullscreen_borderless_and_regular_framed_window', 'pan_up', 'pan_down', 'pan_left', 'pan_right', 'zoom_in', 'zoom_out', 'switch_between_100_percent_and_canvas_zoom' ]
SHORTCUTS_MEDIA_VIEWER_BROWSER_ACTIONS = [ 'view_next', 'view_first', 'view_last', 'view_previous' ]
SHORTCUTS_MAIN_GUI_ACTIONS = [ 'refresh', 'new_page', 'synchronised_wait_switch', 'set_media_focus', 'show_hide_splitters', 'set_search_focus', 'unclose_page', 'close_page', 'redo', 'undo' ]
SHORTCUTS_DUPLICATE_FILTER_ACTIONS = [ 'duplicate_filter_this_is_better', 'duplicate_filter_exactly_the_same', 'duplicate_filter_alternates', 'duplicate_filter_not_dupes', 'duplicate_filter_custom_action', 'duplicate_filter_skip', 'duplicate_filter_back' ]
simple_shortcut_name_to_action_lookup = {}
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
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[ 'custom' ] = SHORTCUTS_MEDIA_ACTIONS + SHORTCUTS_MEDIA_VIEWER_ACTIONS
SHUTDOWN_TIMESTAMP_VACUUM = 0
SHUTDOWN_TIMESTAMP_FATTEN_AC_CACHE = 1
@ -485,6 +498,8 @@ class GlobalBMPs( object ):
GlobalBMPs.dump_fail = wx.Bitmap( os.path.join( HC.STATIC_DIR, 'dump_fail.png' ) )
GlobalBMPs.cog = wx.Bitmap( os.path.join( HC.STATIC_DIR, 'cog.png' ) )
GlobalBMPs.keyboard = wx.Bitmap( os.path.join( HC.STATIC_DIR, 'keyboard.png' ) )
GlobalBMPs.check = wx.Bitmap( os.path.join( HC.STATIC_DIR, 'check.png' ) )
GlobalBMPs.pause = wx.Bitmap( os.path.join( HC.STATIC_DIR, 'pause.png' ) )
GlobalBMPs.play = wx.Bitmap( os.path.join( HC.STATIC_DIR, 'play.png' ) )

View File

@ -491,6 +491,11 @@ class Controller( HydrusController.HydrusController ):
return self._client_session_manager
def GetCommandFromShortcut( self, shortcut_names, shortcut ):
return self._shortcuts_manager.GetCommand( shortcut_names, shortcut )
def GetGUI( self ): return self._gui
def GetOptions( self ):
@ -521,7 +526,7 @@ class Controller( HydrusController.HydrusController ):
while len( missing_locations ) > 0:
with ClientGUITopLevelWindows.DialogManage( None, 'repair file system', 'regular_dialog' ) as dlg:
with ClientGUITopLevelWindows.DialogManage( None, 'repair file system' ) as dlg:
panel = ClientGUIScrolledPanelsManagement.RepairFileSystemPanel( dlg, missing_locations )
@ -568,6 +573,8 @@ class Controller( HydrusController.HydrusController ):
self._client_session_manager = ClientCaches.HydrusSessionManager( self )
self._shortcuts_manager = ClientCaches.ShortcutsManager( self )
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache( self )
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager( self )
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager( self )

View File

@ -939,26 +939,6 @@ class DB( HydrusDB.HydrusDB ):
self._c.executemany( 'INSERT INTO shape_vptree ( phash_id, parent_id, radius, inner_id, inner_population, outer_id, outer_population ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', insert_rows )
def _CacheSimilarFilesGetDuplicatePair( self, service_key, duplicate_type ):
( table_join, predicate_string ) = self._CacheSimilarFilesGetDuplicatePairsTableJoinInfo( service_key )
result = self._c.execute( 'SELECT smaller_hash_id, larger_hash_id FROM ' + table_join + ' WHERE ' + predicate_string + ' AND duplicate_type = ? ORDER BY RANDOM() LIMIT 1;', ( HC.DUPLICATE_UNKNOWN, ) ).fetchone()
if result is None:
return None
else:
( smaller_hash_id, larger_hash_id ) = result
media_results = self._GetMediaResults( ( smaller_hash_id, larger_hash_id ) )
return media_results
def _CacheSimilarFilesGetDuplicatePairsTableJoinInfo( self, file_service_key ):
service_id = self._GetServiceId( file_service_key )
@ -1031,6 +1011,77 @@ class DB( HydrusDB.HydrusDB ):
return dupe_hashes
def _CacheSimilarFilesGetUniqueDuplicatePairs( self, service_key, duplicate_type ):
# per batch, we want a bunch of non-intersecting decisions to keep it simple at the gui-level
# we also want to clear things out in groups
# so lets get a group of non-intersecting stars
( table_join, predicate_string ) = self._CacheSimilarFilesGetDuplicatePairsTableJoinInfo( service_key )
MAX_BATCH_SIZE = 50
pairs_of_hash_ids = []
seen_hash_ids = set()
while True:
result = self._c.execute( 'SELECT smaller_hash_id, larger_hash_id FROM ' + table_join + ' WHERE ' + predicate_string + ' AND duplicate_type = ? ORDER BY RANDOM() LIMIT 10;', ( HC.DUPLICATE_UNKNOWN, ) ).fetchall()
possible_master_hash_ids = set()
for ( smaller_hash_id, larger_hash_id ) in result:
possible_master_hash_ids.add( smaller_hash_id )
possible_master_hash_ids.add( larger_hash_id )
possible_master_hash_ids.difference_update( seen_hash_ids )
if len( possible_master_hash_ids ) == 0:
break # none left from our sample, or none at all in the db
possible_master_hash_ids = list( possible_master_hash_ids )
master_hash_id = random.choice( possible_master_hash_ids )
all_master_pairs = self._c.execute( 'SELECT smaller_hash_id, larger_hash_id FROM ' + table_join + ' WHERE ' + predicate_string + ' AND duplicate_type = ? AND ( smaller_hash_id = ? OR larger_hash_id = ? );', ( HC.DUPLICATE_UNKNOWN, master_hash_id, master_hash_id ) ).fetchall()
good_pairs = []
for ( smaller_hash_id, larger_hash_id ) in all_master_pairs:
if smaller_hash_id in seen_hash_ids or larger_hash_id in seen_hash_ids:
continue
good_pairs.append( ( smaller_hash_id, larger_hash_id ) )
if len( good_pairs ) == 0:
break # none left from our sample
for ( smaller_hash_id, larger_hash_id ) in good_pairs:
seen_hash_ids.add( smaller_hash_id )
seen_hash_ids.add( larger_hash_id )
pairs_of_hash_ids.append( ( smaller_hash_id, larger_hash_id ) )
hash_ids_to_hashes = self._GetHashIdsToHashes( seen_hash_ids )
pairs_of_hashes = [ ( hash_ids_to_hashes[ smaller_hash_id ], hash_ids_to_hashes[ larger_hash_id ] ) for ( smaller_hash_id, larger_hash_id ) in pairs_of_hash_ids ]
return pairs_of_hashes
def _CacheSimilarFilesMaintainDuplicatePairs( self, search_distance, job_key = None, stop_time = None, abandon_if_other_work_to_do = False ):
if abandon_if_other_work_to_do:
@ -4104,8 +4155,8 @@ class DB( HydrusDB.HydrusDB ):
else:
current_selects.append( 'SELECT hash_id FROM ' + current_mappings_table_name + ' NATURAL JOIN current_files NATURAL JOIN tags WHERE current_files.service_id = ' + str( file_service_id ) + ' AND tag_id IN ' + HydrusData.SplayListForDB( possible_subtag_ids ) + ';' )
pending_selects.append( 'SELECT hash_id FROM ' + pending_mappings_table_name + ' NATURAL JOIN current_files NATURAL JOIN tags WHERE current_files.service_id = ' + str( file_service_id ) + ' AND tag_id IN ' + HydrusData.SplayListForDB( possible_subtag_ids ) + ';' )
current_selects.append( 'SELECT hash_id FROM ' + current_mappings_table_name + ' NATURAL JOIN current_files NATURAL JOIN tags WHERE current_files.service_id = ' + str( file_service_id ) + ' AND subtag_id IN ' + HydrusData.SplayListForDB( possible_subtag_ids ) + ';' )
pending_selects.append( 'SELECT hash_id FROM ' + pending_mappings_table_name + ' NATURAL JOIN current_files NATURAL JOIN tags WHERE current_files.service_id = ' + str( file_service_id ) + ' AND subtag_id IN ' + HydrusData.SplayListForDB( possible_subtag_ids ) + ';' )
@ -7208,7 +7259,7 @@ class DB( HydrusDB.HydrusDB ):
if action == 'autocomplete_predicates': result = self._GetAutocompletePredicates( *args, **kwargs )
elif action == 'client_files_locations': result = self._GetClientFilesLocations( *args, **kwargs )
elif action == 'downloads': result = self._GetDownloads( *args, **kwargs )
elif action == 'duplicate_pair': result = self._CacheSimilarFilesGetDuplicatePair( *args, **kwargs )
elif action == 'unique_duplicate_pairs': result = self._CacheSimilarFilesGetUniqueDuplicatePairs( *args, **kwargs )
elif action == 'file_hashes': result = self._GetFileHashes( *args, **kwargs )
elif action == 'file_query_ids': result = self._GetHashIdsFromQuery( *args, **kwargs )
elif action == 'file_system_predicates': result = self._GetFileSystemPredicates( *args, **kwargs )
@ -8594,6 +8645,105 @@ class DB( HydrusDB.HydrusDB ):
self._SetJSONDump( duplicate_filter )
if version == 251:
duplicate_filter = ClientData.Shortcuts( 'duplicate_filter' )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_LEFT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_this_is_better' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_RIGHT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_alternates' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_MIDDLE, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_back' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_SPACE, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_this_is_better' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_skip' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_skip' ) )
self._SetJSONDump( duplicate_filter )
media = ClientData.Shortcuts( 'media' )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F4, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'manage_file_ratings' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F3, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'manage_file_tags' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F7, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'archive_file' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F7, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'inbox_file' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'E' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'open_file_in_external_program' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'R' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'remove_file_from_view' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F12, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'launch_the_archive_delete_filter' ) )
self._SetJSONDump( media )
main_gui = ClientData.Shortcuts( 'main_gui' )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F5, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'refresh' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F9, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'new_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'I' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'synchronised_wait_switch' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'M' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'set_media_focus' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'R' ), [ CC.SHORTCUT_MODIFIER_CTRL, CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'show_hide_splitters' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'S' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'set_search_focus' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'T' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'new_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'U' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'unclose_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'W' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'close_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'Y' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'redo' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'Z' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'undo' ) )
self._SetJSONDump( main_gui )
media_viewer_browser = ClientData.Shortcuts( 'media_viewer_browser' )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_LEFT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_LEFT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_PAGEUP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_PAGEUP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_DOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_RIGHT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_RIGHT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_DOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_PAGEDOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_PAGEDOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_DOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_HOME, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_first' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_HOME, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_first' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_END, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_last' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_END, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_last' ) )
self._SetJSONDump( media_viewer_browser )
media_viewer = ClientData.Shortcuts( 'media_viewer' )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'B' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'move_animation_to_previous_frame' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'N' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'move_animation_to_next_frame' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'F' ), [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'switch_between_fullscreen_borderless_and_regular_framed_window' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'Z' ), [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'switch_between_100_percent_and_canvas_zoom' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_ADD, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_in' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_ADD, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_in' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_SUBTRACT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_out' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_SUBTRACT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_out' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_UP, [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_in' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_DOWN, [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_out' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_UP, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_up' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_DOWN, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_down' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_LEFT, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_left' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_RIGHT, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_right' ) )
self._SetJSONDump( media_viewer )
self._controller.pub( 'splash_set_title_text', 'updated db to v' + str( version + 1 ) )
self._c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )

View File

@ -499,7 +499,7 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
if data is None:
data = 'archive'
data = 'archive_file'
HydrusSerialisable.SerialisableBase.__init__( self )
@ -728,6 +728,10 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
self._dictionary[ 'strings' ][ 'namespace_connector' ] = ':'
self._dictionary[ 'strings' ][ 'export_phrase' ] = '{hash}'
self._dictionary[ 'string_list' ] = {}
self._dictionary[ 'string_list' ][ 'default_media_viewer_custom_shortcuts' ] = []
#
client_files_default = os.path.join( db_dir, 'client_files' )
@ -1176,6 +1180,14 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
def GetStringList( self, name ):
with self._lock:
return self._dictionary[ 'string_list' ][ name ]
def GetSuggestedTagsFavourites( self, service_key ):
with self._lock:
@ -1304,6 +1316,14 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
def SetStringList( self, name, value ):
with self._lock:
self._dictionary[ 'string_list' ][ name ] = value
def SetSuggestedTagsFavourites( self, service_key, tags ):
with self._lock:
@ -1635,6 +1655,11 @@ class Shortcut( HydrusSerialisable.SerialisableBase ):
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 )
@ -1714,6 +1739,11 @@ class Shortcuts( HydrusSerialisable.SerialisableBaseNamed ):
def __len__( self ):
return len( self._shortcuts_to_commands )
def _GetSerialisableInfo( self ):
return [ ( shortcut.GetSerialisableTuple(), command.GetSerialisableTuple() ) for ( shortcut, command ) in self._shortcuts_to_commands.items() ]
@ -1866,15 +1896,15 @@ def ConvertMouseEventToShortcut( event ):
key = None
if event.LeftDown():
if event.LeftDown() or event.LeftDClick():
key = CC.SHORTCUT_MOUSE_LEFT
elif event.MiddleDown():
elif event.MiddleDown() or event.MiddleDClick():
key = CC.SHORTCUT_MOUSE_MIDDLE
elif event.RightDown():
elif event.RightDown() or event.RightDClick():
key = CC.SHORTCUT_MOUSE_RIGHT

View File

@ -113,60 +113,8 @@ def GetClientDefaultOptions():
options[ 'sort_by' ] = default_sort_by_choices
options[ 'show_all_tags_in_autocomplete' ] = True
shortcuts = {}
shortcuts[ wx.ACCEL_NORMAL ] = {}
shortcuts[ wx.ACCEL_CTRL ] = {}
shortcuts[ wx.ACCEL_ALT ] = {}
shortcuts[ wx.ACCEL_SHIFT ] = {}
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_F3 ] = 'manage_tags'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_F4 ] = 'manage_ratings'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_F5 ] = 'refresh'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_F7 ] = 'archive'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_F12 ] = 'filter'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_F9 ] = 'new_page'
shortcuts[ wx.ACCEL_NORMAL ][ ord( 'F' ) ] = 'fullscreen_switch'
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_F7 ] = 'inbox'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'B' ) ] = 'frame_back'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'N' ) ] = 'frame_next'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'T' ) ] = 'new_page'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'U' ) ] = 'unclose_page'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'W' ) ] = 'close_page'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'R' ) ] = 'show_hide_splitters'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'S' ) ] = 'set_search_focus'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'M' ) ] = 'set_media_focus'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'I' ) ] = 'synchronised_wait_switch'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'Z' ) ] = 'undo'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'Y' ) ] = 'redo'
shortcuts[ wx.ACCEL_CTRL ][ ord( 'E' ) ] = 'open_externally'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_UP ] = 'previous'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_LEFT ] = 'previous'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_UP ] = 'previous'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_LEFT ] = 'previous'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_PAGEUP ] = 'previous'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_PAGEUP ] = 'previous'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_DOWN ] = 'next'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_RIGHT ] = 'next'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_DOWN ] = 'next'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_RIGHT ] = 'next'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_PAGEDOWN ] = 'next'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_PAGEDOWN ] = 'next'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_HOME ] = 'first'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_HOME ] = 'first'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_END ] = 'last'
shortcuts[ wx.ACCEL_NORMAL ][ wx.WXK_NUMPAD_END ] = 'last'
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_UP ] = 'pan_up'
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_DOWN ] = 'pan_down'
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_LEFT ] = 'pan_left'
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_RIGHT ] = 'pan_right'
options[ 'proxy' ] = None
options[ 'shortcuts' ] = shortcuts
options[ 'confirm_client_exit' ] = False
options[ 'default_tag_repository' ] = CC.LOCAL_TAG_SERVICE_KEY
@ -579,10 +527,8 @@ def GetDefaultShortcuts():
duplicate_filter = ClientData.Shortcuts( 'duplicate_filter' )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_LEFT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_this_is_better' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_LEFT, [ wx.ACCEL_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_not_dupes' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_RIGHT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_alternates' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_MIDDLE, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_exactly_the_same' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_RIGHT, [ wx.ACCEL_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_skip' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_MIDDLE, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_back' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_SPACE, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_this_is_better' ) )
duplicate_filter.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'duplicate_filter_skip' ) )
@ -590,4 +536,88 @@ def GetDefaultShortcuts():
shortcuts.append( duplicate_filter )
media = ClientData.Shortcuts( 'media' )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F4, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'manage_file_ratings' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F3, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'manage_file_tags' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F7, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'archive_file' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F7, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'inbox_file' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'E' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'open_file_in_external_program' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'R' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'remove_file_from_view' ) )
media.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F12, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'launch_the_archive_delete_filter' ) )
shortcuts.append( media )
main_gui = ClientData.Shortcuts( 'main_gui' )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F5, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'refresh' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_F9, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'new_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'I' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'synchronised_wait_switch' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'M' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'set_media_focus' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'R' ), [ CC.SHORTCUT_MODIFIER_CTRL, CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'show_hide_splitters' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'S' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'set_search_focus' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'T' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'new_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'U' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'unclose_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'W' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'close_page' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'Y' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'redo' ) )
main_gui.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'Z' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'undo' ) )
shortcuts.append( main_gui )
media_viewer_browser = ClientData.Shortcuts( 'media_viewer_browser' )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_LEFT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_LEFT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_PAGEUP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_PAGEUP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_UP, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_previous' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_DOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_RIGHT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_RIGHT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_DOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_PAGEDOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_PAGEDOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_DOWN, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_next' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_HOME, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_first' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_HOME, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_first' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_END, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_last' ) )
media_viewer_browser.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_END, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'view_last' ) )
shortcuts.append( media_viewer_browser )
media_viewer = ClientData.Shortcuts( 'media_viewer' )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'B' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'move_animation_to_previous_frame' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'N' ), [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'move_animation_to_next_frame' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'F' ), [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'switch_between_fullscreen_borderless_and_regular_framed_window' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, ord( 'Z' ), [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'switch_between_100_percent_and_canvas_zoom' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_ADD, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_in' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_ADD, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_in' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_SUBTRACT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_out' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_NUMPAD_SUBTRACT, [] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_out' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_UP, [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_in' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_MOUSE, CC.SHORTCUT_MOUSE_SCROLL_DOWN, [ CC.SHORTCUT_MODIFIER_CTRL ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'zoom_out' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_UP, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_up' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_DOWN, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_down' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_LEFT, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_left' ) )
media_viewer.SetCommand( ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_RIGHT, [ CC.SHORTCUT_MODIFIER_SHIFT ] ), ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'pan_right' ) )
shortcuts.append( media_viewer )
return shortcuts

View File

@ -1,6 +1,7 @@
import HydrusConstants as HC
import ClientConstants as CC
import ClientCaches
import ClientData
import ClientDragDrop
import ClientExporting
import ClientGUICommon
@ -13,6 +14,7 @@ import ClientGUIPages
import ClientGUIParsing
import ClientGUIScrolledPanelsManagement
import ClientGUIScrolledPanelsReview
import ClientGUIShortcuts
import ClientGUITopLevelWindows
import ClientDownloading
import ClientMedia
@ -86,15 +88,13 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
wx.GetApp().SetTopWindow( self )
self.RefreshAcceleratorTable()
self._message_manager = ClientGUICommon.PopupMessageManager( self )
self.Bind( wx.EVT_LEFT_DCLICK, self.EventFrameNewPage )
self.Bind( wx.EVT_MIDDLE_DOWN, self.EventFrameNewPage )
self.Bind( wx.EVT_CLOSE, self.EventClose )
self.Bind( wx.EVT_MENU, self.EventMenu )
self.Bind( wx.EVT_SET_FOCUS, self.EventFocus )
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
self._controller.sub( self, 'ClearClosedPages', 'clear_closed_pages' )
self._controller.sub( self, 'NewCompose', 'new_compose_frame' )
@ -913,6 +913,7 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
ClientGUIMenus.AppendSeparator( menu )
ClientGUIMenus.AppendMenuItem( self, menu, 'options', 'Change how the client operates.', self._ManageOptions )
ClientGUIMenus.AppendMenuItem( self, menu, 'shortcuts', 'Edit the shortcuts your client responds to.', self._ManageShortcuts )
ClientGUIMenus.AppendSeparator( menu )
@ -1577,6 +1578,9 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
self._menubar = wx.MenuBar()
self._menu_updater = ClientGUICommon.ThreadToGUIUpdater( self._menubar, self.RefreshMenu )
self._dirty_menus = set()
self.SetMenuBar( self._menubar )
for name in MENU_ORDER:
@ -1695,9 +1699,8 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
def _ManageAccountTypes( self, service_key ):
title = 'manage account types'
frame_key = 'regular_dialog'
with ClientGUITopLevelWindows.DialogManage( self, title, frame_key ) as dlg:
with ClientGUITopLevelWindows.DialogManage( self, title ) as dlg:
panel = ClientGUIScrolledPanelsManagement.ManageAccountTypesPanel( dlg, service_key )
@ -1743,9 +1746,8 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
def _ManageParsingScripts( self ):
title = 'manage parsing scripts'
frame_key = 'regular_dialog'
with ClientGUITopLevelWindows.DialogManage( self, title, frame_key ) as dlg:
with ClientGUITopLevelWindows.DialogManage( self, title ) as dlg:
panel = ClientGUIParsing.ManageParsingScriptsPanel( dlg )
@ -1763,9 +1765,8 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
def _ManageServer( self, service_key ):
title = 'manage server services'
frame_key = 'regular_dialog'
with ClientGUITopLevelWindows.DialogManage( self, title, frame_key ) as dlg:
with ClientGUITopLevelWindows.DialogManage( self, title ) as dlg:
panel = ClientGUIScrolledPanelsManagement.ManageServerServicesPanel( dlg, service_key )
@ -1784,9 +1785,8 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
try:
title = 'manage services'
frame_key = 'regular_dialog'
with ClientGUITopLevelWindows.DialogManage( self, title, frame_key ) as dlg:
with ClientGUITopLevelWindows.DialogManage( self, title ) as dlg:
panel = ClientGUIScrolledPanelsManagement.ManageClientServicesPanel( dlg )
@ -1801,6 +1801,18 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
def _ManageShortcuts( self ):
with ClientGUITopLevelWindows.DialogManage( self, 'manage shortcuts' ) as dlg:
panel = ClientGUIScrolledPanelsManagement.ManageShortcutsPanel( dlg )
dlg.SetPanel( panel )
dlg.ShowModal()
def _ManageSubscriptions( self ):
original_pause_status = HC.options[ 'pause_subs_sync' ]
@ -2027,6 +2039,89 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
self._controller.Write( 'save_options', HC.options )
def _ProcessApplicationCommand( self, command ):
command_processed = True
command_type = command.GetCommandType()
data = command.GetData()
if command_type == CC.APPLICATION_COMMAND_TYPE_SIMPLE:
action = data
if action == 'refresh':
self._Refresh()
elif action == 'new_page':
self._ChooseNewPage()
if action == 'close_page':
self._CloseCurrentPage()
elif action == 'unclose_page':
self._UnclosePage()
elif action == 'show_hide_splitters':
self._ShowHideSplitters()
elif action == 'synchronised_wait_switch':
self._SetSynchronisedWait()
elif action == 'set_media_focus':
self._SetMediaFocus()
elif action == 'set_search_focus':
self._SetSearchFocus()
elif action == 'redo':
self._controller.pub( 'redo' )
elif action == 'undo':
self._controller.pub( 'undo' )
else:
command_processed = False
else:
command_processed = False
return command_processed
def _ProcessShortcut( self, shortcut ):
shortcut_processed = False
command = HydrusGlobals.client_controller.GetCommandFromShortcut( [ 'main_gui' ], shortcut )
if command is not None:
command_processed = self._ProcessApplicationCommand( command )
if command_processed:
shortcut_processed = True
return shortcut_processed
def _RebalanceClientFiles( self ):
text = 'This will move your files around your storage directories until they satisfy the weights you have set in the options. It will also recover any folders that are in the wrong place. Use this if you have recently changed your file storage locations and want to hurry any transfers you have set up, or if you are recovering a complicated backup.'
@ -2183,6 +2278,8 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
new_name = dlg.GetValue()
new_name = self._notebook.EscapeMnemonics( new_name )
self._notebook.SetPageText( selection, new_name )
@ -2755,6 +2852,26 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
return self._loading_session
def EventCharHook( self, event ):
if ClientGUIShortcuts.IShouldCatchCharHook( self ):
shortcut = ClientData.ConvertKeyEventToShortcut( event )
if shortcut is not None:
shortcut_processed = self._ProcessShortcut( shortcut )
if shortcut_processed:
return
event.Skip()
def EventClose( self, event ):
if not event.CanVeto():
@ -2790,94 +2907,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def EventMenu( self, event ):
action = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() )
if action is not None:
( command, data ) = action
if command == 'account_info': self._AccountInfo( data )
elif command == 'auto_repo_setup': self._AutoRepoSetup()
elif command == 'auto_server_setup': self._AutoServerSetup()
elif command == 'backup_service': self._BackupService( data )
elif command == 'close_page': self._CloseCurrentPage()
elif command == 'delete_gui_session':
self._controller.Write( 'delete_serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_GUI_SESSION, data )
self._controller.pub( 'notify_new_sessions' )
elif command == 'fetch_ip': self._FetchIP( data )
elif command == 'force_idle_mode':
self._controller.ForceIdle()
elif command == 'load_gui_session': self._LoadGUISession( data )
elif command == 'manage_account_types': self._ManageAccountTypes( data )
elif command == 'manage_boorus': self._ManageBoorus()
elif command == 'manage_parsing_scripts': self._ManageParsingScripts()
elif command == 'manage_pixiv_account': self._ManagePixivAccount()
elif command == 'manage_server_services': self._ManageServer( data )
elif command == 'manage_services': self._ManageServices()
elif command == 'manage_subscriptions': self._ManageSubscriptions()
elif command == 'manage_tag_censorship': self._ManageTagCensorship()
elif command == 'manage_tag_parents': self._ManageTagParents()
elif command == 'manage_tag_siblings': self._ManageTagSiblings()
elif command == 'manage_upnp': self._ManageUPnP()
elif command == 'modify_account': self._ModifyAccount( data )
elif command == 'new_accounts': self._GenerateNewAccounts( data )
elif command == 'new_import_booru': self._NewPageImportBooru()
elif command == 'new_import_gallery':
site_type = data
gallery_identifier = ClientDownloading.GalleryIdentifier( site_type )
self._NewPageImportGallery( gallery_identifier )
elif command == 'new_import_page_of_images': self._NewPageImportPageOfImages()
elif command == 'new_import_thread_watcher': self._NewPageImportThreadWatcher()
elif command == 'new_import_urls': self._NewPageImportURLs()
elif command == 'new_page':
self._ChooseNewPage()
elif command == 'new_page_query': self._NewPageQuery( data )
elif command == 'petitions': self._NewPagePetitions( data )
elif command == 'pubsub_profile_mode':
HydrusGlobals.pubsub_profile_mode = not HydrusGlobals.pubsub_profile_mode
elif command == 'redo':
self._controller.pub( 'redo' )
elif command == 'refresh':
self._Refresh()
elif command == 'review_services': self._ReviewServices()
elif command == 'save_gui_session': self._SaveGUISession()
elif command == 'set_media_focus': self._SetMediaFocus()
elif command == 'set_search_focus': self._SetSearchFocus()
elif command == 'show_hide_splitters':
self._ShowHideSplitters()
elif command == 'start_ipfs_download': self._StartIPFSDownload()
elif command == 'start_youtube_download': self._StartYoutubeDownload()
elif command == 'synchronised_wait_switch': self._SetSynchronisedWait()
elif command == 'unclose_page':
self._UnclosePage()
elif command == 'undo': self._controller.pub( 'undo' )
else: event.Skip()
def EventNotebookLeftDoubleClick( self, event ):
( tab_index, flags ) = self._notebook.HitTest( ( event.GetX(), event.GetY() ) )
@ -3119,28 +3148,47 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def NotifyNewOptions( self ):
self.RefreshAcceleratorTable()
self._dirty_menus.add( 'services' )
self.RefreshMenu( 'services' )
self._menu_updater.Update()
def NotifyNewPending( self ): self.RefreshMenu( 'pending' )
def NotifyNewPending( self ):
self._dirty_menus.add( 'pending' )
self._menu_updater.Update()
def NotifyNewPermissions( self ):
self.RefreshMenu( 'pages' )
self.RefreshMenu( 'services' )
self._dirty_menus.add( 'pages' )
self._dirty_menus.add( 'services' )
self._menu_updater.Update()
def NotifyNewServices( self ):
self.RefreshMenu( 'pages' )
self.RefreshMenu( 'services' )
self._dirty_menus.add( 'pages' )
self._dirty_menus.add( 'services' )
self._menu_updater.Update()
def NotifyNewSessions( self ): self.RefreshMenu( 'pages' )
def NotifyNewSessions( self ):
self._dirty_menus.add( 'pages' )
self._menu_updater.Update()
def NotifyNewUndo( self ): self.RefreshMenu( 'undo' )
def NotifyNewUndo( self ):
self._dirty_menus.add( 'undo' )
self._menu_updater.Update()
def PageDeleted( self, page_key ):
@ -3174,75 +3222,69 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
return False
def RefreshAcceleratorTable( self ):
interested_actions = [ 'archive', 'inbox', 'close_page', 'filter', 'manage_ratings', 'manage_tags', 'new_page', 'unclose_page', 'refresh', 'set_media_focus', 'set_search_focus', 'show_hide_splitters', 'synchronised_wait_switch', 'undo', 'redo' ]
entries = []
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( action ) ) for ( key, action ) in key_dict.items() if action in interested_actions ] )
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
def RefreshMenu( self, name ):
def RefreshMenu( self ):
db_going_to_hang_if_we_hit_it = HydrusGlobals.client_controller.DBCurrentlyDoingJob()
if db_going_to_hang_if_we_hit_it:
wx.CallLater( 2500, self.RefreshMenu, name )
wx.CallLater( 2500, self.RefreshMenu )
return
( menu, label, show ) = self._GenerateMenuInfo( name )
if HC.PLATFORM_OSX:
for name in self._dirty_menus:
menu.SetTitle( label ) # causes bugs in os x if this is not here
( menu, label, show ) = self._GenerateMenuInfo( name )
( old_menu, old_label, old_show ) = self._menus[ name ]
if old_show:
old_menu_index = self._menubar.FindMenu( old_label )
if show:
if HC.PLATFORM_OSX:
self._menubar.Replace( old_menu_index, menu, label )
menu.SetTitle( label ) # causes bugs in os x if this is not here
( old_menu, old_label, old_show ) = self._menus[ name ]
if old_show:
old_menu_index = self._menubar.FindMenu( old_label )
if show:
self._menubar.Replace( old_menu_index, menu, label )
else:
self._menubar.Remove( old_menu_index )
else:
self._menubar.Remove( old_menu_index )
else:
if show:
insert_index = 0
for temp_name in MENU_ORDER:
if show:
if temp_name == name: break
insert_index = 0
( temp_menu, temp_label, temp_show ) = self._menus[ temp_name ]
if temp_show:
for temp_name in MENU_ORDER:
insert_index += 1
if temp_name == name: break
( temp_menu, temp_label, temp_show ) = self._menus[ temp_name ]
if temp_show:
insert_index += 1
self._menubar.Insert( insert_index, menu, label )
self._menubar.Insert( insert_index, menu, label )
self._menus[ name ] = ( menu, label, show )
ClientGUIMenus.DestroyMenu( old_menu )
self._menus[ name ] = ( menu, label, show )
ClientGUIMenus.DestroyMenu( old_menu )
self._dirty_menus = set()
def RefreshStatusBar( self ):

View File

@ -58,7 +58,7 @@ class AutoCompleteDropdown( wx.Panel ):
self._text_ctrl.Bind( wx.EVT_TEXT, self.EventText )
self._text_ctrl.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown )
self._text_ctrl.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
self._text_ctrl.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel )
@ -208,7 +208,7 @@ class AutoCompleteDropdown( wx.Panel ):
visible = self._text_ctrl.IsShownOnScreen()
focus_remains_on_self_or_children = ClientGUICommon.WindowHasFocus( self._dropdown_window ) or ClientGUICommon.WindowHasFocus( self._text_ctrl ) or ClientGUICommon.ChildHasFocus( self._dropdown_window )
focus_remains_on_self_or_children = ClientGUICommon.WindowOrAnyTLPChildHasFocus( self )
return tlp_active and visible and focus_remains_on_self_or_children
@ -276,12 +276,7 @@ class AutoCompleteDropdown( wx.Panel ):
self._BroadcastChoices( predicates )
def EventCloseDropdown( self, event ):
HydrusGlobals.client_controller.GetGUI().Close()
def EventKeyDown( self, event ):
def EventCharHook( self, event ):
HydrusGlobals.client_controller.ResetIdleTimer()
@ -346,7 +341,7 @@ class AutoCompleteDropdown( wx.Panel ):
new_event = wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = id )
self._text_ctrl.ProcessEvent( new_event )
self.ProcessEvent( new_event )
elif key in ( wx.WXK_PAGEDOWN, wx.WXK_NUMPAD_PAGEDOWN, wx.WXK_PAGEUP, wx.WXK_NUMPAD_PAGEUP ) and self._text_ctrl.GetValue() == '' and len( self._dropdown_list ) == 0:
@ -361,11 +356,11 @@ class AutoCompleteDropdown( wx.Panel ):
new_event = wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = id )
self._text_ctrl.ProcessEvent( new_event )
self.ProcessEvent( new_event )
else:
self._dropdown_list.ProcessEvent( event )
self._dropdown_list.ProcessEvent( event ) # this typically skips the event, letting the text ctrl take it
else:
@ -374,6 +369,11 @@ class AutoCompleteDropdown( wx.Panel ):
def EventCloseDropdown( self, event ):
HydrusGlobals.client_controller.GetGUI().Close()
def EventKillFocus( self, event ):
self._move_hide_timer.Start( 1, wx.TIMER_ONE_SHOT )
@ -396,10 +396,16 @@ class AutoCompleteDropdown( wx.Panel ):
if event.CmdDown():
key_event = wx.KeyEvent( wx.EVT_KEY_DOWN.typeId )
key_event = wx.KeyEvent( wx.EVT_CHAR_HOOK.typeId )
if event.GetWheelRotation() > 0: key_event.m_keyCode = wx.WXK_UP
else: key_event.m_keyCode = wx.WXK_DOWN
if event.GetWheelRotation() > 0:
key_event.m_keyCode = wx.WXK_UP
else:
key_event.m_keyCode = wx.WXK_DOWN
self._dropdown_list.ProcessEvent( key_event )

File diff suppressed because it is too large Load Diff

View File

@ -29,58 +29,69 @@ ID_TIMER_SLIDESHOW = wx.NewId()
ID_TIMER_MEDIA_INFO_DISPLAY = wx.NewId()
ID_TIMER_POPUP = wx.NewId()
def ChildHasFocus( window ):
def WindowOrAnyTLPChildHasFocus( window ):
focus = wx.Window.FindFocus()
if focus is None:
return False
while not isinstance( focus, wx.TopLevelWindow ):
focus = focus.GetParent()
if focus is None:
return False
while focus is not None:
if focus == window:
return True
focus = focus.GetParent()
return False
def TLPHasFocus( window ):
def WindowOrSameTLPChildHasFocus( window ):
focus = wx.Window.FindFocus()
if focus is None:
while focus is not None:
return False
if focus == window:
return True
if isinstance( focus, wx.TopLevelWindow ):
return False
focus = focus.GetParent()
if isinstance( focus, wx.TopLevelWindow ):
return False
def GetFocusTLP():
focus = wx.Window.FindFocus()
return GetTLP( focus )
def GetTLP( window ):
if window is None:
focus_tlp = focus
return None
elif isinstance( window, wx.TopLevelWindow ):
return window
else:
focus_tlp = wx.GetTopLevelParent( focus )
return window.GetTopLevelParent()
if isinstance( window, wx.TopLevelWindow ):
window_tlp = window
else:
window_tlp = wx.GetTopLevelParent( window )
def TLPHasFocus( window ):
focus_tlp = GetFocusTLP()
window_tlp = GetTLP( window )
return window_tlp == focus_tlp
@ -143,7 +154,9 @@ def WrapInGrid( parent, rows, expand_text = False ):
cflags = control_flags
gridbox.AddF( wx.StaticText( parent, label = text ), text_flags )
st = BetterStaticText( parent, text )
gridbox.AddF( st, text_flags )
gridbox.AddF( control, cflags )
@ -153,7 +166,9 @@ def WrapInText( control, parent, text ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( parent, label = text ), CC.FLAGS_VCENTER )
st = BetterStaticText( parent, text )
hbox.AddF( st, CC.FLAGS_VCENTER )
hbox.AddF( control, CC.FLAGS_EXPAND_BOTH_WAYS )
return hbox
@ -231,7 +246,9 @@ class BetterButton( wx.Button ):
def __init__( self, parent, label, func, *args, **kwargs ):
wx.Button.__init__( self, parent, label = label, style = wx.BU_EXACTFIT )
wx.Button.__init__( self, parent, style = wx.BU_EXACTFIT )
self.SetLabelText( label )
self._func = func
self._args = args
@ -291,6 +308,22 @@ class BetterRadioBox( wx.RadioBox ):
return self._indices_to_data[ index ]
class BetterStaticText( wx.StaticText ):
def __init__( self, parent, label = None ):
wx.StaticText.__init__( self, parent )
if label is not None:
# to escape mnemonic '&' swallowing
self.SetLabelText( label )
# at some point, rewrite this to be a control that'll produce a custom geteffectiveminsize and use wx.lib.wordwrap to dc draw the text
# st.Wrap is a pain to deal with here, seems to sometimes/always not be able to increase after an initial non-zero call
class BufferedWindow( wx.Window ):
def __init__( self, *args, **kwargs ):
@ -1315,8 +1348,9 @@ class NoneableSpinCtrl( wx.Panel ):
self._multiplier = multiplier
self._num_dimensions = num_dimensions
self._checkbox = wx.CheckBox( self, label = none_phrase )
self._checkbox = wx.CheckBox( self )
self._checkbox.Bind( wx.EVT_CHECKBOX, self.EventCheckBox )
self._checkbox.SetLabelText( none_phrase )
self._one = wx.SpinCtrl( self, min = min, max = max, size = ( 60, -1 ) )
@ -1329,20 +1363,20 @@ class NoneableSpinCtrl( wx.Panel ):
if len( message ) > 0:
hbox.AddF( wx.StaticText( self, label = message + ': ' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, message + ': ' ), CC.FLAGS_VCENTER )
hbox.AddF( self._one, CC.FLAGS_VCENTER )
if self._num_dimensions == 2:
hbox.AddF( wx.StaticText( self, label = 'x' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, 'x' ), CC.FLAGS_VCENTER )
hbox.AddF( self._two, CC.FLAGS_VCENTER )
if self._unit is not None:
hbox.AddF( wx.StaticText( self, label = unit ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, self._unit ), CC.FLAGS_VCENTER )
hbox.AddF( self._checkbox, CC.FLAGS_VCENTER )
@ -1498,7 +1532,7 @@ class PopupDismissAll( PopupWindow ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
self._text = wx.StaticText( self )
self._text = BetterStaticText( self )
self._text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
button = wx.Button( self, label = 'dismiss all' )
@ -3423,7 +3457,7 @@ class Shortcut( wx.Panel ):
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( wx.StaticText( self, label = 'Mouse events only work for the duplicate filter atm!' ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( BetterStaticText( self, 'Mouse events only work for the duplicate filter atm!' ), CC.FLAGS_EXPAND_PERPENDICULAR )
gridbox = wx.FlexGridSizer( 0, 2 )
@ -3657,7 +3691,7 @@ class TextAndGauge( wx.Panel ):
wx.Panel.__init__( self, parent )
self._st = wx.StaticText( self )
self._st = BetterStaticText( self )
self._gauge = Gauge( self )
vbox = wx.BoxSizer( wx.VERTICAL )
@ -3899,7 +3933,7 @@ class TimeDeltaCtrl( wx.Panel ):
self._days.Bind( wx.EVT_SPINCTRL, self.EventChange )
hbox.AddF( self._days, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'days' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, 'days' ), CC.FLAGS_VCENTER )
if self._show_hours:
@ -3908,7 +3942,7 @@ class TimeDeltaCtrl( wx.Panel ):
self._hours.Bind( wx.EVT_SPINCTRL, self.EventChange )
hbox.AddF( self._hours, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'hours' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, 'hours' ), CC.FLAGS_VCENTER )
if self._show_minutes:
@ -3917,7 +3951,7 @@ class TimeDeltaCtrl( wx.Panel ):
self._minutes.Bind( wx.EVT_SPINCTRL, self.EventChange )
hbox.AddF( self._minutes, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'minutes' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, 'minutes' ), CC.FLAGS_VCENTER )
if self._show_seconds:
@ -3926,7 +3960,7 @@ class TimeDeltaCtrl( wx.Panel ):
self._seconds.Bind( wx.EVT_SPINCTRL, self.EventChange )
hbox.AddF( self._seconds, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'seconds' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, 'seconds' ), CC.FLAGS_VCENTER )
if self._monthly_allowed:
@ -3935,7 +3969,7 @@ class TimeDeltaCtrl( wx.Panel ):
self._monthly.Bind( wx.EVT_CHECKBOX, self.EventChange )
hbox.AddF( self._monthly, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'monthly' ), CC.FLAGS_VCENTER )
hbox.AddF( BetterStaticText( self, 'monthly' ), CC.FLAGS_VCENTER )
self.SetSizer( hbox )

View File

@ -164,7 +164,7 @@ class BandwidthRulesCtrl( ClientGUICommon.StaticBox ):
self._max_allowed = wx.SpinCtrl( self, min = 1, max = 1024 * 1024 * 1024 )
self._max_allowed_st = wx.StaticText( self )
self._max_allowed_st = ClientGUICommon.BetterStaticText( self )
#

View File

@ -196,7 +196,7 @@ class DialogButtonChoice( Dialog ):
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
for button in self._buttons:
@ -285,9 +285,36 @@ class DialogChooseNewServiceMethod( Dialog ):
def GetRegister( self ): return self._should_register
class DialogCommitInterstitialFiltering( Dialog ):
def __init__( self, parent, label ):
Dialog.__init__( self, parent, 'commit and continue?', position = 'center' )
self._commit = wx.Button( self, id = wx.ID_YES, label = 'commit and continue' )
self._commit.SetForegroundColour( ( 0, 128, 0 ) )
self._back = wx.Button( self, id = wx.ID_CANCEL, label = 'go back' )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( wx.StaticText( self, label = label, style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._commit, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._back, CC.FLAGS_EXPAND_PERPENDICULAR )
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._commit.SetFocus )
class DialogFinishFiltering( Dialog ):
def __init__( self, parent, num_kept, num_deleted, keep = 'keep', delete = 'delete' ):
def __init__( self, parent, label ):
Dialog.__init__( self, parent, 'are you sure?', position = 'center' )
@ -306,8 +333,6 @@ class DialogFinishFiltering( Dialog ):
vbox = wx.BoxSizer( wx.VERTICAL )
label = keep + ' ' + HydrusData.ConvertIntToPrettyString( num_kept ) + ' and ' + delete + ' ' + HydrusData.ConvertIntToPrettyString( num_deleted ) + ' files?'
vbox.AddF( wx.StaticText( self, label = label, style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
@ -371,10 +396,10 @@ class DialogGenerateNewAccounts( Dialog ):
ctrl_box = wx.BoxSizer( wx.HORIZONTAL )
ctrl_box.AddF( wx.StaticText( self, label = 'generate' ), CC.FLAGS_VCENTER )
ctrl_box.AddF( ClientGUICommon.BetterStaticText( self, 'generate' ), CC.FLAGS_VCENTER )
ctrl_box.AddF( self._num, CC.FLAGS_VCENTER )
ctrl_box.AddF( self._account_types, CC.FLAGS_VCENTER )
ctrl_box.AddF( wx.StaticText( self, label = 'accounts, to expire in' ), CC.FLAGS_VCENTER )
ctrl_box.AddF( ClientGUICommon.BetterStaticText( self, 'accounts, to expire in' ), CC.FLAGS_VCENTER )
ctrl_box.AddF( self._lifetime, CC.FLAGS_VCENTER )
b_box = wx.BoxSizer( wx.HORIZONTAL )
@ -496,385 +521,6 @@ class DialogInputImportTagOptions( Dialog ):
return import_tag_options
class DialogInputCustomFilterAction( Dialog ):
def __init__( self, parent, shortcut, command ):
Dialog.__init__( self, parent, 'input custom filter action' )
self._current_ratings_like_service = None
self._current_ratings_numerical_service = None
self._hidden_cancel = wx.Button( self, id = wx.ID_CANCEL, size = ( 0, 0 ) )
self._shortcut_panel = ClientGUICommon.StaticBox( self, 'shortcut' )
self._shortcut = ClientGUICommon.Shortcut( self._shortcut_panel )
self._none_panel = ClientGUICommon.StaticBox( self, 'non-service actions' )
choices = [ 'manage_tags', 'manage_ratings', 'archive', 'inbox', 'delete', 'fullscreen_switch', 'frame_back', 'frame_next', 'next', 'first', 'last', 'open_externally', 'pan_up', 'pan_down', 'pan_left', 'pan_right', 'previous', 'remove', 'zoom_in', 'zoom_out', 'zoom_switch' ]
choices.extend( CC.DUPLICATE_FILTER_ACTIONS )
self._none_actions = wx.Choice( self._none_panel, choices = choices )
self._ok_none = wx.Button( self._none_panel, label = 'ok' )
self._ok_none.Bind( wx.EVT_BUTTON, self.EventOKNone )
self._ok_none.SetForegroundColour( ( 0, 128, 0 ) )
self._tag_panel = ClientGUICommon.StaticBox( self, 'tag service actions' )
self._tag_service_keys = wx.Choice( self._tag_panel )
self._tag_value = wx.TextCtrl( self._tag_panel, style = wx.TE_READONLY )
expand_parents = False
self._tag_input = ClientGUIACDropdown.AutoCompleteDropdownTagsWrite( self._tag_panel, self.SetTags, expand_parents, CC.LOCAL_FILE_SERVICE_KEY, CC.COMBINED_TAG_SERVICE_KEY )
self._ok_tag = wx.Button( self._tag_panel, label = 'ok' )
self._ok_tag.Bind( wx.EVT_BUTTON, self.EventOKTag )
self._ok_tag.SetForegroundColour( ( 0, 128, 0 ) )
self._ratings_like_panel = ClientGUICommon.StaticBox( self, 'like/dislike ratings service actions' )
self._ratings_like_service_keys = wx.Choice( self._ratings_like_panel )
self._ratings_like_service_keys.Bind( wx.EVT_CHOICE, self.EventRecalcActions )
self._ratings_like_like = wx.RadioButton( self._ratings_like_panel, style = wx.RB_GROUP, label = 'like' )
self._ratings_like_dislike = wx.RadioButton( self._ratings_like_panel, label = 'dislike' )
self._ratings_like_remove = wx.RadioButton( self._ratings_like_panel, label = 'remove rating' )
self._ok_ratings_like = wx.Button( self._ratings_like_panel, label = 'ok' )
self._ok_ratings_like.Bind( wx.EVT_BUTTON, self.EventOKRatingsLike )
self._ok_ratings_like.SetForegroundColour( ( 0, 128, 0 ) )
self._ratings_numerical_panel = ClientGUICommon.StaticBox( self, 'numerical ratings service actions' )
self._ratings_numerical_service_keys = wx.Choice( self._ratings_numerical_panel )
self._ratings_numerical_service_keys.Bind( wx.EVT_CHOICE, self.EventRecalcActions )
self._ratings_numerical_slider = wx.Slider( self._ratings_numerical_panel, style = wx.SL_AUTOTICKS | wx.SL_LABELS )
self._ratings_numerical_remove = wx.CheckBox( self._ratings_numerical_panel, label = 'remove rating' )
self._ok_ratings_numerical = wx.Button( self._ratings_numerical_panel, label = 'ok' )
self._ok_ratings_numerical.Bind( wx.EVT_BUTTON, self.EventOKRatingsNumerical )
self._ok_ratings_numerical.SetForegroundColour( ( 0, 128, 0 ) )
services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_TAG, HC.TAG_REPOSITORY, HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) )
for service in services:
service_type = service.GetServiceType()
if service_type in HC.TAG_SERVICES: choice = self._tag_service_keys
elif service_type == HC.LOCAL_RATING_LIKE: choice = self._ratings_like_service_keys
elif service_type == HC.LOCAL_RATING_NUMERICAL: choice = self._ratings_numerical_service_keys
choice.Append( service.GetName(), service.GetServiceKey() )
self._SetActions()
#
self._shortcut.SetValue( shortcut )
command_type = command.GetCommandType()
data = command.GetData()
if command_type == CC.APPLICATION_COMMAND_TYPE_SIMPLE:
action = data
self._none_actions.SetStringSelection( action )
else:
( service_key, content_type, action, value ) = data
self._service = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
service_name = self._service.GetName()
service_type = self._service.GetServiceType()
if service_type in HC.TAG_SERVICES:
self._tag_service_keys.SetStringSelection( service_name )
self._tag_value.SetValue( value )
elif service_type == HC.LOCAL_RATING_LIKE:
self._ratings_like_service_keys.SetStringSelection( service_name )
self._SetActions()
if value is None:
self._ratings_like_remove.SetValue( True )
elif value == True:
self._ratings_like_like.SetValue( True )
elif value == False:
self._ratings_like_dislike.SetValue( True )
elif service_type == HC.LOCAL_RATING_NUMERICAL:
self._ratings_numerical_service_keys.SetStringSelection( service_name )
self._SetActions()
if value is None:
self._ratings_numerical_remove.SetValue( True )
else:
num_stars = self._current_ratings_numerical_service.GetNumStars()
slider_value = int( round( value * num_stars ) )
self._ratings_numerical_slider.SetValue( slider_value )
#
self._shortcut_panel.AddF( self._shortcut, CC.FLAGS_EXPAND_PERPENDICULAR )
none_hbox = wx.BoxSizer( wx.HORIZONTAL )
none_hbox.AddF( self._none_actions, CC.FLAGS_EXPAND_DEPTH_ONLY )
none_hbox.AddF( self._ok_none, CC.FLAGS_VCENTER )
self._none_panel.AddF( none_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
tag_sub_vbox = wx.BoxSizer( wx.VERTICAL )
tag_sub_vbox.AddF( self._tag_value, CC.FLAGS_EXPAND_PERPENDICULAR )
tag_sub_vbox.AddF( self._tag_input, CC.FLAGS_EXPAND_BOTH_WAYS )
tag_hbox = wx.BoxSizer( wx.HORIZONTAL )
tag_hbox.AddF( self._tag_service_keys, CC.FLAGS_EXPAND_DEPTH_ONLY )
tag_hbox.AddF( tag_sub_vbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
tag_hbox.AddF( self._ok_tag, CC.FLAGS_VCENTER )
self._tag_panel.AddF( tag_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
ratings_like_hbox = wx.BoxSizer( wx.HORIZONTAL )
ratings_like_hbox.AddF( self._ratings_like_service_keys, CC.FLAGS_EXPAND_DEPTH_ONLY )
ratings_like_hbox.AddF( self._ratings_like_like, CC.FLAGS_VCENTER )
ratings_like_hbox.AddF( self._ratings_like_dislike, CC.FLAGS_VCENTER )
ratings_like_hbox.AddF( self._ratings_like_remove, CC.FLAGS_VCENTER )
ratings_like_hbox.AddF( self._ok_ratings_like, CC.FLAGS_VCENTER )
self._ratings_like_panel.AddF( ratings_like_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
ratings_numerical_hbox = wx.BoxSizer( wx.HORIZONTAL )
ratings_numerical_hbox.AddF( self._ratings_numerical_service_keys, CC.FLAGS_EXPAND_DEPTH_ONLY )
ratings_numerical_hbox.AddF( self._ratings_numerical_slider, CC.FLAGS_VCENTER )
ratings_numerical_hbox.AddF( self._ratings_numerical_remove, CC.FLAGS_VCENTER )
ratings_numerical_hbox.AddF( self._ok_ratings_numerical, CC.FLAGS_VCENTER )
self._ratings_numerical_panel.AddF( ratings_numerical_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( self._none_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._tag_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._ratings_like_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._ratings_numerical_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( self._shortcut_panel, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = u'\u2192' ), CC.FLAGS_VCENTER )
hbox.AddF( vbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
self.SetSizer( hbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( 680, y ) )
wx.CallAfter( self._ok_none.SetFocus )
def _SetActions( self ):
if self._ratings_like_service_keys.GetCount() > 0:
selection = self._ratings_like_service_keys.GetSelection()
if selection != wx.NOT_FOUND:
service_key = self._ratings_like_service_keys.GetClientData( selection )
service = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
self._current_ratings_like_service = service
if self._ratings_numerical_service_keys.GetCount() > 0:
selection = self._ratings_numerical_service_keys.GetSelection()
if selection != wx.NOT_FOUND:
service_key = self._ratings_numerical_service_keys.GetClientData( selection )
service = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
self._current_ratings_numerical_service = service
num_stars = service.GetNumStars()
allow_zero = service.AllowZero()
if allow_zero:
min = 0
else:
min = 1
self._ratings_numerical_slider.SetRange( min, num_stars )
def EventOKNone( self, event ):
action = self._none_actions.GetStringSelection()
self._final_command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, action )
self.EndModal( wx.ID_OK )
def EventOKRatingsLike( self, event ):
selection = self._ratings_like_service_keys.GetSelection()
if selection != wx.NOT_FOUND:
service_key = self._ratings_like_service_keys.GetClientData( selection )
if self._ratings_like_like.GetValue():
value = 1.0
elif self._ratings_like_dislike.GetValue():
value = 0.0
else:
value = None
self._final_command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_FLIP, value ) )
self.EndModal( wx.ID_OK )
else:
self.EndModal( wx.ID_CANCEL )
def EventOKRatingsNumerical( self, event ):
selection = self._ratings_numerical_service_keys.GetSelection()
if selection != wx.NOT_FOUND:
service_key = self._ratings_numerical_service_keys.GetClientData( selection )
if self._ratings_numerical_remove.GetValue():
value = None
else:
value = self._ratings_numerical_slider.GetValue()
num_stars = self._current_ratings_numerical_service.GetNumStars()
allow_zero = self._current_ratings_numerical_service.AllowZero()
if allow_zero:
value = float( value ) / num_stars
else:
value = float( value - 1 ) / ( num_stars - 1 )
self._final_command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_FLIP, value ) )
self.EndModal( wx.ID_OK )
else:
self.EndModal( wx.ID_CANCEL )
def EventOKTag( self, event ):
selection = self._tag_service_keys.GetSelection()
if selection != wx.NOT_FOUND:
service_key = self._tag_service_keys.GetClientData( selection )
value = self._tag_value.GetValue()
self._final_command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_FLIP, value ) )
self.EndModal( wx.ID_OK )
else:
self.EndModal( wx.ID_CANCEL )
def EventRecalcActions( self, event ):
self._SetActions()
event.Skip()
def GetInfo( self ):
shortcut = self._shortcut.GetValue()
return ( shortcut, self._final_command )
def SetTags( self, tags ):
if len( tags ) > 0:
tag = list( tags )[0]
self._tag_value.SetValue( tag )
class DialogInputFileSystemPredicates( Dialog ):
def __init__( self, parent, predicate_type ):
@ -1075,7 +721,7 @@ class DialogInputLocalBooruShare( Dialog ):
if new_share: intro += os.linesep + 'The link will not work until you ok this dialog.'
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( timeout_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( link_box, CC.FLAGS_BUTTON_SIZER )
@ -1578,7 +1224,7 @@ class DialogInputNamespaceRegex( Dialog ):
control_box = wx.BoxSizer( wx.HORIZONTAL )
control_box.AddF( self._namespace, CC.FLAGS_EXPAND_BOTH_WAYS )
control_box.AddF( wx.StaticText( self, label = ':' ), CC.FLAGS_VCENTER )
control_box.AddF( ClientGUICommon.BetterStaticText( self, ':' ), CC.FLAGS_VCENTER )
control_box.AddF( self._regex, CC.FLAGS_EXPAND_BOTH_WAYS )
b_box = wx.BoxSizer( wx.HORIZONTAL )
@ -1589,7 +1235,7 @@ class DialogInputNamespaceRegex( Dialog ):
intro = r'Put the namespace (e.g. page) on the left.' + os.linesep + r'Put the regex (e.g. [1-9]+\d*(?=.{4}$)) on the right.' + os.linesep + r'All files will be tagged with "namespace:regex".'
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( control_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( self._shortcuts, CC.FLAGS_LONE_BUTTON )
vbox.AddF( self._regex_intro_link, CC.FLAGS_LONE_BUTTON )
@ -1721,102 +1367,6 @@ class DialogInputNewFormField( Dialog ):
return ( name, field_type, default, editable )
class DialogInputShortcut( Dialog ):
def __init__( self, parent, modifier = wx.ACCEL_NORMAL, key = wx.WXK_F7, action = 'new_page' ):
Dialog.__init__( self, parent, 'edit shortcut' )
self._action = action
self._shortcut = ClientGUICommon.Shortcut( self )
self._actions = wx.Choice( self, choices = [ 'archive', 'inbox', 'close_page', 'filter', 'fullscreen_switch', 'frame_back', 'frame_next', 'manage_ratings', 'manage_tags', 'new_page', 'unclose_page', 'refresh', 'set_media_focus', 'set_search_focus', 'show_hide_splitters', 'synchronised_wait_switch', 'next', 'first', 'last', 'undo', 'redo', 'open_externally', 'pan_up', 'pan_down', 'pan_left', 'pan_right', 'previous', 'remove', 'zoom_in', 'zoom_out', 'zoom_switch' ] )
self._ok = wx.Button( self, id= wx.ID_OK, label = 'Ok' )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'Cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
if modifier not in CC.shortcut_wx_to_hydrus_lookup:
modifiers = []
else:
modifiers = [ CC.shortcut_wx_to_hydrus_lookup[ modifier ] ]
shortcut = ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, key, modifiers )
self._shortcut.SetValue( shortcut )
self._actions.SetSelection( self._actions.FindString( action ) )
#
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( self._shortcut, CC.FLAGS_VCENTER )
hbox.AddF( self._actions, CC.FLAGS_VCENTER )
b_box = wx.BoxSizer( wx.HORIZONTAL )
b_box.AddF( self._ok, CC.FLAGS_VCENTER )
b_box.AddF( self._cancel, CC.FLAGS_VCENTER )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( b_box, CC.FLAGS_BUTTON_SIZER )
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._ok.SetFocus )
def GetInfo( self ):
shortcut = self._shortcut.GetValue()
modifiers = shortcut._modifiers
if modifiers == []:
modifier = wx.ACCEL_NORMAL
else:
hydrus_modifier = modifiers[0]
if hydrus_modifier == CC.SHORTCUT_MODIFIER_ALT:
modifier = wx.ACCEL_ALT
elif hydrus_modifier == CC.SHORTCUT_MODIFIER_CTRL:
modifier = wx.ACCEL_CTRL
elif hydrus_modifier == CC.SHORTCUT_MODIFIER_SHIFT:
modifier = wx.ACCEL_SHIFT
else:
modifier = wx.ACCEL_NORMAL
key = shortcut._shortcut_key
return ( modifier, key, self._actions.GetStringSelection() )
class DialogInputTags( Dialog ):
def __init__( self, parent, service_key, tags ):
@ -4035,360 +3585,6 @@ class DialogSetupExport( Dialog ):
self._tags_box.SetTagsByMedia( all_media )
class DialogShortcuts( Dialog ):
def __init__( self, parent ):
Dialog.__init__( self, parent, 'setup shortcuts' )
self._edit_log = []
self._shortcuts = ClientGUICommon.ListBook( self )
self._shortcuts.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.EventSelect )
self._add = wx.Button( self, label = 'add' )
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
self._delete = wx.Button( self, label = 'delete' )
self._delete.Bind( wx.EVT_BUTTON, self.EventDelete )
self._ok = wx.Button( self, id = wx.ID_OK, label = 'ok' )
self._ok.Bind( wx.EVT_BUTTON, self.EventOK )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
default_shortcuts = self._GetDefaultShortcuts()
page = self._Panel( self._shortcuts, default_shortcuts )
self._shortcuts.AddPage( 'default', 'default', page )
all_shortcuts = HydrusGlobals.client_controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS )
names_to_shortcuts = { shortcuts.GetName() : shortcuts for shortcuts in all_shortcuts }
for ( name, shortcuts ) in names_to_shortcuts.items():
self._shortcuts.AddPageArgs( name, name, self._Panel, ( self._shortcuts, shortcuts ), {} )
#
button_hbox = wx.BoxSizer( wx.HORIZONTAL )
button_hbox.AddF( self._add, CC.FLAGS_VCENTER )
button_hbox.AddF( self._delete, CC.FLAGS_VCENTER )
buttons = wx.BoxSizer( wx.HORIZONTAL )
buttons.AddF( self._ok, CC.FLAGS_VCENTER )
buttons.AddF( self._cancel, CC.FLAGS_VCENTER )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( self._shortcuts, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( button_hbox, CC.FLAGS_VCENTER )
vbox.AddF( buttons, CC.FLAGS_BUTTON_SIZER )
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
if x < 780: x = 780
if y < 480: y = 480
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self.EventSelect, None )
wx.CallAfter( self._ok.SetFocus )
def _GetDefaultShortcuts( self ):
default_shortcuts = ClientData.Shortcuts( 'default' )
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items():
for ( key, action ) in key_dict.items():
if modifier not in CC.shortcut_wx_to_hydrus_lookup:
modifiers = []
else:
modifiers = [ CC.shortcut_wx_to_hydrus_lookup[ modifier ] ]
shortcut = ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, key, modifiers )
if action in ( 'manage_tags', 'manage_ratings', 'archive', 'inbox', 'fullscreen_switch', 'frame_back', 'frame_next', 'next', 'first', 'last', 'open_externally', 'pan_up', 'pan_down', 'pan_left', 'pan_right', 'previous', 'remove', 'zoom_in', 'zoom_out', 'zoom_switch' ):
command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, action )
default_shortcuts.SetCommand( shortcut, command )
shortcut = ClientData.Shortcut( CC.SHORTCUT_TYPE_KEYBOARD, wx.WXK_DELETE, [] )
command = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'delete' )
default_shortcuts.SetCommand( shortcut, command )
return default_shortcuts
def _CurrentPageIsUntouchable( self ):
name = self._shortcuts.GetCurrentKey()
if name is None or name in CC.SHORTCUTS_RESERVED_NAMES: # None = 'default'
return True
else:
return False
def EventDelete( self, event ):
page = self._shortcuts.GetCurrentPage()
if page is not None:
if not self._CurrentPageIsUntouchable():
name = self._shortcuts.GetCurrentKey()
self._edit_log.append( HydrusData.EditLogActionDelete( name ) )
self._shortcuts.DeleteCurrentPage()
def EventOK( self, event ):
for entry in self._edit_log:
if entry.GetAction() == HC.DELETE:
name = entry.GetIdentifier()
HydrusGlobals.client_controller.Write( 'delete_serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS, name )
default_page = self._shortcuts.GetPage( 'default' )
for page in self._shortcuts.GetActivePages():
if page is not default_page:
shortcuts = page.GetShortcuts()
HydrusGlobals.client_controller.Write( 'serialisable', shortcuts )
self.EndModal( wx.ID_OK )
def EventAdd( self, event ):
with DialogTextEntry( self, 'Enter name for these shortcuts.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
name = dlg.GetValue()
if name == '': return
while self._shortcuts.KeyExists( name ):
name += str( random.randint( 0, 9 ) )
shortcuts = ClientData.Shortcuts( name )
page = self._shortcuts.GetCurrentPage()
if page is not None:
existing_shortcuts = page.GetShortcuts()
for ( shortcut, command ) in existing_shortcuts:
shortcuts.SetCommand( shortcut, command )
page = self._Panel( self._shortcuts, shortcuts )
self._shortcuts.AddPage( name, name, page, select = True )
def EventSelect( self, event ):
if self._CurrentPageIsUntouchable():
self._delete.Disable()
else:
self._delete.Enable()
def GetShortcuts( self ):
page = self._shortcuts.GetCurrentPage()
shortcuts = page.GetShortcuts()
return shortcuts
class _Panel( wx.Panel ):
def __init__( self, parent, shortcuts ):
wx.Panel.__init__( self, parent )
self._name = shortcuts.GetName()
self._shortcuts = ClientGUICommon.SaneListCtrl( self, 120, [ ( 'shortcut', 150 ), ( 'command', -1 ) ], delete_key_callback = self.RemoveShortcuts, activation_callback = self.EditShortcuts )
self._add = wx.Button( self, label = 'add' )
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
self._add.SetForegroundColour( ( 0, 128, 0 ) )
self._edit = wx.Button( self, label = 'edit' )
self._edit.Bind( wx.EVT_BUTTON, self.EventEdit )
self._remove = wx.Button( self, label = 'remove' )
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
#
for ( shortcut, command ) in shortcuts:
sort_tuple = ( shortcut, command )
pretty_tuple = self._ConvertSortTupleToPrettyTuple( sort_tuple )
self._shortcuts.Append( pretty_tuple, sort_tuple )
self._shortcuts.SortListItems( 1 )
#
action_buttons = wx.BoxSizer( wx.HORIZONTAL )
action_buttons.AddF( self._add, CC.FLAGS_VCENTER )
action_buttons.AddF( self._edit, CC.FLAGS_VCENTER )
action_buttons.AddF( self._remove, CC.FLAGS_VCENTER )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( self._shortcuts, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( action_buttons, CC.FLAGS_BUTTON_SIZER )
self.SetSizer( vbox )
def _ConvertSortTupleToPrettyTuple( self, ( shortcut, command ) ):
return ( shortcut.ToString(), command.ToString() )
def EditShortcuts( self ):
for index in self._shortcuts.GetAllSelected():
( shortcut, command ) = self._shortcuts.GetClientData( index )
with DialogInputCustomFilterAction( self, shortcut, command ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
( shortcut, command ) = dlg.GetInfo()
sort_tuple = ( shortcut, command )
pretty_tuple = self._ConvertSortTupleToPrettyTuple( sort_tuple )
self._shortcuts.UpdateRow( index, pretty_tuple, sort_tuple )
def EventAdd( self, event ):
shortcut = ClientData.Shortcut()
command = ClientData.ApplicationCommand()
with DialogInputCustomFilterAction( self, shortcut, command ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
( shortcut, command ) = dlg.GetInfo()
sort_tuple = ( shortcut, command )
pretty_tuple = self._ConvertSortTupleToPrettyTuple( sort_tuple )
self._shortcuts.Append( pretty_tuple, sort_tuple )
def EventEdit( self, event ):
self.EditShortcuts()
def EventRemove( self, event ):
self.RemoveShortcuts()
def GetShortcuts( self ):
shortcuts = ClientData.Shortcuts( self._name )
for ( shortcut, command ) in self._shortcuts.GetClientData():
shortcuts.SetCommand( shortcut, command )
return shortcuts
def RemoveShortcuts( self ):
with DialogYesNo( self, 'Remove all selected?' ) as dlg:
if dlg.ShowModal() == wx.ID_YES:
self._shortcuts.RemoveAllSelected()
class DialogTextEntry( Dialog ):
def __init__( self, parent, message, default = '', allow_blank = False, suggestions = None ):
@ -4433,8 +3629,7 @@ class DialogTextEntry( Dialog ):
hbox.AddF( self._ok, CC.FLAGS_SMALL_INDENT )
hbox.AddF( self._cancel, CC.FLAGS_SMALL_INDENT )
st_message = wx.StaticText( self, label = message )
st_message = ClientGUICommon.BetterStaticText( self, message )
st_message.Wrap( 480 )
vbox = wx.BoxSizer( wx.VERTICAL )
@ -4507,11 +3702,13 @@ class DialogYesNo( Dialog ):
Dialog.__init__( self, parent, title, position = 'center' )
self._yes = wx.Button( self, id = wx.ID_YES, label = yes_label )
self._yes = wx.Button( self, id = wx.ID_YES )
self._yes.SetForegroundColour( ( 0, 128, 0 ) )
self._yes.SetLabelText( yes_label )
self._no = wx.Button( self, id = wx.ID_NO, label = no_label )
self._no = wx.Button( self, id = wx.ID_NO )
self._no.SetForegroundColour( ( 128, 0, 0 ) )
self._no.SetLabelText( no_label )
self._hidden_cancel = wx.Button( self, id = wx.ID_CANCEL, size = ( 0, 0 ) )
@ -4524,7 +3721,7 @@ class DialogYesNo( Dialog ):
vbox = wx.BoxSizer( wx.VERTICAL )
text = wx.StaticText( self, label = message )
text = ClientGUICommon.BetterStaticText( self, message )
text.Wrap( 480 )

View File

@ -81,7 +81,7 @@ class DialogManage4chanPass( ClientGUIDialogs.Dialog ):
self._token = wx.TextCtrl( self )
self._pin = wx.TextCtrl( self )
self._status = wx.StaticText( self )
self._status = ClientGUICommon.BetterStaticText( self )
self._SetStatus()
@ -1227,7 +1227,7 @@ class DialogManageExportFolders( ClientGUIDialogs.Dialog ):
intro = 'Here you can set the client to regularly export a certain query to a particular location.'
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._export_folders, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( file_buttons, CC.FLAGS_BUTTON_SIZER )
vbox.AddF( buttons, CC.FLAGS_BUTTON_SIZER )
@ -2331,7 +2331,7 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
intro = 'Here you can set the client to regularly check certain folders for new files to import.'
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._import_folders, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( file_buttons, CC.FLAGS_BUTTON_SIZER )
vbox.AddF( buttons, CC.FLAGS_BUTTON_SIZER )
@ -2898,7 +2898,7 @@ class DialogManagePixivAccount( ClientGUIDialogs.Dialog ):
self._id = wx.TextCtrl( self )
self._password = wx.TextCtrl( self )
self._status = wx.StaticText( self )
self._status = ClientGUICommon.BetterStaticText( self )
self._test = wx.Button( self, label = 'test' )
self._test.Bind( wx.EVT_BUTTON, self.EventTest )
@ -2945,7 +2945,7 @@ class DialogManagePixivAccount( ClientGUIDialogs.Dialog ):
text += os.linesep
text += 'You can use a throwaway account if you want--this only needs to log in.'
vbox.AddF( wx.StaticText( self, label = text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( self._status, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._test, CC.FLAGS_EXPAND_PERPENDICULAR )
@ -3073,23 +3073,71 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
#
self.Bind( wx.EVT_MENU, self.EventMenu )
self.RefreshAcceleratorTable()
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
def EventMenu( self, event ):
def _ProcessApplicationCommand( self, command ):
action = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() )
command_processed = True
if action is not None:
command_type = command.GetCommandType()
data = command.GetData()
if command_type == CC.APPLICATION_COMMAND_TYPE_SIMPLE:
( command, data ) = action
action = data
if command == 'manage_ratings': self.EventOK( event )
elif command == 'ok': self.EventOK( event )
else: event.Skip()
if action == 'manage_file_ratings':
self.EventOK( None )
else:
command_processed = False
else:
command_processed = False
return command_processed
def _ProcessShortcut( self, shortcut ):
shortcut_processed = False
command = HydrusGlobals.client_controller.GetCommandFromShortcut( [ 'media' ], shortcut )
if command is not None:
command_processed = self._ProcessApplicationCommand( command )
if command_processed:
shortcut_processed = True
return shortcut_processed
def EventCharHook( self, event ):
shortcut = ClientData.ConvertKeyEventToShortcut( event )
if shortcut is not None:
shortcut_processed = self._ProcessShortcut( shortcut )
if shortcut_processed:
return
event.Skip()
def EventOK( self, event ):
@ -3121,18 +3169,10 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
HydrusGlobals.client_controller.Write( 'save_options', HC.options )
finally: self.EndModal( wx.ID_OK )
def RefreshAcceleratorTable( self ):
interested_actions = [ 'manage_ratings' ]
entries = []
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( action ) ) for ( key, action ) in key_dict.items() if action in interested_actions ] )
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
finally:
self.EndModal( wx.ID_OK )
class _LikePanel( wx.Panel ):
@ -3472,7 +3512,7 @@ class DialogManageTagCensorship( ClientGUIDialogs.Dialog ):
intro = "Here you can set which tags or classes of tags you do not want to see. Input something like 'series:' to censor an entire namespace, or ':' for all namespaced tags, and the empty string (just hit enter with no text added) for all unnamespaced tags. You will have to refresh your current queries to see any changes."
st = wx.StaticText( self, label = intro )
st = ClientGUICommon.BetterStaticText( self, intro )
st.Wrap( 350 )
@ -3484,14 +3524,6 @@ class DialogManageTagCensorship( ClientGUIDialogs.Dialog ):
self.SetInitialSize( ( -1, 480 ) )
interested_actions = [ 'set_search_focus' ]
entries = []
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( action ) ) for ( key, action ) in key_dict.items() if action in interested_actions ] )
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
def _SetSearchFocus( self ):
@ -3660,16 +3692,6 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
self.SetInitialSize( ( 550, 780 ) )
interested_actions = [ 'set_search_focus' ]
entries = []
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( action ) ) for ( key, action ) in key_dict.items() if action in interested_actions ] )
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
self.Bind( wx.EVT_MENU, self.EventMenu )
def _SetSearchFocus( self ):
@ -3805,7 +3827,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._tag_parents, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( self._add, CC.FLAGS_LONE_BUTTON )
vbox.AddF( tags_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
@ -4252,18 +4274,6 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
self.SetInitialSize( ( 550, 780 ) )
#
interested_actions = [ 'set_search_focus' ]
entries = []
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( action ) ) for ( key, action ) in key_dict.items() if action in interested_actions ] )
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
self.Bind( wx.EVT_MENU, self.EventMenu )
def _SetSearchFocus( self ):
@ -4345,7 +4355,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
self._tag_siblings.Bind( wx.EVT_LIST_ITEM_DESELECTED, self.EventItemSelected )
self._old_siblings = ClientGUIListBoxes.ListBoxTagsStringsAddRemove( self, self._service_key, show_sibling_text = False )
self._new_sibling = wx.StaticText( self )
self._new_sibling = ClientGUICommon.BetterStaticText( self )
expand_parents = False
@ -4407,7 +4417,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._tag_siblings, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( self._add, CC.FLAGS_LONE_BUTTON )
vbox.AddF( text_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )

View File

@ -4,9 +4,13 @@ import ClientGUICanvas
import ClientGUICommon
import ClientGUIDialogs
import ClientGUIListBoxes
import ClientGUITopLevelWindows
import ClientGUIScrolledPanelsEdit
import ClientGUIScrolledPanelsManagement
import HydrusConstants as HC
import HydrusData
import HydrusGlobals
import HydrusSerialisable
import os
import wx
@ -168,8 +172,8 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
self._current_index_string = ''
self._top_hbox = wx.BoxSizer( wx.HORIZONTAL )
self._title_text = wx.StaticText( self, label = 'title' )
self._info_text = wx.StaticText( self, label = 'info' )
self._title_text = ClientGUICommon.BetterStaticText( self, 'title' )
self._info_text = ClientGUICommon.BetterStaticText( self, 'info' )
self._button_hbox = wx.BoxSizer( wx.HORIZONTAL )
self._PopulateLeftButtons()
@ -224,6 +228,18 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
return ( should_resize, ideal_size, ideal_position )
def _ManageShortcuts( self ):
with ClientGUITopLevelWindows.DialogManage( self, 'manage shortcuts' ) as dlg:
panel = ClientGUIScrolledPanelsManagement.ManageShortcutsPanel( dlg )
dlg.SetPanel( panel )
dlg.ShowModal()
def _PopulateCenterButtons( self ):
self._archive_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.archive, self._Archive )
@ -248,7 +264,7 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
self._previous_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.previous, HydrusGlobals.client_controller.pub, 'canvas_show_previous', self._canvas_key )
self._previous_button.SetToolTipString( 'previous' )
self._index_text = wx.StaticText( self, label = 'index' )
self._index_text = ClientGUICommon.BetterStaticText( self, 'index' )
self._next_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.next, HydrusGlobals.client_controller.pub, 'canvas_show_next', self._canvas_key )
self._next_button.SetToolTipString( 'next' )
@ -260,7 +276,7 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
def _PopulateRightButtons( self ):
self._zoom_text = wx.StaticText( self, label = 'zoom' )
self._zoom_text = ClientGUICommon.BetterStaticText( self, 'zoom' )
zoom_in = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.zoom_in, HydrusGlobals.client_controller.pub, 'canvas_zoom_in', self._canvas_key )
zoom_in.SetToolTipString( 'zoom in' )
@ -271,6 +287,15 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
zoom_switch = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.zoom_switch, HydrusGlobals.client_controller.pub, 'canvas_zoom_switch', self._canvas_key )
zoom_switch.SetToolTipString( 'zoom switch' )
menu_items = []
menu_items.append( ( 'normal', 'edit shortcuts', 'edit your sets of shortcuts, and change what shortcuts are currently active on this media viewer', self._ManageShortcuts ) )
menu_items.append( ( 'normal', 'set current shortcuts', 'change which custom shortcuts are active on this media viewers', HydrusData.Call( HydrusGlobals.client_controller.pub, 'edit_media_viewer_custom_shortcuts', self._canvas_key ) ) )
menu_items.append( ( 'normal', 'set default shortcuts', 'change which custom shortcuts are typically active on new media viewers', self._SetDefaultShortcuts ) )
shortcuts = ClientGUICommon.MenuBitmapButton( self, CC.GlobalBMPs.keyboard, menu_items )
shortcuts.SetToolTipString( 'shortcuts' )
fullscreen_switch = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.fullscreen_switch, HydrusGlobals.client_controller.pub, 'canvas_fullscreen_switch', self._canvas_key )
fullscreen_switch.SetToolTipString( 'fullscreen switch' )
@ -284,6 +309,7 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
self._top_hbox.AddF( zoom_in, CC.FLAGS_VCENTER )
self._top_hbox.AddF( zoom_out, CC.FLAGS_VCENTER )
self._top_hbox.AddF( zoom_switch, CC.FLAGS_VCENTER )
self._top_hbox.AddF( shortcuts, CC.FLAGS_VCENTER )
self._top_hbox.AddF( fullscreen_switch, CC.FLAGS_VCENTER )
self._top_hbox.AddF( open_externally, CC.FLAGS_VCENTER )
self._top_hbox.AddF( close, CC.FLAGS_VCENTER )
@ -359,6 +385,40 @@ class FullscreenHoverFrameTop( FullscreenHoverFrame ):
def _SetDefaultShortcuts( self ):
new_options = HydrusGlobals.client_controller.GetNewOptions()
default_media_viewer_custom_shortcuts = new_options.GetStringList( 'default_media_viewer_custom_shortcuts' )
all_shortcut_names = HydrusGlobals.client_controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS )
custom_shortcuts_names = [ name for name in all_shortcut_names if name not in CC.SHORTCUTS_RESERVED_NAMES ]
if len( custom_shortcuts_names ) == 0:
wx.MessageBox( 'You have no custom shortcuts set up, so you cannot choose any!' )
return
with ClientGUITopLevelWindows.DialogEdit( self, 'manage shortcuts' ) as dlg:
choice_tuples = [ ( name, name, name in default_media_viewer_custom_shortcuts ) for name in custom_shortcuts_names ]
panel = ClientGUIScrolledPanelsEdit.EditChooseMultiple( dlg, choice_tuples )
dlg.SetPanel( panel )
if dlg.ShowModal() == wx.ID_OK:
new_default_media_viewer_custom_shortcuts = panel.GetValue()
new_options.SetStringList( 'default_media_viewer_custom_shortcuts', new_default_media_viewer_custom_shortcuts )
def AddCommand( self, label, func ):
command_button = ClientGUICommon.BetterButton( self, label, func )
@ -455,7 +515,6 @@ class FullscreenHoverFrameTopDuplicatesFilter( FullscreenHoverFrameTop ):
menu_items = []
menu_items.append( ( 'normal', 'edit tag/ratings merge options and whether to delete bad files', 'edit what happens when you filter files', self._EditMergeOptions ) )
menu_items.append( ( 'normal', 'edit shortcuts', 'edit how to quickly filter files', self._EditShortcuts ) )
cog_button = ClientGUICommon.MenuBitmapButton( self, CC.GlobalBMPs.cog, menu_items )
@ -469,17 +528,6 @@ class FullscreenHoverFrameTopDuplicatesFilter( FullscreenHoverFrameTop ):
wx.MessageBox( 'This doesn\'t do anything yet!' )
def _EditShortcuts( self ):
with ClientGUIDialogs.DialogShortcuts( self ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
HydrusGlobals.client_controller.pub( 'refresh_shortcuts' )
def _PopulateLeftButtons( self ):
FullscreenHoverFrameTop._PopulateLeftButtons( self )
@ -717,7 +765,7 @@ class FullscreenHoverFrameRatings( FullscreenHoverFrame ):
self._ResetData()
class FullscreenHoverFrameTags( FullscreenHoverFrame ):
def __init__( self, parent, canvas_key ):

View File

@ -55,7 +55,7 @@ class ListBox( wx.ScrolledWindow ):
self.Bind( wx.EVT_LEFT_DOWN, self.EventMouseSelect )
self.Bind( wx.EVT_LEFT_DCLICK, self.EventDClick )
self.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown )
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
def __len__( self ):
@ -472,14 +472,7 @@ class ListBox( wx.ScrolledWindow ):
self._ordered_terms.sort( key = lexicographic_key )
def EventDClick( self, event ):
self._Activate()
def EventEraseBackground( self, event ): pass
def EventKeyDown( self, event ):
def EventCharHook( self, event ):
shift = event.ShiftDown()
ctrl = event.CmdDown()
@ -549,6 +542,13 @@ class ListBox( wx.ScrolledWindow ):
def EventDClick( self, event ):
self._Activate()
def EventEraseBackground( self, event ): pass
def EventMouseSelect( self, event ):
self._HandleClick( event )
@ -1041,7 +1041,7 @@ class ListBoxTagsPredicates( ListBoxTags ):
def EventKeyDown( self, event ):
def EventCharHook( self, event ):
# this realigns the hit index in the down direction
@ -1070,7 +1070,7 @@ class ListBoxTagsPredicates( ListBoxTags ):
if hit_index is None:
ListBoxTags.EventKeyDown( self, event )
ListBoxTags.EventCharHook( self, event )
else:
@ -1696,7 +1696,7 @@ class ListBoxTagsStringsAddRemove( ListBoxTagsStrings ):
def EventKeyDown( self, event ):
def EventCharHook( self, event ):
( modifier, key ) = ClientData.ConvertKeyEventToSimpleTuple( event )

View File

@ -964,6 +964,7 @@ class ManagementPanelDuplicateFilter( ManagementPanel ):
self._search_distance_button.Disable()
self._search_distance_spinctrl.Disable()
self._show_some_dupes.Disable()
self._launch_filter.Disable()
self._job_key = ClientThreading.JobKey( cancellable = True )
@ -1156,10 +1157,12 @@ class ManagementPanelDuplicateFilter( ManagementPanel ):
if num_unknown > 0:
self._show_some_dupes.Enable()
self._launch_filter.Enable()
else:
self._show_some_dupes.Disable()
self._launch_filter.Disable()

View File

@ -9,6 +9,7 @@ import ClientGUIDialogs
import ClientGUIDialogsManage
import ClientGUIMenus
import ClientGUIScrolledPanelsManagement
import ClientGUIShortcuts
import ClientGUITopLevelWindows
import ClientMedia
import ClientTags
@ -123,6 +124,8 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
self._PublishSelectionChange()
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
def _Archive( self ):
@ -322,40 +325,6 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
def _CustomFilter( self, shortcuts_name = None ):
shortcuts = None
if shortcuts_name is not None:
shortcuts = HydrusGlobals.client_controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS, shortcuts_name )
else:
with ClientGUIDialogs.DialogShortcuts( self ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
shortcuts = dlg.GetShortcuts()
if shortcuts is not None:
media_results = self.GenerateMediaResults( discriminant = CC.DISCRIMINANT_LOCAL, selected_media = set( self._selected_media ), for_media_viewer = True )
if len( media_results ) > 0:
canvas_frame = ClientGUICanvas.CanvasFrame( self.GetTopLevelParent() )
canvas_window = ClientGUICanvas.CanvasMediaListCustomFilter( canvas_frame, self._page_key, media_results, shortcuts )
canvas_frame.SetCanvas( canvas_window )
def _Delete( self, file_service_key = None ):
if file_service_key is None:
@ -536,7 +505,7 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
def _Filter( self ):
def _ArchiveDeleteFilter( self ):
media_results = self.GenerateMediaResults( discriminant = CC.DISCRIMINANT_LOCAL_BUT_NOT_IN_TRASH, selected_media = set( self._selected_media ), for_media_viewer = True )
@ -544,7 +513,7 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
canvas_frame = ClientGUICanvas.CanvasFrame( self.GetTopLevelParent() )
canvas_window = ClientGUICanvas.CanvasMediaListFilterInbox( canvas_frame, self._page_key, media_results )
canvas_window = ClientGUICanvas.CanvasMediaListFilterArchiveDelete( canvas_frame, self._page_key, media_results )
canvas_frame.SetCanvas( canvas_window )
@ -968,6 +937,74 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
def _ProcessApplicationCommand( self, command ):
command_processed = True
command_type = command.GetCommandType()
data = command.GetData()
if command_type == CC.APPLICATION_COMMAND_TYPE_SIMPLE:
action = data
if action == 'manage_file_ratings':
self._ManageRatings()
elif action == 'manage_file_tags':
self._ManageTags()
elif action == 'archive_file':
self._Archive()
elif action == 'inbox_file':
self._Inbox()
elif action == 'remove_file_from_view':
self._Remove()
elif action == 'open_file_in_external_program':
self._OpenExternally()
if action == 'launch_the_archive_delete_filter':
self._ArchiveDeleteFilter()
else:
command_processed = False
else:
command_processed = False
return command_processed
def _ProcessShortcut( self, shortcut ):
shortcut_processed = False
command = HydrusGlobals.client_controller.GetCommandFromShortcut( [ 'media' ], shortcut )
if command is not None:
command_processed = self._ProcessApplicationCommand( command )
shortcut_processed = command_processed
return shortcut_processed
def _PublishSelectionChange( self, force_reload = False ):
if len( self._selected_media ) == 0:
@ -993,6 +1030,15 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
def _RedrawMedia( self, media ): pass
def _Remove( self ):
singletons = [ media for media in self._selected_media if not media.IsCollection() ]
collections = [ media for media in self._selected_media if media.IsCollection() ]
self._RemoveMedia( singletons, collections )
def _RescindDownloadSelected( self ):
hashes = self._GetSelectedHashes( discriminant = CC.DISCRIMINANT_NOT_LOCAL )
@ -1250,6 +1296,26 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
def EventCharHook( self, event ):
if ClientGUIShortcuts.IShouldCatchCharHook( self ):
shortcut = ClientData.ConvertKeyEventToShortcut( event )
if shortcut is not None:
shortcut_processed = self._ProcessShortcut( shortcut )
if shortcut_processed:
return
event.Skip()
def FileDumped( self, page_key, hash, status ):
if page_key == self._page_key:
@ -1869,15 +1935,6 @@ class MediaPanelThumbnails( MediaPanel ):
def _Remove( self ):
singletons = [ media for media in self._selected_media if not media.IsCollection() ]
collections = [ media for media in self._selected_media if media.IsCollection() ]
self._RemoveMedia( singletons, collections )
def _RemoveMedia( self, singleton_media, collected_media ):
if self._focussed_media is not None:
@ -2105,7 +2162,7 @@ class MediaPanelThumbnails( MediaPanel ):
( command, data ) = action
if command == 'archive': self._Archive()
if command == 'archive_file': self._Archive()
elif command == 'copy_bmp': self._CopyBMPToClipboard()
elif command == 'copy_files': self._CopyFilesToClipboard()
elif command == 'copy_hash': self._CopyHashToClipboard( data )
@ -2120,11 +2177,7 @@ class MediaPanelThumbnails( MediaPanel ):
if self._focussed_media is not None: self._HitMedia( self._focussed_media, True, False )
elif command == 'custom_filter':
self._CustomFilter( data )
elif command == 'delete':
elif command == 'delete_file':
if data is None:
@ -2137,15 +2190,15 @@ class MediaPanelThumbnails( MediaPanel ):
elif command == 'export_files': self._ExportFiles()
elif command == 'export_tags': self._ExportTags()
elif command == 'filter': self._Filter()
elif command == 'launch_the_archive_delete_filter': self._ArchiveDeleteFilter()
elif command == 'fullscreen': self._FullScreen()
elif command == 'inbox': self._Inbox()
elif command == 'manage_ratings': self._ManageRatings()
elif command == 'manage_tags': self._ManageTags()
elif command == 'inbox_file': self._Inbox()
elif command == 'manage_file_ratings': self._ManageRatings()
elif command == 'manage_file_tags': self._ManageTags()
elif command == 'modify_account': self._ModifyUploaders( data )
elif command == 'open_externally': self._OpenExternally()
elif command == 'open_file_in_external_program': self._OpenExternally()
elif command == 'petition': self._PetitionFiles( data )
elif command == 'remove': self._Remove()
elif command == 'remove_file_from_view': self._Remove()
elif command == 'rescind_petition': self._RescindPetitionFiles( data )
elif command == 'rescind_upload': self._RescindUploadFiles( data )
elif command == 'scroll_end': self._ScrollEnd( False )
@ -2779,38 +2832,7 @@ class MediaPanelThumbnails( MediaPanel ):
if selection_has_local and multiple_selected:
filter_menu = wx.Menu()
if selection_has_local_file_domain:
ClientGUIMenus.AppendMenuItem( self, filter_menu, 'archive/delete', 'Launch a special media viewer that will quickly archive (left-click) and delete (right-click) the selected media.', self._Filter )
shortcut_names = HydrusGlobals.client_controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS )
shortcut_names = [ name for name in shortcut_names if name not in CC.SHORTCUTS_RESERVED_NAMES ]
if len( shortcut_names ) > 0:
custom_shortcuts_menu = wx.Menu()
ClientGUIMenus.AppendMenuItem( self, custom_shortcuts_menu, 'manage', 'Manage your different custom filters and their shortcuts.', self._CustomFilter )
ClientGUIMenus.AppendSeparator( custom_shortcuts_menu )
for shortcut_name in shortcut_names:
ClientGUIMenus.AppendMenuItem( self, custom_shortcuts_menu, shortcut_name, 'Open the ' + shortcut_name + ' custom filter.', self._CustomFilter, shortcut_name )
ClientGUIMenus.AppendMenu( filter_menu, custom_shortcuts_menu, 'custom filters' )
else:
ClientGUIMenus.AppendMenuItem( self, filter_menu, 'create a custom filter', 'Create a custom filter that uses non-default shortcuts.', self._CustomFilter )
ClientGUIMenus.AppendMenu( menu, filter_menu, 'filter' )
ClientGUIMenus.AppendMenuItem( self, menu, 'archive/delete filter', 'Launch a special media viewer that will quickly archive (left-click) and delete (right-click) the selected media.', self._ArchiveDeleteFilter )
ClientGUIMenus.AppendSeparator( menu )
@ -3038,8 +3060,8 @@ class MediaPanelThumbnails( MediaPanel ):
( wx.ACCEL_NORMAL, wx.WXK_NUMPAD_HOME, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'scroll_home' ) ),
( wx.ACCEL_NORMAL, wx.WXK_END, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'scroll_end' ) ),
( wx.ACCEL_NORMAL, wx.WXK_NUMPAD_END, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'scroll_end' ) ),
( wx.ACCEL_NORMAL, wx.WXK_DELETE, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete' ) ),
( wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DELETE, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete' ) ),
( wx.ACCEL_NORMAL, wx.WXK_DELETE, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete_file' ) ),
( wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DELETE, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete_file' ) ),
( wx.ACCEL_NORMAL, wx.WXK_RETURN, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'fullscreen' ) ),
( wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ENTER, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'fullscreen' ) ),
( wx.ACCEL_NORMAL, wx.WXK_UP, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'key_up' ) ),
@ -3071,12 +3093,10 @@ class MediaPanelThumbnails( MediaPanel ):
if HC.PLATFORM_OSX:
entries.append( ( wx.ACCEL_NORMAL, wx.WXK_BACK, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete' ) ) )
entries.append( ( wx.ACCEL_NORMAL, wx.WXK_BACK, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete_file' ) ) )
entries.append( ( wx.ACCEL_SHIFT, wx.WXK_BACK, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'undelete' ) ) )
for ( modifier, key_dict ) in HC.options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( action ) ) for ( key, action ) in key_dict.items() if action not in ( 'previous', 'next' ) ] )
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )

View File

@ -48,7 +48,7 @@ class OptionsPanelImportFiles( OptionsPanel ):
vbox.AddF( self._auto_archive, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._exclude_deleted, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( wx.StaticText( self, label = 'minimum:' ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, 'minimum:' ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._min_size, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._min_resolution, CC.FLAGS_EXPAND_PERPENDICULAR )
@ -300,7 +300,7 @@ class OptionsPanelTags( OptionsPanel ):
self._service_keys_to_checkbox_info[ service_key ] = []
outer_gridbox.AddF( wx.StaticText( self, label = service.GetName() ), CC.FLAGS_VCENTER )
outer_gridbox.AddF( ClientGUICommon.BetterStaticText( self, service.GetName() ), CC.FLAGS_VCENTER )
vbox = wx.BoxSizer( wx.VERTICAL )

View File

@ -437,7 +437,7 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._name_and_type = wx.StaticText( self )
self._name_and_type = ClientGUICommon.BetterStaticText( self )
#
@ -481,7 +481,7 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._file_info_st = wx.StaticText( self )
self._file_info_st = ClientGUICommon.BetterStaticText( self )
#
@ -551,9 +551,9 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._address = wx.StaticText( self )
self._functional = wx.StaticText( self )
self._bandwidth_summary = wx.StaticText( self )
self._address = ClientGUICommon.BetterStaticText( self )
self._functional = ClientGUICommon.BetterStaticText( self )
self._bandwidth_summary = ClientGUICommon.BetterStaticText( self )
self._bandwidth_panel = wx.Panel( self )
#
@ -631,10 +631,10 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._title_and_expires_st = wx.StaticText( self )
self._status_st = wx.StaticText( self )
self._next_sync_st = wx.StaticText( self )
self._bandwidth_summary = wx.StaticText( self )
self._title_and_expires_st = ClientGUICommon.BetterStaticText( self )
self._status_st = ClientGUICommon.BetterStaticText( self )
self._next_sync_st = ClientGUICommon.BetterStaticText( self )
self._bandwidth_summary = ClientGUICommon.BetterStaticText( self )
self._bandwidth_panel = wx.Panel( self )
self._refresh_account_button = ClientGUICommon.BetterButton( self, 'refresh account', self._RefreshAccount )
@ -805,7 +805,7 @@ class ReviewServicePanel( wx.Panel ):
self._content_panel = wx.Panel( self )
self._metadata_st = wx.StaticText( self )
self._metadata_st = ClientGUICommon.BetterStaticText( self )
self._download_progress = ClientGUICommon.TextAndGauge( self )
self._processing_progress = ClientGUICommon.TextAndGauge( self )
@ -1075,7 +1075,7 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._name_and_type = wx.StaticText( self )
self._name_and_type = ClientGUICommon.BetterStaticText( self )
#
@ -1114,7 +1114,7 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._name_and_type = wx.StaticText( self )
self._name_and_type = ClientGUICommon.BetterStaticText( self )
#
@ -1153,7 +1153,7 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._rating_info_st = wx.StaticText( self )
self._rating_info_st = ClientGUICommon.BetterStaticText( self )
#
@ -1215,7 +1215,7 @@ class ReviewServicePanel( wx.Panel ):
self._my_updater = ClientGUICommon.ThreadToGUIUpdater( self, self._Refresh )
self._tag_info_st = wx.StaticText( self )
self._tag_info_st = ClientGUICommon.BetterStaticText( self )
self._advanced_content_update = ClientGUICommon.BetterButton( self, 'advanced service-wide update', self._AdvancedContentUpdate )

View File

@ -56,16 +56,16 @@ class PanelPredicateSystemAge( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:age' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:age' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._years, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'years' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'years' ), CC.FLAGS_VCENTER )
hbox.AddF( self._months, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'months' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'months' ), CC.FLAGS_VCENTER )
hbox.AddF( self._days, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'days' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'days' ), CC.FLAGS_VCENTER )
hbox.AddF( self._hours, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'hours' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'hours' ), CC.FLAGS_VCENTER )
self.SetSizer( hbox )
@ -109,12 +109,12 @@ class PanelPredicateSystemDuration( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:duration' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:duration' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._duration_s, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 's' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 's' ), CC.FLAGS_VCENTER )
hbox.AddF( self._duration_ms, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = 'ms' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'ms' ), CC.FLAGS_VCENTER )
self.SetSizer( hbox )
@ -148,7 +148,7 @@ class PanelPredicateSystemFileService( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:file service:' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:file service:' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._current_pending, CC.FLAGS_VCENTER )
hbox.AddF( self._file_service_key, CC.FLAGS_VCENTER )
@ -183,7 +183,7 @@ class PanelPredicateSystemHash( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:hash=' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:hash=' ), CC.FLAGS_VCENTER )
hbox.AddF( self._hash, CC.FLAGS_VCENTER )
hbox.AddF( self._hash_type, CC.FLAGS_VCENTER )
@ -233,7 +233,7 @@ class PanelPredicateSystemHeight( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:height' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:height' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._height, CC.FLAGS_VCENTER )
@ -267,7 +267,7 @@ class PanelPredicateSystemLimit( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:limit=' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:limit=' ), CC.FLAGS_VCENTER )
hbox.AddF( self._limit, CC.FLAGS_VCENTER )
self.SetSizer( hbox )
@ -305,7 +305,7 @@ class PanelPredicateSystemMime( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:mime' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:mime' ), CC.FLAGS_VCENTER )
hbox.AddF( self._mimes, CC.FLAGS_VCENTER )
self.SetSizer( hbox )
@ -344,7 +344,7 @@ class PanelPredicateSystemNumPixels( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:num_pixels' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:num_pixels' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._num_pixels, CC.FLAGS_VCENTER )
hbox.AddF( self._unit, CC.FLAGS_VCENTER )
@ -383,7 +383,7 @@ class PanelPredicateSystemNumTags( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:num_tags' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:num_tags' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._num_tags, CC.FLAGS_VCENTER )
@ -421,7 +421,7 @@ class PanelPredicateSystemNumWords( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:num_words' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:num_words' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._num_words, CC.FLAGS_VCENTER )
@ -470,7 +470,7 @@ class PanelPredicateSystemRating( PanelPredicateSystem ):
self._like_checkboxes_to_info[ not_rated_checkbox ] = ( service_key, ClientRatings.NULL )
self._like_rating_ctrls.append( rating_ctrl )
gridbox.AddF( wx.StaticText( self, label = name ), CC.FLAGS_VCENTER )
gridbox.AddF( ClientGUICommon.BetterStaticText( self, name ), CC.FLAGS_VCENTER )
gridbox.AddF( rated_checkbox, CC.FLAGS_VCENTER )
gridbox.AddF( not_rated_checkbox, CC.FLAGS_VCENTER )
gridbox.AddF( ( 20, 20 ), CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
@ -501,7 +501,7 @@ class PanelPredicateSystemRating( PanelPredicateSystem ):
self._numerical_checkboxes_to_info[ not_rated_checkbox ] = ( service_key, ClientRatings.NULL )
self._numerical_rating_ctrls_to_info[ rating_ctrl ] = choice
gridbox.AddF( wx.StaticText( self, label = name ), CC.FLAGS_VCENTER )
gridbox.AddF( ClientGUICommon.BetterStaticText( self, name ), CC.FLAGS_VCENTER )
gridbox.AddF( rated_checkbox, CC.FLAGS_VCENTER )
gridbox.AddF( not_rated_checkbox, CC.FLAGS_VCENTER )
gridbox.AddF( choice, CC.FLAGS_VCENTER )
@ -636,10 +636,10 @@ class PanelPredicateSystemRatio( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:ratio' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:ratio' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._width, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label = ':' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, ':' ), CC.FLAGS_VCENTER )
hbox.AddF( self._height, CC.FLAGS_VCENTER )
self.SetSizer( hbox )
@ -676,7 +676,7 @@ class PanelPredicateSystemSimilarTo( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:similar_to' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:similar_to' ), CC.FLAGS_VCENTER )
hbox.AddF( self._hash, CC.FLAGS_VCENTER )
hbox.AddF( wx.StaticText( self, label=u'\u2248' ), CC.FLAGS_VCENTER )
hbox.AddF( self._max_hamming, CC.FLAGS_VCENTER )
@ -729,7 +729,7 @@ class PanelPredicateSystemSize( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:size' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:size' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._size, CC.FLAGS_VCENTER )
hbox.AddF( self._unit, CC.FLAGS_VCENTER )
@ -768,7 +768,7 @@ class PanelPredicateSystemWidth( PanelPredicateSystem ):
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label = 'system:width' ), CC.FLAGS_VCENTER )
hbox.AddF( ClientGUICommon.BetterStaticText( self, 'system:width' ), CC.FLAGS_VCENTER )
hbox.AddF( self._sign, CC.FLAGS_VCENTER )
hbox.AddF( self._width, CC.FLAGS_VCENTER )

View File

@ -190,7 +190,7 @@ class EditFrameLocationPanel( ClientGUIScrolledPanels.EditPanel ):
text = 'Setting frame location info for ' + name + '.'
vbox.AddF( wx.StaticText( self, label = text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._remember_size, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._remember_position, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._last_size, CC.FLAGS_EXPAND_PERPENDICULAR )
@ -312,7 +312,7 @@ class EditMediaViewOptionsPanel( ClientGUIScrolledPanels.EditPanel ):
text = 'Setting media view options for ' + HC.mime_string_lookup[ self._mime ] + '.'
vbox.AddF( wx.StaticText( self, label = text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.BetterStaticText( self, text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( ClientGUICommon.WrapInText( self._media_show_action, self, 'media viewer show action:' ), CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( ClientGUICommon.WrapInText( self._preview_show_action, self, 'preview show action:' ), CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
@ -343,7 +343,7 @@ class EditMediaViewOptionsPanel( ClientGUIScrolledPanels.EditPanel ):
vbox.AddF( self._exact_zooms_only, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( wx.StaticText( self, label = 'Nearest neighbour is fast and ugly, 8x8 lanczos and area resampling are slower but beautiful.' ), CC.FLAGS_VCENTER )
vbox.AddF( ClientGUICommon.BetterStaticText( self, 'Nearest neighbour is fast and ugly, 8x8 lanczos and area resampling are slower but beautiful.' ), CC.FLAGS_VCENTER )
vbox.AddF( ClientGUICommon.WrapInText( self._scale_up_quality, self, '>100% (interpolation) quality:' ), CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( ClientGUICommon.WrapInText( self._scale_down_quality, self, '<100% (decimation) quality:' ), CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
@ -419,7 +419,7 @@ class EditSeedCachePanel( ClientGUIScrolledPanels.EditPanel ):
self._controller = controller
self._seed_cache = seed_cache
self._text = wx.StaticText( self, label = 'initialising' )
self._text = ClientGUICommon.BetterStaticText( self, 'initialising' )
self._seed_cache_control = ClientGUIControls.SeedCacheControl( self, self._seed_cache )
vbox = wx.BoxSizer( wx.VERTICAL )
@ -524,7 +524,7 @@ class EditServersideService( ClientGUIScrolledPanels.EditPanel ):
self._port = wx.SpinCtrl( self, min = 1, max = 65535 )
self._upnp_port = ClientGUICommon.NoneableSpinCtrl( self, 'external upnp port', none_phrase = 'do not forward port', min = 1, max = 65535 )
self._bandwidth_tracker_st = wx.StaticText( self )
self._bandwidth_tracker_st = ClientGUICommon.BetterStaticText( self )
#
@ -648,7 +648,7 @@ class EditServersideService( ClientGUIScrolledPanels.EditPanel ):
ClientGUICommon.StaticBox.__init__( self, parent, 'server-wide bandwidth' )
self._bandwidth_tracker_st = wx.StaticText( self )
self._bandwidth_tracker_st = ClientGUICommon.BetterStaticText( self )
bandwidth_rules = dictionary[ 'server_bandwidth_rules' ]
@ -680,6 +680,47 @@ class EditServersideService( ClientGUIScrolledPanels.EditPanel ):
class EditChooseMultiple( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent, choice_tuples ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
self._checkboxes = wx.CheckListBox( self )
self._checkboxes.SetMinSize( ( 320, 420 ) )
for ( i, ( label, data, selected ) ) in enumerate( choice_tuples ):
self._checkboxes.Append( label, data )
if selected:
self._checkboxes.Check( i )
#
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( self._checkboxes, CC.FLAGS_EXPAND_BOTH_WAYS )
self.SetSizer( vbox )
def GetValue( self ):
datas = []
for index in self._checkboxes.GetChecked():
datas.append( self._checkboxes.GetClientData( index ) )
return datas
class EditSubscriptionPanel( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent, subscription ):

File diff suppressed because it is too large Load Diff

View File

@ -124,7 +124,7 @@ class AdvancedContentUpdatePanel( ClientGUIScrolledPanels.ReviewPanel ):
message += ' files on ' + self._service_name
title_st = wx.StaticText( self, label = message)
title_st = ClientGUICommon.BetterStaticText( self, message )
title_st.Wrap( 540 )
@ -132,7 +132,7 @@ class AdvancedContentUpdatePanel( ClientGUIScrolledPanels.ReviewPanel ):
message += os.linesep * 2
message += 'You may need to refresh your existing searches to see their effect.'
st = wx.StaticText( self, label = message )
st = ClientGUICommon.BetterStaticText( self, message )
st.Wrap( 540 )

View File

@ -1,5 +1,21 @@
import ClientGUICommon
import HydrusGlobals
import wx
def IShouldCatchCharHook( evt_handler ):
if HydrusGlobals.client_controller.MenuIsOpen():
return False
if not ClientGUICommon.WindowOrSameTLPChildHasFocus( evt_handler ):
return False
return True
class ShortcutsHandler( object ):
def __init__( self, parent, initial_shortcuts = None ):

View File

@ -360,7 +360,7 @@ class DialogThatResizes( NewDialog ):
class DialogThatTakesScrollablePanel( DialogThatResizes ):
def __init__( self, parent, title, frame_key ):
def __init__( self, parent, title, frame_key = 'regular_dialog' ):
self._panel = None
@ -468,7 +468,7 @@ class DialogNullipotent( DialogThatTakesScrollablePanelClose ):
def __init__( self, parent, title ):
DialogThatTakesScrollablePanelClose.__init__( self, parent, title, 'regular_dialog' )
DialogThatTakesScrollablePanelClose.__init__( self, parent, title )
def EventOk( self, event ):
@ -504,7 +504,7 @@ class DialogEdit( DialogThatTakesScrollablePanelApplyCancel ):
def __init__( self, parent, title ):
DialogThatTakesScrollablePanelApplyCancel.__init__( self, parent, title, 'regular_dialog' )
DialogThatTakesScrollablePanelApplyCancel.__init__( self, parent, title )
def EventOk( self, event ):

View File

@ -49,7 +49,7 @@ options = {}
# Misc
NETWORK_VERSION = 18
SOFTWARE_VERSION = 251
SOFTWARE_VERSION = 252
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -72,9 +72,8 @@ class TestDBDialogs( unittest.TestCase ):
HydrusGlobals.test_controller.SetRead( 'serialisable_named', [] )
title = 'subs test'
frame_key = 'regular_dialog'
with ClientGUITopLevelWindows.DialogManage( None, title, frame_key ) as dlg:
with ClientGUITopLevelWindows.DialogManage( None, title ) as dlg:
panel = ClientGUIScrolledPanelsManagement.ManageSubscriptionsPanel( dlg )
@ -134,7 +133,7 @@ class TestNonDBDialogs( unittest.TestCase ):
def test_dialog_finish_filtering( self ):
with ClientGUIDialogs.DialogFinishFiltering( None, 3, 5 ) as dlg:
with ClientGUIDialogs.DialogFinishFiltering( None, 'keep 3 files and delete 5 files?' ) as dlg:
HitButton( dlg._back )
@ -143,7 +142,7 @@ class TestNonDBDialogs( unittest.TestCase ):
self.assertEqual( result, wx.ID_CANCEL )
with ClientGUIDialogs.DialogFinishFiltering( None, 3, 5 ) as dlg:
with ClientGUIDialogs.DialogFinishFiltering( None, 'keep 3 files and delete 5 files?' ) as dlg:
HitButton( dlg._commit )
@ -152,7 +151,7 @@ class TestNonDBDialogs( unittest.TestCase ):
self.assertEqual( result, wx.ID_YES )
with ClientGUIDialogs.DialogFinishFiltering( None, 3, 5 ) as dlg:
with ClientGUIDialogs.DialogFinishFiltering( None, 'keep 3 files and delete 5 files?' ) as dlg:
HitButton( dlg._forget )

View File

@ -129,7 +129,7 @@ class TestSerialisables( unittest.TestCase ):
acs = []
acs.append( ( ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'archive' ), 'archive' ) )
acs.append( ( ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'archive_file' ), 'archive_file' ) )
acs.append( ( ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( HydrusData.GenerateKey(), HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_FLIP, 'test' ) ), 'flip on/off mappings "test" for unknown service!' ) )
acs.append( ( ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( CC.LOCAL_TAG_SERVICE_KEY, HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_FLIP, 'test' ) ), 'flip on/off mappings "test" for local tags' ) )
acs.append( ( ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( HydrusData.GenerateKey(), HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_SET, 0.4 ) ), 'set ratings "0.4" for unknown service!' ) )
@ -189,7 +189,7 @@ class TestSerialisables( unittest.TestCase ):
self._dump_and_load_and_test( shortcuts, test )
command_1 = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'archive' )
command_1 = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_SIMPLE, 'archive_file' )
command_2 = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( HydrusData.GenerateKey(), HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_FLIP, 'test' ) )
command_3 = ClientData.ApplicationCommand( CC.APPLICATION_COMMAND_TYPE_CONTENT, ( CC.LOCAL_TAG_SERVICE_KEY, HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_FLIP, 'test' ) )