From 99e5e326f8a6627366815d21fc9f5c23d0650392 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 10 Mar 2025 16:07:03 +0100 Subject: [PATCH 01/11] Add "Artist Note" input field to Save Workfile prompt --- client/ayon_core/tools/workfiles/abstract.py | 1 + client/ayon_core/tools/workfiles/control.py | 19 +++++++++++++------ .../tools/workfiles/widgets/files_widget.py | 4 +++- .../tools/workfiles/widgets/save_as_dialog.py | 11 +++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/tools/workfiles/abstract.py b/client/ayon_core/tools/workfiles/abstract.py index b78e987032..d9f3247305 100644 --- a/client/ayon_core/tools/workfiles/abstract.py +++ b/client/ayon_core/tools/workfiles/abstract.py @@ -1016,6 +1016,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon): workdir, filename, template_key, + artist_note, ): """Save current state of workfile to workarea. diff --git a/client/ayon_core/tools/workfiles/control.py b/client/ayon_core/tools/workfiles/control.py index ca97015eea..6634899bdc 100644 --- a/client/ayon_core/tools/workfiles/control.py +++ b/client/ayon_core/tools/workfiles/control.py @@ -554,6 +554,7 @@ class BaseWorkfileController( workdir, filename, template_key, + artist_note, ): self._emit_event("save_as.started") @@ -565,6 +566,7 @@ class BaseWorkfileController( workdir, filename, template_key, + artist_note=artist_note, ) except Exception: failed = True @@ -701,11 +703,12 @@ class BaseWorkfileController( def _save_as_workfile( self, - folder_id, - task_id, - workdir, - filename, - template_key, + folder_id: str, + task_id: str, + workdir: str, + filename: str, + template_key: str, + artist_note, src_filepath=None, ): # Trigger before save event @@ -748,7 +751,11 @@ class BaseWorkfileController( self._host_save_workfile(dst_filepath) # Make sure workfile info exists - self.save_workfile_info(folder_id, task_name, dst_filepath, None) + if not artist_note: + artist_note = None + self.save_workfile_info( + folder_id, task_name, dst_filepath, note=artist_note + ) # Create extra folders create_workdir_extra_folders( diff --git a/client/ayon_core/tools/workfiles/widgets/files_widget.py b/client/ayon_core/tools/workfiles/widgets/files_widget.py index dbe5966c31..2ff6298f3c 100644 --- a/client/ayon_core/tools/workfiles/widgets/files_widget.py +++ b/client/ayon_core/tools/workfiles/widgets/files_widget.py @@ -213,7 +213,8 @@ class FilesWidget(QtWidgets.QWidget): self._controller.duplicate_workfile( filepath, result["workdir"], - result["filename"] + result["filename"], + artist_note=result["artist_note"] ) def _on_workarea_browse_clicked(self): @@ -261,6 +262,7 @@ class FilesWidget(QtWidgets.QWidget): result["workdir"], result["filename"], result["template_key"], + artist_note=result["artist_note"] ) def _on_workarea_path_changed(self, event): diff --git a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py index 77dac1198a..6c2e340726 100644 --- a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py +++ b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py @@ -143,6 +143,11 @@ class SaveAsDialog(QtWidgets.QDialog): version_layout.addWidget(version_input) version_layout.addWidget(last_version_check) + # Artist note widget + artist_note_input = QtWidgets.QPlainTextEdit(inputs_widget) + artist_note_input.setPlaceholderText( + "Provide a note about this workfile.") + # Preview widget preview_widget = QtWidgets.QLabel("Preview filename", inputs_widget) preview_widget.setWordWrap(True) @@ -161,6 +166,7 @@ class SaveAsDialog(QtWidgets.QDialog): subversion_label = QtWidgets.QLabel("Subversion:", inputs_widget) extension_label = QtWidgets.QLabel("Extension:", inputs_widget) preview_label = QtWidgets.QLabel("Preview:", inputs_widget) + artist_note_label = QtWidgets.QLabel("Artist Note:", inputs_widget) # Build inputs inputs_layout = QtWidgets.QGridLayout(inputs_widget) @@ -172,6 +178,8 @@ class SaveAsDialog(QtWidgets.QDialog): inputs_layout.addWidget(extension_combobox, 2, 1) inputs_layout.addWidget(preview_label, 3, 0) inputs_layout.addWidget(preview_widget, 3, 1) + inputs_layout.addWidget(artist_note_label, 4, 0) + inputs_layout.addWidget(artist_note_input, 4, 1) # Build layout main_layout = QtWidgets.QVBoxLayout(self) @@ -206,11 +214,13 @@ class SaveAsDialog(QtWidgets.QDialog): self._extension_combobox = extension_combobox self._subversion_input = subversion_input self._preview_widget = preview_widget + self._artist_note_input = artist_note_input self._version_label = version_label self._subversion_label = subversion_label self._extension_label = extension_label self._preview_label = preview_label + self._artist_note_label = artist_note_label # Post init setup @@ -322,6 +332,7 @@ class SaveAsDialog(QtWidgets.QDialog): "folder_id": self._folder_id, "task_id": self._task_id, "template_key": self._template_key, + "artist_note": self._artist_note_input.toPlainText(), } self.close() From 4ce2ea74432dd6803dc4a1e39b918ea14a1145b7 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 10 Mar 2025 16:13:38 +0100 Subject: [PATCH 02/11] Fix duplicate workfile from published --- client/ayon_core/tools/workfiles/abstract.py | 3 ++- client/ayon_core/tools/workfiles/control.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/workfiles/abstract.py b/client/ayon_core/tools/workfiles/abstract.py index d9f3247305..53116c1029 100644 --- a/client/ayon_core/tools/workfiles/abstract.py +++ b/client/ayon_core/tools/workfiles/abstract.py @@ -1060,7 +1060,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon): pass @abstractmethod - def duplicate_workfile(self, src_filepath, workdir, filename): + def duplicate_workfile(self, src_filepath, workdir, filename, artist_note): """Duplicate workfile. Workfiles is not opened when done. @@ -1069,6 +1069,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon): src_filepath (str): Source workfile path. workdir (str): Destination workdir. filename (str): Destination filename. + artist_note (str): Artist note. """ pass diff --git a/client/ayon_core/tools/workfiles/control.py b/client/ayon_core/tools/workfiles/control.py index 6634899bdc..8d5b22fc32 100644 --- a/client/ayon_core/tools/workfiles/control.py +++ b/client/ayon_core/tools/workfiles/control.py @@ -610,7 +610,7 @@ class BaseWorkfileController( {"failed": failed}, ) - def duplicate_workfile(self, src_filepath, workdir, filename): + def duplicate_workfile(self, src_filepath, workdir, filename, artist_note): self._emit_event("workfile_duplicate.started") failed = False From 297756403455b841e886309d8991fed8f213abef Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 10 Mar 2025 16:16:49 +0100 Subject: [PATCH 03/11] Fix Copy to different context from published context --- client/ayon_core/tools/workfiles/abstract.py | 2 ++ client/ayon_core/tools/workfiles/control.py | 2 ++ client/ayon_core/tools/workfiles/widgets/files_widget.py | 1 + 3 files changed, 5 insertions(+) diff --git a/client/ayon_core/tools/workfiles/abstract.py b/client/ayon_core/tools/workfiles/abstract.py index 53116c1029..152ca33d99 100644 --- a/client/ayon_core/tools/workfiles/abstract.py +++ b/client/ayon_core/tools/workfiles/abstract.py @@ -1041,6 +1041,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon): workdir, filename, template_key, + artist_note, ): """Action to copy published workfile representation to workarea. @@ -1055,6 +1056,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon): workdir (str): Workarea directory. filename (str): Workarea filename. template_key (str): Template key. + artist_note (str): Artist note. """ pass diff --git a/client/ayon_core/tools/workfiles/control.py b/client/ayon_core/tools/workfiles/control.py index 8d5b22fc32..33c3b3f6e1 100644 --- a/client/ayon_core/tools/workfiles/control.py +++ b/client/ayon_core/tools/workfiles/control.py @@ -586,6 +586,7 @@ class BaseWorkfileController( workdir, filename, template_key, + artist_note, ): self._emit_event("copy_representation.started") @@ -597,6 +598,7 @@ class BaseWorkfileController( workdir, filename, template_key, + artist_note, src_filepath=representation_filepath ) except Exception: diff --git a/client/ayon_core/tools/workfiles/widgets/files_widget.py b/client/ayon_core/tools/workfiles/widgets/files_widget.py index 2ff6298f3c..f0b74f4289 100644 --- a/client/ayon_core/tools/workfiles/widgets/files_widget.py +++ b/client/ayon_core/tools/workfiles/widgets/files_widget.py @@ -315,6 +315,7 @@ class FilesWidget(QtWidgets.QWidget): result["workdir"], result["filename"], result["template_key"], + artist_note=result["artist_note"] ) def _on_save_as_request(self): From a1b0a24e548d3ebc90b38f00c14d5897e59013a3 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 11 Mar 2025 11:37:27 +0100 Subject: [PATCH 04/11] Update client/ayon_core/tools/workfiles/control.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/workfiles/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/workfiles/control.py b/client/ayon_core/tools/workfiles/control.py index 33c3b3f6e1..3a7459da0c 100644 --- a/client/ayon_core/tools/workfiles/control.py +++ b/client/ayon_core/tools/workfiles/control.py @@ -710,7 +710,7 @@ class BaseWorkfileController( workdir: str, filename: str, template_key: str, - artist_note, + artist_note: str, src_filepath=None, ): # Trigger before save event From 87124eee5360a2dc48a725ba918c9a455d714e54 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 11 Mar 2025 11:38:05 +0100 Subject: [PATCH 05/11] Update client/ayon_core/tools/workfiles/widgets/save_as_dialog.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/workfiles/widgets/save_as_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py index 6c2e340726..79a94a1d78 100644 --- a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py +++ b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py @@ -144,7 +144,7 @@ class SaveAsDialog(QtWidgets.QDialog): version_layout.addWidget(last_version_check) # Artist note widget - artist_note_input = QtWidgets.QPlainTextEdit(inputs_widget) + artist_note_input = PlaceholderPlainTextEdit(inputs_widget) artist_note_input.setPlaceholderText( "Provide a note about this workfile.") From 02265616749035873ceb472f11c14ef64fb462f3 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 11 Mar 2025 11:39:09 +0100 Subject: [PATCH 06/11] Add import --- client/ayon_core/tools/workfiles/widgets/save_as_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py index 79a94a1d78..f50c3e1368 100644 --- a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py +++ b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py @@ -1,6 +1,6 @@ from qtpy import QtWidgets, QtCore -from ayon_core.tools.utils import PlaceholderLineEdit +from ayon_core.tools.utils import PlaceholderLineEdit, PlaceholderPlainTextEdit class SubversionLineEdit(QtWidgets.QWidget): From aef050f390937a6fe6497869e3aec2aa98654363 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 19 Mar 2025 11:23:29 +0100 Subject: [PATCH 07/11] added function 'get_addons_resources_dir' --- client/ayon_core/lib/__init__.py | 2 ++ client/ayon_core/lib/local_settings.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/client/ayon_core/lib/__init__.py b/client/ayon_core/lib/__init__.py index 03ed574081..92c3966e77 100644 --- a/client/ayon_core/lib/__init__.py +++ b/client/ayon_core/lib/__init__.py @@ -9,6 +9,7 @@ from .local_settings import ( AYONSettingsRegistry, get_launcher_local_dir, get_launcher_storage_dir, + get_addons_resources_dir, get_local_site_id, get_ayon_username, ) @@ -142,6 +143,7 @@ __all__ = [ "AYONSettingsRegistry", "get_launcher_local_dir", "get_launcher_storage_dir", + "get_addons_resources_dir", "get_local_site_id", "get_ayon_username", diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index eff0068f00..d994145d4b 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -96,6 +96,30 @@ def get_launcher_local_dir(*subdirs: str) -> str: return os.path.join(storage_dir, *subdirs) +def get_addons_resources_dir(addon_name: str, *args) -> str: + """Get directory for storing resources for addons. + + Some addons might need to store ad-hoc resources that are not part of + addon client package (e.g. because of size). Studio might define + dedicated directory to store them with 'AYON_ADDONS_RESOURCES_DIR' + environment variable. By default, is used 'addons_resources' in + launcher storage (might be shared across platforms). + + Args: + addon_name (str): Addon name. + *args (str): Subfolders in resources directory. + + Returns: + str: Path to resources directory. + + """ + addons_resources_dir = os.getenv("AYON_ADDONS_RESOURCES_DIR") + if not addons_resources_dir: + addons_resources_dir = get_launcher_storage_dir("addons_resources") + + return os.path.join(addons_resources_dir, addon_name, *args) + + class AYONSecureRegistry: """Store information using keyring. From e56c71d3eaba32c35ae70371741be43433adaad2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:51:07 +0100 Subject: [PATCH 08/11] ceil height of 'ExpandingTextEdit' --- client/ayon_core/tools/utils/widgets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/utils/widgets.py b/client/ayon_core/tools/utils/widgets.py index 1074b6d4fb..f08e2fa5f2 100644 --- a/client/ayon_core/tools/utils/widgets.py +++ b/client/ayon_core/tools/utils/widgets.py @@ -1,4 +1,5 @@ import logging +import math from typing import Optional, List, Set, Any from qtpy import QtWidgets, QtCore, QtGui @@ -413,8 +414,8 @@ class ExpandingTextEdit(QtWidgets.QTextEdit): return margins.top() + document.size().height() + margins.bottom() def sizeHint(self): - width = super(ExpandingTextEdit, self).sizeHint().width() - return QtCore.QSize(width, self.heightForWidth(width)) + width = super().sizeHint().width() + return QtCore.QSize(width, math.ceil(self.heightForWidth(width))) class BaseClickableFrame(QtWidgets.QFrame): From fd4e5f58d48ee62757d6087802c9756e6a248f02 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 24 Mar 2025 16:06:14 +0100 Subject: [PATCH 09/11] change where the ceil happens --- client/ayon_core/tools/utils/widgets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/utils/widgets.py b/client/ayon_core/tools/utils/widgets.py index f08e2fa5f2..0cd6d68ab3 100644 --- a/client/ayon_core/tools/utils/widgets.py +++ b/client/ayon_core/tools/utils/widgets.py @@ -411,11 +411,13 @@ class ExpandingTextEdit(QtWidgets.QTextEdit): document = self.document().clone() document.setTextWidth(document_width) - return margins.top() + document.size().height() + margins.bottom() + return math.ceil( + margins.top() + document.size().height() + margins.bottom() + ) def sizeHint(self): width = super().sizeHint().width() - return QtCore.QSize(width, math.ceil(self.heightForWidth(width))) + return QtCore.QSize(width, self.heightForWidth(width)) class BaseClickableFrame(QtWidgets.QFrame): From 04e91389e17a7636c9c1aaeb61bc9554bbb257b9 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 25 Mar 2025 22:55:11 +0100 Subject: [PATCH 10/11] Make launcher project filter field case insensitive --- client/ayon_core/tools/utils/projects_widget.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/tools/utils/projects_widget.py b/client/ayon_core/tools/utils/projects_widget.py index fd361493ab..88d8a6c9f5 100644 --- a/client/ayon_core/tools/utils/projects_widget.py +++ b/client/ayon_core/tools/utils/projects_widget.py @@ -286,6 +286,7 @@ class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel): self._sort_by_type = True # Disable case sensitivity self.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive) + self.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) def _type_sort(self, l_index, r_index): if not self._sort_by_type: From 8c919be06865c06fa5b2baa80134a266c9e6f3fd Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 26 Mar 2025 12:10:59 +0100 Subject: [PATCH 11/11] Update client/ayon_core/tools/workfiles/widgets/save_as_dialog.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/workfiles/widgets/save_as_dialog.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py index f50c3e1368..bddff816fe 100644 --- a/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py +++ b/client/ayon_core/tools/workfiles/widgets/save_as_dialog.py @@ -178,8 +178,8 @@ class SaveAsDialog(QtWidgets.QDialog): inputs_layout.addWidget(extension_combobox, 2, 1) inputs_layout.addWidget(preview_label, 3, 0) inputs_layout.addWidget(preview_widget, 3, 1) - inputs_layout.addWidget(artist_note_label, 4, 0) - inputs_layout.addWidget(artist_note_input, 4, 1) + inputs_layout.addWidget(artist_note_label, 4, 0, 1, 2) + inputs_layout.addWidget(artist_note_input, 5, 0, 1, 2) # Build layout main_layout = QtWidgets.QVBoxLayout(self)