[Edit Linked Library] Removed no-longer-relevant comment
[blender-addons-contrib.git] / space_view3d_paint_bprojection.py
index 9cc738a010f6db8820e2ff3e39d062522ee4ed07..29a2859442764fac4cb3548ac84de59bcd43d67e 100644 (file)
@@ -2,13 +2,14 @@ bl_info = {
     "name": "BProjection",
     "description": "Help Clone tool",
     "author": "kgeogeo",
-    "version": (1, 0),
-    "blender": (2, 6, 3),
+    "version": (2, 0),
+    "blender": (2, 6, 6),
     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/bprojection",
     "tracker_url":"http://projects.blender.org/tracker/index.php?func=detail&aid=30521&group_id=153&atid=468",
     "category": "Paint"}
 
 import bpy
+from bpy.app.handlers import persistent
 from bpy.types import Panel, Operator
 from bpy.props import IntProperty, FloatProperty, BoolProperty, IntVectorProperty, StringProperty, FloatVectorProperty, CollectionProperty
 from bpy_extras import view3d_utils
@@ -17,16 +18,22 @@ from math import *
 import mathutils
 from mathutils import *
 
+BProjection_Empty    = 'Empty for BProjection'
+BProjection_Material = 'Material for BProjection'
+BProjection_Texture  = 'Texture for BProjection'
+
 # Main function for align the plan to view
 def align_to_view(context):
+    global last_mouse
+    last_mouse = Vector((0,0))
     ob = context.object
-    em = bpy.data.objects['Empty for BProjection']       
+    em = bpy.data.objects[BProjection_Empty]       
     rotation = em.custom_rotation
     scale = em.custom_scale
     z = em.custom_location.z
     pos = [em.custom_location.x, em.custom_location.y]
     
-    reg = context.area.regions[4]        
+    reg = context.region       
     width = reg.width
     height = reg.height 
     
@@ -38,8 +45,8 @@ def align_to_view(context):
     v = Vector((pos[0],pos[1],z))
     v.rotate(vr)
 
-    em = bpy.data.objects['Empty for BProjection']
-    img = bpy.data.textures['Texture for BProjection'].image
+    em = bpy.data.objects[BProjection_Empty]
+    img = bpy.data.textures[BProjection_Texture].image
     if img and img.size[1] != 0:
         prop = img.size[0]/img.size[1]
     else: prop = 1    
@@ -50,7 +57,7 @@ def align_to_view(context):
         em.scale = Vector((prop*scale[0], scale[1], 1))
     pos_cur = em.location - sd.cursor_location
     rot_cur1 = em.rotation_euler.to_quaternion()
-    em.location = v + ob.location            
+    em.location = v + ob.location
     em.rotation_euler = Quaternion.to_euler(vr*quat)   
     if em.custom_c3d:
         if em.custom_old_scale != em.custom_scale:
@@ -63,8 +70,8 @@ def align_to_view(context):
         sd.cursor_location =  v
 
 def applyimage(context):        
-        img = bpy.data.textures['Texture for BProjection'].image
-        em = bpy.data.objects['Empty for BProjection']
+        img = bpy.data.textures[BProjection_Texture].image
+        em = bpy.data.objects[BProjection_Empty]
         ob = context.object
                
         face = ob.data.polygons
@@ -104,7 +111,7 @@ def find_uv(context):
 # Function to update the scaleUV
 def update_UVScale(self, context):
     ob = context.object
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     v = Vector((em.custom_offsetuv[0]/10 + 0.5, em.custom_offsetuv[1]/10 + 0.5))
     l = Vector((0.0,0.0))
     s = em.custom_scaleuv
@@ -123,12 +130,12 @@ def update_UVScale(self, context):
     applyimage(context)
 
 def update_PropUVScale(self, context):
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     if em.custom_linkscaleuv:
         em.custom_scaleuv = [em.custom_propscaleuv,em.custom_propscaleuv]
 
 def update_LinkUVScale(self, context):
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     if em.custom_linkscaleuv:
         em.custom_propscaleuv = em.custom_scaleuv.x
         update_PropUVScale(self, context)
@@ -138,7 +145,7 @@ def update_LinkUVScale(self, context):
 # Function to update the offsetUV
 def update_UVOffset(self, context):
     ob = context.object
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     o = em.custom_offsetuv
     oo = em.custom_old_offsetuv 
     l = find_uv(context)
@@ -175,13 +182,13 @@ def update_FlipUVY(self, context):
 # Function to update
 def update_Rotation(self, context):              
     ob = context.object
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     if em.custom_rotc3d:
         angle = em.custom_rotation - em.custom_old_rotation
         sd = context.space_data
         vr = sd.region_3d.view_rotation.copy()        
         c = sd.cursor_location - ob.location
-        e = bpy.data.objects['Empty for BProjection'].location - ob.location
+        e = bpy.data.objects[BProjection_Empty].location - ob.location
         vo = Vector((0.0, 0.0, 1.0))
         vo.rotate(vr)
         quat = mathutils.Quaternion(vo, math.radians(angle))
@@ -199,7 +206,7 @@ def update_Rotation(self, context):
 # Function to update scale
 def update_Scale(self, context):              
     ob = context.object
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     
     if em.custom_scac3d:
         sd = context.space_data
@@ -215,7 +222,7 @@ def update_Scale(self, context):
         c.rotate(vr)
         ce.rotate(vr)
         
-        img = bpy.data.textures['Texture for BProjection'].image
+        img = bpy.data.textures[BProjection_Texture].image
         if img and img.size[1] != 0:
             prop = img.size[0]/img.size[1]
         else: prop = 1
@@ -226,17 +233,16 @@ def update_Scale(self, context):
 
     else:          
         align_to_view(context)
-            
-    
+                
     em.custom_old_scale = em.custom_scale
 
 def update_PropScale(self, context):
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     if em.custom_linkscale:
         em.custom_scale = [em.custom_propscale,em.custom_propscale]
     
 def update_LinkScale(self, context):
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     if em.custom_linkscale:
         em.custom_propscale = em.custom_scale.x
         update_PropScale(self, context)
@@ -244,22 +250,50 @@ def update_LinkScale(self, context):
         update_Scale(self, context) 
 
 def update_activeviewname(self, context):
-    em = bpy.data.objects['Empty for BProjection']
+    em = bpy.data.objects[BProjection_Empty]
     if self.custom_active:
         em.custom_active_view = self.custom_active_view
 
+def update_style_clone(self, context):    
+    km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
+    for kmi in km.keymap_items:
+        if self.custom_style_clone:         
+            if kmi.idname == 'paint.image_paint':
+                kmi.idname = 'paint.bp_paint'
+        else:
+            if kmi.idname == 'paint.bp_paint':
+                kmi.idname = 'paint.image_paint'    
+
 class custom_props(bpy.types.PropertyGroup):
-    custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
-                                           default=(0,0,-1.0),
-                                           subtype = 'XYZ', size=3)
+    custom_fnlevel = IntProperty(name="Fast navigate level", description="Increase or decrease the SubSurf level, decrease make navigation faster", default=0)
+    
+    custom_location = FloatVectorProperty(name="Location", description="Location of the plane",
+                                          default=(1.0,0,-1.0),
+                                          subtype = 'XYZ', 
+                                          soft_min = -10,
+                                          soft_max = 10,
+                                          step=0.1,
+                                          size=3)
                                            
     custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
