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