6423c7eb6cd3dfcabf0288a403c16cd0541f54fb
[blender.git] / release / scripts / startup / bl_ui / space_toolsystem_toolbar.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
21 # For now group all tools together
22 # we may want to move these into per space-type files.
23 #
24 # For now keep this in a single file since it's an area that may change,
25 # so avoid making changes all over the place.
26
27 import bpy
28 from bpy.types import Panel
29
30 from .space_toolsystem_common import (
31     ToolSelectPanelHelper,
32     ToolDef,
33 )
34
35 from bpy.app.translations import pgettext_tip as tip_
36
37
38 I18N_CTX_OPERATOR = bpy.app.translations.contexts_C_to_py['BLT_I18NCONTEXT_OPERATOR_DEFAULT']
39
40
41 def kmi_to_string_or_none(kmi):
42     return kmi.to_string() if kmi else "<none>"
43
44
45 def generate_from_enum_ex(
46         _context, *,
47         idname_prefix,
48         icon_prefix,
49         type,
50         attr,
51         tooldef_keywords={},
52 ):
53     tool_defs = []
54     for enum in type.bl_rna.properties[attr].enum_items_static:
55         name = enum.name
56         idname = enum.identifier
57         tool_defs.append(
58             ToolDef.from_dict(
59                 dict(
60                     idname=idname_prefix + name,
61                     label=name,
62                     icon=icon_prefix + idname.lower(),
63                     data_block=idname,
64                     **tooldef_keywords,
65                 )
66             )
67         )
68     return tuple(tool_defs)
69
70
71 # Use for shared widget data.
72 class _template_widget:
73     class VIEW3D_GGT_xform_extrude:
74         @staticmethod
75         def draw_settings(_context, layout, tool):
76             props = tool.gizmo_group_properties("VIEW3D_GGT_xform_extrude")
77             layout.prop(props, "axis_type", expand=True)
78
79     class VIEW3D_GGT_xform_gizmo:
80         @staticmethod
81         def draw_settings_with_index(context, layout, index):
82             scene = context.scene
83             orient_slot = scene.transform_orientation_slots[index]
84             layout.prop(orient_slot, "type")
85
86
87 class _defs_view3d_generic:
88     @ToolDef.from_fn
89     def cursor():
90         def draw_settings(_context, layout, tool):
91             props = tool.operator_properties("view3d.cursor3d")
92             layout.prop(props, "use_depth")
93             layout.prop(props, "orientation")
94         return dict(
95             idname="builtin.cursor",
96             label="Cursor",
97             description=(
98                 "Set the cursor location, drag to transform"
99             ),
100             icon="ops.generic.cursor",
101             keymap="3D View Tool: Cursor",
102             draw_settings=draw_settings,
103         )
104
105     @ToolDef.from_fn
106     def cursor_click():
107         return dict(
108             idname="builtin.none",
109             label="None",
110             icon="ops.generic.cursor",
111             keymap=(),
112         )
113
114     @ToolDef.from_fn
115     def ruler():
116         def description(_context, _item, km):
117             if km is not None:
118                 kmi_add = km.keymap_items.find_from_operator("view3d.ruler_add")
119                 kmi_remove = km.keymap_items.find_from_operator("view3d.ruler_remove")
120             else:
121                 kmi_add = None
122                 kmi_remove = None
123             return tip_(
124                 "Measure distance and angles.\n"
125                 "\u2022 {} anywhere for new measurement.\n"
126                 "\u2022 Drag ruler segment to measure an angle.\n"
127                 "\u2022 {} to remove the active ruler.\n"
128                 "\u2022 Ctrl while dragging to snap.\n"
129                 "\u2022 Shift while dragging to measure surface thickness."
130             ).format(
131                 kmi_to_string_or_none(kmi_add),
132                 kmi_to_string_or_none(kmi_remove),
133             )
134         return dict(
135             idname="builtin.measure",
136             label="Measure",
137             description=description,
138             icon="ops.view3d.ruler",
139             widget="VIEW3D_GGT_ruler",
140             keymap="3D View Tool: Measure",
141         )
142
143
144 class _defs_annotate:
145
146     def draw_settings_common(context, layout, tool):
147         if type(context.gpencil_data_owner) is bpy.types.Object:
148             gpd = context.scene.grease_pencil
149         else:
150             gpd = context.gpencil_data
151
152         if gpd is not None:
153             if gpd.layers.active_note is not None:
154                 text = gpd.layers.active_note
155                 maxw = 25
156                 if len(text) > maxw:
157                     text = text[:maxw - 5] + '..' + text[-3:]
158             else:
159                 text = ""
160
161             gpl = context.active_gpencil_layer
162             if gpl is not None:
163                 layout.label(text="Annotation:")
164                 sub = layout.row(align=True)
165                 sub.ui_units_x = 8
166
167                 sub.prop(gpl, "color", text="")
168                 sub.popover(
169                     panel="TOPBAR_PT_annotation_layers",
170                     text=text,
171                 )
172
173         tool_settings = context.tool_settings
174         space_type = tool.space_type
175         if space_type == 'VIEW_3D':
176             layout.separator()
177
178             row = layout.row(align=True)
179             row.prop(tool_settings, "annotation_stroke_placement_view3d", text="Placement")
180             if tool_settings.gpencil_stroke_placement_view3d == 'CURSOR':
181                 row.prop(tool_settings.gpencil_sculpt, "lockaxis")
182             elif tool_settings.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}:
183                 row.prop(tool_settings, "use_gpencil_stroke_endpoints")
184
185     @ToolDef.from_fn.with_args(draw_settings=draw_settings_common)
186     def scribble(*, draw_settings):
187         return dict(
188             idname="builtin.annotate",
189             label="Annotate",
190             icon="ops.gpencil.draw",
191             cursor='PAINT_BRUSH',
192             keymap="Generic Tool: Annotate",
193             draw_settings=draw_settings,
194         )
195
196     @ToolDef.from_fn.with_args(draw_settings=draw_settings_common)
197     def line(*, draw_settings):
198         return dict(
199             idname="builtin.annotate_line",
200             label="Annotate Line",
201             icon="ops.gpencil.draw.line",
202             cursor='CROSSHAIR',
203             keymap="Generic Tool: Annotate Line",
204             draw_settings=draw_settings,
205         )
206
207     @ToolDef.from_fn.with_args(draw_settings=draw_settings_common)
208     def poly(*, draw_settings):
209         return dict(
210             idname="builtin.annotate_polygon",
211             label="Annotate Polygon",
212             icon="ops.gpencil.draw.poly",
213             cursor='CROSSHAIR',
214             keymap="Generic Tool: Annotate Polygon",
215             draw_settings=draw_settings,
216         )
217
218     @ToolDef.from_fn
219     def eraser():
220         def draw_settings(context, layout, _tool):
221             # TODO: Move this setting to tool_settings
222             prefs = context.preferences
223             layout.prop(prefs.edit, "grease_pencil_eraser_radius", text="Radius")
224         return dict(
225             idname="builtin.annotate_eraser",
226             label="Annotate Eraser",
227             icon="ops.gpencil.draw.eraser",
228             cursor='CROSSHAIR',  # XXX: Always show brush circle when enabled
229             keymap="Generic Tool: Annotate Eraser",
230             draw_settings=draw_settings,
231         )
232
233
234 class _defs_transform:
235
236     @ToolDef.from_fn
237     def translate():
238         def draw_settings(context, layout, _tool):
239             _template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
240         return dict(
241             idname="builtin.move",
242             label="Move",
243             # cursor='SCROLL_XY',
244             icon="ops.transform.translate",
245             widget="VIEW3D_GGT_xform_gizmo",
246             operator="transform.translate",
247             keymap="3D View Tool: Move",
248             draw_settings=draw_settings,
249         )
250
251     @ToolDef.from_fn
252     def rotate():
253         def draw_settings(context, layout, _tool):
254             _template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 2)
255         return dict(
256             idname="builtin.rotate",
257             label="Rotate",
258             # cursor='SCROLL_XY',
259             icon="ops.transform.rotate",
260             widget="VIEW3D_GGT_xform_gizmo",
261             operator="transform.rotate",
262             keymap="3D View Tool: Rotate",
263             draw_settings=draw_settings,
264         )
265
266     @ToolDef.from_fn
267     def scale():
268         def draw_settings(context, layout, _tool):
269             _template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 3)
270         return dict(
271             idname="builtin.scale",
272             label="Scale",
273             # cursor='SCROLL_XY',
274             icon="ops.transform.resize",
275             widget="VIEW3D_GGT_xform_gizmo",
276             operator="transform.resize",
277             keymap="3D View Tool: Scale",
278             draw_settings=draw_settings,
279         )
280
281     @ToolDef.from_fn
282     def scale_cage():
283         def draw_settings(context, layout, _tool):
284             _template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 3)
285         return dict(
286             idname="builtin.scale_cage",
287             label="Scale Cage",
288             icon="ops.transform.resize.cage",
289             widget="VIEW3D_GGT_xform_cage",
290             operator="transform.resize",
291             keymap="3D View Tool: Scale",
292             draw_settings=draw_settings,
293         )
294
295
296 class _defs_view3d_select:
297
298     @ToolDef.from_fn
299     def select():
300         def draw_settings(_context, _layout, _tool):
301             pass
302         return dict(
303             idname="builtin.select",
304             label="Select",
305             icon="ops.generic.select",
306             widget=None,
307             keymap="3D View Tool: Select",
308             draw_settings=draw_settings,
309         )
310
311     @ToolDef.from_fn
312     def box():
313         def draw_settings(_context, layout, tool):
314             props = tool.operator_properties("view3d.select_box")
315             row = layout.row()
316             row.use_property_split = False
317             row.prop(props, "mode", text="", expand=True, icon_only=True)
318         return dict(
319             idname="builtin.select_box",
320             label="Select Box",
321             icon="ops.generic.select_box",
322             widget=None,
323             keymap="3D View Tool: Select Box",
324             draw_settings=draw_settings,
325         )
326
327     @ToolDef.from_fn
328     def lasso():
329         def draw_settings(_context, layout, tool):
330             props = tool.operator_properties("view3d.select_lasso")
331             row = layout.row()
332             row.use_property_split = False
333             row.prop(props, "mode", text="", expand=True, icon_only=True)
334         return dict(
335             idname="builtin.select_lasso",
336             label="Select Lasso",
337             icon="ops.generic.select_lasso",
338             widget=None,
339             keymap="3D View Tool: Select Lasso",
340             draw_settings=draw_settings,
341         )
342
343     @ToolDef.from_fn
344     def circle():
345         def draw_settings(_context, layout, tool):
346             props = tool.operator_properties("view3d.select_circle")
347             row = layout.row()
348             row.use_property_split = False
349             row.prop(props, "mode", text="", expand=True, icon_only=True)
350             layout.prop(props, "radius")
351
352         def draw_cursor(_context, tool, xy):
353             from gpu_extras.presets import draw_circle_2d
354             props = tool.operator_properties("view3d.select_circle")
355             radius = props.radius
356             draw_circle_2d(xy, (1.0,) * 4, radius, 32)
357
358         return dict(
359             idname="builtin.select_circle",
360             label="Select Circle",
361             icon="ops.generic.select_circle",
362             widget=None,
363             keymap="3D View Tool: Select Circle",
364             draw_settings=draw_settings,
365             draw_cursor=draw_cursor,
366         )
367
368
369 # -----------------------------------------------------------------------------
370 # Object Modes (named based on context.mode)
371
372
373 class _defs_edit_armature:
374
375     @ToolDef.from_fn
376     def roll():
377         return dict(
378             idname="builtin.roll",
379             label="Roll",
380             icon="ops.armature.bone.roll",
381             widget=None,
382             keymap=(),
383         )
384
385     @ToolDef.from_fn
386     def bone_envelope():
387         return dict(
388             idname="builtin.bone_envelope",
389             label="Bone Envelope",
390             icon="ops.transform.bone_envelope",
391             widget=None,
392             keymap=(),
393         )
394
395     @ToolDef.from_fn
396     def bone_size():
397         return dict(
398             idname="builtin.bone_size",
399             label="Bone Size",
400             icon="ops.transform.bone_size",
401             widget=None,
402             keymap=(),
403         )
404
405     @ToolDef.from_fn
406     def extrude():
407         return dict(
408             idname="builtin.extrude",
409             label="Extrude",
410             icon="ops.armature.extrude_move",
411             widget="VIEW3D_GGT_xform_extrude",
412             keymap=(),
413             draw_settings=_template_widget.VIEW3D_GGT_xform_extrude.draw_settings,
414         )
415
416     @ToolDef.from_fn
417     def extrude_cursor():
418         return dict(
419             idname="builtin.extrude_to_cursor",
420             label="Extrude to Cursor",
421             icon="ops.armature.extrude_cursor",
422             widget=None,
423             keymap=(),
424         )
425
426
427 class _defs_edit_mesh:
428
429     @ToolDef.from_fn
430     def cube_add():
431         return dict(
432             idname="builtin.add_cube",
433             label="Add Cube",
434             icon="ops.mesh.primitive_cube_add_gizmo",
435             description=(
436                 "Add cube to mesh interactively"
437             ),
438             widget=None,
439             keymap=(),
440         )
441
442     @ToolDef.from_fn
443     def rip_region():
444         def draw_settings(_context, layout, tool):
445             props = tool.operator_properties("mesh.rip_move")
446             props_macro = props.MESH_OT_rip
447             layout.prop(props_macro, "use_fill")
448
449         return dict(
450             idname="builtin.rip_region",
451             label="Rip Region",
452             icon="ops.mesh.rip",
453             widget=None,
454             keymap=(),
455             draw_settings=draw_settings,
456         )
457
458     @ToolDef.from_fn
459     def rip_edge():
460         return dict(
461             idname="builtin.rip_edge",
462             label="Rip Edge",
463             icon="ops.mesh.rip_edge",
464             widget=None,
465             keymap=(),
466         )
467
468     @ToolDef.from_fn
469     def poly_build():
470         return dict(
471             idname="builtin.poly_build",
472             label="Poly Build",
473             icon="ops.mesh.polybuild_hover",
474             widget="VIEW3D_GGT_mesh_preselect_elem",
475             keymap=(),
476         )
477
478     @ToolDef.from_fn
479     def edge_slide():
480         def draw_settings(_context, layout, tool):
481             props = tool.operator_properties("transform.edge_slide")
482             layout.prop(props, "correct_uv")
483
484         return dict(
485             idname="builtin.edge_slide",
486             label="Edge Slide",
487             icon="ops.transform.edge_slide",
488             widget=None,
489             keymap=(),
490             draw_settings=draw_settings,
491         )
492
493     @ToolDef.from_fn
494     def vert_slide():
495         def draw_settings(_context, layout, tool):
496             props = tool.operator_properties("transform.vert_slide")
497             layout.prop(props, "correct_uv")
498
499         return dict(
500             idname="builtin.vertex_slide",
501             label="Vertex Slide",
502             icon="ops.transform.vert_slide",
503             widget=None,
504             keymap=(),
505             draw_settings=draw_settings,
506         )
507
508     @ToolDef.from_fn
509     def spin():
510         def draw_settings(_context, layout, tool):
511             props = tool.operator_properties("mesh.spin")
512             layout.prop(props, "steps")
513             props = tool.gizmo_group_properties("MESH_GGT_spin")
514             layout.prop(props, "axis")
515
516         return dict(
517             idname="builtin.spin",
518             label="Spin",
519             icon="ops.mesh.spin",
520             widget="MESH_GGT_spin",
521             keymap=(),
522             draw_settings=draw_settings,
523         )
524
525     @ToolDef.from_fn
526     def spin_duplicate():
527         def draw_settings(_context, layout, tool):
528             props = tool.operator_properties("mesh.spin")
529             layout.prop(props, "steps")
530             props = tool.gizmo_group_properties("MESH_GGT_spin")
531             layout.prop(props, "axis")
532
533         return dict(
534             idname="builtin.spin_duplicates",
535             label="Spin Duplicates",
536             icon="ops.mesh.spin.duplicate",
537             widget="MESH_GGT_spin",
538             keymap=(),
539             draw_settings=draw_settings,
540         )
541
542     @ToolDef.from_fn
543     def inset():
544         def draw_settings(_context, layout, tool):
545             props = tool.operator_properties("mesh.inset")
546             layout.prop(props, "use_outset")
547             layout.prop(props, "use_individual")
548             layout.prop(props, "use_even_offset")
549             layout.prop(props, "use_relative_offset")
550
551         return dict(
552             idname="builtin.inset_faces",
553             label="Inset Faces",
554             icon="ops.mesh.inset",
555             widget=None,
556             keymap=(),
557             draw_settings=draw_settings,
558         )
559
560     @ToolDef.from_fn
561     def bevel():
562         def draw_settings(_context, layout, tool):
563             props = tool.operator_properties("mesh.bevel")
564             layout.prop(props, "offset_type")
565             layout.prop(props, "segments")
566             layout.prop(props, "profile", slider=True)
567             layout.prop(props, "vertex_only")
568
569         return dict(
570             idname="builtin.bevel",
571             label="Bevel",
572             icon="ops.mesh.bevel",
573             widget=None,
574             keymap=(),
575             draw_settings=draw_settings,
576         )
577
578     @ToolDef.from_fn
579     def extrude():
580         return dict(
581             idname="builtin.extrude_region",
582             label="Extrude Region",
583             # The operator description isn't useful in this case, give our own.
584             description=(
585                 "Extrude freely or along an axis"
586             ),
587             icon="ops.mesh.extrude_region_move",
588             widget="VIEW3D_GGT_xform_extrude",
589             # Important to use same operator as 'E' key.
590             operator="view3d.edit_mesh_extrude_move_normal",
591             keymap=(),
592             draw_settings=_template_widget.VIEW3D_GGT_xform_extrude.draw_settings,
593         )
594
595     @ToolDef.from_fn
596     def extrude_normals():
597         def draw_settings(_context, layout, tool):
598             props = tool.operator_properties("mesh.extrude_region_shrink_fatten")
599             props_macro = props.TRANSFORM_OT_shrink_fatten
600             layout.prop(props_macro, "use_even_offset")
601         return dict(
602             idname="builtin.extrude_along_normals",
603             label="Extrude Along Normals",
604             icon="ops.mesh.extrude_region_shrink_fatten",
605             widget=None,
606             operator="mesh.extrude_region_shrink_fatten",
607             keymap=(),
608             draw_settings=draw_settings,
609         )
610
611     @ToolDef.from_fn
612     def extrude_individual():
613         return dict(
614             idname="builtin.extrude_individual",
615             label="Extrude Individual",
616             icon="ops.mesh.extrude_faces_move",
617             widget=None,
618             keymap=(),
619         )
620
621     @ToolDef.from_fn
622     def extrude_cursor():
623         def draw_settings(_context, layout, tool):
624             props = tool.operator_properties("mesh.dupli_extrude_cursor")
625             layout.prop(props, "rotate_source")
626
627         return dict(
628             idname="builtin.extrude_to_cursor",
629             label="Extrude to Cursor",
630             icon="ops.mesh.dupli_extrude_cursor",
631             widget=None,
632             keymap=(),
633             draw_settings=draw_settings,
634         )
635
636     @ToolDef.from_fn
637     def loopcut_slide():
638
639         def draw_settings(_context, layout, tool):
640             props = tool.operator_properties("mesh.loopcut_slide")
641             props_macro = props.MESH_OT_loopcut
642             layout.prop(props_macro, "number_cuts")
643             props_macro = props.TRANSFORM_OT_edge_slide
644             layout.prop(props_macro, "correct_uv")
645
646         return dict(
647             idname="builtin.loop_cut",
648             label="Loop Cut",
649             icon="ops.mesh.loopcut_slide",
650             widget="VIEW3D_GGT_mesh_preselect_edgering",
651             keymap=(),
652             draw_settings=draw_settings,
653         )
654
655     @ToolDef.from_fn
656     def offset_edge_loops_slide():
657         return dict(
658             idname="builtin.offset_edge_loop_cut",
659             label="Offset Edge Loop Cut",
660             icon="ops.mesh.offset_edge_loops_slide",
661             widget=None,
662             keymap=(),
663         )
664
665     @ToolDef.from_fn
666     def vertex_smooth():
667         def draw_settings(_context, layout, tool):
668             props = tool.operator_properties("mesh.vertices_smooth")
669             layout.prop(props, "repeat")
670         return dict(
671             idname="builtin.smooth",
672             label="Smooth",
673             icon="ops.mesh.vertices_smooth",
674             widget="WM_GGT_value_operator_redo",
675             keymap=(),
676             draw_settings=draw_settings,
677         )
678
679     @ToolDef.from_fn
680     def vertex_randomize():
681         def draw_settings(_context, layout, tool):
682             props = tool.operator_properties("transform.vertex_random")
683             layout.prop(props, "uniform")
684             layout.prop(props, "normal")
685             layout.prop(props, "seed")
686         return dict(
687             idname="builtin.randomize",
688             label="Randomize",
689             icon="ops.transform.vertex_random",
690             widget="WM_GGT_value_operator_redo",
691             keymap=(),
692             draw_settings=draw_settings,
693         )
694
695     @ToolDef.from_fn
696     def shear():
697         def draw_settings(context, layout, tool):
698             props = tool.operator_properties("transform.shear")
699             layout.label(text="View Axis:")
700             layout.prop(props, "shear_axis", expand=True)
701             _template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 2)
702         return dict(
703             idname="builtin.shear",
704             label="Shear",
705             icon="ops.transform.shear",
706             widget="VIEW3D_GGT_xform_shear",
707             keymap=(),
708             draw_settings=draw_settings,
709         )
710
711     @ToolDef.from_fn
712     def tosphere():
713         return dict(
714             idname="builtin.to_sphere",
715             label="To Sphere",
716             icon="ops.transform.tosphere",
717             widget=None,
718             keymap=(),
719         )
720
721     @ToolDef.from_fn
722     def shrink_fatten():
723         def draw_settings(_context, layout, tool):
724             props = tool.operator_properties("transform.shrink_fatten")
725             layout.prop(props, "use_even_offset")
726
727         return dict(
728             idname="builtin.shrink_fatten",
729             label="Shrink/Fatten",
730             icon="ops.transform.shrink_fatten",
731             widget=None,
732             keymap=(),
733             draw_settings=draw_settings,
734         )
735
736     @ToolDef.from_fn
737     def push_pull():
738         return dict(
739             idname="builtin.push_pull",
740             label="Push/Pull",
741             icon="ops.transform.push_pull",
742             widget=None,
743             keymap=(),
744         )
745
746     @ToolDef.from_fn
747     def knife():
748         def draw_settings(_context, layout, tool):
749             props = tool.operator_properties("mesh.knife_tool")
750             layout.prop(props, "use_occlude_geometry")
751             layout.prop(props, "only_selected")
752
753         return dict(
754             idname="builtin.knife",
755             label="Knife",
756             icon="ops.mesh.knife_tool",
757             widget=None,
758             keymap=(),
759             draw_settings=draw_settings,
760         )
761
762     @ToolDef.from_fn
763     def bisect():
764         def draw_settings(_context, layout, tool):
765             props = tool.operator_properties("mesh.bisect")
766             layout.prop(props, "use_fill")
767             layout.prop(props, "clear_inner")
768             layout.prop(props, "clear_outer")
769             layout.prop(props, "threshold")
770         return dict(
771             idname="builtin.bisect",
772             label="Bisect",
773             icon="ops.mesh.bisect",
774             widget=None,
775             keymap=(),
776             draw_settings=draw_settings,
777         )
778
779
780 class _defs_edit_curve:
781
782     @ToolDef.from_fn
783     def draw():
784         def draw_settings(context, layout, _tool):
785             # Tool settings initialize operator options.
786             tool_settings = context.tool_settings
787             cps = tool_settings.curve_paint_settings
788
789             col = layout.row()
790
791             col.prop(cps, "curve_type")
792
793             if cps.curve_type == 'BEZIER':
794                 col.prop(cps, "error_threshold")
795                 col.prop(cps, "fit_method")
796                 col.prop(cps, "use_corners_detect")
797
798                 col = layout.row()
799                 col.active = cps.use_corners_detect
800                 col.prop(cps, "corner_angle")
801
802         return dict(
803             idname="builtin.draw",
804             label="Draw",
805             cursor='PAINT_BRUSH',
806             icon="ops.curve.draw",
807             widget=None,
808             keymap=(),
809             draw_settings=draw_settings,
810         )
811
812     @ToolDef.from_fn
813     def extrude():
814         return dict(
815             idname="builtin.extrude",
816             label="Extrude",
817             icon="ops.curve.extrude_move",
818             widget="VIEW3D_GGT_xform_extrude",
819             keymap=(),
820             draw_settings=_template_widget.VIEW3D_GGT_xform_extrude.draw_settings,
821         )
822
823     @ToolDef.from_fn
824     def extrude_cursor():
825         return dict(
826             idname="builtin.extrude_cursor",
827             label="Extrude Cursor",
828             icon="ops.curve.extrude_cursor",
829             widget=None,
830             keymap=(),
831         )
832
833     @ToolDef.from_fn
834     def tilt():
835         return dict(
836             idname="builtin.tilt",
837             label="Tilt",
838             icon="ops.transform.tilt",
839             widget=None,
840             keymap=(),
841         )
842
843     @ToolDef.from_fn
844     def curve_radius():
845         return dict(
846             idname="builtin.radius",
847             label="Radius",
848             description=(
849                 "Expand or contract the radius of the selected curve points"
850             ),
851             icon="ops.curve.radius",
852             widget=None,
853             keymap=(),
854         )
855
856     @ToolDef.from_fn
857     def curve_vertex_randomize():
858         def draw_settings(_context, layout, tool):
859             props = tool.operator_properties("transform.vertex_random")
860             layout.prop(props, "uniform")
861             layout.prop(props, "normal")
862             layout.prop(props, "seed")
863         return dict(
864             idname="builtin.randomize",
865             label="Randomize",
866             icon="ops.curve.vertex_random",
867             widget="WM_GGT_value_operator_redo",
868             keymap=(),
869             draw_settings=draw_settings,
870         )
871
872
873 class _defs_pose:
874
875     @ToolDef.from_fn
876     def breakdown():
877         return dict(
878             idname="builtin.breakdowner",
879             label="Breakdowner",
880             icon="ops.pose.breakdowner",
881             widget=None,
882             keymap=(),
883         )
884
885     @ToolDef.from_fn
886     def push():
887         return dict(
888             idname="builtin.push",
889             label="Push",
890             icon="ops.pose.push",
891             widget=None,
892             keymap=(),
893         )
894
895     @ToolDef.from_fn
896     def relax():
897         return dict(
898             idname="builtin.relax",
899             label="Relax",
900             icon="ops.pose.relax",
901             widget=None,
902             keymap=(),
903         )
904
905
906 class _defs_particle:
907
908     @staticmethod
909     def generate_from_brushes(context):
910         return generate_from_enum_ex(
911             context,
912             idname_prefix="builtin_brush.",
913             icon_prefix="brush.particle.",
914             type=bpy.types.ParticleEdit,
915             attr="tool",
916         )
917
918
919 class _defs_sculpt:
920
921     @staticmethod
922     def generate_from_brushes(context):
923         return generate_from_enum_ex(
924             context,
925             idname_prefix="builtin_brush.",
926             icon_prefix="brush.sculpt.",
927             type=bpy.types.Brush,
928             attr="sculpt_tool",
929         )
930
931     @ToolDef.from_fn
932     def hide_border():
933         return dict(
934             idname="builtin.box_hide",
935             label="Box Hide",
936             icon="ops.sculpt.border_hide",
937             widget=None,
938             keymap=(),
939         )
940
941     @ToolDef.from_fn
942     def mask_border():
943         return dict(
944             idname="builtin.box_mask",
945             label="Box Mask",
946             icon="ops.sculpt.border_mask",
947             widget=None,
948             keymap=(),
949         )
950
951
952 class _defs_vertex_paint:
953
954     @staticmethod
955     def poll_select_mask(context):
956         if context is None:
957             return True
958         ob = context.active_object
959         return (ob and ob.type == 'MESH' and
960                 (ob.data.use_paint_mask or
961                  ob.data.use_paint_mask_vertex))
962
963     @staticmethod
964     def generate_from_brushes(context):
965         return generate_from_enum_ex(
966             context,
967             idname_prefix="builtin_brush.",
968             icon_prefix="brush.paint_vertex.",
969             type=bpy.types.Brush,
970             attr="vertex_tool",
971         )
972
973
974 class _defs_texture_paint:
975
976     @staticmethod
977     def poll_select_mask(context):
978         if context is None:
979             return True
980         ob = context.active_object
981         return (ob and ob.type == 'MESH' and
982                 (ob.data.use_paint_mask))
983
984     @staticmethod
985     def generate_from_brushes(context):
986         return generate_from_enum_ex(
987             context,
988             idname_prefix="builtin_brush.",
989             icon_prefix="brush.paint_texture.",
990             type=bpy.types.Brush,
991             attr="image_tool",
992         )
993
994
995 class _defs_weight_paint:
996
997     @staticmethod
998     def poll_select_mask(context):
999         if context is None:
1000             return True
1001         ob = context.active_object
1002         return (ob and ob.type == 'MESH' and
1003                 (ob.data.use_paint_mask or
1004                  ob.data.use_paint_mask_vertex))
1005
1006     @staticmethod
1007     def generate_from_brushes(context):
1008         return generate_from_enum_ex(
1009             context,
1010             idname_prefix="builtin_brush.",
1011             icon_prefix="brush.paint_weight.",
1012             type=bpy.types.Brush,
1013             attr="weight_tool",
1014         )
1015
1016     @ToolDef.from_fn
1017     def sample_weight():
1018         return dict(
1019             idname="builtin.sample_weight",
1020             label="Sample Weight",
1021             icon="ops.paint.weight_sample",
1022             widget=None,
1023             keymap=(),
1024         )
1025
1026     @ToolDef.from_fn
1027     def sample_weight_group():
1028         return dict(
1029             idname="builtin.sample_vertex_group",
1030             label="Sample Vertex Group",
1031             icon="ops.paint.weight_sample_group",
1032             widget=None,
1033             keymap=(),
1034         )
1035
1036     @ToolDef.from_fn
1037     def gradient():
1038         def draw_settings(context, layout, tool):
1039             brush = context.tool_settings.weight_paint.brush
1040             if brush is not None:
1041                 from .properties_paint_common import UnifiedPaintPanel
1042                 UnifiedPaintPanel.prop_unified_weight(layout, context, brush, "weight", slider=True)
1043                 UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True)
1044             props = tool.operator_properties("paint.weight_gradient")
1045             layout.prop(props, "type")
1046
1047         return dict(
1048             idname="builtin.gradient",
1049             label="Gradient",
1050             icon="ops.paint.weight_gradient",
1051             widget=None,
1052             keymap=(),
1053             draw_settings=draw_settings,
1054         )
1055
1056
1057 class _defs_image_generic:
1058
1059     @staticmethod
1060     def poll_uvedit(context):
1061         if context is None:
1062             return True
1063         ob = context.edit_object
1064         if ob is not None:
1065             data = ob.data
1066             if data is not None:
1067                 return bool(getattr(data, "uv_layers", False))
1068         return False
1069
1070     @ToolDef.from_fn
1071     def cursor():
1072         return dict(
1073             idname="builtin.cursor",
1074             label="Cursor",
1075             description=(
1076                 "Set the cursor location, drag to transform"
1077             ),
1078             icon="ops.generic.cursor",
1079             keymap=(),
1080         )
1081
1082     # Currently a place holder so we can switch away from the annotation tool.
1083     # Falls back to default image editor action.
1084     @ToolDef.from_fn
1085     def sample():
1086         def draw_settings(_context, layout, tool):
1087             props = tool.operator_properties("image.sample")
1088             layout.prop(props, "size")
1089         return dict(
1090             idname="builtin.sample",
1091             label="Sample",
1092             description=(
1093                 "Sample pixel values under the cursor"
1094             ),
1095             icon="ops.paint.weight_sample",  # XXX, needs own icon.
1096             keymap="Image Editor Tool: Sample",
1097             draw_settings=draw_settings,
1098         )
1099
1100
1101 class _defs_image_uv_transform:
1102
1103     @ToolDef.from_fn
1104     def transform():
1105         return dict(
1106             idname="builtin.transform",
1107             label="Transform",
1108             description=(
1109                 "Supports any combination of grab, rotate & scale at once"
1110             ),
1111             icon="ops.transform.transform",
1112             widget="IMAGE_GGT_gizmo2d",
1113             # No keymap default action, only for gizmo!
1114         )
1115
1116
1117 class _defs_image_uv_select:
1118
1119     @ToolDef.from_fn
1120     def select():
1121         def draw_settings(_context, _layout, _tool):
1122             pass
1123         return dict(
1124             idname="builtin.select",
1125             label="Select",
1126             icon="ops.generic.select",
1127             widget=None,
1128             keymap=(),
1129             draw_settings=draw_settings,
1130         )
1131
1132     @ToolDef.from_fn
1133     def box():
1134         def draw_settings(_context, layout, tool):
1135             props = tool.operator_properties("uv.select_box")
1136             row = layout.row()
1137             row.use_property_split = False
1138             row.prop(props, "mode", text="", expand=True, icon_only=True)
1139         return dict(
1140             idname="builtin.select_box",
1141             label="Select Box",
1142             icon="ops.generic.select_box",
1143             widget=None,
1144             keymap=(),
1145             draw_settings=draw_settings,
1146         )
1147
1148     @ToolDef.from_fn
1149     def lasso():
1150         def draw_settings(_context, layout, tool):
1151             props = tool.operator_properties("uv.select_lasso")
1152             row = layout.row()
1153             row.use_property_split = False
1154             row.prop(props, "mode", text="", expand=True, icon_only=True)
1155         return dict(
1156             idname="builtin.select_lasso",
1157             label="Select Lasso",
1158             icon="ops.generic.select_lasso",
1159             widget=None,
1160             keymap=(),
1161             draw_settings=draw_settings,
1162         )
1163
1164     @ToolDef.from_fn
1165     def circle():
1166         def draw_settings(_context, layout, tool):
1167             props = tool.operator_properties("uv.select_circle")
1168             row = layout.row()
1169             row.use_property_split = False
1170             row.prop(props, "mode", text="", expand=True, icon_only=True)
1171             layout.prop(props, "radius")
1172         return dict(
1173             idname="builtin.select_circle",
1174             label="Select Circle",
1175             icon="ops.generic.select_circle",
1176             widget=None,
1177             keymap=(),
1178             draw_settings=draw_settings,
1179         )
1180
1181
1182 class _defs_image_uv_sculpt:
1183
1184     @staticmethod
1185     def generate_from_brushes(context):
1186         def draw_cursor(context, _tool, xy):
1187             from gpu_extras.presets import draw_circle_2d
1188             tool_settings = context.tool_settings
1189             uv_sculpt = tool_settings.uv_sculpt
1190             if not uv_sculpt.show_brush:
1191                 return
1192             ups = tool_settings.unified_paint_settings
1193             if ups.use_unified_size:
1194                 radius = ups.size
1195             else:
1196                 brush = tool_settings.uv_sculpt.brush
1197                 if brush is None:
1198                     return
1199                 radius = brush.size
1200             draw_circle_2d(xy, (1.0,) * 4, radius, 32)
1201
1202         return generate_from_enum_ex(
1203             context,
1204             idname_prefix="builtin_brush.",
1205             icon_prefix="brush.uv_sculpt.",
1206             type=bpy.types.Brush,
1207             attr="uv_sculpt_tool",
1208             tooldef_keywords=dict(
1209                 operator="sculpt.uv_sculpt_stroke",
1210                 keymap="Image Editor Tool: Uv, Sculpt Stroke",
1211                 draw_cursor=draw_cursor,
1212             ),
1213         )
1214
1215
1216 class _defs_gpencil_paint:
1217
1218     @staticmethod
1219     def generate_from_brushes(context):
1220         return generate_from_enum_ex(
1221             context,
1222             idname_prefix="builtin_brush.",
1223             icon_prefix="brush.gpencil_draw.",
1224             type=bpy.types.Brush,
1225             attr="gpencil_tool",
1226             tooldef_keywords=dict(
1227                 operator="gpencil.draw",
1228             ),
1229         )
1230
1231     @ToolDef.from_fn
1232     def cutter():
1233         return dict(
1234             idname="builtin.cutter",
1235             label="Cutter",
1236             icon="ops.gpencil.stroke_cutter",
1237             cursor='KNIFE',
1238             widget=None,
1239             keymap=(),
1240         )
1241
1242     @ToolDef.from_fn
1243     def line():
1244         return dict(
1245             idname="builtin.line",
1246             label="Line",
1247             icon="ops.gpencil.primitive_line",
1248             cursor='CROSSHAIR',
1249             widget=None,
1250             keymap=(),
1251         )
1252
1253     @ToolDef.from_fn
1254     def box():
1255         return dict(
1256             idname="builtin.box",
1257             label="Box",
1258             icon="ops.gpencil.primitive_box",
1259             cursor='CROSSHAIR',
1260             widget=None,
1261             keymap=(),
1262         )
1263
1264     @ToolDef.from_fn
1265     def circle():
1266         return dict(
1267             idname="builtin.circle",
1268             label="Circle",
1269             icon="ops.gpencil.primitive_circle",
1270             cursor='CROSSHAIR',
1271             widget=None,
1272             keymap=(),
1273         )
1274
1275     @ToolDef.from_fn
1276     def arc():
1277         return dict(
1278             idname="builtin.arc",
1279             label="Arc",
1280             icon="ops.gpencil.primitive_arc",
1281             cursor='CROSSHAIR',
1282             widget=None,
1283             keymap=(),
1284         )
1285
1286     @ToolDef.from_fn
1287     def curve():
1288         return dict(
1289             idname="builtin.curve",
1290             label="Curve",
1291             icon="ops.gpencil.primitive_curve",
1292             cursor='CROSSHAIR',
1293             widget=None,
1294             keymap=(),
1295         )
1296
1297
1298 class _defs_gpencil_edit:
1299     @ToolDef.from_fn
1300     def bend():
1301         return dict(
1302             idname="builtin.bend",
1303             label="Bend",
1304             icon="ops.gpencil.edit_bend",
1305             widget=None,
1306             keymap=(),
1307         )
1308
1309     @ToolDef.from_fn
1310     def select():
1311         def draw_settings(context, layout, _tool):
1312             layout.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
1313         return dict(
1314             idname="builtin.select",
1315             label="Select",
1316             icon="ops.generic.select",
1317             widget=None,
1318             keymap=(),
1319             draw_settings=draw_settings,
1320         )
1321
1322     @ToolDef.from_fn
1323     def box_select():
1324         def draw_settings(context, layout, tool):
1325             props = tool.operator_properties("gpencil.select_box")
1326             row = layout.row()
1327             row.use_property_split = False
1328             row.prop(props, "mode", text="", expand=True, icon_only=True)
1329             layout.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
1330         return dict(
1331             idname="builtin.select_box",
1332             label="Select Box",
1333             icon="ops.generic.select_box",
1334             widget=None,
1335             keymap=(),
1336             draw_settings=draw_settings,
1337         )
1338
1339     @ToolDef.from_fn
1340     def lasso_select():
1341         def draw_settings(context, layout, tool):
1342             props = tool.operator_properties("gpencil.select_lasso")
1343             row = layout.row()
1344             row.use_property_split = False
1345             row.prop(props, "mode", text="", expand=True, icon_only=True)
1346             layout.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
1347         return dict(
1348             idname="builtin.select_lasso",
1349             label="Select Lasso",
1350             icon="ops.generic.select_lasso",
1351             widget=None,
1352             keymap=(),
1353             draw_settings=draw_settings,
1354         )
1355
1356     @ToolDef.from_fn
1357     def circle_select():
1358         def draw_settings(context, layout, tool):
1359             props = tool.operator_properties("gpencil.select_circle")
1360             row = layout.row()
1361             row.use_property_split = False
1362             row.prop(props, "mode", text="", expand=True, icon_only=True)
1363             layout.prop(props, "radius")
1364             layout.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
1365         return dict(
1366             idname="builtin.select_circle",
1367             label="Select Circle",
1368             icon="ops.generic.select_circle",
1369             widget=None,
1370             keymap=(),
1371             draw_settings=draw_settings,
1372         )
1373
1374     @ToolDef.from_fn
1375     def radius():
1376         return dict(
1377             idname="builtin.radius",
1378             label="Radius",
1379             description=(
1380                 "Expand or contract the radius of the selected points"
1381             ),
1382             icon="ops.gpencil.radius",
1383
1384             widget=None,
1385             keymap=(),
1386         )
1387
1388     @ToolDef.from_fn
1389     def shear():
1390         return dict(
1391             idname="builtin.shear",
1392             label="Shear",
1393             icon="ops.gpencil.edit_shear",
1394             widget=None,
1395             keymap=(),
1396         )
1397
1398     @ToolDef.from_fn
1399     def tosphere():
1400         return dict(
1401             idname="builtin.to_sphere",
1402             label="To Sphere",
1403             icon="ops.transform.tosphere",
1404             widget=None,
1405             keymap=(),
1406         )
1407
1408     @ToolDef.from_fn
1409     def extrude():
1410         return dict(
1411             idname="builtin.extrude",
1412             label="Extrude",
1413             icon="ops.gpencil.extrude_move",
1414             widget="VIEW3D_GGT_xform_extrude",
1415             keymap=(),
1416             draw_settings=_template_widget.VIEW3D_GGT_xform_extrude.draw_settings,
1417         )
1418
1419
1420 class _defs_gpencil_sculpt:
1421
1422     @staticmethod
1423     def generate_from_brushes(context):
1424         return generate_from_enum_ex(
1425             context,
1426             idname_prefix="builtin_brush.",
1427             icon_prefix="ops.gpencil.sculpt_",
1428             type=bpy.types.GPencilSculptSettings,
1429             attr="sculpt_tool",
1430         )
1431
1432
1433 class _defs_gpencil_weight:
1434
1435     @staticmethod
1436     def generate_from_brushes(context):
1437         return generate_from_enum_ex(
1438             context,
1439             idname_prefix="builtin_brush.",
1440             icon_prefix="ops.gpencil.sculpt_",
1441             type=bpy.types.GPencilSculptSettings,
1442             attr="weight_tool",
1443         )
1444
1445
1446 class _defs_node_select:
1447
1448     @ToolDef.from_fn
1449     def select():
1450         def draw_settings(_context, _layout, _tool):
1451             pass
1452         return dict(
1453             idname="builtin.select",
1454             label="Select",
1455             icon="ops.generic.select",
1456             widget=None,
1457             keymap="Node Tool: Select",
1458             draw_settings=draw_settings,
1459         )
1460
1461     @ToolDef.from_fn
1462     def box():
1463         def draw_settings(_context, layout, tool):
1464             props = tool.operator_properties("node.select_box")
1465             row = layout.row()
1466             row.use_property_split = False
1467             row.prop(props, "mode", text="", expand=True, icon_only=True)
1468             pass
1469         return dict(
1470             idname="builtin.select_box",
1471             label="Select Box",
1472             icon="ops.generic.select_box",
1473             widget=None,
1474             keymap="Node Tool: Select Box",
1475             draw_settings=draw_settings,
1476         )
1477
1478     @ToolDef.from_fn
1479     def lasso():
1480         def draw_settings(_context, layout, tool):
1481             props = tool.operator_properties("node.select_lasso")
1482             row = layout.row()
1483             row.use_property_split = False
1484             row.prop(props, "mode", text="", expand=True, icon_only=True)
1485         return dict(
1486             idname="builtin.select_lasso",
1487             label="Select Lasso",
1488             icon="ops.generic.select_lasso",
1489             widget=None,
1490             keymap="Node Tool: Select Lasso",
1491             draw_settings=draw_settings,
1492         )
1493
1494     @ToolDef.from_fn
1495     def circle():
1496         def draw_settings(_context, layout, tool):
1497             props = tool.operator_properties("node.select_circle")
1498             row = layout.row()
1499             row.use_property_split = False
1500             row.prop(props, "mode", text="", expand=True, icon_only=True)
1501             layout.prop(props, "radius")
1502         return dict(
1503             idname="builtin.select_circle",
1504             label="Select Circle",
1505             icon="ops.generic.select_circle",
1506             widget=None,
1507             keymap="Node Tool: Select Circle",
1508             draw_settings=draw_settings,
1509         )
1510
1511
1512 class _defs_node_edit:
1513
1514     @ToolDef.from_fn
1515     def links_cut():
1516         return dict(
1517             idname="builtin.links_cut",
1518             label="Links Cut",
1519             icon="ops.node.links_cut",
1520             widget=None,
1521             keymap="Node Tool: Links Cut",
1522         )
1523
1524
1525 class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
1526     bl_space_type = 'IMAGE_EDITOR'
1527     bl_region_type = 'TOOLS'
1528     bl_label = "Tools"  # not visible
1529     bl_options = {'HIDE_HEADER'}
1530
1531     # Satisfy the 'ToolSelectPanelHelper' API.
1532     keymap_prefix = "Image Editor Tool:"
1533
1534     @classmethod
1535     def tools_from_context(cls, context, mode=None):
1536         if mode is None:
1537             if context.space_data is None:
1538                 mode = 'VIEW'
1539             else:
1540                 mode = context.space_data.mode
1541         for tools in (cls._tools[None], cls._tools.get(mode, ())):
1542             for item in tools:
1543                 if not (type(item) is ToolDef) and callable(item):
1544                     yield from item(context)
1545                 else:
1546                     yield item
1547
1548     @classmethod
1549     def tools_all(cls):
1550         yield from cls._tools.items()
1551
1552     # for reuse
1553     _tools_transform = (
1554         _defs_image_uv_transform.transform,
1555     )
1556
1557     _tools_select = (
1558         (
1559             _defs_image_uv_select.select,
1560             _defs_image_uv_select.box,
1561             _defs_image_uv_select.circle,
1562             _defs_image_uv_select.lasso,
1563         ),
1564     )
1565
1566     _tools_annotate = (
1567         (
1568             _defs_annotate.scribble,
1569             _defs_annotate.line,
1570             _defs_annotate.poly,
1571             _defs_annotate.eraser,
1572         ),
1573     )
1574
1575     _tools = {
1576         None: [
1577             # for all modes
1578         ],
1579         'VIEW': [
1580             _defs_image_generic.sample,
1581             *_tools_annotate,
1582         ],
1583         'UV': [
1584             *_tools_select,
1585             _defs_image_generic.cursor,
1586             None,
1587             *_tools_transform,
1588             None,
1589             *_tools_annotate,
1590             None,
1591             lambda context: (
1592                 _defs_image_uv_sculpt.generate_from_brushes(context)
1593                 if _defs_image_generic.poll_uvedit(context)
1594                 else ()
1595             ),
1596         ],
1597         'MASK': [
1598             None,
1599         ],
1600         'PAINT': [
1601             _defs_texture_paint.generate_from_brushes,
1602         ],
1603     }
1604
1605
1606 class NODE_PT_tools_active(ToolSelectPanelHelper, Panel):
1607     bl_space_type = 'NODE_EDITOR'
1608     bl_region_type = 'TOOLS'
1609     bl_label = "Tools"  # not visible
1610     bl_options = {'HIDE_HEADER'}
1611
1612     # Satisfy the 'ToolSelectPanelHelper' API.
1613     keymap_prefix = "Node Editor Tool:"
1614
1615     @classmethod
1616     def tools_from_context(cls, context, mode=None):
1617         if mode is None:
1618             if context.space_data is None:
1619                 mode = None
1620             else:
1621                 mode = context.space_data.tree_type
1622         for tools in (cls._tools[None], cls._tools.get(mode, ())):
1623             for item in tools:
1624                 if not (type(item) is ToolDef) and callable(item):
1625                     yield from item(context)
1626                 else:
1627                     yield item
1628
1629     @classmethod
1630     def tools_all(cls):
1631         yield from cls._tools.items()
1632
1633     _tools_select = (
1634         (
1635             _defs_node_select.select,
1636             _defs_node_select.box,
1637             _defs_node_select.lasso,
1638             _defs_node_select.circle,
1639         ),
1640     )
1641
1642     _tools_annotate = (
1643         (
1644             _defs_annotate.scribble,
1645             _defs_annotate.line,
1646             _defs_annotate.poly,
1647             _defs_annotate.eraser,
1648         ),
1649     )
1650
1651     _tools = {
1652         None: [
1653             *_tools_select,
1654             None,
1655             *_tools_annotate,
1656             None,
1657             _defs_node_edit.links_cut,
1658         ],
1659     }
1660
1661
1662 class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
1663     bl_space_type = 'VIEW_3D'
1664     bl_region_type = 'TOOLS'
1665     bl_label = "Tools"  # not visible
1666     bl_options = {'HIDE_HEADER'}
1667
1668     # Satisfy the 'ToolSelectPanelHelper' API.
1669     keymap_prefix = "3D View Tool:"
1670
1671     @classmethod
1672     def tools_from_context(cls, context, mode=None):
1673         if mode is None:
1674             mode = context.mode
1675         for tools in (cls._tools[None], cls._tools.get(mode, ())):
1676             for item in tools:
1677                 if not (type(item) is ToolDef) and callable(item):
1678                     yield from item(context)
1679                 else:
1680                     yield item
1681
1682     @classmethod
1683     def tools_all(cls):
1684         yield from cls._tools.items()
1685
1686     # for reuse
1687     _tools_transform = (
1688         _defs_transform.translate,
1689         _defs_transform.rotate,
1690         (
1691             _defs_transform.scale,
1692             _defs_transform.scale_cage,
1693         ),
1694     )
1695
1696     _tools_select = (
1697         (
1698             _defs_view3d_select.select,
1699             _defs_view3d_select.box,
1700             _defs_view3d_select.circle,
1701             _defs_view3d_select.lasso,
1702         ),
1703     )
1704
1705     _tools_annotate = (
1706         (
1707             _defs_annotate.scribble,
1708             _defs_annotate.line,
1709             _defs_annotate.poly,
1710             _defs_annotate.eraser,
1711         ),
1712     )
1713
1714     _tools_gpencil_select = (
1715         (
1716             _defs_gpencil_edit.select,
1717             _defs_gpencil_edit.box_select,
1718             _defs_gpencil_edit.circle_select,
1719             _defs_gpencil_edit.lasso_select,
1720         ),
1721     )
1722
1723     _tools_default = (
1724         *_tools_select,
1725         _defs_view3d_generic.cursor,
1726         None,
1727         *_tools_transform,
1728         None,
1729         *_tools_annotate,
1730         _defs_view3d_generic.ruler,
1731     )
1732
1733     _tools = {
1734         None: [
1735             # Don't use this! because of paint modes.
1736             # _defs_view3d_generic.cursor,
1737             # End group.
1738         ],
1739         'OBJECT': [
1740             *_tools_default,
1741         ],
1742         'POSE': [
1743             *_tools_default,
1744             None,
1745             (
1746                 _defs_pose.breakdown,
1747                 _defs_pose.push,
1748                 _defs_pose.relax,
1749             ),
1750         ],
1751         'EDIT_ARMATURE': [
1752             *_tools_default,
1753             None,
1754             _defs_edit_armature.roll,
1755             (
1756                 _defs_edit_armature.bone_size,
1757                 _defs_edit_armature.bone_envelope,
1758             ),
1759             None,
1760             (
1761                 _defs_edit_armature.extrude,
1762                 _defs_edit_armature.extrude_cursor,
1763             ),
1764         ],
1765         'EDIT_MESH': [
1766             *_tools_default,
1767             None,
1768             _defs_edit_mesh.cube_add,
1769             None,
1770             (
1771                 _defs_edit_mesh.extrude,
1772                 _defs_edit_mesh.extrude_normals,
1773                 _defs_edit_mesh.extrude_individual,
1774                 _defs_edit_mesh.extrude_cursor,
1775             ),
1776             _defs_edit_mesh.inset,
1777             _defs_edit_mesh.bevel,
1778             (
1779                 _defs_edit_mesh.loopcut_slide,
1780                 _defs_edit_mesh.offset_edge_loops_slide,
1781             ),
1782             (
1783                 _defs_edit_mesh.knife,
1784                 _defs_edit_mesh.bisect,
1785             ),
1786             _defs_edit_mesh.poly_build,
1787             (
1788                 _defs_edit_mesh.spin,
1789                 _defs_edit_mesh.spin_duplicate,
1790             ),
1791             (
1792                 _defs_edit_mesh.vertex_smooth,
1793                 _defs_edit_mesh.vertex_randomize,
1794             ),
1795             (
1796                 _defs_edit_mesh.edge_slide,
1797                 _defs_edit_mesh.vert_slide,
1798             ),
1799             (
1800                 _defs_edit_mesh.shrink_fatten,
1801                 _defs_edit_mesh.push_pull,
1802             ),
1803             (
1804                 _defs_edit_mesh.shear,
1805                 _defs_edit_mesh.tosphere,
1806             ),
1807             (
1808                 _defs_edit_mesh.rip_region,
1809                 _defs_edit_mesh.rip_edge,
1810             ),
1811         ],
1812         'EDIT_CURVE': [
1813             *_tools_default,
1814             None,
1815             _defs_edit_curve.draw,
1816             (
1817                 _defs_edit_curve.extrude,
1818                 _defs_edit_curve.extrude_cursor,
1819             ),
1820             None,
1821             _defs_edit_curve.curve_radius,
1822             _defs_edit_curve.tilt,
1823             None,
1824             _defs_edit_curve.curve_vertex_randomize,
1825         ],
1826         'EDIT_SURFACE': [
1827             *_tools_default,
1828         ],
1829         'EDIT_METABALL': [
1830             *_tools_default,
1831         ],
1832         'EDIT_LATTICE': [
1833             *_tools_default,
1834         ],
1835         'EDIT_TEXT': [
1836             _defs_view3d_generic.cursor,
1837             None,
1838             *_tools_annotate,
1839             _defs_view3d_generic.ruler,
1840         ],
1841         'PARTICLE': [
1842             *_tools_select,
1843             _defs_view3d_generic.cursor,
1844             None,
1845             _defs_particle.generate_from_brushes,
1846         ],
1847         'SCULPT': [
1848             _defs_sculpt.generate_from_brushes,
1849             None,
1850             _defs_sculpt.hide_border,
1851             _defs_sculpt.mask_border,
1852             None,
1853             *_tools_annotate,
1854         ],
1855         'PAINT_TEXTURE': [
1856             _defs_texture_paint.generate_from_brushes,
1857             None,
1858             lambda context: (
1859                 VIEW3D_PT_tools_active._tools_select
1860                 if _defs_texture_paint.poll_select_mask(context)
1861                 else ()
1862             ),
1863             *_tools_annotate,
1864         ],
1865         'PAINT_VERTEX': [
1866             _defs_vertex_paint.generate_from_brushes,
1867             None,
1868             lambda context: (
1869                 VIEW3D_PT_tools_active._tools_select
1870                 if _defs_vertex_paint.poll_select_mask(context)
1871                 else ()
1872             ),
1873             *_tools_annotate,
1874         ],
1875         'PAINT_WEIGHT': [
1876             _defs_weight_paint.generate_from_brushes,
1877             _defs_weight_paint.gradient,
1878             None,
1879             (
1880                 _defs_weight_paint.sample_weight,
1881                 _defs_weight_paint.sample_weight_group,
1882             ),
1883             None,
1884             lambda context: (
1885                 (_defs_view3d_generic.cursor,)
1886                 if context is None or context.pose_object
1887                 else ()
1888             ),
1889             None,
1890             lambda context: (
1891                 VIEW3D_PT_tools_active._tools_select
1892                 if _defs_weight_paint.poll_select_mask(context)
1893                 else ()
1894             ),
1895             *_tools_annotate,
1896         ],
1897         'PAINT_GPENCIL': [
1898             _defs_view3d_generic.cursor,
1899             None,
1900             _defs_gpencil_paint.generate_from_brushes,
1901             _defs_gpencil_paint.cutter,
1902             None,
1903             _defs_gpencil_paint.line,
1904             _defs_gpencil_paint.arc,
1905             _defs_gpencil_paint.curve,
1906             _defs_gpencil_paint.box,
1907             _defs_gpencil_paint.circle,
1908         ],
1909         'EDIT_GPENCIL': [
1910             *_tools_gpencil_select,
1911             _defs_view3d_generic.cursor,
1912             None,
1913             *_tools_transform,
1914             None,
1915             _defs_gpencil_edit.extrude,
1916             _defs_gpencil_edit.radius,
1917             _defs_gpencil_edit.bend,
1918             (
1919                 _defs_gpencil_edit.shear,
1920                 _defs_gpencil_edit.tosphere,
1921             ),
1922
1923         ],
1924         'SCULPT_GPENCIL': [
1925             *_tools_gpencil_select,
1926             None,
1927             _defs_gpencil_sculpt.generate_from_brushes,
1928         ],
1929         'WEIGHT_GPENCIL': [
1930             _defs_gpencil_weight.generate_from_brushes,
1931         ],
1932     }
1933
1934
1935 classes = (
1936     IMAGE_PT_tools_active,
1937     NODE_PT_tools_active,
1938     VIEW3D_PT_tools_active,
1939 )
1940
1941 if __name__ == "__main__":  # only for live edit.
1942     from bpy.utils import register_class
1943     for cls in classes:
1944         register_class(cls)