-                                     min=-180, max=180, default=0)
+                                    min=-180, max=180, default=0)
                                          
     custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
-                                       subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
-    custom_propscale = FloatProperty(name="PropScale", description="Scale the Plan",
-                                           default=1.0,min = 0.1)
+                                       default=(1.0, 1.0),
+                                       subtype = 'XYZ',
+                                       min = 0.1,
+                                       max = 10,
+                                       soft_min=0.1,
+                                       soft_max=10,
+                                       step=0.1,
+                                       size=2)
+    custom_propscale = FloatProperty(name="PropScale", description="Scale the Plane",
+                                     default=1.0,
+                                     min = 0.1,
+                                     max = 10,
+                                     soft_min=0.1,
+                                     soft_max=10,
+                                     step=0.1)
                                                                                     
     custom_linkscale = BoolProperty(name="linkscale", default=True)
    
@@ -277,6 +311,7 @@ class custom_props(bpy.types.PropertyGroup):
     # other properties
     custom_active= BoolProperty(name="custom_active", default=True)   
     custom_expand = BoolProperty(name="expand", default=False)
+    custom_style_clone = BoolProperty(name="custom_style_clone", default=False)
     
     custom_active_view = StringProperty(name = "custom_active_view",default = "View",update = update_activeviewname)
     
@@ -286,37 +321,71 @@ class custom_props(bpy.types.PropertyGroup):
 
 # Function to create custom properties
 def createcustomprops(context):
-    Ob = bpy.types.Object    
+    Ob = bpy.types.Object
+    
+    Ob.custom_fnlevel = IntProperty(name="Fast navigate level", description="Increase or decrease the SubSurf level, decrease make navigation faster", default=0)
     
     # plane properties 
-    Ob.custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
-                                           default=(5.0,0.0,-1.0),
-                                           subtype = 'XYZ', size=3, update = update_Location)
+    Ob.custom_location = FloatVectorProperty(name="Location", description="Location of the plane",
+                                           default  = (1.0, 0, -1.0),
+                                           subtype  = 'XYZ', 
+                                           size     = 3,
+                                           step     = 0.5,
+                                           soft_min = -10,
+                                           soft_max = 10,
+                                           update = update_Location)
                                            
     Ob.custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
-                                     min=-180, max=180, default=0,update = update_Rotation)
+                                       min=-180, max=180, default=0,update = update_Rotation)
                                      
     Ob.custom_old_rotation = FloatProperty(name="old_Rotation", description="Old Rotate the plane",
-                                         min=-180, max=180, default=0)
+                                           min=-180, max=180, default=0)
                                          
     Ob.custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
-                                          subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2,update = update_Scale)
-    Ob.custom_propscale = FloatProperty(name="PropScale", description="Scale the Plan",
-                                           default=1.0,min = 0.1,update = update_PropScale)
+                                          subtype = 'XYZ',
+                                          default=(1.0, 1.0),
+                                          min = 0.1,
+                                          max = 10,
+                                          soft_min = 0.1,
+                                          soft_max = 10,
+                                          size=2,
+                                          step=0.5,
+                                          update = update_Scale)
+                                          
+    Ob.custom_propscale = FloatProperty(name="PropScale", description="Scale the Plane",
+                                        default  = 1.0,
+                                        min      = 0.1,
+                                        soft_min = 0.1,
+                                        soft_max = 10,
+                                        step     = 0.5,
+                                        update   = update_PropScale)
+                                           
     Ob.custom_old_scale = FloatVectorProperty(name="old_Scales", description="Old Scale the planes",
                                           subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
                                           
     Ob.custom_linkscale = BoolProperty(name="linkscale", default=True, update = update_LinkScale)
     
                                 
-    Ob.custom_sub = IntProperty(name="Subdivide", description="Number of subdivision of the plan",
-                                     min=1, max=20, default=10)                                
+    Ob.custom_sub = IntProperty(name="Subdivide", description="Number of subdivision of the plane",
+                                     min=0, max=20, default=0)                                
     
     # UV properties
     Ob.custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
-                                            default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2,update = update_UVScale)
+                                            default  = (1.0,1.0),
+                                            soft_min = 0.01,
+                                            soft_max = 100,
+                                            min      = 0.01, 
+                                            subtype  = 'XYZ',
+                                            size     = 2,
+                                            update   = update_UVScale)
+                                            
     Ob.custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
-                                           default=1.0,min = 0.01,update = update_PropUVScale)    
+                                          default    = 1.0,
+                                          soft_min   = 0.01,
+                                          soft_max   = 100,
+                                          min        = 0.01,
+                                          update     = update_PropUVScale)    
+
     Ob.custom_old_scaleuv = FloatVectorProperty(name="old_ScaleUV", description="Scale the texture's UV",
                                                 default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
     Ob.custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
@@ -332,9 +401,13 @@ def createcustomprops(context):
     Ob.custom_rotc3d = BoolProperty(name="rotc3d", default=False)
     Ob.custom_scac3d = BoolProperty(name="scac3d", default=False)
     Ob.custom_expand = BoolProperty(name="expand", default=True)
-    Ob.custom_active_view = StringProperty(name = "custom_active_view",default = "View")
-    Ob.custom_active_object = StringProperty(name = "custom_active_object",default = context.object.name)
+    Ob.custom_style_clone = BoolProperty(name="custom_style_clone", default=False, update = update_style_clone)
     
+    Ob.custom_active_view = StringProperty(name = "custom_active_view",default = "View")
+    try:
+        Ob.custom_active_object = StringProperty(name = "custom_active_object",default = context.object.name)
+    except:
+        Ob.custom_active_object = StringProperty(name = "custom_active_object",default = 'debut')    
     Ob.custom_props = CollectionProperty(type = custom_props)
 
 # Function to remove custom properties
@@ -342,14 +415,15 @@ def removecustomprops():
     list_prop = ['custom_location', 'custom_rotation', 'custom_old_rotation', 'custom_scale', 'custom_old_scale', 'custom_c3d',
                  'custom_rotc3d', 'custom_scaleuv', 'custom_flipuvx', 'custom_flipuvy', 'custom_linkscale',
                  'custom_linkscaleuv', 'custom_old_scaleuv', 'custom_offsetuv', 'custom_old_offsetuv', 'custom_scac3d', 'custom_sub',
-                 'custom_expand', 'custom_active_view', 'custom_propscaleuv', 'custom_props', 'custom_propscale']
+                 'custom_expand', 'custom_style_clone', 'custom_active_view', 'custom_propscaleuv', 'custom_props', 'custom_propscale']
     for prop in list_prop:
         try:
-            del bpy.data.objects['Empty for BProjection'][prop]
+            del bpy.data.objects[BProjection_Empty][prop]
         except:
-            do = 'nothing'
+            pass
+        
 def clear_props(context):
