Collection Manager: QCD polishing. Task: T69577
Made QCD internal structure more stable. Prevented reload scripts from resetting QCD slots. Fixed QCD being left in an incorrect state on undo/redo. Fixed a small error on unregister.
This commit is contained in:
parent
bbd5fd92a3
commit
a32b859fec
|
@ -22,7 +22,7 @@ bl_info = {
|
|||
"name": "Collection Manager",
|
||||
"description": "Manage collections and their objects",
|
||||
"author": "Ryan Inch",
|
||||
"version": (2,4,5),
|
||||
"version": (2,4,9),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "View3D - Object Mode (Shortcut - M)",
|
||||
"warning": '', # used for warning icon and text in addons panel
|
||||
|
@ -126,6 +126,9 @@ def register():
|
|||
qcd_init.register_qcd()
|
||||
|
||||
def unregister():
|
||||
if bpy.context.preferences.addons[__package__].preferences.enable_qcd:
|
||||
qcd_init.unregister_qcd()
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
|
@ -136,8 +139,6 @@ def unregister():
|
|||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
qcd_init.unregister_qcd()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
# Copyright 2011, Ryan Inch
|
||||
|
||||
from . import persistent_data
|
||||
|
||||
import bpy
|
||||
|
||||
from bpy.types import (
|
||||
|
@ -45,21 +47,23 @@ class QCDSlots():
|
|||
overrides = {}
|
||||
allow_update = True
|
||||
|
||||
def __init__(self):
|
||||
self._slots = persistent_data.slots
|
||||
self.overrides = persistent_data.overrides
|
||||
|
||||
def __iter__(self):
|
||||
return self._slots.items().__iter__()
|
||||
|
||||
def __repr__(self):
|
||||
return self._slots.__repr__()
|
||||
|
||||
def __contains__(self, key):
|
||||
try:
|
||||
int(key)
|
||||
return key in self._slots
|
||||
def contains(self, *, idx=None, name=None):
|
||||
if idx:
|
||||
return idx in self._slots.keys()
|
||||
if name:
|
||||
return name in self._slots.values()
|
||||
|
||||
except ValueError:
|
||||
return key in self._slots.values()
|
||||
|
||||
return False
|
||||
raise
|
||||
|
||||
def get_data_for_blend(self):
|
||||
return f"{self._slots.__repr__()}\n{self.overrides.__repr__()}"
|
||||
|
@ -69,8 +73,14 @@ class QCDSlots():
|
|||
blend_slots = eval(decoupled_data[0])
|
||||
blend_overrides = eval(decoupled_data[1])
|
||||
|
||||
self._slots = blend_slots
|
||||
self.overrides = blend_overrides
|
||||
self._slots.clear()
|
||||
self.overrides.clear()
|
||||
|
||||
for k, v in blend_slots.items():
|
||||
self._slots[k] = v
|
||||
|
||||
for k, v in blend_overrides.items():
|
||||
self.overrides[k] = v
|
||||
|
||||
def length(self):
|
||||
return len(self._slots)
|
||||
|
@ -91,21 +101,64 @@ class QCDSlots():
|
|||
def add_slot(self, idx, name):
|
||||
self._slots[idx] = name
|
||||
|
||||
if name in self.overrides:
|
||||
del self.overrides[name]
|
||||
|
||||
def update_slot(self, idx, name):
|
||||
self._slots[idx] = name
|
||||
self.add_slot(idx, name)
|
||||
|
||||
def del_slot(self, slot):
|
||||
try:
|
||||
int(slot)
|
||||
del self._slots[slot]
|
||||
|
||||
except ValueError:
|
||||
idx = self.get_idx(slot)
|
||||
def del_slot(self, *, idx=None, name=None):
|
||||
if idx and not name:
|
||||
del self._slots[idx]
|
||||
return
|
||||
|
||||
def clear(self):
|
||||
if name and not idx:
|
||||
slot_idx = self.get_idx(name)
|
||||
del self._slots[slot_idx]
|
||||
return
|
||||
|
||||
raise
|
||||
|
||||
def add_override(self, name):
|
||||
qcd_slots.del_slot(name=name)
|
||||
qcd_slots.overrides[name] = True
|
||||
|
||||
def clear_slots(self):
|
||||
self._slots.clear()
|
||||
|
||||
def update_qcd(self):
|
||||
for idx, name in list(self._slots.items()):
|
||||
if not layer_collections.get(name, None):
|
||||
qcd_slots.del_slot(name=name)
|
||||
|
||||
def auto_numerate(self, *, renumerate=False):
|
||||
global max_lvl
|
||||
|
||||
if self.length() < 20:
|
||||
lvl = 0
|
||||
num = 1
|
||||
while lvl <= max_lvl:
|
||||
if num > 20:
|
||||
break
|
||||
|
||||
for laycol in layer_collections.values():
|
||||
if num > 20:
|
||||
break
|
||||
|
||||
if int(laycol["lvl"]) == lvl:
|
||||
if laycol["name"] in qcd_slots.overrides:
|
||||
if not renumerate:
|
||||
num += 1
|
||||
continue
|
||||
|
||||
if (not self.contains(idx=str(num)) and
|
||||
not self.contains(name=laycol["name"])):
|
||||
self.add_slot(str(num), laycol["name"])
|
||||
|
||||
num += 1
|
||||
|
||||
lvl += 1
|
||||
|
||||
qcd_slots = QCDSlots()
|
||||
|
||||
|
||||
|
@ -140,45 +193,39 @@ def update_qcd_slot(self, context):
|
|||
update_needed = False
|
||||
|
||||
try:
|
||||
int(self.qcd_slot)
|
||||
int(self.qcd_slot_idx)
|
||||
except:
|
||||
|
||||
if self.qcd_slot == "":
|
||||
qcd_slots.del_slot(self.name)
|
||||
qcd_slots.overrides[self.name] = True
|
||||
if self.qcd_slot_idx == "":
|
||||
qcd_slots.add_override(self.name)
|
||||
|
||||
if self.name in qcd_slots:
|
||||
if qcd_slots.contains(name=self.name):
|
||||
qcd_slots.allow_update = False
|
||||
self.qcd_slot = qcd_slots.get_idx(self.name)
|
||||
self.qcd_slot_idx = qcd_slots.get_idx(self.name)
|
||||
qcd_slots.allow_update = True
|
||||
|
||||
if self.name in qcd_slots.overrides:
|
||||
qcd_slots.allow_update = False
|
||||
self.qcd_slot = ""
|
||||
self.qcd_slot_idx = ""
|
||||
qcd_slots.allow_update = True
|
||||
|
||||
return
|
||||
|
||||
if self.name in qcd_slots:
|
||||
qcd_slots.del_slot(self.name)
|
||||
if qcd_slots.contains(name=self.name):
|
||||
qcd_slots.del_slot(name=self.name)
|
||||
update_needed = True
|
||||
|
||||
if self.qcd_slot in qcd_slots:
|
||||
qcd_slots.overrides[qcd_slots.get_name(self.qcd_slot)] = True
|
||||
qcd_slots.del_slot(self.qcd_slot)
|
||||
if qcd_slots.contains(idx=self.qcd_slot_idx):
|
||||
qcd_slots.add_override(qcd_slots.get_name(self.qcd_slot_idx))
|
||||
update_needed = True
|
||||
|
||||
if int(self.qcd_slot) > 20:
|
||||
self.qcd_slot = "20"
|
||||
if int(self.qcd_slot_idx) > 20:
|
||||
self.qcd_slot_idx = "20"
|
||||
|
||||
if int(self.qcd_slot) < 1:
|
||||
self.qcd_slot = "1"
|
||||
|
||||
qcd_slots.add_slot(self.qcd_slot, self.name)
|
||||
|
||||
if self.name in qcd_slots.overrides:
|
||||
del qcd_slots.overrides[self.name]
|
||||
if int(self.qcd_slot_idx) < 1:
|
||||
self.qcd_slot_idx = "1"
|
||||
|
||||
qcd_slots.add_slot(self.qcd_slot_idx, self.name)
|
||||
|
||||
if update_needed:
|
||||
update_property_group(context)
|
||||
|
@ -187,10 +234,10 @@ def update_qcd_slot(self, context):
|
|||
class CMListCollection(PropertyGroup):
|
||||
name: StringProperty(update=update_col_name)
|
||||
last_name: StringProperty()
|
||||
qcd_slot: StringProperty(name="QCD Slot", update=update_qcd_slot)
|
||||
qcd_slot_idx: StringProperty(name="QCD Slot", update=update_qcd_slot)
|
||||
|
||||
|
||||
def update_collection_tree(context, renumerate=False):
|
||||
def update_collection_tree(context, *, renumerate_qcd=False):
|
||||
global max_lvl
|
||||
global row_index
|
||||
global collection_tree
|
||||
|
@ -222,36 +269,9 @@ def update_collection_tree(context, renumerate=False):
|
|||
for laycol in master_laycol["children"]:
|
||||
collection_tree.append(laycol)
|
||||
|
||||
# update qcd
|
||||
for x in range(20):
|
||||
qcd_slot = qcd_slots.get_name(str(x+1))
|
||||
if qcd_slot and not layer_collections.get(qcd_slot, None):
|
||||
qcd_slots.del_slot(qcd_slot)
|
||||
qcd_slots.update_qcd()
|
||||
|
||||
# update autonumeration
|
||||
if qcd_slots.length() < 20:
|
||||
lvl = 0
|
||||
num = 1
|
||||
while lvl <= max_lvl:
|
||||
if num > 20:
|
||||
break
|
||||
|
||||
for laycol in layer_collections.values():
|
||||
if num > 20:
|
||||
break
|
||||
|
||||
if int(laycol["lvl"]) == lvl:
|
||||
if laycol["name"] in qcd_slots.overrides:
|
||||
if not renumerate:
|
||||
num += 1
|
||||
continue
|
||||
|
||||
if str(num) not in qcd_slots and laycol["name"] not in qcd_slots:
|
||||
qcd_slots.add_slot(str(num), laycol["name"])
|
||||
|
||||
num += 1
|
||||
|
||||
lvl += 1
|
||||
qcd_slots.auto_numerate(renumerate=renumerate_qcd)
|
||||
|
||||
|
||||
def get_all_collections(context, collections, parent, tree, level=0, visible=False):
|
||||
|
@ -290,13 +310,13 @@ def get_all_collections(context, collections, parent, tree, level=0, visible=Fal
|
|||
get_all_collections(context, item.children, laycol, laycol["children"], level+1)
|
||||
|
||||
|
||||
def update_property_group(context, renumerate=False):
|
||||
def update_property_group(context, *, renumerate_qcd=False):
|
||||
global collection_tree
|
||||
global qcd_slots
|
||||
|
||||
qcd_slots.allow_update = False
|
||||
|
||||
update_collection_tree(context, renumerate)
|
||||
update_collection_tree(context, renumerate_qcd=renumerate_qcd)
|
||||
context.scene.collection_manager.cm_list_collection.clear()
|
||||
create_property_group(context, collection_tree)
|
||||
|
||||
|
@ -312,7 +332,7 @@ def create_property_group(context, tree):
|
|||
for laycol in tree:
|
||||
new_cm_listitem = cm.cm_list_collection.add()
|
||||
new_cm_listitem.name = laycol["name"]
|
||||
new_cm_listitem.qcd_slot = qcd_slots.get_idx(laycol["name"], "")
|
||||
new_cm_listitem.qcd_slot_idx = qcd_slots.get_idx(laycol["name"], "")
|
||||
|
||||
if laycol["has_children"]:
|
||||
create_property_group(context, laycol["children"])
|
||||
|
|
|
@ -1905,8 +1905,8 @@ class CMRemoveCollectionOperator(Operator):
|
|||
|
||||
|
||||
# update qcd
|
||||
if self.collection_name in qcd_slots:
|
||||
qcd_slots.del_slot(self.collection_name)
|
||||
if qcd_slots.contains(name=self.collection_name):
|
||||
qcd_slots.del_slot(name=self.collection_name)
|
||||
|
||||
if self.collection_name in qcd_slots.overrides:
|
||||
del qcd_slots.overrides[self.collection_name]
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# Copyright 2011, Ryan Inch
|
||||
|
||||
# QCD
|
||||
slots = {}
|
||||
overrides = {}
|
|
@ -3,6 +3,7 @@ import bpy
|
|||
import bpy.utils.previews
|
||||
from bpy.app.handlers import persistent
|
||||
|
||||
from . import internals
|
||||
from . import preferences
|
||||
from . import qcd_move_widget
|
||||
from . import qcd_operators
|
||||
|
@ -27,8 +28,11 @@ def depsgraph_update_post_handler(dummy):
|
|||
|
||||
qcd_operators.move_selection.clear()
|
||||
qcd_operators.move_active = None
|
||||
qcd_operators.get_move_selection()
|
||||
qcd_operators.get_move_active()
|
||||
|
||||
@persistent
|
||||
def undo_redo_post_handler(dummy):
|
||||
qcd_operators.move_selection.clear()
|
||||
qcd_operators.move_active = None
|
||||
|
||||
@persistent
|
||||
def save_internal_data(dummy):
|
||||
|
@ -63,6 +67,8 @@ def register_qcd():
|
|||
addon_qcd_keymaps.append((km, kmi))
|
||||
|
||||
bpy.app.handlers.depsgraph_update_post.append(depsgraph_update_post_handler)
|
||||
bpy.app.handlers.undo_post.append(undo_redo_post_handler)
|
||||
bpy.app.handlers.redo_post.append(undo_redo_post_handler)
|
||||
bpy.app.handlers.save_pre.append(save_internal_data)
|
||||
bpy.app.handlers.load_post.append(load_internal_data)
|
||||
|
||||
|
@ -117,6 +123,8 @@ def unregister_qcd():
|
|||
bpy.utils.unregister_class(cls)
|
||||
|
||||
bpy.app.handlers.depsgraph_update_post.remove(depsgraph_update_post_handler)
|
||||
bpy.app.handlers.undo_post.remove(undo_redo_post_handler)
|
||||
bpy.app.handlers.redo_post.remove(undo_redo_post_handler)
|
||||
bpy.app.handlers.save_pre.remove(save_internal_data)
|
||||
bpy.app.handlers.load_post.remove(load_internal_data)
|
||||
|
||||
|
|
|
@ -653,10 +653,10 @@ def allocate_main_ui(self, context):
|
|||
for num in range(button_group):
|
||||
slot_num = row_num + num
|
||||
|
||||
qcd_slot = qcd_slots.get_name(f"{slot_num}")
|
||||
qcd_slot_name = qcd_slots.get_name(f"{slot_num}")
|
||||
|
||||
if qcd_slot:
|
||||
qcd_laycol = layer_collections[qcd_slot]["ptr"]
|
||||
if qcd_slot_name:
|
||||
qcd_laycol = layer_collections[qcd_slot_name]["ptr"]
|
||||
collection_objects = qcd_laycol.collection.objects
|
||||
selected_objects = qcd_operators.get_move_selection()
|
||||
active_object = qcd_operators.get_move_active()
|
||||
|
@ -815,16 +815,16 @@ def draw_callback_px(self, context):
|
|||
rounding = 5
|
||||
|
||||
if num < 10:
|
||||
if not f"{num+2}" in qcd_slots:
|
||||
if not qcd_slots.contains(idx=f"{num+2}"):
|
||||
tr = rounding
|
||||
|
||||
if not f"{num}" in qcd_slots:
|
||||
if not qcd_slots.contains(idx=f"{num}"):
|
||||
tl = rounding
|
||||
else:
|
||||
if not f"{num+2}" in qcd_slots:
|
||||
if not qcd_slots.contains(idx=f"{num+2}"):
|
||||
br = rounding
|
||||
|
||||
if not f"{num}" in qcd_slots:
|
||||
if not qcd_slots.contains(idx=f"{num}"):
|
||||
bl = rounding
|
||||
|
||||
if num in [0,5]:
|
||||
|
|
|
@ -47,35 +47,22 @@ def get_move_selection():
|
|||
global move_selection
|
||||
|
||||
if not move_selection:
|
||||
move_selection = bpy.context.selected_objects
|
||||
move_selection = [obj.name for obj in bpy.context.selected_objects]
|
||||
|
||||
return move_selection
|
||||
return [bpy.data.objects[name] for name in move_selection]
|
||||
|
||||
def get_move_active():
|
||||
global move_active
|
||||
global move_selection
|
||||
|
||||
if not move_active:
|
||||
move_active = bpy.context.view_layer.objects.active
|
||||
move_active = getattr(bpy.context.view_layer.objects.active, "name", None)
|
||||
|
||||
if move_active not in get_move_selection():
|
||||
if move_active not in [obj.name for obj in get_move_selection()]:
|
||||
move_active = None
|
||||
|
||||
if move_active:
|
||||
try:
|
||||
move_active.name
|
||||
return bpy.data.objects[move_active] if move_active else None
|
||||
|
||||
except:
|
||||
move_active = None
|
||||
move_selection = []
|
||||
|
||||
# update header widget
|
||||
cm = bpy.context.scene.collection_manager
|
||||
cm.update_header.clear()
|
||||
new_update_header = cm.update_header.add()
|
||||
new_update_header.name = "updated"
|
||||
|
||||
return move_active
|
||||
|
||||
class MoveToQCDSlot(Operator):
|
||||
'''Move object(s) to QCD slot'''
|
||||
|
@ -94,10 +81,11 @@ class MoveToQCDSlot(Operator):
|
|||
selected_objects = get_move_selection()
|
||||
active_object = get_move_active()
|
||||
move_triggered = True
|
||||
qcd_laycol = qcd_slots.get_name(self.slot)
|
||||
qcd_laycol = None
|
||||
slot_name = qcd_slots.get_name(self.slot)
|
||||
|
||||
if qcd_laycol:
|
||||
qcd_laycol = layer_collections[qcd_laycol]["ptr"]
|
||||
if slot_name:
|
||||
qcd_laycol = layer_collections[slot_name]["ptr"]
|
||||
|
||||
else:
|
||||
return {'CANCELLED'}
|
||||
|
@ -213,10 +201,11 @@ class ViewQCDSlot(Operator):
|
|||
global layer_collections
|
||||
global rto_history
|
||||
|
||||
qcd_laycol = qcd_slots.get_name(self.slot)
|
||||
qcd_laycol = None
|
||||
slot_name = qcd_slots.get_name(self.slot)
|
||||
|
||||
if qcd_laycol:
|
||||
qcd_laycol = layer_collections[qcd_laycol]["ptr"]
|
||||
if slot_name:
|
||||
qcd_laycol = layer_collections[slot_name]["ptr"]
|
||||
|
||||
else:
|
||||
return {'CANCELLED'}
|
||||
|
@ -297,6 +286,6 @@ class RenumerateQCDSlots(Operator):
|
|||
if event.ctrl:
|
||||
qcd_slots.overrides.clear()
|
||||
|
||||
update_property_group(context, renumerate=True)
|
||||
update_property_group(context, renumerate_qcd=True)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
|
|
@ -343,7 +343,7 @@ class CM_UL_items(UIList):
|
|||
if context.preferences.addons[__package__].preferences.enable_qcd:
|
||||
QCD = row.row()
|
||||
QCD.scale_x = 0.4
|
||||
QCD.prop(item, "qcd_slot", text="")
|
||||
QCD.prop(item, "qcd_slot_idx", text="")
|
||||
|
||||
name_row = row.row()
|
||||
|
||||
|
@ -483,7 +483,7 @@ class CM_UL_items(UIList):
|
|||
flt_flags = [0] * len(list_items)
|
||||
|
||||
for idx, item in enumerate(list_items):
|
||||
if item.qcd_slot:
|
||||
if item.qcd_slot_idx:
|
||||
flt_flags[idx] |= self.bitflag_filter_item
|
||||
|
||||
else: # display as treeview
|
||||
|
@ -533,10 +533,10 @@ def view3d_header_qcd_slots(self, context):
|
|||
update_collection_tree(context)
|
||||
|
||||
for x in range(20):
|
||||
qcd_slot = qcd_slots.get_name(str(x+1))
|
||||
qcd_slot_name = qcd_slots.get_name(str(x+1))
|
||||
|
||||
if qcd_slot:
|
||||
qcd_laycol = layer_collections[qcd_slot]["ptr"]
|
||||
if qcd_slot_name:
|
||||
qcd_laycol = layer_collections[qcd_slot_name]["ptr"]
|
||||
collection_objects = qcd_laycol.collection.objects
|
||||
selected_objects = qcd_operators.get_move_selection()
|
||||
active_object = qcd_operators.get_move_active()
|
||||
|
|
Loading…
Reference in New Issue