Import Export Vertex Groups rewritten
[blender-addons-contrib.git] / space_view3d_toolshelf_menu.py
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 # some parts based on 3d_cursor_menu.py by Jonathan Smith (JayDez) & work by sim88 & sam. 
19 # view3d_advanced_dynamic_toolshelf_menu byBrendon Murphy (meta-androcto)
20
21 bl_info = {
22     "name": "Dynamic Toolshelf Menu",
23     "author": "meta-androcto",
24     "version": (3, 0, 0),
25     "blender": (2, 7, 1),
26     "location": "View3D > Spacebar Key, Dynamic Tab",
27     "description": "Context Sensitive Toolshelf Menu",
28     "warning": "",
29     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
30                 "Scripts/3D_interaction/Dynamic_Spacebar_Menu",
31     "category": "3D View",
32 }
33
34 import bpy
35 from bpy import *
36
37 class View3DPanel():
38     bl_space_type = 'VIEW_3D'
39     bl_region_type = 'TOOLS'
40
41 class VIEW3D_PT_add_menu(View3DPanel,bpy.types.Panel):
42     bl_label = "Dynamic Toolshelf"
43     bl_category = "Dynamic"
44
45     def draw(self, context):
46         layout = self.layout
47         settings = context.tool_settings
48         layout.operator_context = 'INVOKE_REGION_WIN'
49
50         ob = context
51         if ob.mode == 'OBJECT':
52             # Object mode
53
54             # Search Menu
55             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
56             layout.separator()
57
58             # Add Menu block
59             layout.menu("VIEW3D_MT_AddMenu", icon='OBJECT_DATAMODE')
60
61             # Transform block
62             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
63
64             # Mirror block
65             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
66
67             # Cursor Block
68             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
69
70             # Parent block
71             layout.menu("VIEW3D_MT_ParentMenu", icon='ROTACTIVE')
72
73             # Group block
74             layout.menu("VIEW3D_MT_GroupMenu", icon='GROUP')
75
76             # Modifier block
77             layout.operator_menu_enum("object.modifier_add", "type",
78                                       icon='MODIFIER')
79
80             # Align block
81             layout.menu("VIEW3D_MT_AlignMenu", icon='ALIGN')
82
83             # Select block
84             layout.menu("VIEW3D_MT_SelectMenu", icon='RESTRICT_SELECT_OFF')
85
86             # Toolshelf block
87             layout.operator("view3d.toolshelf", text= 'hide toolshelf', icon='MENU_PANEL')
88
89             # Properties block
90             layout.operator("view3d.properties", icon='MENU_PANEL')
91
92             #TODO: Add if statement to test whether editmode switch needs to
93             #be added to the menu, since certain object can't enter edit mode
94             #In which case we don't need the toggle
95             # Toggle Editmode
96             layout.operator("object.editmode_toggle", text="Enter Edit Mode",
97                             icon='EDITMODE_HLT')
98
99             # Delete block
100             layout.operator("object.delete", text="Delete Object",
101                             icon='CANCEL')
102
103
104         elif ob.mode == 'EDIT_MESH':
105             # Edit mode
106
107             # Search Menu
108             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
109             layout.separator()
110
111             # Add block
112             layout.menu("INFO_MT_mesh_add", text="Add Mesh",
113                         icon='OUTLINER_OB_MESH')
114
115             # Transform block
116             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
117
118             # Mirror block
119             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
120
121             # Cursor block
122             layout.menu("VIEW3D_MT_EditCursorMenu", icon='CURSOR')
123
124             # Proportional block
125             layout.prop_menu_enum(settings, "proportional_edit",
126                                   icon="PROP_CON")
127             layout.prop_menu_enum(settings, "proportional_edit_falloff",
128                                   icon="SMOOTHCURVE")
129
130             # Edit block
131             layout.menu("VIEW3D_MT_edit_TK", icon='EDITMODE_HLT')
132
133             # Multi Select
134             layout.menu("VIEW3D_MT_edit_multi", icon='VERTEXSEL')
135
136             # Extrude block
137             layout.menu("VIEW3D_MT_edit_mesh_extrude", icon='EDIT_VEC')
138
139             # Tools block
140             layout.menu("VIEW3D_MT_edit_mesh_specials", icon='MODIFIER')
141
142                         # UV Map block
143             layout.menu("VIEW3D_MT_uv_map", icon='MOD_UVPROJECT')
144
145             # Select block
146             layout.menu("VIEW3D_MT_SelectEditMenu",
147                         icon='RESTRICT_SELECT_OFF')
148
149             # Toolshelf block
150             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
151
152             # Properties block
153             layout.operator("view3d.properties", icon='MENU_PANEL')
154
155             # Toggle Object Mode
156             layout.operator("object.editmode_toggle",
157                             text="Enter Object Mode", icon='OBJECT_DATAMODE')
158
159             # Delete Block
160             layout.operator("mesh.delete", icon='CANCEL')
161
162         if ob.mode == 'EDIT_CURVE':
163             # Curve menu
164
165             # Search Menu
166             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
167             layout.separator()
168
169             # Add block
170             layout.menu("INFO_MT_curve_add", text="Add Curve",
171                         icon='OUTLINER_OB_CURVE')
172
173             # Transform block
174             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
175
176             # Mirror block
177             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
178
179             # Cursor block
180             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
181
182             # Proportional block
183             layout.prop_menu_enum(settings, "proportional_edit",
184                                   icon="PROP_CON")
185             layout.prop_menu_enum(settings, "proportional_edit_falloff",
186                                   icon="SMOOTHCURVE")
187
188             # Edit Control Points
189             layout.menu("VIEW3D_MT_EditCurveCtrlpoints",
190                         icon='CURVE_BEZCURVE')
191
192             # Edit Curve Specials
193             layout.menu("VIEW3D_MT_EditCurveSpecials",
194                         icon='MODIFIER')
195
196             # Select Curve Block
197             #Could use: VIEW3D_MT_select_edit_curve
198             #Which is the default, instead of a hand written one, left it alone
199             #for now though.
200             layout.menu("VIEW3D_MT_SelectCurveMenu",
201                         icon='RESTRICT_SELECT_OFF')
202
203             # Toolshelf block
204             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
205
206             # Properties block
207             layout.operator("view3d.properties", icon='MENU_PANEL')
208
209             # Toggle Objectmode
210             layout.operator("object.editmode_toggle", text="Enter Object Mode",
211                             icon='OBJECT_DATA')
212
213             # Delete block
214             layout.operator("curve.delete", text="Delete Object",
215                             icon='CANCEL')
216
217         if ob.mode == 'EDIT_SURFACE':
218             # Surface menu
219
220             # Search Menu
221             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
222             layout.separator()
223
224             # Add block
225             layout.menu("INFO_MT_surface_add", text="Add Surface",
226                         icon='OUTLINER_OB_SURFACE')
227
228             # Transform block
229             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
230
231             # Mirror block
232             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
233
234             # Cursor block
235             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
236
237             # Proportional block
238             layout.prop_menu_enum(settings, "proportional_edit",
239                                   icon="PROP_CON")
240             layout.prop_menu_enum(settings, "proportional_edit_falloff",
241                                   icon="SMOOTHCURVE")
242
243             # Edit Curve Specials
244             layout.menu("VIEW3D_MT_EditCurveSpecials",
245                         icon='MODIFIER')
246
247             # Select Surface
248             layout.menu("VIEW3D_MT_SelectSurface", icon='RESTRICT_SELECT_OFF')
249
250             # Toolshelf block
251             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
252
253
254             # Properties block
255             layout.operator("view3d.properties", icon='MENU_PANEL')
256
257             # Toggle Objectmode
258             layout.operator("object.editmode_toggle", text="Enter Object Mode",
259                             icon='OBJECT_DATA')
260
261             # Delete block
262             layout.operator("curve.delete", text="Delete Object",
263                             icon='CANCEL')
264
265         if ob.mode == 'EDIT_METABALL':
266             # Metaball menu
267
268             #Search Menu
269             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
270             layout.separator()
271
272             # Add block
273             #layout.menu("INFO_MT_metaball_add", text="Add Metaball",
274             #            icon='OUTLINER_OB_META')
275             layout.operator_menu_enum("object.metaball_add", "type",
276                                       text="Add Metaball",
277                                       icon='OUTLINER_OB_META')
278
279             # Transform block
280             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
281
282             # Mirror block
283             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
284
285             # Cursor block
286             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
287
288             # Proportional block
289             layout.prop_menu_enum(settings, "proportional_edit",
290                                   icon="PROP_CON")
291             layout.prop_menu_enum(settings, "proportional_edit_falloff",
292                                   icon="SMOOTHCURVE")
293
294             #Select Metaball
295             layout.menu("VIEW3D_MT_SelectMetaball", icon='RESTRICT_SELECT_OFF')
296
297             # Toolshelf block
298             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
299
300             # Properties block
301             layout.operator("view3d.properties", icon='MENU_PANEL')
302
303             # Toggle Objectmode
304             layout.operator("object.editmode_toggle", text="Enter Object Mode",
305                             icon='OBJECT_DATA')
306
307             # Delete block
308             layout.operator("mball.delete_metaelems", text="Delete Object",
309                             icon='CANCEL')
310
311         elif ob.mode == 'EDIT_LATTICE':
312             # Lattice menu
313
314             #Search Menu
315             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
316             layout.separator()
317
318             # Transform block
319             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
320
321             # Mirror block
322             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
323
324             # Cursor block
325             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
326
327             # Proportional block
328             layout.prop_menu_enum(settings, "proportional_edit",
329                                   icon= "PROP_CON")
330             layout.prop_menu_enum(settings, "proportional_edit_falloff",
331                                   icon= "SMOOTHCURVE")
332             layout.operator("lattice.make_regular")
333
334             #Select Lattice
335             layout.menu("VIEW3D_MT_select_edit_lattice",
336                         icon='RESTRICT_SELECT_OFF')
337
338             # Toolshelf block
339             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
340
341             # Properties block
342             layout.operator("view3d.properties", icon='MENU_PANEL')
343
344             # Toggle Objectmode
345             layout.operator("object.editmode_toggle", text="Enter Object Mode",
346                             icon='OBJECT_DATA')
347
348             # Delete block - Can't delete any lattice stuff so not needed
349             #layout.operator("object.delete", text="Delete Object",
350             #                icon='CANCEL')
351
352         if  context.mode == 'PARTICLE':
353             # Particle menu
354
355             #Search Menu
356             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
357             layout.separator()
358
359             # Transform block
360             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
361
362             # Mirror block
363             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
364
365             # Cursor block
366             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
367
368             # Proportional block
369             layout.prop_menu_enum(settings, "proportional_edit",
370                                   icon= "PROP_CON")
371             layout.prop_menu_enum(settings, "proportional_edit_falloff",
372                                   icon= "SMOOTHCURVE")
373
374             # Particle block
375             layout.menu("VIEW3D_MT_particle", icon='PARTICLEMODE')
376
377             #Select Particle
378             layout.menu("VIEW3D_MT_select_particle",
379                         icon='RESTRICT_SELECT_OFF')
380
381             # History/Cursor Block
382             layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT')
383
384             # Toolshelf block
385             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
386
387             # Properties block
388             layout.operator("view3d.properties", icon='MENU_PANEL')
389
390             # Toggle Objectmode
391             layout.operator("object.mode_set", text="Enter Object Mode",
392                             icon='OBJECT_DATA')
393
394             # Delete block
395             layout.operator("object.delete", text="Delete Object",
396                             icon='CANCEL')
397
398         ob = context
399         if ob.mode == 'PAINT_WEIGHT':
400             # Weight paint menu
401
402             # Search Menu
403             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
404             layout.separator()
405
406             # Transform block
407             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
408
409             # Cursor block
410             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
411
412             # Weight Paint block
413             layout.menu("VIEW3D_MT_paint_weight", icon='WPAINT_HLT')
414
415             # History/Cursor Block
416             layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT')
417
418             # Toolshelf block
419             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
420
421             # Properties block
422             layout.operator("view3d.properties", icon='MENU_PANEL')
423
424             # Toggle Objectmode
425             layout.operator("object.mode_set", text="Enter Object Mode",
426                             icon='OBJECT_DATA')
427
428         elif ob.mode == 'PAINT_VERTEX':
429             # Vertex paint menu
430
431             # Search Menu
432             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
433             layout.separator()
434
435             # Transform block
436             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
437
438             # Cursor block
439             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
440
441             # Vertex Paint block
442             layout.operator("paint.vertex_color_set", icon='VPAINT_HLT')
443
444             # History/Cursor Block
445             layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT')
446
447             # Toolshelf block
448             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
449
450             # Properties block
451             layout.operator("view3d.properties", icon='MENU_PANEL')
452
453             # Toggle Objectmode
454             layout.operator("object.mode_set", text="Enter Object Mode",
455                             icon='OBJECT_DATA')
456
457         elif ob.mode == 'PAINT_TEXTURE':
458             # Texture paint menu
459
460             # Search Menu
461             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
462             layout.separator()
463
464             # Transform block
465             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
466
467             # Cursor block
468             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
469
470             # History/Cursor Block
471             layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT')
472
473             # Toolshelf block
474             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
475
476             # Properties block
477             layout.operator("view3d.properties", icon='MENU_PANEL')
478
479             # Toggle Objectmode
480             layout.operator("object.mode_set", text="Enter Object Mode",
481                             icon='OBJECT_DATA')
482
483         elif ob.mode == 'SCULPT':
484             # Sculpt menu
485
486             # Search Menu
487             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
488             layout.separator()
489
490             # Transform block
491             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
492
493             # Mirror block
494             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
495
496             # Cursor block
497             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
498
499             # Sculpt block
500             layout.menu("VIEW3D_MT_sculpt", icon='SCULPTMODE_HLT')
501
502             # History/Cursor Block
503             layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT')
504
505             # Toolshelf block
506             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
507
508             # Properties block
509             layout.operator("view3d.properties", icon='MENU_PANEL')
510
511             # Toggle Objectmode
512             layout.operator("object.mode_set", text="Enter Object Mode",
513                             icon='OBJECT_DATA')
514
515         elif ob.mode == 'EDIT_ARMATURE':
516             # Armature Edit menu
517
518             # Search Menu
519             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
520             layout.separator()
521
522             # Transform block
523             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
524
525             # Mirror block
526             layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR')
527
528             # Cursor block
529             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
530
531             # Proportional block
532             layout.prop_menu_enum(settings, "proportional_edit",
533                                   icon="PROP_CON")
534             layout.prop_menu_enum(settings, "proportional_edit_falloff",
535                                   icon="SMOOTHCURVE")
536             layout.separator()
537
538             # Edit Armature roll
539             layout.menu("VIEW3D_MT_edit_armature_roll",
540                         icon='BONE_DATA')
541
542             # Edit Armature Toolkit
543             layout.menu("VIEW3D_MT_EditArmatureTK",
544                         icon='ARMATURE_DATA')
545
546             # Edit Armature Name
547             layout.menu("VIEW3D_MT_ArmatureName",
548                         icon='NEW')
549
550             # Parent block
551             layout.menu("VIEW3D_MT_ParentMenu", icon='ROTACTIVE')
552
553             # bone options block
554             layout.menu("VIEW3D_MT_bone_options_toggle",
555                         text="Bone Settings")
556
557             # Edit Armature Specials
558             layout.menu("VIEW3D_MT_armature_specials", icon='MODIFIER')
559
560             # Edit Armature Select
561             layout.menu("VIEW3D_MT_SelectArmatureMenu",
562                         icon='RESTRICT_SELECT_OFF')
563
564             # Toolshelf block
565             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
566
567             # Properties block
568             layout.operator("view3d.properties", icon='MENU_PANEL')
569
570             # Toggle Posemode
571             layout.operator("object.posemode_toggle", text="Enter Pose Mode",
572                             icon='POSE_HLT')
573
574             # Toggle Posemode
575             layout.operator("object.editmode_toggle", text="Enter Object Mode",
576                             icon='OBJECT_DATA')
577
578             # Delete block
579             layout.operator("armature.delete", text="Delete Object",
580                             icon='CANCEL')
581
582         if context.mode == 'POSE':
583             # Pose mode menu
584             arm = context.active_object.data
585
586             # Search Menu
587             layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
588             layout.separator()
589
590             # Transform Menu
591             layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL')
592
593             # Clear Transform
594             layout.menu("VIEW3D_MT_pose_transform")
595
596             # Cursor Menu
597             layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR')
598
599             # Pose Copy Block
600             layout.menu("VIEW3D_MT_PoseCopy", icon='FILE')
601
602             if arm.draw_type in {'BBONE', 'ENVELOPE'}:
603                 layout.operator("transform.transform",
604                                 text="Scale Envelope Distance").mode = 'BONE_SIZE'
605
606             layout.menu("VIEW3D_MT_pose_apply")
607             layout.operator("pose.relax")
608             layout.menu("VIEW3D_MT_KeyframeMenu")
609             layout.menu("VIEW3D_MT_pose_pose")
610             layout.menu("VIEW3D_MT_pose_motion")
611             layout.menu("VIEW3D_MT_pose_group")
612             layout.menu("VIEW3D_MT_pose_ik")
613             layout.menu("VIEW3D_MT_PoseNames")
614             layout.menu("VIEW3D_MT_pose_constraints")
615             layout.operator("pose.quaternions_flip")
616
617             layout.operator_context = 'INVOKE_AREA'
618             layout.operator("armature.armature_layers",
619                             text="Change Armature Layers...")
620             layout.operator("pose.bone_layers", text="Change Bone Layers...")
621
622             layout.menu("VIEW3D_MT_pose_showhide")
623             layout.menu("VIEW3D_MT_bone_options_toggle",
624                         text="Bone Settings")
625
626             # Select Pose Block
627             layout.menu("VIEW3D_MT_SelectPoseMenu", icon='RESTRICT_SELECT_OFF')
628
629             # Toolshelf block
630             layout.operator("view3d.toolshelf", icon='MENU_PANEL')
631
632             # Properties block
633             layout.operator("view3d.properties", icon='MENU_PANEL')
634
635             # Toggle Editmode
636             layout.operator("object.editmode_toggle", text="Enter Edit Mode",
637                             icon='EDITMODE_HLT')
638
639             layout.operator("object.mode_set", text="Enter Object Mode",
640                             icon='OBJECT_DATA').mode='OBJECT'
641
642 class VIEW3D_MT_AddMenu(bpy.types.Menu):
643     bl_label = "Add Object Menu"
644
645     def draw(self, context):
646         layout = self.layout
647         layout.operator_context = 'INVOKE_REGION_WIN'
648
649         layout.menu("INFO_MT_mesh_add", text="Add Mesh",
650                     icon='OUTLINER_OB_MESH')
651         layout.menu("INFO_MT_curve_add", text="Add Curve",
652                     icon='OUTLINER_OB_CURVE')
653         layout.menu("INFO_MT_surface_add", text="Add Surface",
654                     icon='OUTLINER_OB_SURFACE')
655         layout.operator_menu_enum("object.metaball_add", "type",
656                                   icon='OUTLINER_OB_META')
657         layout.operator("object.text_add", text="Add Text",
658                         icon='OUTLINER_OB_FONT')
659         layout.separator()
660         layout.menu("INFO_MT_armature_add", text="Add Armature",
661                     icon='OUTLINER_OB_ARMATURE')
662         layout.operator("object.add", text="Lattice",
663                         icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
664         layout.separator()
665         layout.operator("object.add", text="Add Empty",
666                         icon='OUTLINER_OB_EMPTY')
667         layout.separator()
668         layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
669         layout.separator()
670         layout.operator("object.camera_add", text="Camera",
671                         icon='OUTLINER_OB_CAMERA')
672         layout.operator_menu_enum("object.lamp_add", "type",
673                                   icon="OUTLINER_OB_LAMP")
674         layout.separator()
675
676         layout.operator_menu_enum("object.effector_add", "type",
677                                   text="Force Field",
678                                   icon='OUTLINER_OB_EMPTY')
679         layout.operator_menu_enum("object.group_instance_add", "group",
680                                   text="Group Instance",
681                                   icon='OUTLINER_OB_EMPTY')
682
683
684 class VIEW3D_MT_TransformMenu(bpy.types.Menu):
685     bl_label = "Transform Menu"
686
687     # TODO: get rid of the custom text strings?
688     def draw(self, context):
689         layout = self.layout
690
691         layout.operator("transform.translate", text="Grab/Move")
692         # TODO: sub-menu for grab per axis
693         layout.operator("transform.rotate", text="Rotate")
694         # TODO: sub-menu for rot per axis
695         layout.operator("transform.resize", text="Scale")
696         # TODO: sub-menu for scale per axis
697         layout.separator()
698
699         layout.operator("transform.tosphere", text="To Sphere")
700         layout.operator("transform.shear", text="Shear")
701         layout.operator("transform.bend", text="Bend")
702         layout.operator("transform.push_pull", text="Push/Pull")
703         if context.edit_object and context.edit_object.type == 'ARMATURE':
704             layout.operator("armature.align")
705         else:
706             layout.operator_context = 'EXEC_REGION_WIN'
707             # @todo vvv See alignmenu() in edit.c of b2.4x to get this working.
708             layout.operator("transform.transform",
709                             text="Align to Transform Orientation").mode = 'ALIGN'
710         layout.separator()
711
712         layout.operator_context = 'EXEC_AREA'
713
714         layout.operator("object.origin_set",
715                         text="Geometry to Origin").type = 'GEOMETRY_ORIGIN'
716         layout.operator("object.origin_set",
717                         text="Origin to Geometry").type = 'ORIGIN_GEOMETRY'
718         layout.operator("object.origin_set",
719                         text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR'
720
721
722 class VIEW3D_MT_MirrorMenu(bpy.types.Menu):
723     bl_label = "Mirror Menu"
724
725     def draw(self, context):
726         layout = self.layout
727
728         layout.operator("transform.mirror", text="Interactive Mirror")
729         layout.separator()
730
731         layout.operator_context = 'INVOKE_REGION_WIN'
732
733         props = layout.operator("transform.mirror", text="X Global")
734         props.constraint_axis = (True, False, False)
735         props.constraint_orientation = 'GLOBAL'
736
737         props = layout.operator("transform.mirror", text="Y Global")
738         props.constraint_axis = (False, True, False)
739         props.constraint_orientation = 'GLOBAL'
740
741         props = layout.operator("transform.mirror", text="Z Global")
742         props.constraint_axis = (False, False, True)
743         props.constraint_orientation = 'GLOBAL'
744
745         if context.edit_object:
746
747             layout.separator()
748
749             props = layout.operator("transform.mirror", text="X Local")
750             props.constraint_axis = (True, False, False)
751             props.constraint_orientation = 'LOCAL'
752             props = layout.operator("transform.mirror", text="Y Local")
753             props.constraint_axis = (False, True, False)
754             props.constraint_orientation = 'LOCAL'
755             props = layout.operator("transform.mirror", text="Z Local")
756             props.constraint_axis = (False, False, True)
757             props.constraint_orientation = 'LOCAL'
758
759             layout.operator("object.vertex_group_mirror")
760
761 class VIEW3D_MT_ParentMenu(bpy.types.Menu):
762     bl_label = "Parent Menu"
763
764     def draw(self, context):
765         layout = self.layout
766
767         layout.operator("object.parent_set", text="Set")
768         layout.operator("object.parent_clear", text="Clear")
769
770 class VIEW3D_MT_GroupMenu(bpy.types.Menu):
771     bl_label = "Group Menu"
772
773     def draw(self, context):
774         layout = self.layout
775
776         layout.operator("group.create")
777         layout.operator("group.objects_remove")
778         layout.separator()
779
780         layout.operator("group.objects_add_active")
781         layout.operator("group.objects_remove_active")
782
783 class VIEW3D_MT_AlignMenu(bpy.types.Menu):
784     bl_label = "Align Menu"
785
786     def draw(self, context):
787         layout = self.layout
788
789         layout.menu("VIEW3D_MT_view_align_selected")
790         layout.separator()
791
792         layout.operator("view3d.view_all",
793                         text="Center Cursor and View All").center = True
794         layout.operator("view3d.camera_to_view",
795                         text="Align Active Camera to View")
796         layout.operator("view3d.view_selected")
797         layout.operator("view3d.view_center_cursor")
798
799 class VIEW3D_MT_SelectMenu(bpy.types.Menu):
800     bl_label = "Select Menu"
801
802     def draw(self, context):
803         layout = self.layout
804         layout.operator_context = 'INVOKE_REGION_WIN'
805
806         layout.operator("view3d.select_border")
807         layout.operator("view3d.select_circle")
808         layout.separator()
809
810         layout.operator("object.select_all").action = 'TOGGLE'
811         layout.operator("object.select_all", text="Inverse").action = 'INVERT'
812         layout.operator("object.select_random", text="Random")
813         layout.operator("object.select_mirror", text="Mirror")
814         layout.operator("object.select_by_layer", text="Select All by Layer")
815         layout.operator_menu_enum("object.select_by_type", "type",
816                                   text="Select All by Type...")
817         layout.operator("object.select_camera", text="Select Camera")
818         layout.separator()
819
820         layout.operator_menu_enum("object.select_grouped", "type",
821                                   text="Grouped")
822         layout.operator_menu_enum("object.select_linked", "type",
823                                   text="Linked")
824         layout.operator("object.select_pattern", text="Select Pattern...")
825
826 class VIEW3D_MT_SelectEditMenu(bpy.types.Menu):
827     bl_label = "Select Menu"
828
829     def draw(self, context):
830         layout = self.layout
831
832         layout.operator("view3d.select_border")
833         layout.operator("view3d.select_circle")
834         layout.separator()
835
836         layout.operator("mesh.select_all").action = 'TOGGLE'
837         layout.operator("mesh.select_all", text="Inverse").action = 'INVERT'
838         layout.separator()
839
840         layout.operator("mesh.select_random", text="Random")
841         layout.operator("mesh.select_nth", text="Every N Number of Verts")
842         layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
843         layout.operator("mesh.faces_select_linked_flat",
844                         text="Linked Flat Faces")
845         layout.operator("mesh.select_interior_faces", text="Interior Faces")
846         layout.operator("mesh.select_axis", text="Side of Active")
847         layout.separator()
848
849         layout.operator("mesh.select_face_by_sides", text="By Number of Verts")
850         if context.scene.tool_settings.mesh_select_mode[2] == False:
851             layout.operator("mesh.select_non_manifold", text="Non Manifold")
852         layout.operator("mesh.select_loose", text="Loose Geometry")
853         layout.operator("mesh.select_similar", text="Similar")
854
855         layout.separator()
856
857         layout.operator("mesh.select_less", text="Less")
858         layout.operator("mesh.select_more", text="More")
859         layout.separator()
860
861         layout.operator("mesh.select_mirror", text="Mirror")
862
863         layout.operator("mesh.select_linked", text="Linked")
864         layout.operator("mesh.shortest_path_select", text="Shortest Path")
865         layout.operator("mesh.loop_multi_select", text="Edge Loop")
866         layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True
867         layout.separator()
868
869         layout.operator("mesh.loop_to_region")
870         layout.operator("mesh.region_to_loop")
871
872 class VIEW3D_MT_SelectCurveMenu(bpy.types.Menu):
873     bl_label = "Select Menu"
874
875     def draw(self, context):
876         layout = self.layout
877
878         layout.operator("view3d.select_border")
879         layout.operator("view3d.select_circle")
880         layout.separator()
881
882         layout.operator("curve.select_all").action = 'TOGGLE'
883         layout.operator("curve.select_all").action = 'INVERT'
884         layout.operator("curve.select_random")
885         layout.operator("curve.select_nth")
886         layout.separator()
887
888         layout.operator("curve.de_select_first")
889         layout.operator("curve.de_select_last")
890         layout.operator("curve.select_next")
891         layout.operator("curve.select_previous")
892         layout.separator()
893
894         layout.operator("curve.select_more")
895         layout.operator("curve.select_less")
896
897 class VIEW3D_MT_SelectArmatureMenu(bpy.types.Menu):
898     bl_label = "Select Menu"
899
900     def draw(self, context):
901         layout = self.layout
902
903         layout.operator("view3d.select_border")
904         layout.separator()
905
906         layout.operator("armature.select_all")
907         layout.operator("armature.select_inverse", text="Inverse")
908         layout.separator()
909
910         layout.operator("armature.select_hierarchy",
911                         text="Parent").direction = 'PARENT'
912         layout.operator("armature.select_hierarchy",
913                         text="Child").direction = 'CHILD'
914         layout.separator()
915
916         props = layout.operator("armature.select_hierarchy",
917                                 text="Extend Parent")
918         props.extend = True
919         props.direction = 'PARENT'
920
921         props = layout.operator("armature.select_hierarchy",
922                                 text="Extend Child")
923         props.extend = True
924         props.direction = 'CHILD'
925
926         layout.operator("object.select_pattern", text="Select Pattern...")
927
928
929 class VIEW3D_MT_SelectPoseMenu(bpy.types.Menu):
930     bl_label = "Select Menu"
931
932     def draw(self, context):
933         layout = self.layout
934
935         layout.operator("view3d.select_border")
936         layout.separator()
937
938         layout.operator("pose.select_all").action = 'TOGGLE'
939         layout.operator("pose.select_all", text="Inverse").action = 'INVERT'
940         layout.operator("pose.select_constraint_target",
941                         text="Constraint Target")
942         layout.operator("pose.select_linked", text="Linked")
943         layout.separator()
944
945         layout.operator("pose.select_hierarchy",
946                         text="Parent").direction = 'PARENT'
947         layout.operator("pose.select_hierarchy",
948                         text="Child").direction = 'CHILD'
949         layout.separator()
950
951         props = layout.operator("pose.select_hierarchy", text="Extend Parent")
952         props.extend = True
953         props.direction = 'PARENT'
954
955         props = layout.operator("pose.select_hierarchy", text="Extend Child")
956         props.extend = True
957         props.direction = 'CHILD'
958         layout.separator()
959
960         layout.operator_menu_enum("pose.select_grouped", "type",
961                                   text="Grouped")
962         layout.operator("object.select_pattern", text="Select Pattern...")
963
964 class VIEW3D_MT_PoseCopy(bpy.types.Menu):
965     bl_label = "Pose Copy"
966
967     def draw(self, context):
968         layout = self.layout
969
970         layout.operator("pose.copy")
971         layout.operator("pose.paste")
972         layout.operator("pose.paste",
973                         text="Paste X-Flipped Pose").flipped = True
974         layout.separator()
975
976 class VIEW3D_MT_PoseNames(bpy.types.Menu):
977     bl_label = "Pose Copy"
978
979     def draw(self, context):
980         layout = self.layout
981
982         layout.operator_context = 'EXEC_AREA'
983         layout.operator("pose.autoside_names",
984                         text="AutoName Left/Right").axis = 'XAXIS'
985         layout.operator("pose.autoside_names",
986                         text="AutoName Front/Back").axis = 'YAXIS'
987         layout.operator("pose.autoside_names",
988                         text="AutoName Top/Bottom").axis = 'ZAXIS'
989
990         layout.operator("pose.flip_names")
991
992
993 class VIEW3D_MT_SelectSurface(bpy.types.Menu):
994     bl_label = "Select Menu"
995
996     def draw(self, context):
997         layout = self.layout
998
999         layout.operator("view3d.select_border")
1000         layout.operator("view3d.select_circle")
1001
1002         layout.separator()
1003
1004         layout.operator("curve.select_all").action = 'TOGGLE'
1005         layout.operator("curve.select_all").action = 'INVERT'
1006         layout.operator("curve.select_random")
1007         layout.operator("curve.select_nth")
1008
1009         layout.separator()
1010
1011         layout.operator("curve.select_row")
1012
1013         layout.separator()
1014
1015         layout.operator("curve.select_more")
1016         layout.operator("curve.select_less")
1017
1018 class VIEW3D_MT_SelectMetaball(bpy.types.Menu):
1019     bl_label = "Select Menu"
1020
1021     def draw(self, context):
1022         layout = self.layout
1023
1024         layout.operator("view3d.select_border")
1025
1026         layout.separator()
1027
1028         layout.operator("mball.select_all").action = 'TOGGLE'
1029         layout.operator("mball.select_all").action = 'INVERT'
1030         layout.operator("mball.select_random_metaelems")
1031
1032 class VIEW3D_MT_edit_TK(bpy.types.Menu):
1033     bl_label = "Edit Mesh Tools"
1034
1035     def draw(self, context):
1036         layout = self.layout
1037         layout.row()  # XXX, is this needed?
1038
1039         layout.operator_context = 'INVOKE_REGION_WIN'
1040
1041         layout.menu("VIEW3D_MT_edit_mesh_vertices", icon='VERTEXSEL')
1042         layout.menu("VIEW3D_MT_edit_mesh_edges", icon='EDGESEL')
1043         layout.menu("VIEW3D_MT_edit_mesh_faces", icon='FACESEL')
1044         layout.separator()
1045         layout.menu("VIEW3D_MT_edit_mesh_normals", icon='META_DATA')
1046         layout.operator("mesh.loopcut_slide",
1047                         text="Loopcut", icon='EDIT_VEC')
1048
1049
1050
1051 class VIEW3D_MT_edit_multi(bpy.types.Menu):
1052     bl_label = "Multi Select"
1053
1054     def draw(self, context):
1055         layout = self.layout
1056         layout.operator_context = 'INVOKE_REGION_WIN'
1057
1058         layout.separator()
1059         prop = layout.operator("wm.context_set_value", text="Vertex Select",
1060                                icon='VERTEXSEL')
1061         prop.value = "(True, False, False)"
1062         prop.data_path = "tool_settings.mesh_select_mode"
1063
1064         prop = layout.operator("wm.context_set_value", text="Edge Select",
1065                                icon='EDGESEL')
1066         prop.value = "(False, True, False)"
1067         prop.data_path = "tool_settings.mesh_select_mode"
1068
1069         prop = layout.operator("wm.context_set_value", text="Face Select",
1070                                icon='FACESEL')
1071         prop.value = "(False, False, True)"
1072         prop.data_path = "tool_settings.mesh_select_mode"
1073         layout.separator()
1074
1075         prop = layout.operator("wm.context_set_value",
1076                                text="Vertex & Edge Select",
1077                                icon='EDITMODE_HLT')
1078         prop.value = "(True, True, False)"
1079         prop.data_path = "tool_settings.mesh_select_mode"
1080
1081         prop = layout.operator("wm.context_set_value",
1082                                text="Vertex & Face Select",
1083                                icon='ORTHO')
1084         prop.value = "(True, False, True)"
1085         prop.data_path = "tool_settings.mesh_select_mode"
1086
1087         prop = layout.operator("wm.context_set_value",
1088                                text="Edge & Face Select",
1089                                icon='SNAP_FACE')
1090         prop.value = "(False, True, True)"
1091         prop.data_path = "tool_settings.mesh_select_mode"
1092         layout.separator()
1093
1094         prop = layout.operator("wm.context_set_value",
1095                                text="Vertex & Edge & Face Select",
1096                                icon='SNAP_VOLUME')
1097         prop.value = "(True, True, True)"
1098         prop.data_path = "tool_settings.mesh_select_mode"
1099
1100 class VIEW3D_MT_editM_Edge(bpy.types.Menu):
1101     bl_label = "Edges"
1102
1103     def draw(self, context):
1104         layout = self.layout
1105         layout.operator_context = 'INVOKE_REGION_WIN'
1106
1107         layout.operator("mesh.mark_seam")
1108         layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
1109         layout.separator()
1110
1111         layout.operator("mesh.mark_sharp")
1112         layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
1113         layout.operator("mesh.extrude_move_along_normals", text="Extrude")
1114         layout.separator()
1115
1116         layout.operator("mesh.edge_rotate",
1117                         text="Rotate Edge CW").direction = 'CW'
1118         layout.operator("mesh.edge_rotate",
1119                         text="Rotate Edge CCW").direction = 'CCW'
1120         layout.separator()
1121
1122         layout.operator("TFM_OT_edge_slide", text="Edge Slide")
1123         layout.operator("mesh.loop_multi_select", text="Edge Loop")
1124         layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True
1125         layout.operator("mesh.loop_to_region")
1126         layout.operator("mesh.region_to_loop")
1127
1128
1129 class VIEW3D_MT_EditCurveCtrlpoints(bpy.types.Menu):
1130     bl_label = "Control Points"
1131
1132     def draw(self, context):
1133         layout = self.layout
1134
1135         edit_object = context.edit_object
1136
1137         if edit_object.type == 'CURVE':
1138             layout.operator("transform.transform").mode = 'TILT'
1139             layout.operator("curve.tilt_clear")
1140             layout.operator("curve.separate")
1141
1142             layout.separator()
1143
1144             layout.operator_menu_enum("curve.handle_type_set", "type")
1145
1146             layout.separator()
1147
1148             layout.menu("VIEW3D_MT_hook")
1149
1150
1151 class VIEW3D_MT_EditCurveSegments(bpy.types.Menu):
1152     bl_label = "Curve Segments"
1153
1154     def draw(self, context):
1155         layout = self.layout
1156
1157         layout.operator("curve.subdivide")
1158         layout.operator("curve.switch_direction")
1159
1160 class VIEW3D_MT_EditCurveSpecials(bpy.types.Menu):
1161     bl_label = "Specials"
1162
1163     def draw(self, context):
1164         layout = self.layout
1165
1166         layout.operator("curve.subdivide")
1167         layout.operator("curve.switch_direction")
1168         layout.operator("curve.spline_weight_set")
1169         layout.operator("curve.radius_set")
1170         layout.operator("curve.smooth")
1171         layout.operator("curve.smooth_weight")
1172         layout.operator("curve.smooth_radius")
1173         layout.operator("curve.smooth_tilt")
1174
1175 class VIEW3D_MT_EditArmatureTK(bpy.types.Menu):
1176     bl_label = "Armature Tools"
1177
1178     def draw(self, context):
1179         layout = self.layout
1180
1181         # Edit Armature
1182
1183         layout.operator("transform.transform",
1184                         text="Scale Envelope Distance").mode = 'BONE_SIZE'
1185
1186         layout.operator("transform.transform",
1187                         text="Scale B-Bone Width").mode = 'BONE_SIZE'
1188         layout.separator()
1189
1190         layout.operator("armature.extrude_move")
1191
1192         layout.operator("armature.extrude_forked")
1193
1194         layout.operator("armature.duplicate_move")
1195         layout.operator("armature.merge")
1196         layout.operator("armature.fill")
1197         layout.operator("armature.delete")
1198         layout.operator("armature.separate")
1199
1200         layout.separator()
1201
1202         layout.operator("armature.subdivide", text="Subdivide")
1203         layout.operator("armature.switch_direction", text="Switch Direction")
1204
1205 class VIEW3D_MT_ArmatureName(bpy.types.Menu):
1206     bl_label = "Armature Name"
1207
1208     def draw(self, context):
1209         layout = self.layout
1210
1211         layout.operator_context = 'EXEC_AREA'
1212         layout.operator("armature.autoside_names",
1213                         text="AutoName Left/Right").type = 'XAXIS'
1214         layout.operator("armature.autoside_names",
1215                         text="AutoName Front/Back").type = 'YAXIS'
1216         layout.operator("armature.autoside_names",
1217                         text="AutoName Top/Bottom").type = 'ZAXIS'
1218         layout.operator("armature.flip_names")
1219         layout.separator()
1220
1221 class VIEW3D_MT_KeyframeMenu(bpy.types.Menu):
1222     bl_label = "Keyframe Menu"
1223
1224     def draw(self, context):
1225         layout = self.layout
1226
1227         # Keyframe Bleck
1228         layout.operator("anim.keyframe_insert_menu",
1229                         text="Insert Keyframe...")
1230         layout.operator("anim.keyframe_delete_v3d",
1231                         text="Delete Keyframe...")
1232         layout.operator("anim.keying_set_active_set",
1233                         text="Change Keying Set...")
1234         layout.separator()
1235
1236 # Classes for VIEW3D_MT_CursorMenu()
1237 class VIEW3D_OT_pivot_cursor(bpy.types.Operator):
1238     "Cursor as Pivot Point"
1239     bl_idname = "view3d.pivot_cursor"
1240     bl_label = "Cursor as Pivot Point"
1241
1242     @classmethod
1243     def poll(cls, context):
1244         return bpy.context.space_data.pivot_point != 'CURSOR'
1245
1246     def execute(self, context):
1247         bpy.context.space_data.pivot_point = 'CURSOR'
1248         return {'FINISHED'}
1249
1250 class VIEW3D_OT_revert_pivot(bpy.types.Operator):
1251     "Revert Pivot Point"
1252     bl_idname = "view3d.revert_pivot"
1253     bl_label = "Reverts Pivot Point to median"
1254
1255     @classmethod
1256     def poll(cls, context):
1257         return bpy.context.space_data.pivot_point != 'MEDIAN_POINT'
1258
1259     def execute(self, context):
1260         bpy.context.space_data.pivot_point = 'MEDIAN_POINT'
1261         # @todo Change this to 'BOUDNING_BOX_CENTER' if needed...
1262         return{'FINISHED'}
1263
1264 class VIEW3D_MT_CursorMenu(bpy.types.Menu):
1265     bl_label = "Snap Cursor Menu"
1266
1267     def draw(self, context):
1268
1269         layout = self.layout
1270         layout.operator_context = 'INVOKE_REGION_WIN'
1271         layout.operator("view3d.snap_cursor_to_selected",
1272                         text="Cursor to Selected")
1273         layout.operator("view3d.snap_cursor_to_center",
1274                         text="Cursor to Center")
1275         layout.operator("view3d.snap_cursor_to_grid",
1276                         text="Cursor to Grid")
1277         layout.operator("view3d.snap_cursor_to_active",
1278                         text="Cursor to Active")
1279         layout.separator()
1280         layout.operator("view3d.snap_selected_to_cursor",
1281                         text="Selection to Cursor")
1282         layout.operator("view3d.snap_selected_to_grid",
1283                         text="Selection to Grid")
1284         layout.separator()
1285         layout.operator("view3d.pivot_cursor",
1286                         text="Set Cursor as Pivot Point")
1287         layout.operator("view3d.revert_pivot",
1288                         text="Revert Pivot Point")
1289
1290 class VIEW3D_MT_EditCursorMenu(bpy.types.Menu):
1291     bl_label = "Snap Cursor Menu"
1292
1293     def draw(self, context):
1294
1295         layout = self.layout
1296         layout.operator_context = 'INVOKE_REGION_WIN'
1297         layout.operator("view3d.snap_cursor_to_selected",
1298                         text="Cursor to Selected")
1299         layout.operator("view3d.snap_cursor_to_center",
1300                         text="Cursor to Center")
1301         layout.operator("view3d.snap_cursor_to_grid",
1302                         text="Cursor to Grid")
1303         layout.operator("view3d.snap_cursor_to_active",
1304                         text="Cursor to Active")
1305         layout.separator()
1306         layout.operator("view3d.snap_selected_to_cursor",
1307                         text="Selection to Cursor")
1308         layout.operator("view3d.snap_selected_to_grid",
1309                         text="Selection to Grid")
1310         layout.separator()
1311         layout.operator("view3d.pivot_cursor",
1312                         text="Set Cursor as Pivot Point")
1313         layout.operator("view3d.revert_pivot",
1314                         text="Revert Pivot Point")
1315         layout.operator("view3d.snap_cursor_to_edge_intersection",
1316                         text="Cursor to Edge Intersection")
1317         layout.operator("transform.snap_type", text="Snap Tools",
1318                         icon='SNAP_ON')
1319
1320 def abs(val):
1321     if val > 0:
1322         return val
1323     return -val
1324
1325 def edgeIntersect(context, operator):
1326     from mathutils.geometry import intersect_line_line
1327
1328     obj = context.active_object
1329
1330     if (obj.type != "MESH"):
1331         operator.report({'ERROR'}, "Object must be a mesh")
1332         return None
1333
1334     edges = []
1335     mesh = obj.data
1336     verts = mesh.vertices
1337
1338     is_editmode = (obj.mode == 'EDIT')
1339     if is_editmode:
1340         bpy.ops.object.mode_set(mode='OBJECT')
1341
1342     for e in mesh.edges:
1343         if e.select:
1344             edges.append(e)
1345
1346             if len(edges) > 2:
1347                 break
1348
1349     if is_editmode:
1350         bpy.ops.object.mode_set(mode='EDIT')
1351
1352     if len(edges) != 2:
1353         operator.report({'ERROR'},
1354                         "Operator requires exactly 2 edges to be selected")
1355         return
1356
1357     line = intersect_line_line(verts[edges[0].vertices[0]].co,
1358                                verts[edges[0].vertices[1]].co,
1359                                verts[edges[1].vertices[0]].co,
1360                                verts[edges[1].vertices[1]].co)
1361
1362     if line is None:
1363         operator.report({'ERROR'}, "Selected edges do not intersect")
1364         return
1365
1366     point = line[0].lerp(line[1], 0.5)
1367     context.scene.cursor_location = obj.matrix_world * point
1368
1369 class VIEW3D_OT_CursorToEdgeIntersection(bpy.types.Operator):
1370     "Finds the mid-point of the shortest distance between two edges"
1371
1372     bl_idname = "view3d.snap_cursor_to_edge_intersection"
1373     bl_label = "Cursor to Edge Intersection"
1374
1375     @classmethod
1376     def poll(cls, context):
1377         obj = context.active_object
1378         return obj != None and obj.type == 'MESH'
1379
1380     def execute(self, context):
1381         edgeIntersect(context, self)
1382         return {'FINISHED'}
1383
1384 class VIEW3D_MT_undoS(bpy.types.Menu):
1385     bl_label = "Undo/Redo"
1386
1387     def draw(self, context):
1388         layout = self.layout
1389         layout.operator_context = 'INVOKE_REGION_WIN'
1390         layout.operator("ed.undo", icon='TRIA_LEFT')
1391         layout.operator("ed.redo", icon='TRIA_RIGHT')
1392
1393 def register():
1394     bpy.utils.register_module(__name__)
1395
1396
1397 def unregister():
1398     bpy.utils.unregister_module(__name__)
1399
1400 if __name__ == "__main__":
1401     register()