-    em = bpy.data.objects['Empty for BProjection'
+    em = bpy.data.objects[BProjection_Empty
     em.custom_scale = [1,1]
     em.custom_rotation = 0
     em.custom_scaleuv =[1.0,1.0]
@@ -368,7 +442,7 @@ class CreateView(Operator):
 
     def execute(self, context):              
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         new_props = em.custom_props.add()        
         em.custom_active_view = new_props.custom_active_view               
         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = True
@@ -386,7 +460,7 @@ class SaveView(Operator):
     index = IntProperty(default = 0)
     
     def execute(self, context):              
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         prop = em.custom_props[self.index]                            
         prop.custom_rotation =  em.custom_rotation                    
         prop.custom_scale =  em.custom_scale                  
@@ -399,9 +473,9 @@ class SaveView(Operator):
         prop.custom_flipuvx = em.custom_flipuvx
         prop.custom_flipuvy = em.custom_flipuvy
         try:
-            prop.custom_image = bpy.data.textures['Texture for BProjection'].image.name
+            prop.custom_image = bpy.data.textures[BProjection_Texture].image.name
         except:
-            do = 'nothing'
+            pass
         
         return {'FINISHED'}
 
@@ -413,7 +487,7 @@ class PasteView(Operator):
     index = IntProperty(default = 0)
     
     def execute(self, context):              
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         tmp_scac3d = em.custom_scac3d
         tmp_rotc3d = em.custom_rotc3d
         em.custom_scac3d = False
@@ -428,8 +502,8 @@ class PasteView(Operator):
         em.custom_scale =  prop.custom_scale
         em.custom_propscale = prop.custom_propscale                     
         if prop.custom_image != '':
-            if bpy.data.textures['Texture for BProjection'].image.name != prop.custom_image:
-                bpy.data.textures['Texture for BProjection'].image = bpy.data.images[prop.custom_image]
+            if bpy.data.textures[BProjection_Texture].image.name != prop.custom_image:
+                bpy.data.textures[BProjection_Texture].image = bpy.data.images[prop.custom_image]
                 applyimage(context)
         if em.custom_flipuvx != prop.custom_flipuvx:
             em.custom_flipuvx = prop.custom_flipuvx
@@ -448,7 +522,7 @@ class RemoveView(Operator):
     
     def execute(self, context):              
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         
         ob.active_shape_key_index =  self.index + 1
         bpy.ops.object.shape_key_remove()
@@ -485,7 +559,7 @@ class ActiveView(Operator):
     
     def execute(self, context):
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         for item in (item for item in em.custom_props if item.custom_active == True):
             bpy.ops.object.save_view(index = item.custom_index)
             item.custom_active = False
@@ -512,19 +586,22 @@ class BProjection(Panel):
     def poll(cls, context):
         return (context.image_paint_object or context.sculpt_object)
 
-    def draw(self, context):        
-        layout = self.layout
-                
-        try: 
-            bpy.data.objects['Empty for BProjection']
-            
-            tex = bpy.data.textures['Texture for BProjection']
+    def draw(self, context):
+        layout = self.layout        
+        if  BProjection_Empty in [ob.name for ob in bpy.data.objects]:
+            tex = bpy.data.textures[BProjection_Texture]
+
             ob = context.object
-            em = bpy.data.objects['Empty for BProjection']
+            em = bpy.data.objects[BProjection_Empty]
             if ob == bpy.data.objects[em.custom_active_object]:            
                 col = layout.column(align =True)
                 col.operator("object.removebprojectionplane", text="Remove BProjection plane")           
-                
+
+            try:
+                matBProjection = bpy.data.materials[BProjection_Material]
+            except:
+                matBProjection = None
+            
             box = layout.box()
 
             row = box.row()
@@ -573,9 +650,20 @@ class BProjection(Panel):
                     else: 
                         row.prop(em,'custom_scaleuv',text='')
                         row.prop(em, "custom_linkscaleuv",text="",icon='UNLINKED')            
+                    
+                    if matBProjection:
+                        if context.scene.game_settings.material_mode == 'GLSL' and context.space_data.viewport_shade == 'TEXTURED':
+                            row = box.column(align =True)
+                            row.prop(matBProjection,'alpha', slider = True)
+                            
                     row = box.column(align =True)
-                    row.prop(ob.material_slots['Material for BProjection'].material,'alpha', slider = True)
+                    row.prop(ob,"custom_fnlevel")
                     row = box.column(align =True)
+                    if not em.custom_style_clone:
+                        row.prop(em,"custom_style_clone",text="Style Clone Normal", icon='RENDERLAYERS')
+                    else:
+                        row.prop(em,"custom_style_clone",text="Style Clone New", icon='RENDERLAYERS')    
+                    row = box.column(align =True)    
     
                 if ob == bpy.data.objects[em.custom_active_object]:    
                     for item in em.custom_props:
@@ -593,9 +681,18 @@ class BProjection(Panel):
                     col = box.column(align =True)
                     col.operator("object.change_object", text="Change Object")       
 
-        except:
+        else:
+            ob = context.object
             col = layout.column(align = True)
-            col.operator("object.addbprojectionplane", text="Add BProjection plan")
+            
+            if ob.active_material is None:
+                col.label(text="Add a material first!", icon="ERROR")
+            elif ob.data.uv_textures.active is None:
+                col.label(text="Create UVMap first!!", icon="ERROR")
+            else:
+                col.operator("object.addbprojectionplane", text="Add BProjection plane")
+                col = layout.column(align = True)
+                col.prop(ob, "custom_sub",text="Subdivision level")
                    
 
 # Oprerator Class to apply the image to the plane             
@@ -615,7 +712,7 @@ class IntuitiveScale(Operator):
 
     def invoke(self, context, event):
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         x = event.mouse_region_x
         y = event.mouse_region_y                
         if len(ob.grease_pencil.layers.active.frames) == 0: 
@@ -658,9 +755,7 @@ class AddBProjectionPlane(Operator):
     bl_label = "Configure"
     
     def creatematerial(self, context):        
-        try:
-            matBProjection = bpy.data.materials['Material for BProjection']
-        except:            
+        if 'Material for BProjection' not in [mat.name for mat in bpy.data.materials]:            
             bpy.data.textures.new(name='Texture for BProjection',type='IMAGE')
     
             bpy.data.materials.new(name='Material for BProjection')
@@ -684,11 +779,8 @@ class AddBProjectionPlane(Operator):
         ob.data.update()
             
     def execute(self, context):    
-        try:
-            bpy.data.objects['Empty for BProjection']
-
-        except:                 
-            createcustomprops(context)
+        if  BProjection_Empty not in [ob.name for ob in bpy.data.objects]:                
+            
             cm = bpy.context.object.mode
             '''tmp = context.object
             for ob in (ob for ob in bpy.data.objects if ob.type == 'MESH' and ob.hide == False and context.scene in ob.users_scene):
@@ -704,7 +796,7 @@ class AddBProjectionPlane(Operator):
         
             bpy.ops.object.add()
             em = context.object
-            em.name = "Empty for BProjection"
+            em.name = BProjection_Empty
                         
             context.scene.objects.active = ob
             ob.select = True
@@ -723,8 +815,10 @@ class AddBProjectionPlane(Operator):
             for i in range(4):
                 ob.data.edges[len(ob.data.edges)-1-i].crease = 1
             bpy.ops.object.editmode_toggle()
-
-            bpy.ops.mesh.subdivide(number_cuts = em.custom_sub)
+            
+            em.custom_sub = ob.custom_sub
+            if em.custom_sub > 0:
+                bpy.ops.mesh.subdivide(number_cuts = em.custom_sub)
     
             em.select = True
             bpy.ops.object.hook_add_selob()
@@ -744,35 +838,44 @@ class AddBProjectionPlane(Operator):
             bpy.ops.object.shape_key_add(from_mix = False)
             
             bpy.ops.object.create_view()
-            # ----------------------------------------------
-            # XXX, this isnt future proof, DON'T USE INDEX's - campbell                    
+                    
             km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
-            km.keymap_items[3-1].idname = 'view3d.rotate_view3d'
-            km.keymap_items[19-1].idname = 'view3d.zoom_view3d'
-            km.keymap_items[19-1].properties.delta = 1.0
-            km.keymap_items[20-1].idname = 'view3d.zoom_view3d'
-            km.keymap_items[20-1].properties.delta = -1.0
-            km.keymap_items[4-1].idname = 'view3d.pan_view3d'
-            km.keymap_items[28-1].idname = 'view3d.preset_view3d'
-            km.keymap_items[28-1].properties.view = 'FRONT'
-            km.keymap_items[30-1].idname = 'view3d.preset_view3d'
-            km.keymap_items[30-1].properties.view = 'RIGHT'            
-            km.keymap_items[34-1].idname = 'view3d.preset_view3d'
-            km.keymap_items[34-1].properties.view = 'TOP'
-            km.keymap_items[36-1].idname = 'view3d.preset_view3d'
-            km.keymap_items[36-1].properties.view = 'BACK'
-            km.keymap_items[37-1].idname = 'view3d.preset_view3d'
-            km.keymap_items[37-1].properties.view = 'LEFT'            
-            km.keymap_items[38-1].idname = 'view3d.preset_view3d'
-            km.keymap_items[38-1].properties.view = 'BOTTOM'                                   
+            l = ['view3d.rotate','view3d.move','view3d.zoom','view3d.viewnumpad','paint.bp_paint','MOUSE','KEYBOARD','LEFT','MIDDLEMOUSE','WHEELINMOUSE','WHEELOUTMOUSE','NUMPAD_1','NUMPAD_3','NUMPAD_7']
+            for kmi in km.keymap_items:
+                if kmi.idname in l and kmi.map_type in l and kmi.type in l:
+                    try:
+                        p = kmi.properties.delta
+                        if p == -1 or p == 1:
+                            kmi.idname = 'view3d.zoom_view3d'
+                            kmi.properties.delta = p
+                    except:
+                        try:
+                            p = kmi.properties.type
+                            if kmi.shift == False :
+                                kmi.idname = 'view3d.preset_view3d'
+                                kmi.properties.view = p
+                        except:
+                            if kmi.idname == 'view3d.rotate':
+                                kmi.idname = 'view3d.rotate_view3d'  
+                            if kmi.idname == 'view3d.move':
+                                kmi.idname = 'view3d.pan_view3d'
+                                                              
             km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
+                    
             kmi = km.keymap_items.new("object.intuitivescale", 'LEFTMOUSE', 'PRESS', shift=True)
-                        
+            kmi = km.keymap_items.new("object.bp_grab", 'G', 'PRESS')
+            kmi = km.keymap_items.new("object.bp_rotate", 'R', 'PRESS') 
+            kmi = km.keymap_items.new("object.bp_scale", 'S', 'PRESS')            
+            kmi = km.keymap_items.new("object.bp_scaleuv", 'U', 'PRESS')
+            kmi = km.keymap_items.new("object.bp_offsetuv", 'Y', 'PRESS')
+            kmi = km.keymap_items.new("object.bp_clear_prop", 'C', 'PRESS')
+            kmi = km.keymap_items.new("object.bp_toggle_alpha", 'Q', 'PRESS')
             align_to_view(context)
             
             context.space_data.cursor_location = em.location
             
             bpy.ops.object.mode_set(mode = cm, toggle=False)
+            bpy.data.objects[BProjection_Empty].custom_active_object = context.object.name
             
         return {'FINISHED'}
 
@@ -786,7 +889,7 @@ class RemoveBProjectionPlane(Operator):
         i = 0
 
         for ms in ob.material_slots:
-            if ms.name == 'Material for BProjection':
+            if ms.name == BProjection_Material:
                 index = i
             i+=1
                 
@@ -821,7 +924,7 @@ class RemoveBProjectionPlane(Operator):
    
             ob.select = False
                 
-            em = bpy.data.objects['Empty for BProjection']
+            em = bpy.data.objects[BProjection_Empty]
             context.scene.objects.active = em
             em.hide = False
             em.select = True
@@ -830,33 +933,8 @@ class RemoveBProjectionPlane(Operator):
             context.scene.objects.active = ob
             ob.select = True
             
-            km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
-            # ----------------------------------------------
-            # XXX, this isnt future proof, DON'T USE INDEX's - campbell
-            km.keymap_items[3-1].idname = 'view3d.rotate'
-            km.keymap_items[19-1].idname = 'view3d.zoom'
-            km.keymap_items[19-1].properties.delta = 1.0
-            km.keymap_items[20-1].idname = 'view3d.zoom'
-            km.keymap_items[20-1].properties.delta = -1.0
-            km.keymap_items[4-1].idname = 'view3d.move'
-            km.keymap_items[28-1].idname = 'view3d.viewnumpad'
-            km.keymap_items[28-1].properties.type = 'FRONT'
-            km.keymap_items[30-1].idname = 'view3d.viewnumpad'
-            km.keymap_items[30-1].properties.type = 'RIGHT'            
-            km.keymap_items[34-1].idname = 'view3d.viewnumpad'
-            km.keymap_items[34-1].properties.type = 'TOP'
-            km.keymap_items[36-1].idname = 'view3d.viewnumpad'
-            km.keymap_items[36-1].properties.type = 'BACK'
-            km.keymap_items[37-1].idname = 'view3d.viewnumpad'
-            km.keymap_items[37-1].properties.type = 'LEFT'            
-            km.keymap_items[38-1].idname = 'view3d.viewnumpad'
-            km.keymap_items[38-1].properties.type = 'BOTTOM'            
-            
-            km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
-            #to do
-            for kmi in (kmi for kmi in km.keymap_items if kmi.idname in {"object.intuitivescale", }):
-                    km.keymap_items.remove(kmi)
-            
+            reinitkey()
+                        
             '''tmp = context.object
             for ob in (ob for ob in bpy.data.objects if ob.type == 'MESH' and ob.hide == False and context.scene in ob.users_scene):
                 context.scene.objects.active = ob
@@ -878,6 +956,37 @@ class RemoveBProjectionPlane(Operator):
         
         return {'FINISHED'}
 
+def reinitkey():
+    km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
+    l = ['view3d.zoom_view3d','view3d.preset_view3d','view3d.rotate_view3d','view3d.pan_view3d','MOUSE','KEYBOARD','MIDDLEMOUSE','WHEELINMOUSE','WHEELOUTMOUSE','NUMPAD_1','NUMPAD_3','NUMPAD_7']
+    for kmi in km.keymap_items:
+        if kmi.idname in l and kmi.map_type in l and kmi.type in l:
+            try:
+                p = kmi.properties.delta
+                if p == -1 or p == 1:
+                    kmi.idname = 'view3d.zoom'
+                    kmi.properties.delta = p
+            except:
+                try:
+                    p = kmi.properties.view
+                    if kmi.shift == False :
+                        kmi.idname = 'view3d.viewnumpad'
+                        kmi.properties.type = p
+                except:
+                    if kmi.idname == 'view3d.rotate_view3d':
+                        kmi.idname = 'view3d.rotate'  
+                    if kmi.idname == 'view3d.pan_view3d':
+                        kmi.idname = 'view3d.move'            
+            
+    km = bpy.context.window_manager.keyconfigs.default.keymaps['Image Paint']
+                
+    for kmi in km.keymap_items:
+        if kmi.idname == 'paint.bp_paint':
+            kmi.idname = 'paint.image_paint'
+            
+    for kmi in (kmi for kmi in km.keymap_items if kmi.idname in {"object.intuitivescale", "object.bp_grab", "object.bp_rotate", "object.bp_scale", "object.bp_scaleuv", "object.bp_clear_prop", "object.bp_offsetuv","object.bp_toggle_alpha", }):
+            km.keymap_items.remove(kmi)
+
 # Oprerator Class to remove what is no more needed    
 class ChangeObject(Operator):
     bl_idname = "object.change_object"
@@ -888,7 +997,7 @@ class ChangeObject(Operator):
         i = 0
 
         for ms in ob.material_slots:
-            if ms.name == 'Material for BProjection':
+            if ms.name == BProjection_Material:
                 index = i
             i+=1
                 
@@ -897,7 +1006,7 @@ class ChangeObject(Operator):
     
     def execute(self, context):
             new_ob = context.object
-            em = bpy.data.objects['Empty for BProjection']              
+            em = bpy.data.objects[BProjection_Empty]              
             context.scene.objects.active = bpy.data.objects[em.custom_active_object]
             ob = context.object
             if ob != new_ob:
@@ -940,7 +1049,7 @@ class ChangeObject(Operator):
                 
                 bplane.select = True            
                 context.scene.objects.active = bplane
-                for ms in (ms for ms in bplane.material_slots if ms.name != 'Material for BProjection'):
+                for ms in (ms for ms in bplane.material_slots if ms.name != BProjection_Material):
                     bplane.active_material = ms.material
                     bpy.ops.object.material_slot_remove()
                 
@@ -984,6 +1093,517 @@ class ChangeObject(Operator):
                 em.custom_c3d = tmp
                     
             return {'FINISHED'}
+    
+#Paint from the bp_plan
+
+last_mouse = Vector((0,0))
+
+def move_bp(self,context,cm,fm):
+    em = bpy.data.objects['Empty for BProjection']
+    
+    deltax = cm.x - round(fm.x)
+    deltay = cm.y - round(fm.y)
+    
+    sd = context.space_data              
+    l =  sd.region_3d
+    vr = l.view_rotation.copy()
+    vr.invert()
+    
+    v_init = Vector((0.0,0.0,1.0))
+    
+    pos = [-deltax,-deltay]
+    v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
+    pos = [0,0]
+    vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)        
+    loc = vbl - v 
+      
+    loc.rotate(vr)
+        
+    em.custom_location -= loc
+    
+    self.first_mouse = cm
+            
+class BP_Paint(bpy.types.Operator):
+    bl_idname = "paint.bp_paint"
+    bl_label = "Paint BProjection Plane"
+    first_mouse = Vector((0,0))
+    
+    @classmethod
+    def poll(cls, context):
+        return 1
+
+    def modal(self, context, event):
+        global last_mouse
+        em = bpy.data.objects['Empty for BProjection']        
+        sd = context.space_data
+        
+        center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location)
+        vec_init = self.first_mouse - center        
+        vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center               
+            
+        if event.type == 'MOUSEMOVE':#'INBETWEEN_MOUSEMOVE':                
+            step_act = Vector((event.mouse_region_x, event.mouse_region_y)) - self.step_prev
+            if step_act.length >= context.scene.tool_settings.unified_paint_settings.size*bpy.data.brushes['Clone'].spacing/100 or bpy.data.brushes['Clone'].use_airbrush: 
+                move_bp(self,context,Vector((event.mouse_region_x, event.mouse_region_y)) - self.v_offset,self.first_mouse)   
+                
+                bpy.ops.paint.image_paint(stroke=[{"name":"", "location":(0, 0, 0), "mouse":(event.mouse_region_x, event.mouse_region_y),
+                                                       "pressure":1, "pen_flip":False, "time":0, "is_start":False}])
+                self.step_prev = Vector((event.mouse_region_x, event.mouse_region_y))
+                
+        if event.type == 'LEFTMOUSE':
+            em.custom_c3d = True
+            bpy.data.materials['Material for BProjection'].alpha = self.alpha
+            em.custom_location = self.first_location
+            return {'FINISHED'}
+        
+        if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
+            em.custom_c3d = True
+            bpy.data.materials['Material for BProjection'].alpha = self.alpha
+            em.custom_location = self.first_location
+            return {'FINISHED'}
+        
+        return {'PASS_THROUGH'}
+                
+    def invoke(self, context, event):   
+        em = bpy.data.objects['Empty for BProjection']
+        context.window_manager.modal_handler_add(self)
+        self.first_mouse = Vector((event.mouse_region_x, event.mouse_region_y))
+        
+        sd = context.space_data              
+        l =  sd.region_3d        
+        v_init = Vector((0.0,0.0,1.0))
+        context.scene.cursor_location = view3d_utils.region_2d_to_location_3d(context.region, l, [event.mouse_region_x, event.mouse_region_y], v_init)
+        
+        self.first_location = em.custom_location.copy()
+        
+        self.v_offset =  Vector((context.region.width, context.region.height)) - Vector((event.mouse_region_x, event.mouse_region_y))
+        move_bp(self,context,Vector((event.mouse_region_x, event.mouse_region_y)) - self.v_offset,self.first_mouse)
+        
+        em.custom_c3d = False
+        self.alpha = bpy.data.materials['Material for BProjection'].alpha
+        
+        em.custom_location.z = -10
+         
+        bpy.data.materials['Material for BProjection'].alpha = 0
+            
+        bpy.ops.paint.image_paint(stroke=[{"name":"", "location":(0, 0, 0), "mouse":(event.mouse_region_x, event.mouse_region_y),
+                                                   "pressure":1, "pen_flip":False, "time":0, "is_start":False}])
+        self.step_prev = Vector((event.mouse_region_x, event.mouse_region_y))       
+        return {'RUNNING_MODAL'}  
+
+# Oprerator Class toggle the alpha of the plane             
+temp_alpha = 0
+class ApplyImage(Operator):
+    bl_idname = "object.bp_toggle_alpha"
+    bl_label = "Toggle Alpha of the BP"
+    
+    def execute(self, context):        
+        global temp_alpha  
+        if temp_alpha != 0:
+            bpy.data.materials['Material for BProjection'].alpha = temp_alpha 
+            temp_alpha = 0
+        else:
+            temp_alpha = bpy.data.materials['Material for BProjection'].alpha
+            bpy.data.materials['Material for BProjection'].alpha = 0    
+        
+        return {'FINISHED'}
+    
+#reinit the values of the bp_plane
+class BP_Clear_Props(Operator):
+    bl_idname = "object.bp_clear_prop"
+    bl_label = "Clear Props BProjection Plane"
+
+    def execute(self, context):        
+        clear_props(context)
+        
+        return{'FINISHED'}
+    
+#Move the UV of the bp_plane
+class BP_OffsetUV(bpy.types.Operator):
+    bl_idname = "object.bp_offsetuv"
+    bl_label = "OffsetUV BProjection Plane"
+    
+    axe_x = True
+    axe_y = True
+
+    first_mouse = Vector((0,0))
+    first_offsetuv = Vector((0,0))
+    
+    @classmethod
+    def poll(cls, context):
+        return 1
+
+    def modal(self, context, event):
+        em = bpy.data.objects['Empty for BProjection']        
+                
+        if event.shift:
+            fac = 0.1
+        else:
+            fac = 1
+
+        if event.type == 'X' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_y = False
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_y = False
+                self.axe_x = True   
+        
+        if event.type == 'Y' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_x = False
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_x = True
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+                self.axe_x = False
+                
+        deltax = (event.mouse_region_x - self.first_mouse.x)*fac
+        deltay = (event.mouse_region_y - self.first_mouse.y)*fac
+
+        if event.type == 'MOUSEMOVE':
+
+            if  not self.axe_y:
+                deltay = 0
+            if not self.axe_x:
+                deltax = 0                  
+                                                
+            ouv = em.custom_offsetuv
+            em.custom_offsetuv = [ouv[0] - deltax/50,ouv[1] - deltay/50]
+        
+            self.first_mouse.x = event.mouse_region_x
+            self.first_mouse.y = event.mouse_region_y 
+
+        if event.type == 'LEFTMOUSE':
+            return {'FINISHED'}
+        
+        if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
+            em.custom_offsetuv = self.first_offsetuv
+            return {'FINISHED'}
+        
+        return {'RUNNING_MODAL'}
+                
+    def invoke(self, context, event):   
+        em = bpy.data.objects['Empty for BProjection']
+        context.window_manager.modal_handler_add(self)
+        self.first_mouse.x = event.mouse_region_x
+        self.first_mouse.y = event.mouse_region_y
+        self.first_offsetuv = em.custom_offsetuv.copy()
+                
+        return {'RUNNING_MODAL'}
+
+#Scale the UV of the bp_plane
+class BP_ScaleUV(bpy.types.Operator):
+    bl_idname = "object.bp_scaleuv"
+    bl_label = "ScaleUV BProjection Plane"
+    
+    axe_x = True
+    axe_y = True
+
+    first_mouse = Vector((0,0))
+    first_scaleuv = Vector((0,0))
+    
+    @classmethod
+    def poll(cls, context):
+        return 1
+
+    def modal(self, context, event):
+        em = bpy.data.objects['Empty for BProjection']        
+                
+        if event.shift:
+            fac = 0.1
+        else:
+            fac = 1
+
+        if event.type == 'X' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_y = False
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_y = False
+                self.axe_x = True   
+        
+        if event.type == 'Y' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_x = False
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_x = True
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+                self.axe_x = False
+                
+        deltax = (event.mouse_region_x - self.first_mouse.x)*fac
+        deltay = (event.mouse_region_y - self.first_mouse.y)*fac
+
+        if event.type == 'MOUSEMOVE':
+
+            if  not self.axe_y:
+                deltay = 0
+            if not self.axe_x:
+                deltax = 0                
+            
+            if self.axe_x and self.axe_y:
+                fac = em.custom_scaleuv[1]/em.custom_scaleuv[0]
+                deltay = deltax * fac
+            else:
+                em.custom_linkscaleuv = False    
+                                                
+            s = em.custom_scaleuv
+            em.custom_scaleuv = [s[0] + deltax/50, s[1] + deltay/50]
+        
+            self.first_mouse.x = event.mouse_region_x
+            self.first_mouse.y = event.mouse_region_y 
+
+        if event.type == 'LEFTMOUSE':
+            return {'FINISHED'}
+        
+        if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
+            em.custom_scaleuv = self.first_scaleuv
+            return {'FINISHED'}
+        
+        return {'RUNNING_MODAL'}
+                
+    def invoke(self, context, event):   
+        em = bpy.data.objects['Empty for BProjection']
+        context.window_manager.modal_handler_add(self)
+        self.first_mouse.x = event.mouse_region_x
+        self.first_mouse.y = event.mouse_region_y
+        self.first_scaleuv = em.custom_scaleuv.copy()
+                
+        return {'RUNNING_MODAL'}
+    
+#Scale the bp_plane
+class BP_Scale(bpy.types.Operator):
+    bl_idname = "object.bp_scale"
+    bl_label = "Scale BProjection Plane"
+    
+    axe_x = True
+    axe_y = True
+
+    first_mouse = Vector((0,0))
+    first_scale = Vector((0,0,0))
+    
+    @classmethod
+    def poll(cls, context):
+        return 1
+
+    def modal(self, context, event):
+        em = bpy.data.objects['Empty for BProjection']        
+        sd = context.space_data
+
+        center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location)
+        vec_init = self.first_mouse - center        
+        vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
+        scale_fac = vec_act.length/vec_init.length
+                        
+        if event.ctrl:
+            scale_fac = round(scale_fac,1)
+
+        if event.type == 'X' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_y = False
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_y = False
+                self.axe_x = True   
+        
+        if event.type == 'Y' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_x = False
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_x = True
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+                self.axe_x = False
+        
+        if event.type == 'MOUSEMOVE':
+            
+            if self.axe_x:
+                em.custom_scale = [self.first_scale[0]*scale_fac, self.first_scale[1]]
+            if self.axe_y:
+                em.custom_scale = [self.first_scale[0], self.first_scale[1]*scale_fac]                
+            
+            if self.axe_x and self.axe_y:
+                em.custom_scale = [self.first_scale[0]*scale_fac, self.first_scale[1]*scale_fac]
+            else:
+                em.custom_linkscale = False    
+
+        if event.type == 'LEFTMOUSE':
+            return {'FINISHED'}
+        
+        if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
+            em.custom_scale = self.first_scale
+            return {'FINISHED'}
+        
+        return {'RUNNING_MODAL'}
+                
+    def invoke(self, context, event):   
+        em = bpy.data.objects['Empty for BProjection']
+        context.window_manager.modal_handler_add(self)
+        self.first_mouse.x = event.mouse_region_x
+        self.first_mouse.y = event.mouse_region_y
+        self.first_scale = em.custom_scale.copy()
+                
+        return {'RUNNING_MODAL'}
+    
+#Rotate the bp_plan
+class BP_Rotate(bpy.types.Operator):
+    bl_idname = "object.bp_rotate"
+    bl_label = "Rotate BProjection Plane"
+    
+    first_mouse = Vector((0,0))
+    first_rotation = 0
+    
+    @classmethod
+    def poll(cls, context):
+        return 1
+
+    def modal(self, context, event):
+        em = bpy.data.objects['Empty for BProjection']        
+        sd = context.space_data
+        
+        center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location if em.custom_rotc3d else context.scene.cursor_location)
+        vec_init = self.first_mouse - center        
+        vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
+        rot = -vec_init.angle_signed(vec_act)*180/pi
+              
+        if event.shift:
+            rot = rot
+        else:
+            rot = int(rot)
+        
+        if event.ctrl:
+            rot = int(rot/5)*5                 
+            
+        if event.type == 'MOUSEMOVE':
+                
+            em.custom_rotation = self.first_rotation + rot
+
+        if event.type == 'LEFTMOUSE':
+            return {'FINISHED'}
+        
+        if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
+            em.custom_rotation = self.first_rotation
+            return {'FINISHED'}
+        
+        return {'RUNNING_MODAL'}
+                
+    def invoke(self, context, event):   
+        em = bpy.data.objects['Empty for BProjection']
+        context.window_manager.modal_handler_add(self)
+        self.first_mouse.x = event.mouse_region_x
+        self.first_mouse.y = event.mouse_region_y
+        self.first_rotation = em.custom_rotation
+                
+        return {'RUNNING_MODAL'}   
+     
+# grab the bp_plan
+class BP_Grab(bpy.types.Operator):
+    bl_idname = "object.bp_grab"
+    bl_label = "Grab BProjection Plane"
+    
+    axe_x = True
+    axe_y = True
+    axe_z = False
+    first_mouse = Vector((0,0))
+    first_location = Vector((0,0,0))
+    
+    @classmethod
+    def poll(cls, context):
+        return 1
+
+    def modal(self, context, event):
+        em = bpy.data.objects['Empty for BProjection']        
+                
+        if event.shift:
+            fac = 0.1
+        else:
+            fac = 1
+
+        if event.type == 'X' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_y = False
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_y = False
+                self.axe_x = True
+            if self.axe_z == True:
+                self.axe_z = False
+                self.axe_x = True   
+        
+        if event.type == 'Y' and event.value == 'PRESS':
+            if self.axe_x == True and self.axe_y == True:
+                self.axe_x = False
+            elif self.axe_x == False and self.axe_y == True:
+                self.axe_x = True
+            elif self.axe_x == True and self.axe_y == False:
+                self.axe_y = True
+                self.axe_x = False
+            if self.axe_z == True:
+                self.axe_z = False
+                self.axe_y = True
+                
+        if event.type == 'Z' and event.value == 'PRESS':
+            if self.axe_z == False:
+                self.axe_z = True
+                self.axe_x = False
+                self.axe_y = False
+            elif self.axe_z == True:    
+                self.axe_z = False
+                self.axe_x = True
+                self.axe_y = True
+                
+        deltax = event.mouse_region_x - round(self.first_mouse.x)
+        deltay = event.mouse_region_y - round(self.first_mouse.y)
+        
+        if event.type == 'MOUSEMOVE':
+            sd = context.space_data              
+            l =  sd.region_3d
+            vr = l.view_rotation.copy()
+            vr.invert()
+            
+            v_init = Vector((0.0,0.0,1.0))
+            
+            pos = [-deltax,-deltay]
+            v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
+            pos = [0,0]
+            vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)        
+            loc = vbl - v 
+      
+            loc.rotate(vr)
+            if  not self.axe_y:
+                loc.y = loc.z = 0
+            if not self.axe_x:
+                loc.x = loc.z = 0
+            if self.axe_z:
+                loc.z = deltax/10
+                
+            em.custom_location += loc*fac
+        
+            self.first_mouse.x = event.mouse_region_x
+            self.first_mouse.y = event.mouse_region_y 
+
+        if event.type == 'LEFTMOUSE':
+            return {'FINISHED'}
+        
+        if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
+            em.custom_location = self.first_location
+            return {'FINISHED'}
+        
+        return {'RUNNING_MODAL'}
+                
+    def invoke(self, context, event):   
+        em = bpy.data.objects['Empty for BProjection']
+        context.window_manager.modal_handler_add(self)
+        self.first_mouse.x = event.mouse_region_x
+        self.first_mouse.y = event.mouse_region_y
+        self.first_location = em.custom_location.copy()
+                
+        return {'RUNNING_MODAL'}            
 
 # Oprerator Class to rotate the view3D
 class RotateView3D(Operator):
