From 682d8e6b0551935645724e0b632fb5736448979f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 26 May 2023 12:28:45 +0800 Subject: [PATCH 01/15] custom script for setting frame range for read node --- openpype/hosts/nuke/api/lib.py | 30 ++++++ openpype/hosts/nuke/api/pipeline.py | 5 + openpype/widgets/custom_popup.py | 141 ++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 openpype/widgets/custom_popup.py diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index a439142051..1aa0a95c86 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2358,6 +2358,36 @@ class WorkfileSettings(object): # add colorspace menu item self.set_colorspace() + def reset_frame_range_read_nodes(self): + from openpype.widgets import custom_popup + parent = get_main_window() + dialog = custom_popup.CustomScriptDialog(parent=parent) + dialog.setWindowTitle("Frame Range for Read Node") + dialog.set_name("Frame Range: ") + dialog.set_line_edit("%s - %s" % (nuke.root().firstFrame(), + nuke.root().lastFrame())) + frame = dialog.widgets["line_edit"] + selection = dialog.widgets["selection"] + dialog.on_clicked.connect( + lambda: set_frame_range(frame, selection) + ) + def set_frame_range(frame, selection): + frame_range = frame.text() + selected = selection.isChecked() + for read_node in nuke.allNodes("Read"): + if selected: + if not nuke.selectedNodes(): + return + if read_node in nuke.selectedNodes(): + read_node["frame_mode"].setValue("start_at") + read_node["frame"].setValue(frame_range) + else: + read_node["frame_mode"].setValue("start_at") + read_node["frame"].setValue(frame_range) + dialog.show() + + return False + def set_favorites(self): from .utils import set_context_favorites diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index d649ffae7f..8d6be76e48 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -282,6 +282,11 @@ def _install_menu(): lambda: WorkfileSettings().set_context_settings() ) + menu.addSeparator() + menu.addCommand( + "Set Frame Range(Read Node)", + lambda: WorkfileSettings().reset_frame_range_read_nodes() + ) menu.addSeparator() menu.addCommand( "Build Workfile", diff --git a/openpype/widgets/custom_popup.py b/openpype/widgets/custom_popup.py new file mode 100644 index 0000000000..c4bb1ad43b --- /dev/null +++ b/openpype/widgets/custom_popup.py @@ -0,0 +1,141 @@ +import sys +import contextlib + +from PySide2 import QtCore, QtWidgets + + +class CustomScriptDialog(QtWidgets.QDialog): + """A Popup that moves itself to bottom right of screen on show event. + + The UI contains a message label and a red highlighted button to "show" + or perform another custom action from this pop-up. + + """ + + on_clicked = QtCore.Signal() + on_line_changed = QtCore.Signal(str) + + def __init__(self, parent=None, *args, **kwargs): + super(CustomScriptDialog, self).__init__(parent=parent, *args, **kwargs) + self.setContentsMargins(0, 0, 0, 0) + + # Layout + layout = QtWidgets.QVBoxLayout(self) + line_layout = QtWidgets.QHBoxLayout() + line_layout.setContentsMargins(10, 5, 10, 10) + selection_layout = QtWidgets.QHBoxLayout() + selection_layout.setContentsMargins(10, 5, 10, 10) + button_layout = QtWidgets.QHBoxLayout() + button_layout.setContentsMargins(10, 5, 10, 10) + + # Increase spacing slightly for readability + line_layout.setSpacing(10) + button_layout.setSpacing(8) + name = QtWidgets.QLabel("") + name.setStyleSheet(""" + QLabel { + font-size: 12px; + } + """) + line_edit = QtWidgets.QLineEdit("") + selection_name = QtWidgets.QLabel("Use Selection") + selection_name.setStyleSheet(""" + QLabel { + font-size: 12px; + } + """) + has_selection = QtWidgets.QCheckBox() + button = QtWidgets.QPushButton("Execute") + button.setSizePolicy(QtWidgets.QSizePolicy.Maximum, + QtWidgets.QSizePolicy.Maximum) + cancel = QtWidgets.QPushButton("Cancel") + cancel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, + QtWidgets.QSizePolicy.Maximum) + + line_layout.addWidget(name) + line_layout.addWidget(line_edit) + selection_layout.addWidget(selection_name) + selection_layout.addWidget(has_selection) + button_layout.addWidget(button) + button_layout.addWidget(cancel) + layout.addLayout(line_layout) + layout.addLayout(selection_layout) + layout.addLayout(button_layout) + # Default size + self.resize(100, 30) + + self.widgets = { + "name": name, + "line_edit": line_edit, + "selection": has_selection, + "button": button, + "cancel": cancel + } + + # Signals + has_selection.toggled.connect(self.emit_click_with_state) + line_edit.textChanged.connect(self.on_line_edit_changed) + button.clicked.connect(self._on_clicked) + cancel.clicked.connect(self.close) + self.update_values() + # Set default title + self.setWindowTitle("Custom Popup") + + def update_values(self): + self.widgets["selection"].isChecked() + + def emit_click_with_state(self): + """Emit the on_clicked signal with the toggled state""" + checked = self.widgets["selection"].isChecked() + return checked + + def set_name(self, name): + self.widgets['name'].setText(name) + + def set_line_edit(self, line_edit): + self.widgets['line_edit'].setText(line_edit) + print(line_edit) + + def setButtonText(self, text): + self.widgets["button"].setText(text) + + def setCancelText(self, text): + self.widgets["cancel"].setText(text) + + def on_line_edit_changed(self): + line_edit = self.widgets['line_edit'].text() + self.on_line_changed.emit(line_edit) + return self.set_line_edit(line_edit) + + + def _on_clicked(self): + """Callback for when the 'show' button is clicked. + + Raises the parent (if any) + + """ + + parent = self.parent() + self.close() + + # Trigger the signal + self.on_clicked.emit() + + if parent: + parent.raise_() + + def showEvent(self, event): + + # Position popup based on contents on show event + return super(CustomScriptDialog, self).showEvent(event) + +@contextlib.contextmanager +def application(): + app = QtWidgets.QApplication(sys.argv) + yield + app.exec_() + +if __name__ == "__main__": + with application(): + dialog = CustomScriptDialog() + dialog.show() From 3ece2a8fcf73fa7d0da438ef056447fd7967c6ee Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 26 May 2023 12:56:11 +0800 Subject: [PATCH 02/15] clean up & cosmetic fix --- openpype/hosts/nuke/api/lib.py | 5 ++++- openpype/widgets/custom_popup.py | 12 +++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 1aa0a95c86..94a0ff15ad 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2362,7 +2362,7 @@ class WorkfileSettings(object): from openpype.widgets import custom_popup parent = get_main_window() dialog = custom_popup.CustomScriptDialog(parent=parent) - dialog.setWindowTitle("Frame Range for Read Node") + dialog.setWindowTitle("Frame Range") dialog.set_name("Frame Range: ") dialog.set_line_edit("%s - %s" % (nuke.root().firstFrame(), nuke.root().lastFrame())) @@ -2371,9 +2371,12 @@ class WorkfileSettings(object): dialog.on_clicked.connect( lambda: set_frame_range(frame, selection) ) + def set_frame_range(frame, selection): frame_range = frame.text() selected = selection.isChecked() + if not nuke.allNodes("Read"): + return for read_node in nuke.allNodes("Read"): if selected: if not nuke.selectedNodes(): diff --git a/openpype/widgets/custom_popup.py b/openpype/widgets/custom_popup.py index c4bb1ad43b..85e31d6ce0 100644 --- a/openpype/widgets/custom_popup.py +++ b/openpype/widgets/custom_popup.py @@ -16,7 +16,9 @@ class CustomScriptDialog(QtWidgets.QDialog): on_line_changed = QtCore.Signal(str) def __init__(self, parent=None, *args, **kwargs): - super(CustomScriptDialog, self).__init__(parent=parent, *args, **kwargs) + super(CustomScriptDialog, self).__init__(parent=parent, + *args, + **kwargs) self.setContentsMargins(0, 0, 0, 0) # Layout @@ -30,7 +32,7 @@ class CustomScriptDialog(QtWidgets.QDialog): # Increase spacing slightly for readability line_layout.setSpacing(10) - button_layout.setSpacing(8) + button_layout.setSpacing(10) name = QtWidgets.QLabel("") name.setStyleSheet(""" QLabel { @@ -47,7 +49,7 @@ class CustomScriptDialog(QtWidgets.QDialog): has_selection = QtWidgets.QCheckBox() button = QtWidgets.QPushButton("Execute") button.setSizePolicy(QtWidgets.QSizePolicy.Maximum, - QtWidgets.QSizePolicy.Maximum) + QtWidgets.QSizePolicy.Maximum) cancel = QtWidgets.QPushButton("Cancel") cancel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) @@ -62,7 +64,7 @@ class CustomScriptDialog(QtWidgets.QDialog): layout.addLayout(selection_layout) layout.addLayout(button_layout) # Default size - self.resize(100, 30) + self.resize(100, 40) self.widgets = { "name": name, @@ -107,7 +109,6 @@ class CustomScriptDialog(QtWidgets.QDialog): self.on_line_changed.emit(line_edit) return self.set_line_edit(line_edit) - def _on_clicked(self): """Callback for when the 'show' button is clicked. @@ -129,6 +130,7 @@ class CustomScriptDialog(QtWidgets.QDialog): # Position popup based on contents on show event return super(CustomScriptDialog, self).showEvent(event) + @contextlib.contextmanager def application(): app = QtWidgets.QApplication(sys.argv) From 54cccc6a6af7f4d3e04e47173b3e302dbc5d2aa0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 26 May 2023 12:57:05 +0800 Subject: [PATCH 03/15] hound --- openpype/widgets/custom_popup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/widgets/custom_popup.py b/openpype/widgets/custom_popup.py index 85e31d6ce0..be4b0c32d5 100644 --- a/openpype/widgets/custom_popup.py +++ b/openpype/widgets/custom_popup.py @@ -137,6 +137,7 @@ def application(): yield app.exec_() + if __name__ == "__main__": with application(): dialog = CustomScriptDialog() From 2e58cd2e1a1a1dd23e0bc59bc1cbc414fa6d1ec9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 30 May 2023 21:44:26 +0800 Subject: [PATCH 04/15] move the custom popup menu to nuke/startup and add the frame setting to Openpype tool menu --- openpype/hosts/nuke/api/lib.py | 32 --------- openpype/hosts/nuke/api/pipeline.py | 5 -- .../nuke/startup}/custom_popup.py | 71 ++++++++++++++----- .../defaults/project_settings/nuke.json | 7 ++ 4 files changed, 61 insertions(+), 54 deletions(-) rename openpype/{widgets => hosts/nuke/startup}/custom_popup.py (65%) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 94a0ff15ad..59a63d1373 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2358,38 +2358,6 @@ class WorkfileSettings(object): # add colorspace menu item self.set_colorspace() - def reset_frame_range_read_nodes(self): - from openpype.widgets import custom_popup - parent = get_main_window() - dialog = custom_popup.CustomScriptDialog(parent=parent) - dialog.setWindowTitle("Frame Range") - dialog.set_name("Frame Range: ") - dialog.set_line_edit("%s - %s" % (nuke.root().firstFrame(), - nuke.root().lastFrame())) - frame = dialog.widgets["line_edit"] - selection = dialog.widgets["selection"] - dialog.on_clicked.connect( - lambda: set_frame_range(frame, selection) - ) - - def set_frame_range(frame, selection): - frame_range = frame.text() - selected = selection.isChecked() - if not nuke.allNodes("Read"): - return - for read_node in nuke.allNodes("Read"): - if selected: - if not nuke.selectedNodes(): - return - if read_node in nuke.selectedNodes(): - read_node["frame_mode"].setValue("start_at") - read_node["frame"].setValue(frame_range) - else: - read_node["frame_mode"].setValue("start_at") - read_node["frame"].setValue(frame_range) - dialog.show() - - return False def set_favorites(self): from .utils import set_context_favorites diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 33e25d3c81..75b0f80d21 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -286,11 +286,6 @@ def _install_menu(): lambda: WorkfileSettings().set_context_settings() ) - menu.addSeparator() - menu.addCommand( - "Set Frame Range(Read Node)", - lambda: WorkfileSettings().reset_frame_range_read_nodes() - ) menu.addSeparator() menu.addCommand( "Build Workfile", diff --git a/openpype/widgets/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py similarity index 65% rename from openpype/widgets/custom_popup.py rename to openpype/hosts/nuke/startup/custom_popup.py index be4b0c32d5..c85577133c 100644 --- a/openpype/widgets/custom_popup.py +++ b/openpype/hosts/nuke/startup/custom_popup.py @@ -1,9 +1,26 @@ import sys import contextlib - +import re +import nuke from PySide2 import QtCore, QtWidgets +def get_main_window(): + """Acquire Nuke's main window""" + main_window = None + if main_window is None: + + top_widgets = QtWidgets.QApplication.topLevelWidgets() + name = "Foundry::UI::DockMainWindow" + for widget in top_widgets: + if ( + widget.inherits("QMainWindow") + and widget.metaObject().className() == name + ): + main_window = widget + break + return main_window + class CustomScriptDialog(QtWidgets.QDialog): """A Popup that moves itself to bottom right of screen on show event. @@ -14,6 +31,9 @@ class CustomScriptDialog(QtWidgets.QDialog): on_clicked = QtCore.Signal() on_line_changed = QtCore.Signal(str) + context = None + + def __init__(self, parent=None, *args, **kwargs): super(CustomScriptDialog, self).__init__(parent=parent, @@ -23,23 +43,25 @@ class CustomScriptDialog(QtWidgets.QDialog): # Layout layout = QtWidgets.QVBoxLayout(self) - line_layout = QtWidgets.QHBoxLayout() - line_layout.setContentsMargins(10, 5, 10, 10) + frame_layout = QtWidgets.QHBoxLayout() + frame_layout.setContentsMargins(10, 5, 10, 10) selection_layout = QtWidgets.QHBoxLayout() selection_layout.setContentsMargins(10, 5, 10, 10) button_layout = QtWidgets.QHBoxLayout() button_layout.setContentsMargins(10, 5, 10, 10) # Increase spacing slightly for readability - line_layout.setSpacing(10) + frame_layout.setSpacing(10) button_layout.setSpacing(10) - name = QtWidgets.QLabel("") + name = QtWidgets.QLabel("Frame Range: ") name.setStyleSheet(""" QLabel { font-size: 12px; } """) - line_edit = QtWidgets.QLineEdit("") + line_edit = QtWidgets.QLineEdit( + "%s-%s" % (nuke.root().firstFrame(), + nuke.root().lastFrame())) selection_name = QtWidgets.QLabel("Use Selection") selection_name.setStyleSheet(""" QLabel { @@ -54,13 +76,13 @@ class CustomScriptDialog(QtWidgets.QDialog): cancel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) - line_layout.addWidget(name) - line_layout.addWidget(line_edit) + frame_layout.addWidget(name) + frame_layout.addWidget(line_edit) selection_layout.addWidget(selection_name) selection_layout.addWidget(has_selection) button_layout.addWidget(button) button_layout.addWidget(cancel) - layout.addLayout(line_layout) + layout.addLayout(frame_layout) layout.addLayout(selection_layout) layout.addLayout(button_layout) # Default size @@ -73,7 +95,6 @@ class CustomScriptDialog(QtWidgets.QDialog): "button": button, "cancel": cancel } - # Signals has_selection.toggled.connect(self.emit_click_with_state) line_edit.textChanged.connect(self.on_line_edit_changed) @@ -115,18 +136,34 @@ class CustomScriptDialog(QtWidgets.QDialog): Raises the parent (if any) """ + frame_range = self.widgets['line_edit'].text() + selected = self.widgets["selection"].isChecked() + pattern = r"^(?P-?[0-9]+)(?:(?:-+)(?P-?[0-9]+))?$" + match = re.match(pattern, frame_range) + frame_start = int(match.group("start")) + frame_end = int(match.group("end")) + if not nuke.allNodes("Read"): + return + for read_node in nuke.allNodes("Read"): + if selected: + if not nuke.selectedNodes(): + return + if read_node in nuke.selectedNodes(): + read_node["frame_mode"].setValue("start_at") + read_node["frame"].setValue(frame_range) + read_node["first"].setValue(frame_start) + read_node["last"].setValue(frame_end) + else: + read_node["frame_mode"].setValue("start_at") + read_node["frame"].setValue(frame_range) + read_node["first"].setValue(frame_start) + read_node["last"].setValue(frame_end) - parent = self.parent() self.close() - # Trigger the signal - self.on_clicked.emit() - - if parent: - parent.raise_() + return False def showEvent(self, event): - # Position popup based on contents on show event return super(CustomScriptDialog, self).showEvent(event) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index f01bdf7d50..287d13e5c9 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -222,6 +222,13 @@ "title": "OpenPype Docs", "command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_nuke_tut')", "tooltip": "Open the OpenPype Nuke user doc page" + }, + { + "type": "action", + "sourcetype": "python", + "title": "Set Frame Range(Read Node)", + "command": "from openpype.hosts.nuke.startup import custom_popup;from openpype.hosts.nuke.startup.custom_popup import get_main_window;custom_popup.CustomScriptDialog(parent=get_main_window()).show();", + "tooltip": "Set Frame Range for Read Node(s)" } ] }, From 3556b58fdc593eef0c22eb3d6b357e0c0ac0be7c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 30 May 2023 21:46:25 +0800 Subject: [PATCH 05/15] hound fix --- openpype/hosts/nuke/api/lib.py | 1 - openpype/hosts/nuke/startup/custom_popup.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 59a63d1373..a439142051 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2358,7 +2358,6 @@ class WorkfileSettings(object): # add colorspace menu item self.set_colorspace() - def set_favorites(self): from .utils import set_context_favorites diff --git a/openpype/hosts/nuke/startup/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py index c85577133c..dfbd590e03 100644 --- a/openpype/hosts/nuke/startup/custom_popup.py +++ b/openpype/hosts/nuke/startup/custom_popup.py @@ -21,6 +21,7 @@ def get_main_window(): break return main_window + class CustomScriptDialog(QtWidgets.QDialog): """A Popup that moves itself to bottom right of screen on show event. @@ -34,7 +35,6 @@ class CustomScriptDialog(QtWidgets.QDialog): context = None - def __init__(self, parent=None, *args, **kwargs): super(CustomScriptDialog, self).__init__(parent=parent, *args, From dddfeecceb4c711e1d8b848c8454d529992e6182 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 30 May 2023 21:47:03 +0800 Subject: [PATCH 06/15] hound fix --- openpype/hosts/nuke/startup/custom_popup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/nuke/startup/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py index dfbd590e03..d400ed913c 100644 --- a/openpype/hosts/nuke/startup/custom_popup.py +++ b/openpype/hosts/nuke/startup/custom_popup.py @@ -34,7 +34,6 @@ class CustomScriptDialog(QtWidgets.QDialog): on_line_changed = QtCore.Signal(str) context = None - def __init__(self, parent=None, *args, **kwargs): super(CustomScriptDialog, self).__init__(parent=parent, *args, From 8f0821ab327db90a6fba5d95594bdcc461fb33e3 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 30 May 2023 22:12:47 +0800 Subject: [PATCH 07/15] the dialog closes as usual by clicking execute button when there is no nuke nodes or no nuke nodes by selection --- openpype/hosts/nuke/startup/custom_popup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/startup/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py index d400ed913c..57d79f99ff 100644 --- a/openpype/hosts/nuke/startup/custom_popup.py +++ b/openpype/hosts/nuke/startup/custom_popup.py @@ -142,10 +142,12 @@ class CustomScriptDialog(QtWidgets.QDialog): frame_start = int(match.group("start")) frame_end = int(match.group("end")) if not nuke.allNodes("Read"): + self.close() return for read_node in nuke.allNodes("Read"): if selected: if not nuke.selectedNodes(): + self.close() return if read_node in nuke.selectedNodes(): read_node["frame_mode"].setValue("start_at") From 11728bae0e4f1a539d5959ec3cfe9fe523fe356a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 31 May 2023 20:02:05 +0800 Subject: [PATCH 08/15] roy's comment and uses import instead of from..import --- openpype/hosts/nuke/startup/custom_popup.py | 17 ++++------------- .../defaults/project_settings/nuke.json | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/nuke/startup/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py index 57d79f99ff..7f60fdc70b 100644 --- a/openpype/hosts/nuke/startup/custom_popup.py +++ b/openpype/hosts/nuke/startup/custom_popup.py @@ -23,10 +23,7 @@ def get_main_window(): class CustomScriptDialog(QtWidgets.QDialog): - """A Popup that moves itself to bottom right of screen on show event. - - The UI contains a message label and a red highlighted button to "show" - or perform another custom action from this pop-up. + """A Custom Popup For Nuke Read Node """ @@ -95,7 +92,7 @@ class CustomScriptDialog(QtWidgets.QDialog): "cancel": cancel } # Signals - has_selection.toggled.connect(self.emit_click_with_state) + has_selection.toggled.connect(self.on_checked_changed) line_edit.textChanged.connect(self.on_line_edit_changed) button.clicked.connect(self._on_clicked) cancel.clicked.connect(self.close) @@ -104,10 +101,9 @@ class CustomScriptDialog(QtWidgets.QDialog): self.setWindowTitle("Custom Popup") def update_values(self): - self.widgets["selection"].isChecked() + return self.widgets["selection"].isChecked() - def emit_click_with_state(self): - """Emit the on_clicked signal with the toggled state""" + def on_checked_changed(self): checked = self.widgets["selection"].isChecked() return checked @@ -164,11 +160,6 @@ class CustomScriptDialog(QtWidgets.QDialog): return False - def showEvent(self, event): - # Position popup based on contents on show event - return super(CustomScriptDialog, self).showEvent(event) - - @contextlib.contextmanager def application(): app = QtWidgets.QApplication(sys.argv) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 287d13e5c9..c116540a99 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -227,7 +227,7 @@ "type": "action", "sourcetype": "python", "title": "Set Frame Range(Read Node)", - "command": "from openpype.hosts.nuke.startup import custom_popup;from openpype.hosts.nuke.startup.custom_popup import get_main_window;custom_popup.CustomScriptDialog(parent=get_main_window()).show();", + "command": "import openpype.hosts.nuke.startup.custom_popup as popup;popup.CustomScriptDialog(parent=popup.get_main_window()).show();", "tooltip": "Set Frame Range for Read Node(s)" } ] From 803dd565751bb65a6ef5b97e7c6f5447f4534717 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 31 May 2023 20:03:18 +0800 Subject: [PATCH 09/15] hound fix --- openpype/hosts/nuke/startup/custom_popup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/nuke/startup/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py index 7f60fdc70b..76d5a25596 100644 --- a/openpype/hosts/nuke/startup/custom_popup.py +++ b/openpype/hosts/nuke/startup/custom_popup.py @@ -160,6 +160,7 @@ class CustomScriptDialog(QtWidgets.QDialog): return False + @contextlib.contextmanager def application(): app = QtWidgets.QApplication(sys.argv) From 183b2866d9e1f1f7b611fa6860c1edc315798b66 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 31 May 2023 20:14:57 +0800 Subject: [PATCH 10/15] style fix --- openpype/settings/defaults/project_settings/nuke.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index c116540a99..35e5b1975c 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -226,7 +226,7 @@ { "type": "action", "sourcetype": "python", - "title": "Set Frame Range(Read Node)", + "title": "Set Frame Range (Read Node)", "command": "import openpype.hosts.nuke.startup.custom_popup as popup;popup.CustomScriptDialog(parent=popup.get_main_window()).show();", "tooltip": "Set Frame Range for Read Node(s)" } From a30ba51508f03c1adbac8c434432a80184d0665b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 1 Jun 2023 00:11:30 +0800 Subject: [PATCH 11/15] use nukescript's panel --- openpype/hosts/nuke/startup/custom_popup.py | 174 ------------------ .../startup/ops_frame_setting_for_read.py | 46 +++++ .../defaults/project_settings/nuke.json | 2 +- 3 files changed, 47 insertions(+), 175 deletions(-) delete mode 100644 openpype/hosts/nuke/startup/custom_popup.py create mode 100644 openpype/hosts/nuke/startup/ops_frame_setting_for_read.py diff --git a/openpype/hosts/nuke/startup/custom_popup.py b/openpype/hosts/nuke/startup/custom_popup.py deleted file mode 100644 index 76d5a25596..0000000000 --- a/openpype/hosts/nuke/startup/custom_popup.py +++ /dev/null @@ -1,174 +0,0 @@ -import sys -import contextlib -import re -import nuke -from PySide2 import QtCore, QtWidgets - - -def get_main_window(): - """Acquire Nuke's main window""" - main_window = None - if main_window is None: - - top_widgets = QtWidgets.QApplication.topLevelWidgets() - name = "Foundry::UI::DockMainWindow" - for widget in top_widgets: - if ( - widget.inherits("QMainWindow") - and widget.metaObject().className() == name - ): - main_window = widget - break - return main_window - - -class CustomScriptDialog(QtWidgets.QDialog): - """A Custom Popup For Nuke Read Node - - """ - - on_clicked = QtCore.Signal() - on_line_changed = QtCore.Signal(str) - context = None - - def __init__(self, parent=None, *args, **kwargs): - super(CustomScriptDialog, self).__init__(parent=parent, - *args, - **kwargs) - self.setContentsMargins(0, 0, 0, 0) - - # Layout - layout = QtWidgets.QVBoxLayout(self) - frame_layout = QtWidgets.QHBoxLayout() - frame_layout.setContentsMargins(10, 5, 10, 10) - selection_layout = QtWidgets.QHBoxLayout() - selection_layout.setContentsMargins(10, 5, 10, 10) - button_layout = QtWidgets.QHBoxLayout() - button_layout.setContentsMargins(10, 5, 10, 10) - - # Increase spacing slightly for readability - frame_layout.setSpacing(10) - button_layout.setSpacing(10) - name = QtWidgets.QLabel("Frame Range: ") - name.setStyleSheet(""" - QLabel { - font-size: 12px; - } - """) - line_edit = QtWidgets.QLineEdit( - "%s-%s" % (nuke.root().firstFrame(), - nuke.root().lastFrame())) - selection_name = QtWidgets.QLabel("Use Selection") - selection_name.setStyleSheet(""" - QLabel { - font-size: 12px; - } - """) - has_selection = QtWidgets.QCheckBox() - button = QtWidgets.QPushButton("Execute") - button.setSizePolicy(QtWidgets.QSizePolicy.Maximum, - QtWidgets.QSizePolicy.Maximum) - cancel = QtWidgets.QPushButton("Cancel") - cancel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, - QtWidgets.QSizePolicy.Maximum) - - frame_layout.addWidget(name) - frame_layout.addWidget(line_edit) - selection_layout.addWidget(selection_name) - selection_layout.addWidget(has_selection) - button_layout.addWidget(button) - button_layout.addWidget(cancel) - layout.addLayout(frame_layout) - layout.addLayout(selection_layout) - layout.addLayout(button_layout) - # Default size - self.resize(100, 40) - - self.widgets = { - "name": name, - "line_edit": line_edit, - "selection": has_selection, - "button": button, - "cancel": cancel - } - # Signals - has_selection.toggled.connect(self.on_checked_changed) - line_edit.textChanged.connect(self.on_line_edit_changed) - button.clicked.connect(self._on_clicked) - cancel.clicked.connect(self.close) - self.update_values() - # Set default title - self.setWindowTitle("Custom Popup") - - def update_values(self): - return self.widgets["selection"].isChecked() - - def on_checked_changed(self): - checked = self.widgets["selection"].isChecked() - return checked - - def set_name(self, name): - self.widgets['name'].setText(name) - - def set_line_edit(self, line_edit): - self.widgets['line_edit'].setText(line_edit) - print(line_edit) - - def setButtonText(self, text): - self.widgets["button"].setText(text) - - def setCancelText(self, text): - self.widgets["cancel"].setText(text) - - def on_line_edit_changed(self): - line_edit = self.widgets['line_edit'].text() - self.on_line_changed.emit(line_edit) - return self.set_line_edit(line_edit) - - def _on_clicked(self): - """Callback for when the 'show' button is clicked. - - Raises the parent (if any) - - """ - frame_range = self.widgets['line_edit'].text() - selected = self.widgets["selection"].isChecked() - pattern = r"^(?P-?[0-9]+)(?:(?:-+)(?P-?[0-9]+))?$" - match = re.match(pattern, frame_range) - frame_start = int(match.group("start")) - frame_end = int(match.group("end")) - if not nuke.allNodes("Read"): - self.close() - return - for read_node in nuke.allNodes("Read"): - if selected: - if not nuke.selectedNodes(): - self.close() - return - if read_node in nuke.selectedNodes(): - read_node["frame_mode"].setValue("start_at") - read_node["frame"].setValue(frame_range) - read_node["first"].setValue(frame_start) - read_node["last"].setValue(frame_end) - else: - read_node["frame_mode"].setValue("start_at") - read_node["frame"].setValue(frame_range) - read_node["first"].setValue(frame_start) - read_node["last"].setValue(frame_end) - - self.close() - - return False - - -@contextlib.contextmanager -def application(): - app = QtWidgets.QApplication(sys.argv) - yield - app.exec_() - - -if __name__ == "__main__": - with application(): - dialog = CustomScriptDialog() - dialog.show() diff --git a/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py b/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py new file mode 100644 index 0000000000..153effc7ad --- /dev/null +++ b/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py @@ -0,0 +1,46 @@ +import nuke +import nukescripts +import re + + +class FrameSettingsPanel(nukescripts.PythonPanel): + def __init__(self, node): + nukescripts.PythonPanel.__init__(self, 'Frame Range') + self.read_node = node + # CREATE KNOBS + self.range = nuke.String_Knob('fRange', 'Frame Range', '%s-%s' % + (nuke.root().firstFrame(), nuke.root().lastFrame())) + self.selected = nuke.Boolean_Knob("selection") + # ADD KNOBS + self.addKnob(self.selected) + self.addKnob(self.range) + self.selected.setValue(False) + + def knobChanged(self, knob): + frame_range = self.range.value() + pattern = r"^(?P-?[0-9]+)(?:(?:-+)(?P-?[0-9]+))?$" + match = re.match(pattern, frame_range) + frame_start = int(match.group("start")) + frame_end = int(match.group("end")) + if not self.read_node: + return + for r in self.read_node: + if self.onchecked(): + if not nuke.selectedNodes(): + return + if r in nuke.selectedNodes(): + r["frame_mode"].setValue("start_at") + r["frame"].setValue(frame_range) + r["first"].setValue(frame_start) + r["last"].setValue(frame_end) + else: + r["frame_mode"].setValue("start_at") + r["frame"].setValue(frame_range) + r["first"].setValue(frame_start) + r["last"].setValue(frame_end) + + def onchecked(self): + if self.selected.value(): + return True + else: + return False diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 35e5b1975c..cb06ad0a3b 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -227,7 +227,7 @@ "type": "action", "sourcetype": "python", "title": "Set Frame Range (Read Node)", - "command": "import openpype.hosts.nuke.startup.custom_popup as popup;popup.CustomScriptDialog(parent=popup.get_main_window()).show();", + "command": "import ops_frame_setting_for_read as popup;import nuke;popup.FrameSettingsPanel(nuke.allNodes('Read')).showModalDialog();", "tooltip": "Set Frame Range for Read Node(s)" } ] From 0655a6222bf3c69f4b4b3e9008c6c7803ffd3f94 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 1 Jun 2023 00:12:22 +0800 Subject: [PATCH 12/15] hound fix --- openpype/hosts/nuke/startup/ops_frame_setting_for_read.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py b/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py index 153effc7ad..bf98ef83f6 100644 --- a/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py +++ b/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py @@ -9,11 +9,14 @@ class FrameSettingsPanel(nukescripts.PythonPanel): self.read_node = node # CREATE KNOBS self.range = nuke.String_Knob('fRange', 'Frame Range', '%s-%s' % - (nuke.root().firstFrame(), nuke.root().lastFrame())) + (nuke.root().firstFrame(), + nuke.root().lastFrame())) self.selected = nuke.Boolean_Knob("selection") + self.info = nuke.Help_Knob("Instruction") # ADD KNOBS self.addKnob(self.selected) self.addKnob(self.range) + self.addKnob(self.info) self.selected.setValue(False) def knobChanged(self, knob): From 021ea8d6380e439ccddcdbf3ac78542b4329a7e1 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 1 Jun 2023 00:30:19 +0800 Subject: [PATCH 13/15] update the command --- openpype/settings/defaults/project_settings/nuke.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index cb06ad0a3b..a0caa40396 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -227,7 +227,7 @@ "type": "action", "sourcetype": "python", "title": "Set Frame Range (Read Node)", - "command": "import ops_frame_setting_for_read as popup;import nuke;popup.FrameSettingsPanel(nuke.allNodes('Read')).showModalDialog();", + "command": "import openpype.hosts.nuke.startup.ops_frame_setting_for_read as popup;import nuke;popup.FrameSettingsPanel(nuke.allNodes('Read')).showModalDialog();", "tooltip": "Set Frame Range for Read Node(s)" } ] From abc266e9e5868277b47c2dabdd1697ec13d1a024 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 1 Jun 2023 16:14:29 +0200 Subject: [PATCH 14/15] refactor the script to be frame number rather then frame range --- .../startup/frame_setting_for_read_nodes.py | 47 ++++++++++++++++++ .../startup/ops_frame_setting_for_read.py | 49 ------------------- .../defaults/project_settings/nuke.json | 6 +-- 3 files changed, 50 insertions(+), 52 deletions(-) create mode 100644 openpype/hosts/nuke/startup/frame_setting_for_read_nodes.py delete mode 100644 openpype/hosts/nuke/startup/ops_frame_setting_for_read.py diff --git a/openpype/hosts/nuke/startup/frame_setting_for_read_nodes.py b/openpype/hosts/nuke/startup/frame_setting_for_read_nodes.py new file mode 100644 index 0000000000..f0cbabe20f --- /dev/null +++ b/openpype/hosts/nuke/startup/frame_setting_for_read_nodes.py @@ -0,0 +1,47 @@ +""" OpenPype custom script for resetting read nodes start frame values """ + +import nuke +import nukescripts + + +class FrameSettingsPanel(nukescripts.PythonPanel): + """ Frame Settings Panel """ + def __init__(self): + nukescripts.PythonPanel.__init__(self, "Set Frame Start (Read Node)") + + # create knobs + self.frame = nuke.Int_Knob( + 'frame', 'Frame Number') + self.selected = nuke.Boolean_Knob("selection") + # add knobs to panel + self.addKnob(self.selected) + self.addKnob(self.frame) + + # set values + self.selected.setValue(False) + self.frame.setValue(nuke.root().firstFrame()) + + def process(self): + """ Process the panel values. """ + # get values + frame = self.frame.value() + if self.selected.value(): + # selected nodes processing + if not nuke.selectedNodes(): + return + for rn_ in nuke.selectedNodes(): + if rn_.Class() != "Read": + continue + rn_["frame_mode"].setValue("start_at") + rn_["frame"].setValue(str(frame)) + else: + # all nodes processing + for rn_ in nuke.allNodes(filter="Read"): + rn_["frame_mode"].setValue("start_at") + rn_["frame"].setValue(str(frame)) + + +def main(): + p_ = FrameSettingsPanel() + if p_.showModalDialog(): + print(p_.process()) diff --git a/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py b/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py deleted file mode 100644 index bf98ef83f6..0000000000 --- a/openpype/hosts/nuke/startup/ops_frame_setting_for_read.py +++ /dev/null @@ -1,49 +0,0 @@ -import nuke -import nukescripts -import re - - -class FrameSettingsPanel(nukescripts.PythonPanel): - def __init__(self, node): - nukescripts.PythonPanel.__init__(self, 'Frame Range') - self.read_node = node - # CREATE KNOBS - self.range = nuke.String_Knob('fRange', 'Frame Range', '%s-%s' % - (nuke.root().firstFrame(), - nuke.root().lastFrame())) - self.selected = nuke.Boolean_Knob("selection") - self.info = nuke.Help_Knob("Instruction") - # ADD KNOBS - self.addKnob(self.selected) - self.addKnob(self.range) - self.addKnob(self.info) - self.selected.setValue(False) - - def knobChanged(self, knob): - frame_range = self.range.value() - pattern = r"^(?P-?[0-9]+)(?:(?:-+)(?P-?[0-9]+))?$" - match = re.match(pattern, frame_range) - frame_start = int(match.group("start")) - frame_end = int(match.group("end")) - if not self.read_node: - return - for r in self.read_node: - if self.onchecked(): - if not nuke.selectedNodes(): - return - if r in nuke.selectedNodes(): - r["frame_mode"].setValue("start_at") - r["frame"].setValue(frame_range) - r["first"].setValue(frame_start) - r["last"].setValue(frame_end) - else: - r["frame_mode"].setValue("start_at") - r["frame"].setValue(frame_range) - r["first"].setValue(frame_start) - r["last"].setValue(frame_end) - - def onchecked(self): - if self.selected.value(): - return True - else: - return False diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index a0caa40396..3f8be4c872 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -226,9 +226,9 @@ { "type": "action", "sourcetype": "python", - "title": "Set Frame Range (Read Node)", - "command": "import openpype.hosts.nuke.startup.ops_frame_setting_for_read as popup;import nuke;popup.FrameSettingsPanel(nuke.allNodes('Read')).showModalDialog();", - "tooltip": "Set Frame Range for Read Node(s)" + "title": "Set Frame Start (Read Node)", + "command": "from openpype.hosts.nuke.startup.frame_setting_for_read_nodes import main;main();", + "tooltip": "Set frame start for read node(s)" } ] }, From 8356dfac7e1150cbe31cc8a63f26cee0c0fe1dd0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 1 Jun 2023 16:41:13 +0200 Subject: [PATCH 15/15] py2 compatibility --- openpype/hosts/nuke/startup/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 openpype/hosts/nuke/startup/__init__.py diff --git a/openpype/hosts/nuke/startup/__init__.py b/openpype/hosts/nuke/startup/__init__.py new file mode 100644 index 0000000000..e69de29bb2