Tool System: brushes are now categorized by tool
authorCampbell Barton <ideasman42@gmail.com>
Thu, 1 Nov 2018 22:10:23 +0000 (09:10 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 2 Nov 2018 08:40:39 +0000 (19:40 +1100)
The toolbar now shows brush types, the brush selector now
only shows brushes matching the current tool type.

Details:

- Add's Paint.tool_slots (used by the toolbar).
- Removed custom grease pencil brush tool code.
- Bumped subversion.

See T57526 for details.

21 files changed:
release/scripts/startup/bl_ui/properties_grease_pencil_common.py
release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_blender_version.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/library_query.c
source/blender/blenkernel/intern/paint.c
source/blender/blenkernel/intern/paint_toolslots.c [new file with mode: 0644]
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_280.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/gpencil/gpencil_ops.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/gpencil/gpencil_utils.c
source/blender/makesdna/DNA_brush_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_brush.c
source/blender/makesrna/intern/rna_sculpt_paint.c

index 91892e010b7af9f0a96aa464d13422d84d6b04f3..363cc5f17977dcab06a66e791c9d89882f288319 100644 (file)
@@ -341,10 +341,10 @@ class GreasePencilAppearancePanel:
 
             layout.prop(gp_settings, "use_cursor", text="Show Brush")
 
-            if gp_settings.tool == 'DRAW':
+            if brush.gpencil_tool == 'DRAW':
                 layout.prop(gp_settings, "show_lasso", text="Show fill color while drawing")
 
-            if gp_settings.tool == 'FILL':
+            if brush.gpencil_tool == 'FILL':
                 layout.prop(brush, "cursor_color_add", text="Color")
 
         elif ob.mode in {'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}:
index 04b643257717ecd948001927f666642a2225f36c..caffcf829c54e6135f47134e692cbd42fdcd368c 100644 (file)
@@ -38,65 +38,40 @@ from .properties_grease_pencil_common import (
     AnnotationDataPanel,
 )
 
-def generate_from_brushes_ex(
-        context, *,
+
+def generate_from_brushes_tool_slots_ex(
+        context, paint, *,
         icon_prefix,
-        brush_test_attr,
         brush_category_attr,
         brush_category_layout,
+        # Optional
+        icon_fn=None,
+        tooldef_keywords={},
 ):
     # Categories
     brush_categories = {}
-    if context.mode != 'GPENCIL_PAINT':
-        for brush in context.blend_data.brushes:
-            if getattr(brush, brush_test_attr) and brush.gpencil_settings is None:
-                category = getattr(brush, brush_category_attr)
-                name = brush.name
-                brush_categories.setdefault(category, []).append(
-                    ToolDef.from_dict(
-                        dict(
-                            text=name,
-                            icon=icon_prefix + category.lower(),
-                            data_block=name,
-                        )
-                    )
-                )
-    else:
-        def draw_settings(context, layout, tool):
-            _defs_gpencil_paint.draw_settings_common(context, layout, tool)
+    for paint_slot in paint.tool_slots:
+        brush = paint_slot.brush
+        if brush is None:
+            continue
+        category = getattr(brush, brush_category_attr)
+
+        if icon_fn is not None:
+            icon_id = icon_fn(brush)
+        else:
+            icon_id = category.lower()
 
-        for brush_type in brush_category_layout:
-            for brush in context.blend_data.brushes:
-                if brush.gpencil_settings and getattr(brush, brush_test_attr) and brush.gpencil_settings.gp_icon == brush_type[0]:
-                    category = brush_type[0]
-                    name = brush.name
-                    text = name
-
-                    # Define icon.
-                    icon_name = {
-                        'PENCIL': 'draw_pencil',
-                        'PEN': 'draw_pen',
-                        'INK': 'draw_ink',
-                        'INKNOISE': 'draw_noise',
-                        'BLOCK': 'draw_block',
-                        'MARKER': 'draw_marker',
-                        'FILL': 'draw_fill',
-                        'SOFT': 'draw.eraser_soft',
-                        'HARD': 'draw.eraser_hard',
-                        'STROKE': 'draw.eraser_stroke',
-                    }[category]
-                    brush_categories.setdefault(category, []).append(
-                        ToolDef.from_dict(
-                            dict(
-                                text=text,
-                                icon=icon_prefix + icon_name,
-                                data_block=name,
-                                widget=None,
-                                operator="gpencil.draw",
-                                draw_settings=draw_settings,
-                            )
-                        )
-                    )
+        name = brush.name
+        brush_categories.setdefault(category, []).append(
+            ToolDef.from_dict(
+                dict(
+                    text=name,
+                    icon=icon_prefix + icon_id,
+                    data_block=name,
+                    **tooldef_keywords,
+                )
+            )
+        )
 
     def tools_from_brush_group(groups):
         assert(type(groups) is tuple)
@@ -1052,10 +1027,9 @@ class _defs_sculpt:
 
     @staticmethod
     def generate_from_brushes(context):
-        return generate_from_brushes_ex(
-            context,
+        return generate_from_brushes_tool_slots_ex(
+            context, context.tool_settings.sculpt,
             icon_prefix="brush.sculpt.",
-            brush_test_attr="use_paint_sculpt",
             brush_category_attr="sculpt_tool",
             brush_category_layout=(
                 ('DRAW',),
@@ -1070,7 +1044,7 @@ class _defs_sculpt:
                 ('FILL',),
                 ('SIMPLIFY',),
                 ('MASK',),
-            )
+            ),
         )
 
     @ToolDef.from_fn
@@ -1108,10 +1082,9 @@ class _defs_vertex_paint:
 
     @staticmethod
     def generate_from_brushes(context):
-        return generate_from_brushes_ex(
-            context,
+        return generate_from_brushes_tool_slots_ex(
+            context, context.tool_settings.vertex_paint,
             icon_prefix="brush.paint_vertex.",
-            brush_test_attr="use_paint_vertex",
             brush_category_attr="vertex_tool",
             brush_category_layout=(
                 ('MIX',),
@@ -1123,7 +1096,7 @@ class _defs_vertex_paint:
                     'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY',
                     'SATURATION', 'HUE', 'ERASE_ALPHA', 'ADD_ALPHA',
                 ),
-            )
+            ),
         )
 
 
@@ -1131,10 +1104,9 @@ class _defs_texture_paint:
 
     @staticmethod
     def generate_from_brushes(context):
-        return generate_from_brushes_ex(
-            context,
+        return generate_from_brushes_tool_slots_ex(
+            context, context.tool_settings.image_paint,
             icon_prefix="brush.paint_texture.",
-            brush_test_attr="use_paint_image",
             brush_category_attr="image_tool",
             brush_category_layout=(
                 ('DRAW',),
@@ -1143,7 +1115,7 @@ class _defs_texture_paint:
                 ('CLONE',),
                 ('FILL',),
                 ('MASK',),
-            )
+            ),
         )
 
 
@@ -1158,10 +1130,9 @@ class _defs_weight_paint:
 
     @staticmethod
     def generate_from_brushes(context):
-        return generate_from_brushes_ex(
-            context,
+        return generate_from_brushes_tool_slots_ex(
+            context, context.tool_settings.weight_paint,
             icon_prefix="brush.paint_weight.",
-            brush_test_attr="use_paint_weight",
             brush_category_attr="vertex_tool",
             brush_category_layout=(
                 ('MIX',),
@@ -1173,7 +1144,7 @@ class _defs_weight_paint:
                     'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY',
                     'SATURATION', 'HUE',
                 ),
-            )
+            ),
         )
 
     @ToolDef.from_fn
@@ -1368,9 +1339,11 @@ class _defs_gpencil_paint:
         ob = context.active_object
         if ob and ob.mode == 'GPENCIL_PAINT':
             brush = context.active_gpencil_brush
+            if brush is None:
+                return
             gp_settings = brush.gpencil_settings
 
-            if gp_settings.tool == 'ERASE':
+            if brush.gpencil_tool == 'ERASE':
                 row = layout.row(align=True)
                 row.prop(brush, "size", text="Radius")
                 row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
@@ -1378,7 +1351,7 @@ class _defs_gpencil_paint:
                     row = layout.row(align=True)
                     row.prop(gp_settings, "pen_strength", slider=True)
                     row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
-            elif gp_settings.tool == 'FILL':
+            elif brush.gpencil_tool == 'FILL':
                 row = layout.row()
                 row.prop(gp_settings, "fill_leak", text="Leak Size")
                 row.prop(brush, "size", text="Thickness")
@@ -1402,26 +1375,42 @@ class _defs_gpencil_paint:
 
     @staticmethod
     def generate_from_brushes(context):
-        return generate_from_brushes_ex(
-            context,
+
+        def draw_settings(context, layout, tool):
+            _defs_gpencil_paint.draw_settings_common(context, layout, tool)
+
+        def icon_fn(brush):
+            return {
+                'PENCIL': 'draw_pencil',
+                'PEN': 'draw_pen',
+                'INK': 'draw_ink',
+                'INKNOISE': 'draw_noise',
+                'BLOCK': 'draw_block',
+                'MARKER': 'draw_marker',
+                'FILL': 'draw_fill',
+                'SOFT': 'draw.eraser_soft',
+                'HARD': 'draw.eraser_hard',
+                'STROKE': 'draw.eraser_stroke',
+            }[brush.gpencil_settings.gp_icon]
+
+        return generate_from_brushes_tool_slots_ex(
+            context, context.tool_settings.gpencil_paint,
             icon_prefix="brush.gpencil.",
-            brush_test_attr="use_paint_grease_pencil",
-            brush_category_attr="grease_pencil_tool",
+            brush_category_attr="gpencil_tool",
             brush_category_layout=(
-                ('PENCIL',),
-                ('PEN',),
-                ('INK',),
-                ('INKNOISE',),
-                ('BLOCK',),
-                ('MARKER',),
+                ('DRAW',),
                 ('FILL',),
-                ('SOFT',),
-                ('HARD',),
-                ('STROKE',),
-            )
+                ('ERASE',),
+            ),
+            tooldef_keywords=dict(
+                operator="gpencil.draw",
+                draw_settings=draw_settings,
+            ),
+            icon_fn=icon_fn,
         )
 
 
+
 class _defs_gpencil_edit:
     @ToolDef.from_fn
     def bend():
index f3c110236082a8b888ead3d3dca336719c09b54f..1abfb92917b5d78ec69ccff4e664332af0e04f86 100644 (file)
@@ -1492,11 +1492,11 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
 
         if brush is not None:
             # XXX: Items in "sub" currently show up beside the brush selector in a separate column
-            if gp_settings.tool == 'ERASE':
+            if brush.gpencil_tool == 'ERASE':
                 sub.prop(gp_settings, "use_default_eraser", text="")
 
             # Brush details
-            if gp_settings.tool == 'ERASE':
+            if brush.gpencil_tool == 'ERASE':
                 row = layout.row(align=True)
                 row.prop(brush, "size", text="Radius")
                 row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
@@ -1509,7 +1509,7 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
                     row.prop(gp_settings, "eraser_strength_factor")
                     row = layout.row(align=True)
                     row.prop(gp_settings, "eraser_thickness_factor")
-            elif gp_settings.tool == 'FILL':
+            elif brush.gpencil_tool == 'FILL':
                 col = layout.column(align=True)
                 col.prop(gp_settings, "fill_leak", text="Leak Size")
                 col.separator()
@@ -1550,9 +1550,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
     @classmethod
     def poll(cls, context):
         brush = context.active_gpencil_brush
-        gp_settings = brush.gpencil_settings
-
-        return brush is not None and gp_settings.tool != 'ERASE'
+        return brush is not None and brush.gpencil_tool != 'ERASE'
 
     def draw_header_preset(self, context):
         VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
@@ -1588,9 +1586,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
     @classmethod
     def poll(cls, context):
         brush = context.active_gpencil_brush
-        gp_settings = brush.gpencil_settings
-
-        return brush is not None and gp_settings.tool == 'DRAW'
+        return brush is not None and brush.gpencil_tool == 'DRAW'
 
     def draw_header(self, context):
         brush = context.active_gpencil_brush
@@ -1620,9 +1616,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
     @classmethod
     def poll(cls, context):
         brush = context.active_gpencil_brush
-        gp_settings = brush.gpencil_settings
-
-        return brush is not None and gp_settings.tool != 'ERASE'
+        return brush is not None and brush.gpencil_tool != 'ERASE'
 
     def draw_header(self, context):
         brush = context.active_gpencil_brush
@@ -1661,9 +1655,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
     @classmethod
     def poll(cls, context):
         brush = context.active_gpencil_brush
-        gp_settings = brush.gpencil_settings
-
-        return brush is not None and gp_settings.tool != 'ERASE'
+        return brush is not None and brush.gpencil_tool != 'ERASE'
 
     def draw_header(self, context):
         brush = context.active_gpencil_brush
@@ -1698,9 +1690,7 @@ class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
     @classmethod
     def poll(cls, context):
         brush = context.active_gpencil_brush
-        gp_settings = brush.gpencil_settings
-
-        return brush is not None and gp_settings.tool != 'ERASE'
+        return brush is not None and brush.gpencil_tool != 'ERASE'
 
     @staticmethod
     def draw(self, context):
index b95e2e504d0f0b1de9745692cf141cb870eeb4ec..b695132416ec15433624cba15d4285b77c6559ee 100644 (file)
@@ -28,7 +28,7 @@
  * and keep comment above the defines.
  * Use STRINGIFY() rather than defining with quotes */
 #define BLENDER_VERSION         280
-#define BLENDER_SUBVERSION      29
+#define BLENDER_SUBVERSION      30
 /* Several breakages with 280, e.g. collections vs layers */
 #define BLENDER_MINVERSION      280
 #define BLENDER_MINSUBVERSION   0
index 3782d26fc1beffce0f56dcac9477181441b88e9c..b8938c87275404db690add94e841c0c4b69c4869 100644 (file)
@@ -168,6 +168,13 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B
 
 void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
 
+
+/* Tool slot API. */
+void BKE_paint_toolslots_init_from_main(struct Main *bmain);
+void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len);
+void BKE_paint_toolslots_brush_update_ex(struct Scene *scene, struct Paint *paint, struct Brush *brush);
+void BKE_paint_toolslots_brush_update(struct Scene *scene, struct Paint *paint);
+
 /* Used for both vertex color and weight paint */
 struct SculptVertexPaintGeomMap {
        int *vert_map_mem;
index 77c9df1242893d50c8e54eece10f7ef92efe49f2..f2e2c0406af36c2f7d1d7ac17cd064dc4f79f5d9 100644 (file)
@@ -168,6 +168,7 @@ set(SRC
        intern/outliner_treehash.c
        intern/packedFile.c
        intern/paint.c
+       intern/paint_toolslots.c
        intern/particle.c
        intern/particle_child.c
        intern/particle_distribute.c
index 13087877d5d6937808c7329cf78cc58d23d41144..94ff7f3f2e5d0d601d7da9aae680440edef2caa4 100644 (file)
@@ -304,7 +304,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->draw_subdivide = 1;
        brush->gpencil_settings->draw_random_sub = 0.0f;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+       brush->gpencil_tool = GPAINT_TOOL_DRAW;
 
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
@@ -336,7 +336,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->thick_smoothlvl = 3;
        brush->gpencil_settings->draw_random_sub = 0.0f;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+       brush->gpencil_tool = GPAINT_TOOL_DRAW;
 
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
@@ -365,7 +365,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->draw_subdivide = 1;
        brush->gpencil_settings->draw_random_sub = 0.0f;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+       brush->gpencil_tool = GPAINT_TOOL_DRAW;
 
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
@@ -402,7 +402,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->draw_subdivide = 1;
        brush->gpencil_settings->draw_random_sub = 0.0f;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+       brush->gpencil_tool = GPAINT_TOOL_DRAW;
 
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
@@ -438,7 +438,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->draw_subdivide = 0;
        brush->gpencil_settings->draw_random_sub = 0;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+       brush->gpencil_tool = GPAINT_TOOL_DRAW;
 
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
@@ -469,7 +469,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->draw_subdivide = 1;
        brush->gpencil_settings->draw_random_sub = 0.0f;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+       brush->gpencil_tool = GPAINT_TOOL_DRAW;
 
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
@@ -483,7 +483,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->gpencil_settings->fill_threshold = 0.1f;
        brush->gpencil_settings->fill_simplylvl = 1;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_FILL;
+       brush->gpencil_tool = GPAINT_TOOL_FILL;
 
        brush->gpencil_settings->draw_smoothfac = 0.1f;
        brush->gpencil_settings->draw_smoothlvl = 1;
@@ -501,7 +501,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->size = 30.0f;
        brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+       brush->gpencil_tool = GPAINT_TOOL_ERASE;
        brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
        brush->gpencil_settings->era_strength_f = 100.0f;
        brush->gpencil_settings->era_thickness_f = 0.10f;
@@ -511,7 +511,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->size = 30.0f;
        brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+       brush->gpencil_tool = GPAINT_TOOL_ERASE;
        brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
 
        /* Stroke Eraser brush */
@@ -519,7 +519,7 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->size = 30.0f;
        brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
        brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
-       brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+       brush->gpencil_tool = GPAINT_TOOL_ERASE;
        brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
 
        /* set default brush */
index e82e1cf2d6bde5e55ddd7429122f7133f2067d5e..ea1b35e4c1efd57e7670d75ab10f005fbb03ec74 100644 (file)
@@ -280,6 +280,9 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
 static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
 {
        FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+       for (int i = 0; i < paint->tool_slots_len; i++) {
+               FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
+       }
        FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
 
        FOREACH_FINALIZE_VOID;
index 545581e65ec4b02e8fbc02c9a43753cd19cafe3a..93b54fcb132f6bdf57853d8c887a6254e8e777dd 100644 (file)
@@ -549,6 +549,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
 void BKE_paint_free(Paint *paint)
 {
        curvemapping_free(paint->cavity_curve);
+       MEM_SAFE_FREE(paint->tool_slots);
 }
 
 /* called when copying scene settings, so even if 'src' and 'tar' are the same
@@ -559,10 +560,16 @@ void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
 {
        tar->brush = src->brush;
        tar->cavity_curve = curvemapping_copy(src->cavity_curve);
+       tar->tool_slots = MEM_dupallocN(src->tool_slots);
 
        if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
                id_us_plus((ID *)tar->brush);
                id_us_plus((ID *)tar->palette);
+               if (src->tool_slots != NULL) {
+                       for (int i = 0; i < tar->tool_slots_len; i++) {
+                               id_us_plus((ID *)tar->tool_slots[i].brush);
+                       }
+               }
        }
 }
 
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
new file mode 100644 (file)
index 0000000..bdafe21
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/paint_toolslots.c
+ *  \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_paint.h"
+
+void BKE_paint_toolslots_len_ensure(Paint *paint, int len)
+{
+       if (paint->tool_slots_len < len) {
+               paint->tool_slots = MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len);
+               paint->tool_slots_len = len;
+       }
+}
+
+typedef bool (*BrushCompatFn)(const Brush *brush);
+typedef char (*BrushToolFn)(const Brush *brush);
+
+static void paint_toolslots_init_paint(
+        Main *bmain,
+        Paint *paint,
+        BrushCompatFn brush_compat_fn, BrushToolFn brush_tool_fn)
+{
+       for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+               if (brush_compat_fn(brush)) {
+                       uint slot_index = brush_tool_fn(brush);
+                       BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+                       if (paint->tool_slots[slot_index].brush == NULL) {
+                               paint->tool_slots[slot_index].brush = brush;
+                               id_us_plus(&brush->id);
+                       }
+               }
+       }
+}
+
+/* Image paint. */
+static bool brush_compat_from_imagepaint(const Brush *brush) { return brush->ob_mode & OB_MODE_TEXTURE_PAINT; }
+static char brush_tool_from_imagepaint(const Brush *brush) { return brush->imagepaint_tool; }
+/* Sculpt. */
+static bool brush_compat_from_sculpt(const Brush *brush) { return brush->ob_mode & OB_MODE_SCULPT; }
+static char brush_tool_from_sculpt(const Brush *brush) { return brush->sculpt_tool; }
+/* Vertex Paint. */
+static bool brush_compat_from_vertexpaint(const Brush *brush) { return brush->ob_mode & OB_MODE_VERTEX_PAINT; }
+static char brush_tool_from_vertexpaint(const Brush *brush) { return brush->vertexpaint_tool; }
+/* Weight Paint. */
+static bool brush_compat_from_weightpaint(const Brush *brush) { return brush->ob_mode & OB_MODE_WEIGHT_PAINT; }
+static char brush_tool_from_weightpaint(const Brush *brush) { return brush->vertexpaint_tool; }
+/* Grease Pencil. */
+static bool brush_compat_from_gpencil(const Brush *brush) { return brush->ob_mode & OB_MODE_GPENCIL_PAINT; }
+static char brush_tool_from_gpencil(const Brush *brush) { return brush->gpencil_tool; }
+
+void BKE_paint_toolslots_init_from_main(struct Main *bmain)
+{
+       for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+               ToolSettings *ts = scene->toolsettings;
+               paint_toolslots_init_paint(bmain, &ts->imapaint.paint, brush_compat_from_imagepaint, brush_tool_from_imagepaint);
+               paint_toolslots_init_paint(bmain, &ts->sculpt->paint, brush_compat_from_sculpt, brush_tool_from_sculpt);
+               paint_toolslots_init_paint(bmain, &ts->vpaint->paint, brush_compat_from_vertexpaint, brush_tool_from_vertexpaint);
+               paint_toolslots_init_paint(bmain, &ts->wpaint->paint, brush_compat_from_weightpaint, brush_tool_from_weightpaint);
+               paint_toolslots_init_paint(bmain, &ts->gp_paint->paint, brush_compat_from_gpencil, brush_tool_from_gpencil);
+       }
+}
+
+
+void BKE_paint_toolslots_brush_update_ex(Scene *scene, Paint *paint, Brush *brush)
+{
+       ToolSettings *ts = scene->toolsettings;
+       int slot_index;
+       if (paint == &ts->imapaint.paint) {
+               slot_index = brush->imagepaint_tool;
+       }
+       else if (paint == &ts->sculpt->paint) {
+               slot_index = brush->sculpt_tool;
+       }
+       else if (paint == &ts->vpaint->paint) {
+               slot_index = brush->vertexpaint_tool;
+       }
+       else if (paint == &ts->wpaint->paint) {
+               slot_index = brush->vertexpaint_tool;
+       }
+       else if (paint == &ts->gp_paint->paint) {
+               slot_index = brush->gpencil_tool;
+       }
+       BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+       PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+       id_us_plus(&brush->id);
+       id_us_min(&tslot->brush->id);
+       tslot->brush = brush;
+}
+
+void BKE_paint_toolslots_brush_update(Scene *scene, Paint *paint)
+{
+       if (paint->brush == NULL) {
+               return;
+       }
+       BKE_paint_toolslots_brush_update_ex(scene, paint, paint->brush);
+}
index ddda9eb610e5f4f6d462bd6c245b8e09b6ccbfc8..6b5b5c59706aaf1181032c6d89ac76db4bb149a5 100644 (file)
@@ -5910,6 +5910,11 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p)
 {
        if (p) {
                p->brush = newlibadr_us(fd, sce->id.lib, p->brush);
+               for (int i = 0; i < p->tool_slots_len; i++) {
+                       if (p->tool_slots[i].brush != NULL) {
+                               p->tool_slots[i].brush = newlibadr_us(fd, sce->id.lib, p->tool_slots[i].brush);
+                       }
+               }
                p->palette = newlibadr_us(fd, sce->id.lib, p->palette);
                p->paint_cursor = NULL;
        }
@@ -6205,6 +6210,8 @@ static void direct_link_paint(FileData *fd, Paint *p)
                direct_link_curvemapping(fd, p->cavity_curve);
        else
                BKE_paint_cavity_curve_preset(p, CURVE_PRESET_LINE);
+
+       p->tool_slots = newdataadr(fd, p->tool_slots);
 }
 
 static void direct_link_paint_helper(FileData *fd, Paint **paint)
index 98bebd70d140e488c07604dc35c9b61ab5726947..1384a4f28e2bb538d565d03bf8f205bf10f726df 100644 (file)
@@ -909,6 +909,15 @@ void do_versions_after_linking_280(Main *bmain)
                        }
                }
        }