@@ -991,17 +1611,13 @@ class RotateView3D(Operator):
     bl_label = "Rotate the View3D"
     
     first_mouse = Vector((0,0))
-
-    pan = Vector((0,0))
-
-    key = ['']
  
     first_time = True
     tmp_level = -1
-    
+
     def vect_sphere(self, context, mx, my):
-        width = context.area.regions[4].width
-        height = context.area.regions[4].height
+        width = context.region.width
+        height = context.region.height
            
         if width >= height:
             ratio = height/width
@@ -1031,8 +1647,6 @@ class RotateView3D(Operator):
     
     def tracball(self, context, mx, my, origine):
         sd = context.space_data
-        ob = context.object
-        em = bpy.data.objects['Empty for BProjection']        
             
         vr_b = sd.region_3d.view_rotation.copy()
         vr_b.invert()
@@ -1055,90 +1669,63 @@ class RotateView3D(Operator):
         sd.region_3d.view_location =  pos_init + origine
         
         self.first_mouse = Vector((mx, my))
+
+    def turnable(self, context, mx, my, origine):
+        sd = context.space_data
+        
+        width = context.region.width
+        height = context.region.height
+            
+        vr_b = sd.region_3d.view_rotation.copy()
+        vr_b.invert()
+        pos_init = sd.region_3d.view_location - origine
+        sd.region_3d.view_location = origine
+        
+        vz = Vector((0,0,1))
+        qz =  Quaternion(vz,-8*(mx-self.first_mouse.x)/width)
+        sd.region_3d.view_rotation.rotate(qz)
+        sd.region_3d.update()
+
+        vx = Vector((1,0,0))
+        vx.rotate(sd.region_3d.view_rotation)        
+        qx =  Quaternion(vx,8*(my-self.first_mouse.y)/height)        
+        sd.region_3d.view_rotation.rotate(qx)                
+        sd.region_3d.update()
+        
+        vr_a = sd.region_3d.view_rotation.copy()                           
+        pos_init.rotate(vr_a*vr_b)            
+        sd.region_3d.view_location =  pos_init + origine
                 
