diff --git a/MultiEdit_05.py b/__init__.py similarity index 85% rename from MultiEdit_05.py rename to __init__.py index b83242c..e3690f8 100644 --- a/MultiEdit_05.py +++ b/__init__.py @@ -18,12 +18,12 @@ bl_info = { "name": "MultiEdit", - "author": "Antonis Karvelas", - "version": (0, 5), + "author": "Antonis Karvelas, Dimitris Chloupis", + "version": (1, 0), "blender": (2, 7, 8), "location": "VIEW 3D > Tools > Multiple Objects Editing ", - "description": "Allows you to edit multiple objects together in edit mode without destroying data", - "warning": "Alpha Version 0.5, maybe has a few problems...", + "description": "Allows you to edit multiple objects together in edit mode without destroying data.", + "warning": "Could still have a few issues, be careful.", "wiki_url": "", "tracker_url": "", "category": "Mesh"} @@ -31,6 +31,9 @@ #Imports: import bpy import math +from mathutils import Vector +from bpy.props import FloatVectorProperty +import time #Create a list to put the names of the selected objects: name_list = [] @@ -44,6 +47,7 @@ #Create a dictionary to put the parents parents_list = {} + class MultiEdit_Enter(bpy.types.Operator): bl_label = "MultiEdit Enter" bl_idname = "objects.multiedit_enter_operator" @@ -127,8 +131,8 @@ def Create_Vertex_Groups(self, object): ###Create the necessary vertex groups:### bpy.context.scene.objects.active = object for vertex_group in object.vertex_groups: - special_vgroups_list.append(vertex_group.name) - + special_vgroups_list.append(vertex_group.name) + #Create vertex groups containting all the vertices: object.vertex_groups.new(object.name) vertex_group = object.vertex_groups[-1] @@ -168,22 +172,6 @@ def Duplicate_Object(self, scene, name, old_object): #Link new object to the given scene and select it scene.objects.link(ob_new) - #Copy all the modifiers: - for mod in old_object.modifiers: - mod_new = ob_new.modifiers.new(mod.name, mod.type) - properties = [p.identifier for p in mod.bl_rna.properties - if not p.is_readonly] - for prop in properties: - setattr(mod_new, prop, getattr(mod, prop)) - - #Copy all the constraints: - for constr in old_object.constraints: - constr_new = ob_new.constraints.new(constr.type) - properties = [p.identifier for p in constr.bl_rna.properties - if not p.is_readonly] - for prop in properties: - setattr(constr_new, prop, getattr(constr, prop)) - #Copy all the vertex groups: for vertex_g in old_object.vertex_groups: vert_g_new = ob_new.vertex_groups.new(vertex_g.name) @@ -196,12 +184,29 @@ def Duplicate_Object(self, scene, name, old_object): for group in old_object.users_group: bpy.context.scene.objects.active = ob_new bpy.ops.object.group_link(group=group.name) - + #Copy parent object value try: parents_list[old_object.name] = (old_object.parent).name except: pass + + #Copy all the modifiers: + for mod in old_object.modifiers: + mod_new = ob_new.modifiers.new(mod.name, mod.type) + properties = [p.identifier for p in mod.bl_rna.properties + if not p.is_readonly] + for prop in properties: + setattr(mod_new, prop, getattr(mod, prop)) + + #Copy all the constraints: + for constr in old_object.constraints: + constr_new = ob_new.constraints.new(constr.type) + properties = [p.identifier for p in constr.bl_rna.properties + if not p.is_readonly] + for prop in properties: + setattr(constr_new, prop, getattr(constr, prop)) + #Finally, return the new object: return ob_new @@ -288,7 +293,7 @@ def Fix_Objects(self, active_object, name, vgroup_index): existing_vg.append(object.vertex_groups[vgroup_index].name) vgroup_index += 1 - + #RENAME OBJECTS, ORGANIZES MATERIALS if len(existing_vg) < 2 and len(existing_vg) > 0: # try: @@ -320,7 +325,7 @@ def Fix_Objects(self, active_object, name, vgroup_index): #Call the Copy_Data function: self.Copy_Data(wanted_object_name, object) - + else: object.name = "New Geometry" @@ -334,10 +339,9 @@ def Fix_Objects(self, active_object, name, vgroup_index): bpy.ops.object.hide_view_clear() #Delete duplicated objects - bpy.ops.object.select_all(action="SELECT") for obj in bpy.context.selected_objects: if "dupl" not in obj.name: - obj.select = False + obj.hide = True bpy.ops.object.delete() #Empty lists for future use @@ -373,14 +377,14 @@ def Copy_Data(self, wanted_object_name, object): for group in bpy.data.objects[wanted_object_name].users_group: bpy.context.scene.objects.active = object bpy.ops.object.group_link(group=group.name) - + #Delete unnecessary vertex groups: for vg in object.vertex_groups: if vg.name in bpy.data.objects[(duplicated_list[(name_list.index(object.name))])].vertex_groups: pass else: - object.vertex_groups.remove(vg) - + object.vertex_groups.remove(vg) + #Copy constraints: for constr in bpy.data.objects[wanted_object_name].constraints: constr_new = object.constraints.new(constr.type) @@ -459,7 +463,7 @@ def Preserve_Data(self): else: pass - + else: for obj in bpy.data.objects: for nam in name_list: @@ -475,8 +479,8 @@ def Preserve_Data(self): else: pass - - #A function to preserve an object's parent: + + #A function to preserve an object's parent: def Preserve_Parents(self, obj): try: obj.parent = bpy.data.objects[parents_list[obj.name]] @@ -534,21 +538,98 @@ def Clear_New_Geometry_Data(self, obj_name): main_object.data.materials.pop() +""" +This Operator is modal and checks automatically if it should enter or exit +MultiEdit mode +""" + + +class MultiEditModal(bpy.types.Operator): + """Translate the view using mouse events""" + + bl_label = "MultiEdit mode start" + bl_idname = "objects.multieditmodal" + bl_context = "editmode" + multiEditMode= False + editingObjects =[] + timeLapse = 0 + + def execute(self, context): + pass + return + + def modal(self, context, event): + + + + # do not check anything if the mouse cursor is not in Viewport + if context.space_data.type == 'VIEW_3D': + + # check every one second + if time.time() > self.timeLapse + 0.3: + self.timeLapse = round(time.time()) + self.editingObjects = [] + + for obj in bpy.data.objects: + if obj.mode == 'EDIT' and bpy.context.scene.multi_edit_enable: + self.editingObjects.append(obj) + + # if in edit mode and multiple selected enter MultiEdit mode + if obj.select and len( + self.editingObjects) > 0 and self.multiEditMode == False and bpy.context.scene.multi_edit_enable: + self.editingObjects.append(obj) + self.multiEditMode = True + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.objects.multiedit_enter_operator() + + # if in object mode , no objects selected and MulitEditMode previously + # enabled , then exit MultiEdit mode + if len(self.editingObjects) == 0 and self.multiEditMode: + self.multiEditMode = False + bpy.ops.objects.multiedit_exit_operator() + + + + + # do not capture any key or mouse event + return {'PASS_THROUGH'} + + def invoke(self, context, event): + + if context.space_data.type == 'VIEW_3D': + v3d = context.space_data + rv3d = v3d.region_3d + + + + context.window_manager.modal_handler_add(self) + return {'RUNNING_MODAL'} + else: + self.report({'WARNING'}, "Active space must be a View3d") + return {'CANCELLED'} + + + +# Main Panel for MultiEdit mode class MultiEdit_Panel(bpy.types.Panel): bl_label = "Multiple Objects Editing" bl_idname = "MultiEdit" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_category = "Tools" + first_draw=True def draw(self, context): - layout = self.layout - sce = bpy.context.scene + layout = self.layout + sce = bpy.context.scene + + layout.operator(MultiEdit_Enter.bl_idname) + layout.operator(MultiEdit_Exit.bl_idname) + layout.operator(MultiEditModal.bl_idname) + layout.prop(sce, "Preserve_Location_Rotation_Scale", toggle=True, icon='ROTATE') + layout.prop(sce, "multi_edit_enable",toggle=True,icon='EDIT') - layout.operator(MultiEdit_Enter.bl_idname) - layout.operator(MultiEdit_Exit.bl_idname) - layout.prop(sce, "Preserve_Location_Rotation_Scale") def register(): bpy.utils.register_class(MultiEdit_Enter) @@ -560,11 +641,20 @@ def register(): description = "Preserve the Location/Rotation/Scale values of the objects.", default = True ) + # Is MultiEdit enabled + bpy.types.Scene.multi_edit_enable = bpy.props.BoolProperty \ + ( + name = "Enable Multi Edit mode", + description = "Can automatically detect if multiple objects are selected and edit them together.", + default = True + ) + bpy.utils.register_class(MultiEditModal) def unregister(): bpy.utils.unregister_class(MultiEdit_Enter); bpy.utils.unregister_class(MultiEdit_Exit); bpy.utils.unregister_class(MultiEdit_Panel); + bpy.utils.unregister_class(MultiEditModal) if __name__ == "__main__": - register() + register() \ No newline at end of file