GPencil: Fix unreported unable to deselect when masking is OFF
[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 bl_ui.properties_paint_common import (
27     UnifiedPaintPanel,
28 )
29 from bl_ui.properties_grease_pencil_common import (
30     AnnotationDataPanel,
31     AnnotationOnionSkin,
32     GreasePencilMaterialsPanel,
33 )
34 from bl_ui.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 bl_ui.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         popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
83
84         # Note: general mode options should be added to 'draw_mode_settings'.
85         if tool_mode == 'SCULPT':
86             if (tool is not None) and tool.has_datablock:
87                 layout.popover_group(context=".paint_common", **popover_kw)
88         elif tool_mode == 'PAINT_VERTEX':
89             if (tool is not None) and tool.has_datablock:
90                 layout.popover_group(context=".paint_common", **popover_kw)
91         elif tool_mode == 'PAINT_WEIGHT':
92             if (tool is not None) and tool.has_datablock:
93                 layout.popover_group(context=".paint_common", **popover_kw)
94         elif tool_mode == 'PAINT_TEXTURE':
95             if (tool is not None) and tool.has_datablock:
96                 layout.popover_group(context=".paint_common", **popover_kw)
97         elif tool_mode == 'EDIT_ARMATURE':
98             pass
99         elif tool_mode == 'EDIT_CURVE':
100             pass
101         elif tool_mode == 'EDIT_MESH':
102             pass
103         elif tool_mode == 'POSE':
104             pass
105         elif tool_mode == 'PARTICLE':
106             # Disable, only shows "Brush" panel, which is already in the top-bar.
107             # if tool.has_datablock:
108             #     layout.popover_group(context=".paint_common", **popover_kw)
109             pass
110         elif tool_mode == 'PAINT_GPENCIL':
111             if (tool is not None) and tool.has_datablock:
112                 layout.popover_group(context=".greasepencil_paint", **popover_kw)
113         elif tool_mode == 'SCULPT_GPENCIL':
114             layout.popover_group(context=".greasepencil_sculpt", **popover_kw)
115         elif tool_mode == 'WEIGHT_GPENCIL':
116             layout.popover_group(context=".greasepencil_weight", **popover_kw)
117
118     def draw_mode_settings(self, context):
119         layout = self.layout
120         mode_string = context.mode
121
122         def row_for_mirror():
123             row = layout.row(align=True)
124             row.label(icon='MOD_MIRROR')
125             sub = row.row(align=True)
126             sub.scale_x = 0.6
127             return row, sub
128
129         if mode_string == 'EDIT_MESH':
130             _row, sub = row_for_mirror()
131             sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
132             tool_settings = context.tool_settings
133             layout.prop(tool_settings, "use_mesh_automerge", text="")
134         elif mode_string == 'EDIT_ARMATURE':
135             _row, sub = row_for_mirror()
136             sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
137         elif mode_string == 'POSE':
138             _row, sub = row_for_mirror()
139             sub.prop(context.object.pose, "use_mirror_x", text="X", toggle=True)
140         elif mode_string == 'PAINT_WEIGHT':
141             row, sub = row_for_mirror()
142             sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
143             row.popover(panel="VIEW3D_PT_tools_weightpaint_symmetry_for_topbar", text="")
144         elif mode_string == 'SCULPT':
145             row, sub = row_for_mirror()
146             sculpt = context.tool_settings.sculpt
147             sub.prop(sculpt, "use_symmetry_x", text="X", toggle=True)
148             sub.prop(sculpt, "use_symmetry_y", text="Y", toggle=True)
149             sub.prop(sculpt, "use_symmetry_z", text="Z", toggle=True)
150             row.popover(panel="VIEW3D_PT_sculpt_symmetry_for_topbar", text="")
151         elif mode_string == 'PAINT_TEXTURE':
152             _row, sub = row_for_mirror()
153             ipaint = context.tool_settings.image_paint
154             sub.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
155             sub.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
156             sub.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
157             # No need for a popover, the panel only has these options.
158         elif mode_string == 'PAINT_VERTEX':
159             row, sub = row_for_mirror()
160             vpaint = context.tool_settings.vertex_paint
161             sub.prop(vpaint, "use_symmetry_x", text="X", toggle=True)
162             sub.prop(vpaint, "use_symmetry_y", text="Y", toggle=True)
163             sub.prop(vpaint, "use_symmetry_z", text="Z", toggle=True)
164             row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")
165
166         # Expand panels from the side-bar as popovers.
167         popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
168
169         if mode_string == 'SCULPT':
170             layout.popover_group(context=".sculpt_mode", **popover_kw)
171         elif mode_string == 'PAINT_VERTEX':
172             layout.popover_group(context=".vertexpaint", **popover_kw)
173         elif mode_string == 'PAINT_WEIGHT':
174             layout.popover_group(context=".weightpaint", **popover_kw)
175         elif mode_string == 'PAINT_TEXTURE':
176             layout.popover_group(context=".imagepaint", **popover_kw)
177         elif mode_string == 'EDIT_TEXT':
178             layout.popover_group(context=".text_edit", **popover_kw)
179         elif mode_string == 'EDIT_ARMATURE':
180             layout.popover_group(context=".armature_edit", **popover_kw)
181         elif mode_string == 'EDIT_METABALL':
182             layout.popover_group(context=".mball_edit", **popover_kw)
183         elif mode_string == 'EDIT_LATTICE':
184             layout.popover_group(context=".lattice_edit", **popover_kw)
185         elif mode_string == 'EDIT_CURVE':
186             layout.popover_group(context=".curve_edit", **popover_kw)
187         elif mode_string == 'EDIT_MESH':
188             layout.popover_group(context=".mesh_edit", **popover_kw)
189         elif mode_string == 'POSE':
190             layout.popover_group(context=".posemode", **popover_kw)
191         elif mode_string == 'PARTICLE':
192             layout.popover_group(context=".particlemode", **popover_kw)
193         elif mode_string == 'OBJECT':
194             layout.popover_group(context=".objectmode", **popover_kw)
195         elif mode_string in {'PAINT_GPENCIL', 'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
196             # Grease pencil layer.
197             gpl = context.active_gpencil_layer
198             if gpl and gpl.info is not None:
199                 text = gpl.info
200                 maxw = 25
201                 if len(text) > maxw:
202                     text = text[:maxw - 5] + '..' + text[-3:]
203             else:
204                 text = ""
205
206             layout.label(text="Layer:")
207             sub = layout.row()
208             sub.ui_units_x = 8
209             sub.popover(
210                 panel="TOPBAR_PT_gpencil_layers",
211                 text=text,
212             )
213
214
215 class _draw_tool_settings_context_mode:
216     @staticmethod
217     def SCULPT(context, layout, tool):
218         if (tool is None) or (not tool.has_datablock):
219             return
220
221         paint = context.tool_settings.sculpt
222         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
223
224         brush = paint.brush
225         if brush is None:
226             return
227
228         from bl_ui.properties_paint_common import (
229             brush_basic_sculpt_settings,
230         )
231         brush_basic_sculpt_settings(layout, context, brush, compact=True)
232
233     @staticmethod
234     def PAINT_TEXTURE(context, layout, tool):
235         if (tool is None) or (not tool.has_datablock):
236             return
237
238         paint = context.tool_settings.image_paint
239         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
240
241         brush = paint.brush
242         if brush is None:
243             return
244
245         from bl_ui.properties_paint_common import (
246             UnifiedPaintPanel,
247             brush_basic_texpaint_settings,
248         )
249         capabilities = brush.image_paint_capabilities
250         if capabilities.has_color:
251             UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
252         brush_basic_texpaint_settings(layout, context, brush, compact=True)
253
254     @staticmethod
255     def PAINT_VERTEX(context, layout, tool):
256         if (tool is None) or (not tool.has_datablock):
257             return
258
259         paint = context.tool_settings.vertex_paint
260         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
261
262         brush = paint.brush
263         if brush is None:
264             return
265
266         from bl_ui.properties_paint_common import (
267             UnifiedPaintPanel,
268             brush_basic_vpaint_settings,
269         )
270         capabilities = brush.vertex_paint_capabilities
271         if capabilities.has_color:
272             UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
273         brush_basic_vpaint_settings(layout, context, brush, compact=True)
274
275     @staticmethod
276     def PAINT_WEIGHT(context, layout, tool):
277         if (tool is None) or (not tool.has_datablock):
278             return
279
280         paint = context.tool_settings.weight_paint
281         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
282         brush = paint.brush
283         if brush is None:
284             return
285
286         from bl_ui.properties_paint_common import brush_basic_wpaint_settings
287         brush_basic_wpaint_settings(layout, context, brush, compact=True)
288
289     @staticmethod
290     def PAINT_GPENCIL(context, layout, tool):
291         if tool is None:
292             return
293
294         # is_paint = True
295         # FIXME: tools must use their own UI drawing!
296         if tool.idname in {"builtin.line", "builtin.box", "builtin.circle", "builtin.arc", "builtin.curve"}:
297             # is_paint = False
298             pass
299         elif tool.idname == "Cutter":
300             row = layout.row(align=True)
301             row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
302             return
303         elif not tool.has_datablock:
304             return
305
306         paint = context.tool_settings.gpencil_paint
307         brush = paint.brush
308         if brush is None:
309             return
310
311         gp_settings = brush.gpencil_settings
312
313         def draw_color_selector():
314             ma = gp_settings.material
315             row = layout.row(align=True)
316             if not gp_settings.use_material_pin:
317                 ma = context.object.active_material
318             icon_id = 0
319             if ma:
320                 icon_id = ma.id_data.preview.icon_id
321                 txt_ma = ma.name
322                 maxw = 25
323                 if len(txt_ma) > maxw:
324                     txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:]
325             else:
326                 txt_ma = ""
327
328             sub = row.row()
329             sub.ui_units_x = 8
330             sub.popover(
331                 panel="TOPBAR_PT_gpencil_materials",
332                 text=txt_ma,
333                 icon_value=icon_id,
334             )
335
336             row.prop(gp_settings, "use_material_pin", text="")
337
338         row = layout.row(align=True)
339         tool_settings = context.scene.tool_settings
340         settings = tool_settings.gpencil_paint
341         row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
342
343         if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}:
344             draw_color_selector()
345
346         from bl_ui.properties_paint_common import (
347             brush_basic_gpencil_paint_settings,
348         )
349         brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
350
351         # FIXME: tools must use their own UI drawing!
352         if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}:
353             settings = context.tool_settings.gpencil_sculpt
354             row = layout.row(align=True)
355             row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
356             sub = row.row(align=True)
357             sub.active = settings.use_thickness_curve
358             sub.popover(
359                 panel="TOPBAR_PT_gpencil_primitive",
360                 text="Thickness Profile",
361             )
362
363         if brush.gpencil_tool == 'FILL':
364             settings = context.tool_settings.gpencil_sculpt
365             row = layout.row(align=True)
366             sub = row.row(align=True)
367             sub.popover(
368                 panel="TOPBAR_PT_gpencil_fill",
369                 text="Fill Options",
370             )
371
372     @staticmethod
373     def SCULPT_GPENCIL(context, layout, tool):
374         if (tool is None) or (not tool.has_datablock):
375             return
376         tool_settings = context.tool_settings
377         settings = tool_settings.gpencil_sculpt
378         brush = settings.brush
379
380         from bl_ui.properties_paint_common import (
381             brush_basic_gpencil_sculpt_settings,
382         )
383         brush_basic_gpencil_sculpt_settings(layout, context, brush, compact=True)
384
385     @staticmethod
386     def WEIGHT_GPENCIL(context, layout, tool):
387         if (tool is None) or (not tool.has_datablock):
388             return
389         tool_settings = context.tool_settings
390         settings = tool_settings.gpencil_sculpt
391         brush = settings.brush
392
393         from bl_ui.properties_paint_common import (
394             brush_basic_gpencil_weight_settings,
395         )
396         brush_basic_gpencil_weight_settings(layout, context, brush, compact=True)
397
398     @staticmethod
399     def PARTICLE(context, layout, tool):
400         if (tool is None) or (not tool.has_datablock):
401             return
402
403         # See: 'VIEW3D_PT_tools_brush', basically a duplicate
404         settings = context.tool_settings.particle_edit
405         brush = settings.brush
406         tool = settings.tool
407         if tool != 'NONE':
408             layout.prop(brush, "size", slider=True)
409             if tool == 'ADD':
410                 layout.prop(brush, "count")
411
412                 layout.prop(settings, "use_default_interpolate")
413                 layout.prop(brush, "steps", slider=True)
414                 layout.prop(settings, "default_key_count", slider=True)
415             else:
416                 layout.prop(brush, "strength", slider=True)
417
418                 if tool == 'LENGTH':
419                     layout.row().prop(brush, "length_mode", expand=True)
420                 elif tool == 'PUFF':
421                     layout.row().prop(brush, "puff_mode", expand=True)
422                     layout.prop(brush, "use_puff_volume")
423                 elif tool == 'COMB':
424                     row = layout.row()
425                     row.active = settings.is_editable
426                     row.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
427                     sub = row.row(align=True)
428                     sub.active = settings.use_emitter_deflect
429                     sub.prop(settings, "emitter_distance", text="Distance")
430
431
432 class VIEW3D_HT_header(Header):
433     bl_space_type = 'VIEW_3D'
434
435     @staticmethod
436     def draw_xform_template(layout, context):
437         obj = context.active_object
438         object_mode = 'OBJECT' if obj is None else obj.mode
439         has_pose_mode = (
440             (object_mode == 'POSE') or
441             (object_mode == 'WEIGHT_PAINT' and context.pose_object is not None)
442         )
443
444         tool_settings = context.tool_settings
445
446         # Mode & Transform Settings
447         scene = context.scene
448
449         # Orientation
450         if object_mode in {'OBJECT', 'EDIT', 'EDIT_GPENCIL'} or has_pose_mode:
451             orient_slot = scene.transform_orientation_slots[0]
452             row = layout.row(align=True)
453
454             sub = row.row()
455             sub.ui_units_x = 4
456             sub.prop_with_popover(
457                 orient_slot,
458                 "type",
459                 text="",
460                 panel="VIEW3D_PT_transform_orientations",
461             )
462
463         # Pivot
464         if object_mode in {'OBJECT', 'EDIT', 'EDIT_GPENCIL', 'SCULPT_GPENCIL'} or has_pose_mode:
465             layout.prop_with_popover(
466                 tool_settings,
467                 "transform_pivot_point",
468                 text="",
469                 icon_only=True,
470                 panel="VIEW3D_PT_pivot_point",
471             )
472
473         # Snap
474         show_snap = False
475         if obj is None:
476             show_snap = True
477         else:
478             if (object_mode not in {
479                     'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
480                     'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'
481             }) or has_pose_mode:
482                 show_snap = True
483             else:
484
485                 from bl_ui.properties_paint_common import UnifiedPaintPanel
486                 paint_settings = UnifiedPaintPanel.paint_settings(context)
487
488                 if paint_settings:
489                     brush = paint_settings.brush
490                     if brush and brush.stroke_method == 'CURVE':
491                         show_snap = True
492
493         if show_snap:
494             snap_items = bpy.types.ToolSettings.bl_rna.properties["snap_elements"].enum_items
495             snap_elements = tool_settings.snap_elements
496             if len(snap_elements) == 1:
497                 text = ""
498                 for elem in snap_elements:
499                     icon = snap_items[elem].icon
500                     break
501             else:
502                 text = "Mix"
503                 icon = 'NONE'
504             del snap_items, snap_elements
505
506             row = layout.row(align=True)
507             row.prop(tool_settings, "use_snap", text="")
508
509             sub = row.row(align=True)
510             sub.popover(
511                 panel="VIEW3D_PT_snapping",
512                 icon=icon,
513                 text=text,
514             )
515
516         # Proportional editing
517         if object_mode in {'EDIT', 'PARTICLE_EDIT', 'SCULPT_GPENCIL', 'EDIT_GPENCIL', 'OBJECT'}:
518             row = layout.row(align=True)
519             kw = {}
520             if object_mode == 'OBJECT':
521                 attr = "use_proportional_edit_objects"
522             else:
523                 attr = "use_proportional_edit"
524
525                 if tool_settings.use_proportional_edit:
526                     if tool_settings.use_proportional_connected:
527                         kw["icon"] = 'PROP_CON'
528                     elif tool_settings.use_proportional_projected:
529                         kw["icon"] = 'PROP_PROJECTED'
530                     else:
531                         kw["icon"] = 'PROP_ON'
532                 else:
533                     kw["icon"] = 'PROP_OFF'
534
535             row.prop(tool_settings, attr, icon_only=True, **kw)
536             sub = row.row(align=True)
537             sub.active = getattr(tool_settings, attr)
538             sub.prop_with_popover(
539                 tool_settings,
540                 "proportional_edit_falloff",
541                 text="",
542                 icon_only=True,
543                 panel="VIEW3D_PT_proportional_edit",
544             )
545
546     def draw(self, context):
547         layout = self.layout
548
549         tool_settings = context.tool_settings
550         view = context.space_data
551         shading = view.shading
552         # mode_string = context.mode
553         obj = context.active_object
554         show_region_tool_header = view.show_region_tool_header
555
556         if not show_region_tool_header:
557             layout.row(align=True).template_header()
558
559         row = layout.row(align=True)
560         object_mode = 'OBJECT' if obj is None else obj.mode
561
562         # Note: This is actually deadly in case enum_items have to be dynamically generated
563         #       (because internal RNA array iterator will free everything immediately...).
564         # XXX This is an RNA internal issue, not sure how to fix it.
565         # Note: Tried to add an accessor to get translated UI strings instead of manual call
566         #       to pgettext_iface below, but this fails because translated enumitems
567         #       are always dynamically allocated.
568         act_mode_item = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode]
569         act_mode_i18n_context = bpy.types.Object.bl_rna.properties["mode"].translation_context
570
571         sub = row.row(align=True)
572         sub.ui_units_x = 5.5
573         sub.operator_menu_enum(
574             "object.mode_set", "mode",
575             text=bpy.app.translations.pgettext_iface(act_mode_item.name, act_mode_i18n_context),
576             icon=act_mode_item.icon,
577         )
578         del act_mode_item
579
580         layout.template_header_3D_mode()
581
582         # Contains buttons like Mode, Pivot, Layer, Mesh Select Mode...
583         if obj:
584             # Particle edit
585             if object_mode == 'PARTICLE_EDIT':
586                 row = layout.row()
587                 row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True)
588
589         # Grease Pencil
590         if obj and obj.type == 'GPENCIL' and context.gpencil_data:
591             gpd = context.gpencil_data
592
593             if gpd.is_stroke_paint_mode:
594                 row = layout.row()
595                 sub = row.row(align=True)
596                 sub.prop(tool_settings, "use_gpencil_draw_onback", text="", icon='MOD_OPACITY')
597                 sub.separator(factor=0.4)
598                 sub.prop(tool_settings, "use_gpencil_weight_data_add", text="", icon='WPAINT_HLT')
599                 sub.separator(factor=0.4)
600                 sub.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
601
602             # Select mode for Editing
603             if gpd.use_stroke_edit_mode:
604                 row = layout.row(align=True)
605                 row.prop(tool_settings, "gpencil_selectmode_edit", text="", expand=True)
606
607             # Select mode for Sculpt
608             if gpd.is_stroke_sculpt_mode :
609                 row = layout.row(align=True)
610                 row.prop(tool_settings, "use_gpencil_select_mask_point", text="")
611                 row.prop(tool_settings, "use_gpencil_select_mask_stroke", text="")
612                 row.prop(tool_settings, "use_gpencil_select_mask_segment", text="")
613
614             if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
615                 row = layout.row(align=True)
616                 row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING')
617
618                 sub = row.row(align=True)
619                 sub.active = gpd.use_multiedit
620                 sub.popover(
621                     panel="VIEW3D_PT_gpencil_multi_frame",
622                     text="Multiframe",
623                 )
624
625             if gpd.use_stroke_edit_mode:
626                 row = layout.row(align=True)
627                 row.popover(
628                     panel="VIEW3D_PT_tools_grease_pencil_interpolate",
629                     text="Interpolate",
630                 )
631
632         overlay = view.overlay
633
634         VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
635
636         layout.separator_spacer()
637
638         if object_mode in {'PAINT_GPENCIL', 'SCULPT_GPENCIL'}:
639             # Grease pencil
640             if object_mode == 'PAINT_GPENCIL':
641                 layout.prop_with_popover(
642                     tool_settings,
643                     "gpencil_stroke_placement_view3d",
644                     text="",
645                     panel="VIEW3D_PT_gpencil_origin",
646                 )
647
648             if object_mode in {'PAINT_GPENCIL', 'SCULPT_GPENCIL'}:
649                 layout.prop_with_popover(
650                     tool_settings.gpencil_sculpt,
651                     "lock_axis",
652                     text="",
653                     panel="VIEW3D_PT_gpencil_lock",
654                 )
655
656             if object_mode == 'PAINT_GPENCIL':
657                 # FIXME: this is bad practice!
658                 # Tool options are to be displayed in the topbar.
659                 if context.workspace.tools.from_space_view3d_mode(object_mode).idname == "builtin_brush.Draw":
660                     settings = tool_settings.gpencil_sculpt.guide
661                     row = layout.row(align=True)
662                     row.prop(settings, "use_guide", text="", icon='GRID')
663                     sub = row.row(align=True)
664                     sub.active = settings.use_guide
665                     sub.popover(
666                         panel="VIEW3D_PT_gpencil_guide",
667                         text="Guides",
668                     )
669
670             layout.separator_spacer()
671         elif not show_region_tool_header:
672             # Transform settings depending on tool header visibility
673             VIEW3D_HT_header.draw_xform_template(layout, context)
674
675             layout.separator_spacer()
676
677         # Viewport Settings
678         layout.popover(
679             panel="VIEW3D_PT_object_type_visibility",
680             icon_value=view.icon_from_show_object_viewport,
681             text="",
682         )
683
684         # Gizmo toggle & popover.
685         row = layout.row(align=True)
686         # FIXME: place-holder icon.
687         row.prop(view, "show_gizmo", text="", toggle=True, icon='GIZMO')
688         sub = row.row(align=True)
689         sub.active = view.show_gizmo
690         sub.popover(
691             panel="VIEW3D_PT_gizmo_display",
692             text="",
693         )
694
695         # Overlay toggle & popover.
696         row = layout.row(align=True)
697         row.prop(overlay, "show_overlays", icon='OVERLAY', text="")
698         sub = row.row(align=True)
699         sub.active = overlay.show_overlays
700         sub.popover(panel="VIEW3D_PT_overlay", text="")
701
702         row = layout.row()
703         row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'})
704
705         if shading.type == 'WIREFRAME':
706             row.prop(shading, "show_xray_wireframe", text="", icon='XRAY')
707         else:
708             row.prop(shading, "show_xray", text="", icon='XRAY')
709
710         row = layout.row(align=True)
711         row.prop(shading, "type", text="", expand=True)
712         sub = row.row(align=True)
713         # TODO, currently render shading type ignores mesh two-side, until it's supported
714         # show the shading popover which shows double-sided option.
715
716         # sub.enabled = shading.type != 'RENDERED'
717         sub.popover(panel="VIEW3D_PT_shading", text="")
718
719
720 class VIEW3D_MT_editor_menus(Menu):
721     bl_label = ""
722
723     def draw(self, context):
724         layout = self.layout
725         obj = context.active_object
726         mode_string = context.mode
727         edit_object = context.edit_object
728         gp_edit = obj and obj.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}
729         ts = context.scene.tool_settings
730
731         layout.menu("VIEW3D_MT_view")
732
733         # Select Menu
734         if gp_edit:
735             if mode_string not in {'PAINT_GPENCIL', 'WEIGHT_GPENCIL'}:
736                 if mode_string == 'SCULPT_GPENCIL' and \
737                     (ts.use_gpencil_select_mask_point or
738                      ts.use_gpencil_select_mask_stroke or
739                      ts.use_gpencil_select_mask_segment):
740                     layout.menu("VIEW3D_MT_select_gpencil")
741                 elif mode_string == 'EDIT_GPENCIL':
742                     layout.menu("VIEW3D_MT_select_gpencil")
743         elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
744             mesh = obj.data
745             if mesh.use_paint_mask:
746                 layout.menu("VIEW3D_MT_select_paint_mask")
747             elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
748                 layout.menu("VIEW3D_MT_select_paint_mask_vertex")
749         elif mode_string != 'SCULPT':
750             layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
751
752         if gp_edit:
753             pass
754         elif mode_string == 'OBJECT':
755             layout.menu("VIEW3D_MT_add", text="Add", text_ctxt=i18n_contexts.operator_default)
756         elif mode_string == 'EDIT_MESH':
757             layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
758         elif mode_string == 'EDIT_CURVE':
759             layout.menu("VIEW3D_MT_curve_add", text="Add", text_ctxt=i18n_contexts.operator_default)
760         elif mode_string == 'EDIT_SURFACE':
761             layout.menu("VIEW3D_MT_surface_add", text="Add", text_ctxt=i18n_contexts.operator_default)
762         elif mode_string == 'EDIT_METABALL':
763             layout.menu("VIEW3D_MT_metaball_add", text="Add", text_ctxt=i18n_contexts.operator_default)
764         elif mode_string == 'EDIT_ARMATURE':
765             layout.menu("TOPBAR_MT_edit_armature_add", text="Add", text_ctxt=i18n_contexts.operator_default)
766
767         if gp_edit:
768             if obj and obj.mode == 'PAINT_GPENCIL':
769                 layout.menu("VIEW3D_MT_paint_gpencil")
770             elif obj and obj.mode == 'EDIT_GPENCIL':
771                 layout.menu("VIEW3D_MT_edit_gpencil")
772                 layout.menu("VIEW3D_MT_edit_gpencil_stroke")
773                 layout.menu("VIEW3D_MT_edit_gpencil_point")
774             elif obj and obj.mode == 'WEIGHT_GPENCIL':
775                 layout.menu("VIEW3D_MT_weight_gpencil")
776
777         elif edit_object:
778             layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
779
780             if mode_string == 'EDIT_MESH':
781                 layout.menu("VIEW3D_MT_edit_mesh_vertices")
782                 layout.menu("VIEW3D_MT_edit_mesh_edges")
783                 layout.menu("VIEW3D_MT_edit_mesh_faces")
784                 layout.menu("VIEW3D_MT_uv_map", text="UV")
785             elif mode_string in {'EDIT_CURVE', 'EDIT_SURFACE'}:
786                 layout.menu("VIEW3D_MT_edit_curve_ctrlpoints")
787                 layout.menu("VIEW3D_MT_edit_curve_segments")
788
789         elif obj:
790             if mode_string != 'PAINT_TEXTURE':
791                 layout.menu("VIEW3D_MT_%s" % mode_string.lower())
792
793         else:
794             layout.menu("VIEW3D_MT_object")
795
796
797 # ********** Menu **********
798
799
800 # ********** Utilities **********
801
802
803 class ShowHideMenu:
804     bl_label = "Show/Hide"
805     _operator_name = ""
806
807     def draw(self, _context):
808         layout = self.layout
809
810         layout.operator("%s.reveal" % self._operator_name)
811         layout.operator("%s.hide" % self._operator_name, text="Hide Selected").unselected = False
812         layout.operator("%s.hide" % self._operator_name, text="Hide Unselected").unselected = True
813
814
815 # Standard transforms which apply to all cases
816 # NOTE: this doesn't seem to be able to be used directly
817 class VIEW3D_MT_transform_base(Menu):
818     bl_label = "Transform"
819     bl_category = "View"
820
821     # TODO: get rid of the custom text strings?
822     def draw(self, context):
823         layout = self.layout
824
825         layout.operator("transform.translate")
826         layout.operator("transform.rotate")
827         layout.operator("transform.resize", text="Scale")
828
829         layout.separator()
830
831         layout.operator("transform.tosphere", text="To Sphere")
832         layout.operator("transform.shear", text="Shear")
833         layout.operator("transform.bend", text="Bend")
834         layout.operator("transform.push_pull", text="Push/Pull")
835
836         if context.mode != 'OBJECT':
837             layout.operator("transform.vertex_warp", text="Warp")
838             layout.operator("transform.vertex_random", text="Randomize")
839
840
841 # Generic transform menu - geometry types
842 class VIEW3D_MT_transform(VIEW3D_MT_transform_base):
843     def draw(self, context):
844         # base menu
845         VIEW3D_MT_transform_base.draw(self, context)
846
847         # generic...
848         layout = self.layout
849         if context.mode == 'EDIT_MESH':
850             layout.operator("transform.shrink_fatten", text="Shrink Fatten")
851         elif context.mode == 'EDIT_CURVE':
852             layout.operator("transform.transform", text="Radius").mode = 'CURVE_SHRINKFATTEN'
853
854         layout.separator()
855
856         layout.operator("transform.translate", text="Move Texture Space").texture_space = True
857         layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
858
859
860 # Object-specific extensions to Transform menu
861 class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
862     def draw(self, context):
863         layout = self.layout
864
865         # base menu
866         VIEW3D_MT_transform_base.draw(self, context)
867
868         # object-specific option follow...
869         layout.separator()
870
871         layout.operator("transform.translate", text="Move Texture Space").texture_space = True
872         layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
873
874         layout.separator()
875
876         layout.operator_context = 'EXEC_REGION_WIN'
877         # XXX see alignmenu() in edit.c of b2.4x to get this working
878         layout.operator("transform.transform", text="Align to Transform Orientation").mode = 'ALIGN'
879
880         layout.separator()
881
882         layout.operator("object.randomize_transform")
883         layout.operator("object.align")
884
885         # TODO: there is a strange context bug here.
886         """
887         layout.operator_context = 'INVOKE_REGION_WIN'
888         layout.operator("object.transform_axis_target")
889         """
890
891
892 # Armature EditMode extensions to Transform menu
893 class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
894     def draw(self, context):
895         layout = self.layout
896
897         # base menu
898         VIEW3D_MT_transform_base.draw(self, context)
899
900         # armature specific extensions follow...
901         obj = context.object
902         if obj.type == 'ARMATURE' and obj.mode in {'EDIT', 'POSE'}:
903             if obj.data.display_type == 'BBONE':
904                 layout.separator()
905
906                 layout.operator("transform.transform", text="Scale BBone").mode = 'BONE_SIZE'
907             elif obj.data.display_type == 'ENVELOPE':
908                 layout.separator()
909
910                 layout.operator("transform.transform", text="Scale Envelope Distance").mode = 'BONE_SIZE'
911                 layout.operator("transform.transform", text="Scale Radius").mode = 'BONE_ENVELOPE'
912
913         if context.edit_object and context.edit_object.type == 'ARMATURE':
914             layout.separator()
915
916             layout.operator("armature.align")
917
918
919 class VIEW3D_MT_mirror(Menu):
920     bl_label = "Mirror"
921
922     def draw(self, _context):
923         layout = self.layout
924
925         layout.operator("transform.mirror", text="Interactive Mirror")
926
927         layout.separator()
928
929         layout.operator_context = 'EXEC_REGION_WIN'
930
931         for (space_name, space_id) in (("Global", 'GLOBAL'), ("Local", 'LOCAL')):
932             for axis_index, axis_name in enumerate("XYZ"):
933                 props = layout.operator("transform.mirror", text=f"{axis_name!s} {space_name!s}")
934                 props.constraint_axis[axis_index] = True
935                 props.orient_type = 'GLOBAL'
936
937             if space_id == 'GLOBAL':
938                 layout.separator()
939
940
941 class VIEW3D_MT_snap(Menu):
942     bl_label = "Snap"
943
944     def draw(self, _context):
945         layout = self.layout
946
947         layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid")
948         layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False
949         layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True
950         layout.operator("view3d.snap_selected_to_active", text="Selection to Active")
951
952         layout.separator()
953
954         layout.operator("view3d.snap_cursor_to_selected", text="Cursor to Selected")
955         layout.operator("view3d.snap_cursor_to_center", text="Cursor to World Origin")
956         layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
957         layout.operator("view3d.snap_cursor_to_active", text="Cursor to Active")
958
959
960 class VIEW3D_MT_uv_map(Menu):
961     bl_label = "UV Mapping"
962
963     def draw(self, context):
964         layout = self.layout
965
966         tool_settings = context.tool_settings
967
968         layout.operator("uv.unwrap")
969         layout.prop(tool_settings, "use_edge_path_live_unwrap")
970
971         layout.separator()
972
973         layout.operator_context = 'INVOKE_DEFAULT'
974         layout.operator("uv.smart_project")
975         layout.operator("uv.lightmap_pack")
976         layout.operator("uv.follow_active_quads")
977
978         layout.separator()
979
980         layout.operator_context = 'EXEC_REGION_WIN'
981         layout.operator("uv.cube_project")
982         layout.operator("uv.cylinder_project")
983         layout.operator("uv.sphere_project")
984
985         layout.separator()
986
987         layout.operator_context = 'INVOKE_REGION_WIN'
988         layout.operator("uv.project_from_view").scale_to_bounds = False
989         layout.operator("uv.project_from_view", text="Project from View (Bounds)").scale_to_bounds = True
990
991         layout.separator()
992
993         layout.operator("mesh.mark_seam").clear = False
994         layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
995
996         layout.separator()
997
998         layout.operator("uv.reset")
999
1000
1001 # ********** View menus **********
1002
1003
1004 class VIEW3D_MT_view(Menu):
1005     bl_label = "View"
1006
1007     def draw(self, context):
1008         layout = self.layout
1009         view = context.space_data
1010
1011         layout.prop(view, "show_region_toolbar")
1012         layout.prop(view, "show_region_ui")
1013         layout.prop(view, "show_region_tool_header")
1014         layout.prop(view, "show_region_hud")
1015
1016         layout.separator()
1017
1018         layout.operator("view3d.view_selected", text="Frame Selected").use_all_regions = False
1019         if view.region_quadviews:
1020             layout.operator("view3d.view_selected", text="Frame Selected (Quad View)").use_all_regions = True
1021
1022         layout.operator("view3d.view_all", text="Frame All").center = False
1023         layout.operator("view3d.view_persportho", text="Perspective/Orthographic")
1024         layout.menu("VIEW3D_MT_view_local")
1025
1026         layout.separator()
1027
1028         layout.menu("VIEW3D_MT_view_cameras", text="Cameras")
1029
1030         layout.separator()
1031         layout.menu("VIEW3D_MT_view_viewpoint")
1032         layout.menu("VIEW3D_MT_view_navigation")
1033         layout.menu("VIEW3D_MT_view_align")
1034
1035         layout.separator()
1036
1037         layout.operator_context = 'INVOKE_REGION_WIN'
1038         layout.menu("VIEW3D_MT_view_regions", text="View Regions")
1039
1040         layout.separator()
1041
1042         layout.operator("screen.animation_play", text="Play Animation")
1043
1044         layout.separator()
1045
1046         layout.operator("render.opengl", text="Viewport Render Image", icon='RENDER_STILL')
1047         layout.operator("render.opengl", text="Viewport Render Animation", icon='RENDER_ANIMATION').animation = True
1048
1049         layout.separator()
1050
1051         layout.menu("INFO_MT_area")
1052
1053
1054 class VIEW3D_MT_view_local(Menu):
1055     bl_label = "Local View"
1056
1057     def draw(self, _context):
1058         layout = self.layout
1059
1060         layout.operator("view3d.localview", text="Toggle Local View")
1061         layout.operator("view3d.localview_remove_from")
1062
1063
1064 class VIEW3D_MT_view_cameras(Menu):
1065     bl_label = "Cameras"
1066
1067     def draw(self, _context):
1068         layout = self.layout
1069
1070         layout.operator("view3d.object_as_camera")
1071         layout.operator("view3d.view_camera", text="Active Camera")
1072
1073
1074 class VIEW3D_MT_view_viewpoint(Menu):
1075     bl_label = "Viewpoint"
1076
1077     def draw(self, _context):
1078         layout = self.layout
1079
1080         layout.operator("view3d.view_camera", text="Camera")
1081
1082         layout.separator()
1083
1084         layout.operator("view3d.view_axis", text="Top").type = 'TOP'
1085         layout.operator("view3d.view_axis", text="Bottom").type = 'BOTTOM'
1086
1087         layout.separator()
1088
1089         layout.operator("view3d.view_axis", text="Front").type = 'FRONT'
1090         layout.operator("view3d.view_axis", text="Back").type = 'BACK'
1091
1092         layout.separator()
1093
1094         layout.operator("view3d.view_axis", text="Right").type = 'RIGHT'
1095         layout.operator("view3d.view_axis", text="Left").type = 'LEFT'
1096
1097
1098 class VIEW3D_MT_view_navigation(Menu):
1099     bl_label = "Navigation"
1100
1101     def draw(self, _context):
1102         from math import pi
1103         layout = self.layout
1104
1105         layout.operator_enum("view3d.view_orbit", "type")
1106         props = layout.operator("view3d.view_orbit", text="Orbit Opposite")
1107         props.type = 'ORBITRIGHT'
1108         props.angle = pi
1109
1110         layout.separator()
1111
1112         layout.operator("view3d.view_roll", text="Roll Left").type = 'LEFT'
1113         layout.operator("view3d.view_roll", text="Roll Right").type = 'RIGHT'
1114
1115         layout.separator()
1116
1117         layout.operator_enum("view3d.view_pan", "type")
1118
1119         layout.separator()
1120
1121         layout.operator("view3d.zoom", text="Zoom In").delta = 1
1122         layout.operator("view3d.zoom", text="Zoom Out").delta = -1
1123         layout.operator("view3d.zoom_border", text="Zoom Region...")
1124         layout.operator("view3d.zoom_camera_1_to_1", text="Zoom Camera 1:1")
1125
1126         layout.separator()
1127
1128         layout.operator("view3d.fly")
1129         layout.operator("view3d.walk")
1130
1131
1132 class VIEW3D_MT_view_align(Menu):
1133     bl_label = "Align View"
1134
1135     def draw(self, _context):
1136         layout = self.layout
1137
1138         layout.menu("VIEW3D_MT_view_align_selected")
1139
1140         layout.separator()
1141
1142         layout.operator("view3d.camera_to_view", text="Align Active Camera to View")
1143         layout.operator("view3d.camera_to_view_selected", text="Align Active Camera to Selected")
1144
1145         layout.separator()
1146
1147         layout.operator("view3d.view_all", text="Center Cursor and View All").center = True
1148         layout.operator("view3d.view_center_cursor")
1149
1150         layout.separator()
1151
1152         layout.operator("view3d.view_lock_to_active")
1153         layout.operator("view3d.view_lock_clear")
1154
1155
1156 class VIEW3D_MT_view_align_selected(Menu):
1157     bl_label = "Align View to Active"
1158
1159     def draw(self, _context):
1160         layout = self.layout
1161
1162         props = layout.operator("view3d.view_axis", text="Top")
1163         props.align_active = True
1164         props.type = 'TOP'
1165
1166         props = layout.operator("view3d.view_axis", text="Bottom")
1167         props.align_active = True
1168         props.type = 'BOTTOM'
1169
1170         layout.separator()
1171
1172         props = layout.operator("view3d.view_axis", text="Front")
1173         props.align_active = True
1174         props.type = 'FRONT'
1175
1176         props = layout.operator("view3d.view_axis", text="Back")
1177         props.align_active = True
1178         props.type = 'BACK'
1179
1180         layout.separator()
1181
1182         props = layout.operator("view3d.view_axis", text="Right")
1183         props.align_active = True
1184         props.type = 'RIGHT'
1185
1186         props = layout.operator("view3d.view_axis", text="Left")
1187         props.align_active = True
1188         props.type = 'LEFT'
1189
1190
1191 class VIEW3D_MT_view_regions(Menu):
1192     bl_label = "View Regions"
1193
1194     def draw(self, _context):
1195         layout = self.layout
1196         layout.operator("view3d.clip_border", text="Clipping Region...")
1197         layout.operator("view3d.render_border", text="Render Region...")
1198
1199         layout.separator()
1200
1201         layout.operator("view3d.clear_render_border")
1202
1203
1204 # ********** Select menus, suffix from context.mode **********
1205
1206 class VIEW3D_MT_select_object_more_less(Menu):
1207     bl_label = "Select More/Less"
1208
1209     def draw(self, _context):
1210         layout = self.layout
1211
1212         layout = self.layout
1213
1214         layout.operator("object.select_more", text="More")
1215         layout.operator("object.select_less", text="Less")
1216
1217         layout.separator()
1218
1219         props = layout.operator("object.select_hierarchy", text="Parent")
1220         props.extend = False
1221         props.direction = 'PARENT'
1222
1223         props = layout.operator("object.select_hierarchy", text="Child")
1224         props.extend = False
1225         props.direction = 'CHILD'
1226
1227         layout.separator()
1228
1229         props = layout.operator("object.select_hierarchy", text="Extend Parent")
1230         props.extend = True
1231         props.direction = 'PARENT'
1232
1233         props = layout.operator("object.select_hierarchy", text="Extend Child")
1234         props.extend = True
1235         props.direction = 'CHILD'
1236
1237
1238 class VIEW3D_MT_select_object(Menu):
1239     bl_label = "Select"
1240
1241     def draw(self, _context):
1242         layout = self.layout
1243
1244         layout.operator("object.select_all", text="All").action = 'SELECT'
1245         layout.operator("object.select_all", text="None").action = 'DESELECT'
1246         layout.operator("object.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_menu_enum("object.select_by_type", "type", text="Select All by Type...")
1256         layout.operator("object.select_camera", text="Select Active Camera")
1257         layout.operator("object.select_mirror", text="Mirror Selection")
1258         layout.operator("object.select_random", text="Select Random")
1259
1260         layout.separator()
1261
1262         layout.menu("VIEW3D_MT_select_object_more_less")
1263
1264         layout.separator()
1265
1266         layout.operator_menu_enum("object.select_grouped", "type", text="Select Grouped")
1267         layout.operator_menu_enum("object.select_linked", "type", text="Select Linked")
1268         layout.operator("object.select_pattern", text="Select Pattern...")
1269
1270
1271 class VIEW3D_MT_select_pose_more_less(Menu):
1272     bl_label = "Select More/Less"
1273
1274     def draw(self, _context):
1275         layout = self.layout
1276
1277         layout = self.layout
1278
1279         props = layout.operator("pose.select_hierarchy", text="Parent")
1280         props.extend = False
1281         props.direction = 'PARENT'
1282
1283         props = layout.operator("pose.select_hierarchy", text="Child")
1284         props.extend = False
1285         props.direction = 'CHILD'
1286
1287         layout.separator()
1288
1289         props = layout.operator("pose.select_hierarchy", text="Extend Parent")
1290         props.extend = True
1291         props.direction = 'PARENT'
1292
1293         props = layout.operator("pose.select_hierarchy", text="Extend Child")
1294         props.extend = True
1295         props.direction = 'CHILD'
1296
1297
1298 class VIEW3D_MT_select_pose(Menu):
1299     bl_label = "Select"
1300
1301     def draw(self, _context):
1302         layout = self.layout
1303
1304         layout.operator("pose.select_all", text="All").action = 'SELECT'
1305         layout.operator("pose.select_all", text="None").action = 'DESELECT'
1306         layout.operator("pose.select_all", text="Invert").action = 'INVERT'
1307
1308         layout.separator()
1309
1310         layout.operator("view3d.select_box")
1311         layout.operator("view3d.select_circle")
1312
1313         layout.separator()
1314
1315         layout.operator("pose.select_mirror", text="Flip Active")
1316
1317         layout.separator()
1318
1319         layout.operator("pose.select_constraint_target", text="Constraint Target")
1320         layout.operator("pose.select_linked", text="Linked")
1321
1322         layout.separator()
1323
1324         layout.menu("VIEW3D_MT_select_pose_more_less")
1325
1326         layout.separator()
1327
1328         layout.operator_menu_enum("pose.select_grouped", "type", text="Grouped")
1329         layout.operator("object.select_pattern", text="Select Pattern...")
1330
1331
1332 class VIEW3D_MT_select_particle(Menu):
1333     bl_label = "Select"
1334
1335     def draw(self, _context):
1336         layout = self.layout
1337
1338         layout.operator("particle.select_all", text="All").action = 'SELECT'
1339         layout.operator("particle.select_all", text="None").action = 'DESELECT'
1340         layout.operator("particle.select_all", text="Invert").action = 'INVERT'
1341
1342         layout.separator()
1343
1344         layout.operator("view3d.select_box")
1345         layout.operator("view3d.select_circle")
1346
1347         layout.separator()
1348
1349         layout.operator("particle.select_linked")
1350
1351         layout.separator()
1352
1353         layout.operator("particle.select_more")
1354         layout.operator("particle.select_less")
1355
1356         layout.separator()
1357
1358         layout.operator("particle.select_random")
1359
1360         layout.separator()
1361
1362         layout.operator("particle.select_roots", text="Roots")
1363         layout.operator("particle.select_tips", text="Tips")
1364
1365
1366 class VIEW3D_MT_edit_mesh_select_similar(Menu):
1367     bl_label = "Select Similar"
1368
1369     def draw(self, _context):
1370         layout = self.layout
1371
1372         layout.operator_enum("mesh.select_similar", "type")
1373
1374         layout.separator()
1375
1376         layout.operator("mesh.select_similar_region", text="Face Regions")
1377
1378
1379 class VIEW3D_MT_edit_mesh_select_by_trait(Menu):
1380     bl_label = "Select All by Trait"
1381
1382     def draw(self, context):
1383         layout = self.layout
1384         tool_settings = context.tool_settings
1385         if tool_settings.mesh_select_mode[2] is False:
1386             layout.operator("mesh.select_non_manifold", text="Non Manifold")
1387         layout.operator("mesh.select_loose", text="Loose Geometry")
1388         layout.operator("mesh.select_interior_faces", text="Interior Faces")
1389         layout.operator("mesh.select_face_by_sides", text="Faces by Sides")
1390
1391         layout.separator()
1392
1393         layout.operator("mesh.select_ungrouped", text="Ungrouped Verts")
1394
1395
1396 class VIEW3D_MT_edit_mesh_select_more_less(Menu):
1397     bl_label = "Select More/Less"
1398
1399     def draw(self, _context):
1400         layout = self.layout
1401
1402         layout.operator("mesh.select_more", text="More")
1403         layout.operator("mesh.select_less", text="Less")
1404
1405         layout.separator()
1406
1407         layout.operator("mesh.select_next_item", text="Next Active")
1408         layout.operator("mesh.select_prev_item", text="Previous Active")
1409
1410
1411 class VIEW3D_MT_edit_mesh_select_linked(Menu):
1412     bl_label = "Select Linked"
1413
1414     def draw(self, _context):
1415         layout = self.layout
1416
1417         layout.operator("mesh.select_linked", text="Linked")
1418         layout.operator("mesh.shortest_path_select", text="Shortest Path")
1419         layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
1420
1421
1422 class VIEW3D_MT_edit_mesh_select_loops(Menu):
1423     bl_label = "Select Loops"
1424
1425     def draw(self, _context):
1426         layout = self.layout
1427
1428         layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False
1429         layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True
1430
1431         layout.separator()
1432
1433         layout.operator("mesh.loop_to_region")
1434         layout.operator("mesh.region_to_loop")
1435
1436
1437 class VIEW3D_MT_select_edit_mesh(Menu):
1438     bl_label = "Select"
1439
1440     def draw(self, _context):
1441         layout = self.layout
1442
1443         # primitive
1444         layout.operator("mesh.select_all", text="All").action = 'SELECT'
1445         layout.operator("mesh.select_all", text="None").action = 'DESELECT'
1446         layout.operator("mesh.select_all", text="Invert").action = 'INVERT'
1447
1448         layout.separator()
1449
1450         layout.operator("view3d.select_box")
1451         layout.operator("view3d.select_circle")
1452
1453         layout.separator()
1454
1455         # numeric
1456         layout.operator("mesh.select_random", text="Select Random")
1457         layout.operator("mesh.select_nth")
1458
1459         layout.separator()
1460
1461         # geometric
1462         layout.operator("mesh.edges_select_sharp", text="Select Sharp Edges")
1463
1464         layout.separator()
1465
1466         # other ...
1467         layout.menu("VIEW3D_MT_edit_mesh_select_similar")
1468
1469         layout.separator()
1470
1471         layout.menu("VIEW3D_MT_edit_mesh_select_by_trait")
1472
1473         layout.separator()
1474
1475         layout.menu("VIEW3D_MT_edit_mesh_select_more_less")
1476
1477         layout.separator()
1478
1479         layout.menu("VIEW3D_MT_edit_mesh_select_loops")
1480
1481         layout.separator()
1482
1483         layout.menu("VIEW3D_MT_edit_mesh_select_linked")
1484
1485         layout.separator()
1486
1487         layout.operator("mesh.select_axis", text="Side of Active")
1488         layout.operator("mesh.select_mirror", text="Mirror Selection")
1489
1490
1491 class VIEW3D_MT_select_edit_curve(Menu):
1492     bl_label = "Select"
1493
1494     def draw(self, _context):
1495         layout = self.layout
1496
1497         layout.operator("curve.select_all", text="All").action = 'SELECT'
1498         layout.operator("curve.select_all", text="None").action = 'DESELECT'
1499         layout.operator("curve.select_all", text="Invert").action = 'INVERT'
1500
1501         layout.separator()
1502
1503         layout.operator("view3d.select_box")
1504         layout.operator("view3d.select_circle")
1505
1506         layout.separator()
1507
1508         layout.operator("curve.select_random")
1509         layout.operator("curve.select_nth")
1510         layout.operator("curve.select_linked", text="Select Linked")
1511         layout.operator("curve.select_similar", text="Select Similar")
1512
1513         layout.separator()
1514
1515         layout.operator("curve.de_select_first")
1516         layout.operator("curve.de_select_last")
1517         layout.operator("curve.select_next")
1518         layout.operator("curve.select_previous")
1519
1520         layout.separator()
1521
1522         layout.operator("curve.select_more")
1523         layout.operator("curve.select_less")
1524
1525
1526 class VIEW3D_MT_select_edit_surface(Menu):
1527     bl_label = "Select"
1528
1529     def draw(self, _context):
1530         layout = self.layout
1531
1532         layout.operator("curve.select_all", text="All").action = 'SELECT'
1533         layout.operator("curve.select_all", text="None").action = 'DESELECT'
1534         layout.operator("curve.select_all", text="Invert").action = 'INVERT'
1535
1536         layout.separator()
1537
1538         layout.operator("view3d.select_box")
1539         layout.operator("view3d.select_circle")
1540
1541         layout.separator()
1542
1543         layout.operator("curve.select_random")
1544         layout.operator("curve.select_nth")
1545         layout.operator("curve.select_linked", text="Select Linked")
1546         layout.operator("curve.select_similar", text="Select Similar")
1547
1548         layout.separator()
1549
1550         layout.operator("curve.select_row")
1551
1552         layout.separator()
1553
1554         layout.operator("curve.select_more")
1555         layout.operator("curve.select_less")
1556
1557
1558 class VIEW3D_MT_edit_text_context_menu(Menu):
1559     bl_label = "Text Context Menu"
1560
1561     def draw(self, _context):
1562         layout = self.layout
1563
1564         layout.operator_context = 'INVOKE_DEFAULT'
1565
1566         layout.operator("font.text_cut", text="Cut")
1567         layout.operator("font.text_copy", text="Copy", icon='COPYDOWN')
1568         layout.operator("font.text_paste", text="Paste", icon='PASTEDOWN')
1569
1570         layout.separator()
1571
1572         layout.operator("font.select_all")
1573
1574         layout.separator()
1575
1576         layout.menu("VIEW3D_MT_edit_font")
1577
1578
1579 class VIEW3D_MT_select_edit_text(Menu):
1580     # intentional name mismatch
1581     # select menu for 3d-text doesn't make sense
1582     bl_label = "Edit"
1583
1584     def draw(self, _context):
1585         layout = self.layout
1586
1587         layout.operator("ed.undo")
1588         layout.operator("ed.redo")
1589
1590         layout.separator()
1591
1592         layout.operator("font.text_cut", text="Cut")
1593         layout.operator("font.text_copy", text="Copy", icon='COPYDOWN')
1594         layout.operator("font.text_paste", text="Paste", icon='PASTEDOWN')
1595
1596         layout.separator()
1597
1598         layout.operator("font.text_paste_from_file")
1599
1600         layout.separator()
1601
1602         layout.operator("font.select_all")
1603
1604         layout.separator()
1605
1606         layout.operator("font.case_set", text="To Uppercase").case = 'UPPER'
1607         layout.operator("font.case_set", text="To Lowercase").case = 'LOWER'
1608
1609         layout.separator()
1610
1611         layout.menu("VIEW3D_MT_edit_text_chars")
1612
1613
1614 class VIEW3D_MT_select_edit_metaball(Menu):
1615     bl_label = "Select"
1616
1617     def draw(self, _context):
1618         layout = self.layout
1619
1620         layout.operator("mball.select_all", text="All").action = 'SELECT'
1621         layout.operator("mball.select_all", text="None").action = 'DESELECT'
1622         layout.operator("mball.select_all", text="Invert").action = 'INVERT'
1623
1624         layout.separator()
1625
1626         layout.operator("view3d.select_box")
1627         layout.operator("view3d.select_circle")
1628
1629         layout.separator()
1630
1631         layout.operator("mball.select_random_metaelems")
1632
1633         layout.separator()
1634
1635         layout.operator_menu_enum("mball.select_similar", "type", text="Similar")
1636
1637
1638 class VIEW3D_MT_edit_lattice_context_menu(Menu):
1639     bl_label = "Lattice Context Menu"
1640
1641     def draw(self, _context):
1642         layout = self.layout
1643
1644         layout = self.layout
1645
1646         layout.menu("VIEW3D_MT_mirror")
1647         layout.operator_menu_enum("lattice.flip", "axis")
1648         layout.menu("VIEW3D_MT_snap")
1649
1650         layout.separator()
1651
1652         layout.operator("lattice.make_regular")
1653
1654
1655 class VIEW3D_MT_select_edit_lattice(Menu):
1656     bl_label = "Select"
1657
1658     def draw(self, _context):
1659         layout = self.layout
1660
1661         layout.operator("lattice.select_all", text="All").action = 'SELECT'
1662         layout.operator("lattice.select_all", text="None").action = 'DESELECT'
1663         layout.operator("lattice.select_all", text="Invert").action = 'INVERT'
1664
1665         layout.separator()
1666
1667         layout.operator("view3d.select_box")
1668         layout.operator("view3d.select_circle")
1669
1670         layout.separator()
1671
1672         layout.operator("lattice.select_mirror")
1673         layout.operator("lattice.select_random")
1674
1675         layout.separator()
1676
1677         layout.operator("lattice.select_more")
1678         layout.operator("lattice.select_less")
1679
1680         layout.separator()
1681
1682         layout.operator("lattice.select_ungrouped", text="Ungrouped Verts")
1683
1684
1685 class VIEW3D_MT_select_edit_armature(Menu):
1686     bl_label = "Select"
1687
1688     def draw(self, _context):
1689         layout = self.layout
1690
1691         layout.operator("armature.select_all", text="All").action = 'SELECT'
1692         layout.operator("armature.select_all", text="None").action = 'DESELECT'
1693         layout.operator("armature.select_all", text="Invert").action = 'INVERT'
1694
1695         layout.separator()
1696
1697         layout.operator("view3d.select_box")
1698         layout.operator("view3d.select_circle")
1699
1700         layout.separator()
1701
1702         layout.operator("armature.select_mirror", text="Mirror").extend = False
1703
1704         layout.separator()
1705
1706         layout.operator("armature.select_more", text="More")
1707         layout.operator("armature.select_less", text="Less")
1708
1709         layout.separator()
1710
1711         props = layout.operator("armature.select_hierarchy", text="Parent")
1712         props.extend = False
1713         props.direction = 'PARENT'
1714
1715         props = layout.operator("armature.select_hierarchy", text="Child")
1716         props.extend = False
1717         props.direction = 'CHILD'
1718
1719         layout.separator()
1720
1721         props = layout.operator("armature.select_hierarchy", text="Extend Parent")
1722         props.extend = True
1723         props.direction = 'PARENT'
1724
1725         props = layout.operator("armature.select_hierarchy", text="Extend Child")
1726         props.extend = True
1727         props.direction = 'CHILD'
1728
1729         layout.operator_menu_enum("armature.select_similar", "type", text="Similar")
1730         layout.operator("object.select_pattern", text="Select Pattern...")
1731
1732
1733 class VIEW3D_MT_select_gpencil(Menu):
1734     bl_label = "Select"
1735
1736     def draw(self, _context):
1737         layout = self.layout
1738
1739         layout.operator("gpencil.select_all", text="All").action = 'SELECT'
1740         layout.operator("gpencil.select_all", text="None").action = 'DESELECT'
1741         layout.operator("gpencil.select_all", text="Invert").action = 'INVERT'
1742
1743         layout.separator()
1744
1745         layout.operator("gpencil.select_box")
1746         layout.operator("gpencil.select_circle")
1747
1748         layout.separator()
1749
1750         layout.operator("gpencil.select_linked", text="Linked")
1751         layout.operator("gpencil.select_alternate")
1752         layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
1753
1754         layout.separator()
1755
1756         layout.operator("gpencil.select_first")
1757         layout.operator("gpencil.select_last")
1758
1759         layout.separator()
1760
1761         layout.operator("gpencil.select_more")
1762         layout.operator("gpencil.select_less")
1763
1764
1765 class VIEW3D_MT_select_paint_mask(Menu):
1766     bl_label = "Select"
1767
1768     def draw(self, _context):
1769         layout = self.layout
1770
1771         layout.operator("paint.face_select_all", text="All").action = 'SELECT'
1772         layout.operator("paint.face_select_all", text="None").action = 'DESELECT'
1773         layout.operator("paint.face_select_all", text="Invert").action = 'INVERT'
1774
1775         layout.separator()
1776
1777         layout.operator("view3d.select_box")
1778         layout.operator("view3d.select_circle")
1779
1780         layout.separator()
1781
1782         layout.operator("paint.face_select_linked", text="Linked")
1783
1784
1785 class VIEW3D_MT_select_paint_mask_vertex(Menu):
1786     bl_label = "Select"
1787
1788     def draw(self, _context):
1789         layout = self.layout
1790
1791         layout.operator("paint.vert_select_all", text="All").action = 'SELECT'
1792         layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
1793         layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
1794
1795         layout.separator()
1796
1797         layout.operator("view3d.select_box")
1798         layout.operator("view3d.select_circle")
1799
1800         layout.separator()
1801
1802         layout.operator("paint.vert_select_ungrouped", text="Ungrouped Verts")
1803
1804
1805 class VIEW3D_MT_angle_control(Menu):
1806     bl_label = "Angle Control"
1807
1808     @classmethod
1809     def poll(cls, context):
1810         settings = UnifiedPaintPanel.paint_settings(context)
1811         if not settings:
1812             return False
1813
1814         brush = settings.brush
1815         tex_slot = brush.texture_slot
1816
1817         return tex_slot.has_texture_angle and tex_slot.has_texture_angle_source
1818
1819     def draw(self, context):
1820         layout = self.layout
1821
1822         settings = UnifiedPaintPanel.paint_settings(context)
1823         brush = settings.brush
1824
1825         sculpt = (context.sculpt_object is not None)
1826
1827         tex_slot = brush.texture_slot
1828
1829         layout.prop(tex_slot, "use_rake", text="Rake")
1830
1831         if brush.brush_capabilities.has_random_texture_angle and tex_slot.has_random_texture_angle:
1832             if sculpt:
1833                 if brush.sculpt_capabilities.has_random_texture_angle:
1834                     layout.prop(tex_slot, "use_random", text="Random")
1835             else:
1836                 layout.prop(tex_slot, "use_random", text="Random")
1837
1838
1839 class VIEW3D_MT_mesh_add(Menu):
1840     bl_idname = "VIEW3D_MT_mesh_add"
1841     bl_label = "Mesh"
1842
1843     def draw(self, _context):
1844         layout = self.layout
1845
1846         layout.operator_context = 'INVOKE_REGION_WIN'
1847
1848         layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE')
1849         layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE')
1850         layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
1851         layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE')
1852         layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE')
1853         layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER')
1854         layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE')
1855         layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS')
1856
1857         layout.separator()
1858
1859         layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID')
1860         layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY')
1861
1862
1863 class VIEW3D_MT_curve_add(Menu):
1864     bl_idname = "VIEW3D_MT_curve_add"
1865     bl_label = "Curve"
1866
1867     def draw(self, _context):
1868         layout = self.layout
1869
1870         layout.operator_context = 'INVOKE_REGION_WIN'
1871
1872         layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE')
1873         layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE')
1874
1875         layout.separator()
1876
1877         layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE')
1878         layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
1879         layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
1880
1881
1882 class VIEW3D_MT_surface_add(Menu):
1883     bl_idname = "VIEW3D_MT_surface_add"
1884     bl_label = "Surface"
1885
1886     def draw(self, _context):
1887         layout = self.layout
1888
1889         layout.operator_context = 'INVOKE_REGION_WIN'
1890
1891         layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE')
1892         layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE')
1893         layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE')
1894         layout.operator("surface.primitive_nurbs_surface_cylinder_add",
1895                         text="Nurbs Cylinder", icon='SURFACE_NCYLINDER')
1896         layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE')
1897         layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS')
1898
1899
1900 class VIEW3D_MT_edit_metaball_context_menu(Menu):
1901     bl_label = "Metaball Context Menu"
1902
1903     def draw(self, _context):
1904         layout = self.layout
1905
1906         layout.operator_context = 'INVOKE_REGION_WIN'
1907
1908         # Add
1909         layout.operator("mball.duplicate_move")
1910
1911         layout.separator()
1912
1913         # Modify
1914         layout.menu("VIEW3D_MT_mirror")
1915         layout.menu("VIEW3D_MT_snap")
1916
1917         layout.separator()
1918
1919         # Remove
1920         layout.operator_context = 'EXEC_DEFAULT'
1921         layout.operator("mball.delete_metaelems", text="Delete")
1922
1923
1924 class VIEW3D_MT_metaball_add(Menu):
1925     bl_idname = "VIEW3D_MT_metaball_add"
1926     bl_label = "Metaball"
1927
1928     def draw(self, _context):
1929         layout = self.layout
1930
1931         layout.operator_context = 'INVOKE_REGION_WIN'
1932         layout.operator_enum("object.metaball_add", "type")
1933
1934
1935 class TOPBAR_MT_edit_curve_add(Menu):
1936     bl_idname = "TOPBAR_MT_edit_curve_add"
1937     bl_label = "Add"
1938     bl_translation_context = i18n_contexts.operator_default
1939
1940     def draw(self, context):
1941         is_surf = context.active_object.type == 'SURFACE'
1942
1943         layout = self.layout
1944         layout.operator_context = 'EXEC_REGION_WIN'
1945
1946         if is_surf:
1947             VIEW3D_MT_surface_add.draw(self, context)
1948         else:
1949             VIEW3D_MT_curve_add.draw(self, context)
1950
1951
1952 class TOPBAR_MT_edit_armature_add(Menu):
1953     bl_idname = "TOPBAR_MT_edit_armature_add"
1954     bl_label = "Armature"
1955
1956     def draw(self, _context):
1957         layout = self.layout
1958
1959         layout.operator_context = 'EXEC_REGION_WIN'
1960         layout.operator("armature.bone_primitive_add", text="Single Bone", icon='BONE_DATA')
1961
1962
1963 class VIEW3D_MT_armature_add(Menu):
1964     bl_idname = "VIEW3D_MT_armature_add"
1965     bl_label = "Armature"
1966
1967     def draw(self, _context):
1968         layout = self.layout
1969
1970         layout.operator_context = 'EXEC_REGION_WIN'
1971         layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA')
1972
1973
1974 class VIEW3D_MT_light_add(Menu):
1975     bl_idname = "VIEW3D_MT_light_add"
1976     bl_label = "Light"
1977
1978     def draw(self, _context):
1979         layout = self.layout
1980
1981         layout.operator_context = 'INVOKE_REGION_WIN'
1982         layout.operator_enum("object.light_add", "type")
1983
1984
1985 class VIEW3D_MT_lightprobe_add(Menu):
1986     bl_idname = "VIEW3D_MT_lightprobe_add"
1987     bl_label = "Light Probe"
1988
1989     def draw(self, _context):
1990         layout = self.layout
1991
1992         layout.operator_context = 'INVOKE_REGION_WIN'
1993         layout.operator_enum("object.lightprobe_add", "type")
1994
1995
1996 class VIEW3D_MT_camera_add(Menu):
1997     bl_idname = "VIEW3D_MT_camera_add"
1998     bl_label = "Camera"
1999
2000     def draw(self, _context):
2001         layout = self.layout
2002         layout.operator_context = 'EXEC_REGION_WIN'
2003         layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
2004
2005
2006 class VIEW3D_MT_add(Menu):
2007     bl_label = "Add"
2008     bl_translation_context = i18n_contexts.operator_default
2009
2010     def draw(self, context):
2011         layout = self.layout
2012
2013         # note, don't use 'EXEC_SCREEN' or operators won't get the 'v3d' context.
2014
2015         # Note: was EXEC_AREA, but this context does not have the 'rv3d', which prevents
2016         #       "align_view" to work on first call (see [#32719]).
2017         layout.operator_context = 'EXEC_REGION_WIN'
2018
2019         # layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH')
2020         layout.menu("VIEW3D_MT_mesh_add", icon='OUTLINER_OB_MESH')
2021
2022         # layout.operator_menu_enum("object.curve_add", "type", text="Curve", icon='OUTLINER_OB_CURVE')
2023         layout.menu("VIEW3D_MT_curve_add", icon='OUTLINER_OB_CURVE')
2024         # layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE')
2025         layout.menu("VIEW3D_MT_surface_add", icon='OUTLINER_OB_SURFACE')
2026         layout.menu("VIEW3D_MT_metaball_add", text="Metaball", icon='OUTLINER_OB_META')
2027         layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
2028         layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
2029
2030         layout.separator()
2031
2032         if VIEW3D_MT_armature_add.is_extended():
2033             layout.menu("VIEW3D_MT_armature_add", icon='OUTLINER_OB_ARMATURE')
2034         else:
2035             layout.operator("object.armature_add", text="Armature", icon='OUTLINER_OB_ARMATURE')
2036
2037         layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
2038
2039         layout.separator()
2040
2041         layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY')
2042         layout.menu("VIEW3D_MT_image_add", text="Image", icon='OUTLINER_OB_IMAGE')
2043
2044         layout.separator()
2045
2046         layout.menu("VIEW3D_MT_light_add", icon='OUTLINER_OB_LIGHT')
2047         layout.menu("VIEW3D_MT_lightprobe_add", icon='OUTLINER_OB_LIGHTPROBE')
2048
2049         layout.separator()
2050
2051         if VIEW3D_MT_camera_add.is_extended():
2052             layout.menu("VIEW3D_MT_camera_add", icon='OUTLINER_OB_CAMERA')
2053         else:
2054             VIEW3D_MT_camera_add.draw(self, context)
2055
2056         layout.separator()
2057
2058         layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
2059
2060         layout.separator()
2061
2062         layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD')
2063
2064         layout.separator()
2065
2066         has_collections = bool(bpy.data.collections)
2067         col = layout.column()
2068         col.enabled = has_collections
2069
2070         if not has_collections or len(bpy.data.collections) > 10:
2071             col.operator_context = 'INVOKE_REGION_WIN'
2072             col.operator(
2073                 "object.collection_instance_add",
2074                 text="Collection Instance..." if has_collections else "No Collections to Instance",
2075                 icon='OUTLINER_OB_GROUP_INSTANCE',
2076             )
2077         else:
2078             col.operator_menu_enum(
2079                 "object.collection_instance_add",
2080                 "collection",
2081                 text="Collection Instance",
2082                 icon='OUTLINER_OB_GROUP_INSTANCE',
2083             )
2084
2085
2086 class VIEW3D_MT_image_add(Menu):
2087     bl_label = "Add Image"
2088
2089     def draw(self, _context):
2090         layout = self.layout
2091         layout.operator("object.load_reference_image", text="Reference", icon='IMAGE_REFERENCE')
2092         layout.operator("object.load_background_image", text="Background", icon='IMAGE_BACKGROUND')
2093
2094
2095 class VIEW3D_MT_object_relations(Menu):
2096     bl_label = "Relations"
2097
2098     def draw(self, _context):
2099         layout = self.layout
2100
2101         layout.operator("object.proxy_make", text="Make Proxy...")
2102
2103         layout.operator("object.make_dupli_face")
2104
2105         layout.separator()
2106
2107         layout.operator_menu_enum("object.make_local", "type", text="Make Local...")
2108         layout.menu("VIEW3D_MT_make_single_user")
2109
2110         layout.separator()
2111
2112         layout.operator("object.data_transfer")
2113         layout.operator("object.datalayout_transfer")
2114
2115
2116 class VIEW3D_MT_object(Menu):
2117     bl_context = "objectmode"
2118     bl_label = "Object"
2119
2120     def draw(self, context):
2121         layout = self.layout
2122
2123         layout.menu("VIEW3D_MT_transform_object")
2124         layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2125         layout.menu("VIEW3D_MT_mirror")
2126         layout.menu("VIEW3D_MT_object_clear")
2127         layout.menu("VIEW3D_MT_object_apply")
2128         layout.menu("VIEW3D_MT_snap")
2129
2130         layout.separator()
2131
2132         layout.operator("object.duplicate_move")
2133         layout.operator("object.duplicate_move_linked")
2134         layout.operator("object.join")
2135
2136         layout.separator()
2137
2138         layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
2139         layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
2140
2141         layout.separator()
2142
2143         layout.menu("VIEW3D_MT_object_parent")
2144         layout.menu("VIEW3D_MT_object_collection")
2145         layout.menu("VIEW3D_MT_object_relations")
2146         layout.menu("VIEW3D_MT_object_constraints")
2147         layout.menu("VIEW3D_MT_object_track")
2148         layout.menu("VIEW3D_MT_make_links", text="Make Links")
2149
2150         layout.separator()
2151
2152         layout.operator("object.shade_smooth")
2153         layout.operator("object.shade_flat")
2154
2155         layout.separator()
2156
2157         layout.menu("VIEW3D_MT_object_animation")
2158         layout.menu("VIEW3D_MT_object_rigid_body")
2159
2160         layout.separator()
2161
2162         layout.menu("VIEW3D_MT_object_quick_effects")
2163
2164         layout.separator()
2165
2166         ob = context.active_object
2167         if ob and ob.type == 'GPENCIL' and context.gpencil_data:
2168             layout.operator_menu_enum("gpencil.convert", "type", text="Convert to")
2169         else:
2170             layout.operator_menu_enum("object.convert", "target")
2171
2172         layout.separator()
2173
2174         layout.menu("VIEW3D_MT_object_showhide")
2175
2176         layout.separator()
2177
2178         layout.operator_context = 'EXEC_DEFAULT'
2179         layout.operator("object.delete", text="Delete").use_global = False
2180         layout.operator("object.delete", text="Delete Global").use_global = True
2181
2182
2183 class VIEW3D_MT_object_animation(Menu):
2184     bl_label = "Animation"
2185
2186     def draw(self, _context):
2187         layout = self.layout
2188
2189         layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
2190         layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframes...")
2191         layout.operator("anim.keyframe_clear_v3d", text="Clear Keyframes...")
2192         layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
2193
2194         layout.separator()
2195
2196         layout.operator("nla.bake", text="Bake Action...")
2197
2198
2199 class VIEW3D_MT_object_rigid_body(Menu):
2200     bl_label = "Rigid Body"
2201
2202     def draw(self, _context):
2203         layout = self.layout
2204
2205         layout.operator("rigidbody.objects_add", text="Add Active").type = 'ACTIVE'
2206         layout.operator("rigidbody.objects_add", text="Add Passive").type = 'PASSIVE'
2207
2208         layout.separator()
2209
2210         layout.operator("rigidbody.objects_remove", text="Remove")
2211
2212         layout.separator()
2213
2214         layout.operator("rigidbody.shape_change", text="Change Shape")
2215         layout.operator("rigidbody.mass_calculate", text="Calculate Mass")
2216         layout.operator("rigidbody.object_settings_copy", text="Copy from Active")
2217         layout.operator("object.visual_transform_apply", text="Apply Transformation")
2218         layout.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
2219
2220         layout.separator()
2221
2222         layout.operator("rigidbody.connect", text="Connect")
2223
2224
2225 class VIEW3D_MT_object_clear(Menu):
2226     bl_label = "Clear"
2227
2228     def draw(self, _context):
2229         layout = self.layout
2230
2231         layout.operator("object.location_clear", text="Location").clear_delta = False
2232         layout.operator("object.rotation_clear", text="Rotation").clear_delta = False
2233         layout.operator("object.scale_clear", text="Scale").clear_delta = False
2234
2235         layout.separator()
2236
2237         layout.operator("object.origin_clear", text="Origin")
2238
2239
2240 class VIEW3D_MT_object_context_menu(Menu):
2241     bl_label = "Object Context Menu"
2242
2243     def draw(self, context):
2244
2245         layout = self.layout
2246         view = context.space_data
2247
2248         obj = context.object
2249
2250         selected_objects_len = len(context.selected_objects)
2251
2252         # If nothing is selected
2253         # (disabled for now until it can be made more useful).
2254         '''
2255         if selected_objects_len == 0:
2256
2257             layout.menu("VIEW3D_MT_add", text="Add", text_ctxt=i18n_contexts.operator_default)
2258             layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
2259
2260             return
2261         '''
2262
2263         # If something is selected
2264         if obj is not None and obj.type in {'MESH', 'CURVE', 'SURFACE'}:
2265             layout.operator("object.shade_smooth", text="Shade Smooth")
2266             layout.operator("object.shade_flat", text="Shade Flat")
2267
2268             layout.separator()
2269
2270         if obj is None:
2271             pass
2272         elif obj.type == 'MESH':
2273             layout.operator_context = 'INVOKE_REGION_WIN'
2274             layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2275
2276             layout.operator_context = 'INVOKE_DEFAULT'
2277             # If more than one object is selected
2278             if selected_objects_len > 1:
2279                 layout.operator("object.join")
2280
2281             layout.separator()
2282
2283         elif obj.type == 'CAMERA':
2284             layout.operator_context = 'INVOKE_REGION_WIN'
2285
2286             if obj.data.type == 'PERSP':
2287                 props = layout.operator("wm.context_modal_mouse", text="Camera Lens Angle")
2288                 props.data_path_iter = "selected_editable_objects"
2289                 props.data_path_item = "data.lens"
2290                 props.input_scale = 0.1
2291                 if obj.data.lens_unit == 'MILLIMETERS':
2292                     props.header_text = "Camera Lens Angle: %.1fmm"
2293                 else:
2294                     props.header_text = "Camera Lens Angle: %.1f\u00B0"
2295
2296             else:
2297                 props = layout.operator("wm.context_modal_mouse", text="Camera Lens Scale")
2298                 props.data_path_iter = "selected_editable_objects"
2299                 props.data_path_item = "data.ortho_scale"
2300                 props.input_scale = 0.01
2301                 props.header_text = "Camera Lens Scale: %.3f"
2302
2303             if not obj.data.dof.focus_object:
2304                 if view and view.camera == obj and view.region_3d.view_perspective == 'CAMERA':
2305                     props = layout.operator("ui.eyedropper_depth", text="DOF Distance (Pick)")
2306                 else:
2307                     props = layout.operator("wm.context_modal_mouse", text="DOF Distance")
2308                     props.data_path_iter = "selected_editable_objects"
2309                     props.data_path_item = "data.dof.focus_distance"
2310                     props.input_scale = 0.02
2311                     props.header_text = "DOF Distance: %.3f"
2312
2313             layout.separator()
2314
2315         elif obj.type in {'CURVE', 'FONT'}:
2316             layout.operator_context = 'INVOKE_REGION_WIN'
2317
2318             props = layout.operator("wm.context_modal_mouse", text="Extrude Size")
2319             props.data_path_iter = "selected_editable_objects"
2320             props.data_path_item = "data.extrude"
2321             props.input_scale = 0.01
2322             props.header_text = "Extrude Size: %.3f"
2323
2324             props = layout.operator("wm.context_modal_mouse", text="Width Size")
2325             props.data_path_iter = "selected_editable_objects"
2326             props.data_path_item = "data.offset"
2327             props.input_scale = 0.01
2328             props.header_text = "Width Size: %.3f"
2329
2330             layout.separator()
2331
2332             layout.operator("object.convert", text="Convert to Mesh").target = 'MESH'
2333             layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2334
2335             layout.separator()
2336
2337         elif obj.type == 'GPENCIL':
2338             layout.operator("gpencil.convert", text="Convert to Path").type = 'PATH'
2339             layout.operator("gpencil.convert", text="Convert to Bezier Curves").type = 'CURVE'
2340             layout.operator("gpencil.convert", text="Convert to Mesh").type = 'POLY'
2341
2342             layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
2343
2344             layout.separator()
2345
2346         elif obj.type == 'EMPTY':
2347             layout.operator_context = 'INVOKE_REGION_WIN'
2348
2349             props = layout.operator("wm.context_modal_mouse", text="Empty Draw Size")
2350             props.data_path_iter = "selected_editable_objects"
2351             props.data_path_item = "empty_display_size"
2352             props.input_scale = 0.01
2353             props.header_text = "Empty Draw Size: %.3f"
2354
2355             layout.separator()
2356
2357         elif obj.type == 'LIGHT':
2358             light = obj.data
2359
2360             layout.operator_context = 'INVOKE_REGION_WIN'
2361
2362             props = layout.operator("wm.context_modal_mouse", text="Energy")
2363             props.data_path_iter = "selected_editable_objects"
2364             props.data_path_item = "data.energy"
2365             props.header_text = "Light Energy: %.3f"
2366
2367             if light.type == 'AREA':
2368                 props = layout.operator("wm.context_modal_mouse", text="Size X")
2369                 props.data_path_iter = "selected_editable_objects"
2370                 props.data_path_item = "data.size"
2371                 props.header_text = "Light Size X: %.3f"
2372
2373                 if light.shape in {'RECTANGLE', 'ELLIPSE'}:
2374                     props = layout.operator("wm.context_modal_mouse", text="Size Y")
2375                     props.data_path_iter = "selected_editable_objects"
2376                     props.data_path_item = "data.size_y"
2377                     props.header_text = "Light Size Y: %.3f"
2378
2379             elif light.type in {'SPOT', 'POINT'}:
2380                 props = layout.operator("wm.context_modal_mouse", text="Radius")
2381                 props.data_path_iter = "selected_editable_objects"
2382                 props.data_path_item = "data.shadow_soft_size"
2383                 props.header_text = "Light Radius: %.3f"
2384
2385             elif light.type == 'SUN':
2386                 props = layout.operator("wm.context_modal_mouse", text="Angle")
2387                 props.data_path_iter = "selected_editable_objects"
2388                 props.data_path_item = "data.angle"
2389                 props.header_text = "Light Angle: %.3f"
2390
2391             if light.type == 'SPOT':
2392                 layout.separator()
2393
2394                 props = layout.operator("wm.context_modal_mouse", text="Spot Size")
2395                 props.data_path_iter = "selected_editable_objects"
2396                 props.data_path_item = "data.spot_size"
2397                 props.input_scale = 0.01
2398                 props.header_text = "Spot Size: %.2f"
2399
2400                 props = layout.operator("wm.context_modal_mouse", text="Spot Blend")
2401                 props.data_path_iter = "selected_editable_objects"
2402                 props.data_path_item = "data.spot_blend"
2403                 props.input_scale = -0.01
2404                 props.header_text = "Spot Blend: %.2f"
2405
2406             layout.separator()
2407
2408         layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
2409         layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
2410
2411         layout.separator()
2412
2413         layout.operator("object.duplicate_move", icon='DUPLICATE')
2414         layout.operator("object.duplicate_move_linked")
2415
2416         layout.separator()
2417
2418         props = layout.operator("wm.call_panel", text="Rename Active Object...")
2419         props.name = "TOPBAR_PT_name"
2420         props.keep_open = False
2421
2422         layout.separator()
2423
2424         layout.menu("VIEW3D_MT_mirror")
2425         layout.menu("VIEW3D_MT_snap")
2426         layout.menu("VIEW3D_MT_object_parent")
2427         layout.operator_context = 'INVOKE_REGION_WIN'
2428
2429         if view and view.local_view:
2430             layout.operator("view3d.localview_remove_from")
2431         else:
2432             layout.operator("object.move_to_collection")
2433
2434         layout.separator()
2435
2436         layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
2437
2438         layout.separator()
2439
2440         layout.operator_context = 'EXEC_DEFAULT'
2441         layout.operator("object.delete", text="Delete").use_global = False
2442
2443
2444 class VIEW3D_MT_object_shading(Menu):
2445     # XXX, this menu is a place to store shading operator in object mode
2446     bl_label = "Shading"
2447
2448     def draw(self, _context):
2449         layout = self.layout
2450         layout.operator("object.shade_smooth", text="Smooth")
2451         layout.operator("object.shade_flat", text="Flat")
2452
2453
2454 class VIEW3D_MT_object_apply(Menu):
2455     bl_label = "Apply"
2456
2457     def draw(self, _context):
2458         layout = self.layout
2459
2460         props = layout.operator("object.transform_apply", text="Location", text_ctxt=i18n_contexts.default)
2461         props.location, props.rotation, props.scale = True, False, False
2462
2463         props = layout.operator("object.transform_apply", text="Rotation", text_ctxt=i18n_contexts.default)
2464         props.location, props.rotation, props.scale = False, True, False
2465
2466         props = layout.operator("object.transform_apply", text="Scale", text_ctxt=i18n_contexts.default)
2467         props.location, props.rotation, props.scale = False, False, True
2468
2469         props = layout.operator("object.transform_apply", text="All Transforms", text_ctxt=i18n_contexts.default)
2470         props.location, props.rotation, props.scale = True, True, True
2471
2472         props = layout.operator("object.transform_apply", text="Rotation & Scale", text_ctxt=i18n_contexts.default)
2473         props.location, props.rotation, props.scale = False, True, True
2474
2475         layout.separator()
2476
2477         layout.operator(
2478             "object.transforms_to_deltas",
2479             text="Location to Deltas",
2480             text_ctxt=i18n_contexts.default,
2481         ).mode = 'LOC'
2482         layout.operator(
2483             "object.transforms_to_deltas",
2484             text="Rotation to Deltas",
2485             text_ctxt=i18n_contexts.default,
2486         ).mode = 'ROT'
2487         layout.operator(
2488             "object.transforms_to_deltas",
2489             text="Scale to Deltas",
2490             text_ctxt=i18n_contexts.default,
2491         ).mode = 'SCALE'
2492
2493         layout.operator(
2494             "object.transforms_to_deltas",
2495             text="All Transforms to Deltas",
2496             text_ctxt=i18n_contexts.default,
2497         ).mode = 'ALL'
2498         layout.operator("object.anim_transforms_to_deltas")
2499
2500         layout.separator()
2501
2502         layout.operator(
2503             "object.visual_transform_apply",
2504             text="Visual Transform",
2505             text_ctxt=i18n_contexts.default,
2506         )
2507         layout.operator(
2508             "object.convert",
2509             text="Visual Geometry to Mesh",
2510             text_ctxt=i18n_contexts.default,
2511         ).target = 'MESH'
2512         layout.operator("object.duplicates_make_real")
2513
2514
2515 class VIEW3D_MT_object_parent(Menu):
2516     bl_label = "Parent"
2517
2518     def draw(self, _context):
2519         layout = self.layout
2520
2521         layout.operator_enum("object.parent_set", "type")
2522
2523         layout.separator()
2524
2525         layout.operator_enum("object.parent_clear", "type")
2526
2527
2528 class VIEW3D_MT_object_track(Menu):
2529     bl_label = "Track"
2530
2531     def draw(self, _context):
2532         layout = self.layout
2533
2534         layout.operator_enum("object.track_set", "type")
2535
2536         layout.separator()
2537
2538         layout.operator_enum("object.track_clear", "type")
2539
2540
2541 class VIEW3D_MT_object_collection(Menu):
2542     bl_label = "Collection"
2543
2544     def draw(self, _context):
2545         layout = self.layout
2546
2547         layout.operator("object.move_to_collection")
2548         layout.operator("object.link_to_collection")
2549
2550         layout.separator()
2551
2552         layout.operator("collection.create")
2553         # layout.operator_menu_enum("collection.objects_remove", "collection")  # BUGGY
2554         layout.operator("collection.objects_remove")
2555         layout.operator("collection.objects_remove_all")
2556
2557         layout.separator()
2558
2559         layout.operator("collection.objects_add_active")
2560         layout.operator("collection.objects_remove_active")
2561
2562
2563 class VIEW3D_MT_object_constraints(Menu):
2564     bl_label = "Constraints"
2565
2566     def draw(self, _context):
2567         layout = self.layout
2568
2569         layout.operator("object.constraint_add_with_targets")
2570         layout.operator("object.constraints_copy")
2571
2572         layout.separator()
2573
2574         layout.operator("object.constraints_clear")
2575
2576
2577 class VIEW3D_MT_object_quick_effects(Menu):
2578     bl_label = "Quick Effects"
2579
2580     def draw(self, _context):
2581         layout = self.layout
2582
2583         layout.operator("object.quick_fur")
2584         layout.operator("object.quick_explode")
2585         layout.operator("object.quick_smoke")
2586         layout.operator("object.quick_fluid")
2587
2588
2589 class VIEW3D_MT_object_showhide(Menu):
2590     bl_label = "Show/Hide"
2591
2592     def draw(self, _context):
2593         layout = self.layout
2594
2595         layout.operator("object.hide_view_clear")
2596
2597         layout.separator()
2598
2599         layout.operator("object.hide_view_set", text="Hide Selected").unselected = False
2600         layout.operator("object.hide_view_set", text="Hide Unselected").unselected = True
2601
2602
2603 class VIEW3D_MT_make_single_user(Menu):
2604     bl_label = "Make Single User"
2605
2606     def draw(self, _context):
2607         layout = self.layout
2608
2609         props = layout.operator("object.make_single_user", text="Object")
2610         props.object = True
2611         props.obdata = props.material = props.animation = False
2612
2613         props = layout.operator("object.make_single_user", text="Object & Data")
2614         props.object = props.obdata = True
2615         props.material = props.animation = False
2616
2617         props = layout.operator("object.make_single_user", text="Object & Data & Materials")
2618         props.object = props.obdata = props.material = True
2619         props.animation = False
2620
2621         props = layout.operator("object.make_single_user", text="Materials")
2622         props.material = True
2623         props.object = props.obdata = props.animation = False
2624
2625         props = layout.operator("object.make_single_user", text="Object Animation")
2626         props.animation = True
2627         props.object = props.obdata = props.material = False
2628
2629
2630 class VIEW3D_MT_make_links(Menu):
2631     bl_label = "Make Links"
2632
2633     def draw(self, _context):
2634         layout = self.layout
2635         operator_context_default = layout.operator_context
2636
2637         if len(bpy.data.scenes) > 10:
2638             layout.operator_context = 'INVOKE_REGION_WIN'
2639             layout.operator("object.make_links_scene", text="Objects to Scene...", icon='OUTLINER_OB_EMPTY')
2640         else:
2641             layout.operator_context = 'EXEC_REGION_WIN'
2642             layout.operator_menu_enum("object.make_links_scene", "scene", text="Objects to Scene")
2643
2644         layout.separator()
2645
2646         layout.operator_context = operator_context_default
2647
2648         layout.operator_enum("object.make_links_data", "type")  # inline
2649
2650         layout.operator("object.join_uvs")  # stupid place to add this!
2651
2652
2653
2654 class VIEW3D_MT_brush_paint_modes(Menu):
2655     bl_label = "Enabled Modes"
2656
2657     def draw(self, context):
2658         layout = self.layout
2659
2660         settings = UnifiedPaintPanel.paint_settings(context)
2661         brush = settings.brush
2662
2663         layout.prop(brush, "use_paint_sculpt", text="Sculpt")
2664         layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt")
2665         layout.prop(brush, "use_paint_vertex", text="Vertex Paint")
2666         layout.prop(brush, "use_paint_weight", text="Weight Paint")
2667         layout.prop(brush, "use_paint_image", text="Texture Paint")
2668
2669
2670 class VIEW3D_MT_paint_vertex(Menu):
2671     bl_label = "Paint"
2672
2673     def draw(self, _context):
2674         layout = self.layout
2675
2676         layout.operator("paint.vertex_color_set")
2677         layout.operator("paint.vertex_color_smooth")
2678         layout.operator("paint.vertex_color_dirt")
2679         layout.operator("paint.vertex_color_from_weight")
2680
2681         layout.separator()
2682
2683         layout.operator("paint.vertex_color_invert", text="Invert")
2684         layout.operator("paint.vertex_color_levels", text="Levels")
2685         layout.operator("paint.vertex_color_hsv", text="Hue Saturation Value")
2686         layout.operator("paint.vertex_color_brightness_contrast", text="Bright/Contrast")
2687
2688
2689 class VIEW3D_MT_hook(Menu):
2690     bl_label = "Hooks"
2691
2692     def draw(self, context):
2693         layout = self.layout
2694         layout.operator_context = 'EXEC_AREA'
2695         layout.operator("object.hook_add_newob")
2696         layout.operator("object.hook_add_selob").use_bone = False
2697         layout.operator("object.hook_add_selob", text="Hook to Selected Object Bone").use_bone = True
2698
2699         if any([mod.type == 'HOOK' for mod in context.active_object.modifiers]):
2700             layout.separator()
2701
2702             layout.operator_menu_enum("object.hook_assign", "modifier")
2703             layout.operator_menu_enum("object.hook_remove", "modifier")
2704
2705             layout.separator()
2706
2707             layout.operator_menu_enum("object.hook_select", "modifier")
2708             layout.operator_menu_enum("object.hook_reset", "modifier")
2709             layout.operator_menu_enum("object.hook_recenter", "modifier")
2710
2711
2712 class VIEW3D_MT_vertex_group(Menu):
2713     bl_label = "Vertex Groups"
2714
2715     def draw(self, context):
2716         layout = self.layout
2717
2718         layout.operator_context = 'EXEC_AREA'
2719         layout.operator("object.vertex_group_assign_new")
2720
2721         ob = context.active_object
2722         if ob.mode == 'EDIT' or (ob.mode == 'WEIGHT_PAINT' and ob.type == 'MESH' and ob.data.use_paint_mask_vertex):
2723             if ob.vertex_groups.active:
2724                 layout.separator()
2725
2726                 layout.operator("object.vertex_group_assign", text="Assign to Active Group")
2727                 layout.operator(
2728                     "object.vertex_group_remove_from",
2729                     text="Remove from Active Group",
2730                 ).use_all_groups = False
2731                 layout.operator("object.vertex_group_remove_from", text="Remove from All").use_all_groups = True
2732
2733         if ob.vertex_groups.active:
2734             layout.separator()
2735
2736             layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group")
2737             layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False
2738             layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True
2739
2740
2741 class VIEW3D_MT_gpencil_vertex_group(Menu):
2742     bl_label = "Vertex Groups"
2743
2744     def draw(self, context):
2745         layout = self.layout
2746
2747         layout.operator_context = 'EXEC_AREA'
2748         ob = context.active_object
2749
2750         layout.operator("object.vertex_group_add", text="Add New Group")
2751         ob = context.active_object
2752         if ob.vertex_groups.active:
2753             layout.separator()
2754
2755             layout.operator("gpencil.vertex_group_assign", text="Assign")
2756             layout.operator("gpencil.vertex_group_remove_from", text="Remove")
2757
2758             layout.operator("gpencil.vertex_group_select", text="Select")
2759             layout.operator("gpencil.vertex_group_deselect", text="Deselect")
2760
2761
2762 class VIEW3D_MT_paint_weight(Menu):
2763     bl_label = "Weights"
2764
2765     @staticmethod
2766     def draw_generic(layout, is_editmode=False):
2767
2768         if not is_editmode:
2769
2770             layout.operator("paint.weight_from_bones", text="Assign Automatic From Bones").type = 'AUTOMATIC'
2771             layout.operator("paint.weight_from_bones", text="Assign From Bone Envelopes").type = 'ENVELOPES'
2772
2773             layout.separator()
2774
2775         layout.operator("object.vertex_group_normalize_all", text="Normalize All")
2776         layout.operator("object.vertex_group_normalize", text="Normalize")
2777
2778         layout.separator()
2779
2780         layout.operator("object.vertex_group_mirror", text="Mirror")
2781         layout.operator("object.vertex_group_invert", text="Invert")
2782         layout.operator("object.vertex_group_clean", text="Clean")
2783
2784         layout.separator()
2785
2786         layout.operator("object.vertex_group_quantize", text="Quantize")
2787         layout.operator("object.vertex_group_levels", text="Levels")
2788         layout.operator("object.vertex_group_smooth", text="Smooth")
2789
2790         if not is_editmode:
2791             props = layout.operator("object.data_transfer", text="Transfer Weights")
2792             props.use_reverse_transfer = True
2793             props.data_type = 'VGROUP_WEIGHTS'
2794
2795         layout.operator("object.vertex_group_limit_total", text="Limit Total")
2796         layout.operator("object.vertex_group_fix", text="Fix Deforms")
2797
2798         if not is_editmode:
2799             layout.separator()
2800
2801             layout.operator("paint.weight_set")
2802
2803     def draw(self, _context):
2804         self.draw_generic(self.layout, is_editmode=False)
2805
2806
2807 class VIEW3D_MT_sculpt(Menu):
2808     bl_label = "Sculpt"
2809
2810     def draw(self, context):
2811         layout = self.layout
2812
2813         props = layout.operator("paint.hide_show", text="Show All")
2814         props.action = 'SHOW'
2815         props.area = 'ALL'
2816
2817         props = layout.operator("paint.hide_show", text="Hide Bounding Box")
2818         props.action = 'HIDE'
2819         props.area = 'INSIDE'
2820
2821         props = layout.operator("paint.hide_show", text="Show Bounding Box")
2822         props.action = 'SHOW'
2823         props.area = 'INSIDE'
2824
2825         props = layout.operator("paint.hide_show", text="Hide Masked")
2826         props.area = 'MASKED'
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.push")
3165         layout.operator("pose.relax")
3166         layout.operator("pose.breakdown")
3167
3168         layout.separator()
3169
3170         layout.operator("pose.paths_calculate", text="Calculate Motion Paths")
3171         layout.operator("pose.paths_clear", text="Clear Motion Paths")
3172
3173         layout.separator()
3174
3175         layout.operator("pose.hide").unselected = False
3176         layout.operator("pose.reveal")
3177
3178         layout.separator()
3179
3180         layout.operator("pose.user_transforms_clear")
3181
3182
3183 class BoneOptions:
3184     def draw(self, context):
3185         layout = self.layout
3186
3187         options = [
3188             "show_wire",
3189             "use_deform",
3190             "use_envelope_multiply",
3191             "use_inherit_rotation",
3192             "use_inherit_scale",
3193         ]
3194
3195         if context.mode == 'EDIT_ARMATURE':
3196             bone_props = bpy.types.EditBone.bl_rna.properties
3197             data_path_iter = "selected_bones"
3198             opt_suffix = ""
3199             options.append("lock")
3200         else:  # pose-mode
3201             bone_props = bpy.types.Bone.bl_rna.properties
3202             data_path_iter = "selected_pose_bones"
3203             opt_suffix = "bone."
3204
3205         for opt in options:
3206             props = layout.operator("wm.context_collection_boolean_set", text=bone_props[opt].name,
3207                                     text_ctxt=i18n_contexts.default)
3208             props.data_path_iter = data_path_iter
3209             props.data_path_item = opt_suffix + opt
3210             props.type = self.type
3211
3212
3213 class VIEW3D_MT_bone_options_toggle(Menu, BoneOptions):
3214     bl_label = "Toggle Bone Options"
3215     type = 'TOGGLE'
3216
3217
3218 class VIEW3D_MT_bone_options_enable(Menu, BoneOptions):
3219     bl_label = "Enable Bone Options"
3220     type = 'ENABLE'
3221
3222
3223 class VIEW3D_MT_bone_options_disable(Menu, BoneOptions):
3224     bl_label = "Disable Bone Options"
3225     type = 'DISABLE'
3226
3227
3228 # ********** Edit Menus, suffix from ob.type **********
3229
3230
3231 class VIEW3D_MT_edit_mesh(Menu):
3232     bl_label = "Mesh"
3233
3234     def draw(self, _context):
3235         layout = self.layout
3236
3237         with_bullet = bpy.app.build_options.bullet
3238
3239         layout.menu("VIEW3D_MT_transform")
3240         layout.menu("VIEW3D_MT_mirror")
3241         layout.menu("VIEW3D_MT_snap")
3242
3243         layout.separator()
3244
3245         layout.operator("mesh.duplicate_move", text="Duplicate")
3246         layout.menu("VIEW3D_MT_edit_mesh_extrude")
3247         layout.operator("mesh.split")
3248         layout.operator("mesh.bisect")
3249         layout.operator("mesh.knife_project")
3250
3251         if with_bullet:
3252             layout.operator("mesh.convex_hull")
3253
3254         layout.separator()
3255
3256         layout.operator("mesh.symmetrize")
3257         layout.operator("mesh.symmetry_snap")
3258
3259         layout.separator()
3260
3261         layout.menu("VIEW3D_MT_edit_mesh_normals")
3262         layout.menu("VIEW3D_MT_edit_mesh_shading")
3263         layout.menu("VIEW3D_MT_edit_mesh_weights")
3264         layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
3265
3266         layout.separator()
3267
3268         layout.menu("VIEW3D_MT_edit_mesh_showhide")
3269         layout.operator_menu_enum("mesh.separate", "type")
3270         layout.menu("VIEW3D_MT_edit_mesh_clean")
3271
3272         layout.separator()
3273
3274         layout.menu("VIEW3D_MT_edit_mesh_delete")
3275
3276
3277 class VIEW3D_MT_edit_mesh_context_menu(Menu):
3278     bl_label = ""
3279
3280     def draw(self, context):
3281
3282         def count_selected_items_for_objects_in_mode():
3283             selected_verts_len = 0
3284             selected_edges_len = 0
3285             selected_faces_len = 0
3286             for ob in context.objects_in_mode_unique_data:
3287                 v, e, f = ob.data.count_selected_items()
3288                 selected_verts_len += v
3289                 selected_edges_len += e
3290                 selected_faces_len += f
3291             return (selected_verts_len, selected_edges_len, selected_faces_len)
3292
3293         is_vert_mode, is_edge_mode, is_face_mode = context.tool_settings.mesh_select_mode
3294         selected_verts_len, selected_edges_len, selected_faces_len = count_selected_items_for_objects_in_mode()
3295
3296         del count_selected_items_for_objects_in_mode
3297
3298         layout = self.layout
3299
3300         layout.operator_context = 'INVOKE_REGION_WIN'
3301
3302         # If nothing is selected
3303         # (disabled for now until it can be made more useful).
3304         '''
3305         # If nothing is selected
3306         if not (selected_verts_len or selected_edges_len or selected_faces_len):
3307             layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
3308
3309             return
3310         '''
3311
3312         # Else something is selected
3313
3314         row = layout.row()
3315
3316         if is_vert_mode:
3317             col = row.column()
3318
3319             col.label(text="Vertex Context Menu", icon='VERTEXSEL')
3320             col.separator()
3321
3322             # Additive Operators
3323             col.operator("mesh.subdivide", text="Subdivide")
3324
3325             col.separator()
3326
3327             col.operator("mesh.extrude_vertices_move", text="Extrude Vertices")
3328             col.operator("mesh.bevel", text="Bevel Vertices").vertex_only = True
3329
3330             if selected_verts_len > 1:
3331                 col.separator()
3332                 col.operator("mesh.edge_face_add", text="New Edge/Face from Vertices")
3333                 col.operator("mesh.vert_connect_path", text="Connect Vertex Path")
3334                 col.operator("mesh.vert_connect", text="Connect Vertex Pairs")
3335
3336             col.separator()
3337
3338             # Deform Operators
3339             col.operator("transform.push_pull", text="Push/Pull")
3340             col.operator("transform.shrink_fatten", text="Shrink/Fatten")
3341             col.operator("transform.shear", text="Shear")
3342             col.operator("transform.vert_slide", text="Slide Vertices")
3343             col.operator("transform.vertex_random", text="Randomize Vertices")
3344             col.operator("mesh.vertices_smooth", text="Smooth Vertices")
3345             col.operator("mesh.vertices_smooth_laplacian", text="Smooth Laplacian")
3346
3347             col.separator()
3348
3349             col.menu("VIEW3D_MT_mirror", text="Mirror Vertices")
3350             col.menu("VIEW3D_MT_snap", text="Snap Vertices")
3351
3352             col.separator()
3353
3354             # Removal Operators
3355             if selected_verts_len > 1:
3356                 col.menu("VIEW3D_MT_edit_mesh_merge", text="Merge Vertices")
3357             col.operator("mesh.split")
3358             col.operator_menu_enum("mesh.separate", "type")
3359             col.operator("mesh.dissolve_verts")
3360             col.operator("mesh.delete", text="Delete Vertices").type = 'VERT'
3361
3362         if is_edge_mode:
3363             render = context.scene.render
3364
3365             col = row.column()
3366             col.label(text="Edge Context Menu", icon='EDGESEL')
3367             col.separator()
3368
3369             # Additive Operators
3370             col.operator("mesh.subdivide", text="Subdivide")
3371
3372             col.separator()
3373
3374             col.operator("mesh.extrude_edges_move", text="Extrude Edges")
3375             col.operator("mesh.bevel", text="Bevel Edges").vertex_only = False
3376             if selected_edges_len >= 2:
3377                 col.operator("mesh.bridge_edge_loops")
3378             if selected_edges_len >= 1:
3379                 col.operator("mesh.edge_face_add", text="New Face from Edges")
3380             if selected_edges_len >= 2:
3381                 col.operator("mesh.fill")
3382
3383             col.separator()
3384
3385             col.operator("mesh.loopcut_slide")
3386             col.operator("mesh.offset_edge_loops_slide")
3387             col.operator("mesh.knife_tool")
3388             col.operator("mesh.bisect")
3389             col.operator("mesh.bridge_edge_loops", text="Bridge Edge Loops")
3390
3391             col.separator()
3392
3393             # Deform Operators
3394             col.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
3395             col.operator("transform.edge_slide")
3396             col.operator("mesh.edge_split")
3397
3398             col.separator()
3399
3400             # Edge Flags
3401             col.operator("transform.edge_crease")
3402             col.operator("transform.edge_bevelweight")
3403
3404             col.separator()
3405
3406             col.operator("mesh.mark_seam").clear = False
3407             col.operator("mesh.mark_seam", text="Clear Seam").clear = True
3408
3409             col.separator()
3410
3411             col.operator("mesh.mark_sharp")
3412             col.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
3413
3414             if render.use_freestyle:
3415                 col.separator()
3416
3417                 col.operator("mesh.mark_freestyle_edge").clear = False
3418                 col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
3419
3420             col.separator()
3421
3422             # Removal Operators
3423             col.operator("mesh.unsubdivide")
3424             col.operator("mesh.split")
3425             col.operator_menu_enum("mesh.separate", "type")
3426             col.operator("mesh.dissolve_edges")
3427             col.operator("mesh.delete", text="Delete Edges").type = 'EDGE'
3428
3429         if is_face_mode:
3430             col = row.column()
3431
3432             col.label(text="Face Context Menu", icon='FACESEL')
3433             col.separator()
3434
3435             # Additive Operators
3436             col.operator("mesh.subdivide", text="Subdivide")
3437
3438             col.separator()
3439
3440             col.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
3441             col.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals")
3442             col.operator("mesh.extrude_faces_move", text="Extrude Individual Faces")
3443
3444             col.operator("mesh.inset")
3445             col.operator("mesh.poke")
3446
3447             if selected_faces_len >= 2:
3448                 col.operator("mesh.bridge_edge_loops", text="Bridge Faces")
3449
3450             col.separator()
3451
3452             # Modify Operators
3453             col.menu("VIEW3D_MT_uv_map", text="UV Unwrap Faces")
3454
3455             col.separator()
3456
3457             props = col.operator("mesh.quads_convert_to_tris")
3458             props.quad_method = props.ngon_method = 'BEAUTY'
3459             col.operator("mesh.tris_convert_to_quads")
3460
3461             col.separator()
3462
3463             col.operator("mesh.faces_shade_smooth")
3464             col.operator("mesh.faces_shade_flat")
3465
3466             col.separator()
3467
3468             # Removal Operators
3469             col.operator("mesh.unsubdivide")
3470             col.operator("mesh.split")
3471             col.operator_menu_enum("mesh.separate", "type")
3472             col.operator("mesh.dissolve_faces")
3473             col.operator("mesh.delete", text="Delete Faces").type = 'FACE'
3474
3475
3476 class VIEW3D_MT_edit_mesh_select_mode(Menu):
3477     bl_label = "Mesh Select Mode"
3478
3479     def draw(self, _context):
3480         layout = self.layout
3481
3482         layout.operator_context = 'INVOKE_REGION_WIN'
3483         layout.operator("mesh.select_mode", text="Vertex", icon='VERTEXSEL').type = 'VERT'
3484         layout.operator("mesh.select_mode", text="Edge", icon='EDGESEL').type = 'EDGE'
3485         layout.operator("mesh.select_mode", text="Face", icon='FACESEL').type = 'FACE'
3486
3487
3488 class VIEW3D_MT_edit_mesh_extrude(Menu):
3489     bl_label = "Extrude"
3490
3491     _extrude_funcs = {
3492         'VERT': lambda layout:
3493         layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices"),
3494         'EDGE': lambda layout:
3495         layout.operator("mesh.extrude_edges_move", text="Extrude Edges"),
3496         'REGION': lambda layout:
3497         layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces"),
3498         'REGION_VERT_NORMAL': lambda layout:
3499         layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"),
3500         'FACE': lambda layout:
3501         layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"),
3502     }
3503
3504     @staticmethod
3505     def extrude_options(context):
3506         tool_settings = context.tool_settings
3507         select_mode = tool_settings.mesh_select_mode
3508         mesh = context.object.data
3509
3510         menu = []
3511         if mesh.total_face_sel:
3512             menu += ['REGION', 'REGION_VERT_NORMAL', 'FACE']
3513         if mesh.total_edge_sel and (select_mode[0] or select_mode[1]):
3514             menu += ['EDGE']
3515         if mesh.total_vert_sel and select_mode[0]:
3516             menu += ['VERT']
3517
3518         # should never get here
3519         return menu
3520
3521     def draw(self, context):
3522         layout = self.layout
3523         layout.operator_context = 'INVOKE_REGION_WIN'
3524
3525         for menu_id in self.extrude_options(context):
3526             self._extrude_funcs[menu_id](layout)
3527
3528
3529 class VIEW3D_MT_edit_mesh_vertices(Menu):
3530     bl_label = "Vertex"
3531
3532     def draw(self, _context):
3533         layout = self.layout
3534         layout.operator_context = 'INVOKE_REGION_WIN'
3535
3536         layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices")
3537         layout.operator("mesh.bevel", text="Bevel Vertices").vertex_only = True
3538
3539         layout.separator()
3540
3541         layout.operator("mesh.edge_face_add", text="New Edge/Face from Vertices")
3542         layout.operator("mesh.vert_connect_path", text="Connect Vertex Path")
3543         layout.operator("mesh.vert_connect", text="Connect Vertex Pairs")
3544
3545         layout.separator()
3546
3547         props = layout.operator("mesh.rip_move", text="Rip Vertices")
3548         props.MESH_OT_rip.use_fill = False
3549         props = layout.operator("mesh.rip_move", text="Rip Vertices and Fill")
3550         props.MESH_OT_rip.use_fill = True
3551         layout.operator("mesh.rip_edge_move", text="Rip Vertices and Extend")
3552
3553         layout.separator()
3554
3555         layout.operator("transform.vert_slide", text="Slide Vertices")
3556         layout.operator("mesh.vertices_smooth", text="Smooth Vertices")
3557
3558         layout.separator()
3559
3560         layout.operator("mesh.blend_from_shape")
3561         layout.operator("mesh.shape_propagate_to_all", text="Propagate to Shapes")
3562
3563         layout.separator()
3564
3565         layout.menu("VIEW3D_MT_edit_mesh_merge", text="Merge Vertices")
3566
3567         layout.separator()
3568
3569         layout.menu("VIEW3D_MT_vertex_group")
3570         layout.menu("VIEW3D_MT_hook")
3571
3572         layout.separator()
3573
3574         layout.operator("object.vertex_parent_set")
3575
3576
3577 class VIEW3D_MT_edit_mesh_edges_data(Menu):
3578     bl_label = "Edge Data"
3579
3580     def draw(self, context):
3581         layout = self.layout
3582
3583         render = context.scene.render
3584
3585         layout.operator_context = 'INVOKE_REGION_WIN'
3586
3587         layout.operator("transform.edge_crease")
3588         layout.operator("transform.edge_bevelweight")
3589
3590         layout.separator()
3591
3592         layout.operator("mesh.mark_seam").clear = False
3593         layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
3594
3595         layout.separator()
3596
3597         layout.operator("mesh.mark_sharp")
3598         layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
3599
3600         layout.operator("mesh.mark_sharp", text="Mark Sharp from Vertices").use_verts = True
3601         props = layout.operator("mesh.mark_sharp", text="Clear Sharp from Vertices")
3602         props.use_verts = True
3603         props.clear = True
3604
3605         if render.use_freestyle:
3606             layout.separator()
3607
3608             layout.operator("mesh.mark_freestyle_edge").clear = False
3609             layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
3610
3611
3612 class VIEW3D_MT_edit_mesh_edges(Menu):
3613     bl_label = "Edge"
3614
3615     def draw(self, _context):
3616         layout = self.layout
3617
3618         with_freestyle = bpy.app.build_options.freestyle
3619
3620         layout.operator_context = 'INVOKE_REGION_WIN'
3621
3622         layout.operator("mesh.extrude_edges_move", text="Extrude Edges")
3623         layout.operator("mesh.bevel", text="Bevel Edges").vertex_only = False
3624         layout.operator("mesh.bridge_edge_loops")
3625
3626         layout.separator()
3627
3628         layout.operator("mesh.subdivide")
3629         layout.operator("mesh.subdivide_edgering")
3630         layout.operator("mesh.unsubdivide")
3631
3632         layout.separator()
3633
3634         layout.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
3635         layout.operator("mesh.edge_rotate", text="Rotate Edge CCW").use_ccw = True
3636
3637         layout.separator()
3638
3639         layout.operator("transform.edge_slide")
3640         layout.operator("mesh.edge_split")
3641
3642         layout.separator()
3643
3644         layout.operator("transform.edge_crease")
3645         layout.operator("transform.edge_bevelweight")
3646
3647         layout.separator()
3648
3649         layout.operator("mesh.mark_seam").clear = False
3650         layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
3651
3652         layout.separator()
3653
3654         layout.operator("mesh.mark_sharp")
3655         layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
3656
3657         layout.operator("mesh.mark_sharp", text="Mark Sharp from Vertices").use_verts = True
3658         props = layout.operator("mesh.mark_sharp", text="Clear Sharp from Vertices")
3659         props.use_verts = True
3660         props.clear = True
3661
3662         if with_freestyle:
3663             layout.separator()
3664
3665             layout.operator("mesh.mark_freestyle_edge").clear = False
3666             layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
3667
3668
3669 class VIEW3D_MT_edit_mesh_faces_data(Menu):
3670     bl_label = "Face Data"
3671
3672     def draw(self, _context):
3673         layout = self.layout
3674
3675         with_freestyle = bpy.app.build_options.freestyle
3676
3677         layout.operator_context = 'INVOKE_REGION_WIN'
3678
3679         layout.operator("mesh.colors_rotate")
3680         layout.operator("mesh.colors_reverse")
3681
3682         layout.separator()
3683
3684         layout.operator("mesh.uvs_rotate")
3685         layout.operator("mesh.uvs_reverse")
3686
3687         layout.separator()
3688
3689         if with_freestyle:
3690             layout.operator("mesh.mark_freestyle_face").clear = False
3691             layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True
3692
3693
3694 class VIEW3D_MT_edit_mesh_faces(Menu):
3695     bl_label = "Face"
3696     bl_idname = "VIEW3D_MT_edit_mesh_faces"
3697
3698     def draw(self, _context):
3699         layout = self.layout
3700
3701         layout.operator_context = 'INVOKE_REGION_WIN'
3702
3703         layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
3704         layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals")
3705         layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces")
3706
3707         layout.separator()
3708
3709         layout.operator("mesh.inset")
3710         layout.operator("mesh.poke")
3711         props = layout.operator("mesh.quads_convert_to_tris")
3712         props.quad_method = props.ngon_method = 'BEAUTY'
3713         layout.operator("mesh.tris_convert_to_quads")
3714         layout.operator("mesh.solidify", text="Solidify Faces")
3715         layout.operator("mesh.wireframe")
3716
3717         layout.separator()
3718
3719         layout.operator("mesh.fill")
3720         layout.operator("mesh.fill_grid")
3721         layout.operator("mesh.beautify_fill")
3722
3723         layout.separator()
3724
3725         layout.operator("mesh.intersect")
3726         layout.operator("mesh.intersect_boolean")
3727
3728         layout.separator()
3729
3730         layout.operator("mesh.face_split_by_edges")
3731
3732         layout.separator()
3733
3734         layout.operator("mesh.faces_shade_smooth")
3735         layout.operator("mesh.faces_shade_flat")
3736
3737         layout.separator()
3738
3739         layout.menu("VIEW3D_MT_edit_mesh_faces_data")
3740
3741
3742 class VIEW3D_MT_edit_mesh_normals_select_strength(Menu):
3743     bl_label = "Select by Face Strength"
3744
3745     def draw(self, _context):
3746         layout = self.layout
3747
3748         op = layout.operator("mesh.mod_weighted_strength", text="Weak")
3749         op.set = False
3750         op.face_strength = 'WEAK'
3751
3752         op = layout.operator("mesh.mod_weighted_strength", text="Medium")
3753         op.set = False
3754         op.face_strength = 'MEDIUM'
3755
3756         op = layout.operator("mesh.mod_weighted_strength", text="Strong")
3757         op.set = False
3758         op.face_strength = 'STRONG'
3759
3760
3761 class VIEW3D_MT_edit_mesh_normals_set_strength(Menu):
3762     bl_label = "Select by Face Strength"
3763
3764     def draw(self, _context):
3765         layout = self.layout
3766
3767         op = layout.operator("mesh.mod_weighted_strength", text="Weak")
3768         op.set = True
3769         op.face_strength = 'WEAK'
3770
3771         op = layout.operator("mesh.mod_weighted_strength", text="Medium")
3772         op.set = True
3773         op.face_strength = 'MEDIUM'
3774
3775         op = layout.operator("mesh.mod_weighted_strength", text="Strong")
3776         op.set = True
3777         op.face_strength = 'STRONG'
3778
3779
3780 class VIEW3D_MT_edit_mesh_normals_average(Menu):
3781     bl_label = "Average"
3782
3783     def draw(self, _context):
3784         layout = self.layout
3785
3786         layout.operator("mesh.average_normals", text="Custom Normal").average_type = 'CUSTOM_NORMAL'
3787         layout.operator("mesh.average_normals", text="Face Area").average_type = 'FACE_AREA'
3788         layout.operator("mesh.average_normals", text="Corner Angle").average_type = 'CORNER_ANGLE'
3789
3790
3791 class VIEW3D_MT_edit_mesh_normals(Menu):
3792     bl_label = "Normals"
3793
3794     def draw(self, _context):
3795         layout = self.layout
3796
3797         layout.operator("mesh.flip_normals", text="Flip")
3798         layout.operator("mesh.normals_make_consistent", text="Recalculate Outside").inside = False
3799         layout.operator("mesh.normals_make_consistent", text="Recalculate Inside").inside = True
3800
3801         layout.separator()
3802
3803         layout.operator("mesh.set_normals_from_faces", text="Set From Faces")
3804
3805         layout.operator_context = 'INVOKE_REGION_WIN'
3806         layout.operator("transform.rotate_normal", text="Rotate...")
3807         layout.operator("mesh.point_normals", text="Point to Target...")
3808         layout.operator_context = 'EXEC_DEFAULT'
3809
3810         layout.operator("mesh.merge_normals", text="Merge")
3811         layout.operator("mesh.split_normals", text="Split")
3812         layout.menu("VIEW3D_MT_edit_mesh_normals_average", text="Average")
3813
3814         layout.separator()
3815
3816         layout.operator("mesh.normals_tools", text="Copy Vectors").mode = 'COPY'
3817         layout.operator("mesh.normals_tools", text="Paste Vectors").mode = 'PASTE'
3818
3819         layout.operator("mesh.smoothen_normals", text="Smoothen Vectors")
3820         layout.operator("mesh.normals_tools", text="Reset Vectors").mode = 'RESET'
3821
3822         layout.separator()
3823
3824         layout.menu("VIEW3D_MT_edit_mesh_normals_select_strength", text="Select by Face Strength")
3825         layout.menu("VIEW3D_MT_edit_mesh_normals_set_strength", text="Set Face Strength")
3826
3827
3828 class VIEW3D_MT_edit_mesh_shading(Menu):
3829     bl_label = "Shading"
3830
3831     def draw(self, _context):
3832         layout = self.layout
3833
3834         layout.operator("mesh.faces_shade_smooth", text="Smooth Faces")
3835         layout.operator("mesh.faces_shade_flat", text="Flat Faces")
3836
3837         layout.separator()
3838
3839         layout.operator("mesh.mark_sharp", text="Smooth Edges").clear = True
3840         layout.operator("mesh.mark_sharp", text="Sharp Edges")
3841
3842         layout.separator()
3843
3844         props = layout.operator("mesh.mark_sharp", text="Smooth Vertices")
3845         props.use_verts = True
3846         props.clear = True
3847
3848         layout.operator("mesh.mark_sharp", text="Sharp Vertices").use_verts = True
3849
3850
3851 class VIEW3D_MT_edit_mesh_weights(Menu):
3852     bl_label = "Weights"
3853
3854     def draw(self, _context):
3855         VIEW3D_MT_paint_weight.draw_generic(self.layout, is_editmode=True)
3856
3857
3858 class VIEW3D_MT_edit_mesh_clean(Menu):
3859     bl_label = "Clean Up"
3860
3861     def draw(self, _context):
3862         layout = self.layout
3863
3864         layout.operator("mesh.delete_loose")
3865
3866         layout.separator()
3867
3868         layout.operator("mesh.decimate")
3869         layout.operator("mesh.dissolve_degenerate")
3870         layout.operator("mesh.dissolve_limited")
3871         layout.operator("mesh.face_make_planar")
3872
3873         layout.separator()
3874
3875         layout.operator("mesh.vert_connect_nonplanar")
3876         layout.operator("mesh.vert_connect_concave")
3877         layout.operator("mesh.remove_doubles")
3878         layout.operator("mesh.fill_holes")
3879
3880
3881 class VIEW3D_MT_edit_mesh_delete(Menu):
3882     bl_label = "Delete"
3883
3884     def draw(self, _context):
3885         layout = self.layout
3886
3887         layout.operator_enum("mesh.delete", "type")
3888
3889         layout.separator()
3890
3891         layout.operator("mesh.dissolve_verts")
3892         layout.operator("mesh.dissolve_edges")
3893         layout.operator("mesh.dissolve_faces")
3894
3895         layout.separator()
3896
3897         layout.operator("mesh.dissolve_limited")
3898
3899         layout.separator()
3900
3901         layout.operator("mesh.edge_collapse")
3902         layout.operator("mesh.delete_edgeloop", text="Edge Loops")
3903
3904
3905 class VIEW3D_MT_edit_mesh_merge(Menu):
3906     bl_label = "Merge"
3907
3908     def draw(self, _context):
3909         layout = self.layout
3910
3911         layout.operator_enum("mesh.merge", "type")
3912
3913         layout.separator()
3914
3915         layout.operator("mesh.remove_doubles", text="By Distance")
3916
3917
3918 class VIEW3D_MT_edit_mesh_showhide(ShowHideMenu, Menu):
3919     _operator_name = "mesh"
3920
3921
3922 class VIEW3D_MT_edit_gpencil_delete(Menu):
3923     bl_label = "Delete"
3924
3925     def draw(self, _context):
3926         layout = self.layout
3927
3928         layout.operator_enum("gpencil.delete", "type")
3929
3930         layout.separator()
3931
3932         layout.operator_enum("gpencil.dissolve", "type")
3933
3934         layout.separator()
3935
3936         layout.operator("gpencil.active_frames_delete_all")
3937 # Edit Curve
3938 # draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface
3939
3940
3941 def draw_curve(self, _context):
3942     layout = self.layout
3943
3944     layout.menu("VIEW3D_MT_transform")
3945     layout.menu("VIEW3D_MT_mirror")
3946     layout.menu("VIEW3D_MT_snap")
3947
3948     layout.separator()
3949
3950     layout.operator("curve.spin")
3951     layout.operator("curve.duplicate_move")
3952
3953     layout.separator()
3954
3955     layout.operator("curve.split")
3956     layout.operator("curve.separate")
3957     layout.operator("curve.cyclic_toggle")
3958     layout.operator_menu_enum("curve.spline_type_set", "type")
3959
3960     layout.separator()
3961
3962     layout.menu("VIEW3D_MT_edit_curve_showhide")
3963     layout.menu("VIEW3D_MT_edit_curve_clean")
3964     layout.menu("VIEW3D_MT_edit_curve_delete")
3965
3966
3967 class VIEW3D_MT_edit_curve(Menu):
3968     bl_label = "Curve"
3969
3970     draw = draw_curve
3971
3972
3973 class VIEW3D_MT_edit_curve_ctrlpoints(Menu):
3974     bl_label = "Control Points"
3975
3976     def draw(self, context):
3977         layout = self.layout
3978
3979         edit_object = context.edit_object
3980
3981         if edit_object.type in {'CURVE', 'SURFACE'}:
3982             layout.operator("curve.extrude_move")
3983
3984             layout.separator()
3985
3986             layout.operator("curve.make_segment")
3987
3988             layout.separator()
3989
3990             if edit_object.type == 'CURVE':
3991                 layout.operator("transform.tilt")
3992                 layout.operator("curve.tilt_clear")
3993
3994                 layout.separator()
3995
3996                 layout.operator_menu_enum("curve.handle_type_set", "type")
3997                 layout.operator("curve.normals_make_consistent")
3998
3999                 layout.separator()
4000
4001             layout.operator("curve.smooth")
4002             if edit_object.type == 'CURVE':
4003                 layout.operator("curve.smooth_tilt")
4004                 layout.operator("curve.smooth_radius")
4005                 layout.operator("curve.smooth_weight")
4006
4007             layout.separator()
4008
4009         layout.menu("VIEW3D_MT_hook")
4010
4011         layout.separator()
4012
4013         layout.operator("object.vertex_parent_set")
4014
4015
4016 class VIEW3D_MT_edit_curve_segments(Menu):
4017     bl_label = "Segments"
4018
4019     def draw(self, _context):
4020         layout = self.layout
4021
4022         layout.operator("curve.subdivide")
4023     &nbs