Skip to content
Snippets Groups Projects
qcd_operators.py 8.97 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ##### 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
    
    import bpy
    
    from bpy.types import (
        Operator,
    )
    
    from bpy.props import (
        BoolProperty,
        StringProperty,
        IntProperty
    )
    
    
    from .internals import (
        layer_collections,
    
        rto_history,
    
        qcd_slots,
        update_property_group,
        get_modifiers,
    
        get_move_active,
        update_qcd_header,
    
    from .operator_utils import (
        apply_to_children,
    )
    
    
    
    class MoveToQCDSlot(Operator):
        '''Move object(s) to QCD slot'''
        bl_label = "Move To QCD Slot"
        bl_idname = "view3d.move_to_qcd_slot"
        bl_options = {'REGISTER', 'UNDO'}
    
        slot: StringProperty()
        toggle: BoolProperty()
    
        def execute(self, context):
            global qcd_slots
            global layer_collections
    
            selected_objects = get_move_selection()
            active_object = get_move_active()
    
            internals.move_triggered = True
    
    
            qcd_laycol = None
            slot_name = qcd_slots.get_name(self.slot)
    
            if slot_name:
                qcd_laycol = layer_collections[slot_name]["ptr"]
    
    
            else:
                return {'CANCELLED'}
    
    
            if not selected_objects:
                return {'CANCELLED'}
    
            # adds object to slot
            if self.toggle:
                if not active_object:
                    active_object = selected_objects[0]
    
                if not active_object.name in qcd_laycol.collection.objects:
                    for obj in selected_objects:
                        if obj.name not in qcd_laycol.collection.objects:
                            qcd_laycol.collection.objects.link(obj)
    
                else:
                    for obj in selected_objects:
                        if obj.name in qcd_laycol.collection.objects:
    
                            if len(obj.users_collection) == 1:
                                continue
    
                            qcd_laycol.collection.objects.unlink(obj)
    
    
            # moves object to slot
            else:
                for obj in selected_objects:
                    if obj.name not in qcd_laycol.collection.objects:
                        qcd_laycol.collection.objects.link(obj)
    
                    for collection in obj.users_collection:
                        qcd_idx = qcd_slots.get_idx(collection.name)
                        if qcd_idx != self.slot:
                            collection.objects.unlink(obj)
    
    
    
            # update the active object if needed
    
            if not context.active_object:
                try:
                    context.view_layer.objects.active = active_object
    
    
                except RuntimeError: # object not in visible slot
    
    
            return {'FINISHED'}
    
    
    class ViewMoveQCDSlot(Operator):
    
        bl_idname = "view3d.view_move_qcd_slot"
        bl_options = {'REGISTER', 'UNDO'}
    
        slot: StringProperty()
    
    
        @classmethod
        def description(cls, context, properties):
            global qcd_slots
    
            slot_name = qcd_slots.get_name(properties.slot)
    
            slot_string = f"QCD Slot {properties.slot}: \"{slot_name}\"\n"
    
            hotkey_string = (
    
                "  * LMB - Isolate slot.\n"
                "  * Shift+LMB - Toggle slot.\n"
                "  * Ctrl+LMB - Move objects to slot.\n"
    
                "  * Ctrl+Shift+LMB - Toggle objects' slot"
    
                )
    
            return f"{slot_string}{hotkey_string}"
    
    
        def invoke(self, context, event):
            global layer_collections
            global qcd_history
    
            modifiers = get_modifiers(event)
    
            if modifiers == {"shift"}:
                bpy.ops.view3d.view_qcd_slot(slot=self.slot, toggle=True)
    
                return {'FINISHED'}
    
            elif modifiers == {"ctrl"}:
                bpy.ops.view3d.move_to_qcd_slot(slot=self.slot, toggle=False)
                return {'FINISHED'}
    
            elif modifiers == {"ctrl", "shift"}:
                bpy.ops.view3d.move_to_qcd_slot(slot=self.slot, toggle=True)
                return {'FINISHED'}
    
            else:
                bpy.ops.view3d.view_qcd_slot(slot=self.slot, toggle=False)
                return {'FINISHED'}
    
    class ViewQCDSlot(Operator):
        '''View objects in QCD slot'''
        bl_label = "View QCD Slot"
        bl_idname = "view3d.view_qcd_slot"
    
        bl_options = {'UNDO'}
    
    
        slot: StringProperty()
        toggle: BoolProperty()
    
        def execute(self, context):
            global qcd_slots
            global layer_collections
            global rto_history
    
    
            qcd_laycol = None
            slot_name = qcd_slots.get_name(self.slot)
    
            if slot_name:
                qcd_laycol = layer_collections[slot_name]["ptr"]
    
    
            # get objects not in object mode
            locked_active_obj = context.view_layer.objects.active
            locked_objs = []
            locked_objs_mode = ""
            for obj in context.view_layer.objects:
                if obj.mode != 'OBJECT':
                    locked_objs.append(obj)
                    locked_objs_mode = obj.mode
    
    
    
                # check if slot can be toggled off.
                for obj in qcd_laycol.collection.objects:
                    if obj.mode != 'OBJECT':
                        return {'CANCELLED'}
    
    
                # get current child exclusion state
                child_exclusion = []
    
    
                def get_child_exclusion(layer_collection):
                    child_exclusion.append([layer_collection, layer_collection.exclude])
    
                apply_to_children(qcd_laycol, get_child_exclusion)
    
    
                # toggle exclusion of qcd_laycol
                qcd_laycol.exclude = not qcd_laycol.exclude
    
                # set correct state for all children
                for laycol in child_exclusion:
                    laycol[0].exclude = laycol[1]
    
    
                # restore locked objects back to their original mode
                # needed because of exclude child updates
                if locked_objs:
                    context.view_layer.objects.active = locked_active_obj
                    bpy.ops.object.mode_set(mode=locked_objs_mode)
    
    
                # set layer as active layer collection
                context.view_layer.active_layer_collection = qcd_laycol
    
            else:
    
                # exclude all collections
    
                for laycol in layer_collections.values():
                    if laycol["name"] != qcd_laycol.name:
    
                        # prevent exclusion if locked objects in this collection
                        if set(locked_objs).isdisjoint(laycol["ptr"].collection.objects):
                            laycol["ptr"].exclude = True
                        else:
                            laycol["ptr"].exclude = False
    
                # un-exclude target collection
    
                qcd_laycol.exclude = False
    
                # exclude all children
    
                def exclude_all_children(layer_collection):
    
                    # prevent exclusion if locked objects in this collection
                    if set(locked_objs).isdisjoint(layer_collection.collection.objects):
                        layer_collection.exclude = True
                    else:
                        layer_collection.exclude = False
    
    
                apply_to_children(qcd_laycol, exclude_all_children)
    
                # restore locked objects back to their original mode
                # needed because of exclude child updates
                if locked_objs:
                    context.view_layer.objects.active = locked_active_obj
                    bpy.ops.object.mode_set(mode=locked_objs_mode)
    
    
                # set layer as active layer collection
                context.view_layer.active_layer_collection = qcd_laycol
    
    
            # update header UI
    
    
            view_layer = context.view_layer.name
            if view_layer in rto_history["exclude"]:
                del rto_history["exclude"][view_layer]
            if view_layer in rto_history["exclude_all"]:
                del rto_history["exclude_all"][view_layer]
    
    
            return {'FINISHED'}
    
    
    class RenumerateQCDSlots(Operator):
    
        bl_label = "Renumerate QCD Slots"
    
        bl_description = (
    
            "Renumerate QCD slots.\n"
            "  * LMB - Renumerate starting from the slot designated 1.\n"
            "  * Alt+LMB - Renumerate from the beginning"
    
        bl_idname = "view3d.renumerate_qcd_slots"
        bl_options = {'REGISTER', 'UNDO'}
    
        def invoke(self, context, event):
            global qcd_slots
    
    
            modifiers = get_modifiers(event)
    
            if modifiers == {'alt'}:
                qcd_slots.renumerate(beginning=True)
    
            else:
                qcd_slots.renumerate()
    
            update_property_group(context)