+
+       if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) {
+               for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+                       if (brush->gpencil_settings != NULL) {
+                               brush->gpencil_tool = brush->gpencil_settings->brush_type;
+                       }
+               }
+               BKE_paint_toolslots_init_from_main(bmain);
+       }
 }
 
 /* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already.
@@ -2030,7 +2039,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                        for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
                                if (brush->gpencil_settings != NULL) {
                                        BrushGpencilSettings *gp = brush->gpencil_settings;
-                                       if (gp->brush_type == GP_BRUSH_TYPE_ERASE) {
+                                       if (gp->brush_type == GPAINT_TOOL_ERASE) {
                                                gp->era_strength_f = 100.0f;
                                                gp->era_thickness_f = 10.0f;
                                        }
index 16bc845a3e987230e140ea6463c1575642bc5ac5..c3693de48667d765e6ee9db76db96ff03f3803dd 100644 (file)
@@ -2434,6 +2434,7 @@ static void write_paint(WriteData *wd, Paint *p)
        if (p->cavity_curve) {
                write_curvemapping(wd, p->cavity_curve);
        }
+       writedata(wd, DATA, sizeof(PaintToolSlot) * p->tool_slots_len, p->tool_slots);
 }
 
 static void write_layer_collections(WriteData *wd, ListBase *lb)
index ed3eab7b64218564888945ad7e4c7647dec9472b..d9a233b78d895718c21c5f348b2259341d7d8019 100644 (file)
@@ -134,7 +134,7 @@ static bool gp_stroke_paintmode_draw_poll(bContext *C)
        Brush *brush = BKE_brush_getactive_gpencil(ts);
        return ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
                (brush && brush->gpencil_settings) &&
-               (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW));
+               (brush->gpencil_tool == GPAINT_TOOL_DRAW));
 }
 
 /* Poll callback for stroke painting (erase brush) */