+        self.first_mouse = Vector((mx, my))
+                        
     def modal(self, context, event):                                
         ob = context.object
         em = bpy.data.objects['Empty for BProjection'] 
-        reg = context.area.regions[4]        
-        if event.value == 'PRESS':
-            self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
-                    
-            self.key = [event.type]
-
+        reg = context.region        
+            
         if event.value == 'RELEASE':
-            self.key = [''] 
+            if self.tmp_level > -1:
+                for sub in context.object.modifiers:
+                    if sub.type in ['SUBSURF','MULTIRES']:
+                        sub.levels = self.tmp_level 
+            return {'FINISHED'}
 
         if event.type == 'MOUSEMOVE':                        
-            
-            if '' in self.key:
+            if context.user_preferences.inputs.view_rotate_method == 'TRACKBALL':
                 self.tracball(context, event.mouse_region_x, event.mouse_region_y,ob.location)
-                align_to_view(context)
-                if self.first_time:
-                    rot_ang = context.user_preferences.view.rotation_angle            
-                    context.user_preferences.view.rotation_angle = 0
-                    bpy.ops.view3d.view_orbit(type='ORBITLEFT')
-                    context.user_preferences.view.rotation_angle = rot_ang   
-                    bpy.ops.view3d.view_persportho()         
-                    bpy.ops.view3d.view_persportho()
-                    self.first_time = False
+            else:
+                self.turnable(context, event.mouse_region_x, event.mouse_region_y,ob.location)
+            align_to_view(context)
+            #to unlock the camera
+            if self.first_time:                    
+                rot_ang = context.user_preferences.view.rotation_angle            
+                context.user_preferences.view.rotation_angle = 0
+                bpy.ops.view3d.view_orbit(type='ORBITLEFT')
+                context.user_preferences.view.rotation_angle = rot_ang   
+                bpy.ops.view3d.view_persportho()         
+                bpy.ops.view3d.view_persportho()
+                self.first_time = False
           
