1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # Copyright 2011, Ryan Inch
22 from .internals
import (
30 update_property_group
,
37 'EDIT_SURFACE': 'EDIT',
39 'EDIT_ARMATURE': 'EDIT',
40 'EDIT_METABALL': 'EDIT',
41 'EDIT_LATTICE': 'EDIT',
44 'PAINT_WEIGHT': 'WEIGHT_PAINT',
45 'PAINT_VERTEX': 'VERTEX_PAINT',
46 'PAINT_TEXTURE': 'TEXTURE_PAINT',
47 'PARTICLE': 'PARTICLE_EDIT',
49 'PAINT_GPENCIL': 'PAINT_GPENCIL',
50 'EDIT_GPENCIL': 'EDIT_GPENCIL',
51 'SCULPT_GPENCIL': 'SCULPT_GPENCIL',
52 'WEIGHT_GPENCIL': 'WEIGHT_GPENCIL',
53 'VERTEX_GPENCIL': 'VERTEX_GPENCIL',
59 "select": "collection.hide_select",
60 "hide": "hide_viewport",
61 "disable": "collection.hide_viewport",
62 "render": "collection.hide_render",
64 "indirect": "indirect_only",
121 def get_rto(layer_collection
, rto
):
122 if rto
in ["exclude", "hide", "holdout", "indirect"]:
123 return getattr(layer_collection
, rto_path
[rto
])
126 collection
= getattr(layer_collection
, "collection")
127 return getattr(collection
, rto_path
[rto
].split(".")[1])
130 def set_rto(layer_collection
, rto
, value
):
131 if rto
in ["exclude", "hide", "holdout", "indirect"]:
132 setattr(layer_collection
, rto_path
[rto
], value
)
135 collection
= getattr(layer_collection
, "collection")
136 setattr(collection
, rto_path
[rto
].split(".")[1], value
)
139 def apply_to_children(parent
, apply_function
):
140 # works for both Collections & LayerCollections
141 child_lists
= [parent
.children
]
146 for child_list
in child_lists
:
147 for child
in child_list
:
148 apply_function(child
)
151 new_child_lists
.append(child
.children
)
153 child_lists
= new_child_lists
156 def isolate_rto(cls
, self
, view_layer
, rto
, *, children
=False):
157 off
= set_off_on
[rto
]["off"]
158 on
= set_off_on
[rto
]["on"]
160 laycol_ptr
= layer_collections
[self
.name
]["ptr"]
161 target
= rto_history
[rto
][view_layer
]["target"]
162 history
= rto_history
[rto
][view_layer
]["history"]
164 # get active collections
165 active_layer_collections
= [x
["ptr"] for x
in layer_collections
.values()
166 if get_rto(x
["ptr"], rto
) == on
]
168 # check if previous state should be restored
169 if cls
.isolated
and self
.name
== target
:
170 # restore previous state
171 for x
, item
in enumerate(layer_collections
.values()):
172 set_rto(item
["ptr"], rto
, history
[x
])
174 # reset target and history
175 del rto_history
[rto
][view_layer
]
179 # check if all RTOs should be activated
180 elif (len(active_layer_collections
) == 1 and
181 active_layer_collections
[0].name
== self
.name
):
182 # activate all collections
183 for item
in layer_collections
.values():
184 set_rto(item
["ptr"], rto
, on
)
186 # reset target and history
187 del rto_history
[rto
][view_layer
]
194 rto_history
[rto
][view_layer
]["target"] = self
.name
200 for item
in layer_collections
.values():
201 history
.append(get_rto(item
["ptr"], rto
))
206 def get_child_states(layer_collection
):
207 child_states
[layer_collection
.name
] = get_rto(layer_collection
, rto
)
209 apply_to_children(laycol_ptr
, get_child_states
)
212 for item
in layer_collections
.values():
213 if item
["name"] != laycol_ptr
.name
:
214 set_rto(item
["ptr"], rto
, off
)
216 set_rto(laycol_ptr
, rto
, on
)
218 if rto
not in ["exclude", "holdout", "indirect"]:
219 # activate all parents
220 laycol
= layer_collections
[self
.name
]
221 while laycol
["id"] != 0:
222 set_rto(laycol
["ptr"], rto
, on
)
223 laycol
= laycol
["parent"]
226 # restore child states
227 def restore_child_states(layer_collection
):
228 set_rto(layer_collection
, rto
, child_states
[layer_collection
.name
])
230 apply_to_children(laycol_ptr
, restore_child_states
)
234 # restore child states
235 def restore_child_states(layer_collection
):
236 set_rto(layer_collection
, rto
, child_states
[layer_collection
.name
])
238 apply_to_children(laycol_ptr
, restore_child_states
)
240 elif rto
== "exclude":
241 # deactivate all children
242 def deactivate_all_children(layer_collection
):
243 set_rto(layer_collection
, rto
, True)
245 apply_to_children(laycol_ptr
, deactivate_all_children
)
250 def toggle_children(self
, view_layer
, rto
):
251 laycol_ptr
= layer_collections
[self
.name
]["ptr"]
253 del rto_history
[rto
][view_layer
]
254 rto_history
[rto
+"_all"].pop(view_layer
, None)
257 state
= not get_rto(laycol_ptr
, rto
)
258 set_rto(laycol_ptr
, rto
, state
)
260 def set_state(layer_collection
):
261 set_rto(layer_collection
, rto
, state
)
263 apply_to_children(laycol_ptr
, set_state
)
266 def activate_all_rtos(view_layer
, rto
):
267 off
= set_off_on
[rto
]["off"]
268 on
= set_off_on
[rto
]["on"]
270 history
= rto_history
[rto
+"_all"][view_layer
]
272 # if not activated, activate all
273 if len(history
) == 0:
276 for item
in reversed(list(layer_collections
.values())):
277 if get_rto(item
["ptr"], rto
) == off
:
280 history
.append(get_rto(item
["ptr"], rto
))
282 set_rto(item
["ptr"], rto
, on
)
290 for x
, item
in enumerate(layer_collections
.values()):
291 set_rto(item
["ptr"], rto
, history
[x
])
294 del rto_history
[rto
+"_all"][view_layer
]
297 def invert_rtos(view_layer
, rto
):
301 for item
in layer_collections
.values():
302 orig_values
.append(get_rto(item
["ptr"], rto
))
304 for x
, item
in enumerate(layer_collections
.values()):
305 set_rto(item
["ptr"], rto
, not orig_values
[x
])
308 for item
in layer_collections
.values():
309 set_rto(item
["ptr"], rto
, not get_rto(item
["ptr"], rto
))
312 rto_history
[rto
].pop(view_layer
, None)
315 def copy_rtos(view_layer
, rto
):
316 if not copy_buffer
["RTO"]:
318 copy_buffer
["RTO"] = rto
319 for laycol
in layer_collections
.values():
320 copy_buffer
["values"].append(get_off_on
[
321 get_rto(laycol
["ptr"], rto
)
329 for x
, laycol
in enumerate(layer_collections
.values()):
330 set_rto(laycol
["ptr"],
333 copy_buffer
["values"][x
]
338 rto_history
[rto
].pop(view_layer
, None)
339 del rto_history
[rto
+"_all"][view_layer
]
342 copy_buffer
["RTO"] = ""
343 copy_buffer
["values"].clear()
346 def swap_rtos(view_layer
, rto
):
347 if not swap_buffer
["A"]["values"]:
349 swap_buffer
["A"]["RTO"] = rto
350 for laycol
in layer_collections
.values():
351 swap_buffer
["A"]["values"].append(get_off_on
[
352 get_rto(laycol
["ptr"], rto
)
360 swap_buffer
["B"]["RTO"] = rto
361 for laycol
in layer_collections
.values():
362 swap_buffer
["B"]["values"].append(get_off_on
[
363 get_rto(laycol
["ptr"], rto
)
370 for x
, laycol
in enumerate(layer_collections
.values()):
371 set_rto(laycol
["ptr"], swap_buffer
["A"]["RTO"],
373 swap_buffer
["A"]["RTO"]
375 swap_buffer
["B"]["values"][x
]
379 set_rto(laycol
["ptr"], swap_buffer
["B"]["RTO"],
381 swap_buffer
["B"]["RTO"]
383 swap_buffer
["A"]["values"][x
]
389 swap_a
= swap_buffer
["A"]["RTO"]
390 swap_b
= swap_buffer
["B"]["RTO"]
392 rto_history
[swap_a
].pop(view_layer
, None)
393 rto_history
[swap_a
+"_all"].pop(view_layer
, None)
394 rto_history
[swap_b
].pop(view_layer
, None)
395 rto_history
[swap_b
+"_all"].pop(view_layer
, None)
398 swap_buffer
["A"]["RTO"] = ""
399 swap_buffer
["A"]["values"].clear()
400 swap_buffer
["B"]["RTO"] = ""
401 swap_buffer
["B"]["values"].clear()
405 if copy_buffer
["RTO"] == rto
:
406 copy_buffer
["RTO"] = ""
407 copy_buffer
["values"].clear()
411 if swap_buffer
["A"]["RTO"] == rto
:
412 swap_buffer
["A"]["RTO"] = ""
413 swap_buffer
["A"]["values"].clear()
414 swap_buffer
["B"]["RTO"] = ""
415 swap_buffer
["B"]["values"].clear()
418 def link_child_collections_to_parent(laycol
, collection
, parent_collection
):
419 # store view layer RTOs for all children of the to be deleted collection
421 def get_child_states(layer_collection
):
422 child_states
[layer_collection
.name
] = (layer_collection
.exclude
,
423 layer_collection
.hide_viewport
,
424 layer_collection
.holdout
,
425 layer_collection
.indirect_only
)
427 apply_to_children(laycol
["ptr"], get_child_states
)
429 # link any subcollections of the to be deleted collection to it's parent
430 for subcollection
in collection
.children
:
431 if not subcollection
.name
in parent_collection
.children
:
432 parent_collection
.children
.link(subcollection
)
434 # apply the stored view layer RTOs to the newly linked collections and their
436 def restore_child_states(layer_collection
):
437 state
= child_states
.get(layer_collection
.name
)
440 layer_collection
.exclude
= state
[0]
441 layer_collection
.hide_viewport
= state
[1]
442 layer_collection
.holdout
= state
[2]
443 layer_collection
.indirect_only
= state
[3]
445 apply_to_children(laycol
["parent"]["ptr"], restore_child_states
)
448 def remove_collection(laycol
, collection
, context
):
450 cm
= context
.scene
.collection_manager
451 selected_row_name
= cm
.cm_list_collection
[cm
.cm_list_index
].name
454 bpy
.data
.collections
.remove(collection
)
457 expanded
.discard(laycol
["name"])
459 if expand_history
["target"] == laycol
["name"]:
460 expand_history
["target"] = ""
462 if laycol
["name"] in expand_history
["history"]:
463 expand_history
["history"].remove(laycol
["name"])
465 if qcd_slots
.contains(name
=laycol
["name"]):
466 qcd_slots
.del_slot(name
=laycol
["name"])
468 if laycol
["name"] in qcd_slots
.overrides
:
469 qcd_slots
.overrides
.remove(laycol
["name"])
472 for rto
in rto_history
.values():
476 update_property_group(context
)
478 # update selected row
479 laycol
= layer_collections
.get(selected_row_name
, None)
481 cm
.cm_list_index
= laycol
["row_index"]
483 elif len(cm
.cm_list_collection
) <= cm
.cm_list_index
:
484 cm
.cm_list_index
= len(cm
.cm_list_collection
) - 1
486 if cm
.cm_list_index
> -1:
487 name
= cm
.cm_list_collection
[cm
.cm_list_index
].name
488 laycol
= layer_collections
[name
]
489 while not laycol
["visible"]:
490 laycol
= laycol
["parent"]
492 cm
.cm_list_index
= laycol
["row_index"]
495 def select_collection_objects(is_master_collection
, collection_name
, replace
, nested
, selection_state
=None):
496 if is_master_collection
:
497 target_collection
= bpy
.context
.view_layer
.layer_collection
.collection
500 laycol
= layer_collections
[collection_name
]
501 target_collection
= laycol
["ptr"].collection
504 bpy
.ops
.object.select_all(action
='DESELECT')
506 if selection_state
== None:
507 selection_state
= get_move_selection().isdisjoint(target_collection
.objects
)
509 def select_objects(collection
):
510 for obj
in collection
.objects
:
512 obj
.select_set(selection_state
)
516 select_objects(target_collection
)
519 apply_to_children(target_collection
, select_objects
)
521 def set_exclude_state(target_layer_collection
, state
):
522 # get current child exclusion state
525 def get_child_exclusion(layer_collection
):
526 child_exclusion
.append([layer_collection
, layer_collection
.exclude
])
528 apply_to_children(target_layer_collection
, get_child_exclusion
)
532 target_layer_collection
.exclude
= state
535 # set correct state for all children
536 for laycol
in child_exclusion
:
537 laycol
[0].exclude
= laycol
[1]