@@ -146,7 +146,7 @@ static bool gp_stroke_paintmode_erase_poll(bContext *C)
        Brush *brush = BKE_brush_getactive_gpencil(ts);
        return ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
                (brush && brush->gpencil_settings) &&
-               (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE));
+               (brush->gpencil_tool == GPAINT_TOOL_ERASE));
 }
 
 /* Poll callback for stroke painting (fill) */
@@ -158,7 +158,7 @@ static bool gp_stroke_paintmode_fill_poll(bContext *C)
        Brush *brush = BKE_brush_getactive_gpencil(ts);
        return ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
                (brush && brush->gpencil_settings) &&
-               (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_FILL));
+               (brush->gpencil_tool == GPAINT_TOOL_FILL));
 }
 
 /* Poll callback for stroke sculpting mode */
index e734542eb430ec95e05e9cd1ae6f5fef4004e54b..afd91d50e1f32b12e883ed5d1801b2a80bfc649f 100644 (file)
@@ -1546,10 +1546,10 @@ static void gp_stroke_doeraser(tGPsdata *p)
        float press = 1.0f;
 
        /* detect if use pressure in eraser */
-       if (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE) {
+       if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
                use_pressure = (bool)(brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
        }
-       else if ((eraser != NULL) & (eraser->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) {
+       else if ((eraser != NULL) & (eraser->gpencil_tool == GPAINT_TOOL_ERASE)) {
                use_pressure = (bool)(eraser->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
        }
        if (use_pressure) {
@@ -1645,7 +1645,7 @@ static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
        Brush *brush_old = paint->brush;
        for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
                if ((brush->ob_mode == OB_MODE_GPENCIL_PAINT) &&
-                   (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE))
+                   (brush->gpencil_tool == GPAINT_TOOL_ERASE))
                {
                        /* save first eraser to use later if no default */
                        if (brush_dft == NULL) {
@@ -1668,7 +1668,7 @@ static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
                brush_dft->size = 30.0f;
                brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
                brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
-               brush_dft->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+               brush_dft->gpencil_tool = GPAINT_TOOL_ERASE;
                brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
 
                /* reset current brush */
@@ -1704,7 +1704,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
 
        /* assign to temp tGPsdata */
        p->brush = brush;
-       if (brush->gpencil_settings->brush_type != GP_BRUSH_TYPE_ERASE) {
+       if (brush->gpencil_tool != GPAINT_TOOL_ERASE) {
                p->eraser = gp_get_default_eraser(p->bmain, ts);
        }
        else {
@@ -2317,7 +2317,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
 
        /* if mode is draw and the brush is eraser, cancel */
        if (paintmode != GP_PAINTMODE_ERASER) {
-               if ((brush) && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) {
+               if ((brush) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
                        return 0;
                }
        }
@@ -2358,7 +2358,7 @@ static void gpencil_draw_cursor_set(tGPsdata *p)
 {
        Brush *brush = p->brush;
        if ((p->paintmode == GP_PAINTMODE_ERASER) ||
-           (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE))
+           (brush->gpencil_tool == GPAINT_TOOL_ERASE))
        {
                WM_cursor_modal_set(p->win, BC_CROSSCURSOR);  /* XXX need a better cursor */
        }
index fd7ce2d41394beacbc81fc08f1856bbd7cbd4b93..5b8c11ac38c957a0f53a689f49bd91bf14dfe5f4 100644 (file)
@@ -1554,7 +1554,7 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata)
                        }
 
                        /* eraser has special shape and use a different shader program */
-                       if (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE) {
+                       if (paintbrush->gpencil_tool == GPAINT_TOOL_ERASE) {
                                ED_gpencil_brush_draw_eraser(paintbrush, x, y);
                                return;
                        }
@@ -1576,7 +1576,7 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata)
                        if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
                            ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
                            ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
-                           (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW))
+                           (paintbrush->gpencil_tool == GPAINT_TOOL_DRAW))
                        {
                                radius = 2.0f;
                                copy_v3_v3(color, gp_style->stroke_rgba);
@@ -1621,7 +1621,7 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata)
        if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
            ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
            ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
-           (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW))
+           (paintbrush->gpencil_tool == GPAINT_TOOL_DRAW))
        {
                imm_draw_circle_fill_2d(pos, x, y, radius, 40);
        }
index 4801aee3c60835de12f725b5b67c3ea9f93eaca1..9cf23f30287c36a0efedea3c3b47dd11372425af 100644 (file)
@@ -80,8 +80,7 @@ typedef struct BrushGpencilSettings {
 
        int   input_samples;   /* maximum distance before generate new point for very fast mouse movements */
        float uv_random;       /* random factor for UV rotation */
-
-       int   brush_type;      /* type of brush (draw, fill, erase, etc..) */
+       int   brush_type DNA_DEPRECATED;  /* moved to 'Brush.gpencil_tool' */
        int   eraser_mode;     /* soft, hard or stroke */
        float active_smooth;   /* smooth while drawing factor */
        float era_strength_f;  /* factor to apply to strength for soft eraser */
@@ -133,13 +132,6 @@ typedef enum eGP_FillDrawModes {
        GP_FILL_DMODE_CONTROL = 2,
 } eGP_FillDrawModes;
 
-/* BrushGpencilSettings->brush type */
-typedef enum eGP_BrushType {
-       GP_BRUSH_TYPE_DRAW = 0,
-       GP_BRUSH_TYPE_FILL = 1,
-       GP_BRUSH_TYPE_ERASE = 2,
-} eGP_BrushType;
-
 /* BrushGpencilSettings->gp_eraser_mode */
 typedef enum eGP_BrushEraserMode {
        GP_BRUSH_ERASER_SOFT = 0,
@@ -216,6 +208,8 @@ typedef struct Brush {
        char vertexpaint_tool;  /* active vertex/weight paint blend mode (poorly named) */
        char imagepaint_tool;   /* active image paint tool */
        char mask_tool;         /* enum eBrushMaskTool, only used if sculpt_tool is SCULPT_TOOL_MASK */
+       char gpencil_tool;      /* Active grease pencil tool. */
+       char _pad0[7];
 
        float autosmooth_factor;
 
@@ -416,6 +410,15 @@ typedef enum eBrushImagePaintTool {
        PAINT_TOOL_MASK = 5
 } eBrushImagePaintTool;
 
+
+/* BrushGpencilSettings->brush type */
+typedef enum eBrushGPaintTool {
+       GPAINT_TOOL_DRAW = 0,
+       GPAINT_TOOL_FILL = 1,
+       GPAINT_TOOL_ERASE = 2,
+} eBrushGPaintTool;
+
+
 /* direction that the brush displaces along */
 enum {
        SCULPT_DISP_DIR_AREA = 0,
index 7d71f1250e3a5f7b993285348e4fa1b3cfdc7cc2..31627760aa32f8ce54aaba7f7f268a724eea4e84 100644 (file)
@@ -797,9 +797,21 @@ typedef struct TimeMarker {
 
 #define PAINT_MAX_INPUT_SAMPLES 64
 
+/* We might want to store other things here. */
+typedef struct PaintToolSlot {
+       struct Brush *brush;
+} PaintToolSlot;
+
 /* Paint Tool Base */
 typedef struct Paint {
        struct Brush *brush;
+
+       /* Each tool has it's own active brush,
+        * The currently active tool is defined by the current 'brush'. */
+       struct PaintToolSlot *tool_slots;
+       int                   tool_slots_len;
+       char _pad1[4];
+
        struct Palette *palette;
        struct CurveMapping *cavity_curve; /* cavity curve */
 
index ad193eecbe862edfc2a3c2f0fa03c2ff02b98623..2c0d647332ce061d0df95335bf24428c94bbc487 100644 (file)
@@ -469,6 +469,7 @@ extern StructRNA RNA_OutflowFluidSettings;
 extern StructRNA RNA_PackedFile;
 extern StructRNA RNA_Paint;
 extern StructRNA RNA_PaintCurve;
+extern StructRNA RNA_PaintToolSlot;
 extern StructRNA RNA_Palette;
 extern StructRNA RNA_PaletteColor;
 extern StructRNA RNA_Panel;
index 2366c5186e3e57b52f88abcef6c9def5adc50cb0..0bcb29fe860858549b2a1b3235114bbc862ceff2 100644 (file)
@@ -126,10 +126,10 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = {
 
 #ifndef RNA_RUNTIME
 static EnumPropertyItem rna_enum_gpencil_brush_types_items[] = {
-       { GP_BRUSH_TYPE_DRAW, "DRAW", ICON_GP_STROKE, "Draw", "The brush is of type used for drawing strokes" },
-       { GP_BRUSH_TYPE_FILL, "FILL", ICON_COLOR, "Fill", "The brush is of type used for filling areas" },
-       { GP_BRUSH_TYPE_ERASE, "ERASE", ICON_PANEL_CLOSE, "Erase", "The brush is used for erasing strokes" },
-       { 0, NULL, 0, NULL, NULL }
+       {GPAINT_TOOL_DRAW, "DRAW", ICON_GP_STROKE, "Draw", "The brush is of type used for drawing strokes"},
+       {GPAINT_TOOL_FILL, "FILL", ICON_COLOR, "Fill", "The brush is of type used for filling areas"},
+       {GPAINT_TOOL_ERASE, "ERASE", ICON_PANEL_CLOSE, "Erase", "The brush is used for erasing strokes"},
+       {0, NULL, 0, NULL, NULL}
 };
 
 static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = {
@@ -508,33 +508,6 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
        WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
 }
 
-static const EnumPropertyItem *rna_DynamicGpencil_type_itemf(
-       bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
-       Main *bmain = CTX_data_main(C);
-       EnumPropertyItem *item = NULL, item_tmp = { 0 };
-       int totitem = 0;
-       int i = 0;
-
-       Brush *brush;
-       for (brush = bmain->brush.first; brush; brush = brush->id.next, i++) {
-               if (brush->gpencil_settings == NULL)
-                       continue;
-
-               item_tmp.identifier = brush->id.name + 2;
-               item_tmp.name = brush->id.name + 2;
-               item_tmp.value = i;
-               item_tmp.icon = brush->gpencil_settings->icon_id;
-
-               RNA_enum_item_add(&item, &totitem, &item_tmp);
-       }
-
-       RNA_enum_item_end(&item, &totitem);
-       *r_free = true;
-
-       return item;
-}
-
 static void rna_TextureSlot_brush_angle_update(bContext *C, PointerRNA *ptr)
 {
        Scene *scene = CTX_data_scene(C);
@@ -725,7 +698,7 @@ static void rna_BrushGpencilSettings_default_eraser_update(Main *bmain, Scene *s
        for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
                if ((brush != brush_cur) &&
                    (brush->ob_mode == OB_MODE_GPENCIL_PAINT) &&
-                   (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE))
+                   (brush->gpencil_tool == GPAINT_TOOL_ERASE))
                {
                        brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER;
                }
@@ -739,7 +712,7 @@ static void rna_BrushGpencilSettings_eraser_mode_update(Main *UNUSED(bmain), Sce
        Brush *brush = paint->brush;
 
        /* set eraser icon */
-       if ((brush) && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) {
+       if ((brush) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
                switch (brush->gpencil_settings->eraser_mode) {
                        case GP_BRUSH_ERASER_SOFT:
                                brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
@@ -964,27 +937,11 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
        StructRNA *srna;
        PropertyRNA *prop;
 
-       /*  Grease Pencil Drawing - generated dynamically */
-       static const EnumPropertyItem prop_dynamic_gpencil_type[] = {
-               {1, "DRAW", 0, "Draw", ""},
-               {0, NULL, 0, NULL, NULL}
-       };
-
        srna = RNA_def_struct(brna, "BrushGpencilSettings", NULL);
        RNA_def_struct_sdna(srna, "BrushGpencilSettings");
        RNA_def_struct_path_func(srna, "rna_BrushGpencilSettings_path");
        RNA_def_struct_ui_text(srna, "Grease Pencil Brush Settings", "Settings for grease pencil brush");
 
-       /* grease pencil drawing brushes */
-       prop = RNA_def_property(srna, "grease_pencil_tool", PROP_ENUM, PROP_NONE);
-       RNA_def_property_enum_sdna(prop, NULL, "brush_type");
-       RNA_def_property_enum_items(prop, prop_dynamic_gpencil_type);
-       RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DynamicGpencil_type_itemf");
-       RNA_def_property_ui_text(prop, "Grease Pencil Tool", "");
-       /* TODO: GPXX review update */
-       RNA_def_property_update(prop, 0, NULL);
-       //RNA_def_property_update(prop, 0, "rna_Brush_gpencil_tool_update");
-
        /* Sensitivity factor for new strokes */
        prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
        RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
@@ -1230,12 +1187,6 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
        RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 
-       prop = RNA_def_property(srna, "tool", PROP_ENUM, PROP_NONE);
-       RNA_def_property_enum_sdna(prop, NULL, "brush_type");
-       RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_types_items);
-       RNA_def_property_ui_text(prop, "Type", "Category of the brush");
-       RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
-
        prop = RNA_def_property(srna, "eraser_mode", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "eraser_mode");
        RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_eraser_modes_items);
@@ -1407,6 +1358,12 @@ static void rna_def_brush(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Image Paint Tool", "");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_Brush_imagepaint_tool_update");
 
+       prop = RNA_def_property(srna, "gpencil_tool", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "gpencil_tool");
+       RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_types_items);
+       RNA_def_property_ui_text(prop, "Type", "Category of the brush");
+       RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
        prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
        RNA_def_property_enum_items(prop, prop_direction_items);
index 9efb4fb4d9741139af5560a47053efedd098e9b6..dcddf77b963559a6f8459729ca6e544aa9e26b86 100644 (file)
@@ -273,23 +273,102 @@ static char *rna_ParticleEdit_path(PointerRNA *UNUSED(ptr))
 static bool rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value)
 {
        Scene *scene = (Scene *)ptr->id.data;
+       const Paint *paint = ptr->data;
        ToolSettings *ts = scene->toolsettings;
        Brush *brush = value.id.data;
        int mode = 0;
+       uint brush_tool_offset = 0;
 
        /* check the origin of the Paint struct to see which paint
         * mode to select from */
 
-       if (ptr->data == &ts->imapaint)
+       if (paint == &ts->imapaint.paint) {
                mode = OB_MODE_TEXTURE_PAINT;
-       else if (ptr->data == ts->sculpt)
+               brush_tool_offset = offsetof(Brush, imagepaint_tool);
+       }
+       else if (paint == &ts->sculpt->paint) {
                mode = OB_MODE_SCULPT;
-       else if (ptr->data == ts->vpaint)
+               brush_tool_offset = offsetof(Brush, sculpt_tool);
+       }
+       else if (paint == &ts->vpaint->paint) {
                mode = OB_MODE_VERTEX_PAINT;
-       else if (ptr->data == ts->wpaint)
+               brush_tool_offset = offsetof(Brush, vertexpaint_tool);
+       }
+       else if (paint == &ts->wpaint->paint) {
                mode = OB_MODE_WEIGHT_PAINT;
-       else if (ptr->data == ts->gp_paint)
+               brush_tool_offset = offsetof(Brush, vertexpaint_tool);
+       }
+       else if (paint == &ts->gp_paint->paint) {
                mode = OB_MODE_GPENCIL_PAINT;
+               brush_tool_offset = offsetof(Brush, gpencil_tool);
+       }
+
+       if (brush->ob_mode & mode) {
+               if (paint->brush) {
+                       const char *tool_a = (const char *)POINTER_OFFSET(paint->brush, brush_tool_offset);
+                       const char *tool_b = (const char *)POINTER_OFFSET(brush,        brush_tool_offset);
+                       if (*tool_a == *tool_b) {
+                               return true;
+                       }
+               }
+               else {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool paint_contains_brush_slot(const Paint *paint, const PaintToolSlot *tslot, int *r_index)
+{
+       if ((tslot >= paint->tool_slots) &&
+           (tslot < (paint->tool_slots + paint->tool_slots_len)))
+       {
+               *r_index = (int)(tslot - paint->tool_slots);
+               return true;
+       }
+       return false;
+}
+
+static bool rna_Brush_mode_with_tool_poll(PointerRNA *ptr, PointerRNA value)
+{
+       Scene *scene = (Scene *)ptr->id.data;
+       const PaintToolSlot *tslot = ptr->data;
+       ToolSettings *ts = scene->toolsettings;
+       Brush *brush = value.id.data;
+       int mode = 0;
+       int slot_index = 0;
+
+       if (paint_contains_brush_slot(&ts->imapaint.paint, tslot, &slot_index)) {
+               if (slot_index != brush->imagepaint_tool) {
+                       return false;
+               }
+               mode = OB_MODE_TEXTURE_PAINT;
+       }
+       else if (paint_contains_brush_slot(&ts->sculpt->paint, tslot, &slot_index)) {
+               if (slot_index != brush->sculpt_tool) {
+                       return false;
+               }
+               mode = OB_MODE_SCULPT;
+       }
+       else if (paint_contains_brush_slot(&ts->vpaint->paint, tslot, &slot_index)) {
+               if (slot_index != brush->vertexpaint_tool) {
+                       return false;
+               }
+               mode = OB_MODE_VERTEX_PAINT;
+       }
+       else if (paint_contains_brush_slot(&ts->wpaint->paint, tslot, &slot_index)) {
+               if (slot_index != brush->vertexpaint_tool) {
+                       return false;
+               }
+               mode = OB_MODE_WEIGHT_PAINT;
+       }
+       else if (paint_contains_brush_slot(&ts->gp_paint->paint, tslot, &slot_index)) {
+               if (slot_index != brush->gpencil_tool) {
+                       return false;
+               }
+               mode = OB_MODE_GPENCIL_PAINT;
+       }
 
        return brush->ob_mode & mode;
 }
@@ -383,9 +462,11 @@ static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr))
 
 static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *)ptr->id.data;
        Paint *paint = ptr->data;
        Brush *br = paint->brush;
        BKE_paint_invalidate_overlay_all();
+       BKE_paint_toolslots_brush_update(scene, paint);
        WM_main_add_notifier(NC_BRUSH | NA_SELECTED, br);
 }
 
@@ -498,6 +579,19 @@ static void rna_def_paint_curve(BlenderRNA *brna)
        RNA_def_struct_ui_icon(srna, ICON_CURVE_BEZCURVE);
 }
 
+static void rna_def_paint_tool_slot(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna = RNA_def_struct(brna, "PaintToolSlot", NULL);
+       RNA_def_struct_ui_text(srna, "Paint Tool Slot", "");
+
+       prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE);
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Brush_mode_with_tool_poll");
+       RNA_def_property_ui_text(prop, "Brush", "");
+}
 
 static void rna_def_paint(BlenderRNA *brna)
 {
@@ -514,6 +608,14 @@ static void rna_def_paint(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Brush", "Active Brush");
        RNA_def_property_update(prop, 0, "rna_Paint_brush_update");
 
+       /* paint_tool_slots */
+       prop = RNA_def_property(srna, "tool_slots", PROP_COLLECTION, PROP_NONE);
+       RNA_def_property_collection_sdna(prop, NULL, "tool_slots", "tool_slots_len");
+       RNA_def_property_struct_type(prop, "PaintToolSlot");
+       /* don't dereference pointer! */
+       RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+       RNA_def_property_ui_text(prop, "Paint Tool Slots", "");
+
        prop = RNA_def_property(srna, "palette", PROP_POINTER, PROP_NONE);
        RNA_def_property_flag(prop, PROP_EDITABLE);
        RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, NULL);
@@ -1276,6 +1378,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
        /* *** Non-Animated *** */
        RNA_define_animate_sdna(false);
        rna_def_paint_curve(brna);
+       rna_def_paint_tool_slot(brna);
        rna_def_paint(brna);
        rna_def_sculpt(brna);
        rna_def_uv_sculpt(brna);