From a290d77a41b40ac89235e48bb9f1521fc041bc6c Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 13 Sep 2021 11:18:25 +0100 Subject: [PATCH 01/86] Fixed Unreal support for templates --- .../unreal/hooks/pre_workfile_preparation.py | 50 ++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index 01b8b6bc05..0c7146634f 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -6,7 +6,9 @@ from pathlib import Path from openpype.lib import ( PreLaunchHook, ApplicationLaunchFailed, - ApplicationNotFound + ApplicationNotFound, + get_workdir_data, + get_workfile_template_key ) from openpype.hosts.unreal.api import lib as unreal_lib @@ -25,13 +27,45 @@ class UnrealPrelaunchHook(PreLaunchHook): self.signature = "( {} )".format(self.__class__.__name__) + def _get_work_filename(self): + # Use last workfile if was found + last_workfile = self.data.get("last_workfile_path") + if last_workfile and os.path.exists(last_workfile): + return os.path.basename(last_workfile) + + # Prepare data for fill data and for getting workfile template key + task_name = self.data["task_name"] + anatomy = self.data["anatomy"] + asset_doc = self.data["asset_doc"] + project_doc = self.data["project_doc"] + + asset_tasks = asset_doc.get("data", {}).get("tasks") or {} + task_info = asset_tasks.get(task_name) or {} + task_type = task_info.get("type") + + workdir_data = get_workdir_data( + project_doc, asset_doc, task_name, self.host_name + ) + # QUESTION raise exception if version is part of filename template? + workdir_data["version"] = 1 + workdir_data["ext"] = "uproject" + + # Get workfile template key for current context + workfile_template_key = get_workfile_template_key( + task_type, + self.host_name, + project_name=project_doc["name"] + ) + # Fill templates + filled_anatomy = anatomy.format(workdir_data) + + # Return filename + return filled_anatomy[workfile_template_key]["file"] + def execute(self): """Hook entry method.""" - asset_name = self.data["asset_name"] - task_name = self.data["task_name"] workdir = self.launch_context.env["AVALON_WORKDIR"] engine_version = self.app_name.split("/")[-1].replace("-", ".") - unreal_project_name = f"{asset_name}_{task_name}" try: if int(engine_version.split(".")[0]) < 4 and \ int(engine_version.split(".")[1]) < 26: @@ -45,6 +79,8 @@ class UnrealPrelaunchHook(PreLaunchHook): # so lets keep it quite. ... + unreal_project_filename = self._get_work_filename() + unreal_project_name = os.path.splitext(unreal_project_filename)[0] # Unreal is sensitive about project names longer then 20 chars if len(unreal_project_name) > 20: self.log.warning(( @@ -55,7 +91,7 @@ class UnrealPrelaunchHook(PreLaunchHook): # of the project name. This is because project name is then used # in various places inside c++ code and there variable names cannot # start with non-alpha. We append 'P' before project name to solve it. - # 😱 + # 😱 if not unreal_project_name[:1].isalpha(): self.log.warning(( "Project name doesn't start with alphabet " @@ -89,10 +125,10 @@ class UnrealPrelaunchHook(PreLaunchHook): ue4_path = unreal_lib.get_editor_executable_path( Path(detected[engine_version])) - self.launch_context.launch_args.append(ue4_path.as_posix()) + self.launch_context.launch_args = [ue4_path.as_posix()] project_path.mkdir(parents=True, exist_ok=True) - project_file = project_path / f"{unreal_project_name}.uproject" + project_file = project_path / unreal_project_filename if not project_file.is_file(): engine_path = detected[engine_version] self.log.info(( From 39c9df52b818938bf02f38c35277cf4dec92ab34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Sep 2021 12:28:52 +0000 Subject: [PATCH 02/86] Bump axios from 0.21.1 to 0.21.4 in /website Bumps [axios](https://github.com/axios/axios) from 0.21.1 to 0.21.4. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.21.1...v0.21.4) --- updated-dependencies: - dependency-name: axios dependency-type: indirect ... Signed-off-by: dependabot[bot] --- website/yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/website/yarn.lock b/website/yarn.lock index 066d156d97..ae40005384 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2175,11 +2175,11 @@ autoprefixer@^10.0.2, autoprefixer@^10.2.5: postcss-value-parser "^4.1.0" axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.0" babel-loader@^8.2.2: version "8.2.2" @@ -3982,10 +3982,10 @@ flux@^4.0.1: fbemitter "^3.0.0" fbjs "^3.0.0" -follow-redirects@^1.0.0, follow-redirects@^1.10.0: - version "1.13.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" - integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA== +follow-redirects@^1.0.0, follow-redirects@^1.14.0: + version "1.14.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" + integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== for-in@^1.0.2: version "1.0.2" From c1eeee9fdc81a255f84dd98338d90ea818e2ec77 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 23 Sep 2021 16:49:51 +0100 Subject: [PATCH 03/86] Apply suggestions from code review --- openpype/hosts/unreal/hooks/pre_workfile_preparation.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index 0c7146634f..880dba5cfb 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -29,9 +29,10 @@ class UnrealPrelaunchHook(PreLaunchHook): def _get_work_filename(self): # Use last workfile if was found - last_workfile = self.data.get("last_workfile_path") - if last_workfile and os.path.exists(last_workfile): - return os.path.basename(last_workfile) + if self.data.get("last_workfile_path"): + last_workfile = Path(self.data.get("last_workfile_path")) + if last_workfile and last_workfile.exists(): + return last_workfile.name # Prepare data for fill data and for getting workfile template key task_name = self.data["task_name"] @@ -91,7 +92,7 @@ class UnrealPrelaunchHook(PreLaunchHook): # of the project name. This is because project name is then used # in various places inside c++ code and there variable names cannot # start with non-alpha. We append 'P' before project name to solve it. - # 😱 + # 😱 if not unreal_project_name[:1].isalpha(): self.log.warning(( "Project name doesn't start with alphabet " From 6621b2c36e6d897b35421a7005857cbf51df053f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 15 Oct 2021 15:00:44 +0200 Subject: [PATCH 04/86] OP-1063 - added validator for source files for Standalone Publisher --- .../plugins/publish/validate_sources.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py new file mode 100644 index 0000000000..da424cfb45 --- /dev/null +++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py @@ -0,0 +1,37 @@ +import pyblish.api +import openpype.api + +import os + + +class ValidateSources(pyblish.api.InstancePlugin): + """Validates source files. + + Loops through all 'files' in 'stagingDir' if actually exist. They might + got deleted between starting of SP and now. + + """ + + order = openpype.api.ValidateContentsOrder + label = "Check source files" + + optional = True # only for unforeseeable cases + + hosts = ["standalonepublisher"] + + def process(self, instance): + self.log.info("instance {}".format(instance.data)) + + for repr in instance.data["representations"]: + files = [] + if isinstance(repr["files"], str): + files.append(repr["files"]) + else: + files = list(repr["files"]) + + for file_name in files: + source_file = os.path.join(repr["stagingDir"], + file_name) + + if not os.path.exists(source_file): + raise ValueError("File {} not found".format(source_file)) From 9eaa0a5a380550203e55aaed36f9ed96ecf2946e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 15 Oct 2021 18:58:37 +0200 Subject: [PATCH 05/86] pass parenting of widget properly in main window --- openpype/tools/loader/app.py | 96 ++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index c18b6e798a..e7a7d2c7ad 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -54,61 +54,72 @@ class LoaderWindow(QtWidgets.QDialog): self.setWindowFlags(QtCore.Qt.Window) self.setFocusPolicy(QtCore.Qt.StrongFocus) - body = QtWidgets.QWidget() - footer = QtWidgets.QWidget() - footer.setFixedHeight(20) + split = QtWidgets.QSplitter(self) - container = QtWidgets.QWidget() + asset_filter_splitter = QtWidgets.QSplitter(split) + asset_filter_splitter.setOrientation(QtCore.Qt.Vertical) - assets = AssetWidget(io, multiselection=True, parent=self) + # --- Left part --- + # Assets widget + assets = AssetWidget( + io, multiselection=True, parent=asset_filter_splitter + ) assets.set_current_asset_btn_visibility(True) - families = FamilyListView(io, self.family_config_cache, self) - subsets = SubsetWidget( - io, - self.groups_config, - self.family_config_cache, - tool_name=self.tool_name, - parent=self + # Families widget + families = FamilyListView( + io, self.family_config_cache, asset_filter_splitter ) - version = VersionWidget(io) - thumbnail = ThumbnailWidget(io) - representations = RepresentationWidget(io, self.tool_name) - - manager = ModulesManager() - sync_server = manager.modules_by_name["sync_server"] - - thumb_ver_splitter = QtWidgets.QSplitter() - thumb_ver_splitter.setOrientation(QtCore.Qt.Vertical) - thumb_ver_splitter.addWidget(thumbnail) - thumb_ver_splitter.addWidget(version) - if sync_server.enabled: - thumb_ver_splitter.addWidget(representations) - thumb_ver_splitter.setStretchFactor(0, 30) - thumb_ver_splitter.setStretchFactor(1, 35) - - # Create splitter to show / hide family filters - asset_filter_splitter = QtWidgets.QSplitter() - asset_filter_splitter.setOrientation(QtCore.Qt.Vertical) asset_filter_splitter.addWidget(assets) asset_filter_splitter.addWidget(families) asset_filter_splitter.setStretchFactor(0, 65) asset_filter_splitter.setStretchFactor(1, 35) - container_layout = QtWidgets.QHBoxLayout(container) - container_layout.setContentsMargins(0, 0, 0, 0) - split = QtWidgets.QSplitter() + # --- Middle part --- + # Subsets widget + subsets = SubsetWidget( + io, + self.groups_config, + self.family_config_cache, + tool_name=self.tool_name, + parent=split + ) + + # --- Right part --- + thumb_ver_splitter = QtWidgets.QSplitter(split) + thumb_ver_splitter.setOrientation(QtCore.Qt.Vertical) + version = VersionWidget(io, parent=thumb_ver_splitter) + thumbnail = ThumbnailWidget(io, parent=thumb_ver_splitter) + + manager = ModulesManager() + sync_server = manager.modules_by_name.get("sync_server") + sync_server_enabled = False + if sync_server is not None: + sync_server_enabled = sync_server.enabled + + thumb_ver_splitter.addWidget(thumbnail) + thumb_ver_splitter.addWidget(version) + + representations = None + if sync_server_enabled: + representations = RepresentationWidget( + io, self.tool_name, parent=thumb_ver_splitter + ) + thumb_ver_splitter.addWidget(representations) + + thumb_ver_splitter.setStretchFactor(0, 30) + thumb_ver_splitter.setStretchFactor(1, 35) + split.addWidget(asset_filter_splitter) split.addWidget(subsets) split.addWidget(thumb_ver_splitter) - container_layout.addWidget(split) + # TODO keep footer size by message size + footer = QtWidgets.QWidget(self) + footer.setFixedHeight(20) - body_layout = QtWidgets.QHBoxLayout(body) - body_layout.addWidget(container) - body_layout.setContentsMargins(0, 0, 0, 0) - - message = QtWidgets.QLabel() + # TODO Don't hide messsage just set label to empty string + message = QtWidgets.QLabel(footer) message.hide() footer_layout = QtWidgets.QVBoxLayout(footer) @@ -116,7 +127,7 @@ class LoaderWindow(QtWidgets.QDialog): footer_layout.setContentsMargins(0, 0, 0, 0) layout = QtWidgets.QVBoxLayout(self) - layout.addWidget(body) + layout.addWidget(split) layout.addWidget(footer) self.data = { @@ -152,6 +163,7 @@ class LoaderWindow(QtWidgets.QDialog): representations.load_started.connect(self._on_load_start) representations.load_ended.connect(self._on_load_end) + # TODO add overlay using stack widget self._overlay_frame = overlay_frame self.family_config_cache.refresh() @@ -161,7 +173,7 @@ class LoaderWindow(QtWidgets.QDialog): self._assetschanged() # Defaults - if sync_server.enabled: + if sync_server_enabled: split.setSizes([250, 1000, 550]) self.resize(1800, 900) else: From 514e49ff239927128b298e054af8ed58328e60b3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 15 Oct 2021 19:07:28 +0200 Subject: [PATCH 06/86] simplified message showing without scheduler --- openpype/tools/loader/app.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index e7a7d2c7ad..a7f66bdccb 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -37,6 +37,7 @@ class LoaderWindow(QtWidgets.QDialog): """Asset loader interface""" tool_name = "loader" + message_timeout = 5000 def __init__(self, parent=None): super(LoaderWindow, self).__init__(parent) @@ -118,12 +119,10 @@ class LoaderWindow(QtWidgets.QDialog): footer = QtWidgets.QWidget(self) footer.setFixedHeight(20) - # TODO Don't hide messsage just set label to empty string - message = QtWidgets.QLabel(footer) - message.hide() + message_label = QtWidgets.QLabel(footer) footer_layout = QtWidgets.QVBoxLayout(footer) - footer_layout.addWidget(message) + footer_layout.addWidget(message_label) footer_layout.setContentsMargins(0, 0, 0, 0) layout = QtWidgets.QVBoxLayout(self) @@ -139,9 +138,6 @@ class LoaderWindow(QtWidgets.QDialog): "thumbnail": thumbnail, "representations": representations }, - "label": { - "message": message, - }, "state": { "assetIds": None } @@ -150,6 +146,12 @@ class LoaderWindow(QtWidgets.QDialog): overlay_frame = OverlayFrame("Loading...", self) overlay_frame.setVisible(False) + message_timer = QtCore.QTimer() + message_timer.setInterval(self.message_timeout) + message_timer.setSingleShot(True) + + message_timer.timeout.connect(self._on_message_timeout) + families.active_changed.connect(subsets.set_family_filters) assets.selection_changed.connect(self.on_assetschanged) assets.refresh_triggered.connect(self.on_assetschanged) @@ -164,7 +166,10 @@ class LoaderWindow(QtWidgets.QDialog): representations.load_ended.connect(self._on_load_end) # TODO add overlay using stack widget + self._message_label = message_label + self._overlay_frame = overlay_frame + self._message_timer = message_timer self.family_config_cache.refresh() self.groups_config.refresh() @@ -450,13 +455,13 @@ class LoaderWindow(QtWidgets.QDialog): asset_widget = self.data["widgets"]["assets"] asset_widget.select_assets(asset) - def echo(self, message): - widget = self.data["label"]["message"] - widget.setText(str(message)) - widget.show() - print(message) + def _on_message_timeout(self): + self._message_label.setText("") - lib.schedule(widget.hide, 5000, channel="message") + def echo(self, message): + self._message_label.setText(str(message)) + print(message) + self._message_timer.start() def closeEvent(self, event): # Kill on holding SHIFT From 893ae73437d11dbce05428a9cdf6afa7507a706c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 15 Oct 2021 19:13:51 +0200 Subject: [PATCH 07/86] fix repres widget --- openpype/tools/loader/app.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index a7f66bdccb..1b316c9223 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -101,12 +101,12 @@ class LoaderWindow(QtWidgets.QDialog): thumb_ver_splitter.addWidget(thumbnail) thumb_ver_splitter.addWidget(version) - representations = None + repres_widget = None if sync_server_enabled: - representations = RepresentationWidget( + repres_widget = RepresentationWidget( io, self.tool_name, parent=thumb_ver_splitter ) - thumb_ver_splitter.addWidget(representations) + thumb_ver_splitter.addWidget(repres_widget) thumb_ver_splitter.setStretchFactor(0, 30) thumb_ver_splitter.setStretchFactor(1, 35) @@ -136,7 +136,6 @@ class LoaderWindow(QtWidgets.QDialog): "subsets": subsets, "version": version, "thumbnail": thumbnail, - "representations": representations }, "state": { "assetIds": None @@ -162,12 +161,14 @@ class LoaderWindow(QtWidgets.QDialog): subsets.load_started.connect(self._on_load_start) subsets.load_ended.connect(self._on_load_end) - representations.load_started.connect(self._on_load_start) - representations.load_ended.connect(self._on_load_end) + repres_widget.load_started.connect(self._on_load_start) + repres_widget.load_ended.connect(self._on_load_end) # TODO add overlay using stack widget self._message_label = message_label + self._repres_widget = repres_widget + self._overlay_frame = overlay_frame self._message_timer = message_timer @@ -321,9 +322,9 @@ class LoaderWindow(QtWidgets.QDialog): self.data["state"]["assetIds"] = asset_ids - representations = self.data["widgets"]["representations"] # reset repre list - representations.set_version_ids([]) + if self._repres_widget is not None: + self._repres_widget.set_version_ids([]) def _subsetschanged(self): asset_ids = self.data["state"]["assetIds"] @@ -414,12 +415,14 @@ class LoaderWindow(QtWidgets.QDialog): self.data["widgets"]["thumbnail"].set_thumbnail(thumbnail_docs) - representations = self.data["widgets"]["representations"] - version_ids = [doc["_id"] for doc in version_docs or []] - representations.set_version_ids(version_ids) + if self._repres_widget is not None: + version_ids = [doc["_id"] for doc in version_docs or []] + self._repres_widget.set_version_ids(version_ids) - # representations.change_visibility("subset", len(rows) > 1) - # representations.change_visibility("asset", len(asset_docs) > 1) + # self._repres_widget.change_visibility("subset", len(rows) > 1) + # self._repres_widget.change_visibility( + # "asset", len(asset_docs) > 1 + # ) def _set_context(self, context, refresh=True): """Set the selection in the interface using a context. From 6d49ebf3a85ef169bedf764e59b5915f10436ac4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 15 Oct 2021 19:16:16 +0200 Subject: [PATCH 08/86] change split to main_splitter --- openpype/tools/loader/app.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 1b316c9223..ea28304134 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -55,9 +55,9 @@ class LoaderWindow(QtWidgets.QDialog): self.setWindowFlags(QtCore.Qt.Window) self.setFocusPolicy(QtCore.Qt.StrongFocus) - split = QtWidgets.QSplitter(self) + main_splitter = QtWidgets.QSplitter(self) - asset_filter_splitter = QtWidgets.QSplitter(split) + asset_filter_splitter = QtWidgets.QSplitter(main_splitter) asset_filter_splitter.setOrientation(QtCore.Qt.Vertical) # --- Left part --- @@ -83,11 +83,11 @@ class LoaderWindow(QtWidgets.QDialog): self.groups_config, self.family_config_cache, tool_name=self.tool_name, - parent=split + parent=main_splitter ) # --- Right part --- - thumb_ver_splitter = QtWidgets.QSplitter(split) + thumb_ver_splitter = QtWidgets.QSplitter(main_splitter) thumb_ver_splitter.setOrientation(QtCore.Qt.Vertical) version = VersionWidget(io, parent=thumb_ver_splitter) thumbnail = ThumbnailWidget(io, parent=thumb_ver_splitter) @@ -111,9 +111,9 @@ class LoaderWindow(QtWidgets.QDialog): thumb_ver_splitter.setStretchFactor(0, 30) thumb_ver_splitter.setStretchFactor(1, 35) - split.addWidget(asset_filter_splitter) - split.addWidget(subsets) - split.addWidget(thumb_ver_splitter) + main_splitter.addWidget(asset_filter_splitter) + main_splitter.addWidget(subsets) + main_splitter.addWidget(thumb_ver_splitter) # TODO keep footer size by message size footer = QtWidgets.QWidget(self) @@ -126,7 +126,7 @@ class LoaderWindow(QtWidgets.QDialog): footer_layout.setContentsMargins(0, 0, 0, 0) layout = QtWidgets.QVBoxLayout(self) - layout.addWidget(split) + layout.addWidget(main_splitter) layout.addWidget(footer) self.data = { @@ -180,10 +180,10 @@ class LoaderWindow(QtWidgets.QDialog): # Defaults if sync_server_enabled: - split.setSizes([250, 1000, 550]) + main_splitter.setSizes([250, 1000, 550]) self.resize(1800, 900) else: - split.setSizes([250, 850, 200]) + main_splitter.setSizes([250, 850, 200]) self.resize(1300, 700) def resizeEvent(self, event): From 98a6225e5ffbba710d829b95ee2dd3cb2ca0c1e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 15 Oct 2021 19:17:04 +0200 Subject: [PATCH 09/86] renamed 'footer' to 'footer_widget' --- openpype/tools/loader/app.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index ea28304134..9569c87e35 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -116,18 +116,18 @@ class LoaderWindow(QtWidgets.QDialog): main_splitter.addWidget(thumb_ver_splitter) # TODO keep footer size by message size - footer = QtWidgets.QWidget(self) - footer.setFixedHeight(20) + footer_widget = QtWidgets.QWidget(self) + footer_widget.setFixedHeight(20) - message_label = QtWidgets.QLabel(footer) + message_label = QtWidgets.QLabel(footer_widget) - footer_layout = QtWidgets.QVBoxLayout(footer) - footer_layout.addWidget(message_label) + footer_layout = QtWidgets.QVBoxLayout(footer_widget) footer_layout.setContentsMargins(0, 0, 0, 0) + footer_layout.addWidget(message_label) layout = QtWidgets.QVBoxLayout(self) layout.addWidget(main_splitter) - layout.addWidget(footer) + layout.addWidget(footer_widget) self.data = { "widgets": { From e144e3d9fd8b1cad9ac6c18ae4faf3169c0a9d58 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 10:03:47 +0200 Subject: [PATCH 10/86] renamed version info widget and do not store it into data --- openpype/tools/loader/app.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 9569c87e35..0ec5a50f31 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -89,7 +89,8 @@ class LoaderWindow(QtWidgets.QDialog): # --- Right part --- thumb_ver_splitter = QtWidgets.QSplitter(main_splitter) thumb_ver_splitter.setOrientation(QtCore.Qt.Vertical) - version = VersionWidget(io, parent=thumb_ver_splitter) + + version_info_widget = VersionWidget(io, parent=thumb_ver_splitter) thumbnail = ThumbnailWidget(io, parent=thumb_ver_splitter) manager = ModulesManager() @@ -99,7 +100,7 @@ class LoaderWindow(QtWidgets.QDialog): sync_server_enabled = sync_server.enabled thumb_ver_splitter.addWidget(thumbnail) - thumb_ver_splitter.addWidget(version) + thumb_ver_splitter.addWidget(version_info_widget) repres_widget = None if sync_server_enabled: @@ -134,8 +135,7 @@ class LoaderWindow(QtWidgets.QDialog): "families": families, "assets": assets, "subsets": subsets, - "version": version, - "thumbnail": thumbnail, + "thumbnail": thumbnail }, "state": { "assetIds": None @@ -167,6 +167,7 @@ class LoaderWindow(QtWidgets.QDialog): # TODO add overlay using stack widget self._message_label = message_label + self._version_info_widget = version_info_widget self._repres_widget = repres_widget self._overlay_frame = overlay_frame @@ -317,7 +318,7 @@ class LoaderWindow(QtWidgets.QDialog): ) # Clear the version information on asset change - self.data["widgets"]["version"].set_version(None) + self._version_info_widget.set_version(None) self.data["widgets"]["thumbnail"].set_thumbnail(asset_docs) self.data["state"]["assetIds"] = asset_ids @@ -404,7 +405,7 @@ class LoaderWindow(QtWidgets.QDialog): else: version_docs.append(item["version_document"]) - self.data["widgets"]["version"].set_version(version_doc) + self._version_info_widget.set_version(version_doc) thumbnail_docs = version_docs assets_widget = self.data["widgets"]["assets"] From c90cf1765c04719c306ef8894eb4f545a8cb7d32 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 10:06:05 +0200 Subject: [PATCH 11/86] renamed thumbnail widget and do not store it into data --- openpype/tools/loader/app.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 0ec5a50f31..43e3750428 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -90,8 +90,8 @@ class LoaderWindow(QtWidgets.QDialog): thumb_ver_splitter = QtWidgets.QSplitter(main_splitter) thumb_ver_splitter.setOrientation(QtCore.Qt.Vertical) + thumbnail_widget = ThumbnailWidget(io, parent=thumb_ver_splitter) version_info_widget = VersionWidget(io, parent=thumb_ver_splitter) - thumbnail = ThumbnailWidget(io, parent=thumb_ver_splitter) manager = ModulesManager() sync_server = manager.modules_by_name.get("sync_server") @@ -99,7 +99,7 @@ class LoaderWindow(QtWidgets.QDialog): if sync_server is not None: sync_server_enabled = sync_server.enabled - thumb_ver_splitter.addWidget(thumbnail) + thumb_ver_splitter.addWidget(thumbnail_widget) thumb_ver_splitter.addWidget(version_info_widget) repres_widget = None @@ -134,8 +134,7 @@ class LoaderWindow(QtWidgets.QDialog): "widgets": { "families": families, "assets": assets, - "subsets": subsets, - "thumbnail": thumbnail + "subsets": subsets }, "state": { "assetIds": None @@ -168,6 +167,7 @@ class LoaderWindow(QtWidgets.QDialog): self._message_label = message_label self._version_info_widget = version_info_widget + self._thumbnail_widget = thumbnail_widget self._repres_widget = repres_widget self._overlay_frame = overlay_frame @@ -318,8 +318,8 @@ class LoaderWindow(QtWidgets.QDialog): ) # Clear the version information on asset change + self._thumbnail_widget.set_thumbnail(asset_docs) self._version_info_widget.set_version(None) - self.data["widgets"]["thumbnail"].set_thumbnail(asset_docs) self.data["state"]["assetIds"] = asset_ids @@ -414,7 +414,7 @@ class LoaderWindow(QtWidgets.QDialog): if len(asset_docs) > 0: thumbnail_docs = asset_docs - self.data["widgets"]["thumbnail"].set_thumbnail(thumbnail_docs) + self._thumbnail_widget.set_thumbnail(thumbnail_docs) if self._repres_widget is not None: version_ids = [doc["_id"] for doc in version_docs or []] From a85c93cc0fa599441e8eee0e3276029469be3a31 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 10:12:18 +0200 Subject: [PATCH 12/86] rename families filter view and do not store it into data --- openpype/tools/loader/app.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 43e3750428..f10348eced 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -68,11 +68,11 @@ class LoaderWindow(QtWidgets.QDialog): assets.set_current_asset_btn_visibility(True) # Families widget - families = FamilyListView( + families_filter_view = FamilyListView( io, self.family_config_cache, asset_filter_splitter ) asset_filter_splitter.addWidget(assets) - asset_filter_splitter.addWidget(families) + asset_filter_splitter.addWidget(families_filter_view) asset_filter_splitter.setStretchFactor(0, 65) asset_filter_splitter.setStretchFactor(1, 35) @@ -132,7 +132,6 @@ class LoaderWindow(QtWidgets.QDialog): self.data = { "widgets": { - "families": families, "assets": assets, "subsets": subsets }, @@ -150,7 +149,7 @@ class LoaderWindow(QtWidgets.QDialog): message_timer.timeout.connect(self._on_message_timeout) - families.active_changed.connect(subsets.set_family_filters) + families_filter_view.active_changed.connect(subsets.set_family_filters) assets.selection_changed.connect(self.on_assetschanged) assets.refresh_triggered.connect(self.on_assetschanged) assets.view.clicked.connect(self.on_assetview_click) @@ -163,15 +162,17 @@ class LoaderWindow(QtWidgets.QDialog): repres_widget.load_started.connect(self._on_load_start) repres_widget.load_ended.connect(self._on_load_end) - # TODO add overlay using stack widget self._message_label = message_label + self._message_timer = message_timer + + self._families_filter_view = families_filter_view self._version_info_widget = version_info_widget self._thumbnail_widget = thumbnail_widget self._repres_widget = repres_widget + # TODO add overlay using stack widget self._overlay_frame = overlay_frame - self._message_timer = message_timer self.family_config_cache.refresh() self.groups_config.refresh() @@ -236,11 +237,10 @@ class LoaderWindow(QtWidgets.QDialog): def _on_subset_refresh(self, has_item): subsets_widget = self.data["widgets"]["subsets"] - families_view = self.data["widgets"]["families"] subsets_widget.set_loading_state(loading=False, empty=not has_item) families = subsets_widget.get_subsets_families() - families_view.set_enabled_families(families) + self._families_filter_view.set_enabled_families(families) def _on_load_end(self): # Delay hiding as click events happened during loading should be @@ -251,9 +251,8 @@ class LoaderWindow(QtWidgets.QDialog): def on_context_task_change(self, *args, **kwargs): assets_widget = self.data["widgets"]["assets"] - families_view = self.data["widgets"]["families"] # Refresh families config - families_view.refresh() + self._families_filter_view.refresh() # Change to context asset on context change assets_widget.select_assets(io.Session["AVALON_ASSET"]) @@ -268,8 +267,7 @@ class LoaderWindow(QtWidgets.QDialog): assets_widget.refresh() assets_widget.setFocus() - families_view = self.data["widgets"]["families"] - families_view.refresh() + self._families_filter_view.refresh() def clear_assets_underlines(self): """Clear colors from asset data to remove colored underlines From 6947c68bfe63014ab17a3e622e170ef27a949d81 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 10:13:27 +0200 Subject: [PATCH 13/86] renamed 'asset_filter_splitter' to 'left_side_splitter' --- openpype/tools/loader/app.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index f10348eced..f81f54cc23 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -57,24 +57,24 @@ class LoaderWindow(QtWidgets.QDialog): main_splitter = QtWidgets.QSplitter(self) - asset_filter_splitter = QtWidgets.QSplitter(main_splitter) - asset_filter_splitter.setOrientation(QtCore.Qt.Vertical) - # --- Left part --- + left_side_splitter = QtWidgets.QSplitter(main_splitter) + left_side_splitter.setOrientation(QtCore.Qt.Vertical) + # Assets widget assets = AssetWidget( - io, multiselection=True, parent=asset_filter_splitter + io, multiselection=True, parent=left_side_splitter ) assets.set_current_asset_btn_visibility(True) # Families widget families_filter_view = FamilyListView( - io, self.family_config_cache, asset_filter_splitter + io, self.family_config_cache, left_side_splitter ) - asset_filter_splitter.addWidget(assets) - asset_filter_splitter.addWidget(families_filter_view) - asset_filter_splitter.setStretchFactor(0, 65) - asset_filter_splitter.setStretchFactor(1, 35) + left_side_splitter.addWidget(assets) + left_side_splitter.addWidget(families_filter_view) + left_side_splitter.setStretchFactor(0, 65) + left_side_splitter.setStretchFactor(1, 35) # --- Middle part --- # Subsets widget @@ -112,7 +112,7 @@ class LoaderWindow(QtWidgets.QDialog): thumb_ver_splitter.setStretchFactor(0, 30) thumb_ver_splitter.setStretchFactor(1, 35) - main_splitter.addWidget(asset_filter_splitter) + main_splitter.addWidget(left_side_splitter) main_splitter.addWidget(subsets) main_splitter.addWidget(thumb_ver_splitter) From 658c4a1b6f48fdb0cc96373032815bcd559432e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 10:21:44 +0200 Subject: [PATCH 14/86] rename asset widget and do not store it to data --- openpype/tools/loader/app.py | 45 +++++++++++++++++------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index f81f54cc23..3f3f03867f 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -62,16 +62,16 @@ class LoaderWindow(QtWidgets.QDialog): left_side_splitter.setOrientation(QtCore.Qt.Vertical) # Assets widget - assets = AssetWidget( + assets_widget = AssetWidget( io, multiselection=True, parent=left_side_splitter ) - assets.set_current_asset_btn_visibility(True) + assets_widget.set_current_asset_btn_visibility(True) # Families widget families_filter_view = FamilyListView( io, self.family_config_cache, left_side_splitter ) - left_side_splitter.addWidget(assets) + left_side_splitter.addWidget(assets_widget) left_side_splitter.addWidget(families_filter_view) left_side_splitter.setStretchFactor(0, 65) left_side_splitter.setStretchFactor(1, 35) @@ -132,7 +132,6 @@ class LoaderWindow(QtWidgets.QDialog): self.data = { "widgets": { - "assets": assets, "subsets": subsets }, "state": { @@ -150,9 +149,9 @@ class LoaderWindow(QtWidgets.QDialog): message_timer.timeout.connect(self._on_message_timeout) families_filter_view.active_changed.connect(subsets.set_family_filters) - assets.selection_changed.connect(self.on_assetschanged) - assets.refresh_triggered.connect(self.on_assetschanged) - assets.view.clicked.connect(self.on_assetview_click) + assets_widget.selection_changed.connect(self.on_assetschanged) + assets_widget.refresh_triggered.connect(self.on_assetschanged) + assets_widget.view.clicked.connect(self.on_assetview_click) subsets.active_changed.connect(self.on_subsetschanged) subsets.version_changed.connect(self.on_versionschanged) subsets.refreshed.connect(self._on_subset_refresh) @@ -162,15 +161,16 @@ class LoaderWindow(QtWidgets.QDialog): repres_widget.load_started.connect(self._on_load_start) repres_widget.load_ended.connect(self._on_load_end) - self._message_label = message_label - self._message_timer = message_timer - + self._assets_widget = assets_widget self._families_filter_view = families_filter_view self._version_info_widget = version_info_widget self._thumbnail_widget = thumbnail_widget self._repres_widget = repres_widget + self._message_label = message_label + self._message_timer = message_timer + # TODO add overlay using stack widget self._overlay_frame = overlay_frame @@ -250,11 +250,10 @@ class LoaderWindow(QtWidgets.QDialog): # ------------------------------ def on_context_task_change(self, *args, **kwargs): - assets_widget = self.data["widgets"]["assets"] # Refresh families config self._families_filter_view.refresh() # Change to context asset on context change - assets_widget.select_assets(io.Session["AVALON_ASSET"]) + self._assets_widget.select_assets(io.Session["AVALON_ASSET"]) def _refresh(self): """Load assets from database""" @@ -263,9 +262,8 @@ class LoaderWindow(QtWidgets.QDialog): project = io.find_one({"type": "project"}, {"type": 1}) assert project, "Project was not found! This is a bug" - assets_widget = self.data["widgets"]["assets"] - assets_widget.refresh() - assets_widget.setFocus() + self._assets_widget.refresh() + self._assets_widget.setFocus() self._families_filter_view.refresh() @@ -275,11 +273,12 @@ class LoaderWindow(QtWidgets.QDialog): own selected subsets. These colors must be cleared from asset data on selection change so they match current selection. """ - last_asset_ids = self.data["state"]["assetIds"] + # TODO do not touch inner attributes of asset widget + last_asset_ids = self.data["state"]["assetIds"] or [] if not last_asset_ids: return - assets_widget = self.data["widgets"]["assets"] + assets_widget = self._assets_widget id_role = assets_widget.model.ObjectIdRole for index in lib.iter_model_rows(assets_widget.model, 0): @@ -292,7 +291,6 @@ class LoaderWindow(QtWidgets.QDialog): def _assetschanged(self): """Selected assets have changed""" - assets_widget = self.data["widgets"]["assets"] subsets_widget = self.data["widgets"]["subsets"] subsets_model = subsets_widget.model @@ -300,7 +298,7 @@ class LoaderWindow(QtWidgets.QDialog): self.clear_assets_underlines() # filter None docs they are silo - asset_docs = assets_widget.get_selected_assets() + asset_docs = self._assets_widget.get_selected_assets() asset_ids = [asset_doc["_id"] for asset_doc in asset_docs] # Start loading @@ -354,7 +352,8 @@ class LoaderWindow(QtWidgets.QDialog): self.clear_assets_underlines() - assets_widget = self.data["widgets"]["assets"] + # TODO do not use inner attributes of asset widget + assets_widget = self._assets_widget indexes = assets_widget.view.selectionModel().selectedRows() for index in indexes: @@ -406,8 +405,7 @@ class LoaderWindow(QtWidgets.QDialog): self._version_info_widget.set_version(version_doc) thumbnail_docs = version_docs - assets_widget = self.data["widgets"]["assets"] - asset_docs = assets_widget.get_selected_assets() + asset_docs = self._assets_widget.get_selected_assets() if not thumbnail_docs: if len(asset_docs) > 0: thumbnail_docs = asset_docs @@ -454,8 +452,7 @@ class LoaderWindow(QtWidgets.QDialog): # scheduled refresh and the silo tabs are not shown. self._refresh() - asset_widget = self.data["widgets"]["assets"] - asset_widget.select_assets(asset) + self._assets_widget.select_assets(asset) def _on_message_timeout(self): self._message_label.setText("") From 584fd49e7b02f5bc74c7173c9b1cce74a0f0765a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 10:34:13 +0200 Subject: [PATCH 15/86] renamed subset widget and do not store it to data --- openpype/tools/loader/app.py | 46 ++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 3f3f03867f..a4b4b5eb28 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -78,7 +78,7 @@ class LoaderWindow(QtWidgets.QDialog): # --- Middle part --- # Subsets widget - subsets = SubsetWidget( + subsets_widget = SubsetWidget( io, self.groups_config, self.family_config_cache, @@ -113,7 +113,7 @@ class LoaderWindow(QtWidgets.QDialog): thumb_ver_splitter.setStretchFactor(1, 35) main_splitter.addWidget(left_side_splitter) - main_splitter.addWidget(subsets) + main_splitter.addWidget(subsets_widget) main_splitter.addWidget(thumb_ver_splitter) # TODO keep footer size by message size @@ -148,22 +148,27 @@ class LoaderWindow(QtWidgets.QDialog): message_timer.timeout.connect(self._on_message_timeout) - families_filter_view.active_changed.connect(subsets.set_family_filters) + families_filter_view.active_changed.connect( + self._on_family_filter_change + ) assets_widget.selection_changed.connect(self.on_assetschanged) assets_widget.refresh_triggered.connect(self.on_assetschanged) + # TODO do not touch view in asset widget assets_widget.view.clicked.connect(self.on_assetview_click) - subsets.active_changed.connect(self.on_subsetschanged) - subsets.version_changed.connect(self.on_versionschanged) - subsets.refreshed.connect(self._on_subset_refresh) + subsets_widget.active_changed.connect(self.on_subsetschanged) + subsets_widget.version_changed.connect(self.on_versionschanged) + subsets_widget.refreshed.connect(self._on_subset_refresh) - subsets.load_started.connect(self._on_load_start) - subsets.load_ended.connect(self._on_load_end) + subsets_widget.load_started.connect(self._on_load_start) + subsets_widget.load_ended.connect(self._on_load_end) repres_widget.load_started.connect(self._on_load_start) repres_widget.load_ended.connect(self._on_load_end) self._assets_widget = assets_widget self._families_filter_view = families_filter_view + self._subsets_widget = subsets_widget + self._version_info_widget = version_info_widget self._thumbnail_widget = thumbnail_widget self._repres_widget = repres_widget @@ -236,10 +241,10 @@ class LoaderWindow(QtWidgets.QDialog): self._overlay_frame.setVisible(False) def _on_subset_refresh(self, has_item): - subsets_widget = self.data["widgets"]["subsets"] - - subsets_widget.set_loading_state(loading=False, empty=not has_item) - families = subsets_widget.get_subsets_families() + self._subsets_widget.set_loading_state( + loading=False, empty=not has_item + ) + families = self._subsets_widget.get_subsets_families() self._families_filter_view.set_enabled_families(families) def _on_load_end(self): @@ -248,6 +253,8 @@ class LoaderWindow(QtWidgets.QDialog): QtCore.QTimer.singleShot(100, self._hide_overlay) # ------------------------------ + def _on_family_filter_change(self, families): + self._subsets_widget.set_family_filters(families) def on_context_task_change(self, *args, **kwargs): # Refresh families config @@ -291,7 +298,8 @@ class LoaderWindow(QtWidgets.QDialog): def _assetschanged(self): """Selected assets have changed""" - subsets_widget = self.data["widgets"]["subsets"] + subsets_widget = self._subsets_widget + # TODO do not touch subset widget inner attributes subsets_model = subsets_widget.model subsets_model.clear() @@ -330,8 +338,9 @@ class LoaderWindow(QtWidgets.QDialog): self._versionschanged() return - subsets = self.data["widgets"]["subsets"] - selected_subsets = subsets.selected_subsets(_merged=True, _other=False) + selected_subsets = self._subsets_widget.selected_subsets( + _merged=True, _other=False + ) asset_models = {} asset_ids = [] @@ -370,7 +379,7 @@ class LoaderWindow(QtWidgets.QDialog): self._versionschanged() def _versionschanged(self): - subsets = self.data["widgets"]["subsets"] + subsets = self._subsets_widget selection = subsets.view.selectionModel() # Active must be in the selected rows otherwise we @@ -488,7 +497,7 @@ class LoaderWindow(QtWidgets.QDialog): event.setAccepted(True) # Avoid interfering other widgets def show_grouping_dialog(self): - subsets = self.data["widgets"]["subsets"] + subsets = self._subsets_widget if not subsets.is_groupable(): self.echo("Grouping not enabled.") return @@ -527,7 +536,8 @@ class SubsetGroupingDialog(QtWidgets.QDialog): self.items = items self.groups_config = groups_config - self.subsets = parent.data["widgets"]["subsets"] + # TODO do not touch inner attributes + self.subsets = parent._subsets_widget self.asset_ids = parent.data["state"]["assetIds"] name = QtWidgets.QLineEdit() From 2d687e5e6a923c4f34fac241f074867f6d85580b Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 19 Oct 2021 15:18:41 +0200 Subject: [PATCH 16/86] fix maya hotbox --- openpype/hosts/maya/api/menu.py | 66 ++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index ad225dcd28..18d3e1e896 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -19,10 +19,8 @@ def _get_menu(menu_name=None): if menu_name is None: menu_name = pipeline._menu - widgets = dict(( - w.objectName(), w) for w in QtWidgets.QApplication.allWidgets()) - menu = widgets.get(menu_name) - return menu + widgets = {w.objectName(): w for w in QtWidgets.QApplication.allWidgets()} + return widgets.get(menu_name) def deferred(): @@ -43,6 +41,34 @@ def deferred(): command=lambda *args: mayalookassigner.show() ) + def add_scripts_menu(): + try: + import scriptsmenu.launchformaya as launchformaya + except ImportError: + log.warning( + "Skipping studio.menu install, because " + "'scriptsmenu' module seems unavailable." + ) + return + + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + config = project_settings["maya"]["scriptsmenu"]["definition"] + _menu = project_settings["maya"]["scriptsmenu"]["name"] + + if not config: + log.warning("Skipping studio menu, no definition found.") + return + + # run the launcher for Maya menu + studio_menu = launchformaya.main( + title=_menu.title(), + objectName=_menu.title().lower().replace(" ", "_") + ) + + # apply configuration + studio_menu.build_from_configuration(studio_menu, config) + def modify_workfiles(): from openpype.tools import workfiles @@ -109,38 +135,12 @@ def deferred(): log.info("Attempting to install scripts menu ...") + # add_scripts_menu() add_build_workfiles_item() add_look_assigner_item() modify_workfiles() remove_project_manager() - - try: - import scriptsmenu.launchformaya as launchformaya - import scriptsmenu.scriptsmenu as scriptsmenu - except ImportError: - log.warning( - "Skipping studio.menu install, because " - "'scriptsmenu' module seems unavailable." - ) - return - - # load configuration of custom menu - project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) - config = project_settings["maya"]["scriptsmenu"]["definition"] - _menu = project_settings["maya"]["scriptsmenu"]["name"] - - if not config: - log.warning("Skipping studio menu, no definition found.") - return - - # run the launcher for Maya menu - studio_menu = launchformaya.main( - title=_menu.title(), - objectName=_menu.title().lower().replace(" ", "_") - ) - - # apply configuration - studio_menu.build_from_configuration(studio_menu, config) + add_scripts_menu() def uninstall(): @@ -161,7 +161,7 @@ def install(): return # Allow time for uninstallation to finish. - cmds.evalDeferred(deferred) + cmds.evalDeferred(deferred, lowestPriority=True) def popup(): From 71d79a2dc91f707bf806f864367de92e54e3cd87 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 15:25:16 +0200 Subject: [PATCH 17/86] ignore save warnings exception in prepare project --- .../event_handlers_server/action_prepare_project.py | 9 +++++++-- .../ftrack/event_handlers_user/action_prepare_project.py | 8 +++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/openpype/modules/default_modules/ftrack/event_handlers_server/action_prepare_project.py b/openpype/modules/default_modules/ftrack/event_handlers_server/action_prepare_project.py index 85317031b2..2e55be2743 100644 --- a/openpype/modules/default_modules/ftrack/event_handlers_server/action_prepare_project.py +++ b/openpype/modules/default_modules/ftrack/event_handlers_server/action_prepare_project.py @@ -3,6 +3,7 @@ import json from avalon.api import AvalonMongoDB from openpype.api import ProjectSettings from openpype.lib import create_project +from openpype.settings import SaveWarningExc from openpype_modules.ftrack.lib import ( ServerAction, @@ -312,7 +313,6 @@ class PrepareProjectServer(ServerAction): if not in_data: return - root_values = {} root_key = "__root__" for key in tuple(in_data.keys()): @@ -392,7 +392,12 @@ class PrepareProjectServer(ServerAction): else: attributes_entity[key] = value - project_settings.save() + try: + project_settings.save() + except SaveWarningExc as exc: + self.log.info("Few warnings happened during settings save:") + for warning in exc.warnings: + self.log.info(str(warning)) # Change custom attributes on project if custom_attribute_values: diff --git a/openpype/modules/default_modules/ftrack/event_handlers_user/action_prepare_project.py b/openpype/modules/default_modules/ftrack/event_handlers_user/action_prepare_project.py index 87d3329179..3759bc81ac 100644 --- a/openpype/modules/default_modules/ftrack/event_handlers_user/action_prepare_project.py +++ b/openpype/modules/default_modules/ftrack/event_handlers_user/action_prepare_project.py @@ -3,6 +3,7 @@ import json from avalon.api import AvalonMongoDB from openpype.api import ProjectSettings from openpype.lib import create_project +from openpype.settings import SaveWarningExc from openpype_modules.ftrack.lib import ( BaseAction, @@ -417,7 +418,12 @@ class PrepareProjectLocal(BaseAction): else: attributes_entity[key] = value - project_settings.save() + try: + project_settings.save() + except SaveWarningExc as exc: + self.log.info("Few warnings happened during settings save:") + for warning in exc.warnings: + self.log.info(str(warning)) # Change custom attributes on project if custom_attribute_values: From 9f35dd7763322a3c488cd827f372bae51080d800 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 17:31:23 +0200 Subject: [PATCH 18/86] added basic of experimental tool definitions --- openpype/tools/experimental_tools/__init__.py | 9 ++ .../tools/experimental_tools/tools_def.py | 82 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 openpype/tools/experimental_tools/__init__.py create mode 100644 openpype/tools/experimental_tools/tools_def.py diff --git a/openpype/tools/experimental_tools/__init__.py b/openpype/tools/experimental_tools/__init__.py new file mode 100644 index 0000000000..d61c560886 --- /dev/null +++ b/openpype/tools/experimental_tools/__init__.py @@ -0,0 +1,9 @@ +from .tools_def import ( + ExperimentalTools, + LOCAL_EXPERIMENTAL_KEY +) + +__all__ = ( + "ExperimentalTools", + "LOCAL_EXPERIMENTAL_KEY" +) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py new file mode 100644 index 0000000000..ec4815c741 --- /dev/null +++ b/openpype/tools/experimental_tools/tools_def.py @@ -0,0 +1,82 @@ +from openpype.settings import get_local_settings + +# Constant key under which local settings are stored +LOCAL_EXPERIMENTAL_KEY = "experimental_tools" + + +class ExperimentalTool: + """Definition of experimental tool. + + Args: + identifier (str): String identifier of tool (unique). + label (str): Label shown in UI. + callback (function): Callback for UI button. + tooltip (str): Tooltip showed on button. + hosts_filter (list): List of host names for which is tool available. + Some tools may not be available in all hosts. + """ + def __init__(self, identifier, label, callback, tooltip, hosts_filter=None): + self.identifier = identifier + self.label = label + self.callback = callback + self.tooltip = tooltip + self.hosts_filter = hosts_filter + self._enabled = True + + def is_available_for_host(self, host_name): + if self.hosts_filter: + return host_name in self.hosts_filter + return True + + @property + def enabled(self): + """Is tool enabled and button is clickable.""" + return self._enabled + + def set_enabled(self, enabled=True): + """Change if tool is enabled.""" + self._enabled = enabled + + def execute(self): + """Trigger registerd callback.""" + self.callback() + + +class ExperimentalTools: + """Wrapper around experimental tools. + + To add/remove experimental tool just add/remove tool to + `experimental_tools` variable in __init__ function. + + """ + def __init__(self, parent=None, host_name=None, filter_hosts=None): + experimental_tools = [] + if filter_hosts is None: + filter_hosts = host_name is not None + + if filter_hosts and not host_name: + filter_hosts = False + + if filter_hosts: + experimental_tools = [ + tool + for tool in experimental_tools + if tool.is_available_for_host(host_name) + ] + + self.tools_by_identifier = { + tool.identifier: tool + for tool in experimental_tools + } + self.experimental_tools = experimental_tools + self._parent_widget = parent + + def refresh_availability(self): + local_settings = get_local_settings() + experimental_settings = ( + local_settings.get(LOCAL_EXPERIMENTAL_KEY) + ) or {} + + for identifier, eperimental_tool in self.tools_by_identifier.items(): + enabled = experimental_settings.get(identifier, False) + eperimental_tool.set_enabled(enabled) From e1e2f8e9ddf60fe8b1a48a21bce67e7e2d47a3d7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 17:33:07 +0200 Subject: [PATCH 19/86] base of dialog for experimental tools --- openpype/tools/experimental_tools/dialog.py | 146 ++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 openpype/tools/experimental_tools/dialog.py diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py new file mode 100644 index 0000000000..db868c572f --- /dev/null +++ b/openpype/tools/experimental_tools/dialog.py @@ -0,0 +1,146 @@ +from Qt import QtWidgets + +from openpype.style import ( + load_stylesheet, + app_icon_path +) + +from .tools_def import ExperimentalTools + + +class ToolButton(QtWidgets.QPushButton): + triggered = QtCore.Signal(str) + + def __init__(self, identifier, *args, **kwargs): + super(ExperimentalDialog, self).__init__(*args, **kwargs) + self._identifier = identifier + + self.clicked.connect(self._on_click) + + def _on_click(self): + self.triggered.emit(self._identifier) + + +class ExperimentalDialog(QtWidgets.QDialog): + refresh_interval = 3000 + + def __init__(self, parent=None): + super(ExperimentalDialog, self).__init__(parent) + self.setWindowTitle("OpenPype Experimental tools") + self.setWindowIcon(app_icon_path()) + + empty_label = QtWidgets.QLabel( + "There are no experimental tools available.", self + ) + content_widget = QtWidgets.QWidget(self) + content_widget.setVisible(False) + + content_layout = QtWidgets.QHBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + + experimental_tools = ExperimentalTools() + buttons_by_tool_identifier = {} + + layout = QtWidgets.QHBoxLayout(self) + layout.addWidget(empty_label) + layout.addWidget(content_widget) + + refresh_timer = QtCore.QTimer() + refresh_timer.setInterval(self.refresh_interval) + refresh_timer.timeout.connect(self._on_refresh_timeout) + + self._empty_label = empty_label + self._content_widget = content_widget + self._content_layout = content_layout + + self._experimental_tools = experimental_tools + self._buttons_by_tool_identifier = buttons_by_tool_identifier + + self._is_refreshing = False + self._refresh_on_active = True + self._window_is_active = False + self._refresh_timer = refresh_timer + + def refresh(self): + if self._is_refreshing: + return + self._is_refreshing = True + + self._experimental_tools.refresh_availability() + + buttons_to_remove = set(self._buttons_by_tool_identifier.keys()) + for idx, tool in enumerate(self._experimental_tools.experimental_tools): + identifier = tool.identifier + if identifier in buttons_to_remove: + buttons_to_remove.remove(identifier) + is_new = False + button = self._buttons_by_tool_identifier[identifier] + else: + is_new = True + button = ToolButton(identifier, self) + button.triggered.connect(self._on_btn_trigger) + self._buttons_by_tool_identifier[identifier] = button + self._content_layout.insertWidget(idx, button) + + if button.text() != tool.label: + button.setText(tool.label) + + if tool.enabled: + button.setToolTip(tool.tooltip) + + elif is_new or button.isEnabled(): + button.setToolTip(( + "You can enable this tool in local settings. + "\n\nOpenPype Tray > Settings > Experimental Tools" + )) + + for identifier in buttons_to_remove: + button = self._buttons_by_tool_identifier.pop(identifier) + button.setVisible(False) + idx = self._content_layout.indexOf(button) + self._content_layout.takeAt(idx) + button.deleteLater() + + self._empty_label.setVisible(not self._buttons_by_tool_identifier) + + self._is_refreshing = False + + def _on_btn_trigger(self, identifier): + tool = self._experimental_tools.tools_by_identifier.get(identifier) + if tool is not None: + tool.execute() + + def showEvent(self, event): + super(LauncherWindow, self).showEvent(event) + + if self._refresh_on_active: + # Start/Restart timer + self._refresh_timer.start() + # Refresh + self.refresh() + + elif not self._refresh_timer.isActive(): + self._refresh_timer.start() + + def changeEvent(self, event): + if event.type() == QtCore.QEvent.ActivationChange: + self._window_is_active = self.isActiveWindow() + if self._window_is_active and self._refresh_on_active: + self._refresh_timer.start() + self.refresh() + + super(LauncherWindow, self).changeEvent(event) + + def _on_refresh_timeout(self): + # Stop timer if window is not visible + if not self.isVisible(): + self._refresh_on_active = True + self._refresh_timer.stop() + + # Skip refreshing if window is not active + elif not self._window_is_active: + self._refresh_on_active = True + + # Window is active and visible so we're refreshing buttons + else: + self.refresh() From 6a68cfd4c93f84cbd99fd1a250606debcc4e92f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 17:36:46 +0200 Subject: [PATCH 20/86] added Experimental tools category to local settings --- .../local_settings/experimental_widget.py | 63 +++++++++++++++++++ .../tools/settings/local_settings/window.py | 33 ++++++++++ 2 files changed, 96 insertions(+) create mode 100644 openpype/tools/settings/local_settings/experimental_widget.py diff --git a/openpype/tools/settings/local_settings/experimental_widget.py b/openpype/tools/settings/local_settings/experimental_widget.py new file mode 100644 index 0000000000..953f8f75a9 --- /dev/null +++ b/openpype/tools/settings/local_settings/experimental_widget.py @@ -0,0 +1,63 @@ +from Qt import QtWidgets +from openpype.tools.experimental_tools import ( + ExperimentalTools, + LOCAL_EXPERIMENTAL_KEY +) + + +__all__ = ( + "LocalExperimentalToolsWidgets", + "LOCAL_EXPERIMENTAL_KEY" +) + + +class LocalExperimentalToolsWidgets(QtWidgets.QWidget): + def __init__(self, parent): + super(LocalExperimentalToolsWidgets, self).__init__(parent) + + self._loading_local_settings = False + + layout = QtWidgets.QFormLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + # Label that says there are no experimental tools available + empty_label = QtWidgets.QLabel(self) + empty_label.setText("There are no experimental tools available.") + + layout.addRow(empty_label) + + experimental_defs = ExperimentalTools() + checkboxes_by_identifier = {} + for tool in experimental_defs.experimental_tools: + checkbox = QtWidgets.QCheckBox(self) + label_widget = QtWidgets.QLabel(tool.label, self) + checkbox.setToolTip(tool.tooltip) + label_widget.setToolTip(tool.tooltip) + layout.addRow(label_widget, checkbox) + + checkboxes_by_identifier[tool.identifier] = checkbox + + empty_label.setVisible(len(checkboxes_by_identifier) == 0) + + self._empty_label = empty_label + self._checkboxes_by_identifier = checkboxes_by_identifier + self._experimental_defs = experimental_defs + + def update_local_settings(self, value): + self._loading_local_settings = True + value = value or {} + + for identifier, checkbox in self._checkboxes_by_identifier.items(): + checked = value.get(identifier, False) + checkbox.setChecked(checked) + + self._loading_local_settings = False + + def settings_value(self): + # Add changed + # If these have changed then + output = {} + for identifier, checkbox in self._checkboxes_by_identifier.items(): + if checkbox.isChecked(): + output[identifier] = True + return output diff --git a/openpype/tools/settings/local_settings/window.py b/openpype/tools/settings/local_settings/window.py index 9e8fd89b23..f22e397323 100644 --- a/openpype/tools/settings/local_settings/window.py +++ b/openpype/tools/settings/local_settings/window.py @@ -20,6 +20,10 @@ from .widgets import ( ) from .mongo_widget import OpenPypeMongoWidget from .general_widget import LocalGeneralWidgets +from .experimental_widget import ( + LocalExperimentalToolsWidgets, + LOCAL_EXPERIMENTAL_KEY +) from .apps_widget import LocalApplicationsWidgets from .projects_widget import ProjectSettingsWidget @@ -44,11 +48,13 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.pype_mongo_widget = None self.general_widget = None + self.experimental_widget = None self.apps_widget = None self.projects_widget = None self._create_pype_mongo_ui() self._create_general_ui() + self._create_experimental_ui() self._create_app_ui() self._create_project_ui() @@ -85,6 +91,26 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.general_widget = general_widget + def _create_experimental_ui(self): + # General + experimental_expand_widget = ExpandingWidget( + "Experimental tools", self + ) + + experimental_content = QtWidgets.QWidget(self) + experimental_layout = QtWidgets.QVBoxLayout(experimental_content) + experimental_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + experimental_expand_widget.set_content_widget(experimental_content) + + experimental_widget = LocalExperimentalToolsWidgets( + experimental_content + ) + experimental_layout.addWidget(experimental_widget) + + self.main_layout.addWidget(experimental_expand_widget) + + self.experimental_widget = experimental_widget + def _create_app_ui(self): # Applications app_expand_widget = ExpandingWidget("Applications", self) @@ -135,6 +161,9 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.projects_widget.update_local_settings( value.get(LOCAL_PROJECTS_KEY) ) + self.experimental_widget.update_local_settings( + value.get(LOCAL_EXPERIMENTAL_KEY) + ) def settings_value(self): output = {} @@ -149,6 +178,10 @@ class LocalSettingsWidget(QtWidgets.QWidget): projects_value = self.projects_widget.settings_value() if projects_value: output[LOCAL_PROJECTS_KEY] = projects_value + + experimental_value = self.experimental_widget.settings_value() + if experimental_value: + output[LOCAL_EXPERIMENTAL_KEY] = experimental_value return output From 90de4cddb582ed50eea8ac65698d3517f6dd058c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 17:50:10 +0200 Subject: [PATCH 21/86] store tools under 'tools' variable --- openpype/tools/experimental_tools/tools_def.py | 2 +- openpype/tools/settings/local_settings/experimental_widget.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index ec4815c741..353ec8e1d5 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -68,7 +68,7 @@ class ExperimentalTools: tool.identifier: tool for tool in experimental_tools } - self.experimental_tools = experimental_tools + self.tools = experimental_tools self._parent_widget = parent def refresh_availability(self): diff --git a/openpype/tools/settings/local_settings/experimental_widget.py b/openpype/tools/settings/local_settings/experimental_widget.py index 953f8f75a9..741c173415 100644 --- a/openpype/tools/settings/local_settings/experimental_widget.py +++ b/openpype/tools/settings/local_settings/experimental_widget.py @@ -28,7 +28,7 @@ class LocalExperimentalToolsWidgets(QtWidgets.QWidget): experimental_defs = ExperimentalTools() checkboxes_by_identifier = {} - for tool in experimental_defs.experimental_tools: + for tool in experimental_defs.tools: checkbox = QtWidgets.QCheckBox(self) label_widget = QtWidgets.QLabel(tool.label, self) checkbox.setToolTip(tool.tooltip) From 27e9f20c07cc3a9550e2fdae70d2b00560e6ede8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 17:58:10 +0200 Subject: [PATCH 22/86] fix dialog file --- openpype/tools/experimental_tools/dialog.py | 25 +++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index db868c572f..14f3e6e48b 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -1,4 +1,4 @@ -from Qt import QtWidgets +from Qt import QtWidgets, QtCore, QtGui from openpype.style import ( load_stylesheet, @@ -12,7 +12,7 @@ class ToolButton(QtWidgets.QPushButton): triggered = QtCore.Signal(str) def __init__(self, identifier, *args, **kwargs): - super(ExperimentalDialog, self).__init__(*args, **kwargs) + super(ToolButton, self).__init__(*args, **kwargs) self._identifier = identifier self.clicked.connect(self._on_click) @@ -27,23 +27,22 @@ class ExperimentalDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(ExperimentalDialog, self).__init__(parent) self.setWindowTitle("OpenPype Experimental tools") - self.setWindowIcon(app_icon_path()) + icon = QtGui.QIcon(app_icon_path()) + self.setWindowIcon(icon) empty_label = QtWidgets.QLabel( "There are no experimental tools available.", self ) content_widget = QtWidgets.QWidget(self) - content_widget.setVisible(False) content_layout = QtWidgets.QHBoxLayout(content_widget) content_layout.setContentsMargins(0, 0, 0, 0) experimental_tools = ExperimentalTools() - buttons_by_tool_identifier = {} layout = QtWidgets.QHBoxLayout(self) layout.addWidget(empty_label) - layout.addWidget(content_widget) + layout.addWidget(content_widget, 1) refresh_timer = QtCore.QTimer() refresh_timer.setInterval(self.refresh_interval) @@ -54,7 +53,7 @@ class ExperimentalDialog(QtWidgets.QDialog): self._content_layout = content_layout self._experimental_tools = experimental_tools - self._buttons_by_tool_identifier = buttons_by_tool_identifier + self._buttons_by_tool_identifier = {} self._is_refreshing = False self._refresh_on_active = True @@ -69,7 +68,7 @@ class ExperimentalDialog(QtWidgets.QDialog): self._experimental_tools.refresh_availability() buttons_to_remove = set(self._buttons_by_tool_identifier.keys()) - for idx, tool in enumerate(self._experimental_tools.experimental_tools): + for idx, tool in enumerate(self._experimental_tools.tools): identifier = tool.identifier if identifier in buttons_to_remove: buttons_to_remove.remove(identifier) @@ -90,7 +89,7 @@ class ExperimentalDialog(QtWidgets.QDialog): elif is_new or button.isEnabled(): button.setToolTip(( - "You can enable this tool in local settings. + "You can enable this tool in local settings." "\n\nOpenPype Tray > Settings > Experimental Tools" )) @@ -101,7 +100,9 @@ class ExperimentalDialog(QtWidgets.QDialog): self._content_layout.takeAt(idx) button.deleteLater() - self._empty_label.setVisible(not self._buttons_by_tool_identifier) + self._empty_label.setVisible( + len(self._buttons_by_tool_identifier) == 0 + ) self._is_refreshing = False @@ -111,7 +112,7 @@ class ExperimentalDialog(QtWidgets.QDialog): tool.execute() def showEvent(self, event): - super(LauncherWindow, self).showEvent(event) + super(ExperimentalDialog, self).showEvent(event) if self._refresh_on_active: # Start/Restart timer @@ -129,7 +130,7 @@ class ExperimentalDialog(QtWidgets.QDialog): self._refresh_timer.start() self.refresh() - super(LauncherWindow, self).changeEvent(event) + super(ExperimentalDialog, self).changeEvent(event) def _on_refresh_timeout(self): # Stop timer if window is not visible From 5026d300bbcae2eaa87dccf3ad2a0655a3ae4274 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 17:58:22 +0200 Subject: [PATCH 23/86] import ExperimentalDialog to init file --- openpype/tools/experimental_tools/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openpype/tools/experimental_tools/__init__.py b/openpype/tools/experimental_tools/__init__.py index d61c560886..75e3210aab 100644 --- a/openpype/tools/experimental_tools/__init__.py +++ b/openpype/tools/experimental_tools/__init__.py @@ -3,7 +3,12 @@ from .tools_def import ( LOCAL_EXPERIMENTAL_KEY ) +from .dialog import ExperimentalDialog + + __all__ = ( "ExperimentalTools", - "LOCAL_EXPERIMENTAL_KEY" + "LOCAL_EXPERIMENTAL_KEY", + + "ExperimentalDialog" ) From 7d3f4d315ff71f71403dddfd3f95d1ecd57e69a3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 18:20:26 +0200 Subject: [PATCH 24/86] empty dialog has Ok btn --- openpype/tools/experimental_tools/dialog.py | 65 ++++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index 14f3e6e48b..237052c055 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -30,41 +30,59 @@ class ExperimentalDialog(QtWidgets.QDialog): icon = QtGui.QIcon(app_icon_path()) self.setWindowIcon(icon) + empty_widget = QtWidgets.QWidget(self) + empty_label = QtWidgets.QLabel( - "There are no experimental tools available.", self + "There are no experimental tools available...", empty_widget ) + + empty_btns_layout = QtWidgets.QHBoxLayout() + ok_btn = QtWidgets.QPushButton("OK", empty_widget) + + empty_btns_layout.setContentsMargins(0, 0, 0, 0) + empty_btns_layout.addStretch(1) + empty_btns_layout.addWidget(ok_btn, 0) + + empty_layout = QtWidgets.QVBoxLayout(empty_widget) + empty_layout.setContentsMargins(0, 0, 0, 0) + empty_layout.addWidget(empty_label) + empty_layout.addStretch(1) + empty_layout.addLayout(empty_btns_layout) + content_widget = QtWidgets.QWidget(self) - content_layout = QtWidgets.QHBoxLayout(content_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(0, 0, 0, 0) experimental_tools = ExperimentalTools() - layout = QtWidgets.QHBoxLayout(self) - layout.addWidget(empty_label) + layout = QtWidgets.QVBoxLayout(self) + layout.addWidget(empty_widget, 1) layout.addWidget(content_widget, 1) refresh_timer = QtCore.QTimer() refresh_timer.setInterval(self.refresh_interval) refresh_timer.timeout.connect(self._on_refresh_timeout) - self._empty_label = empty_label + ok_btn.clicked.connect(self._on_ok_click) + + self._empty_widget = empty_widget self._content_widget = content_widget self._content_layout = content_layout self._experimental_tools = experimental_tools self._buttons_by_tool_identifier = {} - self._is_refreshing = False - self._refresh_on_active = True - self._window_is_active = False self._refresh_timer = refresh_timer - def refresh(self): - if self._is_refreshing: - return - self._is_refreshing = True + # Is dialog first shown + self._first_show = True + # Trigger refresh when window get's activity + self._refresh_on_active = True + # Is window active + self._window_is_active = False + def refresh(self): self._experimental_tools.refresh_availability() buttons_to_remove = set(self._buttons_by_tool_identifier.keys()) @@ -100,11 +118,18 @@ class ExperimentalDialog(QtWidgets.QDialog): self._content_layout.takeAt(idx) button.deleteLater() - self._empty_label.setVisible( - len(self._buttons_by_tool_identifier) == 0 - ) + self._set_visibility() - self._is_refreshing = False + def _is_content_visible(self): + return len(self._buttons_by_tool_identifier) > 0 + + def _set_visibility(self): + content_visible = self._is_content_visible() + self._content_widget.setVisible(content_visible) + self._empty_widget.setVisible(not content_visible) + + def _on_ok_click(self): + self.close() def _on_btn_trigger(self, identifier): tool = self._experimental_tools.tools_by_identifier.get(identifier) @@ -123,6 +148,14 @@ class ExperimentalDialog(QtWidgets.QDialog): elif not self._refresh_timer.isActive(): self._refresh_timer.start() + if self._first_show: + self._first_show = False + # Resize dialog if there is not content + if not self._is_content_visible(): + size = self.size() + size.setWidth(size.width() + size.width() / 3) + self.resize(size) + def changeEvent(self, event): if event.type() == QtCore.QEvent.ActivationChange: self._window_is_active = self.isActiveWindow() From c7df4e9edc7185a0d155a215a8822b3bed9dcbd7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 20:12:23 +0200 Subject: [PATCH 25/86] changed label --- openpype/tools/settings/local_settings/experimental_widget.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/local_settings/experimental_widget.py b/openpype/tools/settings/local_settings/experimental_widget.py index 741c173415..72f999d886 100644 --- a/openpype/tools/settings/local_settings/experimental_widget.py +++ b/openpype/tools/settings/local_settings/experimental_widget.py @@ -22,7 +22,9 @@ class LocalExperimentalToolsWidgets(QtWidgets.QWidget): # Label that says there are no experimental tools available empty_label = QtWidgets.QLabel(self) - empty_label.setText("There are no experimental tools available.") + empty_label.setText( + "There are no experimental tools available..." + ) layout.addRow(empty_label) From 54a8b9d811e6d8602b2f2b729ae0db2701c678ef Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 11:28:54 +0200 Subject: [PATCH 26/86] removed "widget" key from data --- openpype/tools/loader/app.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index a4b4b5eb28..d7fa9640ac 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -131,9 +131,6 @@ class LoaderWindow(QtWidgets.QDialog): layout.addWidget(footer_widget) self.data = { - "widgets": { - "subsets": subsets - }, "state": { "assetIds": None } @@ -206,8 +203,8 @@ class LoaderWindow(QtWidgets.QDialog): # ------------------------------- def on_assetview_click(self, *args): - subsets_widget = self.data["widgets"]["subsets"] - selection_model = subsets_widget.view.selectionModel() + # TODO do not touch inner attributes of subset widget + selection_model = self._subsets_widget.view.selectionModel() if selection_model.selectedIndexes(): selection_model.clearSelection() From 3a56ac5e5e1920dcffea9d54a0f043cc92c5e628 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 11:05:36 +0200 Subject: [PATCH 27/86] validate tool identifier keys --- openpype/tools/experimental_tools/tools_def.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 353ec8e1d5..2fa42bcc6e 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -64,10 +64,16 @@ class ExperimentalTools: if tool.is_available_for_host(host_name) ] - self.tools_by_identifier = { - tool.identifier: tool - for tool in experimental_tools - } + # Store tools by identifier + tools_by_identifier = {} + for tool in experimental_tools: + if tool.identifier in tools_by_identifier: + raise KeyError(( + "Duplicated experimental tool identifier \"{}\"" + ).format(tool.identifier)) + tools_by_identifier[tool.identifier] = tool + + self.tools_by_identifier = tools_by_identifier self.tools = experimental_tools self._parent_widget = parent From 630299e340ab41af673dde31803288bb1587d93f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 11:05:46 +0200 Subject: [PATCH 28/86] fix 80char line --- openpype/tools/experimental_tools/tools_def.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 2fa42bcc6e..13283c157a 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -15,7 +15,9 @@ class ExperimentalTool: hosts_filter (list): List of host names for which is tool available. Some tools may not be available in all hosts. """ - def __init__(self, identifier, label, callback, tooltip, hosts_filter=None): + def __init__( + self, identifier, label, callback, tooltip, hosts_filter=None + ): self.identifier = identifier self.label = label self.callback = callback From b6bb7a9d09fb8e5922bfcaf40ceeaea5d5344d70 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 11:06:21 +0200 Subject: [PATCH 29/86] get host name from environment if not passed # Conflicts: # openpype/tools/experimental_tools/tools_def.py --- openpype/tools/experimental_tools/tools_def.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 13283c157a..0dcec7a871 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -1,3 +1,4 @@ +import os from openpype.settings import get_local_settings # Constant key under which local settings are stored @@ -53,6 +54,10 @@ class ExperimentalTools: """ def __init__(self, parent=None, host_name=None, filter_hosts=None): experimental_tools = [] + + if not host_name: + host_name = os.environ.get("AVALON_APP") + if filter_hosts is None: filter_hosts = host_name is not None From c9860711512a48d18fe9423a0b510e508c59eeb2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 11:06:29 +0200 Subject: [PATCH 30/86] added few docstrings # Conflicts: # openpype/tools/experimental_tools/tools_def.py --- openpype/tools/experimental_tools/tools_def.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 0dcec7a871..5dd92151ca 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -51,19 +51,30 @@ class ExperimentalTools: To add/remove experimental tool just add/remove tool to `experimental_tools` variable in __init__ function. + Args: + parent (QtWidgets.QWidget): Parent widget for tools. + host_name (str): Name of host in which context we're now. Environment + value 'AVALON_APP' is used when not passed. + filter_hosts (bool): Should filter tools. By default is set to 'True' + when 'host_name' is passed. Is always set to 'False' if 'host_name' + is not defined. """ def __init__(self, parent=None, host_name=None, filter_hosts=None): + # Definition of experimental tools experimental_tools = [] + # Try to get host name from env variable `AVALON_APP` if not host_name: host_name = os.environ.get("AVALON_APP") + # Decide if filtering by host name should happen if filter_hosts is None: filter_hosts = host_name is not None if filter_hosts and not host_name: filter_hosts = False + # Filter tools by host name if filter_hosts: experimental_tools = [ tool From dc9f901c7a83331f4495ac8230f195b371f43a24 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 11:18:13 +0200 Subject: [PATCH 31/86] use OpenPype stylesheet in experimental dialog --- openpype/tools/experimental_tools/dialog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index 237052c055..a611416efc 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -29,6 +29,7 @@ class ExperimentalDialog(QtWidgets.QDialog): self.setWindowTitle("OpenPype Experimental tools") icon = QtGui.QIcon(app_icon_path()) self.setWindowIcon(icon) + self.setStyleSheet(load_stylesheet()) empty_widget = QtWidgets.QWidget(self) From 661ba6090967d87edf639fa197ad14e420392196 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 12:21:47 +0200 Subject: [PATCH 32/86] fix parenting in subset widget --- openpype/tools/loader/widgets.py | 70 +++++++++++++++----------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index 6b94fc6e44..d2b0a6b730 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -159,20 +159,25 @@ class SubsetWidget(QtWidgets.QWidget): grouping=enable_grouping ) proxy = SubsetFilterProxyModel() + proxy.setSourceModel(model) + proxy.setDynamicSortFilter(True) + proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) + family_proxy = FamiliesFilterProxyModel() family_proxy.setSourceModel(proxy) - subset_filter = QtWidgets.QLineEdit() + subset_filter = QtWidgets.QLineEdit(self) subset_filter.setPlaceholderText("Filter subsets..") - groupable = QtWidgets.QCheckBox("Enable Grouping") - groupable.setChecked(enable_grouping) + group_checkbox = QtWidgets.QCheckBox("Enable Grouping", self) + group_checkbox.setChecked(enable_grouping) top_bar_layout = QtWidgets.QHBoxLayout() top_bar_layout.addWidget(subset_filter) - top_bar_layout.addWidget(groupable) + top_bar_layout.addWidget(group_checkbox) - view = TreeViewSpinner() + view = TreeViewSpinner(self) + view.setModel(family_proxy) view.setObjectName("SubsetView") view.setIndentation(20) view.setStyleSheet(""" @@ -192,59 +197,50 @@ class SubsetWidget(QtWidgets.QWidget): column = model.Columns.index("time") view.setItemDelegateForColumn(column, time_delegate) - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addLayout(top_bar_layout) - layout.addWidget(view) - view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) view.setSortingEnabled(True) view.sortByColumn(1, QtCore.Qt.AscendingOrder) view.setAlternatingRowColors(True) - self.data = { - "delegates": { - "version": version_delegate, - "time": time_delegate - }, - "state": { - "groupable": groupable - } - } - - self.proxy = proxy - self.model = model - self.view = view - self.filter = subset_filter - self.family_proxy = family_proxy + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addLayout(top_bar_layout) + layout.addWidget(view) # settings and connections - self.proxy.setSourceModel(self.model) - self.proxy.setDynamicSortFilter(True) - self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) - - self.view.setModel(self.family_proxy) - self.view.customContextMenuRequested.connect(self.on_context_menu) - for column_name, width in self.default_widths: idx = model.Columns.index(column_name) view.setColumnWidth(idx, width) + self.model = model + self.view = view + actual_project = dbcon.Session["AVALON_PROJECT"] self.on_project_change(actual_project) + view.customContextMenuRequested.connect(self.on_context_menu) + selection = view.selectionModel() selection.selectionChanged.connect(self.active_changed) version_delegate.version_changed.connect(self.version_changed) - groupable.stateChanged.connect(self.set_grouping) + group_checkbox.stateChanged.connect(self.set_grouping) - self.filter.textChanged.connect(self.proxy.setFilterRegExp) - self.filter.textChanged.connect(self.view.expandAll) + subset_filter.textChanged.connect(proxy.setFilterRegExp) + subset_filter.textChanged.connect(view.expandAll) model.refreshed.connect(self.refreshed) + self.proxy = proxy + self.family_proxy = family_proxy + + self._subset_filter = subset_filter + self._group_checkbox = group_checkbox + + self._version_delegate = version_delegate + self._time_delegate = time_delegate + self.model.refresh() def get_subsets_families(self): @@ -254,7 +250,7 @@ class SubsetWidget(QtWidgets.QWidget): self.family_proxy.setFamiliesFilter(families) def is_groupable(self): - return self.data["state"]["groupable"].checkState() + return self._group_checkbox.isChecked() def set_grouping(self, state): with tools_lib.preserve_selection(tree_view=self.view, @@ -1128,7 +1124,7 @@ class RepresentationWidget(QtWidgets.QWidget): label = QtWidgets.QLabel("Representations", self) - tree_view = DeselectableTreeView() + tree_view = DeselectableTreeView(parent=self) tree_view.setModel(proxy_model) tree_view.setAllColumnsShowFocus(True) tree_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) From c0ca4ea5893b6fa267aad72011e457d93de3722b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 12:29:19 +0200 Subject: [PATCH 33/86] add parenting in util widgets --- openpype/tools/utils/widgets.py | 79 ++++++++++++++++----------------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index b9b542c123..878a9b7c86 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -35,28 +35,19 @@ class AssetWidget(QtWidgets.QWidget): self.dbcon = dbcon - self.setContentsMargins(0, 0, 0, 0) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(4) - # Tree View model = AssetModel(dbcon=self.dbcon, parent=self) proxy = RecursiveSortFilterProxyModel() proxy.setSourceModel(model) proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) - view = AssetsView() + view = AssetsView(self) view.setModel(proxy) if multiselection: asset_delegate = AssetDelegate() view.setSelectionMode(view.ExtendedSelection) view.setItemDelegate(asset_delegate) - # Header - header = QtWidgets.QHBoxLayout() - icon = qtawesome.icon("fa.arrow-down", color=style.colors.light) set_current_asset_btn = QtWidgets.QPushButton(icon, "") set_current_asset_btn.setToolTip("Go to Asset from current Session") @@ -64,22 +55,28 @@ class AssetWidget(QtWidgets.QWidget): set_current_asset_btn.setVisible(False) icon = qtawesome.icon("fa.refresh", color=style.colors.light) - refresh = QtWidgets.QPushButton(icon, "") + refresh = QtWidgets.QPushButton(icon, "", parent=self) refresh.setToolTip("Refresh items") - filter = QtWidgets.QLineEdit() - filter.textChanged.connect(proxy.setFilterFixedString) - filter.setPlaceholderText("Filter assets..") + filter_input = QtWidgets.QLineEdit(self) + filter_input.setPlaceholderText("Filter assets..") - header.addWidget(filter) - header.addWidget(set_current_asset_btn) - header.addWidget(refresh) + # Header + header_layout = QtWidgets.QHBoxLayout() + header_layout.addWidget(filter_input) + header_layout.addWidget(set_current_asset_btn) + header_layout.addWidget(refresh) # Layout - layout.addLayout(header) + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(4) + layout.addLayout(header_layout) layout.addWidget(view) # Signals/Slots + filter_input.textChanged.connect(proxy.setFilterFixedString) + selection = view.selectionModel() selection.selectionChanged.connect(self.selection_changed) selection.currentChanged.connect(self.current_changed) @@ -399,30 +396,30 @@ class OptionalActionWidget(QtWidgets.QWidget): def __init__(self, label, parent=None): super(OptionalActionWidget, self).__init__(parent) - body = QtWidgets.QWidget() - body.setStyleSheet("background: transparent;") + body_widget = QtWidgets.QWidget(self) + body_widget.setStyleSheet("background: transparent;") - icon = QtWidgets.QLabel() - label = QtWidgets.QLabel(label) - option = OptionBox(body) + icon = QtWidgets.QLabel(body_widget) + label = QtWidgets.QLabel(label, body_widget) + option = OptionBox(body_widget) icon.setFixedSize(24, 16) option.setFixedSize(30, 30) - layout = QtWidgets.QHBoxLayout(body) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(2) - layout.addWidget(icon) - layout.addWidget(label) - layout.addSpacing(6) + body_layout = QtWidgets.QHBoxLayout(body_widget) + body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setSpacing(2) + body_layout.addWidget(icon) + body_layout.addWidget(label) + body_layout.addSpacing(6) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(6, 1, 2, 1) layout.setSpacing(0) - layout.addWidget(body) + layout.addWidget(body_widget) layout.addWidget(option) - body.setMouseTracking(True) + body_widget.setMouseTracking(True) label.setMouseTracking(True) option.setMouseTracking(True) self.setMouseTracking(True) @@ -431,7 +428,7 @@ class OptionalActionWidget(QtWidgets.QWidget): self.icon = icon self.label = label self.option = option - self.body = body + self.body = body_widget # (NOTE) For removing ugly QLable shadow FX when highlighted in Nuke. # See https://stackoverflow.com/q/52838690/4145300 @@ -476,20 +473,20 @@ class OptionDialog(QtWidgets.QDialog): def create(self, options): parser = qargparse.QArgumentParser(arguments=options) - decision = QtWidgets.QWidget() - accept = QtWidgets.QPushButton("Accept") - cancel = QtWidgets.QPushButton("Cancel") + decision_widget = QtWidgets.QWidget(self) + accept_btn = QtWidgets.QPushButton("Accept", decision_widget) + cancel_btn = QtWidgets.QPushButton("Cancel", decision_widget) - layout = QtWidgets.QHBoxLayout(decision) - layout.addWidget(accept) - layout.addWidget(cancel) + decision_layout = QtWidgets.QHBoxLayout(decision_widget) + decision_layout.addWidget(accept_btn) + decision_layout.addWidget(cancel_btn) layout = QtWidgets.QVBoxLayout(self) layout.addWidget(parser) - layout.addWidget(decision) + layout.addWidget(decision_widget) - accept.clicked.connect(self.accept) - cancel.clicked.connect(self.reject) + accept_btn.clicked.connect(self.accept) + cancel_btn.clicked.connect(self.reject) parser.changed.connect(self.on_changed) def on_changed(self, argument): From 95838d120a2f834fe38031b4d3fa97b2919f0f4f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 12:32:23 +0200 Subject: [PATCH 34/86] use openpype stylesheet --- openpype/tools/loader/app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index d7fa9640ac..74e121896e 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -1,10 +1,10 @@ import sys from Qt import QtWidgets, QtCore -from avalon import api, io, style, pipeline +from avalon import api, io, pipeline +from openpype.style import load_stylesheet from openpype.tools.utils.widgets import AssetWidget - from openpype.tools.utils import lib from .widgets import ( @@ -46,6 +46,7 @@ class LoaderWindow(QtWidgets.QDialog): if project_name: title += " - {}".format(project_name) self.setWindowTitle(title) + self.setStyleSheet(load_stylesheet()) # Groups config self.groups_config = lib.GroupsConfig(io) @@ -653,7 +654,6 @@ def show(debug=False, parent=None, use_context=False): with lib.application(): window = LoaderWindow(parent) - window.setStyleSheet(style.load_stylesheet()) window.show() if use_context: From a2485eb7bf581273ec0c33b7182dd19e3a33e329 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 12:32:35 +0200 Subject: [PATCH 35/86] add parenting to asset view --- openpype/tools/utils/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/utils/views.py b/openpype/tools/utils/views.py index bed5655647..89e49fe142 100644 --- a/openpype/tools/utils/views.py +++ b/openpype/tools/utils/views.py @@ -68,8 +68,8 @@ class AssetsView(TreeViewSpinner, DeselectableTreeView): This implements a context menu. """ - def __init__(self): - super(AssetsView, self).__init__() + def __init__(self, parent=None): + super(AssetsView, self).__init__(parent) self.setIndentation(15) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.setHeaderHidden(True) From ce755730d2a84684cf319d203754982aae8b585a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 12:50:30 +0200 Subject: [PATCH 36/86] use WA_TranslucentBackground --- openpype/tools/loader/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index d2b0a6b730..0946826dc4 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -37,12 +37,13 @@ class OverlayFrame(QtWidgets.QFrame): super(OverlayFrame, self).__init__(parent) label_widget = QtWidgets.QLabel(label, self) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + main_layout = QtWidgets.QVBoxLayout(self) main_layout.addWidget(label_widget, 1, QtCore.Qt.AlignCenter) self.label_widget = label_widget - label_widget.setStyleSheet("background: transparent;") self.setStyleSheet(( "background: rgba(0, 0, 0, 127);" "font-size: 60pt;" From 4b1f739f211d550276019bbc19d53364b22ca1e3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 12:50:51 +0200 Subject: [PATCH 37/86] move stylesheet of SubsetView to style.css --- openpype/style/style.css | 5 +++++ openpype/tools/loader/widgets.py | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 830ed85f9b..a7e82be567 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -629,3 +629,8 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #PythonInterpreterOutput, #PythonCodeEditor { font-family: "Roboto Mono"; } + +#SubsetView::item { + padding: 5px 1px; + border: 0px; +} diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index 0946826dc4..a55cfb6e43 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -181,12 +181,6 @@ class SubsetWidget(QtWidgets.QWidget): view.setModel(family_proxy) view.setObjectName("SubsetView") view.setIndentation(20) - view.setStyleSheet(""" - QTreeView::item{ - padding: 5px 1px; - border: 0px; - } - """) view.setAllColumnsShowFocus(True) # Set view delegates From 1c179510f7d402f69949faf84b4f6abbb4192e2f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 14:36:03 +0200 Subject: [PATCH 38/86] copied color definitions from new publisher PR --- openpype/style/__init__.py | 40 ++++- openpype/style/color_defs.py | 285 +++++++++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 openpype/style/color_defs.py diff --git a/openpype/style/__init__.py b/openpype/style/__init__.py index 0d7904d133..d763bfdc3c 100644 --- a/openpype/style/__init__.py +++ b/openpype/style/__init__.py @@ -2,6 +2,8 @@ import os import json import collections from openpype import resources +import six +from .color_defs import parse_color _STYLESHEET_CACHE = None @@ -10,6 +12,40 @@ _FONT_IDS = None current_dir = os.path.dirname(os.path.abspath(__file__)) +def get_colors_data(): + data = _get_colors_raw_data() + return data.get("color") or {} + + +def _convert_color_values_to_objects(value): + if isinstance(value, dict): + output = {} + for _key, _value in value.items(): + output[_key] = _convert_color_values_to_objects(_value) + return output + + if not isinstance(value, six.string_types): + raise TypeError(( + "Unexpected type in colors data '{}'. Expected 'str' or 'dict'." + ).format(str(type(value)))) + return parse_color(value) + + +def get_objected_colors(): + colors_data = get_colors_data() + output = {} + for key, value in colors_data.items(): + output[key] = _convert_color_values_to_objects(value) + return output + + +def _get_colors_raw_data(): + data_path = os.path.join(current_dir, "data.json") + with open(data_path, "r") as data_stream: + data = json.load(data_stream) + return data + + def _load_stylesheet(): from . import qrc_resources @@ -19,9 +55,7 @@ def _load_stylesheet(): with open(style_path, "r") as style_file: stylesheet = style_file.read() - data_path = os.path.join(current_dir, "data.json") - with open(data_path, "r") as data_stream: - data = json.load(data_stream) + data = _get_colors_raw_data() data_deque = collections.deque() for item in data.items(): diff --git a/openpype/style/color_defs.py b/openpype/style/color_defs.py new file mode 100644 index 0000000000..4d726cc3f3 --- /dev/null +++ b/openpype/style/color_defs.py @@ -0,0 +1,285 @@ +import re + + +def parse_color(value): + modified_value = value.strip().lower() + if modified_value.startswith("hsla"): + return HSLAColor(value) + + if modified_value.startswith("hsl"): + return HSLColor(value) + + if modified_value.startswith("#"): + return HEXColor(value) + + if modified_value.startswith("rgba"): + return RGBAColor(value) + + if modified_value.startswith("rgb"): + return RGBColor(value) + return UnknownColor(value) + + +def create_qcolor(*args): + from Qt import QtGui + + return QtGui.QColor(*args) + + +def min_max_check(value, min_value, max_value): + if min_value is not None and value < min_value: + raise ValueError("Minimum expected value is '{}' got '{}'".format( + min_value, value + )) + + if max_value is not None and value > max_value: + raise ValueError("Maximum expected value is '{}' got '{}'".format( + min_value, value + )) + + +def int_validation(value, min_value=None, max_value=None): + if not isinstance(value, int): + raise TypeError(( + "Invalid type of hue expected 'int' got {}" + ).format(str(type(value)))) + + min_max_check(value, min_value, max_value) + + +def float_validation(value, min_value=None, max_value=None): + if not isinstance(value, float): + raise TypeError(( + "Invalid type of hue expected 'int' got {}" + ).format(str(type(value)))) + + min_max_check(value, min_value, max_value) + + +class UnknownColor: + def __init__(self, value): + self.value = value + + def get_qcolor(self): + return create_qcolor(self.value) + + +class HEXColor: + regex = re.compile(r"[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$") + + def __init__(self, color_string): + red, green, blue = self.hex_to_rgb(color_string) + + self._color_string = color_string + self._red = red + self._green = green + self._blue = blue + + @property + def red(self): + return self._red + + @property + def green(self): + return self._green + + @property + def blue(self): + return self._blue + + def to_stylesheet_str(self): + return self._color_string + + @classmethod + def hex_to_rgb(cls, value): + hex_value = value.lstrip("#") + if not cls.regex.match(hex_value): + raise ValueError("\"{}\" is not a valid HEX code.".format(value)) + + output = [] + if len(hex_value) == 3: + for char in hex_value: + output.append(int(char * 2, 16)) + else: + for idx in range(3): + start_idx = idx * 2 + output.append(int(hex_value[start_idx:start_idx + 2], 16)) + return output + + def get_qcolor(self): + return create_qcolor(self.red, self.green, self.blue) + + +class RGBColor: + def __init__(self, value): + modified_color = value.lower().strip() + content = modified_color.rstrip(")").lstrip("rgb(") + red_str, green_str, blue_str = ( + item.strip() for item in content.split(",") + ) + red = int(red_str) + green = int(green_str) + blue = int(blue_str) + + int_validation(red, 0, 255) + int_validation(green, 0, 255) + int_validation(blue, 0, 255) + + self._red = red + self._green = green + self._blue = blue + + @property + def red(self): + return self._red + + @property + def green(self): + return self._green + + @property + def blue(self): + return self._blue + + def get_qcolor(self): + return create_qcolor(self.red, self.green, self.blue) + + +class RGBAColor: + def __init__(self, value): + modified_color = value.lower().strip() + content = modified_color.rstrip(")").lstrip("rgba(") + red_str, green_str, blue_str, alpha_str = ( + item.strip() for item in content.split(",") + ) + red = int(red_str) + green = int(green_str) + blue = int(blue_str) + alpha = int(alpha_str) + + int_validation(red, 0, 255) + int_validation(green, 0, 255) + int_validation(blue, 0, 255) + int_validation(alpha, 0, 255) + + self._red = red + self._green = green + self._blue = blue + self._alpha = alpha + + @property + def red(self): + return self._red + + @property + def green(self): + return self._green + + @property + def blue(self): + return self._blue + + @property + def alpha(self): + return self._alpha + + def get_qcolor(self): + return create_qcolor(self.red, self.green, self.blue, self.alpha) + + +class HSLColor: + def __init__(self, value): + modified_color = value.lower().strip() + content = modified_color.rstrip(")").lstrip("hsl(") + hue_str, sat_str, light_str = ( + item.strip() for item in content.split(",") + ) + hue = int(hue_str) % 360 + if "%" in sat_str: + sat = float(sat_str.rstrip("%")) / 100 + else: + sat = float(sat) + + if "%" in light_str: + light = float(light_str.rstrip("%")) / 100 + else: + light = float(light_str) + + int_validation(hue, 0, 360) + float_validation(sat, 0, 1) + float_validation(light, 0, 1) + + self._hue = hue + self._saturation = sat + self._light = light + + @property + def hue(self): + return self._hue + + @property + def saturation(self): + return self._saturation + + @property + def light(self): + return self._light + + def get_qcolor(self): + color = create_qcolor() + color.setHslF(self.hue / 360, self.saturation, self.light) + return color + + +class HSLAColor: + def __init__(self, value): + modified_color = value.lower().strip() + content = modified_color.rstrip(")").lstrip("hsla(") + hue_str, sat_str, light_str, alpha_str = ( + item.strip() for item in content.split(",") + ) + hue = int(hue_str) % 360 + if "%" in sat_str: + sat = float(sat_str.rstrip("%")) / 100 + else: + sat = float(sat) + + if "%" in light_str: + light = float(light_str.rstrip("%")) / 100 + else: + light = float(light_str) + alpha = float(alpha_str) + + if isinstance(alpha, int): + alpha = float(alpha) + + int_validation(hue, 0, 360) + float_validation(sat, 0, 1) + float_validation(light, 0, 1) + float_validation(alpha, 0, 1) + + self._hue = hue + self._saturation = sat + self._light = light + self._alpha = alpha + + @property + def hue(self): + return self._hue + + @property + def saturation(self): + return self._saturation + + @property + def light(self): + return self._light + + @property + def alpha(self): + return self._alpha + + def get_qcolor(self): + color = create_qcolor() + color.setHslF(self.hue / 360, self.saturation, self.light, self.alpha) + return color From 35435fedba310293bc3d0f5c2c7979b5caccc152 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 15:23:37 +0200 Subject: [PATCH 39/86] use rgba instead of hsla --- openpype/style/data.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index a58829d946..5cac7e07db 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -28,7 +28,7 @@ "bg": "#2C313A", "bg-inputs": "#21252B", "bg-buttons": "#434a56", - "bg-button-hover": "hsla(220, 14%, 70%, .3)", + "bg-button-hover": "rgba(168, 175, 189, 0.3)", "bg-inputs-disabled": "#2C313A", "bg-buttons-disabled": "#434a56", @@ -38,15 +38,15 @@ "bg-view": "#21252B", "bg-view-header": "#373D48", - "bg-view-hover": "hsla(220, 14%, 70%, .3)", + "bg-view-hover": "rgba(168, 175, 189, .3)", "bg-view-alternate": "rgb(36, 42, 50)", "bg-view-disabled": "#434a56", "bg-view-alternate-disabled": "#2C313A", - "bg-view-selection": "hsla(200, 60%, 60%, .4)", - "bg-view-selection-hover": "hsla(200, 60%, 60%, .8)", + "bg-view-selection": "rgba(92, 173, 214, .4)", + "bg-view-selection-hover": "rgba(92, 173, 214, .8)", "border": "#373D48", - "border-hover": "hsla(220, 14%, 70%, .3)", + "border-hover": "rgba(168, 175, 189, .3)", "border-focus": "hsl(200, 60%, 60%)" } } From 66a1ba4033deb115db6627ec60fafaa0a9470bad Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 15:24:03 +0200 Subject: [PATCH 40/86] added RepresentationView to stylesheet --- openpype/style/style.css | 2 +- openpype/tools/loader/widgets.py | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index a7e82be567..6507cbe63b 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -630,7 +630,7 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { font-family: "Roboto Mono"; } -#SubsetView::item { +#SubsetView::item, #RepresentationView:item { padding: 5px 1px; border: 0px; } diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index a55cfb6e43..f6ba200eff 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -1120,6 +1120,7 @@ class RepresentationWidget(QtWidgets.QWidget): label = QtWidgets.QLabel("Representations", self) tree_view = DeselectableTreeView(parent=self) + tree_view.setObjectName("RepresentationView") tree_view.setModel(proxy_model) tree_view.setAllColumnsShowFocus(True) tree_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) @@ -1129,12 +1130,6 @@ class RepresentationWidget(QtWidgets.QWidget): tree_view.sortByColumn(1, QtCore.Qt.AscendingOrder) tree_view.setAlternatingRowColors(True) tree_view.setIndentation(20) - tree_view.setStyleSheet(""" - QTreeView::item{ - padding: 5px 1px; - border: 0px; - } - """) tree_view.collapseAll() for column_name, width in self.default_widths: From dd0ed45d53efc57de2b7fabb3b08be495d70257f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 15:36:33 +0200 Subject: [PATCH 41/86] changed order of setting stylesheet --- openpype/tools/loader/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 74e121896e..b29f0970ca 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -46,7 +46,6 @@ class LoaderWindow(QtWidgets.QDialog): if project_name: title += " - {}".format(project_name) self.setWindowTitle(title) - self.setStyleSheet(load_stylesheet()) # Groups config self.groups_config = lib.GroupsConfig(io) @@ -191,6 +190,8 @@ class LoaderWindow(QtWidgets.QDialog): main_splitter.setSizes([250, 850, 200]) self.resize(1300, 700) + self.setStyleSheet(load_stylesheet()) + def resizeEvent(self, event): super(LoaderWindow, self).resizeEvent(event) self._overlay_frame.resize(self.size()) From 740328ef851cd5cc8aa51ec752256b586e27631e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 15:37:08 +0200 Subject: [PATCH 42/86] added parents to delegates --- openpype/tools/loader/widgets.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index f6ba200eff..9a639c3b85 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -182,22 +182,21 @@ class SubsetWidget(QtWidgets.QWidget): view.setObjectName("SubsetView") view.setIndentation(20) view.setAllColumnsShowFocus(True) - - # Set view delegates - version_delegate = VersionDelegate(self.dbcon) - column = model.Columns.index("version") - view.setItemDelegateForColumn(column, version_delegate) - - time_delegate = PrettyTimeDelegate() - column = model.Columns.index("time") - view.setItemDelegateForColumn(column, time_delegate) - view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) view.setSortingEnabled(True) view.sortByColumn(1, QtCore.Qt.AscendingOrder) view.setAlternatingRowColors(True) + # Set view delegates + version_delegate = VersionDelegate(self.dbcon, view) + column = model.Columns.index("version") + view.setItemDelegateForColumn(column, version_delegate) + + time_delegate = PrettyTimeDelegate(view) + column = model.Columns.index("time") + view.setItemDelegateForColumn(column, time_delegate) + layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addLayout(top_bar_layout) From b888240bdb9b66e224e09bf445ba8b815f3e0837 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 15:37:42 +0200 Subject: [PATCH 43/86] use better margins for optional items --- openpype/tools/utils/widgets.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index 878a9b7c86..de75de705b 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -407,14 +407,13 @@ class OptionalActionWidget(QtWidgets.QWidget): option.setFixedSize(30, 30) body_layout = QtWidgets.QHBoxLayout(body_widget) - body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setContentsMargins(4, 0, 4, 0) body_layout.setSpacing(2) body_layout.addWidget(icon) body_layout.addWidget(label) - body_layout.addSpacing(6) layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(6, 1, 2, 1) + layout.setContentsMargins(2, 1, 2, 1) layout.setSpacing(0) layout.addWidget(body_widget) layout.addWidget(option) From 7d70d22e2d76bdb0a7aa6c936e0c8284b7c63839 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 17:31:21 +0200 Subject: [PATCH 44/86] moved set of stylesheet after show of tool --- openpype/tools/utils/host_tools.py | 48 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index ee184ccf2d..599c25d6c8 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -40,7 +40,6 @@ class HostToolsHelper: def get_workfiles_tool(self, parent): """Create, cache and return workfiles tool window.""" if self._workfiles_tool is None: - from avalon import style from openpype.tools.workfiles.app import ( Window, validate_host_requirements ) @@ -49,13 +48,14 @@ class HostToolsHelper: validate_host_requirements(host) workfiles_window = Window(parent=parent) - workfiles_window.setStyleSheet(style.load_stylesheet()) self._workfiles_tool = workfiles_window return self._workfiles_tool def show_workfiles(self, parent=None, use_context=None, save=None): """Workfiles tool for changing context and saving workfiles.""" + from avalon import style + if use_context is None: use_context = True @@ -79,24 +79,30 @@ class HostToolsHelper: # Pull window to the front. workfiles_tool.raise_() workfiles_tool.activateWindow() + workfiles_tool.setStyleSheet(style.load_stylesheet()) def get_loader_tool(self, parent): """Create, cache and return loader tool window.""" if self._loader_tool is None: - from avalon import style from openpype.tools.loader import LoaderWindow loader_window = LoaderWindow(parent=parent or self._parent) - loader_window.setStyleSheet(style.load_stylesheet()) self._loader_tool = loader_window return self._loader_tool def show_loader(self, parent=None, use_context=None): """Loader tool for loading representations.""" + from avalon import style + + loader_tool = self.get_loader_tool(parent) + + loader_tool.show() + loader_tool.raise_() + loader_tool.activateWindow() + if use_context is None: use_context = False - loader_tool = self.get_loader_tool(parent) if use_context: context = {"asset": avalon.api.Session["AVALON_ASSET"]} @@ -104,29 +110,28 @@ class HostToolsHelper: else: loader_tool.refresh() - loader_tool.show() - loader_tool.raise_() - loader_tool.activateWindow() - loader_tool.refresh() + loader_tool.setStyleSheet(style.load_stylesheet()) def get_creator_tool(self, parent): """Create, cache and return creator tool window.""" if self._creator_tool is None: - from avalon import style from avalon.tools.creator.app import Window creator_window = Window(parent=parent or self._parent) - creator_window.setStyleSheet(style.load_stylesheet()) self._creator_tool = creator_window return self._creator_tool def show_creator(self, parent=None): """Show tool to create new instantes for publishing.""" + from avalon import style + creator_tool = self.get_creator_tool(parent) creator_tool.refresh() creator_tool.show() + creator_tool.setStyleSheet(style.load_stylesheet()) + # Pull window to the front. creator_tool.raise_() creator_tool.activateWindow() @@ -134,20 +139,22 @@ class HostToolsHelper: def get_subset_manager_tool(self, parent): """Create, cache and return subset manager tool window.""" if self._subset_manager_tool is None: - from avalon import style from avalon.tools.subsetmanager import Window subset_manager_window = Window(parent=parent or self._parent) - subset_manager_window.setStyleSheet(style.load_stylesheet()) self._subset_manager_tool = subset_manager_window return self._subset_manager_tool def show_subset_manager(self, parent=None): """Show tool display/remove existing created instances.""" + from avalon import style + subset_manager_tool = self.get_subset_manager_tool(parent) subset_manager_tool.show() + subset_manager_tool.setStyleSheet(style.load_stylesheet()) + # Pull window to the front. subset_manager_tool.raise_() subset_manager_tool.activateWindow() @@ -155,20 +162,21 @@ class HostToolsHelper: def get_scene_inventory_tool(self, parent): """Create, cache and return scene inventory tool window.""" if self._scene_inventory_tool is None: - from avalon import style from avalon.tools.sceneinventory.app import Window scene_inventory_window = Window(parent=parent or self._parent) - scene_inventory_window.setStyleSheet(style.load_stylesheet()) self._scene_inventory_tool = scene_inventory_window return self._scene_inventory_tool def show_scene_inventory(self, parent=None): """Show tool maintain loaded containers.""" + from avalon import style + scene_inventory_tool = self.get_scene_inventory_tool(parent) scene_inventory_tool.show() scene_inventory_tool.refresh() + scene_inventory_tool.setStyleSheet(style.load_stylesheet()) # Pull window to the front. scene_inventory_tool.raise_() @@ -177,24 +185,25 @@ class HostToolsHelper: def get_library_loader_tool(self, parent): """Create, cache and return library loader tool window.""" if self._library_loader_tool is None: - from avalon import style from openpype.tools.libraryloader import LibraryLoaderWindow library_window = LibraryLoaderWindow( parent=parent or self._parent ) - library_window.setStyleSheet(style.load_stylesheet()) self._library_loader_tool = library_window return self._library_loader_tool def show_library_loader(self, parent=None): """Loader tool for loading representations from library project.""" + from avalon import style + library_loader_tool = self.get_library_loader_tool(parent) library_loader_tool.show() library_loader_tool.raise_() library_loader_tool.activateWindow() library_loader_tool.refresh() + library_loader_tool.setStyleSheet(style.load_stylesheet()) def show_publish(self, parent=None): """Publish UI.""" @@ -205,18 +214,19 @@ class HostToolsHelper: def get_look_assigner_tool(self, parent): """Create, cache and return look assigner tool window.""" if self._look_assigner_tool is None: - from avalon import style import mayalookassigner mayalookassigner_window = mayalookassigner.App(parent) - mayalookassigner_window.setStyleSheet(style.load_stylesheet()) self._look_assigner_tool = mayalookassigner_window return self._look_assigner_tool def show_look_assigner(self, parent=None): """Look manager is Maya specific tool for look management.""" + from avalon import style + look_assigner_tool = self.get_look_assigner_tool(parent) look_assigner_tool.show() + look_assigner_tool.setStyleSheet(style.load_stylesheet()) def get_tool_by_name(self, tool_name, parent=None, *args, **kwargs): """Show tool by it's name. From 961a602e1c0d2bdd33c2b7b8e3fbe2ee762db5b5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 17:56:42 +0200 Subject: [PATCH 45/86] fix hovering stylesheet of optional action --- openpype/style/style.css | 8 ++++++ openpype/tools/utils/widgets.py | 47 ++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 6507cbe63b..948ee8c7b7 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -634,3 +634,11 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { padding: 5px 1px; border: 0px; } + +#OptionalActionBody, #OptionalActionOption { + background: transparent; +} + +#OptionalActionBody[state="hover"], #OptionalActionOption[state="hover"] { + background: {color:bg-view-hover}; +} diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index de75de705b..15bcbeff90 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -310,7 +310,6 @@ class OptionalMenu(QtWidgets.QMenu): actions that were instances of `QtWidgets.QWidgetAction`. """ - def mouseReleaseEvent(self, event): """Emit option clicked signal if mouse released on it""" active = self.actionAt(event.pos()) @@ -349,6 +348,7 @@ class OptionalAction(QtWidgets.QWidgetAction): self.use_option = use_option self.option_tip = "" self.optioned = False + self.widget = None def createWidget(self, parent): widget = OptionalActionWidget(self.label, parent) @@ -374,20 +374,10 @@ class OptionalAction(QtWidgets.QWidgetAction): self.optioned = True def set_highlight(self, state, global_pos=None): - body = self.widget.body - option = self.widget.option - - role = QtGui.QPalette.Highlight if state else QtGui.QPalette.Window - body.setBackgroundRole(role) - body.setAutoFillBackground(state) - - if not self.use_option: - return - - state = option.is_hovered(global_pos) - role = QtGui.QPalette.Highlight if state else QtGui.QPalette.Window - option.setBackgroundRole(role) - option.setAutoFillBackground(state) + option_state = False + if self.use_option: + option_state = self.widget.option.is_hovered(global_pos) + self.widget.set_hover_properties(state, option_state) class OptionalActionWidget(QtWidgets.QWidget): @@ -397,11 +387,15 @@ class OptionalActionWidget(QtWidgets.QWidget): super(OptionalActionWidget, self).__init__(parent) body_widget = QtWidgets.QWidget(self) - body_widget.setStyleSheet("background: transparent;") + body_widget.setObjectName("OptionalActionBody") icon = QtWidgets.QLabel(body_widget) label = QtWidgets.QLabel(label, body_widget) + # (NOTE) For removing ugly QLable shadow FX when highlighted in Nuke. + # See https://stackoverflow.com/q/52838690/4145300 + label.setStyle(QtWidgets.QStyleFactory.create("Plastique")) option = OptionBox(body_widget) + option.setObjectName("OptionalActionOption") icon.setFixedSize(24, 16) option.setFixedSize(30, 30) @@ -429,9 +423,22 @@ class OptionalActionWidget(QtWidgets.QWidget): self.option = option self.body = body_widget - # (NOTE) For removing ugly QLable shadow FX when highlighted in Nuke. - # See https://stackoverflow.com/q/52838690/4145300 - label.setStyle(QtWidgets.QStyleFactory.create("Plastique")) + def set_hover_properties(self, hovered, option_hovered): + body_state = "" + option_state = "" + if hovered: + body_state = "hover" + + if option_hovered: + option_state = "hover" + + if self.body.property("state") != body_state: + self.body.setProperty("state", body_state) + self.body.style().polish(self.body) + + if self.option.property("state") != option_state: + self.option.setProperty("state", option_state) + self.option.style().polish(self.option) def setIcon(self, icon): pixmap = icon.pixmap(16, 16) @@ -452,8 +459,6 @@ class OptionBox(QtWidgets.QLabel): pixmap = icon.pixmap(18, 18) self.setPixmap(pixmap) - self.setStyleSheet("background: transparent;") - def is_hovered(self, global_pos): if global_pos is None: return False From bcb27d5aebe6ccc8d5cae84dd4177f8d0c4aa7de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 18:24:18 +0200 Subject: [PATCH 46/86] changed new thumbnail --- .../tools/loader/images/default_thumbnail.png | Bin 4018 -> 5118 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/openpype/tools/loader/images/default_thumbnail.png b/openpype/tools/loader/images/default_thumbnail.png index 97bd958e0daf01e740db9f426e1f9b3e22484c87..adea862e5b7169f8279bd398226a2fe6283e4925 100644 GIT binary patch literal 5118 zcmeHLc{o+y*Wc&di)+d?ln^c%BBG)wa!nyKSB5fFU$dgF>1#ZSqKGdM5{f99GH1G1 zh7cl|uP9@#44Juj@AvopJ@4P|@BQqMCt>9Di#vj70t z^>nq&0D$RJ7+_Fz)|eyKN*AU~3<%nEasU6v|7YO;bO!o@*d^&7`ntE7kvV{16qa>F5nX^jD z=gzCBUQolUYiMd|U)0gnyQFVmXk=_+YGzKbxNK=$ zdCSx5_8p?PkFTHqp8KPD!pre|h<&Qa%oEi5iA|6W;LTi@8++TNkDL2eFprmbr}?KH8gV`mHH zJEJ_t8$a3>GEhSI|DOy*&g@RE>ie9kva5L3slZ1AGU-X&Yfjs)jh08IJAAxnhph5` zFIUPawdzr+ue{xNR38aUyJP-M)ZSMoK+>=QaApnms&kM zA=HR+!BzK(3YO{NAbt99XZheR?I?{Qu3`N>M<#EsONme+D!El8)#EM|2+d#(&y4v1 zPp?Rcz)l}9qO6s0(?<}bMMRepyVR`Yrg|+)x2pp9ONOF zoY42rI_sw_xsah-g*=6XZw5f(8DYY=#;;RM$Jk#Hn*GCrvKz9oc^H=OYvmVF@5I3J zy;Je^4%9(Mw8P8N^-tSLvBA#6Az#$dnU7lb6E{@lB4RLPCDsV76=rhPSrAU}U1Xi) zM1*XF;|1{6$6@*QQzAoLuzVYCXodH7pnVhZAmp;l;_z%0G|jl89ijun;R$9kPmJ$d z%=lXcSiZ?tBkH_|${HSCvTr}22=U}%5zhOp+V?pTPCLRua$eJCRRqvNxr;AZ0E+?) z8EmjPN^l}j{~OkEHFPE^seBH8-Db2pzspSaJQ|^K6oU_BwP2Lb0A(8~?cjpm>O4II zpG$s7qh8-M0;x5GV~Ls|^^>Ilc@S+J$^dQ7$GV}C>8hRFVQ`rXneKnf?jQ)cESQ%= zVgZ8w%5)3;a%f%@bP8S;AdA4=R}+Up9+%3lBN{soq?vIPHMkvvqma-G21~2E7~G&7 zsuBx4(VR$Ey14+E1@5LCDTjE({I~U)$<8;vGI|Nn;knA8RT0p+MU%Yt9z9-ZD2*C) z;6xULEcnPOaJQX-BhaL8g|CmrlR=!u_2LM;G|KM-)jDz_dkX|!vK&1XDIW=)`y<{P zo|;%B;5dPym?8?e*~|~(qd_!w=;f?!rtXiK1%1GOxIhBAA`8oFwx2n;BKMFBk)mBW zWC#Liyv3$_G_|r7VWjT?D2qE9Y++?+{|K=C4xa~mPMnAyZTrjXN6dI`%K_b8NWN7R zGwYP9exX{hT%#-<-aD0<_gbLCi$t^_fslRa5vK0PEMIC2N6<;x!d2kL{@ckBW z{QSUE{lMNK+SqJ5WhML^a!7kUq;z5aW3#sB{)fFyHIl3wCu07_cmJ=Op448B*RdXZ zYhw<)Mdvh+kb_3{$tA2mA$Jn*E#WA66ZFVcZ|46g{S^579pmp@13qD zecE`gA%IWMs$-MO-QLW~TU@Q2^EWkF>tC&3D9W?6LMeUxp0waBnw0TRF|s1qh-hj5 z?EhdvTp^Zbt9V(VTDL#^q|QGmz_YjlsiO0tS-;d_j1gFg-_m@NwN2yCP zMPs7@qs05<0yhkV7C~+~wtc%*R3+vGrSaB-Q)g;6n{16?c~xXq|JL55ndJt zV6DY}P7K6yBY#01Pu8{qPu>G;Yz}3$i!%?6*)D<6Ms9r9Z4u*N1!xB=AgCW<&^N$^ zm_iCWR;@nsmtc7*#8IQ-C@-T3k`W<>JO~eZWy?%{0xo`)#^C2&jDZu{tD#aO%D5zk zV?0eB-My~=qIKIF?p8xusNtvH_G0imAPEzZBoK0Ac7B}6i)7-)3C#+Umu$+R$P{!Y z5!4+IcQeP}$H4GB;X)`UsdpSyGn_{*F0ybCK4S2_V4BsKFsZw}FYQSw`^o*l8wd0x zFtJab&+J|AU9{e4Tzq?FKj;voE1%i^7Brl@08j>yWwt?E&Z6Te0SB=cm>!?q}s;+_?9tSd4cndDfgH@rf%_K zsDs;1-#77UMqP>UUqHq^e(4*lUhsFyVEeZ4ax)LCYh+i>0Y#F|le%@)?`2%JdKsX4 zZN`Cd+?zdHhL~pO(woREv}}xyL(jP598>0&21skn!prKg*IrILX*ZP=8B4tLLiHvk z@8MX10%D}j=8(Q*+!?c8blQn}*{4&Mer!fR7=OGON?fdy{H1!muN*zzM0T@BVRd!} zca+P?>qqlwJT^=4>}81{-|ntT14X}*!tGY=c3A1S3shx|lKQmJRLOY$=Izx;rfP1a z^E{AaW)JF@Zg8BQCvHZH3u4GgDH^Pcj=Gy`_QRbmSO$5CLLG4Z29>d}1efxbCawj zrBPhSs$$%Be2{ywCJv5Nk^3;w+KgT@KdqH~WL6#I3YZGy0j)MZw3oDnJ8ms;$+tB4 zS0@L4lwUVE_=!4DbD`B^Uik5IlQ)tgP2zpri=Y35C~_KeDHzB~C_n7$01Pkv!Jb{8 z9pq~9x(agR)OH+t!E;=cee@sysv5)FL|84A-|8TMZKL0+TjPWa+ zMHZ%_?J>8Db#zg!C$4X5V6J3n-PCp0MCk@6^n`vMEl@W{S&_#>3CVo*K;q=Od2O$l z2gH`=G?#nlomoX<6tr1Rccg#x8Vk<-IQRaW2oVtEL1k+SVhP2j2sUZD5R&s|<~2YjexG)q!_eh-U3Jb-U6 zse8T!g%jzA>e-dU!sOEiJu&6Xp6oePK{CNDBrKtWZ+6!Ig|_Yz`u*gu-;X8%8p}?!mcw#X+k^ z`r9`xJ3pP!bd|;B+!QRHwI45Cs*)E9^1}$OJ^N#~dt?!vl=w>w)l77o=7oXtpdX)i zNZ4=N|4SLmxChXE>SF#d z8|2s881<@@@5;JPd!C8I>5lpCc#ot?M0H;gtmHg0Zi z4h|01*48k>x~r?Jqobp(tu2i9_V$-AUv_eGf^`^S+aAI?jIeDFVSNwrc)YW-^B%%o zunk7o2JgZM>;D|#F4(-+_1AhYVQ*_s->d(6-uM6221mg!CMpLSf;zB5o7z zMBcp@b)OjX;9=~excJ8jPZFO#d!F+0RchMnjLfX;H*eqNtNn9>fgx<;TvdyGgFNBq z_0AWZKLBQ>;Id3J(V)7by7i$~scvF&#)mC3V>2&~fQ9Vr;$6nz`I`c(RM`@!6b{8P z<5*FhDm0ds^H`(HaAo54Om?Bh)(^`c@_n}}b{AT&KjU}8PhM@v`}t?{f7dtv?pVuJ zmy_w_FOfl6JzWDu`9sIqSKZi-dgr9fwgj>w3*xfdW{QeAvvnIEy`&5Gaf()~QWE0X zoTFt?mK?4=kvhvedq&H{hu4=)R;*z>Ijf}Eu={YJR}f}G26WXOk%W}0w#P1XFSMQf zW1W7MirhIDQ+anf;fGg|3$d}e^`7-gkZhLS6_?r0EnEKjF+Hwyb|;ZA8Rz@@(X0xP zyI!EGAj!G8CCTe3ST7^zt0N03)%G?gWH3ANI?CV^G>K%+M8yGFXx7nVBGwg=;o>pD z(~YX>q|X#2d_rTk!3XYq64L=-LrTg;Nx|)rdjUp9Mg#egT1t6?Tfjnm!LjqBrF!D4 zve>0H@ra=Us6mO|I9Q0iI5PJGauH5xN&WlNbloVZ)5V==c= z7(M(&IUe9@Uz8W)E*&nM*=WPF)cIPP@1E|fTa}X^XRgyNdFlVUL^xo$Qx35x-k@+c zAPRTEO%rXf((AHp2F+1W4z|mdj2tvuzP=D=cUNCioqIoPUHbJ$j0-n5UmXGIk3PK; zVqn!`2yyyWw%S02wI~M?TZ?t#ZRR?{cfTH6<^G2N^5Rp|(zSqNg!lelahn&P0)&D| zo55X`7@)?>yBJVgQi2FGhSQP+D}A)leDcnzSO97b*e!SxI?k-#s(RD!nwJpaajW)C zz}f*3BaL&K&JsfjV2VsIBx49QEt#)yaR~#FuBu-ysot`?@DUVpS{+Ts zB&(7=q4xn9c0@je_dAPI*h|oRvhvRDbzS*t0MA;d)xhz+@HioO@ud&AL@V(1S}q^W zMyjO!Eej%!=i`G@CgLPL_|p2~SXywqFwsv6RG(#=F?t3N2z{#HgcX8W%J2jU4UtHa zN2ZNTu;^nQ8c=gSN?=SN2KWQPyqwvntB)GF7Cfm@s`jn_Z z3TqEO@?B6_iv{lcote$l!qGset->t8Q5?eVUc9uB(vY8vLW-PdlH1&|S#u}%8rf-x zVb`h}pR2$tKn0ZaM(^fRMc+oEiX_L%2X=hZRhcmhQL?Nh4ZUfjDtcSQr;!?a;TIMbx^4{J6>ccR$SAPF7vdV#w;vECEZa*{|W2y5XCMzm^EmgP+2#2j? zcn9e?_}>F2pd|mQ4egX^gcQfC-^*HEI~NgBY#8^1Za-uO3-p*aCHUmSsMnq>>R~(i z?QU-|gzd@h3e&kt^UxImLP5u%l7|V-UyzW^YV$VTaOe^6z{jk#{Lb{K2})qfo=mp! z^3p&{73+Kvt;iq%s>mksJG)lrK=mY>3@7nVLIfuNocp<_Ks5iX9q*_&^j=O)yEGn< zj55ue2MA*2nYY3^DHaQ1Y_{G56xMetr)R)3@nWupM*}SWK$dTByl7#N$7?BKt6hW^ zu>7z2N1wcD_z+_4eI?9E!d%$YW@J`jS*5}s>0>OO3G$h`#3qk_Rijtj!B4X)w$b~9 zNsl`Ym{Ww)PG3o-L{1pd8;5jSpbNVuUJOH;aZOfz(m|lUhzasd?&@zJC~5V!l|`rA zK)PWgO-f7s&3dn3?odj7cN<+wAVVDWa{JI3<@AiR@46z)V(6A~q$LO6bO^b&)_kx< zzW{o~nC`hP3EtBU797n>A|a-|JMRL1wcNW1@3ZmRtx*~n>}!MA;}7Iz*JzhGdV|7- zH3SJm8uL~?_VRfj&QBJ5R#e*w^N>0a4a_SS!8srE>O5=lcVwqdAb>Tyf5Y{#_5+Lk_(ACWQm(WJ5N zX2?z!W#l-cV(13VoGK3{w7iMXuF+9{A<$}ByDpJVjk~T*nqg;A^KK3@Aro@-7Dxg$ z)1N=#W^yDBoxaJ?zFu2G%`?_X5v@v#kR;JsrLb+yF16UfHWvFoVI{Z2HrmH#(bJ?Rt#zj;+&dqQ_067C4NFJ-A z;d-m;tY%*ob~QBeb55oF;VVSFBmvpkl58rP#^L8RczvZDaOAEjXA8=M7;LI=f%YBUDhzK~4wu|4Ez+!NAoL?J#O6JyvG)eKcsVQ!C#hxg~pFXuo4hT7dnZ&U>JHOtNAUzcA_b*yD zCnjg54}9r2041}cLeQ(4y1R%CvqQ==Jsn;X@j#k6BU2<2PQ_pyxFmKa*TWXMXnpvF zDt@ozhweSEjh}B0Ap-BpFbm)Brd;L6h<`kY)wWIS12(u_f8e^}@zPlAf|YOT5=4*W z`m`NgTxL=a(Q8ZXL@>%0wHOjfHp`AZ0~%bk#sy(*@(vnaNN6nE;YXBJ-1lolEzV$8 z4(CALvE%gR+A@wq$dVY|Y+1f#S?sQx@UvERrm&TF4nxxy*2GB+Jl_hPt(p^ofF+83 zN5^+%+Jgt+`2eMgh6e=z1;WM8kpZsGqoEuB9vyy4aCP7>)5OoY07PVeW(kEHS1Me|0+l9)5auf131WDrcF0Gejq1aP$zG<$A4M|6tNt&Y| z%T_|7NXA21$ikN^NhHfJ$byY;bA zF>Y9)pLJl!D;WH^KBoL?xHj^n^YwNP%tb`*Qrs!f(l<}SJde*M0&;6;5HCi?OKXW( zmsuZNT9_DnK~NUV7w3}DEN^1W(Z%WBcCm)^c@*r25}lPSwQ9e$_e?}DJj5UPzauWZ aQ8TBK`_#VgnlokXr%hW!U;VAB9rQ1Cc_|D4 From acf88c7f16488da71ec5187025382a80c946919a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 18:35:09 +0200 Subject: [PATCH 47/86] alpha can have float number in rgba --- openpype/style/color_defs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/style/color_defs.py b/openpype/style/color_defs.py index 4d726cc3f3..3f504a9d3b 100644 --- a/openpype/style/color_defs.py +++ b/openpype/style/color_defs.py @@ -155,7 +155,10 @@ class RGBAColor: red = int(red_str) green = int(green_str) blue = int(blue_str) - alpha = int(alpha_str) + if "." in alpha_str: + alpha = int(float(alpha_str) * 100) + else: + alpha = int(alpha_str) int_validation(red, 0, 255) int_validation(green, 0, 255) From 0f62d59d5d89ecc19375bbc3dfa1c410c6e0efdb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 18:35:33 +0200 Subject: [PATCH 48/86] use colors in asset delegate from openpype style --- openpype/style/data.json | 10 +++++++++- openpype/tools/utils/delegates.py | 23 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index 5cac7e07db..143c6695af 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -47,6 +47,14 @@ "border": "#373D48", "border-hover": "rgba(168, 175, 189, .3)", - "border-focus": "hsl(200, 60%, 60%)" + "border-focus": "hsl(200, 60%, 60%)", + + "loader": { + "asset-view": { + "selected": "rgba(168, 175, 189, 0.6)", + "hover": "rgba(168, 175, 189, 0.3)", + "selected-hover": "rgba(168, 175, 189, 0.7)" + } + } } } diff --git a/openpype/tools/utils/delegates.py b/openpype/tools/utils/delegates.py index 1827bc7e9b..96353c44c6 100644 --- a/openpype/tools/utils/delegates.py +++ b/openpype/tools/utils/delegates.py @@ -7,6 +7,7 @@ import Qt from Qt import QtWidgets, QtGui, QtCore from avalon.lib import HeroVersionType +from openpype.style import get_objected_colors from .models import ( AssetModel, TreeModel @@ -24,6 +25,19 @@ log = logging.getLogger(__name__) class AssetDelegate(QtWidgets.QItemDelegate): bar_height = 3 + def __init__(self, *args, **kwargs): + super(AssetDelegate, self).__init__(*args, **kwargs) + asset_view_colors = get_objected_colors()["loader"]["asset-view"] + self._selected_color = ( + asset_view_colors["selected"].get_qcolor() + ) + self._hover_color = ( + asset_view_colors["hover"].get_qcolor() + ) + self._selected_hover_color = ( + asset_view_colors["selected-hover"].get_qcolor() + ) + def sizeHint(self, option, index): result = super(AssetDelegate, self).sizeHint(option, index) height = result.height() @@ -66,17 +80,20 @@ class AssetDelegate(QtWidgets.QItemDelegate): counter += 1 # Background - bg_color = QtGui.QColor(60, 60, 60) if option.state & QtWidgets.QStyle.State_Selected: if len(subset_colors) == 0: item_rect.setTop(item_rect.top() + (self.bar_height / 2)) + if option.state & QtWidgets.QStyle.State_MouseOver: - bg_color.setRgb(70, 70, 70) + bg_color = self._selected_hover_color + else: + bg_color = self._selected_color else: item_rect.setTop(item_rect.top() + (self.bar_height / 2)) if option.state & QtWidgets.QStyle.State_MouseOver: - bg_color.setAlpha(100) + bg_color = self._hover_color else: + bg_color = QtGui.QColor() bg_color.setAlpha(0) # When not needed to do a rounded corners (easier and without From ba97477f1102551bb32cecbf0747a9d064238d5c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 20 Oct 2021 19:26:19 +0200 Subject: [PATCH 49/86] fix resources for maya --- openpype/style/pyside2_resources.py | 929 ++++++++++++++-------------- 1 file changed, 453 insertions(+), 476 deletions(-) diff --git a/openpype/style/pyside2_resources.py b/openpype/style/pyside2_resources.py index ee68a74b8e..c7328e7c91 100644 --- a/openpype/style/pyside2_resources.py +++ b/openpype/style/pyside2_resources.py @@ -1,24 +1,15 @@ -# Resource object code (Python 3) -# Created by: object code -# Created by: The Resource Compiler for Qt version 5.15.2 +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created: Wed Oct 20 19:25:24 2021 +# by: The Resource Compiler for PySide2 (Qt v5.12.5) +# # WARNING! All changes made in this file will be lost! from PySide2 import QtCore - qt_resource_data = b"\ -\x00\x00\x00\x9f\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x14\x1f\xf9\ -#\xd9\x0b\x00\x00\x00#IDAT\x08\xd7c`\xc0\ -\x0d\xe6|\x80\xb1\x18\x91\x05R\x04\xe0B\x08\x15)\x02\ -\x0c\x0c\x8c\xc8\x02\x08\x95h\x00\x00\xac\xac\x07\x90Ne\ -4\xac\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x00\xa6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -45,31 +36,6 @@ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ 200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ \xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ \xaeB`\x82\ -\x00\x00\x00\xa5\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ -\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ -200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ -\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ -\xaeB`\x82\ -\x00\x00\x00\xa0\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f\x0d\xfc\ -R+\x9c\x00\x00\x00$IDAT\x08\xd7c`@\ -\x05s>\xc0XL\xc8\x5c&dY&d\xc5pN\ -\x8a\x00\x9c\x93\x22\x80a\x1a\x0a\x00\x00)\x95\x08\xaf\x88\ -\xac\xba4\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x00\xa6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -83,158 +49,43 @@ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ d``b``4D\xe2 s\x19\x90\x8d@\x02\ \x00d@\x09u\x86\xb3\xad\x9c\x00\x00\x00\x00IEN\ D\xaeB`\x82\ -\x00\x00\x00\x9e\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ +\x00\x00\x00\x9f\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ \x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ -\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ -\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ -\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ -\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\x9e\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ -\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ -\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ -\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ -\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x07\x06\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ -\x00\x00\x04\xb0iTXtXML:com.\ -adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0a\x85\x9d\x9f\x08\x00\x00\x01\x83\ -iCCPsRGB IEC6196\ -6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ -\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ -\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ -x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ -Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ -;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ -\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ -\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ -\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ -\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ -RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ -?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ -\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ -\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ -\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ -\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ -\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ -\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ -vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ -\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ -8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ -S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ -\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ -Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00mIDAT\x18\x95u\xcf\xc1\x09\xc2P\ -\x10\x84\xe1\xd7\x85\x07\x9b\xd0C@\xd2\x82x\x14{0\ -W!\x8d\x84`?bKzH\xcc\x97\x83\xfb0\x04\ -\xdf\x9c\x86\x7fg\x99\xdd\x84\x0d\xaaT\x10jl\x13\x1e\ -\xbe\xba\xfe\x0951{\xe6\x8d\x0f&\x1c\x17\xa1S\xb0\ -\x11\x87\x0c/\x01\x07\xec\xb0\x0f?\xe1\xbc\xaei\xa3\xe6\ -\x85w\xf8[\xe9\xf0\xbb\x9f\xfa\xd2\x839\xdc\xa3[\xf3\ -\x19.\xa8\x89\xb50\xf7C\xa0\x00\x00\x00\x00IEN\ -D\xaeB`\x82\ -\x00\x00\x00\xa6\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x14\x1f\xf9\ +#\xd9\x0b\x00\x00\x00#IDAT\x08\xd7c`\xc0\ +\x0d\xe6|\x80\xb1\x18\x91\x05R\x04\xe0B\x08\x15)\x02\ +\x0c\x0c\x8c\xc8\x02\x08\x95h\x00\x00\xac\xac\x07\x90Ne\ +4\xac\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa0\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ \x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f \xb9\ -\x8dw\xe9\x00\x00\x00*IDAT\x08\xd7c`\xc0\ -\x06\xe6|```B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ -d``b`H\x11@\xe2 s\x19\x90\x8d@\x02\ -\x00#\xed\x08\xafd\x9f\x0f\x15\x00\x00\x00\x00IEN\ -D\xaeB`\x82\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ +\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ +\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ +\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x07\xdd\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -363,6 +214,289 @@ zpp\xf0\xe3\x0e.\xa4\xd2\xae\xf0\x8a\xf7\x9a\xe3V\ q[s\x5c@H\xa5\xdda\x81\x0d\x9ek\x8e\xff\xfd\ \xcf?\xcc1\xe9\x01\x1c\x00sR-q\xe4J\x1bi\ \x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f \xb9\ +\x8dw\xe9\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x06\xe6|```B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ +d``b`H\x11@\xe2 s\x19\x90\x8d@\x02\ +\x00#\xed\x08\xafd\x9f\x0f\x15\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa0\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ +\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ +\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ +\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x07\x06\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ +\x00\x00\x04\xb0iTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0a\x85\x9d\x9f\x08\x00\x00\x01\x83\ +iCCPsRGB IEC6196\ +6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ +\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ +\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ +x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ +Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ +;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ +\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ +\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ +\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ +\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ +RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ +?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ +\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ +\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ +\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ +\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ +\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ +\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ +vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ +\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ +8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ +S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ +\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ +Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00mIDAT\x18\x95u\xcf\xc1\x09\xc2P\ +\x10\x84\xe1\xd7\x85\x07\x9b\xd0C@\xd2\x82x\x14{0\ +W!\x8d\x84`?bKzH\xcc\x97\x83\xfb0\x04\ +\xdf\x9c\x86\x7fg\x99\xdd\x84\x0d\xaaT\x10jl\x13\x1e\ +\xbe\xba\xfe\x0951{\xe6\x8d\x0f&\x1c\x17\xa1S\xb0\ +\x11\x87\x0c/\x01\x07\xec\xb0\x0f?\xe1\xbc\xaei\xa3\xe6\ +\x85w\xf8[\xe9\xf0\xbb\x9f\xfa\xd2\x839\xdc\xa3[\xf3\ +\x19.\xa8\x89\xb50\xf7C\xa0\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ +\x00\x00\x070\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ +\x00\x00\x04\xb0iTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0aH\x8b[^\x00\x00\x01\x83\ +iCCPsRGB IEC6196\ +6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ +\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ +\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ +x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ +Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ +;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ +\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ +\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ +\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ +\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ +RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ +?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ +\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ +\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ +\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ +\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ +\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ +\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ +vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ +\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ +8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ +S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ +\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ +Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x97IDAT\x18\x95m\xcf\xb1j\x02A\ +\x14\x85\xe1o\xb7\xb6\xd0'H=Vi\x03\xb1\xb4H\ +;l\xa5\xf19\xf6Y\x02VB\xbaa\x0a\x0b;\x1b\ +\x1bkA\x18\x02)m\xe3\xbe\x82\xcd\x06\x16\xd9\xdb\xdd\ +\x9f\xff\x5c\xee\xa9b*\x13Ls\x13nF&\xa6\xf2\ +\x82\xaeF\x8b\xdf\x98\xca\xfb\x88\xb4\xc0\x0f\xda\x1a[t\ +\xd8\xc7T\xc2@\x9ac\x8f?|U=|\xc5\x09w\ +\xbc\xa1\xc2\x193,r\x13.\xd5\xe0\xc2\x12\x07\x5cQ\ +#\xe0#7\xe1\xa8O\x0e\x7f\xda`\xd7\xaf\x9f\xb9\x09\ +\xdfc\x05\xff\xe5uLe\xf5\xcc\x1f\x0d3,\x83\xb6\ +\x06D\x83\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x07\xad\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -488,6 +622,55 @@ v)`\x8b\x07>\xa8\xe6\xd1\xfe\x0b\x9d\x85\x8eW\x0d\ ^x\xa2\x9e\x0e\xa7 tG9\x1d\xf6\xe1\x95+\xd6\ \xb1D\x8e\x0e\xcbX\xf0\x0fR\x8ay\x18\xdc\xe2\x02p\ \x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa0\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f\x0d\xfc\ +R+\x9c\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05s>\xc0XL\xc8\x5c&dY&d\xc5pN\ +\x8a\x00\x9c\x93\x22\x80a\x1a\x0a\x00\x00)\x95\x08\xaf\x88\ +\xac\xba4\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x9e\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ +\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ +\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ +\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ +\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x9e\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ +\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ +\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ +\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ +\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ \x00\x00\x00\xa6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -501,186 +684,6 @@ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ d``b``4D\xe2 s\x19\x90\x8d@\x02\ \x00d@\x09u\x86\xb3\xad\x9c\x00\x00\x00\x00IEN\ D\xaeB`\x82\ -\x00\x00\x00\xa5\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ -\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ -200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ -\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ -\xaeB`\x82\ -\x00\x00\x00\xa0\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ -\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ -\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ -\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ -\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x070\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ -\x00\x00\x04\xb0iTXtXML:com.\ -adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0aH\x8b[^\x00\x00\x01\x83\ -iCCPsRGB IEC6196\ -6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ -\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ -\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ -x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ -Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ -;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ -\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ -\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ -\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ -\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ -RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ -?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ -\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ -\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ -\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ -\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ -\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ -\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ -vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ -\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ -8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ -S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ -\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ -Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x97IDAT\x18\x95m\xcf\xb1j\x02A\ -\x14\x85\xe1o\xb7\xb6\xd0'H=Vi\x03\xb1\xb4H\ -;l\xa5\xf19\xf6Y\x02VB\xbaa\x0a\x0b;\x1b\ -\x1bkA\x18\x02)m\xe3\xbe\x82\xcd\x06\x16\xd9\xdb\xdd\ -\x9f\xff\x5c\xee\xa9b*\x13Ls\x13nF&\xa6\xf2\ -\x82\xaeF\x8b\xdf\x98\xca\xfb\x88\xb4\xc0\x0f\xda\x1a[t\ -\xd8\xc7T\xc2@\x9ac\x8f?|U=|\xc5\x09w\ -\xbc\xa1\xc2\x193,r\x13.\xd5\xe0\xc2\x12\x07\x5cQ\ -#\xe0#7\xe1\xa8O\x0e\x7f\xda`\xd7\xaf\x9f\xb9\x09\ -\xdfc\x05\xff\xe5uLe\xf5\xcc\x1f\x0d3,\x83\xb6\ -\x06D\x83\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\xa6\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ -;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ -\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ -\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ -D\xaeB`\x82\ -\x00\x00\x00\xa0\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ -\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ -\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ -\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ -\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\xa6\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ -;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ -\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ -\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ -D\xaeB`\x82\ " qt_resource_name = b"\ @@ -693,61 +696,15 @@ qt_resource_name = b"\ \x00i\ \x00m\x00a\x00g\x00e\x00s\ \x00\x15\ -\x0f\xf3\xc0\x07\ -\x00u\ -\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\ -\x00.\x00p\x00n\x00g\ -\x00\x12\ -\x01.\x03'\ +\x03'rg\ \x00c\ -\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\ -\x00g\ -\x00\x0e\ -\x04\xa2\xfc\xa7\ -\x00d\ -\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\ +\x00.\x00p\x00n\x00g\ \x00\x1b\ \x03Z2'\ \x00c\ \x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\ \x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ -\x00\x18\ -\x03\x8e\xdeg\ -\x00r\ -\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\ -\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ -\x00\x11\ -\x00\xb8\x8c\x07\ -\x00l\ -\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ -\ -\x00\x0f\ -\x01s\x8b\x07\ -\x00u\ -\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ -\x00\x0c\ -\x06\xe6\xe6g\ -\x00u\ -\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ -\x00\x0f\ -\x06S%\xa7\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00.\x00p\x00n\x00g\ -\x00\x17\ -\x0ce\xce\x07\ -\x00l\ -\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ -\x00e\x00d\x00.\x00p\x00n\x00g\ -\x00\x14\ -\x04^-\xa7\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00_\x00o\x00n\x00.\ -\x00p\x00n\x00g\ -\x00\x11\ -\x0b\xda0\xa7\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00.\x00p\x00n\x00g\ -\ \x00\x0e\ \x0e\xde\xfa\xc7\ \x00l\ @@ -757,87 +714,107 @@ qt_resource_name = b"\ \x00d\ \x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ \ -\x00\x0f\ -\x02\x9f\x05\x87\ -\x00r\ -\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ -\x00\x12\ -\x05\x8f\x9d\x07\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00_\x00o\x00n\x00.\x00p\x00n\ -\x00g\ -\x00\x17\ -\x0c\xabQ\x07\ -\x00d\ -\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ -\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x15\ +\x0f\xf3\xc0\x07\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\ +\x00.\x00p\x00n\x00g\ \x00\x12\ \x03\x8d\x04G\ \x00r\ \x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\ \x00g\ -\x00\x15\ -\x03'rg\ +\x00\x14\ +\x04^-\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00_\x00o\x00n\x00.\ +\x00p\x00n\x00g\ +\x00\x17\ +\x0ce\xce\x07\ +\x00l\ +\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ +\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x02\x9f\x05\x87\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x06S%\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00.\x00p\x00n\x00g\ +\x00\x12\ +\x01.\x03'\ \x00c\ -\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\ -\x00.\x00p\x00n\x00g\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\ +\x00g\ +\x00\x0e\ +\x04\xa2\xfc\xa7\ +\x00d\ +\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x12\ +\x05\x8f\x9d\x07\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00_\x00o\x00n\x00.\x00p\x00n\ +\x00g\ +\x00\x11\ +\x0b\xda0\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00.\x00p\x00n\x00g\ +\ +\x00\x18\ +\x03\x8e\xdeg\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\ +\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x01s\x8b\x07\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ +\x00\x0c\ +\x06\xe6\xe6g\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x17\ +\x0c\xabQ\x07\ +\x00d\ +\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ +\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x11\ +\x00\xb8\x8c\x07\ +\x00l\ +\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ +\ " qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x16\x00\x02\x00\x00\x00\x13\x00\x00\x00\x03\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x01\x16\x00\x00\x00\x00\x00\x01\x00\x00\x03C\ -\x00\x00\x01vA\x9d\xa25\ -\x00\x00\x02P\x00\x00\x00\x00\x00\x01\x00\x00\x1d!\ -\x00\x00\x01vA\x9d\xa25\ -\x00\x00\x00X\x00\x00\x00\x00\x00\x01\x00\x00\x00\xa3\ -\x00\x00\x01y\xb4r\xcc\x9c\ -\x00\x00\x01>\x00\x00\x00\x00\x00\x01\x00\x00\x03\xed\ -\x00\x00\x01vA\x9d\xa29\ -\x00\x00\x02x\x00\x00\x00\x00\x00\x01\x00\x00\x1d\xca\ -\x00\x00\x01vA\x9d\xa27\ -\x00\x00\x03$\x00\x00\x00\x00\x00\x01\x00\x00&\xf0\ -\x00\x00\x01y\xb4r\xcc\x9c\ -\x00\x00\x00\xa4\x00\x00\x00\x00\x00\x01\x00\x00\x01\xf6\ -\x00\x00\x01y\xb4r\xcc\x9c\ -\x00\x00\x02\xfa\x00\x00\x00\x00\x00\x01\x00\x00&L\ -\x00\x00\x01vA\x9d\xa27\ -\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x01\x00\x00\x02\x9f\ -\x00\x00\x01vA\x9d\xa27\ -\x00\x00\x01\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xe5\ -\x00\x00\x01y\xc2\x05+`\ -\x00\x00\x00\x82\x00\x00\x00\x00\x00\x01\x00\x00\x01M\ -\x00\x00\x01vA\x9d\xa25\ -\x00\x00\x02\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x1en\ -\x00\x00\x01y\xc1\xfc\x16\x91\ -\x00\x00\x01\x80\x00\x00\x00\x00\x00\x01\x00\x00\x051\ -\x00\x00\x01y\xc1\xf9Kx\ -\x00\x00\x01b\x00\x00\x00\x00\x00\x01\x00\x00\x04\x8f\ -\x00\x00\x01vA\x9d\xa29\ -\x00\x00\x02\x06\x00\x00\x00\x00\x00\x01\x00\x00\x14\xc6\ -\x00\x00\x01y\xc2\x05\x91*\ -\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x00\x0c;\ -\x00\x00\x01vA\x9d\xa25\ -\x00\x00\x02\xc6\x00\x00\x00\x00\x00\x01\x00\x00%\xa2\ -\x00\x00\x01vA\x9d\xa25\ -\x00\x00\x02.\x00\x00\x00\x00\x00\x01\x00\x00\x1cw\ -\x00\x00\x01vA\x9d\xa25\ +\x00\x00\x03,\x00\x00\x00\x00\x00\x01\x00\x00&\xf0\ +\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x01\xfd\ +\x00\x00\x01\xe2\x00\x00\x00\x00\x00\x01\x00\x00\x14&\ +\x00\x00\x02\xb6\x00\x00\x00\x00\x00\x01\x00\x00%\x02\ +\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0cx\ \x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01vA\x9d\xa29\ +\x00\x00\x00X\x00\x00\x00\x00\x00\x01\x00\x00\x00\xaa\ +\x00\x00\x01\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x03I\ +\x00\x00\x02\x80\x00\x00\x00\x00\x00\x01\x00\x00$^\ +\x00\x00\x018\x00\x00\x00\x00\x00\x01\x00\x00\x03\xed\ +\x00\x00\x02\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x14\xd0\ +\x00\x00\x02.\x00\x00\x00\x00\x00\x01\x00\x00\x15y\ +\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x0d\x1c\ +\x00\x00\x02\xda\x00\x00\x00\x00\x00\x01\x00\x00%\xa4\ +\x00\x00\x02X\x00\x00\x00\x00\x00\x01\x00\x00\x1c\xad\ +\x00\x00\x01f\x00\x00\x00\x00\x00\x01\x00\x00\x0b\xce\ +\x00\x00\x02\xf8\x00\x00\x00\x00\x00\x01\x00\x00&F\ +\x00\x00\x00\x94\x00\x00\x00\x00\x00\x01\x00\x00\x01S\ +\x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00\x02\xa6\ " - def qInitResources(): - QtCore.qRegisterResourceData( - 0x03, qt_resource_struct, qt_resource_name, qt_resource_data - ) - + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) def qCleanupResources(): - QtCore.qUnregisterResourceData( - 0x03, qt_resource_struct, qt_resource_name, qt_resource_data - ) + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() From 62c411f585ee59c5fc53c22f7a38bde825b56e52 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 21 Oct 2021 10:06:32 +0200 Subject: [PATCH 50/86] fix typo in ci --- tools/ci_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_tools.py b/tools/ci_tools.py index 337b19a346..e5ca0c2c28 100644 --- a/tools/ci_tools.py +++ b/tools/ci_tools.py @@ -27,7 +27,7 @@ def get_release_type_github(Log, github_token): return "minor" if any(label in labels for label in patch_labels): - return "path" + return "patch" return None From 08971bb73ccd34e2f787d6c3c1042e2a9fbc9ca7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Oct 2021 08:23:02 +0000 Subject: [PATCH 51/86] Bump pillow from 8.2.0 to 8.3.2 Bumps [pillow](https://github.com/python-pillow/Pillow) from 8.2.0 to 8.3.2. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/8.2.0...8.3.2) --- updated-dependencies: - dependency-name: pillow dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- poetry.lock | 94 +++++++++++++++++++++++++++++++------------------- pyproject.toml | 2 +- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/poetry.lock b/poetry.lock index e5f5919a01..36105f4213 100644 --- a/poetry.lock +++ b/poetry.lock @@ -782,7 +782,7 @@ six = "*" [[package]] name = "pillow" -version = "8.2.0" +version = "8.3.2" description = "Python Imaging Library (Fork)" category = "main" optional = false @@ -1538,7 +1538,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "ff2bfa35a7304378917a0c25d7d7af9f81a130288d95789bdf7429f071e80b69" +content-hash = "fb6db80d126fe7ef2d1d06d0381b6d11445d6d3e54b33585f6b0a0b6b0b9d372" [metadata.files] acre = [] @@ -2058,40 +2058,59 @@ pathlib2 = [ {file = "pathlib2-2.3.5.tar.gz", hash = "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"}, ] pillow = [ - {file = "Pillow-8.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:dc38f57d8f20f06dd7c3161c59ca2c86893632623f33a42d592f097b00f720a9"}, - {file = "Pillow-8.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a013cbe25d20c2e0c4e85a9daf438f85121a4d0344ddc76e33fd7e3965d9af4b"}, - {file = "Pillow-8.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8bb1e155a74e1bfbacd84555ea62fa21c58e0b4e7e6b20e4447b8d07990ac78b"}, - {file = "Pillow-8.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5236606e8570542ed424849f7852a0ff0bce2c4c8d0ba05cc202a5a9c97dee9"}, - {file = "Pillow-8.2.0-cp36-cp36m-win32.whl", hash = "sha256:12e5e7471f9b637762453da74e390e56cc43e486a88289995c1f4c1dc0bfe727"}, - {file = "Pillow-8.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5afe6b237a0b81bd54b53f835a153770802f164c5570bab5e005aad693dab87f"}, - {file = "Pillow-8.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:cb7a09e173903541fa888ba010c345893cd9fc1b5891aaf060f6ca77b6a3722d"}, - {file = "Pillow-8.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0d19d70ee7c2ba97631bae1e7d4725cdb2ecf238178096e8c82ee481e189168a"}, - {file = "Pillow-8.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:083781abd261bdabf090ad07bb69f8f5599943ddb539d64497ed021b2a67e5a9"}, - {file = "Pillow-8.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c6b39294464b03457f9064e98c124e09008b35a62e3189d3513e5148611c9388"}, - {file = "Pillow-8.2.0-cp37-cp37m-win32.whl", hash = "sha256:01425106e4e8cee195a411f729cff2a7d61813b0b11737c12bd5991f5f14bcd5"}, - {file = "Pillow-8.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3b570f84a6161cf8865c4e08adf629441f56e32f180f7aa4ccbd2e0a5a02cba2"}, - {file = "Pillow-8.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:031a6c88c77d08aab84fecc05c3cde8414cd6f8406f4d2b16fed1e97634cc8a4"}, - {file = "Pillow-8.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:66cc56579fd91f517290ab02c51e3a80f581aba45fd924fcdee01fa06e635812"}, - {file = "Pillow-8.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c32cc3145928c4305d142ebec682419a6c0a8ce9e33db900027ddca1ec39178"}, - {file = "Pillow-8.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:624b977355cde8b065f6d51b98497d6cd5fbdd4f36405f7a8790e3376125e2bb"}, - {file = "Pillow-8.2.0-cp38-cp38-win32.whl", hash = "sha256:5cbf3e3b1014dddc45496e8cf38b9f099c95a326275885199f427825c6522232"}, - {file = "Pillow-8.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:463822e2f0d81459e113372a168f2ff59723e78528f91f0bd25680ac185cf797"}, - {file = "Pillow-8.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:95d5ef984eff897850f3a83883363da64aae1000e79cb3c321915468e8c6add5"}, - {file = "Pillow-8.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b91c36492a4bbb1ee855b7d16fe51379e5f96b85692dc8210831fbb24c43e484"}, - {file = "Pillow-8.2.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d68cb92c408261f806b15923834203f024110a2e2872ecb0bd2a110f89d3c602"}, - {file = "Pillow-8.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f217c3954ce5fd88303fc0c317af55d5e0204106d86dea17eb8205700d47dec2"}, - {file = "Pillow-8.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5b70110acb39f3aff6b74cf09bb4169b167e2660dabc304c1e25b6555fa781ef"}, - {file = "Pillow-8.2.0-cp39-cp39-win32.whl", hash = "sha256:a7d5e9fad90eff8f6f6106d3b98b553a88b6f976e51fce287192a5d2d5363713"}, - {file = "Pillow-8.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c"}, - {file = "Pillow-8.2.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0e04d61f0064b545b989126197930807c86bcbd4534d39168f4aa5fda39bb8f9"}, - {file = "Pillow-8.2.0-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:63728564c1410d99e6d1ae8e3b810fe012bc440952168af0a2877e8ff5ab96b9"}, - {file = "Pillow-8.2.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c03c07ed32c5324939b19e36ae5f75c660c81461e312a41aea30acdd46f93a7c"}, - {file = "Pillow-8.2.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:4d98abdd6b1e3bf1a1cbb14c3895226816e666749ac040c4e2554231068c639b"}, - {file = "Pillow-8.2.0-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:aac00e4bc94d1b7813fe882c28990c1bc2f9d0e1aa765a5f2b516e8a6a16a9e4"}, - {file = "Pillow-8.2.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:22fd0f42ad15dfdde6c581347eaa4adb9a6fc4b865f90b23378aa7914895e120"}, - {file = "Pillow-8.2.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:e98eca29a05913e82177b3ba3d198b1728e164869c613d76d0de4bde6768a50e"}, - {file = "Pillow-8.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8b56553c0345ad6dcb2e9b433ae47d67f95fc23fe28a0bde15a120f25257e291"}, - {file = "Pillow-8.2.0.tar.gz", hash = "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, + {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, + {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, + {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, + {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, + {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, + {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, + {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, + {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, + {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, + {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, + {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, + {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, + {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, ] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, @@ -2294,6 +2313,7 @@ pynput = [ pyobjc-core = [ {file = "pyobjc-core-7.3.tar.gz", hash = "sha256:5081aedf8bb40aac1a8ad95adac9e44e148a882686ded614adf46bb67fd67574"}, {file = "pyobjc_core-7.3-1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a1f1e6b457127cbf2b5bd2b94520a7c89fb590b739911eadb2b0499a3a5b0e6f"}, + {file = "pyobjc_core-7.3-1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:ed708cc47bae8b711f81f252af09898a5f986c7a38cec5ad5623d571d328bff8"}, {file = "pyobjc_core-7.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4e93ad769a20b908778fe950f62a843a6d8f0fa71996e5f3cc9fab5ae7d17771"}, {file = "pyobjc_core-7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f63fd37bbf3785af4ddb2f86cad5ca81c62cfc7d1c0099637ca18343c3656c1"}, {file = "pyobjc_core-7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9b1311f72f2e170742a7ee3a8149f52c35158dc024a21e88d6f1e52ba5d718b"}, @@ -2303,6 +2323,7 @@ pyobjc-core = [ pyobjc-framework-cocoa = [ {file = "pyobjc-framework-Cocoa-7.3.tar.gz", hash = "sha256:b18d05e7a795a3455ad191c3e43d6bfa673c2a4fd480bb1ccf57191051b80b7e"}, {file = "pyobjc_framework_Cocoa-7.3-1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1e31376806e5de883a1d7c7c87d9ff2a8b09fc05d267e0dfce6e42409fb70c67"}, + {file = "pyobjc_framework_Cocoa-7.3-1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d999387927284346035cb63ebb51f86331abc41f9376f9a6970e7f18207db392"}, {file = "pyobjc_framework_Cocoa-7.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9edffdfa6dd1f71f21b531c3e61fdd3e4d5d3bf6c5a528c98e88828cd60bac11"}, {file = "pyobjc_framework_Cocoa-7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:35a6340437a4e0109a302150b7d1f6baf57004ccf74834f9e6062fcafe2fd8d7"}, {file = "pyobjc_framework_Cocoa-7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c3886f2608ab3ed02482f8b2ebf9f782b324c559e84b52cfd92dba8a1109872"}, @@ -2312,6 +2333,7 @@ pyobjc-framework-cocoa = [ pyobjc-framework-quartz = [ {file = "pyobjc-framework-Quartz-7.3.tar.gz", hash = "sha256:98812844c34262def980bdf60923a875cd43428a8375b6fd53bd2cd800eccf0b"}, {file = "pyobjc_framework_Quartz-7.3-1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1139bc6874c0f8b58f0b8602015e0994198bc506a6bcec1071208de32b55ed26"}, + {file = "pyobjc_framework_Quartz-7.3-1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d94a3ed7051266c52392ec07d3b5adbf28d4be83341a24df0d88639344dcd84f"}, {file = "pyobjc_framework_Quartz-7.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ef18f5a16511ded65980bf4f5983ea5d35c88224dbad1b3112abd29c60413ea"}, {file = "pyobjc_framework_Quartz-7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b41eec8d4b10c7c7e011e2f9051367f5499ef315ba52dfbae573c3a2e05469c"}, {file = "pyobjc_framework_Quartz-7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c65456ed045dfe1711d0298734e5a3ad670f8c770f7eb3b19979256c388bdd2"}, diff --git a/pyproject.toml b/pyproject.toml index 085538d306..dade0a2f57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ jsonschema = "^3.2.0" keyring = "^22.0.1" log4mongo = "^1.7" pathlib2= "^2.3.5" # deadline submit publish job only (single place, maybe not needed?) -Pillow = "^8.1" # only used for slates prototype +Pillow = "^8.3" # only used for slates prototype pyblish-base = "^1.8.8" pynput = "^1.7.2" # idle manager in tray pymongo = "^3.11.2" From e47ed5e77713a970c3332cbc0ecf14be9e14cece Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 10:41:48 +0200 Subject: [PATCH 52/86] safer library loader action handling --- openpype/modules/default_modules/avalon_apps/avalon_app.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/modules/default_modules/avalon_apps/avalon_app.py b/openpype/modules/default_modules/avalon_apps/avalon_app.py index d21b37e520..a8e102f447 100644 --- a/openpype/modules/default_modules/avalon_apps/avalon_app.py +++ b/openpype/modules/default_modules/avalon_apps/avalon_app.py @@ -70,6 +70,9 @@ class AvalonModule(OpenPypeModule, ITrayModule): # Definition of Tray menu def tray_menu(self, tray_menu): + if self.libraryloader is None: + return + from Qt import QtWidgets # Actions action_library_loader = QtWidgets.QAction( @@ -87,6 +90,9 @@ class AvalonModule(OpenPypeModule, ITrayModule): return def show_library_loader(self): + if self.libraryloader is None: + return + self.libraryloader.show() # Raise and activate the window From 68ff9ea9c963df63a42594e0578c8bd7a210c88b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 10:43:02 +0200 Subject: [PATCH 53/86] converted library loader to be created same way as loader --- openpype/tools/libraryloader/app.py | 335 ++++++++++++++-------------- 1 file changed, 172 insertions(+), 163 deletions(-) diff --git a/openpype/tools/libraryloader/app.py b/openpype/tools/libraryloader/app.py index 3f11157418..69c5cb61e7 100644 --- a/openpype/tools/libraryloader/app.py +++ b/openpype/tools/libraryloader/app.py @@ -2,8 +2,8 @@ import sys from Qt import QtWidgets, QtCore, QtGui -from avalon import style from avalon.api import AvalonMongoDB +from openpype import style from openpype.tools.utils import lib as tools_lib from openpype.tools.loader.widgets import ( ThumbnailWidget, @@ -28,6 +28,8 @@ class LibraryLoaderWindow(QtWidgets.QDialog): tool_title = "Library Loader 0.5" tool_name = "library_loader" + message_timeout = 5000 + def __init__( self, parent=None, icon=None, show_projects=False, show_libraries=True ): @@ -36,6 +38,20 @@ class LibraryLoaderWindow(QtWidgets.QDialog): self._initial_refresh = False self._ignore_project_change = False + dbcon = AvalonMongoDB() + dbcon.install() + dbcon.Session["AVALON_PROJECT"] = None + + self.dbcon = dbcon + + self.show_projects = show_projects + self.show_libraries = show_libraries + + # Groups config + self.groups_config = tools_lib.GroupsConfig(dbcon) + self.family_config_cache = tools_lib.FamilyConfigCache(dbcon) + + # UI initialization # Enable minimize and maximize for app self.setWindowTitle(self.tool_title) window_flags = QtCore.Qt.Window @@ -43,140 +59,149 @@ class LibraryLoaderWindow(QtWidgets.QDialog): window_flags |= QtCore.Qt.WindowStaysOnTopHint self.setWindowFlags(window_flags) self.setFocusPolicy(QtCore.Qt.StrongFocus) - if icon is not None: - self.setWindowIcon(icon) - # self.setAttribute(QtCore.Qt.WA_DeleteOnClose) - body = QtWidgets.QWidget() - footer = QtWidgets.QWidget() - footer.setFixedHeight(20) + icon = QtGui.QIcon(style.app_icon_path()) + self.setWindowIcon(icon) - container = QtWidgets.QWidget() + main_splitter = QtWidgets.QSplitter(self) - self.dbcon = AvalonMongoDB() - self.dbcon.install() - self.dbcon.Session["AVALON_PROJECT"] = None + # --- Left part --- + left_side_splitter = QtWidgets.QSplitter(main_splitter) + left_side_splitter.setOrientation(QtCore.Qt.Vertical) - self.show_projects = show_projects - self.show_libraries = show_libraries + # Project combobox + projects_combobox = QtWidgets.QComboBox(left_side_splitter) + combobox_delegate = QtWidgets.QStyledItemDelegate(self) + projects_combobox.setItemDelegate(combobox_delegate) - # Groups config - self.groups_config = tools_lib.GroupsConfig(self.dbcon) - self.family_config_cache = tools_lib.FamilyConfigCache(self.dbcon) - - assets = AssetWidget( - self.dbcon, multiselection=True, parent=self + # Assets widget + assets_widget = AssetWidget( + dbcon, multiselection=True, parent=left_side_splitter ) - families = FamilyListView( - self.dbcon, self.family_config_cache, parent=self + + # Families widget + families_filter_view = FamilyListView( + dbcon, self.family_config_cache, left_side_splitter ) - subsets = LibrarySubsetWidget( - self.dbcon, + left_side_splitter.addWidget(projects_combobox) + left_side_splitter.addWidget(assets_widget) + left_side_splitter.addWidget(families_filter_view) + left_side_splitter.setStretchFactor(1, 65) + left_side_splitter.setStretchFactor(2, 35) + + # --- Middle part --- + # Subsets widget + subsets_widget = LibrarySubsetWidget( + dbcon, self.groups_config, self.family_config_cache, tool_name=self.tool_name, parent=self ) - version = VersionWidget(self.dbcon) - thumbnail = ThumbnailWidget(self.dbcon) - - # Project - self.combo_projects = QtWidgets.QComboBox() - - # Create splitter to show / hide family filters - asset_filter_splitter = QtWidgets.QSplitter() - asset_filter_splitter.setOrientation(QtCore.Qt.Vertical) - asset_filter_splitter.addWidget(self.combo_projects) - asset_filter_splitter.addWidget(assets) - asset_filter_splitter.addWidget(families) - asset_filter_splitter.setStretchFactor(1, 65) - asset_filter_splitter.setStretchFactor(2, 35) - - manager = ModulesManager() - sync_server = manager.modules_by_name["sync_server"] - - representations = RepresentationWidget(self.dbcon) - thumb_ver_splitter = QtWidgets.QSplitter() + # --- Right part --- + thumb_ver_splitter = QtWidgets.QSplitter(main_splitter) thumb_ver_splitter.setOrientation(QtCore.Qt.Vertical) - thumb_ver_splitter.addWidget(thumbnail) - thumb_ver_splitter.addWidget(version) - if sync_server.enabled: - thumb_ver_splitter.addWidget(representations) + + thumbnail_widget = ThumbnailWidget(dbcon, parent=thumb_ver_splitter) + version_info_widget = VersionWidget(dbcon, parent=thumb_ver_splitter) + + thumb_ver_splitter.addWidget(thumbnail_widget) + thumb_ver_splitter.addWidget(version_info_widget) + thumb_ver_splitter.setStretchFactor(0, 30) thumb_ver_splitter.setStretchFactor(1, 35) - container_layout = QtWidgets.QHBoxLayout(container) - container_layout.setContentsMargins(0, 0, 0, 0) - split = QtWidgets.QSplitter() - split.addWidget(asset_filter_splitter) - split.addWidget(subsets) - split.addWidget(thumb_ver_splitter) - split.setSizes([180, 950, 200]) - container_layout.addWidget(split) + manager = ModulesManager() + sync_server = manager.modules_by_name.get("sync_server") + sync_server_enabled = False + if sync_server is not None: + sync_server_enabled = sync_server.enabled - body_layout = QtWidgets.QHBoxLayout(body) - body_layout.addWidget(container) - body_layout.setContentsMargins(0, 0, 0, 0) + repres_widget = None + if sync_server_enabled: + repres_widget = RepresentationWidget( + dbcon, self.tool_name, parent=thumb_ver_splitter + ) + thumb_ver_splitter.addWidget(repres_widget) - message = QtWidgets.QLabel() - message.hide() + main_splitter.addWidget(left_side_splitter) + main_splitter.addWidget(subsets_widget) + main_splitter.addWidget(thumb_ver_splitter) - footer_layout = QtWidgets.QVBoxLayout(footer) - footer_layout.addWidget(message) + # --- Footer --- + footer_widget = QtWidgets.QWidget(self) + footer_widget.setFixedHeight(20) + + message_label = QtWidgets.QLabel(footer_widget) + + footer_layout = QtWidgets.QVBoxLayout(footer_widget) footer_layout.setContentsMargins(0, 0, 0, 0) + footer_layout.addWidget(message_label) layout = QtWidgets.QVBoxLayout(self) - layout.addWidget(body) - layout.addWidget(footer) + layout.addWidget(main_splitter) + layout.addWidget(footer_widget) self.data = { - "widgets": { - "families": families, - "assets": assets, - "subsets": subsets, - "version": version, - "thumbnail": thumbnail, - "representations": representations - }, - "label": { - "message": message, - }, "state": { "assetIds": None } } - families.active_changed.connect(subsets.set_family_filters) - assets.selection_changed.connect(self.on_assetschanged) - assets.refresh_triggered.connect(self.on_assetschanged) - assets.view.clicked.connect(self.on_assetview_click) - subsets.active_changed.connect(self.on_subsetschanged) - subsets.version_changed.connect(self.on_versionschanged) - subsets.refreshed.connect(self._on_subset_refresh) - self.combo_projects.currentTextChanged.connect(self.on_project_change) + message_timer = QtCore.QTimer() + message_timer.setInterval(self.message_timeout) + message_timer.setSingleShot(True) + + message_timer.timeout.connect(self._on_message_timeout) + + families_filter_view.active_changed.connect( + self._on_family_filter_change + ) + assets_widget.selection_changed.connect(self.on_assetschanged) + assets_widget.refresh_triggered.connect(self.on_assetschanged) + assets_widget.view.clicked.connect(self.on_assetview_click) + subsets_widget.active_changed.connect(self.on_subsetschanged) + subsets_widget.version_changed.connect(self.on_versionschanged) + subsets_widget.refreshed.connect(self._on_subset_refresh) + projects_combobox.currentTextChanged.connect(self.on_project_change) self.sync_server = sync_server + self._combobox_delegate = combobox_delegate + self._projects_combobox = projects_combobox + self._assets_widget = assets_widget + self._families_filter_view = families_filter_view + + self._subsets_widget = subsets_widget + + self._version_info_widget = version_info_widget + self._thumbnail_widget = thumbnail_widget + self._repres_widget = repres_widget + + self._message_label = message_label + self._message_timer = message_timer + # Set default thumbnail on start - thumbnail.set_thumbnail(None) + thumbnail_widget.set_thumbnail(None) # Defaults - if sync_server.enabled: - split.setSizes([250, 1000, 550]) + if sync_server_enabled: + main_splitter.setSizes([250, 1000, 550]) self.resize(1800, 900) else: - split.setSizes([250, 850, 200]) + main_splitter.setSizes([250, 850, 200]) self.resize(1300, 700) + self.setStyleSheet(style.load_stylesheet()) + def showEvent(self, event): super(LibraryLoaderWindow, self).showEvent(event) if not self._initial_refresh: self.refresh() def on_assetview_click(self, *args): - subsets_widget = self.data["widgets"]["subsets"] - selection_model = subsets_widget.view.selectionModel() + selection_model = self._subsets_widget.view.selectionModel() if selection_model.selectedIndexes(): selection_model.clearSelection() @@ -187,7 +212,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog): self._ignore_project_change = True # Cleanup - self.combo_projects.clear() + self._projects_combobox.clear() # Fill combobox with projects select_project_item = QtGui.QStandardItem("< Select project >") @@ -202,18 +227,18 @@ class LibraryLoaderWindow(QtWidgets.QDialog): item.setData(project_name, QtCore.Qt.UserRole + 1) combobox_items.append(item) - root_item = self.combo_projects.model().invisibleRootItem() + root_item = self._projects_combobox.model().invisibleRootItem() root_item.appendRows(combobox_items) index = 0 self._ignore_project_change = False if old_project_name: - index = self.combo_projects.findText( + index = self._projects_combobox.findText( old_project_name, QtCore.Qt.MatchFixedString ) - self.combo_projects.setCurrentIndex(index) + self._projects_combobox.setCurrentIndex(index) def get_filtered_projects(self): projects = list() @@ -231,8 +256,8 @@ class LibraryLoaderWindow(QtWidgets.QDialog): if self._ignore_project_change: return - row = self.combo_projects.currentIndex() - index = self.combo_projects.model().index(row, 0) + row = self._projects_combobox.currentIndex() + index = self._projects_combobox.model().index(row, 0) project_name = index.data(QtCore.Qt.UserRole + 1) self.dbcon.Session["AVALON_PROJECT"] = project_name @@ -245,11 +270,9 @@ class LibraryLoaderWindow(QtWidgets.QDialog): "Config `%s` has no function `install`" % _config.__name__ ) - subsets = self.data["widgets"]["subsets"] - representations = self.data["widgets"]["representations"] - - subsets.on_project_change(self.dbcon.Session["AVALON_PROJECT"]) - representations.on_project_change(self.dbcon.Session["AVALON_PROJECT"]) + self._subsets_widget.on_project_change(project_name) + if self._repres_widget: + self._repres_widget.on_project_change(project_name) self.family_config_cache.refresh() self.groups_config.refresh() @@ -263,13 +286,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog): @property def current_project(self): - if ( - not self.dbcon.active_project() or - self.dbcon.active_project() == "" - ): - return None - - return self.dbcon.active_project() + return self.dbcon.active_project() or None # ------------------------------- # Delay calling blocking methods @@ -292,12 +309,11 @@ class LibraryLoaderWindow(QtWidgets.QDialog): tools_lib.schedule(self._versionschanged, 150, channel="mongo") def _on_subset_refresh(self, has_item): - subsets_widget = self.data["widgets"]["subsets"] - families_view = self.data["widgets"]["families"] - - subsets_widget.set_loading_state(loading=False, empty=not has_item) - families = subsets_widget.get_subsets_families() - families_view.set_enabled_families(families) + self._subsets_widget.set_loading_state( + loading=False, empty=not has_item + ) + families = self._subsets_widget.get_subsets_families() + self._families_filter_view.set_enabled_families(families) def set_context(self, context, refresh=True): self.echo("Setting context: {}".format(context)) @@ -307,6 +323,9 @@ class LibraryLoaderWindow(QtWidgets.QDialog): ) # ------------------------------ + def _on_family_filter_change(self, families): + self._subsets_widget.set_family_filters(families) + def _refresh(self): if not self._initial_refresh: self._initial_refresh = True @@ -322,74 +341,69 @@ class LibraryLoaderWindow(QtWidgets.QDialog): ) assert project_doc, "This is a bug" - assets_widget = self.data["widgets"]["assets"] - families_view = self.data["widgets"]["families"] - families_view.set_enabled_families(set()) - families_view.refresh() + self._families_filter_view.set_enabled_families(set()) + self._families_filter_view.refresh() - assets_widget.model.stop_fetch_thread() - assets_widget.refresh() - assets_widget.setFocus() + self._assets_widget.model.stop_fetch_thread() + self._assets_widget.refresh() + self._assets_widget.setFocus() def clear_assets_underlines(self): last_asset_ids = self.data["state"]["assetIds"] if not last_asset_ids: return - assets_widget = self.data["widgets"]["assets"] - id_role = assets_widget.model.ObjectIdRole + assets_model = self._assets_widget.model + id_role = assets_model.ObjectIdRole - for index in tools_lib.iter_model_rows(assets_widget.model, 0): + for index in tools_lib.iter_model_rows(assets_model, 0): if index.data(id_role) not in last_asset_ids: continue - assets_widget.model.setData( - index, [], assets_widget.model.subsetColorsRole + assets_model.setData( + index, [], assets_model.subsetColorsRole ) def _assetschanged(self): """Selected assets have changed""" - assets_widget = self.data["widgets"]["assets"] - subsets_widget = self.data["widgets"]["subsets"] - subsets_model = subsets_widget.model + subsets_model = self._subsets_widget.model subsets_model.clear() self.clear_assets_underlines() if not self.dbcon.Session.get("AVALON_PROJECT"): - subsets_widget.set_loading_state( + self._subsets_widget.set_loading_state( loading=False, empty=True ) return # filter None docs they are silo - asset_docs = assets_widget.get_selected_assets() + asset_docs = self._assets_widget.get_selected_assets() if len(asset_docs) == 0: return asset_ids = [asset_doc["_id"] for asset_doc in asset_docs] # Start loading - subsets_widget.set_loading_state( + self._subsets_widget.set_loading_state( loading=bool(asset_ids), empty=True ) subsets_model.set_assets(asset_ids) - subsets_widget.view.setColumnHidden( + self._subsets_widget.view.setColumnHidden( subsets_model.Columns.index("asset"), len(asset_ids) < 2 ) # Clear the version information on asset change - self.data["widgets"]["version"].set_version(None) - self.data["widgets"]["thumbnail"].set_thumbnail(asset_docs) + self._version_info_widget.set_version(None) + self._thumbnail_widget.set_thumbnail(asset_docs) self.data["state"]["assetIds"] = asset_ids - representations = self.data["widgets"]["representations"] # reset repre list - representations.set_version_ids([]) + self._repres_widget.set_version_ids([]) def _subsetschanged(self): asset_ids = self.data["state"]["assetIds"] @@ -398,8 +412,9 @@ class LibraryLoaderWindow(QtWidgets.QDialog): self._versionschanged() return - subsets = self.data["widgets"]["subsets"] - selected_subsets = subsets.selected_subsets(_merged=True, _other=False) + selected_subsets = self._subsets_widget.selected_subsets( + _merged=True, _other=False + ) asset_models = {} asset_ids = [] @@ -420,26 +435,24 @@ class LibraryLoaderWindow(QtWidgets.QDialog): self.clear_assets_underlines() - assets_widget = self.data["widgets"]["assets"] - indexes = assets_widget.view.selectionModel().selectedRows() + indexes = self._assets_widget.view.selectionModel().selectedRows() + assets_model = self._assets_widget.model for index in indexes: - id = index.data(assets_widget.model.ObjectIdRole) + id = index.data(assets_model.ObjectIdRole) if id not in asset_models: continue - assets_widget.model.setData( - index, asset_models[id], assets_widget.model.subsetColorsRole + assets_model.setData( + index, asset_models[id], assets_model.subsetColorsRole ) # Trigger repaint - assets_widget.view.updateGeometries() + self._assets_widget.view.updateGeometries() # Set version in Version Widget self._versionschanged() def _versionschanged(self): - - subsets = self.data["widgets"]["subsets"] - selection = subsets.view.selectionModel() + selection = self._subsets_widget.view.selectionModel() # Active must be in the selected rows otherwise we # assume it's not actually an "active" current index. @@ -448,7 +461,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog): active = selection.currentIndex() rows = selection.selectedRows(column=active.column()) if active and active in rows: - item = active.data(subsets.model.ItemRole) + item = active.data(self._subsets_widget.model.ItemRole) if ( item is not None and not (item.get("isGroup") or item.get("isMerged")) @@ -460,7 +473,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog): for index in rows: if not index or not index.isValid(): continue - item = index.data(subsets.model.ItemRole) + item = index.data(self._subsets_widget.model.ItemRole) if ( item is None or item.get("isGroup") @@ -469,20 +482,18 @@ class LibraryLoaderWindow(QtWidgets.QDialog): continue version_docs.append(item["version_document"]) - self.data["widgets"]["version"].set_version(version_doc) + self._version_info_widget.set_version(version_doc) thumbnail_docs = version_docs if not thumbnail_docs: - assets_widget = self.data["widgets"]["assets"] - asset_docs = assets_widget.get_selected_assets() + asset_docs = self._assets_widget.get_selected_assets() if len(asset_docs) > 0: thumbnail_docs = asset_docs - self.data["widgets"]["thumbnail"].set_thumbnail(thumbnail_docs) + self._thumbnail_widget.set_thumbnail(thumbnail_docs) - representations = self.data["widgets"]["representations"] version_ids = [doc["_id"] for doc in version_docs or []] - representations.set_version_ids(version_ids) + self._repres_widget.set_version_ids(version_ids) def _set_context(self, context, refresh=True): """Set the selection in the interface using a context. @@ -510,16 +521,15 @@ class LibraryLoaderWindow(QtWidgets.QDialog): # scheduled refresh and the silo tabs are not shown. self._refresh_assets() - asset_widget = self.data["widgets"]["assets"] - asset_widget.select_assets(asset) + self._assets_widget.select_assets(asset) + + def _on_message_timeout(self): + self._message_label.setText("") def echo(self, message): - widget = self.data["label"]["message"] - widget.setText(str(message)) - widget.show() + self._message_label.setText(str(message)) print(message) - - tools_lib.schedule(widget.hide, 5000, channel="message") + self._message_timer.start() def closeEvent(self, event): # Kill on holding SHIFT @@ -576,7 +586,6 @@ def show( window = LibraryLoaderWindow( parent, icon, show_projects, show_libraries ) - window.setStyleSheet(style.load_stylesheet()) window.show() module.window = window From b642d770e58643af253e96e739aabe7b8a9d230b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 10:44:28 +0200 Subject: [PATCH 54/86] reorganize initialization --- openpype/tools/loader/app.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 955242e551..54eafd8f6d 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -3,7 +3,7 @@ import sys from Qt import QtWidgets, QtCore from avalon import api, io, pipeline -from openpype.style import load_stylesheet +from openpype import style from openpype.tools.utils.widgets import AssetWidget from openpype.tools.utils import lib @@ -96,15 +96,18 @@ class LoaderWindow(QtWidgets.QDialog): thumbnail_widget = ThumbnailWidget(io, parent=thumb_ver_splitter) version_info_widget = VersionWidget(io, parent=thumb_ver_splitter) + thumb_ver_splitter.addWidget(thumbnail_widget) + thumb_ver_splitter.addWidget(version_info_widget) + + thumb_ver_splitter.setStretchFactor(0, 30) + thumb_ver_splitter.setStretchFactor(1, 35) + manager = ModulesManager() sync_server = manager.modules_by_name.get("sync_server") sync_server_enabled = False if sync_server is not None: sync_server_enabled = sync_server.enabled - thumb_ver_splitter.addWidget(thumbnail_widget) - thumb_ver_splitter.addWidget(version_info_widget) - repres_widget = None if sync_server_enabled: repres_widget = RepresentationWidget( @@ -112,9 +115,6 @@ class LoaderWindow(QtWidgets.QDialog): ) thumb_ver_splitter.addWidget(repres_widget) - thumb_ver_splitter.setStretchFactor(0, 30) - thumb_ver_splitter.setStretchFactor(1, 35) - main_splitter.addWidget(left_side_splitter) main_splitter.addWidget(subsets_widget) main_splitter.addWidget(thumb_ver_splitter) @@ -193,7 +193,7 @@ class LoaderWindow(QtWidgets.QDialog): main_splitter.setSizes([250, 850, 200]) self.resize(1300, 700) - self.setStyleSheet(load_stylesheet()) + self.setStyleSheet(style.load_stylesheet()) def resizeEvent(self, event): super(LoaderWindow, self).resizeEvent(event) From 7cedb5af316288abbb9481a13f6e0951170a11e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 10:45:32 +0200 Subject: [PATCH 55/86] do not set stylesheets of library loader --- openpype/modules/default_modules/avalon_apps/avalon_app.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openpype/modules/default_modules/avalon_apps/avalon_app.py b/openpype/modules/default_modules/avalon_apps/avalon_app.py index a8e102f447..9e650a097e 100644 --- a/openpype/modules/default_modules/avalon_apps/avalon_app.py +++ b/openpype/modules/default_modules/avalon_apps/avalon_app.py @@ -1,6 +1,5 @@ import os import openpype -from openpype import resources from openpype.modules import OpenPypeModule from openpype_interfaces import ITrayModule @@ -52,16 +51,12 @@ class AvalonModule(OpenPypeModule, ITrayModule): def tray_init(self): # Add library tool try: - from Qt import QtGui - from avalon import style from openpype.tools.libraryloader import LibraryLoaderWindow self.libraryloader = LibraryLoaderWindow( - icon=QtGui.QIcon(resources.get_openpype_icon_filepath()), show_projects=True, show_libraries=True ) - self.libraryloader.setStyleSheet(style.load_stylesheet()) except Exception: self.log.warning( "Couldn't load Library loader tool for tray.", From 80b0b590b8c824123b687702c5de5180f038de1b Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 21 Oct 2021 11:27:35 +0100 Subject: [PATCH 56/86] Implemented deselect function to handle objects not in 'object mode' --- openpype/hosts/blender/api/plugin.py | 24 +++++++++++++++++++ .../hosts/blender/plugins/load/load_abc.py | 4 ++-- .../hosts/blender/plugins/load/load_fbx.py | 4 ++-- .../blender/plugins/load/load_layout_blend.py | 2 +- .../blender/plugins/load/load_layout_json.py | 2 +- .../hosts/blender/plugins/load/load_model.py | 6 ++--- .../hosts/blender/plugins/load/load_rig.py | 8 +++---- .../blender/plugins/publish/extract_abc.py | 4 ++-- .../blender/plugins/publish/extract_fbx.py | 6 +++-- 9 files changed, 43 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/blender/api/plugin.py b/openpype/hosts/blender/api/plugin.py index 50b73ade2b..181e5972a8 100644 --- a/openpype/hosts/blender/api/plugin.py +++ b/openpype/hosts/blender/api/plugin.py @@ -95,6 +95,30 @@ def get_local_collection_with_name(name): return None +def deselect_all(): + """Deselect all objects in the scene. + + Blender gives context error if trying to deselect object that it isn't + in object mode. + """ + modes = [] + active = bpy.context.view_layer.objects.active + + for obj in bpy.data.objects: + if obj.mode != 'OBJECT': + modes.append((obj, obj.mode)) + bpy.context.view_layer.objects.active = obj + bpy.ops.object.mode_set(mode = 'OBJECT') + + bpy.ops.object.select_all(action='DESELECT') + + for p in modes: + bpy.context.view_layer.objects.active = p[0] + bpy.ops.object.mode_set(mode = p[1]) + + bpy.context.view_layer.objects.active = active + + class Creator(PypeCreatorMixin, blender.Creator): pass diff --git a/openpype/hosts/blender/plugins/load/load_abc.py b/openpype/hosts/blender/plugins/load/load_abc.py index 92656fac9e..5969432c36 100644 --- a/openpype/hosts/blender/plugins/load/load_abc.py +++ b/openpype/hosts/blender/plugins/load/load_abc.py @@ -47,7 +47,7 @@ class CacheModelLoader(plugin.AssetLoader): bpy.data.objects.remove(empty) def _process(self, libpath, asset_group, group_name): - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() collection = bpy.context.view_layer.active_layer_collection.collection @@ -109,7 +109,7 @@ class CacheModelLoader(plugin.AssetLoader): avalon_info = obj[AVALON_PROPERTY] avalon_info.update({"container_name": group_name}) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() return objects diff --git a/openpype/hosts/blender/plugins/load/load_fbx.py b/openpype/hosts/blender/plugins/load/load_fbx.py index b80dc69adc..5f69aecb1a 100644 --- a/openpype/hosts/blender/plugins/load/load_fbx.py +++ b/openpype/hosts/blender/plugins/load/load_fbx.py @@ -46,7 +46,7 @@ class FbxModelLoader(plugin.AssetLoader): bpy.data.objects.remove(obj) def _process(self, libpath, asset_group, group_name, action): - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() collection = bpy.context.view_layer.active_layer_collection.collection @@ -112,7 +112,7 @@ class FbxModelLoader(plugin.AssetLoader): avalon_info = obj[AVALON_PROPERTY] avalon_info.update({"container_name": group_name}) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() return objects diff --git a/openpype/hosts/blender/plugins/load/load_layout_blend.py b/openpype/hosts/blender/plugins/load/load_layout_blend.py index 85cb4dfbd3..4c1f751a77 100644 --- a/openpype/hosts/blender/plugins/load/load_layout_blend.py +++ b/openpype/hosts/blender/plugins/load/load_layout_blend.py @@ -150,7 +150,7 @@ class BlendLayoutLoader(plugin.AssetLoader): bpy.data.orphans_purge(do_local_ids=False) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() return objects diff --git a/openpype/hosts/blender/plugins/load/load_layout_json.py b/openpype/hosts/blender/plugins/load/load_layout_json.py index 1a4dbbb5cb..38718fd9b2 100644 --- a/openpype/hosts/blender/plugins/load/load_layout_json.py +++ b/openpype/hosts/blender/plugins/load/load_layout_json.py @@ -59,7 +59,7 @@ class JsonLayoutLoader(plugin.AssetLoader): return None def _process(self, libpath, asset, asset_group, actions): - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() with open(libpath, "r") as fp: data = json.load(fp) diff --git a/openpype/hosts/blender/plugins/load/load_model.py b/openpype/hosts/blender/plugins/load/load_model.py index af5591c299..c33c656dec 100644 --- a/openpype/hosts/blender/plugins/load/load_model.py +++ b/openpype/hosts/blender/plugins/load/load_model.py @@ -93,7 +93,7 @@ class BlendModelLoader(plugin.AssetLoader): bpy.data.orphans_purge(do_local_ids=False) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() return objects @@ -126,7 +126,7 @@ class BlendModelLoader(plugin.AssetLoader): asset_group.empty_display_type = 'SINGLE_ARROW' avalon_container.objects.link(asset_group) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() if options is not None: parent = options.get('parent') @@ -158,7 +158,7 @@ class BlendModelLoader(plugin.AssetLoader): bpy.ops.object.parent_set(keep_transform=True) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() objects = self._process(libpath, asset_group, group_name) diff --git a/openpype/hosts/blender/plugins/load/load_rig.py b/openpype/hosts/blender/plugins/load/load_rig.py index 6062c293df..e80da8af45 100644 --- a/openpype/hosts/blender/plugins/load/load_rig.py +++ b/openpype/hosts/blender/plugins/load/load_rig.py @@ -156,7 +156,7 @@ class BlendRigLoader(plugin.AssetLoader): while bpy.data.orphans_purge(do_local_ids=False): pass - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() return objects @@ -191,7 +191,7 @@ class BlendRigLoader(plugin.AssetLoader): action = None - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() create_animation = False @@ -227,7 +227,7 @@ class BlendRigLoader(plugin.AssetLoader): bpy.ops.object.parent_set(keep_transform=True) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() objects = self._process(libpath, asset_group, group_name, action) @@ -250,7 +250,7 @@ class BlendRigLoader(plugin.AssetLoader): data={"dependencies": str(context["representation"]["_id"])} ) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() bpy.context.scene.collection.objects.link(asset_group) diff --git a/openpype/hosts/blender/plugins/publish/extract_abc.py b/openpype/hosts/blender/plugins/publish/extract_abc.py index 4696da3db4..b75bec4e28 100644 --- a/openpype/hosts/blender/plugins/publish/extract_abc.py +++ b/openpype/hosts/blender/plugins/publish/extract_abc.py @@ -28,7 +28,7 @@ class ExtractABC(api.Extractor): # Perform extraction self.log.info("Performing extraction..") - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() selected = [] asset_group = None @@ -50,7 +50,7 @@ class ExtractABC(api.Extractor): flatten=False ) - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/openpype/hosts/blender/plugins/publish/extract_fbx.py b/openpype/hosts/blender/plugins/publish/extract_fbx.py index b91f2a75ef..31d37da8e0 100644 --- a/openpype/hosts/blender/plugins/publish/extract_fbx.py +++ b/openpype/hosts/blender/plugins/publish/extract_fbx.py @@ -24,7 +24,7 @@ class ExtractFBX(api.Extractor): # Perform extraction self.log.info("Performing extraction..") - bpy.ops.object.select_all(action='DESELECT') + plugin.deselect_all() selected = [] asset_group = None @@ -60,7 +60,9 @@ class ExtractFBX(api.Extractor): add_leaf_bones=False ) - bpy.ops.object.select_all(action='DESELECT') + bpy.context.scene.unit_settings.scale_length = scale_length + + plugin.deselect_all() for mat in new_materials: bpy.data.materials.remove(mat) From a2397f48f032389184f8cee414c674cd8ae4d6c8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 12:40:33 +0200 Subject: [PATCH 57/86] set stylesheet on first show --- openpype/tools/libraryloader/app.py | 30 ++++++++++++++++------------- openpype/tools/loader/app.py | 8 +++++++- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/openpype/tools/libraryloader/app.py b/openpype/tools/libraryloader/app.py index 69c5cb61e7..700d3c05bd 100644 --- a/openpype/tools/libraryloader/app.py +++ b/openpype/tools/libraryloader/app.py @@ -35,6 +35,18 @@ class LibraryLoaderWindow(QtWidgets.QDialog): ): super(LibraryLoaderWindow, self).__init__(parent) + # Window modifications + self.setWindowTitle(self.tool_title) + window_flags = QtCore.Qt.Window + if not parent: + window_flags |= QtCore.Qt.WindowStaysOnTopHint + self.setWindowFlags(window_flags) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + icon = QtGui.QIcon(style.app_icon_path()) + self.setWindowIcon(icon) + + self._first_show = True self._initial_refresh = False self._ignore_project_change = False @@ -52,17 +64,6 @@ class LibraryLoaderWindow(QtWidgets.QDialog): self.family_config_cache = tools_lib.FamilyConfigCache(dbcon) # UI initialization - # Enable minimize and maximize for app - self.setWindowTitle(self.tool_title) - window_flags = QtCore.Qt.Window - if not parent: - window_flags |= QtCore.Qt.WindowStaysOnTopHint - self.setWindowFlags(window_flags) - self.setFocusPolicy(QtCore.Qt.StrongFocus) - - icon = QtGui.QIcon(style.app_icon_path()) - self.setWindowIcon(icon) - main_splitter = QtWidgets.QSplitter(self) # --- Left part --- @@ -193,11 +194,14 @@ class LibraryLoaderWindow(QtWidgets.QDialog): main_splitter.setSizes([250, 850, 200]) self.resize(1300, 700) - self.setStyleSheet(style.load_stylesheet()) - def showEvent(self, event): super(LibraryLoaderWindow, self).showEvent(event) + if self._first_show: + self._first_show = False + self.setStyleSheet(style.load_stylesheet()) + if not self._initial_refresh: + self._initial_refresh = True self.refresh() def on_assetview_click(self, *args): diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index 54eafd8f6d..a98c7e2f2f 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -193,7 +193,7 @@ class LoaderWindow(QtWidgets.QDialog): main_splitter.setSizes([250, 850, 200]) self.resize(1300, 700) - self.setStyleSheet(style.load_stylesheet()) + self._first_show = True def resizeEvent(self, event): super(LoaderWindow, self).resizeEvent(event) @@ -203,6 +203,12 @@ class LoaderWindow(QtWidgets.QDialog): super(LoaderWindow, self).moveEvent(event) self._overlay_frame.move(0, 0) + def showEvent(self, event): + super(LoaderWindow, self).showEvent(event) + if self._first_show: + self._first_show = False + self.setStyleSheet(style.load_stylesheet()) + # ------------------------------- # Delay calling blocking methods # ------------------------------- From e545d431da9a8283b5a957c048fa298bd4ca848b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 12:40:42 +0200 Subject: [PATCH 58/86] modified splitter style --- openpype/style/style.css | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 948ee8c7b7..8013f38bea 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -200,12 +200,44 @@ QComboBox::down-arrow, QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QC } /* Splitter */ -QSplitter { - border: none; +QSplitter::handle { + border: 3px solid transparent; } -QSplitter::handle { - border: 1px dotted {color:bg-menu-separator}; +QSplitter::handle:horizontal { + background: qlineargradient( + x1:0, y1:0, x2:1, y2:0, + stop:0.3 rgba(0, 0, 0, 0), + stop:0.5 {color:bg-buttons}, + stop:0.7 rgba(0, 0, 0, 0) + ); +} + +QSplitter::handle:vertical { + background: qlineargradient( + x1:0, y1:0, x2:0, y2:1, + stop:0.3 rgba(0, 0, 0, 0), + stop:0.5 {color:bg-buttons}, + stop:0.7 rgba(0, 0, 0, 0) + ); +} + +QSplitter::handle:horizontal:hover { + background: qlineargradient( + x1:0, y1:0, x2:1, y2:0, + stop:0.3 rgba(0, 0, 0, 0), + stop:0.5 {color:bg-button-hover}, + stop:0.7 rgba(0, 0, 0, 0) + ); +} + +QSplitter::handle:vertical:hover { + background: qlineargradient( + x1:0, y1:0, x2:0, y2:1, + stop:0.3 rgba(0, 0, 0, 0), + stop:0.5 {color:bg-button-hover}, + stop:0.7 rgba(0, 0, 0, 0) + ); } /* SLider */ From 52f474d62d1bfb22b0ada0908a768d90728841b7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 12:42:01 +0200 Subject: [PATCH 59/86] splitter has it's own key in data --- openpype/style/data.json | 3 +++ openpype/style/style.css | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index 143c6695af..c33c2eaa5e 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -32,6 +32,9 @@ "bg-inputs-disabled": "#2C313A", "bg-buttons-disabled": "#434a56", + "bg-splitter": "#434a56", + "bg-splitter-hover": "rgba(168, 175, 189, 0.3)", + "bg-menu-separator": "rgba(75, 83, 98, 127)", "bg-scroll-handle": "#4B5362", diff --git a/openpype/style/style.css b/openpype/style/style.css index 8013f38bea..3f006fb845 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -208,7 +208,7 @@ QSplitter::handle:horizontal { background: qlineargradient( x1:0, y1:0, x2:1, y2:0, stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-buttons}, + stop:0.5 {color:bg-splitter}, stop:0.7 rgba(0, 0, 0, 0) ); } @@ -217,7 +217,7 @@ QSplitter::handle:vertical { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-buttons}, + stop:0.5 {color:bg-splitter}, stop:0.7 rgba(0, 0, 0, 0) ); } @@ -226,7 +226,7 @@ QSplitter::handle:horizontal:hover { background: qlineargradient( x1:0, y1:0, x2:1, y2:0, stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-button-hover}, + stop:0.5 {color:bg-splitter-hover}, stop:0.7 rgba(0, 0, 0, 0) ); } @@ -235,7 +235,7 @@ QSplitter::handle:vertical:hover { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-button-hover}, + stop:0.5 {color:bg-splitter-hover}, stop:0.7 rgba(0, 0, 0, 0) ); } From 36f49122416af0138f8acae4fd72792f6a1c673f Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 21 Oct 2021 11:51:12 +0100 Subject: [PATCH 60/86] Hound fixes --- openpype/hosts/blender/api/plugin.py | 4 ++-- openpype/hosts/blender/plugins/publish/extract_fbx.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/blender/api/plugin.py b/openpype/hosts/blender/api/plugin.py index 181e5972a8..6d437059b8 100644 --- a/openpype/hosts/blender/api/plugin.py +++ b/openpype/hosts/blender/api/plugin.py @@ -108,13 +108,13 @@ def deselect_all(): if obj.mode != 'OBJECT': modes.append((obj, obj.mode)) bpy.context.view_layer.objects.active = obj - bpy.ops.object.mode_set(mode = 'OBJECT') + bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') for p in modes: bpy.context.view_layer.objects.active = p[0] - bpy.ops.object.mode_set(mode = p[1]) + bpy.ops.object.mode_set(mode=p[1]) bpy.context.view_layer.objects.active = active diff --git a/openpype/hosts/blender/plugins/publish/extract_fbx.py b/openpype/hosts/blender/plugins/publish/extract_fbx.py index 31d37da8e0..f9ffdea1d1 100644 --- a/openpype/hosts/blender/plugins/publish/extract_fbx.py +++ b/openpype/hosts/blender/plugins/publish/extract_fbx.py @@ -60,8 +60,6 @@ class ExtractFBX(api.Extractor): add_leaf_bones=False ) - bpy.context.scene.unit_settings.scale_length = scale_length - plugin.deselect_all() for mat in new_materials: From a1262df627bba883379425c5c231fbe6a254baac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 14:44:39 +0200 Subject: [PATCH 61/86] added few docstrings --- openpype/style/__init__.py | 47 ++++++++++++--- openpype/style/color_defs.py | 109 ++++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 10 deletions(-) diff --git a/openpype/style/__init__.py b/openpype/style/__init__.py index d763bfdc3c..fd39e93b5d 100644 --- a/openpype/style/__init__.py +++ b/openpype/style/__init__.py @@ -12,12 +12,36 @@ _FONT_IDS = None current_dir = os.path.dirname(os.path.abspath(__file__)) +def _get_colors_raw_data(): + """Read data file with stylesheet fill values. + + Returns: + dict: Loaded data for stylesheet. + """ + data_path = os.path.join(current_dir, "data.json") + with open(data_path, "r") as data_stream: + data = json.load(data_stream) + return data + + def get_colors_data(): + """Only color data from stylesheet data.""" data = _get_colors_raw_data() return data.get("color") or {} def _convert_color_values_to_objects(value): + """Parse all string values in dictionary to Color definitions. + + Recursive function calling itself if value is dictionary. + + Args: + value (dict, str): String is parsed into color definition object and + dictionary is passed into this function. + + Raises: + TypeError: If value in color data do not contain string of dictionary. + """ if isinstance(value, dict): output = {} for _key, _value in value.items(): @@ -32,6 +56,11 @@ def _convert_color_values_to_objects(value): def get_objected_colors(): + """Colors parsed from stylesheet data into color definitions. + + Returns: + dict: Parsed color objects by keys in data. + """ colors_data = get_colors_data() output = {} for key, value in colors_data.items(): @@ -39,14 +68,15 @@ def get_objected_colors(): return output -def _get_colors_raw_data(): - data_path = os.path.join(current_dir, "data.json") - with open(data_path, "r") as data_stream: - data = json.load(data_stream) - return data - - def _load_stylesheet(): + """Load strylesheet and trigger all related callbacks. + + Style require more than a stylesheet string. Stylesheet string + contains paths to resources which must be registered into Qt application + and load fonts used in stylesheets. + + Also replace values from stylesheet data into stylesheet text. + """ from . import qrc_resources qrc_resources.qInitResources() @@ -78,6 +108,7 @@ def _load_stylesheet(): def _load_font(): + """Load and register fonts into Qt application.""" from Qt import QtGui global _FONT_IDS @@ -117,6 +148,7 @@ def _load_font(): def load_stylesheet(): + """Load and return OpenPype Qt stylesheet.""" global _STYLESHEET_CACHE if _STYLESHEET_CACHE is None: _STYLESHEET_CACHE = _load_stylesheet() @@ -125,4 +157,5 @@ def load_stylesheet(): def app_icon_path(): + """Path to OpenPype icon.""" return resources.get_openpype_icon_filepath() diff --git a/openpype/style/color_defs.py b/openpype/style/color_defs.py index 3f504a9d3b..0f4e145ca0 100644 --- a/openpype/style/color_defs.py +++ b/openpype/style/color_defs.py @@ -1,7 +1,27 @@ +"""Color definitions that can be used to parse strings for stylesheet. + +Each definition must have available method `get_qcolor` which should return +`QtGui.QColor` representation of the color. + +# TODO create abstract class to force this method implementation + +Usage: Some colors may be not be used only in stylesheet but is required to +use them in code too. To not hardcode these color values into code it is better +to use same colors that are available fro stylesheets. + +It is possible that some colors may not be used in stylesheet at all and thei +definition is used only in code. +""" + import re def parse_color(value): + """Parse string value of color to one of objected representation. + + Args: + value(str): Color definition usable in stylesheet. + """ modified_value = value.strip().lower() if modified_value.startswith("hsla"): return HSLAColor(value) @@ -21,12 +41,30 @@ def parse_color(value): def create_qcolor(*args): + """Create QtGui.QColor object. + + Args: + *args (tuple): It is possible to pass initialization arguments for + Qcolor. + """ from Qt import QtGui return QtGui.QColor(*args) def min_max_check(value, min_value, max_value): + """Validate number value if is in passed range. + + Args: + value (int, float): Value which is validated. + min_value (int, float): Minimum possible value. Validation is skipped + if passed value is None. + max_value (int, float): Maximum possible value. Validation is skipped + if passed value is None. + + Raises: + ValueError: When 'value' is out of specified range. + """ if min_value is not None and value < min_value: raise ValueError("Minimum expected value is '{}' got '{}'".format( min_value, value @@ -39,6 +77,16 @@ def min_max_check(value, min_value, max_value): def int_validation(value, min_value=None, max_value=None): + """Validation of integer value within range. + + Args: + value (int): Validated value. + min_value (int): Minimum possible value. + max_value (int): Maximum possible value. + + Raises: + TypeError: If 'value' is not 'int' type. + """ if not isinstance(value, int): raise TypeError(( "Invalid type of hue expected 'int' got {}" @@ -48,6 +96,16 @@ def int_validation(value, min_value=None, max_value=None): def float_validation(value, min_value=None, max_value=None): + """Validation of float value within range. + + Args: + value (float): Validated value. + min_value (float): Minimum possible value. + max_value (float): Maximum possible value. + + Raises: + TypeError: If 'value' is not 'float' type. + """ if not isinstance(value, float): raise TypeError(( "Invalid type of hue expected 'int' got {}" @@ -57,6 +115,11 @@ def float_validation(value, min_value=None, max_value=None): class UnknownColor: + """Color from stylesheet data without known color definition. + + This is backup for unknown color definitions which may be for example + constants or definition not yet defined by class. + """ def __init__(self, value): self.value = value @@ -65,6 +128,14 @@ class UnknownColor: class HEXColor: + """Hex color definition. + + Hex color is defined by '#' and 3 or 6 hex values (0-F). + + Examples: + "#fff" + "#f3f3f3" + """ regex = re.compile(r"[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$") def __init__(self, color_string): @@ -92,6 +163,7 @@ class HEXColor: @classmethod def hex_to_rgb(cls, value): + """Convert hex value to rgb.""" hex_value = value.lstrip("#") if not cls.regex.match(hex_value): raise ValueError("\"{}\" is not a valid HEX code.".format(value)) @@ -111,6 +183,13 @@ class HEXColor: class RGBColor: + """Color defined by red green and blue values. + + Each color has possible integer range 0-255. + + Examples: + "rgb(255, 127, 0)" + """ def __init__(self, value): modified_color = value.lower().strip() content = modified_color.rstrip(")").lstrip("rgb(") @@ -146,6 +225,13 @@ class RGBColor: class RGBAColor: + """Color defined by red green, blue and alpha values. + + Each color has possible integer range 0-255. + + Examples: + "rgba(255, 127, 0, 127)" + """ def __init__(self, value): modified_color = value.lower().strip() content = modified_color.rstrip(")").lstrip("rgba(") @@ -191,6 +277,15 @@ class RGBAColor: class HSLColor: + """Color defined by hue, saturation and light values. + + Hue is defined as integer in rage 0-360. Saturation and light can be + defined as float or percent value. + + Examples: + "hsl(27, 0.7, 0.3)" + "hsl(27, 70%, 30%)" + """ def __init__(self, value): modified_color = value.lower().strip() content = modified_color.rstrip(")").lstrip("hsl(") @@ -235,6 +330,16 @@ class HSLColor: class HSLAColor: + """Color defined by hue, saturation, light and alpha values. + + Hue is defined as integer in rage 0-360. Saturation and light can be + defined as float (0-1 range) or percent value(0-100%). And alpha + as float (0-1 range). + + Examples: + "hsl(27, 0.7, 0.3)" + "hsl(27, 70%, 30%)" + """ def __init__(self, value): modified_color = value.lower().strip() content = modified_color.rstrip(")").lstrip("hsla(") @@ -251,10 +356,8 @@ class HSLAColor: light = float(light_str.rstrip("%")) / 100 else: light = float(light_str) - alpha = float(alpha_str) - if isinstance(alpha, int): - alpha = float(alpha) + alpha = float(alpha_str) int_validation(hue, 0, 360) float_validation(sat, 0, 1) From 426c996b71e673ee39edbc84c86170241b9f38b3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 14:50:06 +0200 Subject: [PATCH 62/86] hound fixes in pyside2 resources --- openpype/style/pyside2_resources.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/style/pyside2_resources.py b/openpype/style/pyside2_resources.py index c7328e7c91..80f9b904fd 100644 --- a/openpype/style/pyside2_resources.py +++ b/openpype/style/pyside2_resources.py @@ -811,10 +811,14 @@ qt_resource_struct = b"\ \x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00\x02\xa6\ " + def qInitResources(): - QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qRegisterResourceData( + 0x01, qt_resource_struct, qt_resource_name, qt_resource_data + ) + def qCleanupResources(): - QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) - -qInitResources() + QtCore.qUnregisterResourceData( + 0x01, qt_resource_struct, qt_resource_name, qt_resource_data + ) From 610477961025d7dd7b149668f084baee857aa903 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:00:05 +0200 Subject: [PATCH 63/86] renamed 'ExperimentalDialog' to 'ExperimentalToolsDialog' --- openpype/tools/experimental_tools/__init__.py | 4 ++-- openpype/tools/experimental_tools/dialog.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/tools/experimental_tools/__init__.py b/openpype/tools/experimental_tools/__init__.py index 75e3210aab..d6315e4655 100644 --- a/openpype/tools/experimental_tools/__init__.py +++ b/openpype/tools/experimental_tools/__init__.py @@ -3,12 +3,12 @@ from .tools_def import ( LOCAL_EXPERIMENTAL_KEY ) -from .dialog import ExperimentalDialog +from .dialog import ExperimentalToolsDialog __all__ = ( "ExperimentalTools", "LOCAL_EXPERIMENTAL_KEY", - "ExperimentalDialog" + "ExperimentalToolsDialog" ) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index a611416efc..6173deb693 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -21,11 +21,11 @@ class ToolButton(QtWidgets.QPushButton): self.triggered.emit(self._identifier) -class ExperimentalDialog(QtWidgets.QDialog): +class ExperimentalToolsDialog(QtWidgets.QDialog): refresh_interval = 3000 def __init__(self, parent=None): - super(ExperimentalDialog, self).__init__(parent) + super(ExperimentalToolsDialog, self).__init__(parent) self.setWindowTitle("OpenPype Experimental tools") icon = QtGui.QIcon(app_icon_path()) self.setWindowIcon(icon) @@ -138,7 +138,7 @@ class ExperimentalDialog(QtWidgets.QDialog): tool.execute() def showEvent(self, event): - super(ExperimentalDialog, self).showEvent(event) + super(ExperimentalToolsDialog, self).showEvent(event) if self._refresh_on_active: # Start/Restart timer @@ -164,7 +164,7 @@ class ExperimentalDialog(QtWidgets.QDialog): self._refresh_timer.start() self.refresh() - super(ExperimentalDialog, self).changeEvent(event) + super(ExperimentalToolsDialog, self).changeEvent(event) def _on_refresh_timeout(self): # Stop timer if window is not visible From 0c0809469cddf15bc5412856ed6f478f001cc716 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:00:16 +0200 Subject: [PATCH 64/86] added experimental dialog to host tools --- openpype/tools/utils/host_tools.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index ee184ccf2d..c0e6d71b73 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -28,6 +28,7 @@ class HostToolsHelper: self._scene_inventory_tool = None self._library_loader_tool = None self._look_assigner_tool = None + self._experimental_tools_dialog = None @property def log(self): @@ -218,6 +219,22 @@ class HostToolsHelper: look_assigner_tool = self.get_look_assigner_tool(parent) look_assigner_tool.show() + def get_experimental_tools_dialog(self, parent=None): + if self._experimental_tools_dialog is None: + from openpype.tools.experimental_tools import ( + ExperimentalToolsDialog + ) + + self._experimental_tools_dialog = ExperimentalToolsDialog(parent) + return self._experimental_tools_dialog + + def show_experimental_tools_dialog(self, parent=None): + dialog = self.get_experimental_tools_dialog(parent) + + dialog.show() + dialog.raise_() + dialog.activateWindow() + def get_tool_by_name(self, tool_name, parent=None, *args, **kwargs): """Show tool by it's name. @@ -247,6 +264,9 @@ class HostToolsHelper: elif tool_name == "publish": self.log.info("Can't return publish tool window.") + elif tool_name == "experimental_tools": + return self.get_experimental_tools_dialog(parent, *args, **kwargs) + else: self.log.warning( "Can't show unknown tool name: \"{}\"".format(tool_name) @@ -281,6 +301,9 @@ class HostToolsHelper: elif tool_name == "publish": self.show_publish(parent, *args, **kwargs) + elif tool_name == "experimental_tools": + self.show_experimental_tools_dialog(parent, *args, **kwargs) + else: self.log.warning( "Can't show unknown tool name: \"{}\"".format(tool_name) @@ -355,3 +378,7 @@ def show_look_assigner(parent=None): def show_publish(parent=None): _SingletonPoint.show_tool_by_name("publish", parent) + + +def show_experimental_tools_dialog(parent=None): + _SingletonPoint.show_tool_by_name("experimental_tools", parent) From d4729ab0695ac59673583f02efb9bb9fdfb136ce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:05:11 +0200 Subject: [PATCH 65/86] disable filtering by host name when used in local settings --- openpype/tools/settings/local_settings/experimental_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/settings/local_settings/experimental_widget.py b/openpype/tools/settings/local_settings/experimental_widget.py index 72f999d886..e863d9afb0 100644 --- a/openpype/tools/settings/local_settings/experimental_widget.py +++ b/openpype/tools/settings/local_settings/experimental_widget.py @@ -28,7 +28,7 @@ class LocalExperimentalToolsWidgets(QtWidgets.QWidget): layout.addRow(empty_label) - experimental_defs = ExperimentalTools() + experimental_defs = ExperimentalTools(filter_hosts=False) checkboxes_by_identifier = {} for tool in experimental_defs.tools: checkbox = QtWidgets.QCheckBox(self) From 7a50a106e333ed472dcb8fa6dfd7acc7e71d5efb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:05:20 +0200 Subject: [PATCH 66/86] added few docstrings --- .../tools/experimental_tools/tools_def.py | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 5dd92151ca..6ae4637039 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -8,6 +8,8 @@ LOCAL_EXPERIMENTAL_KEY = "experimental_tools" class ExperimentalTool: """Definition of experimental tool. + Definition is used in local settings and in experimental tools dialog. + Args: identifier (str): String identifier of tool (unique). label (str): Label shown in UI. @@ -91,11 +93,32 @@ class ExperimentalTools: ).format(tool.identifier)) tools_by_identifier[tool.identifier] = tool - self.tools_by_identifier = tools_by_identifier - self.tools = experimental_tools + self._tools_by_identifier = tools_by_identifier + self._tools = experimental_tools self._parent_widget = parent + @property + def tools(self): + """Tools in list. + + Returns: + list: Tools filtered by host name if filtering was enabled + on initialization. + """ + return self._tools + + @property + def tools_by_identifier(self): + """Tools by their identifier. + + Returns: + dict: Tools by identifier filtered by host name if filtering + was enabled on initialization. + """ + return self._tools_by_identifier + def refresh_availability(self): + """Reload local settings and check if any tool changed ability.""" local_settings = get_local_settings() experimental_settings = ( local_settings.get(LOCAL_EXPERIMENTAL_KEY) From 33764f6e16c3cc0e46bc75d7945db592acf0623f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:08:39 +0200 Subject: [PATCH 67/86] added docstrings to host tools --- openpype/tools/utils/host_tools.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index c0e6d71b73..2ac9d0c48b 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -220,6 +220,16 @@ class HostToolsHelper: look_assigner_tool.show() def get_experimental_tools_dialog(self, parent=None): + """Dialog of experimental tools. + + For some hosts it is not easy to modify menu of tools. For + those cases was addded experimental tools dialog which is Qt based + and can dynamically filled by experimental tools so + host need only single "Experimental tools" button to see them. + + Dialog can be also empty with a message that there are not available + experimental tools. + """ if self._experimental_tools_dialog is None: from openpype.tools.experimental_tools import ( ExperimentalToolsDialog @@ -229,6 +239,7 @@ class HostToolsHelper: return self._experimental_tools_dialog def show_experimental_tools_dialog(self, parent=None): + """Show dialog with experimental tools.""" dialog = self.get_experimental_tools_dialog(parent) dialog.show() From 29d1c47a58751ba16f9a5f71ff5d35cf7839ac61 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:12:12 +0200 Subject: [PATCH 68/86] disable buttons of tools that are not turned on --- openpype/tools/experimental_tools/dialog.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index 6173deb693..4923759249 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -112,6 +112,9 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): "\n\nOpenPype Tray > Settings > Experimental Tools" )) + if tool.enabled != button.isEnabled(): + button.setEnabled(tool.enabled) + for identifier in buttons_to_remove: button = self._buttons_by_tool_identifier.pop(identifier) button.setVisible(False) From de9f0f7fa46fa757f1b6ce6d6b985360de98410d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:28:25 +0200 Subject: [PATCH 69/86] adde commented example tool --- openpype/tools/experimental_tools/tools_def.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 6ae4637039..3657c2385b 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -65,6 +65,19 @@ class ExperimentalTools: # Definition of experimental tools experimental_tools = [] + # --- Example tool (callback will just print on click) --- + # def example_callback(*args): + # print("Triggered tool") + # + # experimental_tools = [ + # ExperimentalTool( + # "example", + # "Exmaple experimental tool", + # example_callback, + # "Example tool tooltip." + # ) + # ] + # Try to get host name from env variable `AVALON_APP` if not host_name: host_name = os.environ.get("AVALON_APP") From ee443cb735637b56be5367164309481f7defb35a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:29:28 +0200 Subject: [PATCH 70/86] added example tool into experimental tools --- openpype/hosts/maya/api/menu.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 4f0966abfd..5eb8882030 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -46,6 +46,15 @@ def deferred(): ) ) + def add_experimental_item(): + cmds.menuItem( + "Experimental tools...", + parent=pipeline._menu, + command=lambda *args: host_tools.show_experimental_tools_dialog( + pipeline._parent + ) + ) + def modify_workfiles(): # Find the pipeline menu top_menu = _get_menu() @@ -103,6 +112,7 @@ def deferred(): add_build_workfiles_item() add_look_assigner_item() + add_experimental_item() modify_workfiles() remove_project_manager() From 501f0ed550e76ebbff0340b6bdf2bb14a75e06ce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 15:50:10 +0200 Subject: [PATCH 71/86] added experimental tools into nuke menu --- openpype/hosts/nuke/api/menu.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/hosts/nuke/api/menu.py b/openpype/hosts/nuke/api/menu.py index 87990c5e92..3e74893589 100644 --- a/openpype/hosts/nuke/api/menu.py +++ b/openpype/hosts/nuke/api/menu.py @@ -84,6 +84,12 @@ def install(): ) log.debug("Adding menu item: {}".format(name)) + # Add experimental tools action + menu.addSeparator() + menu.addCommand( + "Experimental tools...", + host_tools.show_experimental_tools_dialog + ) # adding shortcuts add_shortcuts_from_presets() From 6da7c65e295be27cab7fd1c594f78945247ec989 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 16:19:43 +0200 Subject: [PATCH 72/86] set stylesheet after show --- openpype/tools/experimental_tools/dialog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index 4923759249..c7c8ce83fc 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -29,7 +29,6 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): self.setWindowTitle("OpenPype Experimental tools") icon = QtGui.QIcon(app_icon_path()) self.setWindowIcon(icon) - self.setStyleSheet(load_stylesheet()) empty_widget = QtWidgets.QWidget(self) @@ -154,6 +153,8 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): if self._first_show: self._first_show = False + # Set stylesheet + self.setStyleSheet(load_stylesheet()) # Resize dialog if there is not content if not self._is_content_visible(): size = self.size() From 28bf0a23996dd5538b9843dfaa271904b41a416e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 17:14:17 +0200 Subject: [PATCH 73/86] resize after showing --- openpype/tools/libraryloader/app.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openpype/tools/libraryloader/app.py b/openpype/tools/libraryloader/app.py index 700d3c05bd..3e4c5d5850 100644 --- a/openpype/tools/libraryloader/app.py +++ b/openpype/tools/libraryloader/app.py @@ -129,6 +129,10 @@ class LibraryLoaderWindow(QtWidgets.QDialog): main_splitter.addWidget(left_side_splitter) main_splitter.addWidget(subsets_widget) main_splitter.addWidget(thumb_ver_splitter) + if sync_server_enabled: + main_splitter.setSizes([250, 1000, 550]) + else: + main_splitter.setSizes([250, 850, 200]) # --- Footer --- footer_widget = QtWidgets.QWidget(self) @@ -168,6 +172,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog): projects_combobox.currentTextChanged.connect(self.on_project_change) self.sync_server = sync_server + self._sync_server_enabled = sync_server_enabled self._combobox_delegate = combobox_delegate self._projects_combobox = projects_combobox @@ -186,19 +191,15 @@ class LibraryLoaderWindow(QtWidgets.QDialog): # Set default thumbnail on start thumbnail_widget.set_thumbnail(None) - # Defaults - if sync_server_enabled: - main_splitter.setSizes([250, 1000, 550]) - self.resize(1800, 900) - else: - main_splitter.setSizes([250, 850, 200]) - self.resize(1300, 700) - def showEvent(self, event): super(LibraryLoaderWindow, self).showEvent(event) if self._first_show: self._first_show = False self.setStyleSheet(style.load_stylesheet()) + if self._sync_server_enabled: + self.resize(1800, 900) + else: + self.resize(1300, 700) if not self._initial_refresh: self._initial_refresh = True From 2b2f27b74e557a1b34e15bc30ffb8fc9ca23d489 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 17:15:40 +0200 Subject: [PATCH 74/86] set default thumbnail on initialization of ThumbnailWidget --- openpype/tools/libraryloader/app.py | 3 --- openpype/tools/loader/widgets.py | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/tools/libraryloader/app.py b/openpype/tools/libraryloader/app.py index 3e4c5d5850..d7c6c162e6 100644 --- a/openpype/tools/libraryloader/app.py +++ b/openpype/tools/libraryloader/app.py @@ -188,9 +188,6 @@ class LibraryLoaderWindow(QtWidgets.QDialog): self._message_label = message_label self._message_timer = message_timer - # Set default thumbnail on start - thumbnail_widget.set_thumbnail(None) - def showEvent(self, event): super(LibraryLoaderWindow, self).showEvent(event) if self._first_show: diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index b068dd95d1..4c075382ac 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -745,6 +745,7 @@ class ThumbnailWidget(QtWidgets.QLabel): "default_thumbnail.png" ) self.default_pix = QtGui.QPixmap(default_pix_path) + self.set_pixmap() def height(self): width = self.width() From 1b10ef39fd43e65a8ddcfcabb185066d88a578b9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 21 Oct 2021 17:17:24 +0200 Subject: [PATCH 75/86] resize loader after showing --- openpype/tools/loader/app.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index a98c7e2f2f..bbf6719af5 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -119,6 +119,11 @@ class LoaderWindow(QtWidgets.QDialog): main_splitter.addWidget(subsets_widget) main_splitter.addWidget(thumb_ver_splitter) + if sync_server_enabled: + main_splitter.setSizes([250, 1000, 550]) + else: + main_splitter.setSizes([250, 850, 200]) + # TODO keep footer size by message size footer_widget = QtWidgets.QWidget(self) footer_widget.setFixedHeight(20) @@ -164,6 +169,8 @@ class LoaderWindow(QtWidgets.QDialog): repres_widget.load_started.connect(self._on_load_start) repres_widget.load_ended.connect(self._on_load_end) + self._sync_server_enabled = sync_server_enabled + self._assets_widget = assets_widget self._families_filter_view = families_filter_view @@ -185,14 +192,6 @@ class LoaderWindow(QtWidgets.QDialog): self._refresh() self._assetschanged() - # Defaults - if sync_server_enabled: - main_splitter.setSizes([250, 1000, 550]) - self.resize(1800, 900) - else: - main_splitter.setSizes([250, 850, 200]) - self.resize(1300, 700) - self._first_show = True def resizeEvent(self, event): @@ -208,6 +207,10 @@ class LoaderWindow(QtWidgets.QDialog): if self._first_show: self._first_show = False self.setStyleSheet(style.load_stylesheet()) + if self._sync_server_enabled: + self.resize(1800, 900) + else: + self.resize(1300, 700) # ------------------------------- # Delay calling blocking methods From 5b95e21c6f4da5683043895ae97222c10fafcae6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 10:53:03 +0200 Subject: [PATCH 76/86] do not apply avalon style on loader and library loader --- openpype/tools/utils/host_tools.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index 599c25d6c8..2a64e23883 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -93,8 +93,6 @@ class HostToolsHelper: def show_loader(self, parent=None, use_context=None): """Loader tool for loading representations.""" - from avalon import style - loader_tool = self.get_loader_tool(parent) loader_tool.show() @@ -110,8 +108,6 @@ class HostToolsHelper: else: loader_tool.refresh() - loader_tool.setStyleSheet(style.load_stylesheet()) - def get_creator_tool(self, parent): """Create, cache and return creator tool window.""" if self._creator_tool is None: @@ -196,14 +192,11 @@ class HostToolsHelper: def show_library_loader(self, parent=None): """Loader tool for loading representations from library project.""" - from avalon import style - library_loader_tool = self.get_library_loader_tool(parent) library_loader_tool.show() library_loader_tool.raise_() library_loader_tool.activateWindow() library_loader_tool.refresh() - library_loader_tool.setStyleSheet(style.load_stylesheet()) def show_publish(self, parent=None): """Publish UI.""" From 600c94f464d93edded5927873b86379838708a12 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 11:49:15 +0200 Subject: [PATCH 77/86] fix double slashes --- openpype/style/style.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 3f006fb845..6921a786f3 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -425,20 +425,20 @@ QAbstractItemView::branch:open:has-children:has-siblings { QAbstractItemView::branch:open:has-children:!has-siblings:hover, QAbstractItemView::branch:open:has-children:has-siblings:hover { border-image: none; - image: url(:/openpype/images//branch_open_on.png); + image: url(:/openpype/images/branch_open_on.png); background: transparent; } QAbstractItemView::branch:has-children:!has-siblings:closed, QAbstractItemView::branch:closed:has-children:has-siblings { border-image: none; - image: url(:/openpype/images//branch_closed.png); + image: url(:/openpype/images/branch_closed.png); background: transparent; } QAbstractItemView::branch:has-children:!has-siblings:closed:hover, QAbstractItemView::branch:closed:has-children:has-siblings:hover { border-image: none; - image: url(:/openpype/images//branch_closed_on.png); + image: url(:/openpype/images/branch_closed_on.png); background: transparent; } From c85fb71103c22a2be372a1e6ea1c55ed4522c1d1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:26:12 +0200 Subject: [PATCH 78/86] qlineargradient are single line --- openpype/style/style.css | 69 +++++++++++----------------------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 6921a786f3..8e9827084e 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -205,39 +205,23 @@ QSplitter::handle { } QSplitter::handle:horizontal { - background: qlineargradient( - x1:0, y1:0, x2:1, y2:0, - stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-splitter}, - stop:0.7 rgba(0, 0, 0, 0) - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1:0, y1:0, x2:1, y2:0,stop:0.3 rgba(0, 0, 0, 0),stop:0.5 {color:bg-splitter},stop:0.7 rgba(0, 0, 0, 0)); } QSplitter::handle:vertical { - background: qlineargradient( - x1:0, y1:0, x2:0, y2:1, - stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-splitter}, - stop:0.7 rgba(0, 0, 0, 0) - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0.3 rgba(0, 0, 0, 0),stop:0.5 {color:bg-splitter},stop:0.7 rgba(0, 0, 0, 0)); } QSplitter::handle:horizontal:hover { - background: qlineargradient( - x1:0, y1:0, x2:1, y2:0, - stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-splitter-hover}, - stop:0.7 rgba(0, 0, 0, 0) - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1:0, y1:0, x2:1, y2:0,stop:0.3 rgba(0, 0, 0, 0),stop:0.5 {color:bg-splitter-hover},stop:0.7 rgba(0, 0, 0, 0)); } QSplitter::handle:vertical:hover { - background: qlineargradient( - x1:0, y1:0, x2:0, y2:1, - stop:0.3 rgba(0, 0, 0, 0), - stop:0.5 {color:bg-splitter-hover}, - stop:0.7 rgba(0, 0, 0, 0) - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0.3 rgba(0, 0, 0, 0),stop:0.5 {color:bg-splitter-hover},stop:0.7 rgba(0, 0, 0, 0)); } /* SLider */ @@ -264,18 +248,15 @@ QSlider::groove:focus { border-color: {color:border-focus}; } QSlider::handle { - background: qlineargradient( - x1: 0, y1: 0.5, - x2: 1, y2: 0.5, - stop: 0 {palette:blue-base}, - stop: 1 {palette:green-base} - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 0.5,stop: 0 {palette:blue-base},stop: 1 {palette:green-base}); border: 1px solid #5c5c5c; width: 10px; height: 10px; border-radius: 5px; } + QSlider::handle:horizontal { margin: -2px 0; } @@ -284,12 +265,8 @@ QSlider::handle:vertical { } QSlider::handle:disabled { - background: qlineargradient( - x1:0, y1:0, - x2:1, y2:1, - stop:0 {color:bg-buttons}, - stop:1 {color:bg-buttons-disabled} - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1:0, y1:0,x2:1, y2:1,stop:0 {color:bg-buttons},stop:1 {color:bg-buttons-disabled}); } /* Tab widget*/ @@ -307,19 +284,15 @@ QTabBar::tab { border-left: 3px solid transparent; border-top: 1px solid {color:border}; border-right: 1px solid {color:border}; - background: qlineargradient( - x1: 0, y1: 1, x2: 0, y2: 0, - stop: 0.5 {color:bg}, stop: 1.0 {color:bg-inputs} - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,stop: 0.5 {color:bg}, stop: 1.0 {color:bg-inputs}); } QTabBar::tab:selected { background: {color:grey-lighter}; border-left: 3px solid {color:border-focus}; - background: qlineargradient( - x1: 0, y1: 1, x2: 0, y2: 0, - stop: 0.5 {color:bg}, stop: 1.0 {color:border} - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,stop: 0.5 {color:bg}, stop: 1.0 {color:border}); } QTabBar::tab:!selected { @@ -457,12 +430,8 @@ QProgressBar:vertical { } QProgressBar::chunk { - background: qlineargradient( - x1: 0, y1: 0.5, - x2: 1, y2: 0.5, - stop: 0 {palette:blue-base}, - stop: 1 {palette:green-base} - ); + /* must be single like because of Nuke*/ + background: qlineargradient(x1: 0, y1: 0.5,x2: 1, y2: 0.5,stop: 0 {palette:blue-base},stop: 1 {palette:green-base}); } /* Scroll bars */ From 3158710d43f06fd5e2793d84483ba7770c2a2753 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:28:58 +0200 Subject: [PATCH 79/86] removed fixed height of footer widget --- openpype/tools/loader/app.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py index bbf6719af5..dac5e11d4c 100644 --- a/openpype/tools/loader/app.py +++ b/openpype/tools/loader/app.py @@ -124,19 +124,17 @@ class LoaderWindow(QtWidgets.QDialog): else: main_splitter.setSizes([250, 850, 200]) - # TODO keep footer size by message size footer_widget = QtWidgets.QWidget(self) - footer_widget.setFixedHeight(20) message_label = QtWidgets.QLabel(footer_widget) - footer_layout = QtWidgets.QVBoxLayout(footer_widget) + footer_layout = QtWidgets.QHBoxLayout(footer_widget) footer_layout.setContentsMargins(0, 0, 0, 0) - footer_layout.addWidget(message_label) + footer_layout.addWidget(message_label, 1) layout = QtWidgets.QVBoxLayout(self) - layout.addWidget(main_splitter) - layout.addWidget(footer_widget) + layout.addWidget(main_splitter, 1) + layout.addWidget(footer_widget, 0) self.data = { "state": { From 01d059a993af1e486bedb8ae051299f1cbcab07c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:31:52 +0200 Subject: [PATCH 80/86] added transparent image to resources --- openpype/style/images/transparent.png | Bin 0 -> 69 bytes openpype/style/pyqt5_resources.py | 745 +++++++++++++------------- openpype/style/pyside2_resources.py | 602 +++++++++++---------- openpype/style/resources.qrc | 1 + 4 files changed, 679 insertions(+), 669 deletions(-) create mode 100644 openpype/style/images/transparent.png diff --git a/openpype/style/images/transparent.png b/openpype/style/images/transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2e143b39a2e37e52841ff55d410a2000125eca GIT binary patch literal 69 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryJf1F&AsjQ46A}`DJQfDV#ayC~ Pfh-13S3j3^P6 \x0b\xa4\x08020 \x0b\xa6\ -\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ -\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ -D\xaeB`\x82\ -\x00\x00\x00\xa5\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ -\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ -200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ -\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ -\xaeB`\x82\ -\x00\x00\x00\xa6\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ \x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ @@ -62,18 +36,136 @@ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ 200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ \xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ \xaeB`\x82\ -\x00\x00\x00\x9f\ +\x00\x00\x00\xa6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ \x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x14\x1f\xf9\ -#\xd9\x0b\x00\x00\x00#IDAT\x08\xd7c`\xc0\ -\x0d\xe6|\x80\xb1\x18\x91\x05R\x04\xe0B\x08\x15)\x02\ -\x0c\x0c\x8c\xc8\x02\x08\x95h\x00\x00\xac\xac\x07\x90Ne\ -4\xac\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x070\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ +\x00\x00\x04\xb0iTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0aH\x8b[^\x00\x00\x01\x83\ +iCCPsRGB IEC6196\ +6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ +\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ +\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ +x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ +Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ +;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ +\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ +\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ +\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ +\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ +RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ +?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ +\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ +\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ +\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ +\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ +\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ +\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ +vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ +\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ +8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ +S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ +\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ +Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x97IDAT\x18\x95m\xcf\xb1j\x02A\ +\x14\x85\xe1o\xb7\xb6\xd0'H=Vi\x03\xb1\xb4H\ +;l\xa5\xf19\xf6Y\x02VB\xbaa\x0a\x0b;\x1b\ +\x1bkA\x18\x02)m\xe3\xbe\x82\xcd\x06\x16\xd9\xdb\xdd\ +\x9f\xff\x5c\xee\xa9b*\x13Ls\x13nF&\xa6\xf2\ +\x82\xaeF\x8b\xdf\x98\xca\xfb\x88\xb4\xc0\x0f\xda\x1a[t\ +\xd8\xc7T\xc2@\x9ac\x8f?|U=|\xc5\x09w\ +\xbc\xa1\xc2\x193,r\x13.\xd5\xe0\xc2\x12\x07\x5cQ\ +#\xe0#7\xe1\xa8O\x0e\x7f\xda`\xd7\xaf\x9f\xb9\x09\ +\xdfc\x05\xff\xe5uLe\xf5\xcc\x1f\x0d3,\x83\xb6\ +\x06D\x83\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x00\xa0\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -86,6 +178,31 @@ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ \x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ \xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ \x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x9e\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ +\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ +\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ +\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ +\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ \x00\x00\x07\xdd\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -214,19 +331,57 @@ zpp\xf0\xe3\x0e.\xa4\xd2\xae\xf0\x8a\xf7\x9a\xe3V\ q[s\x5c@H\xa5\xdda\x81\x0d\x9ek\x8e\xff\xfd\ \xcf?\xcc1\xe9\x01\x1c\x00sR-q\xe4J\x1bi\ \x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\xa6\ +\x00\x00\x00\x9e\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f \xb9\ -\x8dw\xe9\x00\x00\x00*IDAT\x08\xd7c`\xc0\ -\x06\xe6|```B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ -d``b`H\x11@\xe2 s\x19\x90\x8d@\x02\ -\x00#\xed\x08\xafd\x9f\x0f\x15\x00\x00\x00\x00IEN\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ +\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ +\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ +\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ +\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ D\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ \x00\x00\x00\xa0\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -234,11 +389,23 @@ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ -\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ -\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ -\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ -\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f\x0d\xfc\ +R+\x9c\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05s>\xc0XL\xc8\x5c&dY&d\xc5pN\ +\x8a\x00\x9c\x93\x22\x80a\x1a\x0a\x00\x00)\x95\x08\xaf\x88\ +\xac\xba4\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x9f\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x14\x1f\xf9\ +#\xd9\x0b\x00\x00\x00#IDAT\x08\xd7c`\xc0\ +\x0d\xe6|\x80\xb1\x18\x91\x05R\x04\xe0B\x08\x15)\x02\ +\x0c\x0c\x8c\xc8\x02\x08\x95h\x00\x00\xac\xac\x07\x90Ne\ +4\xac\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x07\x06\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -357,146 +524,28 @@ D\xaeB`\x82\ \x00\x00\x00\xa6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ -;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ -\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ -\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f \xb9\ +\x8dw\xe9\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x06\xe6|```B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ +d``b`H\x11@\xe2 s\x19\x90\x8d@\x02\ +\x00#\xed\x08\xafd\x9f\x0f\x15\x00\x00\x00\x00IEN\ D\xaeB`\x82\ -\x00\x00\x00\xa5\ +\x00\x00\x00\xa0\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ -\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ -200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ -\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ -\xaeB`\x82\ -\x00\x00\x070\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ -\x00\x00\x04\xb0iTXtXML:com.\ -adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0aH\x8b[^\x00\x00\x01\x83\ -iCCPsRGB IEC6196\ -6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ -\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ -\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ -x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ -Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ -;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ -\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ -\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ -\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ -\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ -RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ -?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ -\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ -\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ -\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ -\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ -\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ -\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ -vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ -\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ -8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ -S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ -\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ -Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x97IDAT\x18\x95m\xcf\xb1j\x02A\ -\x14\x85\xe1o\xb7\xb6\xd0'H=Vi\x03\xb1\xb4H\ -;l\xa5\xf19\xf6Y\x02VB\xbaa\x0a\x0b;\x1b\ -\x1bkA\x18\x02)m\xe3\xbe\x82\xcd\x06\x16\xd9\xdb\xdd\ -\x9f\xff\x5c\xee\xa9b*\x13Ls\x13nF&\xa6\xf2\ -\x82\xaeF\x8b\xdf\x98\xca\xfb\x88\xb4\xc0\x0f\xda\x1a[t\ -\xd8\xc7T\xc2@\x9ac\x8f?|U=|\xc5\x09w\ -\xbc\xa1\xc2\x193,r\x13.\xd5\xe0\xc2\x12\x07\x5cQ\ -#\xe0#7\xe1\xa8O\x0e\x7f\xda`\xd7\xaf\x9f\xb9\x09\ -\xdfc\x05\xff\xe5uLe\xf5\xcc\x1f\x0d3,\x83\xb6\ -\x06D\x83\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ +\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ +\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ +\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x07\xad\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -622,55 +671,6 @@ v)`\x8b\x07>\xa8\xe6\xd1\xfe\x0b\x9d\x85\x8eW\x0d\ ^x\xa2\x9e\x0e\xa7 tG9\x1d\xf6\xe1\x95+\xd6\ \xb1D\x8e\x0e\xcbX\xf0\x0fR\x8ay\x18\xdc\xe2\x02p\ \x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\xa0\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f\x0d\xfc\ -R+\x9c\x00\x00\x00$IDAT\x08\xd7c`@\ -\x05s>\xc0XL\xc8\x5c&dY&d\xc5pN\ -\x8a\x00\x9c\x93\x22\x80a\x1a\x0a\x00\x00)\x95\x08\xaf\x88\ -\xac\xba4\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\x9e\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ -\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ -\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ -\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ -\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\x9e\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ -\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ -\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ -\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ -\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00\x00\xa6\ -\x89\ -PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ -\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ -\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ -HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ -\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ -;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ -\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ -\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ -\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ -D\xaeB`\x82\ \x00\x00\x00\xa6\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -695,16 +695,6 @@ qt_resource_name = b"\ \x07\x03}\xc3\ \x00i\ \x00m\x00a\x00g\x00e\x00s\ -\x00\x15\ -\x03'rg\ -\x00c\ -\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\ -\x00.\x00p\x00n\x00g\ -\x00\x1b\ -\x03Z2'\ -\x00c\ -\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\ -\x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ \x00\x0e\ \x0e\xde\xfa\xc7\ \x00l\ @@ -714,62 +704,35 @@ qt_resource_name = b"\ \x00d\ \x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ \ -\x00\x15\ -\x0f\xf3\xc0\x07\ -\x00u\ -\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\ -\x00.\x00p\x00n\x00g\ -\x00\x12\ -\x03\x8d\x04G\ -\x00r\ -\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\ -\x00g\ -\x00\x14\ -\x04^-\xa7\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00_\x00o\x00n\x00.\ -\x00p\x00n\x00g\ -\x00\x17\ -\x0ce\xce\x07\ -\x00l\ -\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ -\x00e\x00d\x00.\x00p\x00n\x00g\ -\x00\x0f\ -\x02\x9f\x05\x87\ -\x00r\ -\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ -\x00\x0f\ -\x06S%\xa7\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00.\x00p\x00n\x00g\ \x00\x12\ \x01.\x03'\ \x00c\ \x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\ \x00g\ -\x00\x0e\ -\x04\xa2\xfc\xa7\ -\x00d\ -\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ \x00\x12\ \x05\x8f\x9d\x07\ \x00b\ \x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00_\x00o\x00n\x00.\x00p\x00n\ \x00g\ -\x00\x11\ -\x0b\xda0\xa7\ -\x00b\ -\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00.\x00p\x00n\x00g\ -\ -\x00\x18\ -\x03\x8e\xdeg\ +\x00\x12\ +\x03\x8d\x04G\ \x00r\ -\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\ -\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\ +\x00g\ \x00\x0f\ \x01s\x8b\x07\ \x00u\ \x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ +\x00\x1b\ +\x03Z2'\ +\x00c\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\ +\x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x14\ +\x04^-\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00_\x00o\x00n\x00.\ +\x00p\x00n\x00g\ \x00\x0c\ \x06\xe6\xe6g\ \x00u\ @@ -779,6 +742,43 @@ qt_resource_name = b"\ \x00d\ \x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ \x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x15\ +\x03'rg\ +\x00c\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\ +\x00.\x00p\x00n\x00g\ +\x00\x0e\ +\x04\xa2\xfc\xa7\ +\x00d\ +\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x18\ +\x03\x8e\xdeg\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\ +\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x15\ +\x0f\xf3\xc0\x07\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\ +\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x06S%\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00.\x00p\x00n\x00g\ +\x00\x17\ +\x0ce\xce\x07\ +\x00l\ +\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ +\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x02\x9f\x05\x87\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x11\ +\x0b\xda0\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00.\x00p\x00n\x00g\ +\ \x00\x11\ \x00\xb8\x8c\x07\ \x00l\ @@ -791,34 +791,30 @@ qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x16\x00\x02\x00\x00\x00\x13\x00\x00\x00\x03\ \x00\x00\x03,\x00\x00\x00\x00\x00\x01\x00\x00&\xf0\ -\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x01\xfd\ -\x00\x00\x01\xe2\x00\x00\x00\x00\x00\x01\x00\x00\x14&\ -\x00\x00\x02\xb6\x00\x00\x00\x00\x00\x01\x00\x00%\x02\ -\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0cx\ +\x00\x00\x00J\x00\x00\x00\x00\x00\x01\x00\x00\x00\xaa\ +\x00\x00\x00r\x00\x00\x00\x00\x00\x01\x00\x00\x01S\ +\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x09\xd5\ +\x00\x00\x02\xe0\x00\x00\x00\x00\x00\x01\x00\x00\x1e\x9b\ +\x00\x00\x01\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x14M\ +\x00\x00\x01\x14\x00\x00\x00\x00\x00\x01\x00\x00\x0aw\ +\x00\x00\x00\xc6\x00\x00\x00\x00\x00\x01\x00\x00\x091\ +\x00\x00\x02\x22\x00\x00\x00\x00\x00\x01\x00\x00\x15\xa0\ +\x00\x00\x01P\x00\x00\x00\x00\x00\x01\x00\x00\x0b \ +\x00\x00\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x14\xf7\ +\x00\x00\x00\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x01\xfd\ +\x00\x00\x02\x88\x00\x00\x00\x00\x00\x01\x00\x00\x16\xe7\ +\x00\x00\x01~\x00\x00\x00\x00\x00\x01\x00\x00\x13\x01\ +\x00\x00\x03\x04\x00\x00\x00\x00\x00\x01\x00\x00\x1f?\ +\x00\x00\x02\xac\x00\x00\x00\x00\x00\x01\x00\x00\x1d\xf1\ +\x00\x00\x01\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x13\xa3\ \x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x00X\x00\x00\x00\x00\x00\x01\x00\x00\x00\xaa\ -\x00\x00\x01\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x03I\ -\x00\x00\x02\x80\x00\x00\x00\x00\x00\x01\x00\x00$^\ -\x00\x00\x018\x00\x00\x00\x00\x00\x01\x00\x00\x03\xed\ -\x00\x00\x02\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x14\xd0\ -\x00\x00\x02.\x00\x00\x00\x00\x00\x01\x00\x00\x15y\ -\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x0d\x1c\ -\x00\x00\x02\xda\x00\x00\x00\x00\x00\x01\x00\x00%\xa4\ -\x00\x00\x02X\x00\x00\x00\x00\x00\x01\x00\x00\x1c\xad\ -\x00\x00\x01f\x00\x00\x00\x00\x00\x01\x00\x00\x0b\xce\ -\x00\x00\x02\xf8\x00\x00\x00\x00\x00\x01\x00\x00&F\ -\x00\x00\x00\x94\x00\x00\x00\x00\x00\x01\x00\x00\x01S\ -\x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00\x02\xa6\ +\x00\x00\x02X\x00\x00\x00\x00\x00\x01\x00\x00\x16D\ " - def qInitResources(): - QtCore.qRegisterResourceData( - 0x01, qt_resource_struct, qt_resource_name, qt_resource_data - ) - + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) def qCleanupResources(): - QtCore.qUnregisterResourceData( - 0x01, qt_resource_struct, qt_resource_name, qt_resource_data - ) + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/openpype/style/resources.qrc b/openpype/style/resources.qrc index a583d9458e..e2e69711f4 100644 --- a/openpype/style/resources.qrc +++ b/openpype/style/resources.qrc @@ -19,5 +19,6 @@ images/up_arrow.png images/up_arrow_disabled.png images/up_arrow_on.png + images/transparent.png From 536c6383715627a7778927f58840db3f71d84d69 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:32:09 +0200 Subject: [PATCH 81/86] use transparent image to hide branches in tree view --- openpype/style/style.css | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index 8e9827084e..f8a61cbbd3 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -415,6 +415,25 @@ QAbstractItemView::branch:closed:has-children:has-siblings:hover { background: transparent; } +QAbstractItemView::branch:has-siblings:!adjoins-item { + border-image: none; + image: url(:/openpype/images/transparent.png); + background: transparent; +} + +QAbstractItemView::branch:has-siblings:adjoins-item { + border-image: none; + image: url(:/openpype/images/transparent.png); + background: transparent; +} + +QAbstractItemView::branch:!has-children:!has-siblings:adjoins-item { + border-image: none; + image: url(:/openpype/images/transparent.png); + background: transparent; +} + + /* Progress bar */ QProgressBar { border: 1px solid {color:border}; From 140c290c607ad0dd87cce1e5f44afce38091c0ef Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:32:19 +0200 Subject: [PATCH 82/86] set down/up arrow for header --- openpype/style/style.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index f8a61cbbd3..d6f2460a27 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -340,6 +340,15 @@ QHeaderView::section:first { QHeaderView::section:last { border-right: none; } + +QHeaderView::down-arrow { + image: url(:/openpype/images/down_arrow.png); +} + +QHeaderView::up-arrow { + image: url(:/openpype/images/up_arrow.png); +} + /* Views QListView QTreeView QTableView */ QAbstractItemView { border: 0px solid {color:border}; From d4b4d2e8417e267a6381cf0fd883910b3b4bf5ad Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:40:12 +0200 Subject: [PATCH 83/86] fix formatting --- openpype/style/pyside2_resources.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/style/pyside2_resources.py b/openpype/style/pyside2_resources.py index e4bbc50533..97ee781c5d 100644 --- a/openpype/style/pyside2_resources.py +++ b/openpype/style/pyside2_resources.py @@ -812,9 +812,13 @@ qt_resource_struct = b"\ " def qInitResources(): - QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qRegisterResourceData( + 0x01, qt_resource_struct, qt_resource_name, qt_resource_data + ) def qCleanupResources(): - QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qUnregisterResourceData( + 0x01, qt_resource_struct, qt_resource_name, qt_resource_data + ) qInitResources() From c39c3ecb045629160d809fd3e25bdb3bad173ea1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 12:40:38 +0200 Subject: [PATCH 84/86] do not call pyside initialization on import --- openpype/style/pyside2_resources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/style/pyside2_resources.py b/openpype/style/pyside2_resources.py index 97ee781c5d..dff01eec49 100644 --- a/openpype/style/pyside2_resources.py +++ b/openpype/style/pyside2_resources.py @@ -811,14 +811,14 @@ qt_resource_struct = b"\ \x00\x00\x02X\x00\x00\x00\x00\x00\x01\x00\x00\x16D\ " + def qInitResources(): QtCore.qRegisterResourceData( 0x01, qt_resource_struct, qt_resource_name, qt_resource_data ) + def qCleanupResources(): QtCore.qUnregisterResourceData( 0x01, qt_resource_struct, qt_resource_name, qt_resource_data ) - -qInitResources() From 765fcf701434a19c3ff4e0401a0bb904e6e8f1f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 14:24:25 +0200 Subject: [PATCH 85/86] fix typo in label --- openpype/tools/experimental_tools/tools_def.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/experimental_tools/tools_def.py b/openpype/tools/experimental_tools/tools_def.py index 3657c2385b..254f542c4d 100644 --- a/openpype/tools/experimental_tools/tools_def.py +++ b/openpype/tools/experimental_tools/tools_def.py @@ -72,7 +72,7 @@ class ExperimentalTools: # experimental_tools = [ # ExperimentalTool( # "example", - # "Exmaple experimental tool", + # "Example experimental tool", # example_callback, # "Example tool tooltip." # ) From dc5f2221b9c6d838ef383c648bea66e8fd0e2b69 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 22 Oct 2021 14:34:43 +0200 Subject: [PATCH 86/86] added label describing how to turn onoff experimental tools --- openpype/tools/experimental_tools/dialog.py | 39 +++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index c7c8ce83fc..0fd170b31e 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -30,6 +30,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): icon = QtGui.QIcon(app_icon_path()) self.setWindowIcon(icon) + # Widgets for cases there are not available experimental tools empty_widget = QtWidgets.QWidget(self) empty_label = QtWidgets.QLabel( @@ -49,16 +50,42 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): empty_layout.addStretch(1) empty_layout.addLayout(empty_btns_layout) - content_widget = QtWidgets.QWidget(self) + # Content of Experimental tools - content_layout = QtWidgets.QVBoxLayout(content_widget) + # Layout where buttons are added + content_layout = QtWidgets.QVBoxLayout() content_layout.setContentsMargins(0, 0, 0, 0) + # Separator line + separator_widget = QtWidgets.QWidget(self) + separator_widget.setObjectName("Separator") + separator_widget.setMinimumHeight(2) + separator_widget.setMaximumHeight(2) + + # Label describing how to turn off tools + tool_btns_widget = QtWidgets.QWidget(self) + tool_btns_label = QtWidgets.QLabel( + ( + "You can enable these features in" + "
OpenPype tray -> Settings -> Experimental tools" + ), + tool_btns_widget + ) + tool_btns_label.setAlignment(QtCore.Qt.AlignCenter) + + tool_btns_layout = QtWidgets.QVBoxLayout(tool_btns_widget) + tool_btns_layout.setContentsMargins(0, 0, 0, 0) + tool_btns_layout.addLayout(content_layout) + tool_btns_layout.addStretch(1) + tool_btns_layout.addWidget(separator_widget, 0) + tool_btns_layout.addWidget(tool_btns_label, 0) + experimental_tools = ExperimentalTools() + # Main layout layout = QtWidgets.QVBoxLayout(self) layout.addWidget(empty_widget, 1) - layout.addWidget(content_widget, 1) + layout.addWidget(tool_btns_widget, 1) refresh_timer = QtCore.QTimer() refresh_timer.setInterval(self.refresh_interval) @@ -67,7 +94,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): ok_btn.clicked.connect(self._on_ok_click) self._empty_widget = empty_widget - self._content_widget = content_widget + self._tool_btns_widget = tool_btns_widget self._content_layout = content_layout self._experimental_tools = experimental_tools @@ -94,7 +121,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): button = self._buttons_by_tool_identifier[identifier] else: is_new = True - button = ToolButton(identifier, self) + button = ToolButton(identifier, self._tool_btns_widget) button.triggered.connect(self._on_btn_trigger) self._buttons_by_tool_identifier[identifier] = button self._content_layout.insertWidget(idx, button) @@ -128,7 +155,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): def _set_visibility(self): content_visible = self._is_content_visible() - self._content_widget.setVisible(content_visible) + self._tool_btns_widget.setVisible(content_visible) self._empty_widget.setVisible(not content_visible) def _on_ok_click(self):