diff --git a/docs/changelog.md b/docs/changelog.md
index 6d9b9964..6b92dce5 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 f1917fee..cee65312 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 29d3ec93..aadfe73e 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 e2637a54..811bad7b 100644
--- a/hydrus/client/ClientOptions.py
+++ b/hydrus/client/ClientOptions.py
@@ -256,7 +256,8 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
'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 981f5e97..634d0250 100644
--- a/hydrus/client/db/ClientDB.py
+++ b/hydrus/client/db/ClientDB.py
@@ -1272,7 +1272,7 @@ class DB( HydrusDB.HydrusDB ):
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 @@ class DB( HydrusDB.HydrusDB ):
service_ids_to_nums_cleared = self.modules_files_storage.ClearLocalDeleteRecord()
- self._SyncCombinedDeletedFiles()
+ self._ResyncCombinedDeletedFiles()
else:
@@ -5810,7 +5810,7 @@ class DB( HydrusDB.HydrusDB ):
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 @@ class DB( HydrusDB.HydrusDB ):
+ 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 @@ class DB( HydrusDB.HydrusDB ):
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 @@ class DB( HydrusDB.HydrusDB ):
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 @@ class DB( HydrusDB.HydrusDB ):
+ 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 @@ class DB( HydrusDB.HydrusDB ):
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 @@ class DB( HydrusDB.HydrusDB ):
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 215fd1ce..ec01a602 100644
--- a/hydrus/client/db/ClientDBMappingsCounts.py
+++ b/hydrus/client/db/ClientDBMappingsCounts.py
@@ -399,7 +399,7 @@ class ClientDBMappingsCounts( ClientDBModule.ClientDBModule ):
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 5f1053bc..26bc3042 100644
--- a/hydrus/client/gui/ClientGUI.py
+++ b/hydrus/client/gui/ClientGUI.py
@@ -3233,10 +3233,14 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M
check_submenu = ClientGUIMenus.GenerateMenu( menu )
ClientGUIMenus.AppendMenuItem( check_submenu, 'database integrity' + HC.UNICODE_ELLIPSIS, 'Examine the database for file corruption.', self._CheckDBIntegrity )
- 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.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.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.AppendMenu( menu, check_submenu, 'check and repair' )
@@ -3256,7 +3260,6 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M
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 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M
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 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M
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 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
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 3794614b..3e06960e 100644
--- a/hydrus/client/gui/ClientGUIShortcutControls.py
+++ b/hydrus/client/gui/ClientGUIShortcutControls.py
@@ -248,7 +248,7 @@ class EditShortcutSetPanel( ClientGUIScrolledPanels.EditPanel ):
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 dea6d498..f38074c8 100644
--- a/hydrus/client/gui/ClientGUIShortcuts.py
+++ b/hydrus/client/gui/ClientGUIShortcuts.py
@@ -1343,7 +1343,7 @@ class ShortcutSet( HydrusSerialisable.SerialisableBaseNamed ):
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 a06f9e13..1185c76c 100644
--- a/hydrus/client/gui/ClientGUIStringControls.py
+++ b/hydrus/client/gui/ClientGUIStringControls.py
@@ -137,6 +137,8 @@ class StringMatchButton( ClientGUICommon.BetterButton ):
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 @@ class StringProcessorButton( ClientGUICommon.BetterButton ):
self._UpdateLabel()
+ self.valueChanged.emit()
+
diff --git a/hydrus/client/gui/ClientGUISubscriptions.py b/hydrus/client/gui/ClientGUISubscriptions.py
index 104da528..426cee99 100644
--- a/hydrus/client/gui/ClientGUISubscriptions.py
+++ b/hydrus/client/gui/ClientGUISubscriptions.py
@@ -926,8 +926,10 @@ class EditSubscriptionPanel( ClientGUIScrolledPanels.EditPanel ):
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 2d93bf35..c22b9bb8 100644
--- a/hydrus/client/gui/ClientGUITags.py
+++ b/hydrus/client/gui/ClientGUITags.py
@@ -1431,6 +1431,20 @@ class EditTagFilterPanel( ClientGUIScrolledPanels.EditPanel ):
+ 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 fe9c0f3d..4439e1b5 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 @@ class CanvasBackgroundColourGenerator( object ):
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 @@ class CanvasBackgroundColourGeneratorDuplicates( CanvasBackgroundColourGenerator
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 @@ class Canvas( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
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 @@ class Canvas( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
+ 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 @@ class CanvasWithDetails( Canvas ):
# 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 @@ class CanvasWithDetails( Canvas ):
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 7365385a..4433e8d3 100644
--- a/hydrus/client/gui/canvas/ClientGUICanvasMedia.py
+++ b/hydrus/client/gui/canvas/ClientGUICanvasMedia.py
@@ -879,7 +879,7 @@ class AnimationBar( QW.QWidget ):
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 @@ class AnimationBar( QW.QWidget ):
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 @@ class AnimationBar( QW.QWidget ):
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 @@ class AnimationBar( QW.QWidget ):
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 @@ class AnimationBar( QW.QWidget ):
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 @@ class AnimationBar( QW.QWidget ):
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 79fb6be5..3c9f8f7d 100644
--- a/hydrus/client/gui/exporting/ClientGUIExport.py
+++ b/hydrus/client/gui/exporting/ClientGUIExport.py
@@ -21,6 +21,7 @@ from hydrus.client import ClientGlobals as CG
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 ClientGUIListBoxes
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 @@ class EditExportFolderPanel( ClientGUIScrolledPanels.EditPanel ):
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 @@ If you select synchronise, be careful!'''
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 @@ If you select synchronise, be careful!'''
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 @@ If you select synchronise, be careful!'''
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 @@ class ReviewExportFilesPanel( ClientGUIScrolledPanels.ReviewPanel ):
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 @@ class ReviewExportFilesPanel( ClientGUIScrolledPanels.ReviewPanel ):
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 bff7a628..dbb676ca 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 ClientGUIListBoxes
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 @@ class EditLocalImportFilenameTaggingPanel( ClientGUIScrolledPanels.EditPanel ):
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 d4961e2b..d931913b 100644
--- a/hydrus/client/gui/importing/ClientGUIImportFolders.py
+++ b/hydrus/client/gui/importing/ClientGUIImportFolders.py
@@ -20,6 +20,7 @@ from hydrus.client.gui.importing import ClientGUIImportOptions
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 @@ class EditImportFolderPanel( ClientGUIScrolledPanels.EditPanel ):
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 @@ class EditImportFolderPanel( ClientGUIScrolledPanels.EditPanel ):
self._UpdateCheckRegularly()
+ self._path.dirPickerChanged.connect( self._PathChanged )
+
+ self._PathChanged()
+
def _AddFilenameTaggingOptions( self ):
@@ -601,6 +606,27 @@ class EditImportFolderPanel( ClientGUIScrolledPanels.EditPanel ):
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 7fded847..38785cfb 100644
--- a/hydrus/client/gui/lists/ClientGUIListBoxes.py
+++ b/hydrus/client/gui/lists/ClientGUIListBoxes.py
@@ -1070,8 +1070,6 @@ class ListBox( QW.QScrollArea ):
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 @@ class ListBox( QW.QScrollArea ):
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 @@ class ListBox( QW.QScrollArea ):
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 @@ class ListBox( QW.QScrollArea ):
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 @@ class ListBoxTags( ListBox ):
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 @@ class ListBoxTags( ListBox ):
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 @@ class ListBoxTags( ListBox ):
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 @@ class ListBoxTags( ListBox ):
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 b1e785df..0be775e6 100644
--- a/hydrus/client/gui/lists/ClientGUIListConstants.py
+++ b/hydrus/client/gui/lists/ClientGUIListConstants.py
@@ -1565,3 +1565,20 @@ register_column_type( COLUMN_LIST_DEFERRED_DELETE_TABLE_DATA.ID, COLUMN_LIST_DEF
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 06372748..2f61076f 100644
--- a/hydrus/client/gui/metadata/ClientGUIMetadataMigration.py
+++ b/hydrus/client/gui/metadata/ClientGUIMetadataMigration.py
@@ -16,8 +16,11 @@ from hydrus.client.gui import ClientGUIStringControls
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 @@ from hydrus.client.metadata import ClientMetadataMigrationExporters
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 @@ class EditSingleFileMetadataRouterPanel( ClientGUIScrolledPanels.EditPanel ):
#
+ 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 @@ class EditSingleFileMetadataRouterPanel( ClientGUIScrolledPanels.EditPanel ):
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 @@ class SingleFileMetadataRoutersControl( ClientGUIListBoxes.AddEditDeleteListBox
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 @@ class SingleFileMetadataRoutersButton( QW.QPushButton ):
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 00000000..939b42b7
--- /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 bd22fd77..e5b09fcd 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 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
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 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
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 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
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 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
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 @@ class MediaPanelThumbnails( MediaPanel ):
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 @@ class MediaPanelThumbnails( MediaPanel ):
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 @@ class MediaPanelThumbnails( MediaPanel ):
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 @@ class MediaPanelThumbnails( MediaPanel ):
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 @@ class Thumbnail( Selectable ):
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 @@ class Thumbnail( Selectable ):
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 @@ class Thumbnail( Selectable ):
# _ .___//_/ /_/|_| \___//_/ /____/ _\__, / \____/ \__/ \____/ /_/ /_/\___//_/ /_/ (_)
# /_/ /____/
- 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 7a22b591..8e1827e4 100644
--- a/hydrus/client/gui/panels/ClientGUIScrolledPanelsManagement.py
+++ b/hydrus/client/gui/panels/ClientGUIScrolledPanelsManagement.py
@@ -198,24 +198,26 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
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 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
#
- 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 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
#
- 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 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
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 87598539..fc88b130 100644
--- a/hydrus/client/gui/search/ClientGUIACDropdown.py
+++ b/hydrus/client/gui/search/ClientGUIACDropdown.py
@@ -4,6 +4,7 @@ import os
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 @@ class AutoCompleteDropdown( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
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 @@ class AutoCompleteDropdown( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
# 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 @@ class AutoCompleteDropdown( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
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 @@ class AutoCompleteDropdown( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
+ 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 @@ class AutoCompleteDropdown( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
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 @@ class ListBoxTagsActiveSearchPredicates( ClientGUIListBoxes.ListBoxTagsPredicate
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 @@ class ListBoxTagsActiveSearchPredicates( ClientGUIListBoxes.ListBoxTagsPredicate
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 @@ class ListBoxTagsActiveSearchPredicates( ClientGUIListBoxes.ListBoxTagsPredicate
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 d6523f07..3d45d672 100644
--- a/hydrus/client/gui/services/ClientGUIModalClientsideServiceActions.py
+++ b/hydrus/client/gui/services/ClientGUIModalClientsideServiceActions.py
@@ -73,6 +73,8 @@ class ReviewPurgeTagsPanel( ClientGUIScrolledPanels.ReviewPanel ):
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 a82d9522..d2ad1c01 100644
--- a/hydrus/client/importing/ClientImportLocal.py
+++ b/hydrus/client/importing/ClientImportLocal.py
@@ -1346,7 +1346,10 @@ class ImportFoldersManager( object ):
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 @@ class ImportFoldersManager( object ):
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 aa0dd971..9a4c1894 100644
--- a/hydrus/client/media/ClientMedia.py
+++ b/hydrus/client/media/ClientMedia.py
@@ -1324,16 +1324,16 @@ class MediaList( object ):
def Sort( self, media_sort = None ):
- for media in self._collected_media:
-
- media.Sort( media_sort )
-
-
if media_sort is None:
media_sort = self._media_sort
+ for media in self._collected_media:
+
+ media.Sort( media_sort )
+
+
self._media_sort = media_sort
media_sort_fallback = CG.client_controller.new_options.GetFallbackSort()
diff --git a/hydrus/client/search/ClientSearchAutocomplete.py b/hydrus/client/search/ClientSearchAutocomplete.py
index 7a2577b6..a24570e4 100644
--- a/hydrus/client/search/ClientSearchAutocomplete.py
+++ b/hydrus/client/search/ClientSearchAutocomplete.py
@@ -167,8 +167,7 @@ class ParsedAutocompleteText( object ):
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 @@ class ParsedAutocompleteText( object ):
allow_unnamespaced_search_gives_any_namespace_wildcards_values.append( False )
+ allow_unnamespaced_search_gives_any_namespace_wildcards_values.append( True )
+
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 ) )
-
-
-
- for s in list( search_texts ):
-
- 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 798cf059..7f050854 100644
--- a/hydrus/core/HydrusConstants.py
+++ b/hydrus/core/HydrusConstants.py
@@ -105,7 +105,7 @@ options = {}
# 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 4a621e03..a1c1ed61 100644
--- a/hydrus/test/TestClientTags.py
+++ b/hydrus/test/TestClientTags.py
@@ -520,7 +520,7 @@ class TestTagObjects( unittest.TestCase ):
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 @@ class TestTagObjects( unittest.TestCase ):
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 @@ class TestTagObjects( unittest.TestCase ):
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 @@ class TestTagObjects( unittest.TestCase ):
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 @@ class TestTagObjects( unittest.TestCase ):
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 5b935769..54a7023b 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 bd966111..0b947f59 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 3ed9ecc7..ed9cf119 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 37a88c12..3fb7ba4c 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 4a259b26..d631ef55 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 295e0431..89c8eb1d 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 542af2ac..ff6547be 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 64463ea1..997faa03 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 db58f60c..0d8d1d14 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 a85e928c..23b472d8 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 8c2f8319..b1a44ec1 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 00000000..b745da6d
--- /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 84cea1f6..ec9fc01e 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.
*/
-QWidget#HydrusAnimationBar
+
+/* The main thumbnail grid. */
+
+QWidget#HydrusMediaList
{
- qproperty-hab_border: #000000;
- qproperty-hab_background: #f0f0f0;
- qproperty-hab_nub: #606060;
+ 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;
}
/*
-And this one is odd since we are assigning a colour to html richtext inside a QLabel.
+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;
+}
+
+
+/*
+
+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 295d19d8..00000000
--- 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 5fefdd45..e17abec2 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 354cb536..5dcd49a2 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: