43716f6f861ff1266e3d9023bc8ac2193ea62da2
[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
36 def generate_from_brushes_ex(
37         context, *,
38         icon_prefix,
39         brush_test_attr,
40         brush_category_attr,
41         brush_category_layout,
42 ):
43     # Categories
44     brush_categories = {}
45     if context.mode != 'GPENCIL_PAINT':
46         for brush in context.blend_data.brushes:
47             if getattr(brush, brush_test_attr) and brush.gpencil_settings is None:
48                 category = getattr(brush, brush_category_attr)
49                 name = brush.name
50                 brush_categories.setdefault(category, []).append(
51                     ToolDef.from_dict(
52                         dict(
53                             text=name,
54                             icon=icon_prefix + category.lower(),
55                             data_block=name,
56                         )
57                     )
58                 )
59     else:
60         def draw_settings(context, layout, tool):
61             _defs_gpencil_paint.draw_settings_common(context, layout, tool)
62
63         for brush_type in brush_category_layout:
64             for brush in context.blend_data.brushes:
65                 if getattr(brush, brush_test_attr) and brush.gpencil_settings.gp_icon == brush_type[0]:
66                     category = brush_type[0]
67                     name = brush.name
68                     text = name
69
70                     # XXX, disabled since changing the brush needs to sync back to the tool.
71                     """
72                     # rename default brushes for tool bar
73                     if name.startswith("Draw "):
74                         text = name.replace("Draw ", "")
75                     elif name.startswith("Eraser "):
76                         text = name.replace("Eraser ", "")
77                     elif name.startswith("Fill "):
78                         text = name.replace(" Area", "")
79                     else:
80                         text = name
81                     """
82                     # Define icon.
83                     icon_name = {
84                         'PENCIL': 'draw_pencil',
85                         'PEN': 'draw_pen',
86                         'INK': 'draw_ink',
87                         'INKNOISE': 'draw_noise',
88                         'BLOCK': 'draw_block',
89                         'MARKER': 'draw_marker',
90                         'FILL': 'draw_fill',
91                         'SOFT': 'draw.eraser_soft',
92                         'HARD': 'draw.eraser_hard',
93                         'STROKE': 'draw.eraser_stroke',
94                     }[category]
95                     brush_categories.setdefault(category, []).append(
96                         ToolDef.from_dict(
97                             dict(
98                                 text=text,
99                                 icon=icon_prefix + icon_name,
100                                 data_block=name,
101                                 widget=None,
102                                 operator="gpencil.draw",
103                                 draw_settings=draw_settings,
104                             )
105                         )
106                     )
107
108     def tools_from_brush_group(groups):
109         assert(type(groups) is tuple)
110         if len(groups) == 1:
111             tool_defs = tuple(brush_categories.pop(groups[0], ()))
112         else:
113             tool_defs = tuple(item for g in groups for item in brush_categories.pop(g, ()))
114
115         if len(tool_defs) > 1:
116             return (tool_defs,)
117         else:
118             return tool_defs
119
120     # Each item below is a single toolbar entry:
121     # Grouped for multiple or none if no brushes are found.
122     tool_defs = tuple(
123         tool_def
124         for category in brush_category_layout
125         for tool_def in tools_from_brush_group(category)
126     )
127     # Ensure we use all types.
128     if brush_categories:
129         print(brush_categories)
130     assert(len(brush_categories) == 0)
131     return tool_defs
132
133
134 def generate_from_enum_ex(
135         context, *,
136         icon_prefix,
137         data,
138         attr,
139 ):
140     tool_defs = []
141     for enum in data.rna_type.properties[attr].enum_items_static:
142         name = enum.name
143         identifier = enum.identifier
144         tool_defs.append(
145             ToolDef.from_dict(
146                 dict(
147                     text=name,
148                     icon=icon_prefix + identifier.lower(),
149                     data_block=identifier,
150                 )
151             )
152         )
153     return tuple(tool_defs)
154
155
156 class _defs_view3d_generic:
157     @ToolDef.from_fn
158     def cursor():
159         def draw_settings(context, layout, tool):
160             props = tool.operator_properties("view3d.cursor3d")
161             layout.prop(props, "use_depth")
162             layout.prop(props, "orientation")
163
164         return dict(
165             text="Cursor",
166             description=(
167                 "Set the 3D cursor location, drag to transform"
168             ),
169             icon="ops.generic.cursor",
170             keymap=(
171                 ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
172                 ("transform.translate",
173                  dict(release_confirm=True, cursor_transform=True),
174                  dict(type='EVT_TWEAK_A', value='ANY'),
175                  ),
176             ),
177             draw_settings=draw_settings,
178         )
179
180     @ToolDef.from_fn
181     def cursor_click():
182         return dict(
183             text="None",
184             icon="ops.generic.cursor",
185             keymap=(
186                 # This is a dummy keymap entry, until particle system is properly working with toolsystem.
187                 ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK', ctrl=True, alt=True, shift=True)),
188             ),
189         )
190
191     @ToolDef.from_fn
192     def ruler():
193         return dict(
194             text="Measure",
195             icon="ops.view3d.ruler",
196             widget="VIEW3D_GGT_ruler",
197             keymap=(
198                 ("view3d.ruler_add", dict(), dict(type='EVT_TWEAK_A', value='ANY')),
199             ),
200         )
201
202
203 def _defs_annotate_factory():
204
205     class _defs_annotate:
206         @staticmethod
207         def draw_settings_common(context, layout, tool):
208             ts = context.tool_settings
209
210             space_type = tool.space_type
211             if space_type == 'VIEW_3D':
212                 layout.separator()
213
214                 row = layout.row(align=True)
215                 row.prop(ts, "annotation_stroke_placement_view3d", text="Placement")
216                 if ts.gpencil_stroke_placement_view3d == 'CURSOR':
217                     row.prop(ts.gpencil_sculpt, "lockaxis")
218                 elif ts.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}:
219                     row.prop(ts, "use_gpencil_stroke_endpoints")
220
221         @ToolDef.from_fn
222         def scribble():
223             def draw_settings(context, layout, tool):
224                 _defs_annotate.draw_settings_common(context, layout, tool)
225
226             return dict(
227                 text="Annotate",
228                 icon="ops.gpencil.draw",
229                 cursor='PAINT_BRUSH',
230                 keymap=(
231                     ("gpencil.annotate",
232                      dict(mode='DRAW', wait_for_input=False),
233                      dict(type='EVT_TWEAK_A', value='ANY')),
234                 ),
235                 draw_settings=draw_settings,
236             )
237
238         @ToolDef.from_fn
239         def line():
240             def draw_settings(context, layout, tool):
241                 _defs_annotate.draw_settings_common(context, layout, tool)
242
243             return dict(
244                 text="Annotate Line",
245                 icon="ops.gpencil.draw.line",
246                 cursor='CROSSHAIR',
247                 keymap=(
248                     ("gpencil.annotate",
249                      dict(mode='DRAW_STRAIGHT', wait_for_input=False),
250                      dict(type='EVT_TWEAK_A', value='ANY')),
251                 ),
252                 draw_settings=draw_settings,
253             )
254
255         @ToolDef.from_fn
256         def poly():
257             def draw_settings(context, layout, tool):
258                 _defs_annotate.draw_settings_common(context, layout, tool)
259
260             return dict(
261                 text="Annotate Polygon",
262                 icon="ops.gpencil.draw.poly",
263                 cursor='CROSSHAIR',
264                 keymap=(
265                     ("gpencil.annotate",
266                      dict(mode='DRAW_POLY', wait_for_input=False),
267                      dict(type='ACTIONMOUSE', value='PRESS')),
268                 ),
269                 draw_settings=draw_settings,
270             )
271
272         @ToolDef.from_fn
273         def eraser():
274             def draw_settings(context, layout, tool):
275                 # TODO: Move this setting to toolsettings
276                 user_prefs = context.user_preferences
277                 layout.prop(user_prefs.edit, "grease_pencil_eraser_radius", text="Radius")
278
279             return dict(
280                 text="Annotate Eraser",
281                 icon="ops.gpencil.draw.eraser",
282                 cursor='CROSSHAIR',  # XXX: Always show brush circle when enabled
283                 keymap=(
284                     ("gpencil.annotate",
285                      dict(mode='ERASER', wait_for_input=False),
286                      dict(type='ACTIONMOUSE', value='PRESS')),
287                 ),
288                 draw_settings=draw_settings,
289             )
290     return _defs_annotate
291
292
293 # Needed so annotation gets a keymap per space type.
294 _defs_annotate_image = _defs_annotate_factory()
295 _defs_annotate_view3d = _defs_annotate_factory()
296
297
298 class _defs_transform:
299
300     @ToolDef.from_fn
301     def translate():
302         def draw_settings(context, layout, tool):
303             tool_settings = context.tool_settings
304             layout.prop(tool_settings, "use_gizmo_apron")
305
306         return dict(
307             text="Grab",
308             # cursor='SCROLL_XY',
309             icon="ops.transform.translate",
310             widget="TRANSFORM_GGT_gizmo",
311             operator="transform.translate",
312             # TODO, implement as optional fallback gizmo
313             # keymap=(
314             #     ("transform.translate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),
315             # ),
316             draw_settings=draw_settings,
317         )
318
319     @ToolDef.from_fn
320     def rotate():
321         def draw_settings(context, layout, tool):
322             tool_settings = context.tool_settings
323             layout.prop(tool_settings, "use_gizmo_apron")
324
325         return dict(
326             text="Rotate",
327             # cursor='SCROLL_XY',
328             icon="ops.transform.rotate",
329             widget="TRANSFORM_GGT_gizmo",
330             operator="transform.rotate",
331             # TODO, implement as optional fallback gizmo
332             # keymap=(
333             #     ("transform.rotate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),
334             # ),
335             draw_settings=draw_settings,
336         )
337
338     @ToolDef.from_fn
339     def scale():
340         def draw_settings(context, layout, tool):
341             tool_settings = context.tool_settings
342             layout.prop(tool_settings, "use_gizmo_apron")
343
344         return dict(
345             text="Scale",
346             # cursor='SCROLL_XY',
347             icon="ops.transform.resize",
348             widget="TRANSFORM_GGT_gizmo",
349             operator="transform.resize",
350             # TODO, implement as optional fallback gizmo
351             # keymap=(
352             #     ("transform.resize", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),
353             # ),
354             draw_settings=draw_settings,
355         )
356
357     @ToolDef.from_fn
358     def scale_cage():
359         return dict(
360             text="Scale Cage",
361             icon="ops.transform.resize.cage",
362             widget="VIEW3D_GGT_xform_cage",
363             operator="transform.resize",
364         )
365
366     @ToolDef.from_fn
367     def transform():
368         def draw_settings(context, layout, tool):
369             tool_settings = context.tool_settings
370             layout.prop(tool_settings, "use_gizmo_apron")
371             layout.prop(tool_settings, "use_gizmo_mode")
372
373         return dict(
374             text="Transform",
375             description=(
376                 "Supports any combination of grab, rotate & scale at once"
377             ),
378             icon="ops.transform.transform",
379             widget="TRANSFORM_GGT_gizmo",
380             # No keymap default action, only for gizmo!
381             draw_settings=draw_settings,
382         )
383
384
385 class _defs_view3d_select:
386
387     @ToolDef.from_fn
388     def border():
389         def draw_settings(context, layout, tool):
390             props = tool.operator_properties("view3d.select_border")
391             layout.prop(props, "mode", expand=True)
392         return dict(
393             text="Select Border",
394             icon="ops.generic.select_border",
395             widget=None,
396             keymap=(
397                 ("view3d.select_border",
398                  dict(mode='ADD'),
399                  dict(type='EVT_TWEAK_A', value='ANY')),
400                 ("view3d.select_border",
401                  dict(mode='SUB'),
402                  dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
403             ),
404             draw_settings=draw_settings,
405         )
406
407     @ToolDef.from_fn
408     def circle():
409         def draw_settings(context, layout, tool):
410             props = tool.operator_properties("view3d.select_circle")
411             layout.prop(props, "radius")
412         return dict(
413             text="Select Circle",
414             icon="ops.generic.select_circle",
415             widget=None,
416             keymap=(
417                 ("view3d.select_circle",
418                  dict(deselect=False),
419                  dict(type='ACTIONMOUSE', value='PRESS')),
420                 ("view3d.select_circle",
421                  dict(deselect=True),
422                  dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
423             ),
424             draw_settings=draw_settings,
425         )
426
427     @ToolDef.from_fn
428     def lasso():
429         def draw_settings(context, layout, tool):
430             props = tool.operator_properties("view3d.select_lasso")
431             layout.prop(props, "mode", expand=True)
432         return dict(
433             text="Select Lasso",
434             icon="ops.generic.select_lasso",
435             widget=None,
436             keymap=(
437                 ("view3d.select_lasso",
438                  dict(mode='ADD'),
439                  dict(type='EVT_TWEAK_A', value='ANY')),
440                 ("view3d.select_lasso",
441                  dict(mode='SUB'),
442                  dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
443             ),
444             draw_settings=draw_settings,
445         )
446 # -----------------------------------------------------------------------------
447 # Object Modes (named based on context.mode)
448
449
450 class _defs_edit_armature:
451
452     @ToolDef.from_fn
453     def roll():
454         return dict(
455             text="Roll",
456             icon="ops.armature.bone.roll",
457             widget=None,
458             keymap=(
459                 ("transform.transform",
460                  dict(release_confirm=True, mode='BONE_ROLL'),
461                  dict(type='EVT_TWEAK_A', value='ANY'),),
462             ),
463         )
464
465     @ToolDef.from_fn
466     def bone_envelope():
467         return dict(
468             text="Bone Envelope",
469             icon="ops.transform.bone_envelope",
470             widget=None,
471             keymap=(
472                 ("transform.transform",
473                  dict(release_confirm=True, mode='BONE_ENVELOPE'),
474                  dict(type='ACTIONMOUSE', value='PRESS')),
475             ),
476         )
477
478     @ToolDef.from_fn
479     def bone_size():
480         return dict(
481             text="Bone Size",
482             icon="ops.transform.bone_size",
483             widget=None,
484             keymap=(
485                 ("transform.transform",
486                  dict(release_confirm=True, mode='BONE_SIZE'),
487                  dict(type='ACTIONMOUSE', value='PRESS')),
488             ),
489         )
490
491     @ToolDef.from_fn
492     def extrude():
493         return dict(
494             text="Extrude",
495             icon="ops.armature.extrude_move",
496             widget=None,
497             keymap=(
498                 ("armature.extrude_move",
499                  dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
500                  dict(type='EVT_TWEAK_A', value='ANY')),
501             ),
502         )
503
504     @ToolDef.from_fn
505     def extrude_cursor():
506         return dict(
507             text="Extrude to Cursor",
508             icon="ops.armature.extrude_cursor",
509             widget=None,
510             keymap=(
511                 ("armature.click_extrude", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
512             ),
513         )
514
515
516 class _defs_edit_mesh:
517
518     @ToolDef.from_fn
519     def cube_add():
520         return dict(
521             text="Add Cube",
522             icon="ops.mesh.primitive_cube_add_gizmo",
523             widget=None,
524             keymap=(
525                 ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK')),
526                 ("mesh.primitive_cube_add_gizmo", dict(), dict(type='EVT_TWEAK_A', value='ANY')),
527             ),
528         )
529
530     @ToolDef.from_fn
531     def rip_region():
532         def draw_settings(context, layout, tool):
533             props = tool.operator_properties("mesh.rip_move")
534             props_macro = props.MESH_OT_rip
535             layout.prop(props_macro, "use_fill")
536
537         return dict(
538             text="Rip Region",
539             icon="ops.mesh.rip",
540             widget=None,
541             keymap=(
542                 ("mesh.rip_move",
543                  dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
544                  dict(type='ACTIONMOUSE', value='PRESS')),
545             ),
546             draw_settings=draw_settings,
547         )
548
549     @ToolDef.from_fn
550     def rip_edge():
551         return dict(
552             text="Rip Edge",
553             icon="ops.mesh.rip_edge",
554             widget=None,
555             keymap=(
556                 ("mesh.rip_edge_edge_move", dict(),
557                  dict(type='ACTIONMOUSE', value='PRESS')),
558             ),
559         )
560
561     @ToolDef.from_fn
562     def poly_build():
563         return dict(
564             text="Poly Build",
565             icon="ops.mesh.polybuild_hover",
566             widget=None,
567             keymap=(
568                 ("mesh.polybuild_face_at_cursor_move",
569                  dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
570                  dict(type='ACTIONMOUSE', value='PRESS')),
571                 ("mesh.polybuild_split_at_cursor_move",
572                  dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
573                  dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
574                 ("mesh.polybuild_dissolve_at_cursor", dict(), dict(type='ACTIONMOUSE', value='CLICK', alt=True)),
575                 ("mesh.polybuild_hover", dict(use_boundary=False), dict(type='MOUSEMOVE', value='ANY', alt=True)),
576                 ("mesh.polybuild_hover", dict(use_boundary=True), dict(type='MOUSEMOVE', value='ANY', any=True)),
577             ),
578         )
579
580     @ToolDef.from_fn
581     def edge_slide():
582         def draw_settings(context, layout, tool):
583             props = tool.operator_properties("transform.edge_slide")
584             layout.prop(props, "correct_uv")
585
586         return dict(
587             text="Edge Slide",
588             icon="ops.transform.edge_slide",
589             widget=None,
590             keymap=(
591                 ("transform.edge_slide", dict(release_confirm=True),
592                  dict(type='ACTIONMOUSE', value='PRESS')
593                  ),
594             ),
595             draw_settings=draw_settings,
596         )
597
598     @ToolDef.from_fn
599     def vert_slide():
600         def draw_settings(context, layout, tool):
601             props = tool.operator_properties("transform.vert_slide")
602             layout.prop(props, "correct_uv")
603
604         return dict(
605             text="Vertex Slide",
606             icon="ops.transform.vert_slide",
607             widget=None,
608             keymap=(
609                 ("transform.vert_slide", dict(release_confirm=True),
610                  dict(type='ACTIONMOUSE', value='PRESS')),
611             ),
612             draw_settings=draw_settings,
613         )
614
615     @ToolDef.from_fn
616     def spin():
617         return dict(
618             text="Spin",
619             icon="ops.mesh.spin",
620             widget=None,
621             keymap=(
622                 ("mesh.spin", dict(),
623                  dict(type='ACTIONMOUSE', value='PRESS')),
624             ),
625         )
626
627     @ToolDef.from_fn
628     def spin_duplicate():
629         return dict(
630             text="Spin (Duplicate)",
631             icon="ops.mesh.spin.duplicate",
632             widget=None,
633             keymap=(
634                 ("mesh.spin", dict(dupli=True),
635                  dict(type='ACTIONMOUSE', value='PRESS')),
636             ),
637         )
638
639     @ToolDef.from_fn
640     def inset():
641         def draw_settings(context, layout, tool):
642             props = tool.operator_properties("mesh.inset")
643             layout.prop(props, "use_outset")
644             layout.prop(props, "use_individual")
645             layout.prop(props, "use_even_offset")
646             layout.prop(props, "use_relative_offset")
647
648         return dict(
649             text="Inset Faces",
650             icon="ops.mesh.inset",
651             widget=None,
652             keymap=(
653                 ("mesh.inset", dict(release_confirm=True),
654                  dict(type='ACTIONMOUSE', value='PRESS')),
655             ),
656             draw_settings=draw_settings,
657         )
658
659     @ToolDef.from_fn
660     def bevel():
661         def draw_settings(context, layout, tool):
662             props = tool.operator_properties("mesh.bevel")
663             layout.prop(props, "offset_type")
664             layout.prop(props, "segments")
665             layout.prop(props, "profile", slider=True)
666             layout.prop(props, "vertex_only")
667
668         return dict(
669             text="Bevel",
670             icon="ops.mesh.bevel",
671             widget=None,
672             keymap=(
673                 ("mesh.bevel", dict(release_confirm=True),
674                  dict(type='ACTIONMOUSE', value='PRESS')),
675             ),
676             draw_settings=draw_settings,
677         )
678
679     @ToolDef.from_fn
680     def extrude():
681         return dict(
682             text="Extrude Region",
683             icon="ops.mesh.extrude_region_move",
684             widget="MESH_GGT_extrude",
685             operator="view3d.edit_mesh_extrude_move_normal",
686             keymap=(
687                 ("mesh.extrude_context_move",
688                  dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
689                  dict(type='EVT_TWEAK_A', value='ANY')),
690             ),
691         )
692
693     @ToolDef.from_fn
694     def extrude_normals():
695         def draw_settings(context, layout, tool):
696             props = tool.operator_properties("mesh.extrude_region_shrink_fatten")
697             props_macro = props.TRANSFORM_OT_shrink_fatten
698             layout.prop(props_macro, "use_even_offset")
699         return dict(
700             text="Extrude Along Normals",
701             icon="ops.mesh.extrude_region_shrink_fatten",
702             widget=None,
703             keymap=(
704                 ("mesh.extrude_region_shrink_fatten",
705                  dict(TRANSFORM_OT_shrink_fatten=dict(release_confirm=True)),
706                  dict(type='EVT_TWEAK_A', value='ANY')),
707             ),
708             draw_settings=draw_settings,
709         )
710
711     @ToolDef.from_fn
712     def extrude_individual():
713         return dict(
714             text="Extrude Individual",
715             icon="ops.mesh.extrude_faces_move",
716             widget=None,
717             keymap=(
718                 ("mesh.extrude_faces_move", dict(TRANSFORM_OT_shrink_fatten=dict(release_confirm=True)),
719                  dict(type='EVT_TWEAK_A', value='ANY')),
720             ),
721         )
722
723     @ToolDef.from_fn
724     def extrude_cursor():
725         return dict(
726             text="Extrude to Cursor",
727             icon="ops.mesh.dupli_extrude_cursor",
728             widget=None,
729             keymap=(
730                 ("mesh.dupli_extrude_cursor", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
731             ),
732         )
733
734     @ToolDef.from_fn
735     def loopcut_slide():
736
737         def draw_settings(context, layout, tool):
738             props = tool.operator_properties("mesh.loopcut_slide")
739             props_macro = props.MESH_OT_loopcut
740             layout.prop(props_macro, "number_cuts")
741             props_macro = props.TRANSFORM_OT_edge_slide
742             layout.prop(props_macro, "correct_uv")
743
744         return dict(
745             text="Loop Cut",
746             icon="ops.mesh.loopcut_slide",
747             widget="VIEW3D_GGT_mesh_preselect_edgering",
748             keymap=(
749                 ("mesh.loopcut_slide",
750                  dict(TRANSFORM_OT_edge_slide=dict(release_confirm=True)),
751                  dict(type='ACTIONMOUSE', value='PRESS')),
752             ),
753             draw_settings=draw_settings,
754         )
755
756     @ToolDef.from_fn
757     def offset_edge_loops_slide():
758         return dict(
759             text="Offset Edge Loop Cut",
760             icon="ops.mesh.offset_edge_loops_slide",
761             widget=None,
762             keymap=(
763                 ("mesh.offset_edge_loops_slide", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
764             ),
765         )
766
767     @ToolDef.from_fn
768     def vertex_smooth():
769         return dict(
770             text="Smooth",
771             icon="ops.mesh.vertices_smooth",
772             widget=None,
773             keymap=(
774                 ("mesh.vertices_smooth", dict(),
775                  dict(type='ACTIONMOUSE', value='PRESS')),
776             ),
777         )
778
779     @ToolDef.from_fn
780     def vertex_randomize():
781         return dict(
782             text="Randomize",
783             icon="ops.transform.vertex_random",
784             widget=None,
785             keymap=(
786                 ("transform.vertex_random", dict(),
787                  dict(type='ACTIONMOUSE', value='PRESS')),
788             ),
789         )
790
791     @ToolDef.from_fn
792     def shear():
793         return dict(
794             text="Shear",
795             icon="ops.transform.shear",
796             widget=None,
797             keymap=(
798                 ("transform.shear", dict(release_confirm=True),
799                  dict(type='ACTIONMOUSE', value='PRESS')),
800             ),
801         )
802
803     @ToolDef.from_fn
804     def tosphere():
805         return dict(
806             text="To Sphere",
807             icon="ops.transform.tosphere",
808             widget=None,
809             keymap=(
810                 ("transform.tosphere", dict(release_confirm=True),
811                  dict(type='ACTIONMOUSE', value='PRESS')),
812             ),
813         )
814
815     @ToolDef.from_fn
816     def shrink_fatten():
817         def draw_settings(context, layout, tool):
818             props = tool.operator_properties("transform.shrink_fatten")
819             layout.prop(props, "use_even_offset")
820
821         return dict(
822             text="Shrink/Fatten",
823             icon="ops.transform.shrink_fatten",
824             widget=None,
825             keymap=(
826                 ("transform.shrink_fatten", dict(release_confirm=True),
827                  dict(type='ACTIONMOUSE', value='PRESS')),
828             ),
829             draw_settings=draw_settings,
830         )
831
832     @ToolDef.from_fn
833     def push_pull():
834         return dict(
835             text="Push/Pull",
836             icon="ops.transform.push_pull",
837             widget=None,
838             keymap=(
839                 ("transform.push_pull", dict(release_confirm=True),
840                  dict(type='ACTIONMOUSE', value='PRESS')),
841             ),
842         )
843
844     @ToolDef.from_fn
845     def knife():
846         def draw_settings(context, layout, tool):
847             props = tool.operator_properties("mesh.knife_tool")
848             layout.prop(props, "use_occlude_geometry")
849             layout.prop(props, "only_selected")
850
851         return dict(
852             text="Knife",
853             icon="ops.mesh.knife_tool",
854             widget=None,
855             keymap=(
856                 ("mesh.knife_tool",
857                  dict(wait_for_input=False),
858                  dict(type='ACTIONMOUSE', value='PRESS')),
859             ),
860             draw_settings=draw_settings,
861         )
862
863     @ToolDef.from_fn
864     def bisect():
865         return dict(
866             text="Bisect",
867             icon="ops.mesh.bisect",
868             widget=None,
869             keymap=(
870                 ("mesh.bisect",
871                  dict(),
872                  dict(type='EVT_TWEAK_A', value='ANY')),
873             ),
874         )
875
876
877 class _defs_edit_curve:
878
879     @ToolDef.from_fn
880     def draw():
881         def draw_settings(context, layout, tool):
882             # Tool settings initialize operator options.
883             tool_settings = context.tool_settings
884             cps = tool_settings.curve_paint_settings
885
886             col = layout.row()
887
888             col.prop(cps, "curve_type")
889
890             if cps.curve_type == 'BEZIER':
891                 col.prop(cps, "error_threshold")
892                 col.prop(cps, "fit_method")
893                 col.prop(cps, "use_corners_detect")
894
895                 col = layout.row()
896                 col.active = cps.use_corners_detect
897                 col.prop(cps, "corner_angle")
898
899         return dict(
900             text="Draw",
901             cursor='PAINT_BRUSH',
902             icon=None,
903             widget=None,
904             keymap=(
905                 ("curve.draw", dict(wait_for_input=False), dict(type='ACTIONMOUSE', value='PRESS')),
906             ),
907             draw_settings=draw_settings,
908         )
909
910     @ToolDef.from_fn
911     def extrude():
912         return dict(
913             text="Extrude",
914             icon=None,
915             widget=None,
916             keymap=(
917                 ("curve.extrude_move",
918                  dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
919                  dict(type='EVT_TWEAK_A', value='ANY')),
920             ),
921         )
922
923     @ToolDef.from_fn
924     def extrude_cursor():
925         return dict(
926             text="Extrude Cursor",
927             icon=None,
928             widget=None,
929             keymap=(
930                 ("curve.vertex_add", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
931             ),
932         )
933
934
935 class _defs_pose:
936
937     @ToolDef.from_fn
938     def breakdown():
939         return dict(
940             text="Breakdowner",
941             icon="ops.pose.breakdowner",
942             widget=None,
943             keymap=(
944                 ("pose.breakdown", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
945             ),
946         )
947
948     @ToolDef.from_fn
949     def push():
950         return dict(
951             text="Push",
952             icon="ops.pose.push",
953             widget=None,
954             keymap=(
955                 ("pose.push", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
956             ),
957         )
958
959     @ToolDef.from_fn
960     def relax():
961         return dict(
962             text="Relax",
963             icon="ops.pose.relax",
964             widget=None,
965             keymap=(
966                 ("pose.relax", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
967             ),
968         )
969
970
971 class _defs_particle:
972
973     @staticmethod
974     def generate_from_brushes(context):
975         return generate_from_enum_ex(
976             context,
977             icon_prefix="brush.particle.",
978             data=context.tool_settings.particle_edit,
979             attr="tool",
980         )
981
982
983 class _defs_sculpt:
984
985     @staticmethod
986     def generate_from_brushes(context):
987         return generate_from_brushes_ex(
988             context,
989             icon_prefix="brush.sculpt.",
990             brush_test_attr="use_paint_sculpt",
991             brush_category_attr="sculpt_tool",
992             brush_category_layout=(
993                 ('DRAW',),
994                 ('GRAB', 'THUMB'),
995                 ('SNAKE_HOOK',),
996                 ('BLOB', 'INFLATE'),
997                 ('SMOOTH', 'SCRAPE', 'FLATTEN'),
998                 ('CREASE', 'PINCH'),
999                 ('CLAY', 'CLAY_STRIPS'),
1000                 ('LAYER',),
1001                 ('NUDGE', 'ROTATE'),
1002                 ('FILL',),
1003                 ('SIMPLIFY',),
1004                 ('MASK',),
1005             )
1006         )
1007
1008     @ToolDef.from_fn
1009     def hide_border():
1010         return dict(
1011             text="Border Hide",
1012             icon="ops.sculpt.border_hide",
1013             widget=None,
1014             keymap=(
1015                 ("paint.hide_show", dict(action='HIDE'), dict(type='EVT_TWEAK_A', value='ANY')),
1016                 ("paint.hide_show", dict(action='SHOW'), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
1017                 ("paint.hide_show", dict(action='SHOW', area='ALL'), dict(type='SELECTMOUSE', value='PRESS')),
1018             ),
1019         )
1020
1021     @ToolDef.from_fn
1022     def mask_border():
1023         return dict(
1024             text="Border Mask",
1025             icon="ops.sculpt.border_mask",
1026             widget=None,
1027             keymap=(
1028                 ("view3d.select_border", dict(mode='ADD'), dict(type='EVT_TWEAK_A', value='ANY')),
1029                 ("view3d.select_border", dict(mode='SUB'), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
1030             ),
1031         )
1032
1033
1034 class _defs_vertex_paint:
1035
1036     @staticmethod
1037     def poll_select_mask(context):
1038         mesh = context.object.data
1039         return mesh.use_paint_mask
1040
1041     @staticmethod
1042     def generate_from_brushes(context):
1043         return generate_from_brushes_ex(
1044             context,
1045             icon_prefix="brush.paint_vertex.",
1046             brush_test_attr="use_paint_vertex",
1047             brush_category_attr="vertex_tool",
1048             brush_category_layout=(
1049                 ('MIX',),
1050                 ('BLUR', 'AVERAGE'),
1051                 ('SMEAR',),
1052                 (
1053                     'ADD', 'SUB', 'MUL', 'LIGHTEN', 'DARKEN',
1054                     'COLORDODGE', 'DIFFERENCE', 'SCREEN', 'HARDLIGHT',
1055                     'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY',
1056                     'SATURATION', 'HUE', 'ERASE_ALPHA', 'ADD_ALPHA',
1057                 ),
1058             )
1059         )
1060
1061
1062 class _defs_texture_paint:
1063
1064     @staticmethod
1065     def generate_from_brushes(context):
1066         return generate_from_brushes_ex(
1067             context,
1068             icon_prefix="brush.paint_texture.",
1069             brush_test_attr="use_paint_image",
1070             brush_category_attr="image_tool",
1071             brush_category_layout=(
1072                 ('DRAW',),
1073                 ('SOFTEN',),
1074                 ('SMEAR',),
1075                 ('CLONE',),
1076                 ('FILL',),
1077                 ('MASK',),
1078             )
1079         )
1080
1081
1082 class _defs_weight_paint:
1083
1084     @staticmethod
1085     def poll_select_mask(context):
1086         mesh = context.object.data
1087         return (mesh.use_paint_mask or mesh.use_paint_mask_vertex)
1088
1089     @staticmethod
1090     def generate_from_brushes(context):
1091         return generate_from_brushes_ex(
1092             context,
1093             icon_prefix="brush.paint_weight.",
1094             brush_test_attr="use_paint_weight",
1095             brush_category_attr="vertex_tool",
1096             brush_category_layout=(
1097                 ('MIX',),
1098                 ('BLUR', 'AVERAGE'),
1099                 ('SMEAR',),
1100                 (
1101                     'ADD', 'SUB', 'MUL', 'LIGHTEN', 'DARKEN',
1102                     'COLORDODGE', 'DIFFERENCE', 'SCREEN', 'HARDLIGHT',
1103                     'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY',
1104                     'SATURATION', 'HUE',
1105                 ),
1106             )
1107         )
1108
1109     @ToolDef.from_fn
1110     def sample_weight():
1111         return dict(
1112             text="Sample Weight",
1113             icon="ops.paint.weight_sample",
1114             widget=None,
1115             keymap=(
1116                 ("paint.weight_sample", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
1117             ),
1118         )
1119
1120     @ToolDef.from_fn
1121     def sample_weight_group():
1122         return dict(
1123             text="Sample Vertex Group",
1124             icon="ops.paint.weight_sample_group",
1125             widget=None,
1126             keymap=(
1127                 ("paint.weight_sample_group", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
1128             ),
1129         )
1130
1131     @ToolDef.from_fn
1132     def gradient():
1133         def draw_settings(context, layout, tool):
1134             props = tool.operator_properties("paint.weight_gradient")
1135             layout.prop(props, "type")
1136
1137         return dict(
1138             text="Gradient",
1139             icon="ops.paint.weight_gradient",
1140             widget=None,
1141             keymap=(
1142                 ("paint.weight_gradient", dict(), dict(type='EVT_TWEAK_A', value='ANY')),
1143             ),
1144             draw_settings=draw_settings,
1145         )
1146
1147
1148 class _defs_uv_select:
1149
1150     @ToolDef.from_fn
1151     def border():
1152         return dict(
1153             text="Select Border",
1154             icon="ops.generic.select_border",
1155             widget=None,
1156             keymap=(
1157                 ("uv.select_border",
1158                  dict(deselect=False),
1159                  dict(type='EVT_TWEAK_A', value='ANY')),
1160                 # ("uv.select_border",
1161                 #  dict(deselect=True),
1162                 #  dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
1163             ),
1164         )
1165
1166     @ToolDef.from_fn
1167     def circle():
1168         return dict(
1169             text="Select Circle",
1170             icon="ops.generic.select_circle",
1171             widget=None,
1172             keymap=(
1173                 ("uv.select_circle",
1174                  dict(),  # dict(deselect=False),
1175                  dict(type='ACTIONMOUSE', value='PRESS')),
1176                 # ("uv.select_circle",
1177                 #  dict(deselect=True),
1178                 #  dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
1179             ),
1180         )
1181
1182     @ToolDef.from_fn
1183     def lasso():
1184         return dict(
1185             text="Select Lasso",
1186             icon="ops.generic.select_lasso",
1187             widget=None,
1188             keymap=(
1189                 ("uv.select_lasso",
1190                  dict(deselect=False),
1191                  dict(type='EVT_TWEAK_A', value='ANY')),
1192                 # ("uv.select_lasso",
1193                 #  dict(deselect=True),
1194                 #  dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
1195             ),
1196         )
1197
1198
1199 class _defs_gpencil_paint:
1200     @staticmethod
1201     def draw_color_selector(context, layout):
1202         brush = context.active_gpencil_brush
1203         gp_settings = brush.gpencil_settings
1204         ts = context.tool_settings
1205         row = layout.row(align=True)
1206         row.prop(ts, "use_gpencil_thumbnail_list", text="", icon='IMGDISPLAY')
1207         if ts.use_gpencil_thumbnail_list is False:
1208             row.template_ID(gp_settings, "material", live_icon=True)
1209         else:
1210             row.template_greasepencil_color(gp_settings, "material", rows=3, cols=8, scale=0.8)
1211         row.prop(gp_settings, "pin_material", text="")
1212
1213     @staticmethod
1214     def draw_settings_common(context, layout, tool):
1215         ob = context.active_object
1216         if ob and ob.mode == 'GPENCIL_PAINT':
1217             brush = context.active_gpencil_brush
1218             gp_settings = brush.gpencil_settings
1219             tool_settings = context.tool_settings
1220
1221             if gp_settings.gpencil_brush_type == 'ERASE':
1222                 row = layout.row()
1223                 row.prop(brush, "size", text="Radius")
1224             elif gp_settings.gpencil_brush_type == 'FILL':
1225                 row = layout.row()
1226                 row.prop(gp_settings, "gpencil_fill_leak", text="Leak Size")
1227                 row.prop(brush, "size", text="Thickness")
1228                 row.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify")
1229
1230                 _defs_gpencil_paint.draw_color_selector(context, layout)
1231
1232                 row = layout.row(align=True)
1233                 row.prop(gp_settings, "gpencil_fill_draw_mode", text="")
1234                 row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID')
1235
1236             else:  # bgpsettings.gpencil_brush_type == 'DRAW':
1237                 row = layout.row(align=True)
1238                 row.prop(brush, "size", text="Radius")
1239                 row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
1240                 row = layout.row(align=True)
1241                 row.prop(gp_settings, "pen_strength", slider=True)
1242                 row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
1243
1244                 _defs_gpencil_paint.draw_color_selector(context, layout)
1245
1246     @staticmethod
1247     def generate_from_brushes(context):
1248         return generate_from_brushes_ex(
1249             context,
1250             icon_prefix="brush.gpencil.",
1251             brush_test_attr="use_paint_grease_pencil",
1252             brush_category_attr="grease_pencil_tool",
1253             brush_category_layout=(
1254                 ('PENCIL',),
1255                 ('PEN',),
1256                 ('INK',),
1257                 ('INKNOISE',),
1258                 ('BLOCK',),
1259                 ('MARKER',),
1260                 ('FILL',),
1261                 ('SOFT',),
1262                 ('HARD',),
1263                 ('STROKE',),
1264             )
1265         )
1266
1267
1268 class _defs_gpencil_edit:
1269     @ToolDef.from_fn
1270     def bend():
1271         return dict(
1272             text="Bend",
1273             icon="ops.gpencil.edit_bend",
1274             widget=None,
1275             keymap=(
1276                 ("transform.bend",
1277                  dict(release_confirm=True),
1278                  dict(type='EVT_TWEAK_A', value='ANY')),
1279             ),
1280         )
1281
1282     @ToolDef.from_fn
1283     def mirror():
1284         return dict(
1285             text="Mirror",
1286             icon="ops.gpencil.edit_mirror",
1287             widget=None,
1288             keymap=(
1289                 ("transform.mirror",
1290                  dict(release_confirm=True),
1291                  dict(type='EVT_TWEAK_A', value='ANY')),
1292             ),
1293         )
1294
1295     @ToolDef.from_fn
1296     def shear():
1297         return dict(
1298             text="Shear",
1299             icon="ops.gpencil.edit_shear",
1300             widget=None,
1301             keymap=(
1302                 ("transform.shear",
1303                  dict(release_confirm=True),
1304                  dict(type='EVT_TWEAK_A', value='ANY')),
1305             ),
1306         )
1307
1308     @ToolDef.from_fn
1309     def tosphere():
1310         return dict(
1311             text="To Sphere",
1312             icon="ops.gpencil.edit_to_sphere",
1313             widget=None,
1314             keymap=(
1315                 ("transform.tosphere",
1316                  dict(release_confirm=True),
1317                  dict(type='EVT_TWEAK_A', value='ANY')),
1318             ),
1319         )
1320
1321
1322 class _defs_gpencil_sculpt:
1323     @staticmethod
1324     def draw_settings_common(context, layout, tool):
1325         ob = context.active_object
1326         if ob and ob.mode == 'GPENCIL_SCULPT':
1327             ts = context.tool_settings
1328             settings = ts.gpencil_sculpt
1329             brush = settings.brush
1330
1331             layout.prop(brush, "size", slider=True)
1332
1333             row = layout.row(align=True)
1334             row.prop(brush, "strength", slider=True)
1335             row.prop(brush, "use_pressure_strength", text="")
1336             row.separator()
1337             row.prop(ts.gpencil_sculpt, "use_select_mask", text="")
1338
1339     @ToolDef.from_fn
1340     def smooth():
1341         def draw_settings(context, layout, tool):
1342             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1343
1344         return dict(
1345             text="Smooth",
1346             icon="ops.gpencil.sculpt_smooth",
1347             widget=None,
1348             keymap=(
1349                 ("gpencil.brush_paint",
1350                  dict(mode='SMOOTH', wait_for_input=False),
1351                  dict(type='EVT_TWEAK_A', value='ANY')),
1352             ),
1353             draw_settings=draw_settings,
1354         )
1355
1356     @ToolDef.from_fn
1357     def thickness():
1358         def draw_settings(context, layout, tool):
1359             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1360
1361         return dict(
1362             text="Thickness",
1363             icon="ops.gpencil.sculpt_thickness",
1364             widget=None,
1365             keymap=(
1366                 ("gpencil.brush_paint",
1367                  dict(mode='THICKNESS', wait_for_input=False),
1368                  dict(type='EVT_TWEAK_A', value='ANY')),
1369             ),
1370             draw_settings=draw_settings,
1371         )
1372
1373     @ToolDef.from_fn
1374     def strength():
1375         def draw_settings(context, layout, tool):
1376             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1377
1378         return dict(
1379             text="Strength",
1380             icon="ops.gpencil.sculpt_strength",
1381             widget=None,
1382             keymap=(
1383                 ("gpencil.brush_paint",
1384                  dict(mode='STRENGTH', wait_for_input=False),
1385                  dict(type='EVT_TWEAK_A', value='ANY')),
1386             ),
1387             draw_settings=draw_settings,
1388         )
1389
1390     @ToolDef.from_fn
1391     def grab():
1392         def draw_settings(context, layout, tool):
1393             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1394
1395         return dict(
1396             text="Grab",
1397             icon="ops.gpencil.sculpt_grab",
1398             widget=None,
1399             keymap=(
1400                 ("gpencil.brush_paint",
1401                  dict(mode='GRAB', wait_for_input=False),
1402                  dict(type='EVT_TWEAK_A', value='ANY')),
1403             ),
1404             draw_settings=draw_settings,
1405         )
1406
1407     @ToolDef.from_fn
1408     def push():
1409         def draw_settings(context, layout, tool):
1410             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1411
1412         return dict(
1413             text="Push",
1414             icon="ops.gpencil.sculpt_push",
1415             widget=None,
1416             keymap=(
1417                 ("gpencil.brush_paint",
1418                  dict(mode='PUSH', wait_for_input=False),
1419                  dict(type='EVT_TWEAK_A', value='ANY')),
1420             ),
1421             draw_settings=draw_settings,
1422         )
1423
1424     @ToolDef.from_fn
1425     def twist():
1426         def draw_settings(context, layout, tool):
1427             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1428
1429         return dict(
1430             text="Twist",
1431             icon="ops.gpencil.sculpt_twist",
1432             widget=None,
1433             keymap=(
1434                 ("gpencil.brush_paint",
1435                  dict(mode='TWIST', wait_for_input=False),
1436                  dict(type='EVT_TWEAK_A', value='ANY')),
1437             ),
1438             draw_settings=draw_settings,
1439         )
1440
1441     @ToolDef.from_fn
1442     def pinch():
1443         def draw_settings(context, layout, tool):
1444             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1445
1446         return dict(
1447             text="Pinch",
1448             icon="ops.gpencil.sculpt_pinch",
1449             widget=None,
1450             keymap=(
1451                 ("gpencil.brush_paint",
1452                  dict(mode='PINCH', wait_for_input=False),
1453                  dict(type='EVT_TWEAK_A', value='ANY')),
1454             ),
1455             draw_settings=draw_settings,
1456         )
1457
1458     @ToolDef.from_fn
1459     def randomize():
1460         def draw_settings(context, layout, tool):
1461             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1462
1463         return dict(
1464             text="Randomize",
1465             icon="ops.gpencil.sculpt_randomize",
1466             widget=None,
1467             keymap=(
1468                 ("gpencil.brush_paint",
1469                  dict(mode='RANDOMIZE', wait_for_input=False),
1470                  dict(type='EVT_TWEAK_A', value='ANY')),
1471             ),
1472             draw_settings=draw_settings,
1473         )
1474
1475     @ToolDef.from_fn
1476     def clone():
1477         def draw_settings(context, layout, tool):
1478             _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
1479
1480         return dict(
1481             text="Clone",
1482             icon="ops.gpencil.sculpt_clone",
1483             widget=None,
1484             keymap=(
1485                 ("gpencil.brush_paint",
1486                  dict(mode='CLONE', wait_for_input=False),
1487                  dict(type='EVT_TWEAK_A', value='ANY')),
1488             ),
1489             draw_settings=draw_settings,
1490         )
1491
1492
1493 class _defs_gpencil_weight:
1494     @staticmethod
1495     def draw_settings_common(context, layout, tool):
1496         ob = context.active_object
1497         if ob and ob.mode == 'GPENCIL_WEIGHT':
1498             settings = context.tool_settings.gpencil_sculpt
1499             brush = settings.brush
1500
1501             layout.prop(brush, "size", slider=True)
1502
1503             row = layout.row(align=True)
1504             row.prop(brush, "strength", slider=True)
1505             row.prop(brush, "use_pressure_strength", text="")
1506
1507     @ToolDef.from_fn
1508     def paint():
1509         def draw_settings(context, layout, tool):
1510             _defs_gpencil_weight.draw_settings_common(context, layout, tool)
1511
1512         return dict(
1513             text="Draw",
1514             icon="ops.gpencil.sculpt_weight",
1515             widget=None,
1516             keymap=(
1517                 ("gpencil.brush_paint",
1518                  dict(mode='WEIGHT', wait_for_input=False),
1519                  dict(type='EVT_TWEAK_A', value='ANY')),
1520             ),
1521             draw_settings=draw_settings,
1522         )
1523
1524
1525 class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
1526     bl_space_type = 'IMAGE_EDITOR'
1527     bl_region_type = 'TOOLS'
1528     bl_category = "Tools"
1529     bl_label = "Tools"  # not visible
1530     bl_options = {'HIDE_HEADER'}
1531
1532     # Satisfy the 'ToolSelectPanelHelper' API.
1533     keymap_prefix = "Image Editor Tool:"
1534
1535     @classmethod
1536     def tools_from_context(cls, context, mode=None):
1537         if mode is None:
1538             if context.space_data is None:
1539                 mode = 'VIEW'
1540             else:
1541                 mode = context.space_data.mode
1542         for tools in (cls._tools[None], cls._tools.get(mode, ())):
1543             for item in tools:
1544                 if not (type(item) is ToolDef) and callable(item):
1545                     yield from item(context)
1546                 else:
1547                     yield item
1548
1549     @classmethod
1550     def tools_all(cls):
1551         yield from cls._tools.items()
1552
1553     # for reuse
1554     _tools_select = (
1555         (
1556             _defs_uv_select.border,
1557             _defs_uv_select.circle,
1558             _defs_uv_select.lasso,
1559         ),
1560     )
1561
1562     _tools_annotate = (
1563         (
1564             _defs_annotate_image.scribble,
1565             _defs_annotate_image.line,
1566             _defs_annotate_image.poly,
1567             _defs_annotate_image.eraser,
1568         ),
1569     )
1570
1571     _tools = {
1572         None: [
1573             # for all modes
1574         ],
1575         'VIEW': [
1576             *_tools_select,
1577             *_tools_annotate,
1578         ],
1579         'MASK': [
1580             None,
1581         ],
1582         'PAINT': [
1583             _defs_texture_paint.generate_from_brushes,
1584         ],
1585     }
1586
1587
1588 class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
1589     bl_space_type = 'VIEW_3D'
1590     bl_region_type = 'TOOLS'
1591     bl_category = "Tools"
1592     bl_label = "Tools"  # not visible
1593     bl_options = {'HIDE_HEADER'}
1594
1595     # Satisfy the 'ToolSelectPanelHelper' API.
1596     keymap_prefix = "3D View Tool:"
1597
1598     @classmethod
1599     def tools_from_context(cls, context, mode=None):
1600         if mode is None:
1601             mode = context.mode
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     # for reuse
1614     _tools_transform = (
1615         _defs_transform.transform,
1616         _defs_transform.translate,
1617         _defs_transform.rotate,
1618         (
1619             _defs_transform.scale,
1620             _defs_transform.scale_cage,
1621         ),
1622     )
1623
1624     _tools_select = (
1625         (
1626             _defs_view3d_select.border,
1627             _defs_view3d_select.circle,
1628             _defs_view3d_select.lasso,
1629         ),
1630     )
1631
1632     _tools_annotate = (
1633         (
1634             _defs_annotate_view3d.scribble,
1635             _defs_annotate_view3d.line,
1636             _defs_annotate_view3d.poly,
1637             _defs_annotate_view3d.eraser,
1638         ),
1639         _defs_view3d_generic.ruler,
1640     )
1641
1642     _tools = {
1643         None: [
1644             # Don't use this! because of paint modes.
1645             # _defs_view3d_generic.cursor,
1646             # End group.
1647         ],
1648         'OBJECT': [
1649             _defs_view3d_generic.cursor,
1650             *_tools_select,
1651             None,
1652             *_tools_transform,
1653             None,
1654             *_tools_annotate,
1655         ],
1656         'POSE': [
1657             _defs_view3d_generic.cursor,
1658             *_tools_select,
1659             None,
1660             *_tools_transform,
1661             None,
1662             *_tools_annotate,
1663             None,
1664             (
1665                 _defs_pose.breakdown,
1666                 _defs_pose.push,
1667                 _defs_pose.relax,
1668             ),
1669         ],
1670         'EDIT_ARMATURE': [
1671             _defs_view3d_generic.cursor,
1672             *_tools_select,
1673             None,
1674             *_tools_transform,
1675             None,
1676             *_tools_annotate,
1677             _defs_edit_armature.roll,
1678             (
1679                 _defs_edit_armature.bone_size,
1680                 _defs_edit_armature.bone_envelope,
1681             ),
1682             None,
1683             (
1684                 _defs_edit_armature.extrude,
1685                 _defs_edit_armature.extrude_cursor,
1686             ),
1687         ],
1688         'EDIT_MESH': [
1689             _defs_view3d_generic.cursor,
1690             *_tools_select,
1691             None,
1692             *_tools_transform,
1693             None,
1694             *_tools_annotate,
1695             None,
1696             _defs_edit_mesh.cube_add,
1697             None,
1698             (
1699                 _defs_edit_mesh.extrude,
1700                 _defs_edit_mesh.extrude_normals,
1701                 _defs_edit_mesh.extrude_individual,
1702                 _defs_edit_mesh.extrude_cursor,
1703             ),
1704             _defs_edit_mesh.inset,
1705             _defs_edit_mesh.bevel,
1706             (
1707                 _defs_edit_mesh.loopcut_slide,
1708                 _defs_edit_mesh.offset_edge_loops_slide,
1709             ),
1710             (
1711                 _defs_edit_mesh.knife,
1712                 _defs_edit_mesh.bisect,
1713             ),
1714             _defs_edit_mesh.poly_build,
1715             (
1716                 _defs_edit_mesh.spin,
1717                 _defs_edit_mesh.spin_duplicate,
1718             ),
1719             (
1720                 _defs_edit_mesh.vertex_smooth,
1721                 _defs_edit_mesh.vertex_randomize,
1722             ),
1723             (
1724                 _defs_edit_mesh.edge_slide,
1725                 _defs_edit_mesh.vert_slide,
1726             ),
1727             (
1728                 _defs_edit_mesh.shrink_fatten,
1729                 _defs_edit_mesh.push_pull,
1730             ),
1731             (
1732                 _defs_edit_mesh.shear,
1733                 _defs_edit_mesh.tosphere,
1734             ),
1735             (
1736                 _defs_edit_mesh.rip_region,
1737                 _defs_edit_mesh.rip_edge,
1738             ),
1739         ],
1740         'EDIT_CURVE': [
1741             _defs_view3d_generic.cursor,
1742             *_tools_select,
1743             None,
1744             *_tools_transform,
1745             None,
1746             *_tools_annotate,
1747             None,
1748             _defs_edit_curve.draw,
1749             (
1750                 _defs_edit_curve.extrude,
1751                 _defs_edit_curve.extrude_cursor,
1752             )
1753         ],
1754         'PARTICLE': [
1755             _defs_view3d_generic.cursor,
1756             _defs_particle.generate_from_brushes,
1757         ],
1758         'SCULPT': [
1759             _defs_sculpt.generate_from_brushes,
1760             None,
1761             _defs_sculpt.hide_border,
1762             _defs_sculpt.mask_border,
1763         ],
1764         'PAINT_TEXTURE': [
1765             _defs_texture_paint.generate_from_brushes,
1766         ],
1767         'PAINT_VERTEX': [
1768             _defs_vertex_paint.generate_from_brushes,
1769             None,
1770             lambda context: (
1771                 VIEW3D_PT_tools_active._tools_select
1772                 if _defs_vertex_paint.poll_select_mask(context)
1773                 else ()
1774             ),
1775         ],
1776         'PAINT_WEIGHT': [
1777             # TODO, check for mixed pose mode
1778             _defs_view3d_generic.cursor,
1779             _defs_weight_paint.generate_from_brushes,
1780             None,
1781             _defs_weight_paint.sample_weight,
1782             _defs_weight_paint.sample_weight_group,
1783             None,
1784             lambda context: (
1785                 VIEW3D_PT_tools_active._tools_select
1786                 if _defs_weight_paint.poll_select_mask(context)
1787                 else ()
1788             ),
1789             None,
1790             _defs_weight_paint.gradient,
1791         ],
1792         'GPENCIL_PAINT': [
1793             _defs_gpencil_paint.generate_from_brushes,
1794         ],
1795         'GPENCIL_EDIT': [
1796             _defs_view3d_generic.cursor,
1797             *_tools_select,
1798             None,
1799             *_tools_transform,
1800             None,
1801             _defs_gpencil_edit.bend,
1802             _defs_gpencil_edit.mirror,
1803             _defs_gpencil_edit.shear,
1804             _defs_gpencil_edit.tosphere,
1805         ],
1806         'GPENCIL_SCULPT': [
1807             _defs_gpencil_sculpt.smooth,
1808             _defs_gpencil_sculpt.thickness,
1809             _defs_gpencil_sculpt.strength,
1810             _defs_gpencil_sculpt.grab,
1811             _defs_gpencil_sculpt.push,
1812             _defs_gpencil_sculpt.twist,
1813             _defs_gpencil_sculpt.pinch,
1814             _defs_gpencil_sculpt.randomize,
1815             _defs_gpencil_sculpt.clone,
1816         ],
1817         'GPENCIL_WEIGHT': [
1818             _defs_gpencil_weight.paint,
1819         ],
1820     }
1821
1822
1823 classes = (
1824     IMAGE_PT_tools_active,
1825     VIEW3D_PT_tools_active,
1826 )
1827
1828 if __name__ == "__main__":  # only for live edit.
1829     from bpy.utils import register_class
1830     for cls in classes:
1831         register_class(cls)