-            deltax = event.mouse_region_x - round(self.pan.x)
-            deltay = event.mouse_region_y - round(self.pan.y)          
-
-            if 'G' in self.key:       
-                sd = context.space_data              
-                l =  sd.region_3d
-                vr = l.view_rotation.copy()
-                vr.invert()
-                
-                v_init = Vector((0.0,0.0,1.0))
-                
-                pos = [-deltax,-deltay]
-                v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
-                pos = [0,0]
-                vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)        
-                loc = vbl - v            
-                loc.rotate(vr)
-                em.custom_location += loc              
-                                   
-            if 'S' in self.key:                
-                s = em.custom_scale
-                if em.custom_linkscale:
-                    em.custom_propscale += deltax/20
-                else:
-                    em.custom_scale = [s[0] + deltax/20, s[1] + deltay/20]
-                                          
-            if 'Z' in self.key:                
-                em.custom_location.z+=deltax/10
-                      
-            if 'R' in self.key:
-                em.custom_rotation+=deltax
-                    
-            if 'U' in self.key:
-                suv = em.custom_scaleuv
-                if em.custom_linkscaleuv:    
-                    em.custom_propscaleuv += deltax/50
-                else:
-                    em.custom_scaleuv= [suv[0] + deltax/50 , suv[1] + deltay/50]               
-
-            if 'Y' in self.key:       
-                ouv = em.custom_offsetuv
-                em.custom_offsetuv = [ouv[0] - deltax/50,ouv[1] - deltay/50] 
-
-            self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
-            self.first_mouse = Vector((event.mouse_region_x, self.first_mouse.y))
-                        
-        elif event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
-            if self.tmp_level > -1:
-                bpy.context.object.modifiers['Subsurf'].levels = self.tmp_level      
-            
-            return {'FINISHED'}
-        
-        if 'C' in self.key:
-            clear_props(context)
-        
-        if 'O' in self.key:
-            bpy.ops.object.change_object()            
         return {'RUNNING_MODAL'}
     
     def execute(self, context):        
