Eevee: Add per material option to cull backfaces
[blender.git] / release / scripts / startup / bl_ui / space_view3d.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
19 # <pep8 compliant>
20 import bpy
21 from bpy.types import (
22     Header,
23     Menu,
24     Panel,
25 )
26 from .properties_paint_common import (
27     UnifiedPaintPanel,
28 )
29 from .properties_grease_pencil_common import (
30     AnnotationDataPanel,
31     AnnotationOnionSkin,
32     GreasePencilMaterialsPanel,
33 )
34 from .space_toolsystem_common import (
35     ToolActivePanelHelper,
36 )
37 from bpy.app.translations import contexts as i18n_contexts
38
39
40 class VIEW3D_HT_tool_header(Header):
41     bl_space_type = 'VIEW_3D'
42     bl_region_type = "TOOL_HEADER"
43
44     def draw(self, context):
45         layout = self.layout
46
47         layout.row(align=True).template_header()
48
49         self.draw_tool_settings(context)
50
51         layout.separator_spacer()
52
53         VIEW3D_HT_header.draw_xform_template(layout, context)
54
55         layout.separator_spacer()
56
57         self.draw_mode_settings(context)
58
59     def draw_tool_settings(self, context):
60         layout = self.layout
61         tool_mode = context.mode
62
63         # Active Tool
64         # -----------
65         from .space_toolsystem_common import ToolSelectPanelHelper
66         tool = ToolSelectPanelHelper.draw_active_tool_header(
67             context, layout,
68             tool_key=('VIEW_3D', tool_mode),
69         )
70
71         # Object Mode Options
72         # -------------------
73
74         # Example of how tool_settings can be accessed as pop-overs.
75
76         # TODO(campbell): editing options should be after active tool options
77         # (obviously separated for from the users POV)
78         draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
79         if draw_fn is not None:
80             draw_fn(context, layout, tool)
81
82         # Note: general mode options should be added to 'draw_mode_settings'.
83         if tool_mode == 'SCULPT':
84             if (tool is not None) and tool.has_datablock:
85                 layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".paint_common", category="Tool")
86         elif tool_mode == 'PAINT_VERTEX':
87             if (tool is not None) and tool.has_datablock:
88                 layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".paint_common", category="Tool")
89         elif tool_mode == 'PAINT_WEIGHT':
90             if (tool is not None) and tool.has_datablock:
91                 layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".paint_common", category="Tool")
92         elif tool_mode == 'PAINT_TEXTURE':
93             if (tool is not None) and tool.has_datablock:
94                 layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".paint_common", category="Tool")
95         elif tool_mode == 'EDIT_ARMATURE':
96             pass
97         elif tool_mode == 'EDIT_CURVE':
98             pass
99         elif tool_mode == 'EDIT_MESH':
100             pass
101         elif tool_mode == 'POSE':
102             pass
103         elif tool_mode == 'PARTICLE':
104             # Disable, only shows "Brush" panel, which is already in the top-bar.
105             # if tool.has_datablock:
106             #     layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".paint_common", category="Tool")
107             pass
108         elif tool_mode == 'PAINT_GPENCIL':
109             if (tool is not None) and tool.has_datablock:
110                 layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".greasepencil_paint", category="Tool")
111         elif tool_mode == 'SCULPT_GPENCIL':
112             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".greasepencil_sculpt", category="Tool")
113         elif tool_mode == 'WEIGHT_GPENCIL':
114             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".greasepencil_weight", category="Tool")
115
116     def draw_mode_settings(self, context):
117         layout = self.layout
118
119         # Active Tool
120         # -----------
121         from .space_toolsystem_common import ToolSelectPanelHelper
122         tool = ToolSelectPanelHelper.tool_active_from_context(context)
123         tool_mode = context.mode if tool is None else tool.mode
124
125         if tool_mode == 'SCULPT':
126             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".sculpt_mode", category="Tool")
127         elif tool_mode == 'PAINT_VERTEX':
128             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".vertexpaint", category="Tool")
129         elif tool_mode == 'PAINT_WEIGHT':
130             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".weightpaint", category="Tool")
131         elif tool_mode == 'PAINT_TEXTURE':
132             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".imagepaint", category="Tool")
133         elif tool_mode == 'EDIT_TEXT':
134             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".text_edit", category="Tool")
135         elif tool_mode == 'EDIT_ARMATURE':
136             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".armature_edit", category="Tool")
137         elif tool_mode == 'EDIT_METABALL':
138             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".mball_edit", category="Tool")
139         elif tool_mode == 'EDIT_LATTICE':
140             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".lattice_edit", category="Tool")
141         elif tool_mode == 'EDIT_CURVE':
142             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".curve_edit", category="Tool")
143         elif tool_mode == 'EDIT_MESH':
144             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".mesh_edit", category="Tool")
145         elif tool_mode == 'POSE':
146             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".posemode", category="Tool")
147         elif tool_mode == 'PARTICLE':
148             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".particlemode", category="Tool")
149         elif tool_mode == 'OBJECT':
150             layout.popover_group(space_type='VIEW_3D', region_type='UI', context=".objectmode", category="Tool")
151         elif tool_mode in {'PAINT_GPENCIL', 'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
152             # Grease pencil layer.
153             gpl = context.active_gpencil_layer
154             if gpl and gpl.info is not None:
155                 text = gpl.info
156                 maxw = 25
157                 if len(text) > maxw:
158                     text = text[:maxw - 5] + '..' + text[-3:]
159             else:
160                 text = ""
161
162             layout.label(text="Layer:")
163             sub = layout.row()
164             sub.ui_units_x = 8
165             sub.popover(
166                 panel="TOPBAR_PT_gpencil_layers",
167                 text=text,
168             )
169
170
171 class _draw_tool_settings_context_mode:
172     @staticmethod
173     def SCULPT(context, layout, tool):
174         if (tool is None) or (not tool.has_datablock):
175             return
176
177         paint = context.tool_settings.sculpt
178         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
179
180         brush = paint.brush
181         if brush is None:
182             return
183
184         from .properties_paint_common import (
185             brush_basic_sculpt_settings,
186         )
187         brush_basic_sculpt_settings(layout, context, brush, compact=True)
188
189     @staticmethod
190     def PAINT_TEXTURE(context, layout, tool):
191         if (tool is None) or (not tool.has_datablock):
192             return
193
194         paint = context.tool_settings.image_paint
195         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
196
197         brush = paint.brush
198         if brush is None:
199             return
200
201         from .properties_paint_common import (
202             UnifiedPaintPanel,
203             brush_basic_texpaint_settings,
204         )
205         capabilities = brush.image_paint_capabilities
206         if capabilities.has_color:
207             UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
208         brush_basic_texpaint_settings(layout, context, brush, compact=True)
209
210     @staticmethod
211     def PAINT_VERTEX(context, layout, tool):
212         if (tool is None) or (not tool.has_datablock):
213             return
214
215         paint = context.tool_settings.vertex_paint
216         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
217
218         brush = paint.brush
219         if brush is None:
220             return
221
222         from .properties_paint_common import (
223             UnifiedPaintPanel,
224             brush_basic_vpaint_settings,
225         )
226         capabilities = brush.vertex_paint_capabilities
227         if capabilities.has_color:
228             UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
229         brush_basic_vpaint_settings(layout, context, brush, compact=True)
230
231     @staticmethod
232     def PAINT_WEIGHT(context, layout, tool):
233         if (tool is None) or (not tool.has_datablock):
234             return
235
236         paint = context.tool_settings.weight_paint
237         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
238         brush = paint.brush
239         if brush is None:
240             return
241
242         from .properties_paint_common import brush_basic_wpaint_settings
243         brush_basic_wpaint_settings(layout, context, brush, compact=True)
244
245     @staticmethod
246     def PAINT_GPENCIL(context, layout, tool):
247         if tool is None:
248             return
249
250         # is_paint = True
251         # FIXME: tools must use their own UI drawing!
252         if tool.idname in {"builtin.line", "builtin.box", "builtin.circle", "builtin.arc", "builtin.curve"}:
253             # is_paint = False
254             pass
255         elif tool.idname == "Cutter":
256             row = layout.row(align=True)
257             row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
258             return
259         elif not tool.has_datablock:
260             return
261
262         paint = context.tool_settings.gpencil_paint
263         brush = paint.brush
264         if brush is None:
265             return
266
267         gp_settings = brush.gpencil_settings
268
269         def draw_color_selector():
270             ma = gp_settings.material
271             row = layout.row(align=True)
272             if not gp_settings.use_material_pin:
273                 ma = context.object.active_material
274             icon_id = 0
275             if ma:
276                 icon_id = ma.id_data.preview.icon_id
277                 txt_ma = ma.name
278                 maxw = 25
279                 if len(txt_ma) > maxw:
280                     txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:]
281             else:
282                 txt_ma = ""
283
284             sub = row.row()
285             sub.ui_units_x = 8
286             sub.popover(
287                 panel="TOPBAR_PT_gpencil_materials",
288                 text=txt_ma,
289                 icon_value=icon_id,
290             )
291
292             row.prop(gp_settings, "use_material_pin", text="")
293
294         row = layout.row(align=True)
295         tool_settings = context.scene.tool_settings
296         settings = tool_settings.gpencil_paint
297         row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
298
299         if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}:
300             draw_color_selector()
301
302         from .properties_paint_common import (
303             brush_basic_gpencil_paint_settings,
304         )
305         brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
306
307         # FIXME: tools must use their own UI drawing!
308         if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}:
309             settings = context.tool_settings.gpencil_sculpt
310             row = layout.row(align=True)
311             row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
312             sub = row.row(align=True)
313             sub.active = settings.use_thickness_curve
314             sub.popover(
315                 panel="TOPBAR_PT_gpencil_primitive",
316                 text="Thickness Profile",
317             )
318
319         if brush.gpencil_tool == 'FILL':
320             settings = context.tool_settings.gpencil_sculpt
321             row = layout.row(align=True)
322             sub = row.row(align=True)
323             sub.popover(
324                 panel="TOPBAR_PT_gpencil_fill",
325                 text="Fill Options",
326             )
327
328     @staticmethod
329     def SCULPT_GPENCIL(context, layout, tool):
330         if (tool is None) or (not tool.has_datablock):
331             return
332         tool_settings = context.tool_settings
333         settings = tool_settings.gpencil_sculpt
334         brush = settings.brush
335
336         from .properties_paint_common import (
337             brush_basic_gpencil_sculpt_settings,
338         )
339         brush_basic_gpencil_sculpt_settings(layout, context, brush, compact=True)
340
341     @staticmethod
342     def WEIGHT_GPENCIL(context, layout, tool):
343         if (tool is None) or (not tool.has_datablock):
344             return
345         tool_settings = context.tool_settings
346         settings = tool_settings.gpencil_sculpt
347         brush = settings.brush
348
349         from .properties_paint_common import (
350             brush_basic_gpencil_weight_settings,
351         )
352         brush_basic_gpencil_weight_settings(layout, context, brush, compact=True)
353
354     @staticmethod
355     def PARTICLE(context, layout, tool):
356         if (tool is None) or (not tool.has_datablock):
357             return
358
359         # See: 'VIEW3D_PT_tools_brush', basically a duplicate
360         settings = context.tool_settings.particle_edit
361         brush = settings.brush
362         tool = settings.tool
363         if tool != 'NONE':
364             layout.prop(brush, "size", slider=True)
365             if tool == 'ADD':
366                 layout.prop(brush, "count")
367
368                 layout.prop(settings, "use_default_interpolate")
369                 layout.prop(brush, "steps", slider=True)
370                 layout.prop(settings, "default_key_count", slider=True)
371             else:
372                 layout.prop(brush, "strength", slider=True)
373
374                 if tool == 'LENGTH':
375                     layout.row().prop(brush, "length_mode", expand=True)
376                 elif tool == 'PUFF':
377                     layout.row().prop(brush, "puff_mode", expand=True)
378                     layout.prop(brush, "use_puff_volume")
379                 elif tool == 'COMB':
380                     row = layout.row()
381                     row.active = settings.is_editable
382                     row.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
383                     sub = row.row(align=True)
384                     sub.active = settings.use_emitter_deflect
385                     sub.prop(settings, "emitter_distance", text="Distance")
386
387
388 class VIEW3D_HT_header(Header):
389     bl_space_type = 'VIEW_3D'
390
391     @staticmethod
392     def draw_xform_template(layout, context):
393         obj = context.active_object
394         object_mode = 'OBJECT' if obj is None else obj.mode
395         has_pose_mode = (
396             (object_mode == 'POSE') or
397             (object_mode == 'WEIGHT_PAINT' and context.pose_object is not None)
398         )
399
400         tool_settings = context.tool_settings
401
402         # Mode & Transform Settings
403         scene = context.scene
404
405         # Orientation
406         if object_mode in {'OBJECT', 'EDIT', 'EDIT_GPENCIL'} or has_pose_mode:
407             orient_slot = scene.transform_orientation_slots[0]
408             row = layout.row(align=True)
409
410             sub = row.row()
411             sub.ui_units_x = 4
412             sub.prop_with_popover(
413                 orient_slot,
414                 "type",
415                 text="",
416                 panel="VIEW3D_PT_transform_orientations",
417             )
418
419         # Pivot
420         if object_mode in {'OBJECT', 'EDIT', 'EDIT_GPENCIL', 'SCULPT_GPENCIL'} or has_pose_mode:
421             layout.prop_with_popover(
422                 tool_settings,
423                 "transform_pivot_point",
424                 text="",
425                 icon_only=True,
426                 panel="VIEW3D_PT_pivot_point",
427             )
428
429         # Snap
430         show_snap = False
431         if obj is None:
432             show_snap = True
433         else:
434             if (object_mode not in {
435                     'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
436                     'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'
437             }) or has_pose_mode:
438                 show_snap = True
439             else:
440
441                 from .properties_paint_common import UnifiedPaintPanel
442                 paint_settings = UnifiedPaintPanel.paint_settings(context)
443
444                 if paint_settings:
445                     brush = paint_settings.brush
446                     if brush and brush.stroke_method == 'CURVE':
447                         show_snap = True
448
449         if show_snap:
450             snap_items = bpy.types.ToolSettings.bl_rna.properties["snap_elements"].enum_items
451             snap_elements = tool_settings.snap_elements
452             if len(snap_elements) == 1:
453                 text = ""
454                 for elem in snap_elements:
455                     icon = snap_items[elem].icon
456                     break
457             else:
458                 text = "Mix"
459                 icon = 'NONE'
460             del snap_items, snap_elements
461
462             row = layout.row(align=True)
463             row.prop(tool_settings, "use_snap", text="")
464
465             sub = row.row(align=True)
466             sub.popover(
467                 panel="VIEW3D_PT_snapping",
468                 icon=icon,
469                 text=text,
470             )
471
472         # Proportional editing
473         if object_mode in {'EDIT', 'PARTICLE_EDIT', 'SCULPT_GPENCIL', 'EDIT_GPENCIL', 'OBJECT'}:
474             row = layout.row(align=True)
475             kw = {}
476             if object_mode == 'OBJECT':
477                 attr = "use_proportional_edit_objects"
478             else:
479                 attr = "use_proportional_edit"
480
481                 if tool_settings.use_proportional_edit:
482                     if tool_settings.use_proportional_connected:
483                         kw["icon"] = 'PROP_CON'
484                     elif tool_settings.use_proportional_projected:
485                         kw["icon"] = 'PROP_PROJECTED'
486                     else:
487                         kw["icon"] = 'PROP_ON'
488                 else:
489                     kw["icon"] = 'PROP_OFF'
490
491             row.prop(tool_settings, attr, icon_only=True, **kw)
492             sub = row.row(align=True)
493             sub.active = getattr(tool_settings, attr)
494             sub.prop_with_popover(
495                 tool_settings,
496                 "proportional_edit_falloff",
497                 text="",
498                 icon_only=True,
499                 panel="VIEW3D_PT_proportional_edit",
500             )
501
502         # grease pencil
503         if object_mode == 'PAINT_GPENCIL':
504             layout.prop_with_popover(
505                 tool_settings,
506                 "gpencil_stroke_placement_view3d",
507                 text="",
508                 panel="VIEW3D_PT_gpencil_origin",
509             )
510
511         if object_mode in {'PAINT_GPENCIL', 'SCULPT_GPENCIL'}:
512             layout.prop_with_popover(
513                 tool_settings.gpencil_sculpt,
514                 "lock_axis",
515                 text="",
516                 panel="VIEW3D_PT_gpencil_lock",
517             )
518
519         if object_mode == 'PAINT_GPENCIL':
520             # FIXME: this is bad practice!
521             # Tool options are to be displayed in the topbar.
522             if context.workspace.tools.from_space_view3d_mode(object_mode).idname == "builtin_brush.Draw":
523                 settings = tool_settings.gpencil_sculpt.guide
524                 row = layout.row(align=True)
525                 row.prop(settings, "use_guide", text="", icon='GRID')
526                 sub = row.row(align=True)
527                 sub.active = settings.use_guide
528                 sub.popover(
529                     panel="VIEW3D_PT_gpencil_guide",
530                     text="Guides",
531                 )
532
533     def draw(self, context):
534         layout = self.layout
535
536         tool_settings = context.tool_settings
537         view = context.space_data
538         shading = view.shading
539         # mode_string = context.mode
540         obj = context.active_object
541         show_region_tool_header = view.show_region_tool_header
542
543         if not show_region_tool_header:
544             layout.row(align=True).template_header()
545
546         row = layout.row(align=True)
547         object_mode = 'OBJECT' if obj is None else obj.mode
548
549         # Note: This is actually deadly in case enum_items have to be dynamically generated
550         #       (because internal RNA array iterator will free everything immediately...).
551         # XXX This is an RNA internal issue, not sure how to fix it.
552         # Note: Tried to add an accessor to get translated UI strings instead of manual call
553         #       to pgettext_iface below, but this fails because translated enumitems
554         #       are always dynamically allocated.
555         act_mode_item = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode]
556         act_mode_i18n_context = bpy.types.Object.bl_rna.properties["mode"].translation_context
557
558         sub = row.row(align=True)
559         sub.ui_units_x = 5.5
560         sub.operator_menu_enum(
561             "object.mode_set", "mode",
562             text=bpy.app.translations.pgettext_iface(act_mode_item.name, act_mode_i18n_context),
563             icon=act_mode_item.icon,
564         )
565         del act_mode_item
566
567         layout.template_header_3D_mode()
568
569         # Contains buttons like Mode, Pivot, Layer, Mesh Select Mode...
570         if obj:
571             # Particle edit
572             if object_mode == 'PARTICLE_EDIT':
573                 row = layout.row()
574                 row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True)
575
576         # Grease Pencil
577         if obj and obj.type == 'GPENCIL' and context.gpencil_data:
578             gpd = context.gpencil_data
579
580             if gpd.is_stroke_paint_mode:
581                 row = layout.row()
582                 sub = row.row(align=True)
583                 sub.prop(tool_settings, "use_gpencil_draw_onback", text="", icon='MOD_OPACITY')
584                 sub.separator(factor=0.4)
585                 sub.prop(tool_settings, "use_gpencil_weight_data_add", text="", icon='WPAINT_HLT')
586                 sub.separator(factor=0.4)
587                 sub.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
588
589             if gpd.use_stroke_edit_mode:
590                 row = layout.row(align=True)
591                 row.prop(tool_settings, "gpencil_selectmode", text="", expand=True)
592
593             if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
594                 row = layout.row(align=True)
595
596                 if gpd.is_stroke_sculpt_mode:
597                     row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
598                     row.separator()
599
600                 row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING')
601
602                 sub = row.row(align=True)
603                 sub.active = gpd.use_multiedit
604                 sub.popover(
605                     panel="VIEW3D_PT_gpencil_multi_frame",
606                     text="Multiframe",
607                 )
608
609             if gpd.use_stroke_edit_mode:
610                 row = layout.row(align=True)
611                 row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
612
613                 row.popover(
614                     panel="VIEW3D_PT_tools_grease_pencil_interpolate",
615                     text="Interpolate",
616                 )
617
618         overlay = view.overlay
619
620         VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
621
622         layout.separator_spacer()
623
624         if not show_region_tool_header:
625             VIEW3D_HT_header.draw_xform_template(layout, context)
626
627             layout.separator_spacer()
628
629         # Viewport Settings
630         layout.popover(
631             panel="VIEW3D_PT_object_type_visibility",
632             icon_value=view.icon_from_show_object_viewport,
633             text="",
634         )
635
636         # Gizmo toggle & popover.
637         row = layout.row(align=True)
638         # FIXME: place-holder icon.
639         row.prop(view, "show_gizmo", text="", toggle=True, icon='GIZMO')
640         sub = row.row(align=True)
641         sub.active = view.show_gizmo
642         sub.popover(
643             panel="VIEW3D_PT_gizmo_display",
644             text="",
645         )
646
647         # Overlay toggle & popover.
648         row = layout.row(align=True)
649         row.prop(overlay, "show_overlays", icon='OVERLAY', text="")
650         sub = row.row(align=True)
651         sub.active = overlay.show_overlays
652         sub.popover(panel="VIEW3D_PT_overlay", text="")
653
654         row = layout.row()
655         row.active = (shading.type in {'WIREFRAME', 'SOLID'}) or object_mode in {'EDIT'}
656
657         if shading.type == 'WIREFRAME':
658             row.prop(shading, "show_xray_wireframe", text="", icon='XRAY')
659         else:
660             row.prop(shading, "show_xray", text="", icon='XRAY')
661
662         row = layout.row(align=True)
663         row.prop(shading, "type", text="", expand=True)
664         sub = row.row(align=True)
665         # TODO, currently render shading type ignores mesh two-side, until it's supported
666         # show the shading popover which shows double-sided option.
667
668         # sub.enabled = shading.type != 'RENDERED'
669         sub.popover(panel="VIEW3D_PT_shading", text="")
670
671
672 class VIEW3D_MT_editor_menus(Menu):
673     bl_label = ""
674
675     def draw(self, context):
676         layout = self.layout
677         obj = context.active_object
678         mode_string = context.mode
679         edit_object = context.edit_object
680         gp_edit = obj and obj.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}
681
682         layout.menu("VIEW3D_MT_view")
683
684         # Select Menu
685         if gp_edit:
686             if mode_string not in {'PAINT_GPENCIL', 'WEIGHT_GPENCIL'}:
687                 layout.menu("VIEW3D_MT_select_gpencil")
688         elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
689             mesh = obj.data
690             if mesh.use_paint_mask:
691                 layout.menu("VIEW3D_MT_select_paint_mask")
692             elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
693                 layout.menu("VIEW3D_MT_select_paint_mask_vertex")
694         elif mode_string != 'SCULPT':
695             layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
696
697         if gp_edit:
698             pass
699         elif mode_string == 'OBJECT':
700             layout.menu("VIEW3D_MT_add", text="Add", text_ctxt=i18n_contexts.operator_default)
701         elif mode_string == 'EDIT_MESH':
702             layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
703         elif mode_string == 'EDIT_CURVE':
704             layout.menu("VIEW3D_MT_curve_add", text="Add", text_ctxt=i18n_contexts.operator_default)
705         elif mode_string == 'EDIT_SURFACE':
706             layout.menu("VIEW3D_MT_surface_add", text="Add", text_ctxt=i18n_contexts.operator_default)
707         elif mode_string == 'EDIT_METABALL':
708             layout.menu("VIEW3D_MT_metaball_add", text="Add", text_ctxt=i18n_contexts.operator_default)
709         elif mode_string == 'EDIT_ARMATURE':
710             layout.menu("TOPBAR_MT_edit_armature_add", text="Add", text_ctxt=i18n_contexts.operator_default)
711
712         if gp_edit:
713             if obj and obj.mode == 'PAINT_GPENCIL':
714                 layout.menu("VIEW3D_MT_paint_gpencil")
715             elif obj and obj.mode == 'EDIT_GPENCIL':
716                 layout.menu("VIEW3D_MT_edit_gpencil")
717             elif obj and obj.mode == 'WEIGHT_GPENCIL':
718                 layout.menu("VIEW3D_MT_weight_gpencil")
719
720         elif edit_object:
721             layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
722
723             if mode_string == 'EDIT_MESH':
724                 layout.menu("VIEW3D_MT_edit_mesh_vertices")
725                 layout.menu("VIEW3D_MT_edit_mesh_edges")
726                 layout.menu("VIEW3D_MT_edit_mesh_faces")
727                 layout.menu("VIEW3D_MT_uv_map", text="UV")
728             elif mode_string in {'EDIT_CURVE', 'EDIT_SURFACE'}:
729                 layout.menu("VIEW3D_MT_edit_curve_ctrlpoints")
730                 layout.menu("VIEW3D_MT_edit_curve_segments")
731
732         elif obj:
733             if mode_string != 'PAINT_TEXTURE':
734                 layout.menu("VIEW3D_MT_%s" % mode_string.lower())
735             if mode_string in {'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'PAINT_TEXTURE'}:
736                 layout.menu("VIEW3D_MT_brush")
737             if mode_string == 'SCULPT':
738                 layout.menu("VIEW3D_MT_hide_mask")
739         else:
740             layout.menu("VIEW3D_MT_object")
741
742
743 # ********** Menu **********
744
745
746 # ********** Utilities **********
747
748
749 class ShowHideMenu:
750     bl_label = "Show/Hide"
751     _operator_name = ""
752
753     def draw(self, _context):
754         layout = self.layout
755
756         layout.operator("%s.reveal" % self._operator_name)
757         layout.operator("%s.hide" % self._operator_name, text="Hide Selected").unselected = False
758         layout.operator("%s.hide" % self._operator_name, text="Hide Unselected").unselected = True
759
760
761 # Standard transforms which apply to all cases
762 # NOTE: this doesn't seem to be able to be used directly
763 class VIEW3D_MT_transform_base(Menu):
764     bl_label = "Transform"
765     bl_category = "View"
766
767     # TODO: get rid of the custom text strings?
768     def draw(self, context):
769         layout = self.layout
770
771         layout.operator("transform.translate")
772         layout.operator("transform.rotate")
773         layout.operator("transform.resize", text="Scale")
774
775         layout.separator()
776
777         layout.operator("transform.tosphere", text="To Sphere")
778         layout.operator("transform.shear", text="Shear")
779         layout.operator("transform.bend", text="Bend")
780         layout.operator("transform.push_pull", text="Push/Pull")
781
782         if context.mode != 'OBJECT':
783             layout.operator("transform.vertex_warp", text="Warp")
784             layout.operator("transform.vertex_random", text="Randomize")
785
786
787 # Generic transform menu - geometry types
788 class VIEW3D_MT_transform(VIEW3D_MT_transform_base):
789     def draw(self, context):
790         # base menu
791         VIEW3D_MT_transform_base.draw(self, context)
792
793         # generic...
794         layout = self.layout
795         if context.mode == 'EDIT_MESH':
796             layout.operator("transform.shrink_fatten", text="Shrink Fatten")
797         elif context.mode == 'EDIT_CURVE':
798             layout.operator("transform.transform", text="Radius").mode = 'CURVE_SHRINKFATTEN'
799
800         layout.separator()
801
802         layout.operator("transform.translate", text="Move Texture Space").texture_space = True
803         layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
804
805
806 # Object-specific extensions to Transform menu
807 class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
808     def draw(self, context):
809         layout = self.layout
810
811         # base menu
812         VIEW3D_MT_transform_base.draw(self, context)
813
814         # object-specific option follow...
815         layout.separator()
816
817         layout.operator("transform.translate", text="Move Texture Space").texture_space = True
818         layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
819
820         layout.separator()
821
822         layout.operator_context = 'EXEC_REGION_WIN'
823         # XXX see alignmenu() in edit.c of b2.4x to get this working
824         layout.operator("transform.transform", text="Align to Transform Orientation").mode = 'ALIGN'
825
826         layout.separator()
827
828         layout.operator("object.randomize_transform")
829         layout.operator("object.align")
830
831         # TODO: there is a strange context bug here.
832         """
833         layout.operator_context = 'INVOKE_REGION_WIN'
834         layout.operator("object.transform_axis_target")
835         """
836
837
838 # Armature EditMode extensions to Transform menu
839 class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
840     def draw(self, context):
841         layout = self.layout
842
843         # base menu
844         VIEW3D_MT_transform_base.draw(self, context)
845
846         # armature specific extensions follow...
847         obj = context.object
848         if obj.type == 'ARMATURE' and obj.mode in {'EDIT', 'POSE'}:
849             if obj.data.display_type == 'BBONE':
850                 layout.separator()
851
852                 layout.operator("transform.transform", text="Scale BBone").mode = 'BONE_SIZE'
853             elif obj.data.display_type == 'ENVELOPE':
854                 layout.separator()
855
856                 layout.operator("transform.transform", text="Scale Envelope Distance").mode = 'BONE_SIZE'
857                 layout.operator("transform.transform", text="Scale Radius").mode = 'BONE_ENVELOPE'
858
859         if context.edit_object and context.edit_object.type == 'ARMATURE':
860             layout.separator()
861
862             layout.operator("armature.align")
863
864
865 class VIEW3D_MT_mirror(Menu):
866     bl_label = "Mirror"
867
868     def draw(self, _context):
869         layout = self.layout
870
871         layout.operator("transform.mirror", text="Interactive Mirror")
872
873         layout.separator()
874
875         layout.operator_context = 'EXEC_REGION_WIN'
876
877         for (space_name, space_id) in (("Global", 'GLOBAL'), ("Local", 'LOCAL')):
878             for axis_index, axis_name in enumerate("XYZ"):
879                 props = layout.operator("transform.mirror", text=f"{axis_name!s} {space_name!s}")
880                 props.constraint_axis[axis_index] = True
881                 props.orient_type = 'GLOBAL'
882
883             if space_id == 'GLOBAL':
884                 layout.separator()
885
886
887 class VIEW3D_MT_snap(Menu):
888     bl_label = "Snap"
889
890     def draw(self, _context):
891         layout = self.layout
892
893         layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid")
894         layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False
895         layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True
896         layout.operator("view3d.snap_selected_to_active", text="Selection to Active")
897
898         layout.separator()
899
900         layout.operator("view3d.snap_cursor_to_selected", text="Cursor to Selected")
901         layout.operator("view3d.snap_cursor_to_center", text="Cursor to World Origin")
902         layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
903         layout.operator("view3d.snap_cursor_to_active", text="Cursor to Active")
904
905
906 class VIEW3D_MT_uv_map(Menu):
907     bl_label = "UV Mapping"
908
909     def draw(self, _context):
910         layout = self.layout
911
912         layout.operator("uv.unwrap")
913
914         layout.operator_context = 'INVOKE_DEFAULT'
915         layout.operator("uv.smart_project")
916         layout.operator("uv.lightmap_pack")
917         layout.operator("uv.follow_active_quads")
918
919         layout.separator()
920
921         layout.operator_context = 'EXEC_REGION_WIN'
922         layout.operator("uv.cube_project")
923         layout.operator("uv.cylinder_project")
924         layout.operator("uv.sphere_project")
925
926         layout.separator()
927
928         layout.operator_context = 'INVOKE_REGION_WIN'
929         layout.operator("uv.project_from_view").scale_to_bounds = False
930         layout.operator("uv.project_from_view", text="Project from View (Bounds)").scale_to_bounds = True
931
932         layout.separator()
933
934         layout.operator("mesh.mark_seam").clear = False
935         layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
936
937         layout.separator()
938
939         layout.operator("uv.reset")
940
941
942 # ********** View menus **********
943
944
945 class VIEW3D_MT_view(Menu):
946     bl_label = "View"
947
948     def draw(self, context):
949         layout = self.layout
950         view = context.space_data
951
952         layout.prop(view, "show_region_toolbar")
953         layout.prop(view, "show_region_ui")
954         layout.prop(view, "show_region_hud")
955
956         layout.separator()
957
958         layout.operator("view3d.view_selected", text="Frame Selected").use_all_regions = False
959         if view.region_quadviews:
960             layout.operator("view3d.view_selected", text="Frame Selected (Quad View)").use_all_regions = True
961
962         layout.operator("view3d.view_all", text="Frame All").center = False
963         layout.operator("view3d.view_persportho", text="Perspective/Orthographic")
964         layout.menu("VIEW3D_MT_view_local")
965
966         layout.separator()
967
968         layout.menu("VIEW3D_MT_view_cameras", text="Cameras")
969
970         layout.separator()
971         layout.menu("VIEW3D_MT_view_viewpoint")
972         layout.menu("VIEW3D_MT_view_navigation")
973         layout.menu("VIEW3D_MT_view_align")
974
975         layout.separator()
976
977         layout.operator_context = 'INVOKE_REGION_WIN'
978         layout.menu("VIEW3D_MT_view_regions", text="View Regions")
979
980         layout.separator()
981
982         layout.operator("screen.animation_play", text="Play Animation")
983
984         layout.separator()
985
986         layout.operator("render.opengl", text="Viewport Render Image", icon='RENDER_STILL')
987         layout.operator("render.opengl", text="Viewport Render Animation", icon='RENDER_ANIMATION').animation = True
988
989         layout.separator()
990
991         layout.menu("INFO_MT_area")
992
993
994 class VIEW3D_MT_view_local(Menu):
995     bl_label = "Local View"
996
997     def draw(self, _context):
998         layout = self.layout
999
1000         layout.operator("view3d.localview", text="Toggle Local View")
1001         layout.operator("view3d.localview_remove_from")
1002
1003
1004 class VIEW3D_MT_view_cameras(Menu):
1005     bl_label = "Cameras"
1006
1007     def draw(self, _context):
1008         layout = self.layout
1009
1010         layout.operator("view3d.object_as_camera")
1011         layout.operator("view3d.view_camera", text="Active Camera")
1012
1013
1014 class VIEW3D_MT_view_viewpoint(Menu):
1015     bl_label = "Viewpoint"
1016
1017     def draw(self, _context):
1018         layout = self.layout
1019
1020         layout.operator("view3d.view_camera", text="Camera")
1021
1022         layout.separator()
1023
1024         layout.operator("view3d.view_axis", text="Top").type = 'TOP'
1025         layout.operator("view3d.view_axis", text="Bottom").type = 'BOTTOM'
1026
1027         layout.separator()
1028
1029         layout.operator("view3d.view_axis", text="Front").type = 'FRONT'
1030         layout.operator("view3d.view_axis", text="Back").type = 'BACK'
1031
1032         layout.separator()
1033
1034         layout.operator("view3d.view_axis", text="Right").type = 'RIGHT'
1035         layout.operator("view3d.view_axis", text="Left").type = 'LEFT'
1036
1037
1038 class VIEW3D_MT_view_navigation(Menu):
1039     bl_label = "Navigation"
1040
1041     def draw(self, _context):
1042         from math import pi
1043         layout = self.layout
1044
1045         layout.operator_enum("view3d.view_orbit", "type")
1046         props = layout.operator("view3d.view_orbit", text="Orbit Opposite")
1047         props.type = 'ORBITRIGHT'
1048         props.angle = pi
1049
1050         layout.separator()
1051
1052         layout.operator("view3d.view_roll", text="Roll Left").type = 'LEFT'
1053         layout.operator("view3d.view_roll", text="Roll Right").type = 'RIGHT'
1054
1055         layout.separator()
1056
1057         layout.operator_enum("view3d.view_pan", "type")
1058
1059         layout.separator()
1060
1061         layout.operator("view3d.zoom", text="Zoom In").delta = 1
1062         layout.operator("view3d.zoom", text="Zoom Out").delta = -1
1063         layout.operator("view3d.zoom_border", text="Zoom Border...")
1064         layout.operator("view3d.zoom_camera_1_to_1", text="Zoom Camera 1:1")
1065
1066         layout.separator()
1067
1068         layout.operator("view3d.fly")
1069         layout.operator("view3d.walk")
1070
1071
1072 class VIEW3D_MT_view_align(Menu):
1073     bl_label = "Align View"
1074
1075     def draw(self, _context):
1076         layout = self.layout
1077
1078         layout.menu("VIEW3D_MT_view_align_selected")
1079
1080         layout.separator()
1081
1082         layout.operator("view3d.camera_to_view", text="Align Active Camera to View")
1083         layout.operator("view3d.camera_to_view_selected", text="Align Active Camera to Selected")
1084
1085         layout.separator()
1086
1087         layout.operator("view3d.view_all", text="Center Cursor and View All").center = True
1088         layout.operator("view3d.view_center_cursor")
1089
1090         layout.separator()
1091
1092         layout.operator("view3d.view_lock_to_active")
1093         layout.operator("view3d.view_lock_clear")
1094
1095
1096 class VIEW3D_MT_view_align_selected(Menu):
1097     bl_label = "Align View to Active"
1098
1099     def draw(self, _context):
1100         layout = self.layout
1101
1102         props = layout.operator("view3d.view_axis", text="Top")
1103         props.align_active = True
1104         props.type = 'TOP'
1105
1106         props = layout.operator("view3d.view_axis", text="Bottom")
1107         props.align_active = True
1108         props.type = 'BOTTOM'
1109
1110         layout.separator()
1111
1112         props = layout.operator("view3d.view_axis", text="Front")
1113         props.align_active = True
1114         props.type = 'FRONT'
1115
1116         props = layout.operator("view3d.view_axis", text="Back")
1117         props.align_active = True
1118         props.type = 'BACK'
1119
1120         layout.separator()
1121
1122         props = layout.operator("view3d.view_axis", text="Right")
1123         props.align_active = True
1124         props.type = 'RIGHT'
1125
1126         props = layout.operator("view3d.view_axis", text="Left")
1127         props.align_active = True
1128         props.type = 'LEFT'
1129
1130
1131 class VIEW3D_MT_view_regions(Menu):
1132     bl_label = "View Regions"
1133
1134     def draw(self, _context):
1135         layout = self.layout
1136         layout.operator("view3d.clip_border", text="Clipping Region...")
1137         layout.operator("view3d.render_border", text="Render Region...")
1138
1139         layout.separator()
1140
1141         layout.operator("view3d.clear_render_border")
1142
1143
1144 # ********** Select menus, suffix from context.mode **********
1145
1146 class VIEW3D_MT_select_object_more_less(Menu):
1147     bl_label = "Select More/Less"
1148
1149     def draw(self, _context):
1150         layout = self.layout
1151
1152         layout = self.layout
1153
1154         layout.operator("object.select_more", text="More")
1155         layout.operator("object.select_less", text="Less")
1156
1157         layout.separator()
1158
1159         props = layout.operator("object.select_hierarchy", text="Parent")
1160         props.extend = False
1161         props.direction = 'PARENT'
1162
1163         props = layout.operator("object.select_hierarchy", text="Child")
1164         props.extend = False
1165         props.direction = 'CHILD'
1166
1167         layout.separator()
1168
1169         props = layout.operator("object.select_hierarchy", text="Extend Parent")
1170         props.extend = True
1171         props.direction = 'PARENT'
1172
1173         props = layout.operator("object.select_hierarchy", text="Extend Child")
1174         props.extend = True
1175         props.direction = 'CHILD'
1176
1177
1178 class VIEW3D_MT_select_object(Menu):
1179     bl_label = "Select"
1180
1181     def draw(self, _context):
1182         layout = self.layout
1183
1184         layout.operator("object.select_all", text="All").action = 'SELECT'
1185         layout.operator("object.select_all", text="None").action = 'DESELECT'
1186         layout.operator("object.select_all", text="Invert").action = 'INVERT'
1187
1188         layout.separator()
1189
1190         layout.operator("view3d.select_box")
1191         layout.operator("view3d.select_circle")
1192
1193         layout.separator()
1194
1195         layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...")
1196         layout.operator("object.select_camera", text="Select Active Camera")
1197         layout.operator("object.select_mirror", text="Mirror Selection")
1198         layout.operator("object.select_random", text="Select Random")
1199
1200         layout.separator()
1201
1202         layout.menu("VIEW3D_MT_select_object_more_less")
1203
1204         layout.separator()
1205
1206         layout.operator_menu_enum("object.select_grouped", "type", text="Select Grouped")
1207         layout.operator_menu_enum("object.select_linked", "type", text="Select Linked")
1208         layout.operator("object.select_pattern", text="Select Pattern...")
1209
1210
1211 class VIEW3D_MT_select_pose_more_less(Menu):
1212     bl_label = "Select More/Less"
1213
1214     def draw(self, _context):
1215         layout = self.layout
1216
1217         layout = self.layout
1218
1219         props = layout.operator("pose.select_hierarchy", text="Parent")
1220         props.extend = False
1221         props.direction = 'PARENT'
1222
1223         props = layout.operator("pose.select_hierarchy", text="Child")
1224         props.extend = False
1225         props.direction = 'CHILD'
1226
1227         layout.separator()
1228
1229         props = layout.operator("pose.select_hierarchy", text="Extend Parent")
1230         props.extend = True
1231         props.direction = 'PARENT'
1232
1233         props = layout.operator("pose.select_hierarchy", text="Extend Child")
1234         props.extend = True
1235         props.direction = 'CHILD'
1236
1237
1238 class VIEW3D_MT_select_pose(Menu):
1239     bl_label = "Select"
1240
1241     def draw(self, _context):
1242         layout = self.layout
1243
1244         layout.operator("pose.select_all", text="All").action = 'SELECT'
1245         layout.operator("pose.select_all", text="None").action = 'DESELECT'
1246         layout.operator("pose.select_all", text="Invert").action = 'INVERT'
1247
1248         layout.separator()
1249
1250         layout.operator("view3d.select_box")
1251         layout.operator("view3d.select_circle")
1252
1253         layout.separator()
1254
1255         layout.operator("pose.select_mirror", text="Flip Active")
1256
1257         layout.separator()
1258
1259         layout.operator("pose.select_constraint_target", text="Constraint Target")
1260         layout.operator("pose.select_linked", text="Linked")
1261
1262         layout.separator()
1263
1264         layout.menu("VIEW3D_MT_select_pose_more_less")
1265
1266         layout.separator()
1267
1268         layout.operator_menu_enum("pose.select_grouped", "type", text="Grouped")
1269         layout.operator("object.select_pattern", text="Select Pattern...")
1270
1271
1272 class VIEW3D_MT_select_particle(Menu):
1273     bl_label = "Select"
1274
1275     def draw(self, _context):
1276         layout = self.layout
1277
1278         layout.operator("particle.select_all", text="All").action = 'SELECT'
1279         layout.operator("particle.select_all", text="None").action = 'DESELECT'
1280         layout.operator("particle.select_all", text="Invert").action = 'INVERT'
1281
1282         layout.separator()
1283
1284         layout.operator("view3d.select_box")
1285         layout.operator("view3d.select_circle")
1286
1287         layout.separator()
1288
1289         layout.operator("particle.select_linked")
1290
1291         layout.separator()
1292
1293         layout.operator("particle.select_more")
1294         layout.operator("particle.select_less")
1295
1296         layout.separator()
1297
1298         layout.operator("particle.select_random")
1299
1300         layout.separator()
1301
1302         layout.operator("particle.select_roots", text="Roots")
1303         layout.operator("particle.select_tips", text="Tips")
1304
1305
1306 class VIEW3D_MT_edit_mesh_select_similar(Menu):
1307     bl_label = "Select Similar"
1308
1309     def draw(self, _context):
1310         layout = self.layout
1311
1312         layout.operator_enum("mesh.select_similar", "type")
1313
1314         layout.separator()
1315
1316         layout.operator("mesh.select_similar_region", text="Face Regions")
1317
1318
1319 class VIEW3D_MT_edit_mesh_select_by_trait(Menu):
1320     bl_label = "Select All by Trait"
1321
1322     def draw(self, context):
1323         layout = self.layout
1324         tool_settings = context.tool_settings
1325         if tool_settings.mesh_select_mode[2] is False:
1326             layout.operator("mesh.select_non_manifold", text="Non Manifold")
1327         layout.operator("mesh.select_loose", text="Loose Geometry")
1328         layout.operator("mesh.select_interior_faces", text="Interior Faces")
1329         layout.operator("mesh.select_face_by_sides", text="Faces by Sides")
1330
1331         layout.separator()
1332
1333         layout.operator("mesh.select_ungrouped", text="Ungrouped Verts")
1334
1335
1336 class VIEW3D_MT_edit_mesh_select_more_less(Menu):
1337     bl_label = "Select More/Less"
1338
1339     def draw(self, _context):
1340         layout = self.layout
1341
1342         layout.operator("mesh.select_more", text="More")
1343         layout.operator("mesh.select_less", text="Less")
1344
1345         layout.separator()
1346
1347         layout.operator("mesh.select_next_item", text="Next Active")
1348         layout.operator("mesh.select_prev_item", text="Previous Active")
1349
1350
1351 class VIEW3D_MT_edit_mesh_select_linked(Menu):
1352     bl_label = "Select Linked"
1353
1354     def draw(self, _context):
1355         layout = self.layout
1356
1357         layout.operator("mesh.select_linked", text="Linked")
1358         layout.operator("mesh.shortest_path_select", text="Shortest Path")
1359         layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
1360
1361
1362 class VIEW3D_MT_edit_mesh_select_loops(Menu):
1363     bl_label = "Select Loops"
1364
1365     def draw(self, _context):
1366         layout = self.layout
1367
1368         layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False
1369         layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True
1370
1371         layout.separator()
1372
1373         layout.operator("mesh.loop_to_region")
1374         layout.operator("mesh.region_to_loop")
1375
1376
1377 class VIEW3D_MT_select_edit_mesh(Menu):
1378     bl_label = "Select"
1379
1380     def draw(self, _context):
1381         layout = self.layout
1382
1383         # primitive
1384         layout.operator("mesh.select_all", text="All").action = 'SELECT'
1385         layout.operator("mesh.select_all", text="None").action = 'DESELECT'
1386         layout.operator("mesh.select_all", text="Invert").action = 'INVERT'
1387
1388         layout.separator()
1389
1390         layout.operator("view3d.select_box")
1391         layout.operator("view3d.select_circle")
1392
1393         layout.separator()
1394
1395         # numeric
1396         layout.operator("mesh.select_random", text="Select Random")
1397         layout.operator("mesh.select_nth")
1398
1399         layout.separator()
1400
1401         # geometric
1402         layout.operator("mesh.edges_select_sharp", text="Select Sharp Edges")
1403
1404         layout.separator()
1405
1406         # other ...
1407         layout.menu("VIEW3D_MT_edit_mesh_select_similar")
1408
1409         layout.separator()
1410
1411         layout.menu("VIEW3D_MT_edit_mesh_select_by_trait")
1412
1413         layout.separator()
1414
1415         layout.menu("VIEW3D_MT_edit_mesh_select_more_less")
1416
1417         layout.separator()
1418
1419         layout.menu("VIEW3D_MT_edit_mesh_select_loops")
1420
1421         layout.separator()
1422
1423         layout.menu("VIEW3D_MT_edit_mesh_select_linked")
1424
1425         layout.separator()
1426
1427         layout.operator("mesh.select_axis", text="Side of Active")
1428         layout.operator("mesh.select_mirror", text="Mirror Selection")
1429
1430
1431 class VIEW3D_MT_select_edit_curve(Menu):
1432     bl_label = "Select"
1433
1434     def draw(self, _context):
1435         layout = self.layout
1436
1437         layout.operator("curve.select_all", text="All").action = 'SELECT'
1438         layout.operator("curve.select_all", text="None").action = 'DESELECT'
1439         layout.operator("curve.select_all", text="Invert").action = 'INVERT'
1440
1441         layout.separator()
1442
1443         layout.operator("view3d.select_box")
1444         layout.operator("view3d.select_circle")
1445
1446         layout.separator()
1447
1448         layout.operator("curve.select_random")
1449         layout.operator("curve.select_nth")
1450         layout.operator("curve.select_linked", text="Select Linked")
1451         layout.operator("curve.select_similar", text="Select Similar")
1452
1453         layout.separator()
1454
1455         layout.operator("curve.de_select_first")
1456         layout.operator("curve.de_select_last")
1457         layout.operator("curve.select_next")
1458         layout.operator("curve.select_previous")
1459
1460         layout.separator()
1461
1462         layout.operator("curve.select_more")
1463         layout.operator("curve.select_less")
1464
1465
1466 class VIEW3D_MT_select_edit_surface(Menu):
1467     bl_label = "Select"
1468
1469     def draw(self, _context):
1470         layout = self.layout
1471
1472         layout.operator("curve.select_all", text="All").action = 'SELECT'
1473         layout.operator("curve.select_all", text="None").action = 'DESELECT'
1474         layout.operator("curve.select_all", text="Invert").action = 'INVERT'
1475
1476         layout.separator()
1477
1478         layout.operator("view3d.select_box")
1479         layout.operator("view3d.select_circle")
1480
1481         layout.separator()
1482
1483         layout.operator("curve.select_random")
1484         layout.operator("curve.select_nth")
1485         layout.operator("curve.select_linked", text="Select Linked")
1486         layout.operator("curve.select_similar", text="Select Similar")
1487
1488         layout.separator()
1489
1490         layout.operator("curve.select_row")
1491
1492         layout.separator()
1493
1494         layout.operator("curve.select_more")
1495         layout.operator("curve.select_less")
1496
1497
1498 class VIEW3D_MT_edit_text_context_menu(Menu):
1499     bl_label = "Text Context Menu"
1500
1501     def draw(self, _context):
1502         layout = self.layout
1503
1504         layout.operator_context = 'INVOKE_DEFAULT'
1505
1506         layout.operator("font.text_cut", text="Cut")
1507         layout.operator("font.text_copy", text="Copy", icon='COPYDOWN')
1508         layout.operator("font.text_paste", text="Paste", icon='PASTEDOWN')
1509
1510         layout.separator()
1511
1512         layout.operator("font.select_all")
1513
1514         layout.separator()
1515
1516         layout.menu("VIEW3D_MT_edit_font")
1517
1518
1519 class VIEW3D_MT_select_edit_text(Menu):
1520     # intentional name mismatch
1521     # select menu for 3d-text doesn't make sense
1522     bl_label = "Edit"
1523
1524     def draw(self, _context):
1525         layout = self.layout
1526
1527         layout.operator("ed.undo")
1528         layout.operator("ed.redo")
1529
1530         layout.separator()
1531
1532         layout.operator("font.text_cut", text="Cut")
1533         layout.operator("font.text_copy", text="Copy", icon='COPYDOWN')
1534         layout.operator("font.text_paste", text="Paste", icon='PASTEDOWN')
1535
1536         layout.separator()
1537
1538         layout.operator("font.text_paste_from_file")
1539
1540         layout.separator()
1541
1542         layout.operator("font.select_all")
1543
1544         layout.separator()
1545
1546         layout.menu("VIEW3D_MT_edit_text_chars")
1547
1548
1549 class VIEW3D_MT_select_edit_metaball(Menu):
1550     bl_label = "Select"
1551
1552     def draw(self, _context):
1553         layout = self.layout
1554
1555         layout.operator("mball.select_all", text="All").action = 'SELECT'
1556         layout.operator("mball.select_all", text="None").action = 'DESELECT'
1557         layout.operator("mball.select_all", text="Invert").action = 'INVERT'
1558
1559         layout.separator()
1560
1561         layout.operator("view3d.select_box")
1562         layout.operator("view3d.select_circle")
1563
1564         layout.separator()
1565
1566         layout.operator("mball.select_random_metaelems")
1567
1568         layout.separator()
1569
1570         layout.operator_menu_enum("mball.select_similar", "type", text="Similar")
1571
1572
1573 class VIEW3D_MT_edit_lattice_context_menu(Menu):
1574     bl_label = "Lattice Context Menu"
1575
1576     def draw(self, _context):
1577         layout = self.layout
1578
1579         layout = self.layout
1580
1581         layout.menu("VIEW3D_MT_mirror")
1582         layout.operator_menu_enum("lattice.flip", "axis")
1583         layout.menu("VIEW3D_MT_snap")
1584
1585         layout.separator()
1586
1587         layout.operator("lattice.make_regular")
1588
1589
1590 class VIEW3D_MT_select_edit_lattice(Menu):
1591     bl_label = "Select"
1592
1593     def draw(self, _context):
1594         layout = self.layout
1595
1596         layout.operator("lattice.select_all", text="All").action = 'SELECT'
1597         layout.operator("lattice.select_all", text="None").action = 'DESELECT'
1598         layout.operator("lattice.select_all", text="Invert").action = 'INVERT'
1599
1600         layout.separator()
1601
1602         layout.operator("view3d.select_box")
1603         layout.operator("view3d.select_circle")
1604
1605         layout.separator()
1606
1607         layout.operator("lattice.select_mirror")
1608         layout.operator("lattice.select_random")
1609
1610         layout.separator()
1611
1612         layout.operator("lattice.select_more")
1613         layout.operator("lattice.select_less")
1614
1615         layout.separator()
1616
1617         layout.operator("lattice.select_ungrouped", text="Ungrouped Verts")
1618
1619
1620 class VIEW3D_MT_select_edit_armature(Menu):
1621     bl_label = "Select"
1622
1623     def draw(self, _context):
1624         layout = self.layout
1625
1626         layout.operator("armature.select_all", text="All").action = 'SELECT'
1627         layout.operator("armature.select_all", text="None").action = 'DESELECT'
1628         layout.operator("armature.select_all", text="Invert").action = 'INVERT'
1629
1630         layout.separator()
1631
1632         layout.operator("view3d.select_box")
1633         layout.operator("view3d.select_circle")
1634
1635         layout.separator()
1636
1637         layout.operator("armature.select_mirror", text="Mirror").extend = False
1638
1639         layout.separator()
1640
1641         layout.operator("armature.select_more", text="More")
1642         layout.operator("armature.select_less", text="Less")
1643
1644         layout.separator()
1645
1646         props = layout.operator("armature.select_hierarchy", text="Parent")
1647         props.extend = False
1648         props.direction = 'PARENT'
1649
1650         props = layout.operator("armature.select_hierarchy", text="Child")
1651         props.extend = False
1652         props.direction = 'CHILD'
1653
1654         layout.separator()
1655
1656         props = layout.operator("armature.select_hierarchy", text="Extend Parent")
1657         props.extend = True
1658         props.direction = 'PARENT'
1659
1660         props = layout.operator("armature.select_hierarchy", text="Extend Child")
1661         props.extend = True
1662         props.direction = 'CHILD'
1663
1664         layout.operator_menu_enum("armature.select_similar", "type", text="Similar")
1665         layout.operator("object.select_pattern", text="Select Pattern...")
1666
1667
1668 class VIEW3D_MT_select_gpencil(Menu):
1669     bl_label = "Select"
1670
1671     def draw(self, _context):
1672         layout = self.layout
1673
1674         layout.operator("gpencil.select_all", text="All").action = 'SELECT'
1675         layout.operator("gpencil.select_all", text="None").action = 'DESELECT'
1676         layout.operator("gpencil.select_all", text="Invert").action = 'INVERT'
1677
1678         layout.separator()
1679
1680         layout.operator("gpencil.select_box")
1681         layout.operator("gpencil.select_circle")
1682
1683         layout.separator()
1684
1685         layout.operator("gpencil.select_linked", text="Linked")
1686         layout.operator("gpencil.select_alternate")
1687         layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
1688
1689         layout.separator()
1690
1691         layout.operator("gpencil.select_first")
1692         layout.operator("gpencil.select_last")
1693
1694         layout.separator()
1695
1696         layout.operator("gpencil.select_more")
1697         layout.operator("gpencil.select_less")
1698
1699
1700 class VIEW3D_MT_select_paint_mask(Menu):
1701     bl_label = "Select"
1702
1703     def draw(self, _context):
1704         layout = self.layout
1705
1706         layout.operator("paint.face_select_all", text="All").action = 'SELECT'
1707         layout.operator("paint.face_select_all", text="None").action = 'DESELECT'
1708         layout.operator("paint.face_select_all", text="Invert").action = 'INVERT'
1709
1710         layout.separator()
1711
1712         layout.operator("view3d.select_box")
1713         layout.operator("view3d.select_circle")
1714
1715         layout.separator()
1716
1717         layout.operator("paint.face_select_linked", text="Linked")
1718
1719
1720 class VIEW3D_MT_select_paint_mask_vertex(Menu):
1721     bl_label = "Select"
1722
1723     def draw(self, _context):
1724         layout = self.layout
1725
1726         layout.operator("paint.vert_select_all", text="All").action = 'SELECT'
1727         layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
1728         layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
1729
1730         layout.separator()
1731
1732         layout.operator("view3d.select_box")
1733         layout.operator("view3d.select_circle")
1734
1735         layout.separator()
1736
1737         layout.operator("paint.vert_select_ungrouped", text="Ungrouped Verts")
1738
1739
1740 class VIEW3D_MT_angle_control(Menu):
1741     bl_label = "Angle Control"
1742
1743     @classmethod
1744     def poll(cls, context):
1745         settings = UnifiedPaintPanel.paint_settings(context)
1746         if not settings:
1747             return False
1748
1749         brush = settings.brush
1750         tex_slot = brush.texture_slot
1751
1752         return tex_slot.has_texture_angle and tex_slot.has_texture_angle_source
1753
1754     def draw(self, context):
1755         layout = self.layout
1756
1757         settings = UnifiedPaintPanel.paint_settings(context)
1758         brush = settings.brush
1759
1760         sculpt = (context.sculpt_object is not None)
1761
1762         tex_slot = brush.texture_slot
1763
1764         layout.prop(tex_slot, "use_rake", text="Rake")
1765
1766         if brush.brush_capabilities.has_random_texture_angle and tex_slot.has_random_texture_angle:
1767             if sculpt:
1768                 if brush.sculpt_capabilities.has_random_texture_angle:
1769                     layout.prop(tex_slot, "use_random", text="Random")
1770             else:
1771                 layout.prop(tex_slot, "use_random", text="Random")
1772
1773
1774 class VIEW3D_MT_mesh_add(Menu):
1775     bl_idname = "VIEW3D_MT_mesh_add"
1776     bl_label = "Mesh"
1777
1778     def draw(self, _context):
1779         layout = self.layout
1780
1781         layout.operator_context = 'INVOKE_REGION_WIN'
1782
1783         layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE')
1784         layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE')
1785         layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
1786         layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE')
1787         layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE')
1788         layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER')
1789         layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE')
1790         layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS')
1791
1792         layout.separator()
1793
1794         layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID')
1795         layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY')
1796
1797
1798 class VIEW3D_MT_curve_add(Menu):
1799     bl_idname = "VIEW3D_MT_curve_add"
1800     bl_label = "Curve"
1801
1802     def draw(self, _context):
1803         layout = self.layout
1804
1805         layout.operator_context = 'INVOKE_REGION_WIN'
1806
1807         layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE')
1808         layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE')
1809
1810         layout.separator()
1811
1812         layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE')
1813         layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
1814         layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
1815
1816
1817 class VIEW3D_MT_surface_add(Menu):
1818     bl_idname = "VIEW3D_MT_surface_add"
1819     bl_label = "Surface"
1820
1821     def draw(self, _context):
1822         layout = self.layout
1823
1824         layout.operator_context = 'INVOKE_REGION_WIN'
1825
1826         layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE')
1827         layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE')
1828         layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE')
1829         layout.operator("surface.primitive_nurbs_surface_cylinder_add",
1830                         text="Nurbs Cylinder", icon='SURFACE_NCYLINDER')
1831         layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE')
1832         layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS')
1833
1834
1835 class VIEW3D_MT_edit_metaball_context_menu(Menu):
1836     bl_label = "Metaball Context Menu"
1837
1838     def draw(self, _context):
1839         layout = self.layout
1840
1841         layout.operator_context = 'INVOKE_REGION_WIN'
1842
1843         # Add
1844         layout.operator("mball.duplicate_move")
1845
1846         layout.separator()
1847
1848         # Modify
1849         layout.menu("VIEW3D_MT_mirror")
1850         layout.menu("VIEW3D_MT_snap")
1851
1852         layout.separator()
1853
1854         # Remove
1855         layout.operator_context = 'EXEC_DEFAULT'
1856         layout.operator("mball.delete_metaelems", text="Delete")
1857
1858
1859 class VIEW3D_MT_metaball_add(Menu):
1860     bl_idname = "VIEW3D_MT_metaball_add"
1861     bl_label = "Metaball"
1862
1863     def draw(self, _context):
1864         layout = self.layout
1865
1866         layout.operator_context = 'INVOKE_REGION_WIN'
1867         layout.operator_enum("object.metaball_add", "type")
1868
1869
1870 class TOPBAR_MT_edit_curve_add(Menu):
1871     bl_idname = "TOPBAR_MT_edit_curve_add"
1872     bl_label = "Add"
1873     bl_translation_context = i18n_contexts.operator_default
1874
1875     def draw(self, context):
1876         is_surf = context.active_object.type == 'SURFACE'
1877
1878         layout = self.layout
1879         layout.operator_context = 'EXEC_REGION_WIN'
1880
1881         if is_surf:
1882             VIEW3D_MT_surface_add.draw(self, context)
1883         else:
1884             VIEW3D_MT_curve_add.draw(self, context)
1885
1886
1887 class TOPBAR_MT_edit_armature_add(Menu):
1888     bl_idname = "TOPBAR_MT_edit_armature_add"
1889     bl_label = "Armature"
1890
1891     def draw(self, _context):
1892         layout = self.layout
1893
1894         layout.operator_context = 'EXEC_REGION_WIN'
1895         layout.operator("armature.bone_primitive_add", text="Single Bone", icon='BONE_DATA')
1896
1897
1898 class VIEW3D_MT_armature_add(Menu):
1899     bl_idname = "VIEW3D_MT_armature_add"
1900     bl_label = "Armature"
1901
1902     def draw(self, _context):
1903         layout = self.layout
1904
1905         layout.operator_context = 'EXEC_REGION_WIN'
1906         layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA')
1907
1908
1909 class VIEW3D_MT_light_add(Menu):
1910     bl_idname = "VIEW3D_MT_light_add"
1911     bl_label = "Light"
1912
1913     def draw(self, _context):
1914         layout = self.layout
1915
1916         layout.operator_context = 'INVOKE_REGION_WIN'
1917         layout.operator_enum("object.light_add", "type")
1918
1919
1920 class VIEW3D_MT_lightprobe_add(Menu):
1921     bl_idname = "VIEW3D_MT_lightprobe_add"
1922     bl_label = "Light Probe"
1923
1924     def draw(self, _context):
1925         layout = self.layout
1926
1927         layout.operator_context = 'INVOKE_REGION_WIN'
1928         layout.operator_enum("object.lightprobe_add", "type")
1929
1930
1931 class VIEW3D_MT_camera_add(Menu):
1932     bl_idname = "VIEW3D_MT_camera_add"
1933     bl_label = "Camera"
1934
1935     def draw(self, _context):
1936         layout = self.layout
1937         layout.operator_context = 'EXEC_REGION_WIN'
1938         layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
1939
1940
1941 class VIEW3D_MT_add(Menu):
1942     bl_label = "Add"
1943     bl_translation_context = i18n_contexts.operator_default
1944
1945     def draw(self, context):
1946         layout = self.layout
1947
1948         # note, don't use 'EXEC_SCREEN' or operators won't get the 'v3d' context.
1949
1950         # Note: was EXEC_AREA, but this context does not have the 'rv3d', which prevents
1951         #       "align_view" to work on first call (see [#32719]).
1952         layout.operator_context = 'EXEC_REGION_WIN'
1953
1954         # layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH')
1955         layout.menu("VIEW3D_MT_mesh_add", icon='OUTLINER_OB_MESH')
1956
1957         # layout.operator_menu_enum("object.curve_add", "type", text="Curve", icon='OUTLINER_OB_CURVE')
1958         layout.menu("VIEW3D_MT_curve_add", icon='OUTLINER_OB_CURVE')
1959         # layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE')
1960         layout.menu("VIEW3D_MT_surface_add", icon='OUTLINER_OB_SURFACE')
1961         layout.menu("VIEW3D_MT_metaball_add", text="Metaball", icon='OUTLINER_OB_META')
1962         layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
1963         layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
1964
1965         layout.separator()
1966
1967         if VIEW3D_MT_armature_add.is_extended():
1968             layout.menu("VIEW3D_MT_armature_add", icon='OUTLINER_OB_ARMATURE')
1969         else:
1970             layout.operator("object.armature_add", text="Armature", icon='OUTLINER_OB_ARMATURE')
1971
1972         layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
1973
1974         layout.separator()
1975
1976         layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY')
1977         layout.menu("VIEW3D_MT_image_add", text="Image", icon='OUTLINER_OB_IMAGE')
1978
1979         layout.separator()
1980
1981         layout.menu("VIEW3D_MT_light_add", icon='OUTLINER_OB_LIGHT')
1982         layout.menu("VIEW3D_MT_lightprobe_add", icon='OUTLINER_OB_LIGHTPROBE')
1983
1984         layout.separator()
1985
1986         if VIEW3D_MT_camera_add.is_extended():
1987             layout.menu("VIEW3D_MT_camera_add", icon='OUTLINER_OB_CAMERA')
1988         else:
1989             VIEW3D_MT_camera_add.draw(self, context)
1990
1991         layout.separator()
1992
1993         layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
1994
1995         layout.separator()
1996
1997         layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD')
1998
1999         layout.separator()
2000
2001         has_collections = bool(bpy.data.collections)
2002         col = layout.column()
2003         col.enabled = has_collections
2004
2005         if not has_collections or len(bpy.data.collections) > 10:
2006             col.operator_context = 'INVOKE_REGION_WIN'
2007             col.operator(
2008                 "object.collection_instance_add",
2009                 text="Collection Instance..." if has_collections else "No Collections to Instance",
2010                 icon='OUTLINER_OB_GROUP_INSTANCE',
2011             )
2012         else:
2013             col.operator_menu_enum(
2014                 "object.collection_instance_add",
2015                 "collection",
2016                 text="Collection Instance",
2017                 icon='OUTLINER_OB_GROUP_INSTANCE',
2018             )
2019
2020
2021 class VIEW3D_MT_image_add(Menu):
2022     bl_label = "Add Image"
2023
2024     def draw(self, _context):
2025         layout = self.layout
2026         layout.operator("object.load_reference_image", text="Reference", icon='IMAGE_REFERENCE')
2027         layout.operator("object.load_background_image", text="Background", icon='IMAGE_BACKGROUND')
2028
2029
2030 class VIEW3D_MT_object_relations(Menu):
2031     bl_label = "Relations"
2032
2033     def draw(self, _context):
2034         layout = self.layout
2035
2036         layout.operator("object.proxy_make", text="Make Proxy...")
2037
2038         layout.operator("object.make_dupli_face")
2039
2040         layout.separator()
2041
2042         layout.operator_menu_enum("object.make_local", "type", text="Make Local...")
2043         layout.menu("VIEW3D_MT_make_single_user")
2044
2045         layout.separator()
2046
2047         layout.operator("object.data_transfer")
2048         layout.operator("object.datalayout_transfer")
2049
2050
2051 class VIEW3D_MT_object(Menu):
2052     bl_context = "objectmode"
2053     bl_label = "Object"
2054
2055     def draw(self, context):
2056         layout = self.layout
2057
2058         layout.menu("VIEW3D_MT_transform_object")
2059         layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2060         layout.menu("VIEW3D_MT_mirror")
2061         layout.menu("VIEW3D_MT_object_clear")
2062         layout.menu("VIEW3D_MT_object_apply")
2063         layout.menu("VIEW3D_MT_snap")
2064
2065         layout.separator()
2066
2067         layout.operator("object.duplicate_move")
2068         layout.operator("object.duplicate_move_linked")
2069         layout.operator("object.join")
2070
2071         layout.separator()
2072
2073         layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
2074         layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
2075
2076         layout.separator()
2077
2078         layout.menu("VIEW3D_MT_object_parent")
2079         layout.menu("VIEW3D_MT_object_collection")
2080         layout.menu("VIEW3D_MT_object_relations")
2081         layout.menu("VIEW3D_MT_object_constraints")
2082         layout.menu("VIEW3D_MT_object_track")
2083         layout.menu("VIEW3D_MT_make_links", text="Make Links")
2084
2085         layout.separator()
2086
2087         layout.operator("object.shade_smooth")
2088         layout.operator("object.shade_flat")
2089
2090         layout.separator()
2091
2092         layout.menu("VIEW3D_MT_object_animation")
2093         layout.menu("VIEW3D_MT_object_rigid_body")
2094
2095         layout.separator()
2096
2097         layout.menu("VIEW3D_MT_object_quick_effects")
2098
2099         layout.separator()
2100
2101         ob = context.active_object
2102         if ob and ob.type == 'GPENCIL' and context.gpencil_data:
2103             layout.operator_menu_enum("gpencil.convert", "type", text="Convert to")
2104         else:
2105             layout.operator_menu_enum("object.convert", "target")
2106
2107         layout.separator()
2108
2109         layout.menu("VIEW3D_MT_object_showhide")
2110
2111         layout.separator()
2112
2113         layout.operator_context = 'EXEC_DEFAULT'
2114         layout.operator("object.delete", text="Delete").use_global = False
2115         layout.operator("object.delete", text="Delete Global").use_global = True
2116
2117
2118 class VIEW3D_MT_object_animation(Menu):
2119     bl_label = "Animation"
2120
2121     def draw(self, _context):
2122         layout = self.layout
2123
2124         layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
2125         layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframes...")
2126         layout.operator("anim.keyframe_clear_v3d", text="Clear Keyframes...")
2127         layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
2128
2129         layout.separator()
2130
2131         layout.operator("nla.bake", text="Bake Action...")
2132
2133
2134 class VIEW3D_MT_object_rigid_body(Menu):
2135     bl_label = "Rigid Body"
2136
2137     def draw(self, _context):
2138         layout = self.layout
2139
2140         layout.operator("rigidbody.objects_add", text="Add Active").type = 'ACTIVE'
2141         layout.operator("rigidbody.objects_add", text="Add Passive").type = 'PASSIVE'
2142
2143         layout.separator()
2144
2145         layout.operator("rigidbody.objects_remove", text="Remove")
2146
2147         layout.separator()
2148
2149         layout.operator("rigidbody.shape_change", text="Change Shape")
2150         layout.operator("rigidbody.mass_calculate", text="Calculate Mass")
2151         layout.operator("rigidbody.object_settings_copy", text="Copy from Active")
2152         layout.operator("object.visual_transform_apply", text="Apply Transformation")
2153         layout.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
2154
2155         layout.separator()
2156
2157         layout.operator("rigidbody.connect", text="Connect")
2158
2159
2160 class VIEW3D_MT_object_clear(Menu):
2161     bl_label = "Clear"
2162
2163     def draw(self, _context):
2164         layout = self.layout
2165
2166         layout.operator("object.location_clear", text="Location").clear_delta = False
2167         layout.operator("object.rotation_clear", text="Rotation").clear_delta = False
2168         layout.operator("object.scale_clear", text="Scale").clear_delta = False
2169
2170         layout.separator()
2171
2172         layout.operator("object.origin_clear", text="Origin")
2173
2174
2175 class VIEW3D_MT_object_context_menu(Menu):
2176     bl_label = "Object Context Menu"
2177
2178     def draw(self, context):
2179
2180         layout = self.layout
2181         view = context.space_data
2182
2183         obj = context.object
2184         is_eevee = context.scene.render.engine == 'BLENDER_EEVEE'
2185
2186         selected_objects_len = len(context.selected_objects)
2187
2188         # If nothing is selected
2189         # (disabled for now until it can be made more useful).
2190         '''
2191         if selected_objects_len == 0:
2192
2193             layout.menu("VIEW3D_MT_add", text="Add", text_ctxt=i18n_contexts.operator_default)
2194             layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
2195
2196             return
2197         '''
2198
2199         # If something is selected
2200         if obj is not None and obj.type in {'MESH', 'CURVE', 'SURFACE'}:
2201             layout.operator("object.shade_smooth", text="Shade Smooth")
2202             layout.operator("object.shade_flat", text="Shade Flat")
2203
2204             layout.separator()
2205
2206         if obj is None:
2207             pass
2208         elif obj.type == 'MESH':
2209             layout.operator_context = 'INVOKE_REGION_WIN'
2210             layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2211
2212             layout.operator_context = 'INVOKE_DEFAULT'
2213             # If more than one object is selected
2214             if selected_objects_len > 1:
2215                 layout.operator("object.join")
2216
2217             layout.separator()
2218
2219         elif obj.type == 'CAMERA':
2220             layout.operator_context = 'INVOKE_REGION_WIN'
2221
2222             if obj.data.type == 'PERSP':
2223                 props = layout.operator("wm.context_modal_mouse", text="Camera Lens Angle")
2224                 props.data_path_iter = "selected_editable_objects"
2225                 props.data_path_item = "data.lens"
2226                 props.input_scale = 0.1
2227                 if obj.data.lens_unit == 'MILLIMETERS':
2228                     props.header_text = "Camera Lens Angle: %.1fmm"
2229                 else:
2230                     props.header_text = "Camera Lens Angle: %.1f\u00B0"
2231
2232             else:
2233                 props = layout.operator("wm.context_modal_mouse", text="Camera Lens Scale")
2234                 props.data_path_iter = "selected_editable_objects"
2235                 props.data_path_item = "data.ortho_scale"
2236                 props.input_scale = 0.01
2237                 props.header_text = "Camera Lens Scale: %.3f"
2238
2239             if not obj.data.dof_object:
2240                 if view and view.camera == obj and view.region_3d.view_perspective == 'CAMERA':
2241                     props = layout.operator("ui.eyedropper_depth", text="DOF Distance (Pick)")
2242                 else:
2243                     props = layout.operator("wm.context_modal_mouse", text="DOF Distance")
2244                     props.data_path_iter = "selected_editable_objects"
2245                     props.data_path_item = "data.dof_distance"
2246                     props.input_scale = 0.02
2247                     props.header_text = "DOF Distance: %.3f"
2248
2249             layout.separator()
2250
2251         elif obj.type in {'CURVE', 'FONT'}:
2252             layout.operator_context = 'INVOKE_REGION_WIN'
2253
2254             props = layout.operator("wm.context_modal_mouse", text="Extrude Size")
2255             props.data_path_iter = "selected_editable_objects"
2256             props.data_path_item = "data.extrude"
2257             props.input_scale = 0.01
2258             props.header_text = "Extrude Size: %.3f"
2259
2260             props = layout.operator("wm.context_modal_mouse", text="Width Size")
2261             props.data_path_iter = "selected_editable_objects"
2262             props.data_path_item = "data.offset"
2263             props.input_scale = 0.01
2264             props.header_text = "Width Size: %.3f"
2265
2266             layout.separator()
2267
2268             layout.operator("object.convert", text="Convert to Mesh").target = 'MESH'
2269             layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2270
2271             layout.separator()
2272
2273         elif obj.type == 'GPENCIL':
2274             layout.operator("gpencil.convert", text="Convert to Path").type = 'PATH'
2275             layout.operator("gpencil.convert", text="Convert to Bezier Curves").type = 'CURVE'
2276             layout.operator("gpencil.convert", text="Convert to Mesh").type = 'POLY'
2277
2278             layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2279
2280             layout.separator()
2281
2282         elif obj.type == 'EMPTY':
2283             layout.operator_context = 'INVOKE_REGION_WIN'
2284
2285             props = layout.operator("wm.context_modal_mouse", text="Empty Draw Size")
2286             props.data_path_iter = "selected_editable_objects"
2287             props.data_path_item = "empty_display_size"
2288             props.input_scale = 0.01
2289             props.header_text = "Empty Draw Size: %.3f"
2290
2291             layout.separator()
2292
2293         elif obj.type == 'LIGHT':
2294             light = obj.data
2295
2296             layout.operator_context = 'INVOKE_REGION_WIN'
2297
2298             props = layout.operator("wm.context_modal_mouse", text="Energy")
2299             props.data_path_iter = "selected_editable_objects"
2300             props.data_path_item = "data.energy"
2301             props.header_text = "Light Energy: %.3f"
2302
2303             if light.type == 'AREA':
2304                 props = layout.operator("wm.context_modal_mouse", text="Size X")
2305                 props.data_path_iter = "selected_editable_objects"
2306                 props.data_path_item = "data.size"
2307                 props.header_text = "Light Size X: %.3f"
2308
2309                 if light.shape in {'RECTANGLE', 'ELLIPSE'}:
2310                     props = layout.operator("wm.context_modal_mouse", text="Size Y")
2311                     props.data_path_iter = "selected_editable_objects"
2312                     props.data_path_item = "data.size_y"
2313                     props.header_text = "Light Size Y: %.3f"
2314
2315             elif light.type in {'SPOT', 'POINT', 'SUN'}:
2316                 props = layout.operator("wm.context_modal_mouse", text="Radius")
2317                 props.data_path_iter = "selected_editable_objects"
2318                 props.data_path_item = "data.shadow_soft_size"
2319                 props.header_text = "Light Radius: %.3f"
2320
2321             if light.type == 'SPOT':
2322                 layout.separator()
2323
2324                 props = layout.operator("wm.context_modal_mouse", text="Spot Size")
2325                 props.data_path_iter = "selected_editable_objects"
2326                 props.data_path_item = "data.spot_size"
2327                 props.input_scale = 0.01
2328                 props.header_text = "Spot Size: %.2f"
2329
2330                 props = layout.operator("wm.context_modal_mouse", text="Spot Blend")
2331                 props.data_path_iter = "selected_editable_objects"
2332                 props.data_path_item = "data.spot_blend"
2333                 props.input_scale = -0.01
2334                 props.header_text = "Spot Blend: %.2f"
2335
2336             layout.separator()
2337
2338         layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
2339         layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
2340
2341         layout.separator()
2342
2343         layout.operator("object.duplicate_move", icon='DUPLICATE')
2344         layout.operator("object.duplicate_move_linked")
2345
2346         layout.separator()
2347
2348         props = layout.operator("wm.call_panel", text="Rename Active Object...")
2349         props.name = "TOPBAR_PT_name"
2350         props.keep_open = False
2351
2352         layout.separator()
2353
2354         layout.menu("VIEW3D_MT_mirror")
2355         layout.menu("VIEW3D_MT_snap")
2356         layout.menu("VIEW3D_MT_object_parent")
2357         layout.operator_context = 'INVOKE_REGION_WIN'
2358
2359         if view and view.local_view:
2360             layout.operator("view3d.localview_remove_from")
2361         else:
2362             layout.operator("object.move_to_collection")
2363
2364         layout.separator()
2365
2366         layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
2367
2368         layout.separator()
2369
2370         layout.operator_context = 'EXEC_DEFAULT'
2371         layout.operator("object.delete", text="Delete").use_global = False
2372
2373
2374 class VIEW3D_MT_object_shading(Menu):
2375     # XXX, this menu is a place to store shading operator in object mode
2376     bl_label = "Shading"
2377
2378     def draw(self, _context):
2379         layout = self.layout
2380         layout.operator("object.shade_smooth", text="Smooth")
2381         layout.operator("object.shade_flat", text="Flat")
2382
2383
2384 class VIEW3D_MT_object_apply(Menu):
2385     bl_label = "Apply"
2386
2387     def draw(self, _context):
2388         layout = self.layout
2389
2390         props = layout.operator("object.transform_apply", text="Location", text_ctxt=i18n_contexts.default)
2391         props.location, props.rotation, props.scale = True, False, False
2392
2393         props = layout.operator("object.transform_apply", text="Rotation", text_ctxt=i18n_contexts.default)
2394         props.location, props.rotation, props.scale = False, True, False
2395
2396         props = layout.operator("object.transform_apply", text="Scale", text_ctxt=i18n_contexts.default)
2397         props.location, props.rotation, props.scale = False, False, True
2398
2399         props = layout.operator("object.transform_apply", text="All Transforms", text_ctxt=i18n_contexts.default)
2400         props.location, props.rotation, props.scale = True, True, True
2401
2402         props = layout.operator("object.transform_apply", text="Rotation & Scale", text_ctxt=i18n_contexts.default)
2403         props.location, props.rotation, props.scale = False, True, True
2404
2405         layout.separator()
2406
2407         layout.operator(
2408             "object.transforms_to_deltas",
2409             text="Location to Deltas",
2410             text_ctxt=i18n_contexts.default,
2411         ).mode = 'LOC'
2412         layout.operator(
2413             "object.transforms_to_deltas",
2414             text="Rotation to Deltas",
2415             text_ctxt=i18n_contexts.default,
2416         ).mode = 'ROT'
2417         layout.operator(
2418             "object.transforms_to_deltas",
2419             text="Scale to Deltas",
2420             text_ctxt=i18n_contexts.default,
2421         ).mode = 'SCALE'
2422
2423         layout.operator(
2424             "object.transforms_to_deltas",
2425             text="All Transforms to Deltas",
2426             text_ctxt=i18n_contexts.default,
2427         ).mode = 'ALL'
2428         layout.operator("object.anim_transforms_to_deltas")
2429
2430         layout.separator()
2431
2432         layout.operator(
2433             "object.visual_transform_apply",
2434             text="Visual Transform",
2435             text_ctxt=i18n_contexts.default,
2436         )
2437         layout.operator(
2438             "object.convert",
2439             text="Visual Geometry to Mesh",
2440             text_ctxt=i18n_contexts.default,
2441         ).target = 'MESH'
2442         layout.operator("object.duplicates_make_real")
2443
2444
2445 class VIEW3D_MT_object_parent(Menu):
2446     bl_label = "Parent"
2447
2448     def draw(self, _context):
2449         layout = self.layout
2450
2451         layout.operator_enum("object.parent_set", "type")
2452
2453         layout.separator()
2454
2455         layout.operator_enum("object.parent_clear", "type")
2456
2457
2458 class VIEW3D_MT_object_track(Menu):
2459     bl_label = "Track"
2460
2461     def draw(self, _context):
2462         layout = self.layout
2463
2464         layout.operator_enum("object.track_set", "type")
2465
2466         layout.separator()
2467
2468         layout.operator_enum("object.track_clear", "type")
2469
2470
2471 class VIEW3D_MT_object_collection(Menu):
2472     bl_label = "Collection"
2473
2474     def draw(self, _context):
2475         layout = self.layout
2476
2477         layout.operator("object.move_to_collection")
2478         layout.operator("object.link_to_collection")
2479
2480         layout.separator()
2481
2482         layout.operator("collection.create")
2483         # layout.operator_menu_enum("collection.objects_remove", "collection")  # BUGGY
2484         layout.operator("collection.objects_remove")
2485         layout.operator("collection.objects_remove_all")
2486
2487         layout.separator()
2488
2489         layout.operator("collection.objects_add_active")
2490         layout.operator("collection.objects_remove_active")
2491
2492
2493 class VIEW3D_MT_object_constraints(Menu):
2494     bl_label = "Constraints"
2495
2496     def draw(self, _context):
2497         layout = self.layout
2498
2499         layout.operator("object.constraint_add_with_targets")
2500         layout.operator("object.constraints_copy")
2501
2502         layout.separator()
2503
2504         layout.operator("object.constraints_clear")
2505
2506
2507 class VIEW3D_MT_object_quick_effects(Menu):
2508     bl_label = "Quick Effects"
2509
2510     def draw(self, _context):
2511         layout = self.layout
2512
2513         layout.operator("object.quick_fur")
2514         layout.operator("object.quick_explode")
2515         layout.operator("object.quick_smoke")
2516         layout.operator("object.quick_fluid")
2517
2518
2519 class VIEW3D_MT_object_showhide(Menu):
2520     bl_label = "Show/Hide"
2521
2522     def draw(self, _context):
2523         layout = self.layout
2524
2525         layout.operator("object.hide_view_clear")
2526
2527         layout.separator()
2528
2529         layout.operator("object.hide_view_set", text="Hide Selected").unselected = False
2530         layout.operator("object.hide_view_set", text="Hide Unselected").unselected = True
2531
2532
2533 class VIEW3D_MT_make_single_user(Menu):
2534     bl_label = "Make Single User"
2535
2536     def draw(self, _context):
2537         layout = self.layout
2538
2539         props = layout.operator("object.make_single_user", text="Object")
2540         props.object = True
2541         props.obdata = props.material = props.animation = False
2542
2543         props = layout.operator("object.make_single_user", text="Object & Data")
2544         props.object = props.obdata = True
2545         props.material = props.animation = False
2546
2547         props = layout.operator("object.make_single_user", text="Object & Data & Materials")
2548         props.object = props.obdata = props.material = True
2549         props.animation = False
2550
2551         props = layout.operator("object.make_single_user", text="Materials")
2552         props.material = True
2553         props.object = props.obdata = props.animation = False
2554
2555         props = layout.operator("object.make_single_user", text="Object Animation")
2556         props.animation = True
2557         props.object = props.obdata = props.material = False
2558
2559
2560 class VIEW3D_MT_make_links(Menu):
2561     bl_label = "Make Links"
2562
2563     def draw(self, _context):
2564         layout = self.layout
2565         operator_context_default = layout.operator_context
2566
2567         if len(bpy.data.scenes) > 10:
2568             layout.operator_context = 'INVOKE_REGION_WIN'
2569             layout.operator("object.make_links_scene", text="Objects to Scene...", icon='OUTLINER_OB_EMPTY')
2570         else:
2571             layout.operator_context = 'EXEC_REGION_WIN'
2572             layout.operator_menu_enum("object.make_links_scene", "scene", text="Objects to Scene")
2573
2574         layout.separator()
2575
2576         layout.operator_context = operator_context_default
2577
2578         layout.operator_enum("object.make_links_data", "type")  # inline
2579
2580         layout.operator("object.join_uvs")  # stupid place to add this!
2581
2582
2583 class VIEW3D_MT_brush(Menu):
2584     bl_label = "Brush"
2585
2586     def draw(self, context):
2587         layout = self.layout
2588
2589         tool_settings = context.tool_settings
2590         settings = UnifiedPaintPanel.paint_settings(context)
2591         brush = getattr(settings, "brush", None)
2592
2593         ups = tool_settings.unified_paint_settings
2594         layout.prop(ups, "use_unified_size", text="Unified Size")
2595         layout.prop(ups, "use_unified_strength", text="Unified Strength")
2596         if context.image_paint_object or context.vertex_paint_object:
2597             layout.prop(ups, "use_unified_color", text="Unified Color")
2598         layout.separator()
2599
2600         # skip if no active brush
2601         if not brush:
2602             layout.label(text="No Brushes currently available", icon='INFO')
2603             return
2604
2605         # brush paint modes
2606         layout.menu("VIEW3D_MT_brush_paint_modes")
2607
2608         # brush tool
2609         if context.sculpt_object:
2610             layout.operator("brush.reset")
2611             layout.prop_menu_enum(brush, "sculpt_tool")
2612         elif context.image_paint_object:
2613             layout.prop_menu_enum(brush, "image_tool")
2614         elif context.vertex_paint_object:
2615             layout.prop_menu_enum(brush, "vertex_tool")
2616         elif context.weight_paint_object:
2617             layout.prop_menu_enum(brush, "weight_tool")
2618
2619         # TODO: still missing a lot of brush options here
2620
2621         # sculpt options
2622         if context.sculpt_object:
2623
2624             sculpt_tool = brush.sculpt_tool
2625
2626             layout.separator()
2627             layout.operator_menu_enum("brush.curve_preset", "shape", text="Curve Preset")
2628             layout.separator()
2629
2630             if sculpt_tool != 'GRAB':
2631                 layout.prop_menu_enum(brush, "stroke_method")
2632
2633                 if sculpt_tool in {'DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'}:
2634                     layout.prop_menu_enum(brush, "direction")
2635
2636                 if sculpt_tool == 'LAYER':
2637                     layout.prop(brush, "use_persistent")
2638                     layout.operator("sculpt.set_persistent_base")
2639
2640
2641 class VIEW3D_MT_brush_paint_modes(Menu):
2642     bl_label = "Enabled Modes"
2643
2644     def draw(self, context):
2645         layout = self.layout
2646
2647         settings = UnifiedPaintPanel.paint_settings(context)
2648         brush = settings.brush
2649
2650         layout.prop(brush, "use_paint_sculpt", text="Sculpt")
2651         layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt")
2652         layout.prop(brush, "use_paint_vertex", text="Vertex Paint")
2653         layout.prop(brush, "use_paint_weight", text="Weight Paint")
2654         layout.prop(brush, "use_paint_image", text="Texture Paint")
2655
2656
2657 class VIEW3D_MT_paint_vertex(Menu):
2658     bl_label = "Paint"
2659
2660     def draw(self, _context):
2661         layout = self.layout
2662
2663         layout.operator("paint.vertex_color_set")
2664         layout.operator("paint.vertex_color_smooth")
2665         layout.operator("paint.vertex_color_dirt")
2666         layout.operator("paint.vertex_color_from_weight")
2667
2668         layout.separator()
2669
2670         layout.operator("paint.vertex_color_invert", text="Invert")
2671         layout.operator("paint.vertex_color_levels", text="Levels")
2672         layout.operator("paint.vertex_color_hsv", text="Hue Saturation Value")
2673         layout.operator("paint.vertex_color_brightness_contrast", text="Bright/Contrast")
2674
2675
2676 class VIEW3D_MT_hook(Menu):
2677     bl_label = "Hooks"
2678
2679     def draw(self, context):
2680         layout = self.layout
2681         layout.operator_context = 'EXEC_AREA'
2682         layout.operator("object.hook_add_newob")
2683         layout.operator("object.hook_add_selob").use_bone = False
2684         layout.operator("object.hook_add_selob", text="Hook to Selected Object Bone").use_bone = True
2685
2686         if [mod.type == 'HOOK' for mod in context.active_object.modifiers]:
2687             layout.separator()
2688
2689             layout.operator_menu_enum("object.hook_assign", "modifier")
2690             layout.operator_menu_enum("object.hook_remove", "modifier")
2691
2692             layout.separator()
2693
2694             layout.operator_menu_enum("object.hook_select", "modifier")
2695             layout.operator_menu_enum("object.hook_reset", "modifier")
2696             layout.operator_menu_enum("object.hook_recenter", "modifier")
2697
2698
2699 class VIEW3D_MT_vertex_group(Menu):
2700     bl_label = "Vertex Groups"
2701
2702     def draw(self, context):
2703         layout = self.layout
2704
2705         layout.operator_context = 'EXEC_AREA'
2706         layout.operator("object.vertex_group_assign_new")
2707
2708         ob = context.active_object
2709         if ob.mode == 'EDIT' or (ob.mode == 'WEIGHT_PAINT' and ob.type == 'MESH' and ob.data.use_paint_mask_vertex):
2710             if ob.vertex_groups.active:
2711                 layout.separator()
2712
2713                 layout.operator("object.vertex_group_assign", text="Assign to Active Group")
2714                 layout.operator(
2715                     "object.vertex_group_remove_from",
2716                     text="Remove from Active Group",
2717                 ).use_all_groups = False
2718                 layout.operator("object.vertex_group_remove_from", text="Remove from All").use_all_groups = True
2719
2720         if ob.vertex_groups.active:
2721             layout.separator()
2722
2723             layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group")
2724             layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False
2725             layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True
2726
2727
2728 class VIEW3D_MT_paint_weight(Menu):
2729     bl_label = "Weights"
2730
2731     @staticmethod
2732     def draw_generic(layout, is_editmode=False):
2733
2734         if not is_editmode:
2735
2736             layout.operator("paint.weight_from_bones", text="Assign Automatic From Bones").type = 'AUTOMATIC'
2737             layout.operator("paint.weight_from_bones", text="Assign From Bone Envelopes").type = 'ENVELOPES'
2738
2739             layout.separator()
2740
2741         layout.operator("object.vertex_group_normalize_all", text="Normalize All")
2742         layout.operator("object.vertex_group_normalize", text="Normalize")
2743
2744         layout.separator()
2745
2746         layout.operator("object.vertex_group_mirror", text="Mirror")
2747         layout.operator("object.vertex_group_invert", text="Invert")
2748         layout.operator("object.vertex_group_clean", text="Clean")
2749
2750         layout.separator()
2751
2752         layout.operator("object.vertex_group_quantize", text="Quantize")
2753         layout.operator("object.vertex_group_levels", text="Levels")
2754         layout.operator("object.vertex_group_smooth", text="Smooth")
2755
2756         if not is_editmode:
2757             props = layout.operator("object.data_transfer", text="Transfer Weights")
2758             props.use_reverse_transfer = True
2759             props.data_type = 'VGROUP_WEIGHTS'
2760
2761         layout.operator("object.vertex_group_limit_total", text="Limit Total")
2762         layout.operator("object.vertex_group_fix", text="Fix Deforms")
2763
2764         if not is_editmode:
2765             layout.separator()
2766
2767             layout.operator("paint.weight_set")
2768
2769     def draw(self, _context):
2770         self.draw_generic(self.layout, is_editmode=False)
2771
2772
2773 class VIEW3D_MT_sculpt(Menu):
2774     bl_label = "Sculpt"
2775
2776     def draw(self, context):
2777         layout = self.layout
2778
2779         tool_settings = context.tool_settings
2780         sculpt = tool_settings.sculpt
2781
2782         layout.operator("sculpt.dynamic_topology_toggle", text="Toggle Dynamic Topology")
2783
2784         layout.separator()
2785
2786         layout.prop(sculpt, "use_symmetry_x")
2787         layout.prop(sculpt, "use_symmetry_y")
2788         layout.prop(sculpt, "use_symmetry_z")
2789
2790         layout.separator()
2791
2792         layout.prop(sculpt, "lock_x")
2793         layout.prop(sculpt, "lock_y")
2794         layout.prop(sculpt, "lock_z")
2795
2796         layout.separator()
2797
2798         layout.prop(sculpt, "use_threaded", text="Threaded Sculpt")
2799         layout.prop(sculpt, "show_low_resolution")
2800         layout.prop(sculpt, "show_brush")
2801         layout.prop(sculpt, "use_deform_only")
2802         layout.prop(sculpt, "show_diffuse_color")
2803         layout.prop(sculpt, "show_mask")
2804
2805
2806 class VIEW3D_MT_hide_mask(Menu):
2807     bl_label = "Hide/Mask"
2808
2809     def draw(self, _context):
2810         layout = self.layout
2811
2812         props = layout.operator("paint.hide_show", text="Show All")
2813         props.action = 'SHOW'
2814         props.area = 'ALL'
2815
2816         props = layout.operator("paint.hide_show", text="Hide Bounding Box")
2817         props.action = 'HIDE'
2818         props.area = 'INSIDE'
2819
2820         props = layout.operator("paint.hide_show", text="Show Bounding Box")
2821         props.action = 'SHOW'
2822         props.area = 'INSIDE'
2823
2824         props = layout.operator("paint.hide_show", text="Hide Masked")
2825         props.area = 'MASKED'
2826         props.action = 'HIDE'
2827
2828         layout.separator()
2829
2830         props = layout.operator("paint.mask_flood_fill", text="Invert Mask")
2831         props.mode = 'INVERT'
2832
2833         props = layout.operator("paint.mask_flood_fill", text="Fill Mask")
2834         props.mode = 'VALUE'
2835         props.value = 1
2836
2837         props = layout.operator("paint.mask_flood_fill", text="Clear Mask")
2838         props.mode = 'VALUE'
2839         props.value = 0
2840
2841         props = layout.operator("view3d.select_box", text="Box Mask")
2842         props = layout.operator("paint.mask_lasso_gesture", text="Lasso Mask")
2843
2844
2845 class VIEW3D_MT_particle(Menu):
2846     bl_label = "Particle"
2847
2848     def draw(self, context):
2849         layout = self.layout
2850         tool_settings = context.tool_settings
2851
2852         particle_edit = tool_settings.particle_edit
2853
2854         layout.operator("particle.mirror")
2855
2856         layout.operator("particle.remove_doubles")
2857
2858         layout.separator()
2859
2860         if particle_edit.select_mode == 'POINT':
2861             layout.operator("particle.subdivide")
2862
2863         layout.operator("particle.unify_length")
2864         layout.operator("particle.rekey")
2865         layout.operator("particle.weight_set")
2866
2867         layout.separator()
2868
2869         layout.menu("VIEW3D_MT_particle_showhide")
2870
2871         layout.separator()
2872
2873         layout.operator("particle.delete")
2874
2875
2876 class VIEW3D_MT_particle_context_menu(Menu):
2877     bl_label = "Particle Context Menu"
2878
2879     def draw(self, context):
2880         layout = self.layout
2881         tool_settings = context.tool_settings
2882
2883         particle_edit = tool_settings.particle_edit
2884
2885         layout.operator("particle.rekey")
2886
2887         layout.separator()
2888
2889         layout.operator("particle.delete")
2890
2891         layout.separator()
2892
2893         layout.operator("particle.remove_doubles")
2894         layout.operator("particle.unify_length")
2895
2896         if particle_edit.select_mode == 'POINT':
2897             layout.operator("particle.subdivide")
2898
2899         layout.operator("particle.weight_set")
2900
2901         layout.separator()
2902
2903         layout.operator("particle.mirror")
2904
2905         if particle_edit.select_mode == 'POINT':
2906             layout.separator()
2907
2908             layout.operator("particle.select_all", text="All").action = 'SELECT'
2909             layout.operator("particle.select_all", text="None").action = 'DESELECT'
2910             layout.operator("particle.select_all", text="Invert").action = 'INVERT'
2911
2912             layout.separator()
2913
2914             layout.operator("particle.select_roots")
2915             layout.operator("particle.select_tips")
2916
2917             layout.separator()
2918
2919             layout.operator("particle.select_random")
2920
2921             layout.separator()
2922
2923             layout.operator("particle.select_more")
2924             layout.operator("particle.select_less")
2925
2926             layout.separator()
2927
2928             layout.operator("particle.select_linked")
2929
2930
2931 class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu):
2932     _operator_name = "particle"
2933
2934
2935 class VIEW3D_MT_pose(Menu):
2936     bl_label = "Pose"
2937
2938     def draw(self, _context):
2939         layout = self.layout
2940
2941         layout.menu("VIEW3D_MT_transform_armature")
2942
2943         layout.menu("VIEW3D_MT_pose_transform")
2944         layout.menu("VIEW3D_MT_pose_apply")
2945
2946         layout.menu("VIEW3D_MT_snap")
2947
2948         layout.separator()
2949
2950         layout.menu("VIEW3D_MT_object_animation")
2951
2952         layout.separator()
2953
2954         layout.menu("VIEW3D_MT_pose_slide")
2955         layout.menu("VIEW3D_MT_pose_propagate")
2956
2957         layout.separator()
2958
2959         layout.operator("pose.copy", icon='COPYDOWN')
2960         layout.operator("pose.paste", icon='PASTEDOWN').flipped = False
2961         layout.operator("pose.paste", icon='PASTEFLIPDOWN', text="Paste Pose Flipped").flipped = True
2962
2963         layout.separator()
2964
2965         layout.menu("VIEW3D_MT_pose_library")
2966         layout.menu("VIEW3D_MT_pose_motion")
2967         layout.menu("VIEW3D_MT_pose_group")
2968
2969         layout.separator()
2970
2971         layout.menu("VIEW3D_MT_object_parent")
2972         layout.menu("VIEW3D_MT_pose_ik")
2973         layout.menu("VIEW3D_MT_pose_constraints")
2974
2975         layout.separator()
2976
2977         layout.operator_context = 'EXEC_AREA'
2978         layout.operator("pose.autoside_names", text="AutoName Left/Right").axis = 'XAXIS'
2979         layout.operator("pose.autoside_names", text="AutoName Front/Back").axis = 'YAXIS'
2980         layout.operator("pose.autoside_names", text="AutoName Top/Bottom").axis = 'ZAXIS'
2981
2982         layout.operator("pose.flip_names")
2983
2984         layout.operator("pose.quaternions_flip")
2985
2986         layout.separator()
2987
2988         layout.operator_context = 'INVOKE_AREA'
2989         layout.operator("armature.armature_layers", text="Change Armature Layers...")
2990         layout.operator("pose.bone_layers", text="Change Bone Layers...")
2991
2992         layout.separator()
2993
2994         layout.menu("VIEW3D_MT_pose_showhide")
2995         layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings")
2996
2997
2998 class VIEW3D_MT_pose_transform(Menu):
2999     bl_label = "Clear Transform"
3000
3001     def draw(self, _context):
3002         layout = self.layout
3003
3004         layout.operator("pose.transforms_clear", text="All")
3005
3006         layout.separator()
3007
3008         layout.operator("pose.loc_clear", text="Location")
3009         layout.operator("pose.rot_clear", text="Rotation")
3010         layout.operator("pose.scale_clear", text="Scale")
3011
3012         layout.separator()
3013
3014         layout.operator("pose.user_transforms_clear", text="Reset Unkeyed")
3015
3016
3017 class VIEW3D_MT_pose_slide(Menu):
3018     bl_label = "In-Betweens"
3019
3020     def draw(self, _context):
3021         layout = self.layout
3022
3023         layout.operator("pose.push_rest")
3024         layout.operator("pose.relax_rest")
3025         layout.operator("pose.push")
3026         layout.operator("pose.relax")
3027         layout.operator("pose.breakdown")
3028
3029
3030 class VIEW3D_MT_pose_propagate(Menu):
3031     bl_label = "Propagate"
3032
3033     def draw(self, _context):
3034         layout = self.layout
3035
3036         layout.operator("pose.propagate").mode = 'WHILE_HELD'
3037
3038         layout.separator()
3039
3040         layout.operator("pose.propagate", text="To Next Keyframe").mode = 'NEXT_KEY'
3041         layout.operator("pose.propagate", text="To Last Keyframe (Make Cyclic)").mode = 'LAST_KEY'
3042
3043         layout.separator()
3044
3045         layout.operator("pose.propagate", text="On Selected Keyframes").mode = 'SELECTED_KEYS'
3046
3047         layout.separator()
3048
3049         layout.operator("pose.propagate", text="On Selected Markers").mode = 'SELECTED_MARKERS'
3050
3051
3052 class VIEW3D_MT_pose_library(Menu):
3053     bl_label = "Pose Library"
3054
3055     def draw(self, _context):
3056         layout = self.layout
3057
3058         layout.operator("poselib.browse_interactive", text="Browse Poses...")
3059
3060         layout.separator()
3061
3062         layout.operator("poselib.pose_add", text="Add Pose...")
3063         layout.operator("poselib.pose_rename", text="Rename Pose...")
3064         layout.operator("poselib.pose_remove", text="Remove Pose...")
3065
3066
3067 class VIEW3D_MT_pose_motion(Menu):
3068     bl_label = "Motion Paths"
3069
3070     def draw(self, _context):
3071         layout = self.layout
3072
3073         layout.operator("pose.paths_calculate", text="Calculate")
3074         layout.operator("pose.paths_clear", text="Clear")
3075
3076
3077 class VIEW3D_MT_pose_group(Menu):
3078     bl_label = "Bone Groups"
3079
3080     def draw(self, context):
3081         layout = self.layout
3082
3083         pose = context.active_object.pose
3084
3085         layout.operator_context = 'EXEC_AREA'
3086         layout.operator("pose.group_assign", text="Assign to New Group").type = 0
3087
3088         if pose.bone_groups:
3089             active_group = pose.bone_groups.active_index + 1
3090             layout.operator("pose.group_assign", text="Assign to Group").type = active_group
3091
3092             layout.separator()
3093
3094             # layout.operator_context = 'INVOKE_AREA'
3095             layout.operator("pose.group_unassign")
3096             layout.operator("pose.group_remove")
3097
3098
3099 class VIEW3D_MT_pose_ik(Menu):
3100     bl_label = "Inverse Kinematics"
3101
3102     def draw(self, _context):
3103         layout = self.layout
3104
3105         layout.operator("pose.ik_add")
3106         layout.operator("pose.ik_clear")
3107
3108
3109 class VIEW3D_MT_pose_constraints(Menu):
3110     bl_label = "Constraints"
3111
3112     def draw(self, _context):
3113         layout = self.layout
3114
3115         layout.operator("pose.constraint_add_with_targets", text="Add (With Targets)...")
3116         layout.operator("pose.constraints_copy")
3117         layout.operator("pose.constraints_clear")
3118
3119
3120 class VIEW3D_MT_pose_showhide(ShowHideMenu, Menu):
3121     _operator_name = "pose"
3122
3123
3124 class VIEW3D_MT_pose_apply(Menu):
3125     bl_label = "Apply"
3126
3127     def draw(self, _context):
3128         layout = self.layout
3129
3130         layout.operator("pose.armature_apply").selected = False
3131         layout.operator("pose.armature_apply", text="Apply Selected as Rest Pose").selected = True
3132         layout.operator("pose.visual_transform_apply")
3133
3134         layout.separator()
3135
3136         props = layout.operator("object.assign_property_defaults")
3137         props.process_bones = True
3138
3139
3140 class VIEW3D_MT_pose_context_menu(Menu):
3141     bl_label = "Pose Context Menu"
3142
3143     def draw(self, _context):
3144         layout = self.layout
3145
3146         layout.operator_context = 'INVOKE_REGION_WIN'
3147
3148         layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
3149
3150         layout.separator()
3151
3152         layout.operator("pose.copy", icon='COPYDOWN')
3153         layout.operator("pose.paste", icon='PASTEDOWN').flipped = False
3154         layout.operator("pose.paste", icon='PASTEFLIPDOWN', text="Paste X-Flipped Pose").flipped = True
3155
3156         layout.separator()
3157
3158         props = layout.operator("wm.call_panel", text="Rename Active Bone...")
3159         props.name = "TOPBAR_PT_name"
3160         props.keep_open = False
3161
3162         layout.separator()
3163
3164         layout.operator("pose.paths_calculate", text="Calculate")
3165         layout.operator("pose.paths_clear", text="Clear")
3166
3167         layout.separator()
3168
3169         layout.operator("pose.push")
3170         layout.operator("pose.relax")
3171         layout.operator("pose.breakdown")
3172
3173         layout.separator()
3174
3175         layout.operator("pose.paths_calculate", text="Calculate Motion Paths")
3176         layout.operator("pose.paths_clear", text="Clear Motion Paths")
3177
3178         layout.separator()
3179
3180         layout.operator("pose.hide").unselected = False
3181         layout.operator("pose.reveal")
3182
3183         layout.separator()
3184
3185         layout.operator("pose.user_transforms_clear")
3186
3187
3188 class BoneOptions:
3189     def draw(self, context):
3190         layout = self.layout
3191
3192         options = [
3193             "show_wire",
3194             "use_deform",
3195             "use_envelope_multiply",
3196             "use_inherit_rotation",
3197             "use_inherit_scale",
3198         ]
3199
3200         if context.mode == 'EDIT_ARMATURE':
3201             bone_props = bpy.types.EditBone.bl_rna.properties
3202             data_path_iter = "selected_bones"
3203             opt_suffix = ""
3204             options.append("lock")
3205         else:  # pose-mode
3206             bone_props = bpy.types.Bone.bl_rna.properties
3207             data_path_iter = "selected_pose_bones"
3208             opt_suffix = "bone."
3209
3210         for opt in options:
3211             props = layout.operator("wm.context_collection_boolean_set", text=bone_props[opt].name,
3212                                     text_ctxt=i18n_contexts.default)
3213             props.data_path_iter = data_path_iter
3214             props.data_path_item = opt_suffix + opt
3215             props.type = self.type
3216
3217
3218 class VIEW3D_MT_bone_options_toggle(Menu, BoneOptions):
3219     bl_label = "Toggle Bone Options"
3220     type = 'TOGGLE'
3221
3222
3223 class VIEW3D_MT_bone_options_enable(Menu, BoneOptions):
3224     bl_label = "Enable Bone Options"
3225     type = 'ENABLE'
3226
3227
3228 class VIEW3D_MT_bone_options_disable(Menu, BoneOptions):
3229     bl_label = "Disable Bone Options"
3230     type = 'DISABLE'
3231
3232
3233 # ********** Edit Menus, suffix from ob.type **********
3234
3235
3236 class VIEW3D_MT_edit_mesh(Menu):
3237     bl_label = "Mesh"
3238
3239     def draw(self, _context):
3240         layout = self.layout
3241
3242         with_bullet = bpy.app.build_options.bullet
3243
3244         layout.menu("VIEW3D_MT_transform")
3245         layout.menu("VIEW3D_MT_mirror")
3246         layout.menu("VIEW3D_MT_snap")
3247
3248         layout.separator()
3249
3250         layout.operator("mesh.duplicate_move", text="Duplicate")
3251         layout.menu("VIEW3D_MT_edit_mesh_extrude")
3252         layout.operator("mesh.split")
3253         layout.operator("mesh.bisect")
3254         layout.operator("mesh.knife_project")
3255
3256         if with_bullet:
3257             layout.operator("mesh.convex_hull")
3258
3259         layout.separator()
3260
3261         layout.operator("mesh.symmetrize")
3262         layout.operator("mesh.symmetry_snap")
3263
3264         layout.separator()
3265
3266         layout.menu("VIEW3D_MT_edit_mesh_normals")
3267         layout.menu("VIEW3D_MT_edit_mesh_shading")
3268         layout.menu("VIEW3D_MT_edit_mesh_weights")
3269         layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
3270
3271         layout.separator()
3272
3273         layout.menu("VIEW3D_MT_edit_mesh_showhide")
3274         layout.operator_menu_enum("mesh.separate", "type")
3275         layout.menu("VIEW3D_MT_edit_mesh_clean")
3276
3277         layout.separator()
3278
3279         layout.menu("VIEW3D_MT_edit_mesh_delete")
3280
3281
3282 class VIEW3D_MT_edit_mesh_context_menu(Menu):
3283     bl_label = ""
3284
3285     def draw(self, context):
3286
3287         def count_selected_items_for_objects_in_mode():
3288             selected_verts_len = 0
3289             selected_edges_len = 0
3290             selected_faces_len = 0
3291             for ob in context.objects_in_mode_unique_data:
3292                 v, e, f = ob.data.count_selected_items()
3293                 selected_verts_len += v
3294                 selected_edges_len += e
3295                 selected_faces_len += f
3296             return (selected_verts_len, selected_edges_len, selected_faces_len)
3297
3298         is_vert_mode, is_edge_mode, is_face_mode = context.tool_settings.mesh_select_mode
3299         selected_verts_len, selected_edges_len, selected_faces_len = count_selected_items_for_objects_in_mode()
3300
3301         del count_selected_items_for_objects_in_mode
3302
3303         layout = self.layout
3304
3305         layout.operator_context = 'INVOKE_REGION_WIN'
3306
3307         # If nothing is selected
3308         # (disabled for now until it can be made more useful).
3309         '''
3310         # If nothing is selected
3311         if not (selected_verts_len or selected_edges_len or selected_faces_len):
3312             layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
3313
3314             return
3315         '''
3316
3317         # Else something is selected
3318
3319         row = layout.row()
3320
3321         if is_vert_mode:
3322             col = row.column()
3323
3324             col.label(text="Vertex Context Menu", icon='VERTEXSEL')
3325             col.separator()
3326
3327             # Additive Operators
3328             col.operator("mesh.subdivide", text="Subdivide")
3329
3330             col.separator()
3331
3332             col.operator("mesh.extrude_vertices_move", text="Extrude Vertices")
3333             col.operator("mesh.bevel", text="Bevel Vertices").vertex_only = True
3334
3335             if selected_verts_len > 1:
3336                 col.separator()
3337                 col.operator("mesh.edge_face_add", text="New Edge/Face from Vertices")
3338                 col.operator("mesh.vert_connect_path", text="Connect Vertex Path")
3339                 col.operator("mesh.vert_connect", text="Connect Vertex Pairs")
3340
3341             col.separator()
3342
3343             # Deform Operators
3344             col.operator("transform.push_pull", text="Push/Pull")
3345             col.operator("transform.shrink_fatten", text="Shrink/Fatten")
3346             col.operator("transform.shear", text="Shear")
3347             col.operator("transform.vert_slide", text="Slide Vertices")
3348             col.operator("transform.vertex_random", text="Randomize Vertices")
3349             col.operator("mesh.vertices_smooth", text="Smooth Vertices")
3350             col.operator("mesh.vertices_smooth_laplacian", text="Smooth Laplacian")
3351
3352             col.separator()
3353
3354             col.menu("VIEW3D_MT_mirror", text="Mirror Vertices")
3355             col.menu("VIEW3D_MT_snap", text="Snap Vertices")
3356
3357             col.separator()
3358
3359             # Removal Operators
3360             if selected_verts_len > 1:
3361                 col.menu("VIEW3D_MT_edit_mesh_merge", text="Merge Vertices")
3362             col.operator("mesh.split")
3363             col.operator_menu_enum("mesh.separate", "type")
3364             col.operator("mesh.dissolve_verts")
3365             col.operator("mesh.delete", text="Delete Vertices").type = 'VERT'
3366
3367         if is_edge_mode:
3368             render = context.scene.render
3369
3370             col = row.column()
3371             col.label(text="Edge Context Menu", icon='EDGESEL')
3372             col.separator()
3373
3374             # Additive Operators
3375             col.operator("mesh.subdivide", text="Subdivide")
3376
3377             col.separator()
3378
3379             col.operator("mesh.extrude_edges_move", text="Extrude Edges")
3380             col.operator("mesh.bevel", text="Bevel Edges").vertex_only = False
3381             if selected_edges_len >= 2:
3382                 col.operator("mesh.bridge_edge_loops")
3383             if selected_edges_len >= 1:
3384                 col.operator("mesh.edge_face_add", text="New Face from Edges")
3385             if selected_edges_len >= 2:
3386                 col.operator("mesh.fill")
3387
3388             col.separator()
3389
3390             col.operator("mesh.loopcut_slide")
3391             col.operator("mesh.offset_edge_loops_slide")
3392             col.operator("mesh.knife_tool")
3393             col.operator("mesh.bisect")
3394             col.operator("mesh.bridge_edge_loops", text="Bridge Edge Loops")
3395
3396             col.separator()
3397
3398             # Deform Operators
3399             col.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
3400             col.operator("transform.edge_slide")
3401             col.operator("mesh.edge_split")
3402
3403             col.separator()
3404
3405             # Edge Flags
3406             col.operator("transform.edge_crease")
3407             col.operator("transform.edge_bevelweight")
3408
3409             col.separator()
3410
3411             col.operator("mesh.mark_seam").clear = False
3412             col.operator("mesh.mark_seam", text="Clear Seam").clear = True
3413
3414             col.separator()
3415
3416             col.operator("mesh.mark_sharp")
3417             col.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
3418
3419             if render.use_freestyle:
3420                 col.separator()
3421
3422                 col.operator("mesh.mark_freestyle_edge").clear = False
3423                 col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
3424
3425             col.separator()
3426
3427             # Removal Operators
3428             col.operator("mesh.unsubdivide")
3429             col.operator("mesh.split")
3430             col.operator_menu_enum("mesh.separate", "type")
3431             col.operator("mesh.dissolve_edges")
3432             col.operator("mesh.delete", text="Delete Edges").type = 'EDGE'
3433
3434         if is_face_mode:
3435             col = row.column()
3436
3437             col.label(text="Face Context Menu", icon='FACESEL')
3438             col.separator()
3439
3440             # Additive Operators
3441             col.operator("mesh.subdivide", text="Subdivide")
3442
3443             col.separator()
3444
3445             col.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
3446             col.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals")
3447             col.operator("mesh.extrude_faces_move", text="Extrude Individual Faces")
3448
3449             col.operator("mesh.inset")
3450             col.operator("mesh.poke")
3451
3452             if selected_faces_len >= 2:
3453                 col.operator("mesh.bridge_edge_loops", text="Bridge Faces")
3454
3455             col.separator()
3456
3457             # Modify Operators
3458             col.menu("VIEW3D_MT_uv_map", text="UV Unwrap Faces")
3459
3460             col.separator()
3461
3462             props = col.operator("mesh.quads_convert_to_tris")
3463             props.quad_method = props.ngon_method = 'BEAUTY'
3464             col.operator("mesh.tris_convert_to_quads")
3465
3466             col.separator()
3467
3468             col.operator("mesh.faces_shade_smooth")
3469             col.operator("mesh.faces_shade_flat")
3470
3471             col.separator()
3472
3473             # Removal Operators
3474             col.operator("mesh.unsubdivide")
3475             col.operator("mesh.split")
3476             col.operator_menu_enum("mesh.separate", "type")
3477             col.operator("mesh.dissolve_faces")
3478             col.operator("mesh.delete", text="Delete Faces").type = 'FACE'
3479
3480
3481 class VIEW3D_MT_edit_mesh_select_mode(Menu):
3482     bl_label = "Mesh Select Mode"
3483
3484     def draw(self, _context):
3485         layout = self.layout
3486
3487         layout.operator_context = 'INVOKE_REGION_WIN'
3488         layout.operator("mesh.select_mode", text="Vertex", icon='VERTEXSEL').type = 'VERT'
3489         layout.operator("mesh.select_mode", text="Edge", icon='EDGESEL').type = 'EDGE'
3490         layout.operator("mesh.select_mode", text="Face", icon='FACESEL').type = 'FACE'
3491
3492
3493 class VIEW3D_MT_edit_mesh_extrude(Menu):
3494     bl_label = "Extrude"
3495
3496     _extrude_funcs = {
3497         'VERT': lambda layout:
3498         layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices"),
3499         'EDGE': lambda layout:
3500         layout.operator("mesh.extrude_edges_move", text="Extrude Edges"),
3501         'REGION': lambda layout:
3502         layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces"),
3503         'REGION_VERT_NORMAL': lambda layout:
3504         layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"),
3505         'FACE': lambda layout:
3506         layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"),
3507     }
3508
3509     @staticmethod
3510     def extrude_options(context):
3511         tool_settings = context.tool_settings
3512         select_mode = tool_settings.mesh_select_mode
3513         mesh = context.object.data
3514
3515         menu = []
3516         if mesh.total_face_sel:
3517             menu += ['REGION', 'REGION_VERT_NORMAL', 'FACE']
3518         if&