1# ##### BEGIN GPL LICENSE BLOCK ##### 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software Foundation, 15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16# 17# ##### END GPL LICENSE BLOCK ##### 18 19# <pep8 compliant> 20 21bl_info = { 22 "name": "Hotkey: 'Ctrl Tab'", 23 "description": "Switch between 3d view object/edit modes", 24 "author": "pitiwazou, meta-androcto, italic", 25 "version": (0, 1, 2), 26 "blender": (2, 80, 0), 27 "location": "3D View", 28 "warning": "", 29 "doc_url": "", 30 "category": "Mode Switch Pie" 31} 32 33import bpy 34from bpy.types import ( 35 Menu, 36 Operator 37) 38 39 40class PIE_OT_ClassObject(Operator): 41 bl_idname = "class.object" 42 bl_label = "Class Object" 43 bl_description = "Edit/Object Mode Switch" 44 bl_options = {'REGISTER', 'UNDO'} 45 46 def execute(self, context): 47 if context.object.mode == "OBJECT": 48 bpy.ops.object.mode_set(mode="EDIT") 49 else: 50 bpy.ops.object.mode_set(mode="OBJECT") 51 return {'FINISHED'} 52 53 54class PIE_OT_ClassTexturePaint(Operator): 55 bl_idname = "class.pietexturepaint" 56 bl_label = "Class Texture Paint" 57 bl_description = "Texture Paint" 58 bl_options = {'REGISTER', 'UNDO'} 59 60 def execute(self, context): 61 if context.object.mode == "EDIT": 62 bpy.ops.object.mode_set(mode="OBJECT") 63 bpy.ops.paint.texture_paint_toggle() 64 else: 65 bpy.ops.paint.texture_paint_toggle() 66 return {'FINISHED'} 67 68 69class PIE_OT_ClassWeightPaint(Operator): 70 bl_idname = "class.pieweightpaint" 71 bl_label = "Class Weight Paint" 72 bl_description = "Weight Paint" 73 bl_options = {'REGISTER', 'UNDO'} 74 75 def execute(self, context): 76 if context.object.mode == "EDIT": 77 bpy.ops.object.mode_set(mode="OBJECT") 78 bpy.ops.paint.weight_paint_toggle() 79 else: 80 bpy.ops.paint.weight_paint_toggle() 81 return {'FINISHED'} 82 83 84class PIE_OT_ClassVertexPaint(Operator): 85 bl_idname = "class.pievertexpaint" 86 bl_label = "Class Vertex Paint" 87 bl_description = "Vertex Paint" 88 bl_options = {'REGISTER', 'UNDO'} 89 90 def execute(self, context): 91 if context.object.mode == "EDIT": 92 bpy.ops.object.mode_set(mode="OBJECT") 93 bpy.ops.paint.vertex_paint_toggle() 94 else: 95 bpy.ops.paint.vertex_paint_toggle() 96 return {'FINISHED'} 97 98 99class PIE_OT_ClassParticleEdit(Operator): 100 bl_idname = "class.pieparticleedit" 101 bl_label = "Class Particle Edit" 102 bl_description = "Particle Edit (must have active particle system)" 103 bl_options = {'REGISTER', 'UNDO'} 104 105 def execute(self, context): 106 if context.object.mode == "EDIT": 107 bpy.ops.object.mode_set(mode="OBJECT") 108 bpy.ops.particle.particle_edit_toggle() 109 else: 110 bpy.ops.particle.particle_edit_toggle() 111 return {'FINISHED'} 112 113 114# Set Mode Operator # 115class PIE_OT_SetObjectModePie(Operator): 116 bl_idname = "object.set_object_mode_pie" 117 bl_label = "Set the object interactive mode" 118 bl_description = "I set the interactive mode of object" 119 bl_options = {'REGISTER'} 120 121 mode: bpy.props.StringProperty(name="Interactive mode", default="OBJECT") 122 123 def execute(self, context): 124 if (context.active_object): 125 try: 126 bpy.ops.object.mode_set(mode=self.mode) 127 except TypeError: 128 msg = context.active_object.name + " It is not possible to enter into the interactive mode" 129 self.report(type={"WARNING"}, message=msg) 130 else: 131 self.report(type={"WARNING"}, message="There is no active object") 132 return {'FINISHED'} 133 134 135# Edit Selection Modes 136class PIE_OT_ClassVertex(Operator): 137 bl_idname = "class.vertex" 138 bl_label = "Class Vertex" 139 bl_description = "Vert Select Mode" 140 bl_options = {'REGISTER', 'UNDO'} 141 142 def execute(self, context): 143 if context.object.mode != "EDIT": 144 bpy.ops.object.mode_set(mode="EDIT") 145 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') 146 if bpy.ops.mesh.select_mode != "EDGE, FACE": 147 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') 148 return {'FINISHED'} 149 150 151class PIE_OT_ClassEdge(Operator): 152 bl_idname = "class.edge" 153 bl_label = "Class Edge" 154 bl_description = "Edge Select Mode" 155 bl_options = {'REGISTER', 'UNDO'} 156 157 def execute(self, context): 158 if context.object.mode != "EDIT": 159 bpy.ops.object.mode_set(mode="EDIT") 160 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') 161 if bpy.ops.mesh.select_mode != "VERT, FACE": 162 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') 163 return {'FINISHED'} 164 165 166class PIE_OT_ClassFace(Operator): 167 bl_idname = "class.face" 168 bl_label = "Class Face" 169 bl_description = "Face Select Mode" 170 bl_options = {'REGISTER', 'UNDO'} 171 172 def execute(self, context): 173 if context.object.mode != "EDIT": 174 bpy.ops.object.mode_set(mode="EDIT") 175 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') 176 if bpy.ops.mesh.select_mode != "VERT, EDGE": 177 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') 178 return {'FINISHED'} 179 180 181class PIE_OT_VertsEdgesFaces(Operator): 182 bl_idname = "verts.edgesfaces" 183 bl_label = "Verts Edges Faces" 184 bl_description = "Vert/Edge/Face Select Mode" 185 bl_options = {'REGISTER', 'UNDO'} 186 187 def execute(self, context): 188 if context.object.mode != "EDIT": 189 bpy.ops.object.mode_set(mode="EDIT") 190 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') 191 if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": 192 bpy.ops.object.mode_set(mode="EDIT") 193 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') 194 bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='EDGE') 195 bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') 196 return {'FINISHED'} 197 198 199# Menus 200class PIE_MT_ObjectEditotherModes(Menu): 201 """Edit/Object Others modes""" 202 bl_idname = "MENU_MT_objecteditmodeothermodes" 203 bl_label = "Edit Selection Modes" 204 205 def draw(self, context): 206 layout = self.layout 207 pie = layout.menu_pie() 208 box = pie.split().column() 209 210 box.operator("class.vertex", text="Vertex", icon='VERTEXSEL') 211 box.operator("class.edge", text="Edge", icon='EDGESEL') 212 box.operator("class.face", text="Face", icon='FACESEL') 213 box.operator("verts.edgesfaces", text="Vertex/Edges/Faces", icon='OBJECT_DATAMODE') 214 215 216class PIE_MT_ObjectEditMode(Menu): 217 """Modes Switch""" 218 bl_idname = "PIE_MT_objecteditmode" 219 bl_label = "Mode Switch (Ctrl Tab)" 220 221 def draw(self, context): 222 layout = self.layout 223 ob = context.object 224 # No Object Selected # 225 if not ob or not ob.select_get(): 226 message = "No Active Object Selected" 227 pie = layout.menu_pie() 228 pie.separator() 229 pie.separator() 230 pie.separator() 231 box = pie.box() 232 box.label(text=message, icon="INFO") 233 234 elif ob and ob.type == 'MESH' and ob.mode in {'OBJECT', 'SCULPT', 'VERTEX_PAINT', 235 'WEIGHT_PAINT', 'TEXTURE_PAINT', 236 'PARTICLE_EDIT', 'GPENCIL_EDIT'}: 237 pie = layout.menu_pie() 238 # 4 - LEFT 239 pie.operator("class.pieweightpaint", text="Weight Paint", icon='WPAINT_HLT') 240 # 6 - RIGHT 241 pie.operator("class.pietexturepaint", text="Texture Paint", icon='TPAINT_HLT') 242 # 2 - BOTTOM 243 pie.menu("MENU_MT_objecteditmodeothermodes", text="Edit Modes", icon='EDITMODE_HLT') 244 # 8 - TOP 245 pie.operator("class.object", text="Object/Edit Toggle", icon='OBJECT_DATAMODE') 246 # 7 - TOP - LEFT 247 pie.operator("sculpt.sculptmode_toggle", text="Sculpt", icon='SCULPTMODE_HLT') 248 # 9 - TOP - RIGHT 249 pie.operator("class.pievertexpaint", text="Vertex Paint", icon='VPAINT_HLT') 250 # 1 - BOTTOM - LEFT 251 pie.separator() 252 # 3 - BOTTOM - RIGHT 253 if context.object.particle_systems: 254 pie.operator("class.pieparticleedit", text="Particle Edit", icon='PARTICLEMODE') 255 else: 256 pie.separator() 257 258 elif ob and ob.type == 'MESH' and ob.mode in {'EDIT'}: 259 pie = layout.menu_pie() 260 # 4 - LEFT 261 pie.operator("class.pieweightpaint", text="Weight Paint", icon='WPAINT_HLT') 262 # 6 - RIGHT 263 pie.operator("class.pietexturepaint", text="Texture Paint", icon='TPAINT_HLT') 264 # 2 - BOTTOM 265 pie.menu("MENU_MT_objecteditmodeothermodes", text="Edit Modes", icon='EDITMODE_HLT') 266 # 8 - TOP 267 pie.operator("class.object", text="Edit/Object Toggle", icon='OBJECT_DATAMODE') 268 # 7 - TOP - LEFT 269 pie.operator("sculpt.sculptmode_toggle", text="Sculpt", icon='SCULPTMODE_HLT') 270 # 9 - TOP - RIGHT 271 pie.operator("class.pievertexpaint", text="Vertex Paint", icon='VPAINT_HLT') 272 # 1 - BOTTOM - LEFT 273 pie.separator() 274 # 3 - BOTTOM - RIGHT 275 if context.object.particle_systems: 276 pie.operator("class.pieparticleedit", text="Particle Edit", icon='PARTICLEMODE') 277 else: 278 pie.separator() 279 280 elif ob and ob.type == 'CURVE': 281 pie = layout.menu_pie() 282 # 4 - LEFT 283 pie.separator() 284 # 6 - RIGHT 285 pie.separator() 286 # 2 - BOTTOM 287 pie.separator() 288 # 8 - TOP 289 pie.operator("object.editmode_toggle", text="Edit/Object", icon='OBJECT_DATAMODE') 290 # 7 - TOP - LEFT 291 pie.separator() 292 # 9 - TOP - RIGHT 293 pie.separator() 294 # 1 - BOTTOM - LEFT 295 pie.separator() 296 # 3 - BOTTOM - RIGHT 297 pie.separator() 298 299 elif ob and ob.type == 'ARMATURE': 300 pie = layout.menu_pie() 301 # 4 - LEFT 302 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Object", icon="OBJECT_DATAMODE").mode = "OBJECT" 303 # 6 - RIGHT 304 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Pose", icon="POSE_HLT").mode = "POSE" 305 # 2 - BOTTOM 306 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Edit", icon="EDITMODE_HLT").mode = "EDIT" 307 # 8 - TOP 308 pie.operator("object.editmode_toggle", text="Edit Mode", icon='OBJECT_DATAMODE') 309 # 7 - TOP - LEFT 310 pie.separator() 311 # 9 - TOP - RIGHT 312 pie.separator() 313 # 1 - BOTTOM - LEFT 314 pie.separator() 315 # 3 - BOTTOM - RIGHT 316 pie.separator() 317 318 elif ob and ob.type == 'FONT': 319 pie = layout.menu_pie() 320 pie.separator() 321 pie.separator() 322 pie.separator() 323 pie.operator("object.editmode_toggle", text="Edit/Object Toggle", icon='OBJECT_DATAMODE') 324 pie.separator() 325 pie.separator() 326 pie.separator() 327 # 3 - BOTTOM - RIGHT 328 pie.separator() 329 330 elif ob and ob.type == 'SURFACE': 331 pie = layout.menu_pie() 332 pie.separator() 333 pie.separator() 334 pie.separator() 335 pie.operator("object.editmode_toggle", text="Edit/Object Toggle", icon='OBJECT_DATAMODE') 336 pie.separator() 337 pie.separator() 338 pie.separator() 339 # 3 - BOTTOM - RIGHT 340 pie.separator() 341 342 elif ob and ob.type == 'META': 343 pie = layout.menu_pie() 344 pie.separator() 345 pie.separator() 346 pie.separator() 347 pie.operator("object.editmode_toggle", text="Edit/Object Toggle", icon='OBJECT_DATAMODE') 348 pie.separator() 349 pie.separator() 350 pie.separator() 351 # 3 - BOTTOM - RIGHT 352 pie.separator() 353 354 elif ob and ob.type == 'LATTICE': 355 pie = layout.menu_pie() 356 pie.separator() 357 pie.separator() 358 pie.separator() 359 pie.operator("object.editmode_toggle", text="Edit/Object Toggle", icon='OBJECT_DATAMODE') 360 pie.separator() 361 pie.separator() 362 pie.separator() 363 364 if ob and ob.type == 'GPENCIL': 365 pie = layout.menu_pie() 366 # 4 - LEFT 367 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Sculpt", icon="SCULPTMODE_HLT").mode = "SCULPT_GPENCIL" 368 # 6 - RIGHT 369 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Draw", icon="GREASEPENCIL").mode = "PAINT_GPENCIL" 370 # 2 - BOTTOM 371 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Edit", icon="EDITMODE_HLT").mode = "EDIT_GPENCIL" 372 # 8 - TOP 373 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Object", icon="OBJECT_DATAMODE").mode = "OBJECT" 374 # 7 - TOP - LEFT 375 pie.separator() 376 # 9 - TOP - RIGHT 377 pie.separator() 378 # 1 - BOTTOM - LEFT 379 pie.separator() 380 # 3 - BOTTOM - RIGHT 381 pie.operator(PIE_OT_SetObjectModePie.bl_idname, text="Weight Paint", icon="WPAINT_HLT").mode = "WEIGHT_GPENCIL" 382 383 384 385 elif ob and ob.type in {"LIGHT", "CAMERA", "EMPTY", "SPEAKER"}: 386 message = "Active Object has only Object Mode available" 387 pie = layout.menu_pie() 388 pie.separator() 389 pie.separator() 390 pie.separator() 391 box = pie.box() 392 box.label(text=message, icon="INFO") 393 394 395classes = ( 396 PIE_MT_ObjectEditMode, 397 PIE_OT_ClassObject, 398 PIE_OT_ClassVertex, 399 PIE_OT_ClassEdge, 400 PIE_OT_ClassFace, 401 PIE_MT_ObjectEditotherModes, 402 PIE_OT_ClassTexturePaint, 403 PIE_OT_ClassWeightPaint, 404 PIE_OT_ClassVertexPaint, 405 PIE_OT_ClassParticleEdit, 406 PIE_OT_VertsEdgesFaces, 407 PIE_OT_SetObjectModePie, 408 ) 409 410addon_keymaps = [] 411 412 413def register(): 414 for cls in classes: 415 bpy.utils.register_class(cls) 416 417 wm = bpy.context.window_manager 418 if wm.keyconfigs.addon: 419 # Select Mode 420 km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') 421 kmi = km.keymap_items.new('wm.call_menu_pie', 'TAB', 'PRESS', ctrl=True) 422 kmi.properties.name = "PIE_MT_objecteditmode" 423 addon_keymaps.append((km, kmi)) 424 425 km = wm.keyconfigs.addon.keymaps.new(name='Grease Pencil Stroke Edit Mode') 426 kmi = km.keymap_items.new('wm.call_menu_pie', 'TAB', 'PRESS', ctrl=True) 427 kmi.properties.name = "PIE_MT_objecteditmode" 428 addon_keymaps.append((km, kmi)) 429 430 431def unregister(): 432 for cls in classes: 433 bpy.utils.unregister_class(cls) 434 435 wm = bpy.context.window_manager 436 kc = wm.keyconfigs.addon 437 if kc: 438 for km, kmi in addon_keymaps: 439 km.keymap_items.remove(kmi) 440 addon_keymaps.clear() 441 442 443if __name__ == "__main__": 444 register() 445