-
Notifications
You must be signed in to change notification settings - Fork 40
/
app.py
349 lines (290 loc) · 12.9 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# Copyright (c) 2013 Shotgun Software Inc.
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
"""
Tank Write Node for Nuke
"""
import os
import nuke
import tank
from tank import TankError
class NukeWriteNode(tank.platform.Application):
def init_app(self):
"""
Called as the application is being initialized
"""
# import module and create handler
tk_nuke_writenode = self.import_module("tk_nuke_writenode")
self.__write_node_handler = tk_nuke_writenode.TankWriteNodeHandler(self)
# patch handler onto nuke module for access in WriteNode knobs
nuke._shotgun_write_node_handler = self.__write_node_handler
# and for backwards compatibility!
nuke._tank_write_node_handler = self.__write_node_handler
# add WriteNodes to nuke menu
self.__add_write_node_commands()
# add callbacks:
self.__write_node_handler.add_callbacks()
@property
def context_change_allowed(self):
"""
Specifies that context changes are allowed.
"""
return True
def destroy_app(self):
"""
Called when the app is unloaded/destroyed
"""
self.log_debug("Destroying tk-nuke-writenode app")
# remove any callbacks that were registered by the handler:
self.__write_node_handler.remove_callbacks()
# clean up the nuke module:
if hasattr(nuke, "_shotgun_write_node_handler"):
del nuke._shotgun_write_node_handler
if hasattr(nuke, "_tank_write_node_handler"):
del nuke._tank_write_node_handler
def post_context_change(self, old_context, new_context):
"""
Handles refreshing the render paths of all Shotgun write nodes
after a context change has been completed.
:param old_context: The sgtk.context.Context being switched from.
:param new_context: The sgtk.context.Context being switched to.
"""
self.__write_node_handler.populate_profiles_from_settings()
self.__write_node_handler.populate_script_template()
self.__add_write_node_commands(new_context)
# now the writenode handler settings have been updated we can update the paths of all existing PTR writenodes
for node in self.get_write_nodes():
# Although there are nuke callbacks to handle setting up the new node; on automatic context change
# these are triggered before the engine changes context, so we must manually call it here.
# this will force the path to reset and the profiles to be rebuilt.
self.__write_node_handler.setup_new_node(node)
def process_placeholder_nodes(self):
"""
Convert any placeholder nodes to TK Write Nodes
"""
self.__write_node_handler.process_placeholder_nodes()
# interface for other apps to query write node info:
#
# access general information:
def get_write_nodes(self):
"""
Return list of all write nodes
"""
return self.__write_node_handler.get_nodes()
def get_node_name(self, node):
"""
Return the name for the specified node
"""
return self.__write_node_handler.get_node_name(node)
def get_node_profile_name(self, node):
"""
Return the name of the profile the specified node
is using
"""
return self.__write_node_handler.get_node_profile_name(node)
def get_node_tank_type(self, node):
"""
Return the tank type for the specified node
Note: Legacy version with old 'Tank Type' name - use
get_node_published_file_type instead!
"""
return self.__write_node_handler.get_node_tank_type(node)
def get_node_published_file_type(self, node):
"""
Return the published file type for the specified node
"""
return self.__write_node_handler.get_node_tank_type(node)
def is_node_render_path_locked(self, node):
"""
Determine if the render path for the specified node
is locked. The path will become locked if the cached
version of the path no longer matches the computed
path (using the appropriate render template). This
can happen if the file is moved on disk or if the template
is changed.
"""
return self.__write_node_handler.render_path_is_locked(node)
# access full-res render information:
def get_node_render_path(self, node):
"""
Return the render path for the specified node
"""
return self.__write_node_handler.compute_render_path(node)
def get_node_render_files(self, node):
"""
Return the list of rendered files for the node
"""
return self.__write_node_handler.get_files_on_disk(node)
def get_node_render_template(self, node):
"""
Return the render template for the specified node
"""
return self.__write_node_handler.get_render_template(node)
def get_node_publish_template(self, node):
"""
Return the publish template for the specified node
"""
return self.__write_node_handler.get_publish_template(node)
# access proxy-res render information:
def get_node_proxy_render_path(self, node):
"""
Return the render path for the specified node
"""
return self.__write_node_handler.compute_proxy_path(node)
def get_node_proxy_render_files(self, node):
"""
Return the list of rendered files for the node
"""
return self.__write_node_handler.get_proxy_files_on_disk(node)
def get_node_proxy_render_template(self, node):
"""
Return the render template for the specified node
"""
return self.__write_node_handler.get_proxy_render_template(node)
def get_node_proxy_publish_template(self, node):
"""
Return the publish template for the specified node
"""
return self.__write_node_handler.get_proxy_publish_template(node)
# useful utility functions:
def generate_node_thumbnail(self, node):
"""
Generate a thumnail for the specified node
"""
return self.__write_node_handler.generate_thumbnail(node)
def reset_node_render_path(self, node):
"""
Reset the render path of the specified node. This
will force the render path to be updated based on
the current script path and configuration.
Note, this should really never be needed now that the
path is reset automatically when the user changes something.
"""
self.__write_node_handler.reset_render_path(node)
def convert_to_write_nodes(self, show_warning=False):
"""
Convert all Shotgun write nodes found in the current Script to regular
Nuke Write nodes. Additional toolkit information will be stored on
additional user knobs named 'tk_*'
:param show_warning: Optional bool that sets whether a warning box should be displayed to the user;
defaults to False.
:param create_folders: Optional bool that sets whether the operation will create the required output folders;
defaults to False
"""
# By default we want to convert the write nodes, unless the warning is shown and the user chooses to abort.
continue_with_convert = True
if show_warning:
# defer importing the QT module so the app doesn't require QT unless running this method with the warning.
from sgtk.platform.qt import QtGui
res = QtGui.QMessageBox.question(
None,
"Convert All PTR Write Nodes?",
"This will convert all Flow Production Tracking write nodes to standard "
"write nodes."
"\nOK to proceed?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
)
if res != QtGui.QMessageBox.Yes:
# User chose to abort the operation, we should not convert the write nodes
continue_with_convert = False
if continue_with_convert:
self.__write_node_handler.convert_sg_to_nuke_write_nodes()
def convert_from_write_nodes(self, show_warning=False):
"""
Convert all regular Nuke Write nodes that have previously been converted
from Flow Production Tracking Write nodes, back into Flow Production Tracking Write nodes.
:param show_warning: Optional bool that sets whether a warning box should be displayed to the user;
defaults to False.
"""
# By default we want to convert the write nodes, unless the warning is shown and the user chooses to abort.
continue_with_convert = True
if show_warning:
# defer importing the QT module so the app doesn't require QT unless running this method with the warning.
from sgtk.platform.qt import QtGui
res = QtGui.QMessageBox.question(
None,
"Convert All Write Nodes?",
"This will convert any Flow Production Tracking Write Nodes that have "
"been converted "
"into standard write nodes back to their original form."
"\nOK to proceed?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
)
if res != QtGui.QMessageBox.Yes:
# User chose to abort the operation, we should not convert the write nodes
continue_with_convert = False
if continue_with_convert:
self.__write_node_handler.convert_nuke_to_sg_write_nodes()
def create_new_write_node(self, profile_name):
"""
Creates a Shotgun write node using the provided profile_name.
"""
self.__write_node_handler.create_new_node(profile_name)
# Private methods
#
def __add_write_node_commands(self, context=None):
"""
Creates write node menu entries for all write node configurations
and the convert to and from Shotgun write node actions if configured to do so.
"""
context = context or self.context
write_node_icon = os.path.join(self.disk_location, "resources", "tk2_write.png")
for profile_name in self.__write_node_handler.profile_names:
# add to toolbar menu
cb_fn = lambda pn=profile_name: self.__write_node_handler.create_new_node(
pn
)
self.engine.register_command(
profile_name,
cb_fn,
dict(
type="node",
icon=write_node_icon,
context=context,
),
)
# Show the convert actions in the Menu if configured to do so
if self.get_setting("show_convert_actions"):
# We only want to show the convert methods if there are no promoted knobs,
# as these aren't supported when converting back
# todo: We should check the settings and then scan the scene to see if any PTR write nodes use promoted knobs
write_nodes = self.get_setting("write_nodes")
promoted_knob_write_nodes = next(
(a_node for a_node in write_nodes if a_node["promote_write_knobs"]),
None,
)
if not promoted_knob_write_nodes:
# no presets use promoted knobs so we are OK to register the menus.
convert_to_write_nodes_action = lambda: self.convert_to_write_nodes(
show_warning=True
)
convert_from_write_nodes_action = lambda: self.convert_from_write_nodes(
show_warning=True
)
self.engine.register_command(
"Convert PTR Write Nodes to Write Nodes...",
convert_to_write_nodes_action,
{
"type": "context_menu",
"icon": os.path.join(self.disk_location, "icon_256.png"),
},
)
self.engine.register_command(
"Convert Write Nodes back to PTR format...",
convert_from_write_nodes_action,
{
"type": "context_menu",
"icon": os.path.join(self.disk_location, "icon_256.png"),
},
)
else:
self.log_debug(
"Convert menu options were disabled as "
"promoted knobs were detected in the app settings."
)