@@ -1147,13 +1734,17 @@ class RotateView3D(Operator):
         return{'FINISHED'}
 
     def invoke(self, context, event):
+        bpy.data.objects['Empty for BProjection']
         context.window_manager.modal_handler_add(self)
         self.first_mouse = Vector((event.mouse_region_x,event.mouse_region_y))
         self.first_time = True
         for sub in context.object.modifiers:
-            if sub.type == 'SUBSURF':
-                self.tmp_level = bpy.context.object.modifiers['Subsurf'].levels
-                bpy.context.object.modifiers['Subsurf'].levels = 0
+            if sub.type in ['SUBSURF', 'MULTIRES']:
+                self.tmp_level = sub.levels
+                if sub.levels - self.tmp_level <0:
+                    sub.levels = 0
+                else:
+                    sub.levels += bpy.context.object.custom_fnlevel
         return {'RUNNING_MODAL'}
 
 # Oprerator Class to pan the view3D
@@ -1166,9 +1757,9 @@ class PanView3D(bpy.types.Operator):
 
     def modal(self, context, event):
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
-        width = context.area.regions[4].width
-        height = context.area.regions[4].height
+        em = bpy.data.objects[BProjection_Empty]
+        width = context.region.width
+        height = context.region.height
 
         deltax = event.mouse_region_x - self.first_mouse.x
         deltay = event.mouse_region_y - self.first_mouse.y                
@@ -1187,28 +1778,36 @@ class PanView3D(bpy.types.Operator):
         loc = vbl - v       
         sd.region_3d.view_location += loc         
         loc.rotate(vr)
-        em.custom_location += loc
+        if not em.custom_style_clone:
+            em.custom_location += loc
 
         self.first_mouse.x = event.mouse_region_x
         self.first_mouse.y = event.mouse_region_y
 
         if event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
             if self.tmp_level > -1:
-                bpy.context.object.modifiers['Subsurf'].levels = self.tmp_level 
+                for sub in context.object.modifiers:
+                    if sub.type in ['SUBSURF','MULTIRES']:
+                        sub.levels = self.tmp_level
             return {'FINISHED'}
         
         return {'RUNNING_MODAL'}
                 
     def invoke(self, context, event):
+        bpy.data.objects['Empty for BProjection']    
         context.window_manager.modal_handler_add(self)
         self.first_mouse.x = event.mouse_region_x
         self.first_mouse.y = event.mouse_region_y   
         for sub in context.object.modifiers:
-            if sub.type == 'SUBSURF':
-                self.tmp_level = bpy.context.object.modifiers['Subsurf'].levels
-                bpy.context.object.modifiers['Subsurf'].levels = 0        
+            if sub.type in ['SUBSURF', 'MULTIRES']:
+                self.tmp_level = sub.levels
+                if sub.levels - self.tmp_level <0:
+                    sub.levels = 0
+                else:
+                    sub.levels += bpy.context.object.custom_fnlevel 
+                      
         return {'RUNNING_MODAL'}
-
+        
     def execute(self, context):        
         align_to_view(context)  
         
@@ -1227,11 +1826,11 @@ class ZoomView3D(Operator):
 
     def invoke(self, context, event):                   
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         sd = context.space_data
 
-        width = context.area.regions[4].width
-        height = context.area.regions[4].height              
+        width = context.region.width
+        height = context.region.height              
                     
         r3d =  sd.region_3d
         v_init = Vector((0.0,0.0,1.0))
@@ -1256,7 +1855,9 @@ class ZoomView3D(Operator):
         r3d.view_location *= fac
         r3d.view_location += ob.location
         vres = Vector((em.custom_location.x*fac,em.custom_location.y*fac,em.custom_location.z))
-        em.custom_location = vres
+        
+        if not em.custom_style_clone:
+            em.custom_location = vres
         
         
         align_to_view(context)
@@ -1274,10 +1875,9 @@ class PresetView3D(Operator):
     bl_label = "Preset View3D"
 
     view = StringProperty(name="View", description="Select the view", default='TOP')
-
     def invoke(self, context, event):                   
         ob = context.object
-        em = bpy.data.objects['Empty for BProjection']
+        em = bpy.data.objects[BProjection_Empty]
         origine = ob.location
         sd = context.space_data
 
@@ -1294,16 +1894,21 @@ class PresetView3D(Operator):
 
         vr_a = sd.region_3d.view_rotation.copy()                           
         pos_init.rotate(vr_a*vr_b)            
-        sd.region_3d.view_location =  pos_init + origine
-               
+        sd.region_3d.view_location =  pos_init + origine              
                     
         return {'FINISHED'}
 
+@persistent
+def load_handler(dummy):
+    reinitkey()
+
 def register():
     bpy.utils.register_module(__name__)
+    createcustomprops(bpy.context)
+    bpy.app.handlers.load_post.append(load_handler)
 
 def unregister():
     bpy.utils.unregister_module(__name__)
 
 if __name__ == "__main__":
-    register()
\ No newline at end of file
+    register()