diff --git a/docs/changelog.md b/docs/changelog.md
index 6d9b99640..6b92dce52 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -7,6 +7,43 @@ title: Changelog
!!! note
This is the new changelog, only the most recent builds. For all versions, see the [old changelog](old_changelog.html).
+## [Version 582](https://github.com/hydrusnetwork/hydrus/releases/tag/v582)
+
+### fixes
+
+* fixed an issue where setting a file 'collect' was not automatically sorting the collected objects internally properly. normally when you collect, each collected object is supposed to be sorted internally by filesize or namespace or whatever--this is working again
+* fixed a weird internal error state in the import folders manager where it could get confused about and throw an error regarding the import folders' next work times if an internal update notification occured during an import folder working
+* fixed a typo error with the shortcut set 'special duplicate' button
+* fixed pasting new query texts into the manage subscriptions dialog when one of the pasted texts resurrects a DEAD query. my new summary generation text was handling the DEAD report wrong!
+
+### misc
+
+* the advanced 'all deleted files' service, which is mostly just used for behind the scenes caching calculations, is renamed to 'deleted from anywhere'. the related 'regen->all deleted files' database command is also moved to 'check and repair->sync combined deleted files'
+* the edit tag filter panel's 'load' button now shows all the current tag repositories' tag filters
+* when you hit ctrl-enter on some tags (or otherwise trigger a linked remove+add action) in an active search list (e.g. top-left on a search page), which causes those tags to invert and thus sometimes sorted to a different position, the current selection now propagates through the inversion, with the keyboard focus moved to the post-topmost item. so, you can now basically hit ctrl+enter twice for a no-op
+* fixed the paste button in the new 'purge tags' dialog
+* thanks to a user, we have a new 'Purple' stylesheet
+* I tweaked the some default stylesheet colours and think I fixed the display of the 'valid/invalid' controls you sometimes see (for instance in the new regex input, which goes green/red) for dark mode stylesheets that don't define colours for these. previously, the dark mode text, usually a light grey, was being washed out by the default green
+
+### custom colours in QSS
+
+* you can now set the _options->colours_ colours in a QSS stylesheet! if you are a stylesheet maker, check the default_hydrus.qss file to see how it works--it is the same deal as the animation scanbar previously
+* the options in _options->colours_ remain, but they are now wrapped in a 'overwrite your stylesheet with these colours' checkbox _for now_. existing users are going to be set to 'yes overwrite', so nothing will suddenly change, but new users are going to default to using whatever the current QSS says. in future, I may collapse the light/darkmode distinction into one option set; I may morph it into a "colour highly rated files' thumbnail borders gold" dynamic options system; I may simply delete the whole thing and replace it with in-client QSS editing or something. not sure, so let's see how it goes and how Qt 7's darkmode stuff turns out.
+* I have pasted the hydrus default darkmode colours into all the other stylesheets that come with the program, so new users selecting a darkmode style are going to get something reasonable out of the box rather than the previous ugly clash. the users who made the original stylesheets are welcome to figure out better colours and send them in
+* if you are not set to override with the custom colours in _options->colours_, then hitting _help->darkmode_ now gives you a popup telling you what is going on
+
+### sidecar UI
+
+* the four 'edit sidecars' panels (under manual imports, import folders, manual exports, and export folders), which use paths and media as sources respectively, now have test panels to review the current sidecar route you have set up. they use up to 25 rows of example file paths/media from the actual thing you are working on. it provides a live update of what the sources you set up will load, so you know you have the json parse or .txt separator set up correct
+* for the export folders case, there is a button in the panel 'edit export folders' panel to populate the text context, under your control, since this involves a potentially slow file search
+* there is more to do here. I would like better test panels in the sub-dialogs and I'd like to collapse the related 'eight-nested-dialogs-deep' problem, and in the string processing and parsing UI more generally, but I'm happy with this step forward. let me know where it goes wrong!
+
+### advanced autocomplete logic fixes
+
+* when you enter a wildcard into a Read tag autocomplete, it no longer always delivers the 'always autocompleting' version. so, if you enter `sa*s`, it will suggest `sa*s (wildcard search)` and perhaps `sa*s (any namespace)`, but it will no longer suggest the `sa*s*` variants until you, obviously, actually type that trailing asterisk yourself. I intermittently had no idea what the hell I was doing when I originally developed this stuff
+* the 'unnamespaced input gives `(any namespace)` wildcard results' tag display option is now correctly negatively enforced when entering unnamespaced wildcards. previously it was always adding them, and sometimes inserting them at the top of the list. the `(any namespace)` variant is now always below the unnamespaced when both are present
+* fixed up a bunch of jank unit tests that were testing this badly
+
## [Version 581](https://github.com/hydrusnetwork/hydrus/releases/tag/v581)
### misc
@@ -333,40 +370,3 @@ title: Changelog
* the local booru review services panel no longer shows nor allows management of its shares
* deleted the local booru unit tests
* deleted the local booru help and ancient screenshots
-
-## [Version 572](https://github.com/hydrusnetwork/hydrus/releases/tag/v572)
-
-### misc
-
-* added a new checkbox to _options->files and trash_ to say 'include skipped files when you remove files after archive/delete'
-* thanks to a user, we now have an 'e621' stylsheet in _options->style_. this is the first default stylesheet that uses assets (some checkbox etc.. svgs), which means some users--I think just those who run from source--will need to be careful that their CWD is the hydrus install dir when they boot, or this won't load properly! if you try it and get errors in your log as it tries to load the svgs, let me know!
-
-### share menu
-
-* like the 'open' menu a couple weeks ago, the 'share' menu off of thumbnails or the media viewer is rewritten to nicer code. no major differences, but it has a clearer, universal layout, provides more options for 'the currently focused file' vs 'all selected files', is more careful about only providing commands it can deliver on (e.g. no file copy for remote files), and now everything it does is mappable in the shortcut system under the 'media' shortcut set
-* you can now copy a file's thumbnail as a bitmap from this menu!
-* the canvas now supports 'export files'. the 'export files' window just pops on top of it with the one file
-* 'copy file id' is no longer hidden by advanced mode--go nuts!
-* the share menu no longer has 'share on local booru'. the local booru service was an interesting experiment, but I could never find time to properly dev it and there are better answers with the Client API or simple third-party image hosting services that you can drag and drop to. thus, I am finally sunsetting it. I'll strip away its features over the coming weeks until it is completely removed
-
-### shortcut updates
-
-* the 'copy file hash' shortcut actions, which used to be four separate things, have been collapsed to one action that has a 'hash type' dropdown (and a 'target' dropdown to select either all selected files or just the currently focused file, which will default to 'all selected' on update, which was the previous behaviour). you can also now set 'pixel_hash' or 'blurhash' as the hash type
-* the 'copy file bitmap' shortcuts have similarly been collapsed down to one action with a dropdown, also with the new 'copy thumbnail' command
-* the 'copy files', 'copy file paths', and 'copy file id' shortcuts now have a dropdown for whether you want all selected files or just the currently focused file. updated commands will default to 'all selected', which was the previous behaviour
-* added a 'copy ipfs multihash' shortcut action, which has this new 'focused vs all selected' parameter and the ipfs service to copy from as its options
-
-### boring code cleanup
-
-* wrote a new command for copying arbitrary file hashes, with a new 'file command target'
-* simplified the media hash copying code
-* wrote a new command for copying arbitrary bitmap types
-* combined the bitmap copying code into one shared function call and simplified the surrounding code
-* combined the file and path copying code into shared functions, simplified the code, and added tech for focused vs all selected targeting
-* and the same thing for copying ipfs multihashes
-* wrote a routine to copy a file's thumbnail in the normal clipboard copying pubsub
-* with the recent rounds of simplication, the core thumbnail menu call is now but a mere 600 lines of spaghetti code
-* misc renaming of some enums here so they are more in agreement ('xxx files' instead of 'xxx file', etc...)
-* renamed the various simple commands I have replaced in the past few weeks as 'legacy', so we don't accidentally refer to them again in real code
-* the unit test for 'dateparser decode' is no longer run if dateparser is not in the environment
-* fixed the file metadata parsing unit tests to account for newer ffmpeg, which sees a -10ms different duration on one of the test files, and made the various tests +/-20% lenient to handle this stuff if it comes up again in future
diff --git a/docs/developer_api.md b/docs/developer_api.md
index f1917fee5..cee653125 100644
--- a/docs/developer_api.md
+++ b/docs/developer_api.md
@@ -286,7 +286,7 @@ You won't see all of these, but the service `type` enum is:
* 15 - all local files -- all files on hard disk ('all my files' + updates + trash)
* 17 - file notes
* 18 - Client API
-* 19 - all deleted files -- you can ignore this
+* 19 - deleted from anywhere -- you can ignore this
* 20 - local updates -- a file domain to store repository update files in
* 21 - all my files -- union of all local file domains
* 22 - a 'inc/dec' rating service with positive integer rating
@@ -2142,7 +2142,7 @@ Response:
**It is possible for the king to not be available.** Every group has a king, but if that file has been deleted, or if the file domain here is limited and the king is on a different file service, then it may not be available. A similar issue occurs when you search for filtering pairs--while it is ideal to compare kings with kings, if you set 'files must be pixel dupes', then the user will expect to see those pixel duplicates, not their champions--you may be forced to compare non-kings. `king_is_on_file_domain` lets you know if the king is on the file domain you set, and `king_is_local` lets you know if it is on the hard disk--if `king_is_local=true`, you can do a `/get_files/file` request on it. It is generally rare, but you have to deal with the king being unavailable--in this situation, your best bet is to just use the file itself as its own representative.
-All the relationships you get are filtered by the file domain. If you set the file domain to 'all known files', you will get every relationship a file has, including all deleted files, which is often less useful than you would think. The default, 'all my files' is usually most useful.
+All the relationships you get are filtered by the file domain. If you set the file domain to 'all known files', you will get every relationship a file has, including all deleted files, which is often less useful than you would think. The default, 'all my files', is usually most useful.
A file that has no duplicates is considered to be in a duplicate group of size 1 and thus is always its own king.
diff --git a/docs/old_changelog.html b/docs/old_changelog.html
index 29d3ec936..aadfe73e6 100644
--- a/docs/old_changelog.html
+++ b/docs/old_changelog.html
@@ -34,6 +34,36 @@
+ -
+
+
+ fixes
+ - fixed an issue where setting a file 'collect' was not automatically sorting the collected objects internally properly. normally when you collect, each collected object is supposed to be sorted internally by filesize or namespace or whatever--this is working again
+ - fixed a weird internal error state in the import folders manager where it could get confused about and throw an error regarding the import folders' next work times if an internal update notification occured during an import folder working
+ - fixed a typo error with the shortcut set 'special duplicate' button
+ - fixed pasting new query texts into the manage subscriptions dialog when one of the pasted texts resurrects a DEAD query. my new summary generation text was handling the DEAD report wrong!
+ misc
+ - the advanced 'all deleted files' service, which is mostly just used for behind the scenes caching calculations, is renamed to 'deleted from anywhere'. the related 'regen->all deleted files' database command is also moved to 'check and repair->sync combined deleted files'
+ - the edit tag filter panel's 'load' button now shows all the current tag repositories' tag filters
+ - when you hit ctrl-enter on some tags (or otherwise trigger a linked remove+add action) in an active search list (e.g. top-left on a search page), which causes those tags to invert and thus sometimes sorted to a different position, the current selection now propagates through the inversion, with the keyboard focus moved to the post-topmost item. so, you can now basically hit ctrl+enter twice for a no-op
+ - fixed the paste button in the new 'purge tags' dialog
+ - thanks to a user, we have a new 'Purple' stylesheet
+ - I tweaked the some default stylesheet colours and think I fixed the display of the 'valid/invalid' controls you sometimes see (for instance in the new regex input, which goes green/red) for dark mode stylesheets that don't define colours for these. previously, the dark mode text, usually a light grey, was being washed out by the default green
+ custom colours in QSS
+ - you can now set the _options->colours_ colours in a QSS stylesheet! if you are a stylesheet maker, check the default_hydrus.qss file to see how it works--it is the same deal as the animation scanbar previously
+ - the options in _options->colours_ remain, but they are now wrapped in a 'overwrite your stylesheet with these colours' checkbox _for now_. existing users are going to be set to 'yes overwrite', so nothing will suddenly change, but new users are going to default to using whatever the current QSS says. in future, I may collapse the light/darkmode distinction into one option set; I may morph it into a "colour highly rated files' thumbnail borders gold" dynamic options system; I may simply delete the whole thing and replace it with in-client QSS editing or something. not sure, so let's see how it goes and how Qt 7's darkmode stuff turns out.
+ - I have pasted the hydrus default darkmode colours into all the other stylesheets that come with the program, so new users selecting a darkmode style are going to get something reasonable out of the box rather than the previous ugly clash. the users who made the original stylesheets are welcome to figure out better colours and send them in
+ - if you are not set to override with the custom colours in _options->colours_, then hitting _help->darkmode_ now gives you a popup telling you what is going on
+ sidecar UI
+ - the four 'edit sidecars' panels (under manual imports, import folders, manual exports, and export folders), which use paths and media as sources respectively, now have test panels to review the current sidecar route you have set up. they use up to 25 rows of example file paths/media from the actual thing you are working on. it provides a live update of what the sources you set up will load, so you know you have the json parse or .txt separator set up correct
+ - for the export folders case, there is a button in the panel 'edit export folders' panel to populate the text context, under your control, since this involves a potentially slow file search
+ - there is more to do here. I would like better test panels in the sub-dialogs and I'd like to collapse the related 'eight-nested-dialogs-deep' problem, and in the string processing and parsing UI more generally, but I'm happy with this step forward. let me know where it goes wrong!
+ advanced autocomplete logic fixes
+ - when you enter a wildcard into a Read tag autocomplete, it no longer always delivers the 'always autocompleting' version. so, if you enter `sa*s`, it will suggest `sa*s (wildcard search)` and perhaps `sa*s (any namespace)`, but it will no longer suggest the `sa*s*` variants until you, obviously, actually type that trailing asterisk yourself. I intermittently had no idea what the hell I was doing when I originally developed this stuff
+ - the 'unnamespaced input gives `(any namespace)` wildcard results' tag display option is now correctly negatively enforced when entering unnamespaced wildcards. previously it was always adding them, and sometimes inserting them at the top of the list. the `(any namespace)` variant is now always below the unnamespaced when both are present
+ - fixed up a bunch of jank unit tests that were testing this badly
+
+
-
diff --git a/hydrus/client/ClientOptions.py b/hydrus/client/ClientOptions.py
index e2637a54c..811bad7b9 100644
--- a/hydrus/client/ClientOptions.py
+++ b/hydrus/client/ClientOptions.py
@@ -256,7 +256,8 @@ def _InitialiseDefaults( self ):
'enable_truncated_images_pil' : True,
'do_icc_profile_normalisation' : True,
'mpv_available_at_start' : ClientGUIMPV.MPV_IS_AVAILABLE,
- 'do_sleep_check' : True
+ 'do_sleep_check' : True,
+ 'override_stylesheet_colours' : False
}
#
diff --git a/hydrus/client/db/ClientDB.py b/hydrus/client/db/ClientDB.py
index 981f5e978..634d02504 100644
--- a/hydrus/client/db/ClientDB.py
+++ b/hydrus/client/db/ClientDB.py
@@ -1272,7 +1272,7 @@ def _CreateDB( self ):
init_service_info = [
( CC.COMBINED_TAG_SERVICE_KEY, HC.COMBINED_TAG, 'all known tags' ),
( CC.COMBINED_FILE_SERVICE_KEY, HC.COMBINED_FILE, 'all known files' ),
- ( CC.COMBINED_DELETED_FILE_SERVICE_KEY, HC.COMBINED_DELETED_FILE, 'all deleted files' ),
+ ( CC.COMBINED_DELETED_FILE_SERVICE_KEY, HC.COMBINED_DELETED_FILE, 'deleted from anywhere' ),
( CC.COMBINED_LOCAL_FILE_SERVICE_KEY, HC.COMBINED_LOCAL_FILE, 'all local files' ),
( CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY, HC.COMBINED_LOCAL_MEDIA, 'all my files' ),
( CC.LOCAL_FILE_SERVICE_KEY, HC.LOCAL_FILE_DOMAIN, 'my files' ),
@@ -5802,7 +5802,7 @@ def _ProcessContentUpdatePackage( self, content_update_package, publish_content_
service_ids_to_nums_cleared = self.modules_files_storage.ClearLocalDeleteRecord()
- self._SyncCombinedDeletedFiles()
+ self._ResyncCombinedDeletedFiles()
else:
@@ -5810,7 +5810,7 @@ def _ProcessContentUpdatePackage( self, content_update_package, publish_content_
service_ids_to_nums_cleared = self.modules_files_storage.ClearLocalDeleteRecord( hash_ids )
- self._SyncCombinedDeletedFiles( hash_ids )
+ self._ResyncCombinedDeletedFiles( hash_ids )
self._ExecuteMany( 'UPDATE service_info SET info = info + ? WHERE service_id = ? AND info_type = ?;', ( ( -num_cleared, clear_service_id, HC.SERVICE_INFO_NUM_DELETED_FILES ) for ( clear_service_id, num_cleared ) in service_ids_to_nums_cleared.items() ) )
@@ -8423,6 +8423,84 @@ def _ResetRepositoryProcessing( self, service_key: bytes, content_types ):
+ def _ResyncCombinedDeletedFiles( self, hash_ids = None, do_full_rebuild = False ):
+
+ combined_files_stakeholder_service_ids = self.modules_services.GetServiceIds( HC.FILE_SERVICES_COVERED_BY_COMBINED_DELETED_FILE )
+
+ hash_ids_that_are_desired = set()
+
+ if hash_ids is None:
+
+ for service_id in combined_files_stakeholder_service_ids:
+
+ hash_ids_that_are_desired.update( self.modules_files_storage.GetDeletedHashIdsList( service_id ) )
+
+
+ existing_hash_ids = set( self.modules_files_storage.GetCurrentHashIdsList( self.modules_services.combined_deleted_file_service_id ) )
+
+ else:
+
+ for service_id in combined_files_stakeholder_service_ids:
+
+ hash_ids_that_are_desired.update( self.modules_files_storage.FilterHashIdsToStatus( service_id, hash_ids, HC.CONTENT_STATUS_DELETED ) )
+
+
+ existing_hash_ids = self.modules_files_storage.FilterHashIdsToStatus( self.modules_services.combined_deleted_file_service_id, hash_ids, HC.CONTENT_STATUS_CURRENT )
+
+
+ if do_full_rebuild:
+
+ # this happens in the full 'regenerate' call from the UI database menu. full wipe and recalculation to get any errant timestamps
+
+ hash_ids_to_remove = existing_hash_ids
+ hash_ids_to_add = hash_ids_that_are_desired
+
+ else:
+
+ hash_ids_to_remove = existing_hash_ids.difference( hash_ids_that_are_desired )
+ hash_ids_to_add = hash_ids_that_are_desired.difference( existing_hash_ids )
+
+
+ if len( hash_ids_to_remove ) > 0:
+
+ self._DeleteFiles( self.modules_services.combined_deleted_file_service_id, hash_ids_to_remove, only_if_current = True )
+
+
+ if len( hash_ids_to_add ) > 0:
+
+ hash_ids_to_earliest_timestamps_ms = {}
+
+ for service_id in combined_files_stakeholder_service_ids:
+
+ hash_ids_to_both_timestamps_ms = self.modules_files_storage.GetDeletedHashIdsToTimestampsMS( service_id, hash_ids_to_add )
+
+ for ( hash_id, ( timestamp_ms, original_timestamp_ms ) ) in hash_ids_to_both_timestamps_ms.items():
+
+ if hash_id in hash_ids_to_earliest_timestamps_ms:
+
+ if timestamp_ms is not None:
+
+ existing_timestamp = hash_ids_to_earliest_timestamps_ms[ hash_id ]
+
+ if existing_timestamp is None or timestamp_ms < existing_timestamp:
+
+ hash_ids_to_earliest_timestamps_ms[ hash_id ] = timestamp_ms
+
+
+
+ else:
+
+ hash_ids_to_earliest_timestamps_ms[ hash_id ] = timestamp_ms
+
+
+
+
+ rows = list( hash_ids_to_earliest_timestamps_ms.items() )
+
+ self._AddFiles( self.modules_services.combined_deleted_file_service_id, rows )
+
+
+
def _ResyncTagMappingsCacheFiles( self, tag_service_key = None ):
job_status = ClientThreading.JobStatus( cancellable = True )
@@ -8577,84 +8655,6 @@ def _SetPassword( self, password ):
self._SaveOptions( self._controller.options )
- def _SyncCombinedDeletedFiles( self, hash_ids = None, do_full_rebuild = False ):
-
- combined_files_stakeholder_service_ids = self.modules_services.GetServiceIds( HC.FILE_SERVICES_COVERED_BY_COMBINED_DELETED_FILE )
-
- hash_ids_that_are_desired = set()
-
- if hash_ids is None:
-
- for service_id in combined_files_stakeholder_service_ids:
-
- hash_ids_that_are_desired.update( self.modules_files_storage.GetDeletedHashIdsList( service_id ) )
-
-
- existing_hash_ids = set( self.modules_files_storage.GetCurrentHashIdsList( self.modules_services.combined_deleted_file_service_id ) )
-
- else:
-
- for service_id in combined_files_stakeholder_service_ids:
-
- hash_ids_that_are_desired.update( self.modules_files_storage.FilterHashIdsToStatus( service_id, hash_ids, HC.CONTENT_STATUS_DELETED ) )
-
-
- existing_hash_ids = self.modules_files_storage.FilterHashIdsToStatus( self.modules_services.combined_deleted_file_service_id, hash_ids, HC.CONTENT_STATUS_CURRENT )
-
-
- if do_full_rebuild:
-
- # this happens in the full 'regenerate' call from the UI database menu. full wipe and recalculation to get any errant timestamps
-
- hash_ids_to_remove = existing_hash_ids
- hash_ids_to_add = hash_ids_that_are_desired
-
- else:
-
- hash_ids_to_remove = existing_hash_ids.difference( hash_ids_that_are_desired )
- hash_ids_to_add = hash_ids_that_are_desired.difference( existing_hash_ids )
-
-
- if len( hash_ids_to_remove ) > 0:
-
- self._DeleteFiles( self.modules_services.combined_deleted_file_service_id, hash_ids_to_remove, only_if_current = True )
-
-
- if len( hash_ids_to_add ) > 0:
-
- hash_ids_to_earliest_timestamps_ms = {}
-
- for service_id in combined_files_stakeholder_service_ids:
-
- hash_ids_to_both_timestamps_ms = self.modules_files_storage.GetDeletedHashIdsToTimestampsMS( service_id, hash_ids_to_add )
-
- for ( hash_id, ( timestamp_ms, original_timestamp_ms ) ) in hash_ids_to_both_timestamps_ms.items():
-
- if hash_id in hash_ids_to_earliest_timestamps_ms:
-
- if timestamp_ms is not None:
-
- existing_timestamp = hash_ids_to_earliest_timestamps_ms[ hash_id ]
-
- if existing_timestamp is None or timestamp_ms < existing_timestamp:
-
- hash_ids_to_earliest_timestamps_ms[ hash_id ] = timestamp_ms
-
-
-
- else:
-
- hash_ids_to_earliest_timestamps_ms[ hash_id ] = timestamp_ms
-
-
-
-
- rows = list( hash_ids_to_earliest_timestamps_ms.items() )
-
- self._AddFiles( self.modules_services.combined_deleted_file_service_id, rows )
-
-
-
def _UndeleteFiles( self, service_id, hash_ids ):
if service_id in ( self.modules_services.combined_local_file_service_id, self.modules_services.combined_local_media_service_id, self.modules_services.trash_service_id ):
@@ -9263,7 +9263,7 @@ def ask_what_to_do_png_stuff():
try:
- self._SyncCombinedDeletedFiles( do_full_rebuild = False ) # first time I wrote do_full_rebuild, it was too slow!
+ self._ResyncCombinedDeletedFiles( do_full_rebuild = False ) # first time I wrote do_full_rebuild, it was too slow!
except Exception as e:
@@ -10417,6 +10417,39 @@ def ask_what_to_do_zip_docx_scan():
+ if version == 581:
+
+ try:
+
+ new_options = self.modules_serialisable.GetJSONDump( HydrusSerialisable.SERIALISABLE_TYPE_CLIENT_OPTIONS )
+
+ new_options.SetBoolean( 'override_stylesheet_colours', True )
+
+ self.modules_serialisable.SetJSONDump( new_options )
+
+ except Exception as e:
+
+ HydrusData.PrintException( e )
+
+ message = 'Trying to update your options failed! Please let hydrus dev know!'
+
+ self.pub_initial_message( message )
+
+
+ try:
+
+ self._Execute( 'UPDATE services SET name = ? WHERE name = ? and service_type = ?;', ( 'deleted from anywhere', 'all deleted files', HC.COMBINED_DELETED_FILE ) )
+
+ except Exception as e:
+
+ HydrusData.PrintException( e )
+
+ message = 'Trying to rename "all deleted files" failed! Please let hydrus dev know!'
+
+ self.pub_initial_message( message )
+
+
+
self._controller.frame_splash_status.SetTitleText( 'updated db to v{}'.format( HydrusNumbers.ToHumanInt( version + 1 ) ) )
self._Execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
@@ -10934,7 +10967,6 @@ def _Write( self, action, *args, **kwargs ):
elif action == 'process_repository_content': result = self._ProcessRepositoryContent( *args, **kwargs )
elif action == 'process_repository_definitions': result = self.modules_repositories.ProcessRepositoryDefinitions( *args, **kwargs )
elif action == 'push_recent_tags': self.modules_recent_tags.PushRecentTags( *args, **kwargs )
- elif action == 'regenerate_combined_deleted_files': self._SyncCombinedDeletedFiles( *args, **kwargs )
elif action == 'regenerate_local_hash_cache': self._RegenerateLocalHashCache( *args, **kwargs )
elif action == 'regenerate_local_tag_cache': self._RegenerateLocalTagCache( *args, **kwargs )
elif action == 'regenerate_similar_files': self.modules_similar_files.RegenerateTree( *args, **kwargs )
@@ -10961,6 +10993,7 @@ def _Write( self, action, *args, **kwargs ):
elif action == 'reset_repository': self._ResetRepository( *args, **kwargs )
elif action == 'reset_repository_processing': self._ResetRepositoryProcessing( *args, **kwargs )
elif action == 'reset_potential_search_status': self._PerceptualHashesResetSearchFromHashes( *args, **kwargs )
+ elif action == 'resync_combined_deleted_files': self._ResyncCombinedDeletedFiles( *args, **kwargs )
elif action == 'resync_tag_mappings_cache_files': self._ResyncTagMappingsCacheFiles( *args, **kwargs )
elif action == 'save_options': self._SaveOptions( *args, **kwargs )
elif action == 'serialisable': self.modules_serialisable.SetJSONDump( *args, **kwargs )
diff --git a/hydrus/client/db/ClientDBMappingsCounts.py b/hydrus/client/db/ClientDBMappingsCounts.py
index 215fd1ce8..ec01a602e 100644
--- a/hydrus/client/db/ClientDBMappingsCounts.py
+++ b/hydrus/client/db/ClientDBMappingsCounts.py
@@ -399,7 +399,7 @@ def GetCounts( self, tag_display_type, tag_service_id, file_service_id, tag_ids,
else:
- # for instance this is a search for 'my files' deleted files, but we are searching on 'all deleted files' domain
+ # for instance this is a search for 'my files' deleted files, but we are searching on 'deleted from anywhere' domain
current_min = 0
pending_min = 0
diff --git a/hydrus/client/gui/ClientGUI.py b/hydrus/client/gui/ClientGUI.py
index 5f1053bc7..26bc30421 100644
--- a/hydrus/client/gui/ClientGUI.py
+++ b/hydrus/client/gui/ClientGUI.py
@@ -3233,10 +3233,14 @@ def _InitialiseMenuInfoDatabase( self ):
check_submenu = ClientGUIMenus.GenerateMenu( menu )
ClientGUIMenus.AppendMenuItem( check_submenu, 'database integrity' + HC.UNICODE_ELLIPSIS, 'Examine the database for file corruption.', self._CheckDBIntegrity )
+ ClientGUIMenus.AppendSeparator( check_submenu )
+ ClientGUIMenus.AppendMenuItem( check_submenu, 'fix invalid tags' + HC.UNICODE_ELLIPSIS, 'Scan the database for invalid tags.', self._RepairInvalidTags )
+ ClientGUIMenus.AppendMenuItem( check_submenu, 'fix logically inconsistent mappings' + HC.UNICODE_ELLIPSIS, 'Remove tags that are occupying two mutually exclusive states.', self._FixLogicallyInconsistentMappings )
+ ClientGUIMenus.AppendSeparator( check_submenu )
ClientGUIMenus.AppendMenuItem( check_submenu, 'repopulate truncated mappings tables' + HC.UNICODE_ELLIPSIS, 'Use the mappings cache to try to repair a previously damaged mappings file.', self._RepopulateMappingsTables )
+ ClientGUIMenus.AppendSeparator( check_submenu )
+ ClientGUIMenus.AppendMenuItem( check_submenu, 'resync combined deleted files' + HC.UNICODE_ELLIPSIS, 'Resynchronise the store of all known deleted files.', self._ResyncCombinedDeletedFiles )
ClientGUIMenus.AppendMenuItem( check_submenu, 'resync tag mappings cache files' + HC.UNICODE_ELLIPSIS, 'Check the tag mappings cache for surplus or missing files.', self._ResyncTagMappingsCacheFiles )
- ClientGUIMenus.AppendMenuItem( check_submenu, 'fix logically inconsistent mappings' + HC.UNICODE_ELLIPSIS, 'Remove tags that are occupying two mutually exclusive states.', self._FixLogicallyInconsistentMappings )
- ClientGUIMenus.AppendMenuItem( check_submenu, 'fix invalid tags' + HC.UNICODE_ELLIPSIS, 'Scan the database for invalid tags.', self._RepairInvalidTags )
ClientGUIMenus.AppendMenu( menu, check_submenu, 'check and repair' )
@@ -3256,7 +3260,6 @@ def _InitialiseMenuInfoDatabase( self ):
ClientGUIMenus.AppendSeparator( regen_submenu )
- ClientGUIMenus.AppendMenuItem( regen_submenu, 'all deleted files' + HC.UNICODE_ELLIPSIS, 'Resynchronise the store of all known deleted files.', self._RegenerateCombinedDeletedFiles )
ClientGUIMenus.AppendMenuItem( regen_submenu, 'local hashes cache' + HC.UNICODE_ELLIPSIS, 'Repopulate the cache hydrus uses for fast hash lookup for local files.', self._RegenerateLocalHashCache )
ClientGUIMenus.AppendMenuItem( regen_submenu, 'local tags cache' + HC.UNICODE_ELLIPSIS, 'Repopulate the cache hydrus uses for fast tag lookup for local files.', self._RegenerateLocalTagCache )
@@ -5221,22 +5224,6 @@ def _RefreshStatusBar( self ):
self._statusbar.SetStatusText( db_status, 5, tooltip = db_tooltip )
- def _RegenerateCombinedDeletedFiles( self ):
-
- message = 'This will resynchronise the "all deleted files" cache to the actual records in the database, ensuring that various tag searches over the deleted files domain give correct counts and file results. It isn\'t super important, but this routine fixes it if it is desynchronised.'
- message += '\n' * 2
- message += 'It should not take all that long, but if you have a lot of deleted files, it can take a little while, during which the gui may hang.'
- message += '\n' * 2
- message += 'If you do not have a specific reason to run this, it is pointless.'
-
- result = ClientGUIDialogsQuick.GetYesNo( self, message, yes_label = 'do it', no_label = 'forget it' )
-
- if result == QW.QDialog.Accepted:
-
- self._controller.Write( 'regenerate_combined_deleted_files', do_full_rebuild = True )
-
-
-
def _RegenerateTagCache( self ):
message = 'This will delete and then recreate the fast search cache for one or all tag services.'
@@ -5670,6 +5657,22 @@ def _RestoreSplitterPositions( self ):
self._controller.pub( 'set_splitter_positions', HC.options[ 'hpos' ], HC.options[ 'vpos' ] )
+ def _ResyncCombinedDeletedFiles( self ):
+
+ message = 'This will resynchronise the "deleted from anywhere" cache to the actual records in the database, ensuring that various tag searches over the deleted files domain give correct counts and file results. It isn\'t super important, but this routine fixes it if it is desynchronised.'
+ message += '\n' * 2
+ message += 'It should not take all that long, but if you have a lot of deleted files, it can take a little while, during which the gui may hang.'
+ message += '\n' * 2
+ message += 'If you do not have a specific reason to run this, it is pointless.'
+
+ result = ClientGUIDialogsQuick.GetYesNo( self, message, yes_label = 'do it', no_label = 'forget it' )
+
+ if result == QW.QDialog.Accepted:
+
+ self._controller.Write( 'resync_combined_deleted_files', do_full_rebuild = True )
+
+
+
def _ResyncTagMappingsCacheFiles( self ):
message = 'This will scan your mappings cache for surplus or missing files and correct them. This is useful if you see ghost files or if searches miss files that have the tag.'
@@ -7393,6 +7396,11 @@ def TIMEREventAnimationUpdate( self ):
def FlipDarkmode( self ):
+ if not self._new_options.GetBoolean( 'override_stylesheet_colours' ):
+
+ ClientGUIDialogsMessage.ShowWarning( self, 'Hey, this command comes from an old colour system. If you want to change to darkmode, try _options->style_ instead. Or, if you know what you are doing, make sure you flip the "override" checkbox in _options->colours_ and then try this again.' )
+
+
current_colourset = self._new_options.GetString( 'current_colourset' )
if current_colourset == 'darkmode':
diff --git a/hydrus/client/gui/ClientGUIShortcutControls.py b/hydrus/client/gui/ClientGUIShortcutControls.py
index 3794614b5..3e06960e7 100644
--- a/hydrus/client/gui/ClientGUIShortcutControls.py
+++ b/hydrus/client/gui/ClientGUIShortcutControls.py
@@ -248,7 +248,7 @@ def _SpecialDuplicate( self ):
if addee_shortcut not in all_existing_shortcuts:
- add_rows.append( [ ( addee_shortcut, command ) ] )
+ add_rows.append( ( addee_shortcut, command ) )
all_existing_shortcuts.add( addee_shortcut )
diff --git a/hydrus/client/gui/ClientGUIShortcuts.py b/hydrus/client/gui/ClientGUIShortcuts.py
index dea6d4988..f38074c88 100644
--- a/hydrus/client/gui/ClientGUIShortcuts.py
+++ b/hydrus/client/gui/ClientGUIShortcuts.py
@@ -1343,7 +1343,7 @@ def GetShortcuts( self, simple_action: int ):
def GetShortcutsAndCommands( self ):
- return list( self )
+ return list( self._shortcuts_to_commands.items() )
def HasCommand( self, shortcut: Shortcut ):
diff --git a/hydrus/client/gui/ClientGUIStringControls.py b/hydrus/client/gui/ClientGUIStringControls.py
index a06f9e13f..1185c76cf 100644
--- a/hydrus/client/gui/ClientGUIStringControls.py
+++ b/hydrus/client/gui/ClientGUIStringControls.py
@@ -137,6 +137,8 @@ def SetValue( self, string_match: ClientStrings.StringMatch ):
class StringProcessorButton( ClientGUICommon.BetterButton ):
+ valueChanged = QC.Signal()
+
def __init__( self, parent, string_processor: ClientStrings.StringProcessor, test_data_callable: typing.Callable[ [], ClientParsing.ParsingTestData ] ):
ClientGUICommon.BetterButton.__init__( self, parent, 'edit string processor', self._Edit )
@@ -163,6 +165,8 @@ def _Edit( self ):
self._UpdateLabel()
+ self.valueChanged.emit()
+
diff --git a/hydrus/client/gui/ClientGUISubscriptions.py b/hydrus/client/gui/ClientGUISubscriptions.py
index 104da528e..426cee991 100644
--- a/hydrus/client/gui/ClientGUISubscriptions.py
+++ b/hydrus/client/gui/ClientGUISubscriptions.py
@@ -926,8 +926,10 @@ def _PasteQueries( self ):
if len( DEAD_query_headers ) > 0:
+ DEAD_query_header_texts = [ query_header.GetQueryText() for query_header in DEAD_query_headers ]
+
message += '\n' * 2
- message += f'The DEAD queries{HydrusText.ConvertManyStringsToNiceInsertableHumanSummary(DEAD_query_headers)}were revived.'
+ message += f'The DEAD queries{HydrusText.ConvertManyStringsToNiceInsertableHumanSummary(DEAD_query_header_texts)}were revived.'
diff --git a/hydrus/client/gui/ClientGUITags.py b/hydrus/client/gui/ClientGUITags.py
index 2d93bf358..c22b9bb89 100644
--- a/hydrus/client/gui/ClientGUITags.py
+++ b/hydrus/client/gui/ClientGUITags.py
@@ -1431,6 +1431,20 @@ def _LoadFavourite( self ):
+ tag_repositories = CG.client_controller.services_manager.GetServices( ( HC.TAG_REPOSITORY, ) )
+
+ if len( tag_repositories ) > 0:
+
+ ClientGUIMenus.AppendSeparator( menu )
+
+ for service in sorted( tag_repositories, key = lambda s: s.GetName() ):
+
+ tag_filter = service.GetTagFilter()
+
+ ClientGUIMenus.AppendMenuItem( menu, f'tag filter for "{service.GetName()}"', 'load the serverside tag filter for this service', self.SetValue, tag_filter )
+
+
+
CGC.core().PopupMenu( self, menu )
diff --git a/hydrus/client/gui/canvas/ClientGUICanvas.py b/hydrus/client/gui/canvas/ClientGUICanvas.py
index fe9c0f3d0..4439e1b59 100644
--- a/hydrus/client/gui/canvas/ClientGUICanvas.py
+++ b/hydrus/client/gui/canvas/ClientGUICanvas.py
@@ -143,9 +143,19 @@ def AddAudioVolumeMenu( menu, canvas_type ):
class CanvasBackgroundColourGenerator( object ):
+ def __init__( self, my_canvas ):
+
+ self._my_canvas = my_canvas
+
+
+ def _GetColourFromOptions( self ):
+
+ return self._my_canvas.GetColour( CC.COLOUR_MEDIA_BACKGROUND )
+
+
def GetColour( self ) -> QG.QColor:
- return CG.client_controller.new_options.GetColour( CC.COLOUR_MEDIA_BACKGROUND )
+ return self._GetColourFromOptions()
def CanDoTransparencyCheckerboard( self ) -> bool:
@@ -156,13 +166,6 @@ def CanDoTransparencyCheckerboard( self ) -> bool:
class CanvasBackgroundColourGeneratorDuplicates( CanvasBackgroundColourGenerator ):
- def __init__( self, duplicate_canvas ):
-
- CanvasBackgroundColourGenerator.__init__( self )
-
- self._duplicate_canvas = duplicate_canvas
-
-
def CanDoTransparencyCheckerboard( self ) -> bool:
return CG.client_controller.new_options.GetBoolean( 'draw_transparency_checkerboard_media_canvas' ) or CG.client_controller.new_options.GetBoolean( 'draw_transparency_checkerboard_media_canvas_duplicates' )
@@ -172,11 +175,11 @@ def GetColour( self ) -> QG.QColor:
new_options = CG.client_controller.new_options
- normal_colour = new_options.GetColour( CC.COLOUR_MEDIA_BACKGROUND )
+ normal_colour = self._GetColourFromOptions()
- if self._duplicate_canvas.IsShowingAPair():
+ if self._my_canvas.IsShowingAPair():
- if self._duplicate_canvas.IsShowingFileA():
+ if self._my_canvas.IsShowingFileA():
duplicate_intensity = new_options.GetNoneableInteger( 'duplicate_background_switch_intensity_a' )
@@ -315,14 +318,21 @@ class Canvas( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
def __init__( self, parent, location_context: ClientLocation.LocationContext ):
+ self._qss_colours = {
+ CC.COLOUR_MEDIA_BACKGROUND : QG.QColor( 255, 255, 255 ),
+ CC.COLOUR_MEDIA_TEXT : QG.QColor( 0, 0, 0 )
+ }
+
QW.QWidget.__init__( self, parent )
CAC.ApplicationCommandProcessorMixin.__init__( self )
+ self.setObjectName( 'HydrusMediaViewer' )
+
self.setSizePolicy( QW.QSizePolicy.Expanding, QW.QSizePolicy.Expanding )
self._location_context = location_context
- self._background_colour_generator = CanvasBackgroundColourGenerator()
+ self._background_colour_generator = CanvasBackgroundColourGenerator( self )
self._current_media_start_time_ms = HydrusTime.GetNowMS()
@@ -705,6 +715,18 @@ def GetActiveCustomShortcutNames( self ):
return self._my_shortcuts_handler.GetCustomShortcutNames()
+ def GetColour( self, colour_type ):
+
+ if self._new_options.GetBoolean( 'override_stylesheet_colours' ):
+
+ return self._new_options.GetColour( colour_type )
+
+ else:
+
+ return self._qss_colours.get( colour_type, QG.QColor( 127, 127, 127 ) )
+
+
+
def ManageNotes( self, canvas_key, name_to_start_on = None ):
if canvas_key == self._canvas_key:
@@ -1313,6 +1335,29 @@ def ZoomSwitch( self, canvas_key ):
+ def get_hmv_background( self ):
+
+ return self._qss_colours[ CC.COLOUR_MEDIA_BACKGROUND ]
+
+
+ def get_hmv_text( self ):
+
+ return self._qss_colours[ CC.COLOUR_MEDIA_TEXT ]
+
+
+ def set_hmv_background( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_MEDIA_BACKGROUND ] = colour
+
+
+ def set_hmv_text( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_MEDIA_TEXT ] = colour
+
+
+ hmv_background = QC.Property( QG.QColor, get_hmv_background, set_hmv_background )
+ hmv_text = QC.Property( QG.QColor, get_hmv_text, set_hmv_text )
+
class MediaContainerDragClickReportingFilter( QC.QObject ):
@@ -1843,7 +1888,9 @@ def _DrawTopMiddle( self, painter: QG.QPainter ):
# top-middle
- painter.setPen( QG.QPen( self._new_options.GetColour( CC.COLOUR_MEDIA_TEXT ) ) )
+ pen_colour = self.GetColour( CC.COLOUR_MEDIA_TEXT )
+
+ painter.setPen( QG.QPen( pen_colour ) )
current_y = 3
@@ -1971,7 +2018,9 @@ def _DrawTopRight( self, painter: QG.QPainter ) -> int:
current_y += 18
- painter.setPen( QG.QPen( self._new_options.GetColour( CC.COLOUR_MEDIA_TEXT ) ) )
+ pen_colour = self.GetColour( CC.COLOUR_MEDIA_TEXT )
+
+ painter.setPen( QG.QPen( pen_colour ) )
# repo strings
diff --git a/hydrus/client/gui/canvas/ClientGUICanvasMedia.py b/hydrus/client/gui/canvas/ClientGUICanvasMedia.py
index 7365385af..4433e8d33 100644
--- a/hydrus/client/gui/canvas/ClientGUICanvasMedia.py
+++ b/hydrus/client/gui/canvas/ClientGUICanvasMedia.py
@@ -879,7 +879,7 @@ def __init__( self, parent ):
QW.QWidget.__init__( self, parent )
- self._colours = {
+ self._qss_colours = {
'hab_border' : QG.QColor( 0, 0, 0 ),
'hab_background' : QG.QColor( 240, 240, 240 ),
'hab_nub' : QG.QColor( 96, 96, 96 )
@@ -907,7 +907,7 @@ def _DrawBlank( self, painter ):
self.setProperty( 'playing', False )
- background_colour = self._colours[ 'hab_background' ]
+ background_colour = self._qss_colours[ 'hab_background' ]
painter.setBackground( background_colour )
@@ -963,7 +963,7 @@ def _Redraw( self, painter ):
my_width = self.size().width()
my_height = self.size().height()
- background_colour = self._colours[ 'hab_background' ]
+ background_colour = self._qss_colours[ 'hab_background' ]
if paused:
@@ -1039,7 +1039,7 @@ def _Redraw( self, painter ):
if nub_x is not None:
- painter.fillRect( nub_x, 0, animated_scanbar_nub_width, my_height, self._colours[ 'hab_nub' ] )
+ painter.fillRect( nub_x, 0, animated_scanbar_nub_width, my_height, self._qss_colours[ 'hab_nub' ] )
#
@@ -1075,7 +1075,7 @@ def _Redraw( self, painter ):
painter.setBrush( QC.Qt.NoBrush )
- painter.setPen( QG.QPen( self._colours[ 'hab_border' ] ) )
+ painter.setPen( QG.QPen( self._qss_colours[ 'hab_border' ] ) )
painter.drawRect( 0, 0, my_width - 1, my_height - 1 )
@@ -1260,32 +1260,32 @@ def TIMERAnimationUpdate( self ):
def get_hab_background( self ):
- return self._colours[ 'hab_background' ]
+ return self._qss_colours[ 'hab_background' ]
def get_hab_border( self ):
- return self._colours[ 'hab_border' ]
+ return self._qss_colours[ 'hab_border' ]
def get_hab_nub( self ):
- return self._colours[ 'hab_nub' ]
+ return self._qss_colours[ 'hab_nub' ]
def set_hab_background( self, colour ):
- self._colours[ 'hab_background' ] = colour
+ self._qss_colours[ 'hab_background' ] = colour
def set_hab_border( self, colour ):
- self._colours[ 'hab_border' ] = colour
+ self._qss_colours[ 'hab_border' ] = colour
def set_hab_nub( self, colour ):
- self._colours[ 'hab_nub' ] = colour
+ self._qss_colours[ 'hab_nub' ] = colour
hab_border = QC.Property( QG.QColor, get_hab_border, set_hab_border )
diff --git a/hydrus/client/gui/exporting/ClientGUIExport.py b/hydrus/client/gui/exporting/ClientGUIExport.py
index 79fb6be55..3c9f8f7df 100644
--- a/hydrus/client/gui/exporting/ClientGUIExport.py
+++ b/hydrus/client/gui/exporting/ClientGUIExport.py
@@ -21,6 +21,7 @@
from hydrus.client import ClientLocation
from hydrus.client import ClientThreading
from hydrus.client.exporting import ClientExportingFiles
+from hydrus.client.gui import ClientGUIAsync
from hydrus.client.gui import ClientGUIDialogsMessage
from hydrus.client.gui import ClientGUIDialogsQuick
from hydrus.client.gui import ClientGUIFunctions
@@ -30,10 +31,12 @@
from hydrus.client.gui.lists import ClientGUIListConstants as CGLC
from hydrus.client.gui.lists import ClientGUIListCtrl
from hydrus.client.gui.metadata import ClientGUIMetadataMigration
+from hydrus.client.gui.metadata import ClientGUIMetadataMigrationTest
from hydrus.client.gui.metadata import ClientGUITime
from hydrus.client.gui.panels import ClientGUIScrolledPanels
from hydrus.client.gui.search import ClientGUIACDropdown
from hydrus.client.gui.widgets import ClientGUICommon
+from hydrus.client.media import ClientMedia
from hydrus.client.media import ClientMediaFileFilter
from hydrus.client.metadata import ClientContentUpdates
from hydrus.client.metadata import ClientMetadataMigrationExporters
@@ -301,8 +304,11 @@ def __init__( self, parent, export_folder: ClientExportingFiles.ExportFolder ):
metadata_routers = export_folder.GetMetadataRouters()
allowed_importer_classes = [ ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaTags, ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaNotes, ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaURLs, ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaTimestamps ]
allowed_exporter_classes = [ ClientMetadataMigrationExporters.SingleFileMetadataExporterTXT, ClientMetadataMigrationExporters.SingleFileMetadataExporterJSON ]
+ self._test_context_factory = ClientGUIMetadataMigrationTest.MigrationTestContextFactoryMedia( [] )
- self._metadata_routers_button = ClientGUIMetadataMigration.SingleFileMetadataRoutersButton( self._metadata_routers_box, metadata_routers, allowed_importer_classes, allowed_exporter_classes )
+ self._metadata_routers_button = ClientGUIMetadataMigration.SingleFileMetadataRoutersButton( self._metadata_routers_box, metadata_routers, allowed_importer_classes, allowed_exporter_classes, self._test_context_factory )
+
+ self._update_test_context_factory_button = ClientGUICommon.BetterButton( self._metadata_routers_box, 'update test example files', self._UpdateTestExampleFiles )
#
@@ -381,6 +387,7 @@ def __init__( self, parent, export_folder: ClientExportingFiles.ExportFolder ):
self._phrase_box.Add( phrase_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
self._metadata_routers_box.Add( self._metadata_routers_button, CC.FLAGS_EXPAND_PERPENDICULAR )
+ self._metadata_routers_box.Add( self._update_test_context_factory_button, CC.FLAGS_ON_RIGHT )
vbox = QP.VBoxLayout()
@@ -400,6 +407,17 @@ def __init__( self, parent, export_folder: ClientExportingFiles.ExportFolder ):
self._delete_from_client_after_export.clicked.connect( self.EventDeleteFilesAfterExport )
self._run_regularly.clicked.connect( self._UpdateRunRegularly )
+ self._tag_autocomplete.searchChanged.connect( self._SearchUpdated )
+
+ self._SearchUpdated()
+
+
+ def _SearchUpdated( self ):
+
+ self._update_test_context_factory_button.setText( 'update test example files' )
+
+ self._update_test_context_factory_button.setEnabled( True )
+
def _UpdateRunRegularly( self ):
@@ -409,6 +427,39 @@ def _UpdateRunRegularly( self ):
self._show_working_popup.setEnabled( run_regularly )
+ def _UpdateTestExampleFiles( self ):
+
+ file_search_context = self._tag_autocomplete.GetFileSearchContext()
+
+ def work_callable():
+
+ sort_by = ClientMedia.MediaSort( ( 'system', CC.SORT_FILES_BY_FILESIZE ), CC.SORT_ASC )
+
+ query_hash_ids = CG.client_controller.Read( 'file_query_ids', file_search_context, limit_sort_by = sort_by )
+
+ query_hash_ids = list( query_hash_ids )[:ClientGUIMetadataMigrationTest.HOW_MANY_EXAMPLE_OBJECTS_TO_USE]
+
+ media_results = CG.client_controller.Read( 'media_results_from_ids', query_hash_ids )
+
+ return media_results
+
+
+ def publish_callable( media_results ):
+
+ self._test_context_factory.SetExampleMediaResults( media_results )
+
+ self._update_test_context_factory_button.setText( f'got {HydrusNumbers.ToHumanInt(len( media_results))} files!' )
+
+
+ self._update_test_context_factory_button.setEnabled( False )
+
+ self._update_test_context_factory_button.setText( 'loading' + HC.UNICODE_ELLIPSIS )
+
+ async_job = ClientGUIAsync.AsyncQtJob( self, work_callable, publish_callable )
+
+ async_job.start()
+
+
def _UpdateTypeDeleteUI( self ):
if self._type.GetValue() == HC.EXPORT_FOLDER_TYPE_SYNCHRONISE:
@@ -531,8 +582,6 @@ def __init__( self, parent, flat_media, do_export_and_then_quit = False ):
self._tags_box = ClientGUIListBoxes.StaticBoxSorterForListBoxTags( self, 'files\' tags', tag_presentation_location )
- services_manager = CG.client_controller.services_manager
-
t = ClientGUIListBoxes.ListBoxTagsMedia( self._tags_box, ClientTags.TAG_DISPLAY_DISPLAY_ACTUAL, tag_presentation_location, include_counts = True )
self._tags_box.SetTagsBox( t )
@@ -575,7 +624,11 @@ def __init__( self, parent, flat_media, do_export_and_then_quit = False ):
allowed_importer_classes = [ ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaTags, ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaNotes, ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaURLs, ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaTimestamps ]
allowed_exporter_classes = [ ClientMetadataMigrationExporters.SingleFileMetadataExporterTXT, ClientMetadataMigrationExporters.SingleFileMetadataExporterJSON ]
- self._metadata_routers_button = ClientGUIMetadataMigration.SingleFileMetadataRoutersButton( self, metadata_routers, allowed_importer_classes, allowed_exporter_classes )
+ example_media_results = [ m.GetMediaResult() for m in list( flat_media )[:ClientGUIMetadataMigrationTest.HOW_MANY_EXAMPLE_OBJECTS_TO_USE] ]
+
+ test_context_factory = ClientGUIMetadataMigrationTest.MigrationTestContextFactoryMedia( example_media_results )
+
+ self._metadata_routers_button = ClientGUIMetadataMigration.SingleFileMetadataRoutersButton( self, metadata_routers, allowed_importer_classes, allowed_exporter_classes, test_context_factory )
self._export = QW.QPushButton( 'export', self )
self._export.clicked.connect( self._DoExport )
diff --git a/hydrus/client/gui/importing/ClientGUIImport.py b/hydrus/client/gui/importing/ClientGUIImport.py
index bff7a628c..dbb676ca9 100644
--- a/hydrus/client/gui/importing/ClientGUIImport.py
+++ b/hydrus/client/gui/importing/ClientGUIImport.py
@@ -29,6 +29,7 @@
from hydrus.client.gui.lists import ClientGUIListConstants as CGLC
from hydrus.client.gui.lists import ClientGUIListCtrl
from hydrus.client.gui.metadata import ClientGUIMetadataMigration
+from hydrus.client.gui.metadata import ClientGUIMetadataMigrationTest
from hydrus.client.gui.metadata import ClientGUITime
from hydrus.client.gui.networking import ClientGUINetworkJobControl
from hydrus.client.gui.panels import ClientGUIScrolledPanels
@@ -1070,8 +1071,9 @@ def __init__( self, parent, metadata_routers, paths ):
allowed_importer_classes = [ ClientMetadataMigrationImporters.SingleFileMetadataImporterTXT, ClientMetadataMigrationImporters.SingleFileMetadataImporterJSON ]
allowed_exporter_classes = [ ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaTags, ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaNotes, ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaURLs, ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaTimestamps ]
+ test_context_factory = ClientGUIMetadataMigrationTest.MigrationTestContextFactorySidecar( self._paths[ : ClientGUIMetadataMigrationTest.HOW_MANY_EXAMPLE_OBJECTS_TO_USE ] )
- self._metadata_routers_panel = ClientGUIMetadataMigration.SingleFileMetadataRoutersControl( self, metadata_routers, allowed_importer_classes, allowed_exporter_classes )
+ self._metadata_routers_panel = ClientGUIMetadataMigration.SingleFileMetadataRoutersControl( self, metadata_routers, allowed_importer_classes, allowed_exporter_classes, test_context_factory )
#
diff --git a/hydrus/client/gui/importing/ClientGUIImportFolders.py b/hydrus/client/gui/importing/ClientGUIImportFolders.py
index d4961e2b3..d931913b8 100644
--- a/hydrus/client/gui/importing/ClientGUIImportFolders.py
+++ b/hydrus/client/gui/importing/ClientGUIImportFolders.py
@@ -20,6 +20,7 @@
from hydrus.client.gui.lists import ClientGUIListConstants as CGLC
from hydrus.client.gui.lists import ClientGUIListCtrl
from hydrus.client.gui.metadata import ClientGUIMetadataMigration
+from hydrus.client.gui.metadata import ClientGUIMetadataMigrationTest
from hydrus.client.gui.metadata import ClientGUITime
from hydrus.client.gui.panels import ClientGUIScrolledPanels
from hydrus.client.gui.widgets import ClientGUICommon
@@ -260,9 +261,9 @@ def create_choice():
allowed_importer_classes = [ ClientMetadataMigrationImporters.SingleFileMetadataImporterTXT, ClientMetadataMigrationImporters.SingleFileMetadataImporterJSON ]
allowed_exporter_classes = [ ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaTags, ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaNotes, ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaURLs, ClientMetadataMigrationExporters.SingleFileMetadataExporterMediaTimestamps ]
- self._metadata_routers_button = ClientGUIMetadataMigration.SingleFileMetadataRoutersButton( self, metadata_routers, allowed_importer_classes, allowed_exporter_classes )
+ self._sidecar_test_context_factory = ClientGUIMetadataMigrationTest.MigrationTestContextFactorySidecar( [] )
- services_manager = CG.client_controller.services_manager
+ self._metadata_routers_button = ClientGUIMetadataMigration.SingleFileMetadataRoutersButton( self, metadata_routers, allowed_importer_classes, allowed_exporter_classes, self._sidecar_test_context_factory )
#
@@ -379,6 +380,10 @@ def create_choice():
self._UpdateCheckRegularly()
+ self._path.dirPickerChanged.connect( self._PathChanged )
+
+ self._PathChanged()
+
def _AddFilenameTaggingOptions( self ):
@@ -601,6 +606,27 @@ def _EditFilenameTaggingOptions( self ):
self._filename_tagging_options.SelectDatas( edited_datas )
+ def _PathChanged( self ):
+
+ path = self._path.GetPath()
+
+ try:
+
+ if os.path.exists( path ) and os.path.isdir( path ):
+
+ filenames = list( os.listdir( path ) )[:ClientGUIMetadataMigrationTest.HOW_MANY_EXAMPLE_OBJECTS_TO_USE]
+
+ example_paths = [ os.path.join( path, filename ) for filename in filenames ]
+
+ self._sidecar_test_context_factory.SetExampleFilePaths( example_paths )
+
+
+ except:
+
+ return
+
+
+
def _UpdateCheckRegularly( self ):
if self._check_regularly.isChecked():
diff --git a/hydrus/client/gui/lists/ClientGUIListBoxes.py b/hydrus/client/gui/lists/ClientGUIListBoxes.py
index 7fded8478..38785cfb4 100644
--- a/hydrus/client/gui/lists/ClientGUIListBoxes.py
+++ b/hydrus/client/gui/lists/ClientGUIListBoxes.py
@@ -1070,8 +1070,6 @@ def __init__( self, parent: QW.QWidget, terms_may_have_sibling_or_parent_info: b
self.setWidget( ListBox._InnerWidget( self ) )
self.setWidgetResizable( True )
- self._background_colour = QG.QColor( 255, 255, 255 )
-
self._ordered_terms = []
self._terms_to_logical_indices = {}
self._terms_to_positional_indices = {}
@@ -1295,6 +1293,11 @@ def _DeselectAll( self ):
self._selected_terms = set()
+ def _GetBackgroundColour( self ):
+
+ return QG.QColor( 255, 255, 255 )
+
+
def _GetLogicalIndexFromTerm( self, term ):
if term in self._terms_to_logical_indices:
@@ -1775,7 +1778,9 @@ def _LogicalIndexIsSelected( self, logical_index ):
def _Redraw( self, painter ):
- painter.setBackground( QG.QBrush( self._background_colour ) )
+ bg_colour = self._GetBackgroundColour()
+
+ painter.setBackground( QG.QBrush( bg_colour ) )
painter.eraseRect( painter.viewport() )
@@ -1889,7 +1894,9 @@ def _Redraw( self, painter ):
painter.fillRect( background_colour_x, y_top, rect_width, text_height, namespace_colour )
- text_pen = QG.QPen( self._background_colour )
+ pen_colour = self._GetBackgroundColour()
+
+ text_pen = QG.QPen( pen_colour )
else:
@@ -2444,10 +2451,16 @@ def __init__( self, parent, *args, tag_display_type: int = ClientTags.TAG_DISPLA
self._tag_display_type = tag_display_type
+ self._qss_colours = {
+ CC.COLOUR_TAGS_BOX : QG.QColor( 255, 255, 255 ),
+ }
+
terms_may_have_sibling_or_parent_info = self._tag_display_type == ClientTags.TAG_DISPLAY_STORAGE
ListBox.__init__( self, parent, terms_may_have_sibling_or_parent_info, *args, **kwargs )
+ self.setObjectName( 'HydrusTagList' )
+
if terms_may_have_sibling_or_parent_info:
self._show_parent_decorators = CG.client_controller.new_options.GetBoolean( 'show_parent_decorators_on_storage_taglists' )
@@ -2539,6 +2552,20 @@ def _CanProvideCurrentPagePredicates( self ):
return False
+ def _GetBackgroundColour( self ):
+
+ new_options = CG.client_controller.new_options
+
+ if new_options.GetBoolean( 'override_stylesheet_colours' ):
+
+ return new_options.GetColour( CC.COLOUR_TAGS_BOX )
+
+ else:
+
+ return self._qss_colours.get( CC.COLOUR_TAGS_BOX, QG.QColor( 127, 127, 127 ) )
+
+
+
def _GetRowsOfTextsAndColours( self, term: ClientGUIListBoxesData.ListBoxItem ):
namespace_colours = self._GetNamespaceColours()
@@ -2733,10 +2760,6 @@ def _SelectionChanged( self ):
def _UpdateBackgroundColour( self ):
- new_options = CG.client_controller.new_options
-
- self._background_colour = new_options.GetColour( CC.COLOUR_TAGS_BOX )
-
self.widget().update()
@@ -3596,6 +3619,19 @@ def ForceTagRecalc( self ):
pass
+ def get_htl_background( self ):
+
+ return self._qss_colours[ CC.COLOUR_TAGS_BOX ]
+
+
+ def set_htl_background( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_TAGS_BOX ] = colour
+
+
+ htl_background = QC.Property( QG.QColor, get_htl_background, set_htl_background )
+
+
class ListBoxTagsPredicates( ListBoxTags ):
def __init__( self, *args, tag_display_type = ClientTags.TAG_DISPLAY_DISPLAY_ACTUAL, **kwargs ):
diff --git a/hydrus/client/gui/lists/ClientGUIListConstants.py b/hydrus/client/gui/lists/ClientGUIListConstants.py
index b1e785df5..0be775e62 100644
--- a/hydrus/client/gui/lists/ClientGUIListConstants.py
+++ b/hydrus/client/gui/lists/ClientGUIListConstants.py
@@ -1565,3 +1565,20 @@ class COLUMN_LIST_DEFERRED_DELETE_TABLE_DATA( COLUMN_LIST_DEFINITION ):
register_column_type( COLUMN_LIST_DEFERRED_DELETE_TABLE_DATA.ID, COLUMN_LIST_DEFERRED_DELETE_TABLE_DATA.ROWS, 'num rows', False, 12, True )
default_column_list_sort_lookup[ COLUMN_LIST_DEFERRED_DELETE_TABLE_DATA.ID ] = ( COLUMN_LIST_DEFERRED_DELETE_TABLE_DATA.NAME, True )
+
+class COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS( COLUMN_LIST_DEFINITION ):
+
+ ID = 73
+
+ TEST_OBJECT = 0
+ IMPORTER_STRINGS = 1
+ PROCESSED_STRINGS = 2
+
+
+column_list_type_name_lookup[ COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.ID ] = 'metadata router test results'
+
+register_column_type( COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.ID, COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.TEST_OBJECT, 'source item', False, 32, True )
+register_column_type( COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.ID, COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.IMPORTER_STRINGS, 'sourced strings', False, 48, True )
+register_column_type( COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.ID, COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.PROCESSED_STRINGS, 'processed strings', False, 48, True )
+
+default_column_list_sort_lookup[ COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.ID ] = ( COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.TEST_OBJECT, True )
diff --git a/hydrus/client/gui/metadata/ClientGUIMetadataMigration.py b/hydrus/client/gui/metadata/ClientGUIMetadataMigration.py
index 063727485..2f61076f8 100644
--- a/hydrus/client/gui/metadata/ClientGUIMetadataMigration.py
+++ b/hydrus/client/gui/metadata/ClientGUIMetadataMigration.py
@@ -16,8 +16,11 @@
from hydrus.client.gui import ClientGUITopLevelWindowsPanels
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.lists import ClientGUIListBoxes
+from hydrus.client.gui.lists import ClientGUIListConstants as CGLC
+from hydrus.client.gui.lists import ClientGUIListCtrl
from hydrus.client.gui.metadata import ClientGUIMetadataMigrationExporters
from hydrus.client.gui.metadata import ClientGUIMetadataMigrationImporters
+from hydrus.client.gui.metadata import ClientGUIMetadataMigrationTest
from hydrus.client.gui.panels import ClientGUIScrolledPanels
from hydrus.client.gui.widgets import ClientGUICommon
from hydrus.client.metadata import ClientMetadataMigration
@@ -25,13 +28,14 @@
class EditSingleFileMetadataRouterPanel( ClientGUIScrolledPanels.EditPanel ):
- def __init__( self, parent: QW.QWidget, router: ClientMetadataMigration.SingleFileMetadataRouter, allowed_importer_classes: list, allowed_exporter_classes: list ):
+ def __init__( self, parent: QW.QWidget, router: ClientMetadataMigration.SingleFileMetadataRouter, allowed_importer_classes: list, allowed_exporter_classes: list, test_context_factory: ClientGUIMetadataMigrationTest.MigrationTestContextFactory ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
self._original_router = router
self._allowed_importer_classes = allowed_importer_classes
self._allowed_exporter_classes = allowed_exporter_classes
+ self._test_context_factory = test_context_factory
importers = self._original_router.GetImporters()
string_processor = self._original_router.GetStringProcessor()
@@ -66,13 +70,60 @@ def __init__( self, parent: QW.QWidget, router: ClientMetadataMigration.SingleFi
#
+ self._test_panel = ClientGUICommon.StaticBox( self, 'testing' )
+
+ self._test_panel_help_st = ClientGUICommon.BetterStaticText( self._test_panel, 'Add a source and this will show test data.' )
+ self._test_notebook = ClientGUICommon.BetterNotebook( self._test_panel )
+
+ #
+
+ self._test_panel.Add( self._test_notebook, CC.FLAGS_EXPAND_BOTH_WAYS )
+ self._test_panel.Add( self._test_panel_help_st, CC.FLAGS_CENTER_PERPENDICULAR )
+
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._importers_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._processing_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._exporter_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
- self.widget().setLayout( vbox )
+ hbox = QP.HBoxLayout()
+
+ QP.AddToLayout( hbox, vbox, CC.FLAGS_EXPAND_BOTH_WAYS_POLITE )
+ QP.AddToLayout( hbox, self._test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
+
+ self.widget().setLayout( hbox )
+
+ self._importers_list.listBoxChanged.connect( self._UpdateTestPanel )
+ self._string_processor_button.valueChanged.connect( self._UpdateTestPanel )
+
+ self._UpdateTestPanel()
+
+
+ def _ConvertTestRowToListCtrlTuples( self, test_row ):
+
+ ( importer, test_object ) = test_row
+
+ string_processor = self._string_processor_button.GetValue()
+
+ test_object_pretty = self._test_context_factory.GetTestObjectString( test_object )
+ importer_strings_output = sorted( self._test_context_factory.GetExampleTestStrings( importer, test_object ) )
+
+ if string_processor.MakesChanges():
+
+ processed_strings_output = string_processor.ProcessStrings( importer_strings_output )
+
+ else:
+
+ processed_strings_output = [ 'no changes' ]
+
+
+ pretty_importer_strings_output = ', '.join( importer_strings_output )
+ pretty_processed_strings_output = ', '.join( processed_strings_output )
+
+ display_tuple = ( test_object_pretty, pretty_importer_strings_output, pretty_processed_strings_output )
+ sort_tuple = ( test_object_pretty, len( importer_strings_output ), len( processed_strings_output ) )
+
+ return ( display_tuple, sort_tuple )
def _GetExampleStringProcessorTestData( self ):
@@ -110,6 +161,50 @@ def _GetValue( self ) -> ClientMetadataMigration.SingleFileMetadataRouter:
return router
+ def _UpdateTestPanel( self ):
+
+ importers = self._importers_list.GetData()
+
+ while self._test_notebook.count() > len( importers ):
+
+ last_page_index = self._test_notebook.count() - 1
+
+ page = self._test_notebook.widget( last_page_index )
+
+ self._test_notebook.removeTab( last_page_index )
+
+ page.deleteLater()
+
+
+ we_got_importers = len( self._importers_list.GetData() ) > 0
+
+ self._test_notebook.setVisible( we_got_importers )
+ self._test_panel_help_st.setVisible( not we_got_importers )
+
+ for ( i, importer ) in enumerate( self._importers_list.GetData() ):
+
+ if self._test_notebook.count() < i + 1:
+
+ # make this our new listctrl
+ list_ctrl = ClientGUIListCtrl.BetterListCtrl( self._test_notebook, CGLC.COLUMN_LIST_METADATA_ROUTER_TEST_RESULTS.ID, 11, self._ConvertTestRowToListCtrlTuples )
+
+ self._test_notebook.addTab( list_ctrl, 'init' )
+
+
+ page_name = HydrusText.ElideText( importer.ToString(), 14 )
+
+ self._test_notebook.setTabText( i, page_name )
+
+ list_ctrl = self._test_notebook.widget( i )
+
+ test_objects = self._test_context_factory.GetTestObjects()
+
+ list_ctrl.SetData( [ ( importer, test_object ) for test_object in test_objects ] )
+
+ list_ctrl.UpdateDatas()
+
+
+
def GetValue( self ) -> ClientMetadataMigration.SingleFileMetadataRouter:
router = self._GetValue()
@@ -125,12 +220,13 @@ def convert_router_to_pretty_string( router: ClientMetadataMigration.SingleFileM
class SingleFileMetadataRoutersControl( ClientGUIListBoxes.AddEditDeleteListBox ):
- def __init__( self, parent: QW.QWidget, routers: typing.Collection[ ClientMetadataMigration.SingleFileMetadataRouter ], allowed_importer_classes: list, allowed_exporter_classes: list ):
+ def __init__( self, parent: QW.QWidget, routers: typing.Collection[ ClientMetadataMigration.SingleFileMetadataRouter ], allowed_importer_classes: list, allowed_exporter_classes: list, test_context_factory: ClientGUIMetadataMigrationTest.MigrationTestContextFactory ):
ClientGUIListBoxes.AddEditDeleteListBox.__init__( self, parent, 5, convert_router_to_pretty_string, self._AddRouter, self._EditRouter )
self._allowed_importer_classes = allowed_importer_classes
self._allowed_exporter_classes = allowed_exporter_classes
+ self._test_context_factory = test_context_factory
self.AddDatas( routers )
@@ -197,7 +293,7 @@ def _EditRouter( self, router: ClientMetadataMigration.SingleFileMetadataRouter
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit metadata migration router' ) as dlg:
- panel = EditSingleFileMetadataRouterPanel( self, router, self._allowed_importer_classes, self._allowed_exporter_classes )
+ panel = EditSingleFileMetadataRouterPanel( self, router, self._allowed_importer_classes, self._allowed_exporter_classes, self._test_context_factory )
dlg.SetPanel( panel )
@@ -217,13 +313,14 @@ class SingleFileMetadataRoutersButton( QW.QPushButton ):
valueChanged = QC.Signal()
- def __init__( self, parent: QW.QWidget, routers: typing.Collection[ ClientMetadataMigration.SingleFileMetadataRouter ], allowed_importer_classes: list, allowed_exporter_classes: list ):
+ def __init__( self, parent: QW.QWidget, routers: typing.Collection[ ClientMetadataMigration.SingleFileMetadataRouter ], allowed_importer_classes: list, allowed_exporter_classes: list, test_context_factory: ClientGUIMetadataMigrationTest.MigrationTestContextFactory ):
QW.QPushButton.__init__( self, parent )
self._routers = routers
self._allowed_importer_classes = allowed_importer_classes
self._allowed_exporter_classes = allowed_exporter_classes
+ self._test_context_factory = test_context_factory
self._RefreshLabel()
@@ -236,7 +333,7 @@ def _Edit( self ):
panel = ClientGUIScrolledPanels.EditSingleCtrlPanel( dlg )
- control = SingleFileMetadataRoutersControl( panel, self._routers, self._allowed_importer_classes, self._allowed_exporter_classes )
+ control = SingleFileMetadataRoutersControl( panel, self._routers, self._allowed_importer_classes, self._allowed_exporter_classes, self._test_context_factory )
panel.SetControl( control )
diff --git a/hydrus/client/gui/metadata/ClientGUIMetadataMigrationTest.py b/hydrus/client/gui/metadata/ClientGUIMetadataMigrationTest.py
new file mode 100644
index 000000000..939b42b7c
--- /dev/null
+++ b/hydrus/client/gui/metadata/ClientGUIMetadataMigrationTest.py
@@ -0,0 +1,89 @@
+import typing
+
+from hydrus.client.media import ClientMediaResult
+from hydrus.client.metadata import ClientMetadataMigrationImporters
+
+HOW_MANY_EXAMPLE_OBJECTS_TO_USE = 25
+
+class MigrationTestContextFactory( object ):
+
+ def GetExampleTestStrings( self, importer: ClientMetadataMigrationImporters.SingleFileMetadataImporter, test_object: object ):
+
+ raise NotImplementedError()
+
+
+ def GetExampleTestStringGroups( self, importer: ClientMetadataMigrationImporters.SingleFileMetadataImporter ) -> typing.Collection[ typing.Tuple[ str, typing.Collection[ str ] ] ]:
+
+ raise NotImplementedError()
+
+
+ def GetTestObjects( self ) -> typing.Collection[ object ]:
+
+ raise NotImplementedError()
+
+
+ def GetTestObjectString( self, test_object: object ) -> str:
+
+ raise NotImplementedError()
+
+
+
+class MigrationTestContextFactorySidecar( MigrationTestContextFactory ):
+
+ def __init__( self, example_file_paths: typing.Collection[ str ] ):
+
+ MigrationTestContextFactory.__init__( self )
+
+ self._example_file_paths = example_file_paths
+
+
+ def GetExampleTestStrings( self, importer: ClientMetadataMigrationImporters.SingleFileMetadataImporterSidecar, test_object: str ):
+
+ return importer.Import( test_object )
+
+
+ def GetTestObjects( self ) -> typing.Collection[ str ]:
+
+ return self._example_file_paths
+
+
+ def GetTestObjectString( self, test_object: str ) -> str:
+
+ return test_object
+
+
+ def SetExampleFilePaths( self, paths: typing.Collection[ str ] ):
+
+ self._example_file_paths = paths
+
+
+
+class MigrationTestContextFactoryMedia( MigrationTestContextFactory ):
+
+ def __init__( self, example_media_results: typing.Collection[ ClientMediaResult.MediaResult ] ):
+
+ MigrationTestContextFactory.__init__( self )
+
+ self._example_media_results = example_media_results
+
+
+ def GetExampleTestStrings( self, importer: ClientMetadataMigrationImporters.SingleFileMetadataImporterMedia, test_object: ClientMediaResult.MediaResult ):
+
+ return importer.Import( test_object )
+
+
+ def GetTestObjects( self ) -> typing.Collection[ ClientMediaResult.MediaResult ]:
+
+ return self._example_media_results
+
+
+ def GetTestObjectString( self, test_object: ClientMediaResult.MediaResult ) -> str:
+
+ return test_object.GetHash().hex()
+
+
+ def SetExampleMediaResults( self, media_results: typing.Collection[ ClientMediaResult.MediaResult ] ):
+
+ self._example_media_results = media_results
+
+
diff --git a/hydrus/client/gui/pages/ClientGUIResults.py b/hydrus/client/gui/pages/ClientGUIResults.py
index bd22fd77e..e5b09fcd7 100644
--- a/hydrus/client/gui/pages/ClientGUIResults.py
+++ b/hydrus/client/gui/pages/ClientGUIResults.py
@@ -1,6 +1,5 @@
import collections
import itertools
-import os
import random
import time
import typing
@@ -171,6 +170,20 @@ def __init__( self, parent, page_key, management_controller: ClientGUIManagement
QW.QScrollArea.__init__( self, parent )
+ self._qss_colours = {
+ CC.COLOUR_THUMBGRID_BACKGROUND : QG.QColor( 255, 255, 255 ),
+ CC.COLOUR_THUMB_BACKGROUND : QG.QColor( 255, 255, 255 ),
+ CC.COLOUR_THUMB_BACKGROUND_SELECTED : QG.QColor( 217, 242, 255 ),
+ CC.COLOUR_THUMB_BACKGROUND_REMOTE : QG.QColor( 32, 32, 36 ),
+ CC.COLOUR_THUMB_BACKGROUND_REMOTE_SELECTED : QG.QColor( 64, 64, 72 ),
+ CC.COLOUR_THUMB_BORDER : QG.QColor( 223, 227, 230 ),
+ CC.COLOUR_THUMB_BORDER_SELECTED : QG.QColor( 1, 17, 26 ),
+ CC.COLOUR_THUMB_BORDER_REMOTE : QG.QColor( 248, 208, 204 ),
+ CC.COLOUR_THUMB_BORDER_REMOTE_SELECTED : QG.QColor( 227, 66, 52 )
+ }
+
+ self.setObjectName( 'HydrusMediaList' )
+
self.setFrameStyle( QW.QFrame.Panel | QW.QFrame.Sunken )
self.setLineWidth( 2 )
@@ -1916,6 +1929,20 @@ def Collect( self, media_collect = None ):
self.Sort()
+ def GetColour( self, colour_type ):
+
+ if CG.client_controller.new_options.GetBoolean( 'override_stylesheet_colours' ):
+
+ bg_colour = CG.client_controller.new_options.GetColour( colour_type )
+
+ else:
+
+ bg_colour = self._qss_colours.get( colour_type, QG.QColor( 127, 127, 127 ) )
+
+
+ return bg_colour
+
+
def GetTotalFileSize( self ):
return 0
@@ -2522,6 +2549,106 @@ def SetFocusedMedia( self, media ):
pass
+ def get_hmrp_background( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMBGRID_BACKGROUND ]
+
+
+ def get_hmrp_thumbnail_local_background_normal( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND ]
+
+
+ def get_hmrp_thumbnail_local_background_selected( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND_SELECTED ]
+
+
+ def get_hmrp_thumbnail_local_border_normal( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BORDER ]
+
+
+ def get_hmrp_thumbnail_local_border_selected( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BORDER_SELECTED ]
+
+
+ def get_hmrp_thumbnail_not_local_background_normal( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND_REMOTE ]
+
+
+ def get_hmrp_thumbnail_not_local_background_selected( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND_REMOTE_SELECTED ]
+
+
+ def get_hmrp_thumbnail_not_local_border_normal( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BORDER_REMOTE ]
+
+
+ def get_hmrp_thumbnail_not_local_border_selected( self ):
+
+ return self._qss_colours[ CC.COLOUR_THUMB_BORDER_REMOTE_SELECTED ]
+
+
+ def set_hmrp_background( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMBGRID_BACKGROUND ] = colour
+
+
+ def set_hmrp_thumbnail_local_background_normal( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND ] = colour
+
+
+ def set_hmrp_thumbnail_local_background_selected( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND_SELECTED ] = colour
+
+
+ def set_hmrp_thumbnail_local_border_normal( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BORDER ] = colour
+
+
+ def set_hmrp_thumbnail_local_border_selected( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BORDER_SELECTED ] = colour
+
+
+ def set_hmrp_thumbnail_not_local_background_normal( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND_REMOTE ] = colour
+
+
+ def set_hmrp_thumbnail_not_local_background_selected( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BACKGROUND_REMOTE_SELECTED ] = colour
+
+
+ def set_hmrp_thumbnail_not_local_border_normal( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BORDER_REMOTE ] = colour
+
+
+ def set_hmrp_thumbnail_not_local_border_selected( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_THUMB_BORDER_REMOTE_SELECTED ] = colour
+
+
+ hmrp_background = QC.Property( QG.QColor, get_hmrp_background, set_hmrp_background )
+ hmrp_thumbnail_local_background_normal = QC.Property( QG.QColor, get_hmrp_thumbnail_local_background_normal, set_hmrp_thumbnail_local_background_normal )
+ hmrp_thumbnail_local_background_selected = QC.Property( QG.QColor, get_hmrp_thumbnail_local_background_selected, set_hmrp_thumbnail_local_background_selected )
+ hmrp_thumbnail_local_border_normal = QC.Property( QG.QColor, get_hmrp_thumbnail_local_border_normal, set_hmrp_thumbnail_local_border_normal )
+ hmrp_thumbnail_local_border_selected = QC.Property( QG.QColor, get_hmrp_thumbnail_local_border_selected, set_hmrp_thumbnail_local_border_selected )
+ hmrp_thumbnail_not_local_background_normal = QC.Property( QG.QColor, get_hmrp_thumbnail_not_local_background_normal, set_hmrp_thumbnail_not_local_background_normal )
+ hmrp_thumbnail_not_local_background_selected = QC.Property( QG.QColor, get_hmrp_thumbnail_not_local_background_selected, set_hmrp_thumbnail_not_local_background_selected )
+ hmrp_thumbnail_not_local_border_normal = QC.Property( QG.QColor, get_hmrp_thumbnail_not_local_border_normal, set_hmrp_thumbnail_not_local_border_normal )
+ hmrp_thumbnail_not_local_border_selected = QC.Property( QG.QColor, get_hmrp_thumbnail_not_local_border_selected, set_hmrp_thumbnail_not_local_border_selected )
+
class _InnerWidget( QW.QWidget ):
def __init__( self, parent ):
@@ -2535,7 +2662,7 @@ def paintEvent( self, event ):
painter = QG.QPainter( self )
- bg_colour = CG.client_controller.new_options.GetColour( CC.COLOUR_THUMBGRID_BACKGROUND )
+ bg_colour = self._parent.GetColour( CC.COLOUR_THUMBGRID_BACKGROUND )
painter.setBackground( QG.QBrush( bg_colour ) )
@@ -2724,7 +2851,7 @@ def _DrawCanvasPage( self, page_index, canvas_page ):
new_options = CG.client_controller.new_options
- bg_colour = CG.client_controller.new_options.GetColour( CC.COLOUR_THUMBGRID_BACKGROUND )
+ bg_colour = self.GetColour( CC.COLOUR_THUMBGRID_BACKGROUND )
if HG.thumbnail_debug_mode and page_index % 2 == 0:
@@ -2785,7 +2912,7 @@ def _DrawCanvasPage( self, page_index, canvas_page ):
y = ( thumbnail_row - ( page_index * self._num_rows_per_canvas_page ) ) * thumbnail_span_height + thumbnail_margin
- painter.drawImage( x, y, thumbnail.GetQtImage( self.devicePixelRatio() ) )
+ painter.drawImage( x, y, thumbnail.GetQtImage( self, self.devicePixelRatio() ) )
else:
@@ -2846,7 +2973,7 @@ def _FadeThumbnails( self, thumbnails ):
self._StopFading( hash )
- bitmap = thumbnail.GetQtImage( self.devicePixelRatio() )
+ bitmap = thumbnail.GetQtImage( self, self.devicePixelRatio() )
fade_thumbnails = CG.client_controller.new_options.GetBoolean( 'fade_thumbnails' )
@@ -4475,7 +4602,7 @@ def paintEvent( self, event ):
y_start = self._parent._GetYStart()
- bg_colour = CG.client_controller.new_options.GetColour( CC.COLOUR_THUMBGRID_BACKGROUND )
+ bg_colour = self._parent.GetColour( CC.COLOUR_THUMBGRID_BACKGROUND )
painter.setBackground( QG.QBrush( bg_colour ) )
@@ -4801,7 +4928,7 @@ def ClearTagSummaryCaches( self ):
self._last_lower_summary = None
- def GetQtImage( self, device_pixel_ratio ) -> QG.QImage:
+ def GetQtImage( self, media_panel: MediaPanel, device_pixel_ratio ) -> QG.QImage:
# we probably don't really want to say DPR as a param here, but instead ask for a qt_image in a certain resolution?
# or just give the qt_image to be drawn to?
@@ -4901,7 +5028,9 @@ def GetQtImage( self, device_pixel_ratio ) -> QG.QImage:
painter.setFont( f )
- painter.fillRect( thumbnail_border, thumbnail_border, width - ( thumbnail_border * 2 ), height - ( thumbnail_border * 2 ), new_options.GetColour( background_colour_type ) )
+ bg_color = media_panel.GetColour( background_colour_type )
+
+ painter.fillRect( thumbnail_border, thumbnail_border, width - ( thumbnail_border * 2 ), height - ( thumbnail_border * 2 ), bg_color )
raw_thumbnail_qt_image = thumbnail_hydrus_bmp.GetQtImage()
@@ -5043,7 +5172,9 @@ def GetQtImage( self, device_pixel_ratio ) -> QG.QImage:
# _ .___//_/ /_/|_| \___//_/ /____/ _\__, / \____/ \__/ \____/ /_/ /_/\___//_/ /_/ (_)
# /_/ /____/
- painter.setBrush( QG.QBrush( new_options.GetColour( border_colour_type ) ) )
+ bd_colour = media_panel.GetColour( border_colour_type )
+
+ painter.setBrush( QG.QBrush( bd_colour ) )
painter.setPen( QG.QPen( QC.Qt.NoPen ) )
rectangles = []
diff --git a/hydrus/client/gui/panels/ClientGUIScrolledPanelsManagement.py b/hydrus/client/gui/panels/ClientGUIScrolledPanelsManagement.py
index 7a22b5910..8e1827e44 100644
--- a/hydrus/client/gui/panels/ClientGUIScrolledPanelsManagement.py
+++ b/hydrus/client/gui/panels/ClientGUIScrolledPanelsManagement.py
@@ -198,24 +198,26 @@ def __init__( self, parent ):
self._new_options = CG.client_controller.new_options
- help_text = 'Hey, this page is pretty old. We want to eventually move its capabilities to the more flexible "style" page, but for now, several custom widgets have hardcoded colours set here.'
+ help_text = 'Hey, this page is pretty old, and hydev is in the process of transforming it into a different system. Colours are generally managed through QSS stylesheets now, under the "style" page, but you can still override some stuff here if you want.'
help_text += '\n' * 2
- help_text += 'In a similar way, the "darkmode" here only changes these colours, it does not change the stylesheet. Please bear with the awkwardness of these two systems, we do plan to improve them, thank you!'
+ help_text += 'The "darkmode" in hydrus is also very old and only changes these colours; it does not change the stylesheet. Please bear with the awkwardness, this will be cleaned up eventually, thank you!'
self._help_label = ClientGUICommon.BetterStaticText( self, label = help_text )
self._help_label.setObjectName( 'HydrusWarning' )
- coloursets_panel = ClientGUICommon.StaticBox( self, 'coloursets' )
+ self._help_label.setWordWrap( True )
- self._current_colourset = ClientGUICommon.BetterChoice( coloursets_panel )
+ self._override_stylesheet_colours = QW.QCheckBox( self )
+
+ self._coloursets_panel = ClientGUICommon.StaticBox( self, 'coloursets' )
+
+ self._current_colourset = ClientGUICommon.BetterChoice( self._coloursets_panel )
self._current_colourset.addItem( 'default', 'default' )
self._current_colourset.addItem( 'darkmode', 'darkmode' )
- self._current_colourset.SetValue( self._new_options.GetString( 'current_colourset' ) )
-
- self._notebook = QW.QTabWidget( coloursets_panel )
+ self._notebook = QW.QTabWidget( self._coloursets_panel )
self._gui_colours = {}
@@ -292,20 +294,44 @@ def __init__( self, parent ):
#
- coloursets_panel.Add( ClientGUICommon.WrapInText( self._current_colourset, coloursets_panel, 'current colourset: ' ), CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
- coloursets_panel.Add( self._notebook, CC.FLAGS_EXPAND_BOTH_WAYS )
+ self._override_stylesheet_colours.setChecked( self._new_options.GetBoolean( 'override_stylesheet_colours' ) )
+ self._current_colourset.SetValue( self._new_options.GetString( 'current_colourset' ) )
+
+ #
+
+ rows = []
+
+ rows.append( ( 'override what is set in the stylesheet with the colours on this page: ', self._override_stylesheet_colours ) )
+
+ gridbox = ClientGUICommon.WrapInGrid( self, rows )
+
+ self._coloursets_panel.Add( ClientGUICommon.WrapInText( self._current_colourset, self._coloursets_panel, 'current colourset: ' ), CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
+ self._coloursets_panel.Add( self._notebook, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._help_label, CC.FLAGS_EXPAND_PERPENDICULAR )
- QP.AddToLayout( vbox, coloursets_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
+ QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
+ QP.AddToLayout( vbox, self._coloursets_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
+
vbox.addStretch( 1 )
self.setLayout( vbox )
+ self._override_stylesheet_colours.clicked.connect( self._UpdateOverride )
+
+ self._UpdateOverride()
+
+
+ def _UpdateOverride( self ):
+
+ self._coloursets_panel.setEnabled( self._override_stylesheet_colours.isChecked() )
+
def UpdateOptions( self ):
+ self._new_options.SetBoolean( 'override_stylesheet_colours', self._override_stylesheet_colours.isChecked() )
+
for colourset in self._gui_colours:
for ( colour_type, ctrl ) in list(self._gui_colours[ colourset ].items()):
@@ -3940,12 +3966,14 @@ def __init__( self, parent, new_options ):
#
- help_text = 'Hey, there are several colours, mostly for custom widgets, not set here. Check the "colours" page out!'
+ help_text = 'Hey, there are several custom widget colours that can be overridden in the "colours" page!'
self._help_label = ClientGUICommon.BetterStaticText( self, label = help_text )
self._help_label.setObjectName( 'HydrusWarning' )
+ self._help_label.setWordWrap( True )
+
self._qt_style_name = ClientGUICommon.BetterChoice( self )
self._qt_stylesheet_name = ClientGUICommon.BetterChoice( self )
@@ -3992,9 +4020,7 @@ def __init__( self, parent, new_options ):
text = 'The current styles are what your Qt has available, the stylesheets are what .css and .qss files are currently in install_dir/static/qss.'
text += '\n' * 2
- text += 'Note that there are several colours not handled by this yet. Check out the "colours" page of this options to change them.'
- text += '\n' * 2
- text += 'Also, if you run from source and you select e621 or another stylesheet that includes external (svg) assets, you must make sure that your CWD is the hydrus install folder when you boot.'
+ text += 'If you run from source and you select e621 or another stylesheet that includes external (svg) assets, you must make sure that your CWD is the hydrus install folder when you boot.'
st = ClientGUICommon.BetterStaticText( self, label = text )
diff --git a/hydrus/client/gui/search/ClientGUIACDropdown.py b/hydrus/client/gui/search/ClientGUIACDropdown.py
index 87598539a..fc88b1304 100644
--- a/hydrus/client/gui/search/ClientGUIACDropdown.py
+++ b/hydrus/client/gui/search/ClientGUIACDropdown.py
@@ -4,6 +4,7 @@
import typing
from qtpy import QtCore as QC
+from qtpy import QtGui as QG
from qtpy import QtWidgets as QW
from hydrus.core import HydrusConstants as HC
@@ -799,9 +800,15 @@ class AutoCompleteDropdown( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
def __init__( self, parent ):
+ self._qss_colours = {
+ CC.COLOUR_AUTOCOMPLETE_BACKGROUND : QG.QColor( 235, 248, 255 )
+ }
+
QW.QWidget.__init__( self, parent )
CAC.ApplicationCommandProcessorMixin.__init__( self )
+ self.setObjectName( 'HydrusTagAutocomplete' )
+
self._can_intercept_unusual_key_events = True
if self.window() == CG.client_controller.gui:
@@ -823,8 +830,6 @@ def __init__( self, parent ):
self.setFocusProxy( self._text_ctrl )
- self._UpdateBackgroundColour()
-
self._last_attempted_dropdown_width = 0
self._text_ctrl_widget_event_filter = QP.WidgetEventFilter( self._text_ctrl )
@@ -949,6 +954,8 @@ def __init__( self, parent ):
# trying a second go to see if that improves some positioning
CG.client_controller.CallLaterQtSafe( self, 0.25, 'hide/show dropdown', self._DropdownHideShow )
+ CG.client_controller.CallLaterQtSafe( self, 0.05, 'do autocomplete background colour', self._UpdateBackgroundColour )
+
def _BroadcastChoices( self, predicates, shift_down ):
@@ -1165,14 +1172,14 @@ def _TakeResponsibilityForEnter( self, shift_down ):
def _UpdateBackgroundColour( self ):
- colour = CG.client_controller.new_options.GetColour( CC.COLOUR_AUTOCOMPLETE_BACKGROUND )
+ bg_colour = self.GetColour( CC.COLOUR_AUTOCOMPLETE_BACKGROUND )
if not self._can_intercept_unusual_key_events:
- colour = ClientGUIFunctions.GetLighterDarkerColour( colour )
+ bg_colour = ClientGUIFunctions.GetLighterDarkerColour( bg_colour )
- QP.SetBackgroundColour( self._text_ctrl, colour )
+ QP.SetBackgroundColour( self._text_ctrl, bg_colour )
self._text_ctrl.update()
@@ -1410,6 +1417,20 @@ def EventText( self, new_text ):
+ def GetColour( self, colour_type ):
+
+ new_options = CG.client_controller.new_options
+
+ if new_options.GetBoolean( 'override_stylesheet_colours' ):
+
+ return new_options.GetColour( colour_type )
+
+ else:
+
+ return self._qss_colours.get( colour_type, QG.QColor( 127, 127, 127 ) )
+
+
+
def MoveNotebookPageFocus( self, index = None, direction = None ):
new_index = None
@@ -1534,6 +1555,18 @@ def SetForceDropdownHide( self, value ):
self._DropdownHideShow()
+ def get_hta_background( self ):
+
+ return self._qss_colours[ CC.COLOUR_AUTOCOMPLETE_BACKGROUND ]
+
+
+ def set_hta_background( self, colour ):
+
+ self._qss_colours[ CC.COLOUR_AUTOCOMPLETE_BACKGROUND ] = colour
+
+
+ hta_background = QC.Property( QG.QColor, get_hta_background, set_hta_background )
+
class ChildrenTab( ListBoxTagsPredicatesAC ):
@@ -2932,6 +2965,8 @@ def _EnterPredicates( self, predicates, permit_add = True, permit_remove = True
terms_to_be_added = set()
terms_to_be_removed = set()
+ terms_to_select = set()
+
for predicate in predicates:
predicate = predicate.GetCountlessCopy()
@@ -2953,7 +2988,14 @@ def _EnterPredicates( self, predicates, permit_add = True, permit_remove = True
m_e_preds = self._GetMutuallyExclusivePredicates( predicate )
- terms_to_be_removed.update( ( self._GenerateTermFromPredicate( pred ) for pred in m_e_preds ) )
+ new_removees = [ self._GenerateTermFromPredicate( pred ) for pred in m_e_preds ]
+
+ if True in ( t in self._selected_terms for t in new_removees ):
+
+ terms_to_select.add( term )
+
+
+ terms_to_be_removed.update( new_removees )
@@ -2964,6 +3006,15 @@ def _EnterPredicates( self, predicates, permit_add = True, permit_remove = True
self._Sort()
+ if len( terms_to_select ) > 0:
+
+ self._selected_terms.update( terms_to_select )
+
+ earliest_guy = sorted( terms_to_select, key = lambda t: self._terms_to_logical_indices[ t ] )[0]
+
+ self._Hit( False, False, self._terms_to_logical_indices[ earliest_guy ] )
+
+
self._DataHasChanged()
diff --git a/hydrus/client/gui/services/ClientGUIModalClientsideServiceActions.py b/hydrus/client/gui/services/ClientGUIModalClientsideServiceActions.py
index d6523f077..3d45d672e 100644
--- a/hydrus/client/gui/services/ClientGUIModalClientsideServiceActions.py
+++ b/hydrus/client/gui/services/ClientGUIModalClientsideServiceActions.py
@@ -73,6 +73,8 @@ def __init__( self, parent, service_key: bytes, tags: typing.Collection[ str ] )
self.widget().setLayout( vbox )
+ self._autocomplete.tagsPasted.connect( self._tags_to_remove.AddTags )
+
def Go( self ):
diff --git a/hydrus/client/importing/ClientImportLocal.py b/hydrus/client/importing/ClientImportLocal.py
index a82d95228..d2ad1c014 100644
--- a/hydrus/client/importing/ClientImportLocal.py
+++ b/hydrus/client/importing/ClientImportLocal.py
@@ -1346,7 +1346,10 @@ def _DoWork( self ):
with self._lock:
- del self._import_folder_names_to_next_work_time_cache[ name ]
+ if name in self._import_folder_names_to_next_work_time_cache:
+
+ del self._import_folder_names_to_next_work_time_cache[ name ]
+
return
@@ -1365,7 +1368,10 @@ def _DoWork( self ):
if next_work_time is None:
- del self._import_folder_names_to_next_work_time_cache[ name ]
+ if name in self._import_folder_names_to_next_work_time_cache:
+
+ del self._import_folder_names_to_next_work_time_cache[ name ]
+
else:
diff --git a/hydrus/client/media/ClientMedia.py b/hydrus/client/media/ClientMedia.py
index aa0dd9715..9a4c1894f 100644
--- a/hydrus/client/media/ClientMedia.py
+++ b/hydrus/client/media/ClientMedia.py
@@ -1324,14 +1324,14 @@ def ResetService( self, service_key ):
def Sort( self, media_sort = None ):
- for media in self._collected_media:
+ if media_sort is None:
- media.Sort( media_sort )
+ media_sort = self._media_sort
- if media_sort is None:
+ for media in self._collected_media:
- media_sort = self._media_sort
+ media.Sort( media_sort )
self._media_sort = media_sort
diff --git a/hydrus/client/search/ClientSearchAutocomplete.py b/hydrus/client/search/ClientSearchAutocomplete.py
index 7a2577b6b..a24570e47 100644
--- a/hydrus/client/search/ClientSearchAutocomplete.py
+++ b/hydrus/client/search/ClientSearchAutocomplete.py
@@ -167,8 +167,7 @@ def GetNonTagFileSearchPredicates( self, allow_auto_wildcard_conversion ):
search_texts = []
- allow_unnamespaced_search_gives_any_namespace_wildcards_values = [ True ]
- always_autocompleting_values = [ True, False ]
+ allow_unnamespaced_search_gives_any_namespace_wildcards_values = []
if '*' in self.raw_content:
@@ -176,20 +175,11 @@ def GetNonTagFileSearchPredicates( self, allow_auto_wildcard_conversion ):
allow_unnamespaced_search_gives_any_namespace_wildcards_values.append( False )
- for allow_unnamespaced_search_gives_any_namespace_wildcards in allow_unnamespaced_search_gives_any_namespace_wildcards_values:
-
- for always_autocompleting in always_autocompleting_values:
-
- search_texts.append( self._GetSearchText( always_autocompleting, allow_auto_wildcard_conversion = allow_unnamespaced_search_gives_any_namespace_wildcards, force_do_not_collapse = True ) )
-
-
+ allow_unnamespaced_search_gives_any_namespace_wildcards_values.append( True )
- for s in list( search_texts ):
+ for allow_unnamespaced_search_gives_any_namespace_wildcards in allow_unnamespaced_search_gives_any_namespace_wildcards_values:
- if ':' not in s:
-
- search_texts.append( '*:{}'.format( s ) )
-
+ search_texts.append( self._GetSearchText( False, allow_auto_wildcard_conversion = allow_unnamespaced_search_gives_any_namespace_wildcards, force_do_not_collapse = True ) )
search_texts = HydrusData.DedupeList( search_texts )
diff --git a/hydrus/core/HydrusConstants.py b/hydrus/core/HydrusConstants.py
index 798cf0590..7f0508545 100644
--- a/hydrus/core/HydrusConstants.py
+++ b/hydrus/core/HydrusConstants.py
@@ -105,7 +105,7 @@
# Misc
NETWORK_VERSION = 20
-SOFTWARE_VERSION = 581
+SOFTWARE_VERSION = 582
CLIENT_API_VERSION = 65
SERVER_THUMBNAIL_DIMENSIONS = ( 200, 200 )
diff --git a/hydrus/test/TestClientTags.py b/hydrus/test/TestClientTags.py
index 4a621e039..a1c1ed612 100644
--- a/hydrus/test/TestClientTags.py
+++ b/hydrus/test/TestClientTags.py
@@ -520,7 +520,7 @@ def write_predicate_tests( pat: ClientSearchAutocomplete.ParsedAutocompleteText,
bool_tests( parsed_autocomplete_text, [ True, True, False, True, False, False, True ] )
search_text_tests( parsed_autocomplete_text, [ 'samus*', 'samus*' ] )
- read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'samus*' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'samus*' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:samus*' ) ] ] )
+ read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'samus*' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'samus*' ) ] ] )
#
@@ -545,7 +545,7 @@ def write_predicate_tests( pat: ClientSearchAutocomplete.ParsedAutocompleteText,
bool_tests( parsed_autocomplete_text, [ True, True, False, True, False, False, True ] )
search_text_tests( parsed_autocomplete_text, [ 's*s', 's*s*' ] )
- read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s*' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s*' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:s*s*' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:s*s' ) ] ] )
+ read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s' ) ] ] )
#
@@ -553,7 +553,7 @@ def write_predicate_tests( pat: ClientSearchAutocomplete.ParsedAutocompleteText,
bool_tests( parsed_autocomplete_text, [ True, True, False, True, False, False, False ] )
search_text_tests( parsed_autocomplete_text, [ 's*s', 's*s*' ] )
- read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s*', inclusive = False ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s*', inclusive = False ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s', inclusive = False ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:s*s*', inclusive = False ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:s*s', inclusive = False ) ] ] )
+ read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s', inclusive = False ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s', inclusive = False ) ] ] )
#
@@ -575,7 +575,7 @@ def write_predicate_tests( pat: ClientSearchAutocomplete.ParsedAutocompleteText,
bool_tests( parsed_autocomplete_text, [ True, True, False, True, False, False, True ] )
search_text_tests( parsed_autocomplete_text, [ 's*s a*n', 's*s a*n*' ] )
- read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s a*n*' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s a*n*' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s a*n' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:s*s a*n*' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, '*:s*s a*n' ) ] ] )
+ read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s a*n' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 's*s a*n' ) ] ] )
#
@@ -615,7 +615,7 @@ def write_predicate_tests( pat: ClientSearchAutocomplete.ParsedAutocompleteText,
bool_tests( parsed_autocomplete_text, [ True, True, False, True, False, False, True ] )
search_text_tests( parsed_autocomplete_text, [ 'n*n g*s e*n:as*ka', 'n*n g*s e*n:as*ka*' ] )
- read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'n*n g*s e*n:as*ka*' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'n*n g*s e*n:as*ka*' ), ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'n*n g*s e*n:as*ka' ) ] ] )
+ read_predicate_tests( parsed_autocomplete_text, [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'n*n g*s e*n:as*ka' ), [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_WILDCARD, 'n*n g*s e*n:as*ka' ) ] ] )
#
diff --git a/static/qss/CutieDuck_(darkorange)-alternate-tooltip-colour.qss b/static/qss/CutieDuck_(darkorange)-alternate-tooltip-colour.qss
index 5b935769f..54a7023b9 100644
--- a/static/qss/CutieDuck_(darkorange)-alternate-tooltip-colour.qss
+++ b/static/qss/CutieDuck_(darkorange)-alternate-tooltip-colour.qss
@@ -436,3 +436,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #ffa02f;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/CutieDuck_(darkorange).qss b/static/qss/CutieDuck_(darkorange).qss
index bd966111f..0b947f59e 100644
--- a/static/qss/CutieDuck_(darkorange).qss
+++ b/static/qss/CutieDuck_(darkorange).qss
@@ -437,3 +437,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #ffa02f;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/Dark_Blue 1.1.qss b/static/qss/Dark_Blue 1.1.qss
index 3ed9ecc72..ed9cf1190 100644
--- a/static/qss/Dark_Blue 1.1.qss
+++ b/static/qss/Dark_Blue 1.1.qss
@@ -459,3 +459,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #8be9fd;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/Dark_Blue-alternate-tooltip-colour.qss b/static/qss/Dark_Blue-alternate-tooltip-colour.qss
index 37a88c124..3fb7ba4cc 100644
--- a/static/qss/Dark_Blue-alternate-tooltip-colour.qss
+++ b/static/qss/Dark_Blue-alternate-tooltip-colour.qss
@@ -439,3 +439,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #8be9fd;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/Dark_Blue.qss b/static/qss/Dark_Blue.qss
index 4a259b266..d631ef557 100644
--- a/static/qss/Dark_Blue.qss
+++ b/static/qss/Dark_Blue.qss
@@ -440,3 +440,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #8be9fd;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/DarkerDuck_(darkorange)-alternate-tooltip-colour.qss b/static/qss/DarkerDuck_(darkorange)-alternate-tooltip-colour.qss
index 295e0431b..89c8eb1d2 100644
--- a/static/qss/DarkerDuck_(darkorange)-alternate-tooltip-colour.qss
+++ b/static/qss/DarkerDuck_(darkorange)-alternate-tooltip-colour.qss
@@ -395,3 +395,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #ffa02f;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/DarkerDuck_(darkorange).qss b/static/qss/DarkerDuck_(darkorange).qss
index 542af2ac8..ff6547be5 100644
--- a/static/qss/DarkerDuck_(darkorange).qss
+++ b/static/qss/DarkerDuck_(darkorange).qss
@@ -396,3 +396,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #ffa02f;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/Hydracula-alternate-tooltip-colour.qss b/static/qss/Hydracula-alternate-tooltip-colour.qss
index 64463ea1c..997faa03c 100644
--- a/static/qss/Hydracula-alternate-tooltip-colour.qss
+++ b/static/qss/Hydracula-alternate-tooltip-colour.qss
@@ -487,3 +487,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #50fa7b;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/Hydracula.qss b/static/qss/Hydracula.qss
index db58f60cb..0d8d1d145 100644
--- a/static/qss/Hydracula.qss
+++ b/static/qss/Hydracula.qss
@@ -488,3 +488,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: #50fa7b;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/OledBlack-alternate-tooltip-colour.qss b/static/qss/OledBlack-alternate-tooltip-colour.qss
index a85e928c8..23b472d82 100644
--- a/static/qss/OledBlack-alternate-tooltip-colour.qss
+++ b/static/qss/OledBlack-alternate-tooltip-colour.qss
@@ -437,3 +437,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: white;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/OledBlack.qss b/static/qss/OledBlack.qss
index 8c2f83197..b1a44ec14 100644
--- a/static/qss/OledBlack.qss
+++ b/static/qss/OledBlack.qss
@@ -438,3 +438,51 @@ QLabel#HydrusHyperlink
{
qproperty-link_color: white;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/Purple.qss b/static/qss/Purple.qss
new file mode 100644
index 000000000..b745da6d2
--- /dev/null
+++ b/static/qss/Purple.qss
@@ -0,0 +1,340 @@
+/*
+A Purple theme for Hydrus Network by B1N4RYJ4N
+Version..: 1.0
+
+To achieve the intended results you must:
+
+1. Activate dark mode
+2. adjust the Qt style to Fusion
+3. adjust the Qt stylesheet to Purple
+4. adjust the current colourset under files > options > colors > current colourset to darkmode
+5. adjust your color values under files > options > colors > darkmode like so:
+
+ thumbnail background normal..: #2D1F2D
+ thumbnail background selected: #8E4585
+ thumbnail border normal......: #8E4585
+ thumbnail border selected....: #6B3A65
+ thumbnail grid background....: #2D1F2D
+ autocomplete background......: #6B3A65
+ media viewer background......: #2D1F2D
+ media viewer text............: #E6D0E6
+ tag box background...........: #2D1F2D
+
+6. adjust your tag presentation color values under files > options > tag presentation > (On thumbnail top, On thumbnail bottom-right, On media viewer top) like so:
+
+ background colour............: #8E4585
+ text colour..................: #E6D0E6
+*/
+
+
+/* General settings */
+QAbstractItemView {
+ background-color: #2D1F2D;
+}
+
+QWidget {
+ color: #E6D0E6;
+ background-color: #2D1F2D;
+ alternate-background-color: #2D1F2D;
+}
+
+QWidget::disabled {
+ background-color: #2D1F2D;
+}
+
+QWidget::item::selected {
+ color: #FFF;
+ background-color: #8E4585;
+}
+
+QWidget::item:hover {
+ color: #FFF;
+ background-color: #8E4585;
+}
+
+QWidget#HydrusAnimationBar
+{
+ qproperty-hab_border: #6B3A65;
+ qproperty-hab_background: #8E4585;
+ qproperty-hab_nub: #D070C0;
+}
+
+/* Tooltips */
+QToolTip {
+ color: #FFD0FF;
+ border: 1px solid black;
+ background-color: #2D1F2D;
+ padding: 1px;
+}
+
+/* Menüs */
+QMenu {
+ color: #E6D0E6;
+ background: #2D1F2D;
+}
+
+QMenu::item:selected {
+ color: #FFF;
+ background: #8E4585;
+}
+
+/* Menüleiste */
+QMenuBar::item:selected {
+ color: #FFF;
+ background: #8E4585;
+}
+
+/* Buttons */
+QPushButton {
+ color: #E6D0E6;
+ background-color: #2D1F2D;
+}
+
+QPushButton::hover {
+ color: #FFF;
+ background-color: #2D1F2D;
+}
+
+QPushButton#HydrusAccept {
+ color: #A0FFA0;
+}
+
+QPushButton#HydrusCancel {
+ color: #FFA0A0;
+}
+
+/* Tabs */
+QTabBar::tab {
+ color: #FFD0FF;
+ background-color: #231823;
+ padding: 3px 10px 2px 10px;
+}
+
+QTabBar::tab:selected {
+ color: #FFF;
+ background-color: #8E4585;
+}
+
+QTabBar::tab:hover:!selected {
+ color: #FFF;
+ background-color: #8E4585;
+}
+
+/* Eingabefelder */
+QLineEdit {
+ border: 1px solid #8E4585;
+ border-radius: 1px;
+ background-color: #433043;
+ padding: 1px;
+}
+
+QLineEdit:focus {
+ color: #FFF;
+ border: 1px solid #E6D0E6;
+}
+
+/* Fortschrittsbalken */
+QProgressBar {
+ color: #E6D0E6;
+ border: 1px solid #8E4585;
+ text-align: center;
+ padding: 1px;
+ border-radius: 0px;
+ background-color: #433043;
+ width: 15px;
+ qproperty-textVisible: true;
+}
+
+QProgressBar::chunk {
+ background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0,
+ stop: 0 #B058A7,
+ stop: 0.4999 #8E4585,
+ stop: 0.5 #7D3A74,
+ stop: 1 #6B3A65);
+ border-radius: 0px;
+ border: 0px;
+}
+
+/* Header lines */
+QHeaderView::section {
+ background-color: #6B3A65;
+ color: #E6D0E6;
+ padding-left: 4px;
+ border: 1px solid #8E4585;
+}
+
+/* Scrollbar */
+QScrollBar {
+ background: #2D1F2D;
+ margin: 0;
+}
+
+QScrollBar:vertical {
+ width: 14px;
+}
+
+QScrollBar:horizontal {
+ height: 14px;
+}
+
+QScrollBar::handle {
+ background: #6B3A65;
+ border: 2px solid #8E4585;
+ border-radius: 7px;
+ min-height: 20px;
+}
+
+QScrollBar::handle:vertical {
+ margin: 2px 2px 2px 2px;
+}
+
+QScrollBar::handle:horizontal {
+ margin: 2px 2px 2px 2px;
+}
+
+QScrollBar::handle:hover {
+ background: #8E4585;
+ border-color: #B058A7;
+}
+
+QScrollBar::handle:pressed {
+ background: #B058A7;
+ border-color: #D070C0;
+}
+
+QScrollBar::add-line, QScrollBar::sub-line {
+ background: #433043;
+ height: 14px;
+ width: 14px;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:vertical {
+ subcontrol-position: bottom;
+}
+
+QScrollBar::sub-line:vertical {
+ subcontrol-position: top;
+}
+
+QScrollBar::add-line:horizontal {
+ subcontrol-position: right;
+}
+
+QScrollBar::sub-line:horizontal {
+ subcontrol-position: left;
+}
+
+QScrollBar::up-arrow, QScrollBar::down-arrow,
+QScrollBar::left-arrow, QScrollBar::right-arrow {
+ background: #8E4585;
+ height: 6px;
+ width: 6px;
+}
+
+QScrollBar::add-page, QScrollBar::sub-page {
+ background: #3D2A3D;
+}
+
+/* Text fields */
+QTextEdit {
+ color: #D0B0D0;
+ background-color: #433043;
+}
+
+QPlainTextEdit {
+ background-color: #433043;
+ color: #E6D0E6;
+}
+
+/* Special text fields */
+QTextEdit#HydrusValid, QLineEdit#HydrusValid {
+ color: #2D1F2D;
+ background-color: #A0E6A0;
+}
+
+QTextEdit#HydrusIndeterminate, QLineEdit#HydrusIndeterminateValid {
+ color: #2D1F2D;
+ background-color: #D0B0FF;
+}
+
+QTextEdit#HydrusInvalid, QLineEdit#HydrusInvalid {
+ color: #2D1F2D;
+ background-color: #E6A0A0;
+}
+
+/* Labels */
+QLabel#HydrusValid {
+ color: #A0FFA0;
+}
+
+QLabel#HydrusIndeterminate {
+ color: #D0B0FF;
+}
+
+QLabel#HydrusInvalid {
+ color: #FFA0A0;
+}
+
+QLabel#HydrusWarning {
+ color: #FFA0A0;
+}
+
+/* Checkboxes */
+QCheckBox#HydrusWarning {
+ color: #FFA0A0;
+}
+
+/* Hyperlinks */
+QLabel#HydrusHyperlink
+{
+ qproperty-link_color: #D070C0;
+}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/default_hydrus.qss b/static/qss/default_hydrus.qss
index 84cea1f6f..ec9fc01e7 100644
--- a/static/qss/default_hydrus.qss
+++ b/static/qss/default_hydrus.qss
@@ -1,7 +1,6 @@
/*
Default QSS for hydrus. This is prepended to any stylesheet loaded in hydrus.
Copying these entries in your own stylesheets should override these settings.
-This will get more work in future.
*/
/*
@@ -14,12 +13,13 @@ Here are some text and background colours
QLabel#HydrusValid
{
- color: #008000;
+ color: #008000;
}
QLineEdit#HydrusValid, QTextEdit#HydrusValid, QPlainTextEdit#HydrusValid
{
- background-color: #80ff80;
+ color: #000000;
+ background-color: #80ff80;
}
@@ -27,12 +27,13 @@ QLineEdit#HydrusValid, QTextEdit#HydrusValid, QPlainTextEdit#HydrusValid
QLabel#HydrusIndeterminate
{
- color: #000080;
+ color: #000080;
}
QLineEdit#HydrusIndeterminate, QTextEdit#HydrusIndeterminate, QPlainTextEdit#HydrusIndeterminate
{
- background-color: #000080;
+ color: #000000;
+ background-color: #000080;
}
@@ -40,12 +41,13 @@ QLineEdit#HydrusIndeterminate, QTextEdit#HydrusIndeterminate, QPlainTextEdit#Hyd
QLabel#HydrusInvalid
{
- color: #800000;
+ color: #800000;
}
QLineEdit#HydrusInvalid, QTextEdit#HydrusInvalid, QPlainTextEdit#HydrusInvalid
{
- background-color: #ff8080;
+ color: #000000;
+ background-color: #ff8080;
}
@@ -53,7 +55,7 @@ QLineEdit#HydrusInvalid, QTextEdit#HydrusInvalid, QPlainTextEdit#HydrusInvalid
QLabel#HydrusWarning, QCheckBox#HydrusWarning
{
- color: #800000;
+ color: #800000;
}
/*
@@ -64,12 +66,12 @@ Buttons on dialogs
QPushButton#HydrusAccept
{
- color: #008000;
+ color: #008000;
}
QPushButton#HydrusCancel
{
- color: #800000;
+ color: #800000;
}
/*
@@ -80,12 +82,12 @@ This is the green/red button that switches 'include current tags' and similar st
QPushButton#HydrusOnOffButton[hydrus_on=true]
{
- color: #008000;
+ color: #008000;
}
QPushButton#HydrusOnOffButton[hydrus_on=false]
{
- color: #800000;
+ color: #800000;
}
/*
@@ -96,12 +98,12 @@ This is the Command Palette (default Ctrl+P), and specifically the background co
QLocatorResultWidget#selectedLocatorResult
{
- background-color: palette(highlight);
+ background-color: palette(highlight);
}
QLocatorResultWidget QWidget
{
- background: transparent;
+ background: transparent;
}
@@ -115,21 +117,73 @@ These are drawn by hydev on a blank canvas, so they work a little different.
/*
-The scanbar beneath video/audio in the media viewer.
+The main colours in the _options->colours_ panel. This used to be hardcoded, with no way to change it in QSS, but now the QSS is the default and the options panel has the choice of overriding what the current stylesheet suggests.
*/
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #ffffff;
+ qproperty-hmrp_thumbnail_local_background_normal: #ffffff;
+ qproperty-hmrp_thumbnail_local_border_normal: #dfe3e6;
+ qproperty-hmrp_thumbnail_local_background_selected: #d9f2ff;
+ qproperty-hmrp_thumbnail_local_border_selected: #01111a;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #202024;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #404048;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #ffffff;
+ qproperty-hmv_text: #000000;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #ebf8ff;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #ffffff;
+}
+
+
+/*
+
+Other custom stuff
+
+*/
+
+/* The scanbar beneath video/audio in the media viewer. */
+
QWidget#HydrusAnimationBar
{
- qproperty-hab_border: #000000;
- qproperty-hab_background: #f0f0f0;
- qproperty-hab_nub: #606060;
+ qproperty-hab_border: #000000;
+ qproperty-hab_background: #f0f0f0;
+ qproperty-hab_nub: #606060;
}
/*
-And this one is odd since we are assigning a colour to html richtext inside a QLabel.
+Clickable Links
+
+This one is odd since we are assigning a colour to html richtext inside a QLabel.
We hack it with hardcoded 'style' attribute in the html in python code.
*/
@@ -137,5 +191,5 @@ We hack it with hardcoded 'style' attribute in the html in python code.
QLabel#HydrusHyperlink
{
- qproperty-link_color: palette(link);
+ qproperty-link_color: palette(link);
}
diff --git a/static/qss/default_hydrus_dark.qss b/static/qss/default_hydrus_dark.qss
deleted file mode 100644
index 295d19d80..000000000
--- a/static/qss/default_hydrus_dark.qss
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
-Default QSS for hydrus. This is prepended to any stylesheet loaded in hydrus.
-Copying these entries in your own stylesheets should override these settings.
-This will get more work in future.
-*/
-
-/*
-
-Here are some text and background colours
-
-*/
-
-/* Example: This regex is valid */
-
-QLabel#HydrusValid
-{
- color: #2ed42e;
-}
-
-QLineEdit#HydrusValid, QTextEdit#HydrusValid, QPlainTextEdit#HydrusValid
-{
- background-color: #80ff80;
-}
-
-
-/* Duplicates 'middle' text colour */
-
-QLabel#HydrusIndeterminate
-{
- color: #8080ff;
-}
-
-QLineEdit#HydrusIndeterminate, QTextEdit#HydrusIndeterminate, QPlainTextEdit#HydrusIndeterminate
-{
- background-color: #8080ff;
-}
-
-
-/* Example: This regex is invalid */
-
-QLabel#HydrusInvalid
-{
- color: #ff7171;
-}
-
-QLineEdit#HydrusInvalid, QTextEdit#HydrusInvalid, QPlainTextEdit#HydrusInvalid
-{
- background-color: #ff8080;
-}
-
-
-/* Example: Your files are going to be deleted! */
-
-QLabel#HydrusWarning, QCheckBox#HydrusWarning
-{
- color: #ff7171;
-}
-
-/*
-
-Buttons on dialogs
-
-*/
-
-QPushButton#HydrusAccept
-{
- color: #2ed42e;
-}
-
-QPushButton#HydrusCancel
-{
- color: #ff7171;
-}
-
-/*
-
-This is the green/red button that switches 'include current tags' and similar states on/off
-
-*/
-
-QPushButton#HydrusOnOffButton[hydrus_on=true]
-{
- color: #2ed42e;
-}
-
-QPushButton#HydrusOnOffButton[hydrus_on=false]
-{
- color: #ff7171;
-}
-
-/*
-
-This is the Command Palette (default Ctrl+P), and specifically the background colour of the item you currently have selected.
-
-*/
-
-QLocatorResultWidget#selectedLocatorResult
-{
- background-color: palette(highlight);
-}
-
-QLocatorResultWidget QWidget
-{
- background: transparent;
-}
-
-
-/*
-
-Custom Controls
-
-These are drawn by hydev on a blank canvas, so they work a little different.
-
-*/
-
-/*
-
-The scanbar beneath video/audio in the media viewer.
-
-*/
-
-QWidget#HydrusAnimationBar
-{
- qproperty-hab_border: #000000;
- qproperty-hab_background: #606060;
- qproperty-hab_nub: #f0f0f0;
-}
-
-
-/*
-
-And this one is odd since we are assigning a colour to html richtext inside a QLabel.
-We hack it with hardcoded 'style' attribute in the html in python code.
-
-*/
-
-
-QLabel#HydrusHyperlink
-{
- qproperty-link_color: palette(link);
-}
diff --git a/static/qss/e621.qss b/static/qss/e621.qss
index 5fefdd45f..e17abec29 100644
--- a/static/qss/e621.qss
+++ b/static/qss/e621.qss
@@ -668,3 +668,51 @@ QLocatorResultWidget#selectedLocatorResult {
background: #2b538e;
border-bottom: 1px solid#2b538e;
}
+
+
+/*
+
+Here is more hydev added--now we have this tech, I am copying the default 'darkmode' colours in the options to all of the darkmode stylesheets so the default choice for new users isn't the dark/light jank-mix. Stylesheet authors are welcome to fix this up with better colours for their particular style and send them in.
+
+*/
+
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
+{
+ qproperty-hmrp_background: #343434;
+ qproperty-hmrp_thumbnail_local_background_normal: #404048;
+ qproperty-hmrp_thumbnail_local_border_normal: #91a3b0;
+ qproperty-hmrp_thumbnail_local_background_selected: #708090;
+ qproperty-hmrp_thumbnail_local_border_selected: #dfe3e6;
+ qproperty-hmrp_thumbnail_not_local_background_normal: #400d02;
+ qproperty-hmrp_thumbnail_not_local_border_normal: #f8d0cc;
+ qproperty-hmrp_thumbnail_not_local_background_selected: #ab274f;
+ qproperty-hmrp_thumbnail_not_local_border_selected: #e34234;
+}
+
+
+/* The media viewer. */
+
+QWidget#HydrusMediaViewer
+{
+ qproperty-hmv_background: #343434;
+ qproperty-hmv_text: #708090;
+}
+
+
+/* The tag autocomplete text input. */
+
+QWidget#HydrusTagAutocomplete
+{
+ qproperty-hta_background: #536267;
+}
+
+
+/* Tag lists across the program. */
+
+QWidget#HydrusTagList
+{
+ qproperty-htl_background: #232629;
+}
diff --git a/static/qss/readme.txt b/static/qss/readme.txt
index 354cb5360..5dcd49a23 100644
--- a/static/qss/readme.txt
+++ b/static/qss/readme.txt
@@ -2,9 +2,7 @@ Place a .css or .qss Qt StyleSheet file in here, and hydrus will provide it as a
Don't edit any of the files in here in place--they'll just be overwritten the next time you update. Copy to your own custom filenames if you want to edit anything.
-The default_hydrus.qss is used by the client to draw some custom widget colours. It is prepended to any custom stylesheet that is loaded, check it out for the class names you want want to override in your own custom QSS.
-
-This is still a bit of a test. I think to do this properly we'll want to move to folders so we can include additional assets like images.
+The default_hydrus.qss is used by the client to draw some custom widget colours. It is prepended to any custom stylesheet that is loaded, so check it out for the class names you want want to override in your own QSS.
Here's some examples, there are some QSS files buried here: