Refactor: Tools: Change how tools are marked as using brushes

The previous way of considering tools with the `data_block` member set
as using brushes was rather unclear/confusing, but also a bit outdated
with the brush assets changes. Since then most sculpt/paint modes use a
unified brush tool, there was no tool for every brush type (aka brush
tool) anymore. So now the `data_block` member was just set dynamically to
match the active brush type which is otherwise irrelevant to the tool
system now.

Further, this will become important to bring back some of the tools that
use brushes in grease pencil draw mode, see #116337. For that we want to
keep the unified brush tool, but still allow other tools that only use a
specific brush type. So marking a tool as using brushes should be done
separately from indicating a specific brush type.

Removing/replacing the `data_block` member should happen separately
still, pending further developments (e.g. see #125449).

Pull Request: https://projects.blender.org/blender/blender/pulls/125911
This commit is contained in:
Julian Eisel
2024-09-16 12:20:25 +02:00
committed by Julian Eisel
parent 183112ad40
commit b64bf66257
11 changed files with 95 additions and 280 deletions

View File

@@ -103,8 +103,7 @@ class UnifiedPaintPanel:
# If there is no active tool, then there can't be an active brush.
return None
if not tool.has_datablock:
# tool.has_datablock is always true for tools that use brushes.
if not tool.use_brushes:
return None
space_data = context.space_data

View File

@@ -710,7 +710,7 @@ class IMAGE_HT_tool_header(Header):
draw_fn(context, layout, tool)
if tool_mode == 'PAINT':
if (tool is not None) and tool.has_datablock:
if (tool is not None) and tool.use_brushes:
layout.popover("IMAGE_PT_paint_settings_advanced")
layout.popover("IMAGE_PT_paint_stroke")
layout.popover("IMAGE_PT_paint_curve")
@@ -734,7 +734,7 @@ class IMAGE_HT_tool_header(Header):
class _draw_tool_settings_context_mode:
@staticmethod
def UV(context, layout, tool):
if tool and tool.has_datablock:
if tool and tool.use_brushes:
if context.mode == 'EDIT_MESH':
tool_settings = context.tool_settings
uv_sculpt = tool_settings.uv_sculpt
@@ -763,7 +763,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def PAINT(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return
paint = context.tool_settings.image_paint

View File

@@ -96,7 +96,7 @@ ToolDef = namedtuple(
# This isn't very nice and may change, tool definitions shouldn't care about this.
"keymap",
# Optional data-block associated with this tool.
# (Typically brush name, usage depends on mode, we could use for non-brush ID's in other modes).
# Currently only used as an identifier for particle brushes.
"data_block",
# Optional primary operator (for introspection only).
"operator",

View File

@@ -34,6 +34,7 @@ def generate_from_enum_ex(
icon_prefix,
type,
attr,
options,
cursor='DEFAULT',
tooldef_keywords=None,
icon_map=None,
@@ -76,6 +77,7 @@ def generate_from_enum_ex(
icon=icon,
cursor=cursor,
data_block=idname,
options=options,
**tooldef_keywords,
),
),
@@ -1391,31 +1393,12 @@ class _defs_particle:
icon_prefix="brush.particle.",
type=bpy.types.ParticleEdit,
attr="tool",
options={'USE_BRUSHES'}
)
class _defs_sculpt:
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.sculpt.brush
if brush:
tool = brush.sculpt_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
@staticmethod
def draw_lasso_stroke_settings(layout, props, draw_inline, draw_popover):
if draw_inline:
@@ -1870,26 +1853,6 @@ class _defs_vertex_paint:
(ob.data.use_paint_mask or
ob.data.use_paint_mask_vertex))
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.vertex_paint.brush
if brush:
tool = brush.vertex_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
class _defs_texture_paint:
@@ -1901,26 +1864,15 @@ class _defs_texture_paint:
return (ob and ob.type == 'MESH' and
(ob.data.use_paint_mask))
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.image_paint.brush
if brush:
tool = brush.image_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
cursor='PAINT_CROSS',
data_block=tool
)
)
]
@ToolDef.from_fn
def brush():
return dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
cursor='PAINT_CROSS',
options={'USE_BRUSHES'},
)
class _defs_weight_paint:
@@ -1938,26 +1890,6 @@ class _defs_weight_paint:
return VIEW3D_PT_tools_active._tools_select
return ()
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.weight_paint.brush
if brush:
tool = brush.weight_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
@ToolDef.from_fn
def sample_weight():
def draw_settings(context, layout, _tool):
@@ -2031,26 +1963,6 @@ class _defs_weight_paint:
class _defs_grease_pencil_paint:
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_paint.brush
if brush:
tool = brush.gpencil_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
@ToolDef.from_fn
def trim():
def draw_settings(context, layout, _tool):
@@ -2550,26 +2462,6 @@ class _defs_gpencil_paint:
brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
return True
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_paint.brush
if brush:
tool = brush.gpencil_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
@ToolDef.from_fn
def cutter():
def draw_settings(_context, layout, tool):
@@ -2922,26 +2814,6 @@ class _defs_gpencil_sculpt:
)
)
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
if brush:
tool = brush.gpencil_sculpt_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
class _defs_grease_pencil_sculpt:
@staticmethod
@@ -2959,71 +2831,15 @@ class _defs_grease_pencil_sculpt:
)
)
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
if brush:
tool = brush.gpencil_sculpt_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
class _defs_gpencil_weight:
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_weight_paint.brush
if brush:
tool = brush.gpencil_weight_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
# No mode specific tools currently (only general ones).
pass
class _defs_grease_pencil_weight:
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_weight_paint.brush
if brush:
tool = brush.gpencil_weight_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
# No mode specific tools currently (only general ones).
pass
class _defs_grease_pencil_vertex:
@@ -3065,26 +2881,8 @@ class _defs_grease_pencil_vertex:
class _defs_curves_sculpt:
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.curves_sculpt.brush
if brush:
tool = brush.curves_sculpt_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
# No mode specific tools currently (only general ones).
pass
class _defs_gpencil_vertex:
@@ -3104,26 +2902,6 @@ class _defs_gpencil_vertex:
)
)
@staticmethod
def generate_from_brushes(context):
# Though `data_block` is conceptually unnecessary with a single brush tool,
# it's still used because many areas assume that brush tools have it set #bToolRef.
tool = None
if context:
brush = context.tool_settings.gpencil_vertex_paint.brush
if brush:
tool = brush.gpencil_vertex_tool
return [
ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
data_block=tool
)
)
]
class _defs_node_select:
@@ -3385,6 +3163,15 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
# Private tool lists for convenient reuse in `_tools`.
_brush_tool = ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
options={'USE_BRUSHES'},
)
)
_tools_transform = (
_defs_image_uv_transform.translate,
_defs_image_uv_transform.rotate,
@@ -3439,7 +3226,7 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
],
'PAINT': [
_defs_texture_paint.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
],
@@ -3539,6 +3326,15 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
# Private tool lists for convenient reuse in `_tools`.
_brush_tool = ToolDef.from_dict(
dict(
idname="builtin.brush",
label="Brush",
icon="brush.sculpt.paint",
options={'USE_BRUSHES'},
)
)
_tools_transform = (
_defs_transform.translate,
_defs_transform.rotate,
@@ -3748,7 +3544,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_particle.generate_from_brushes,
],
'SCULPT': [
_defs_sculpt.generate_from_brushes,
_brush_tool,
None,
(
_defs_sculpt.mask_border,
@@ -3791,7 +3587,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
'SCULPT_GREASE_PENCIL': [
_defs_grease_pencil_sculpt.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
lambda context: (
@@ -3801,7 +3597,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
],
'PAINT_TEXTURE': [
_defs_texture_paint.generate_from_brushes,
_brush_tool,
None,
lambda context: (
VIEW3D_PT_tools_active._tools_select
@@ -3811,7 +3607,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
'PAINT_VERTEX': [
_defs_vertex_paint.generate_from_brushes,
_brush_tool,
None,
lambda context: (
VIEW3D_PT_tools_active._tools_select
@@ -3821,7 +3617,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
'PAINT_WEIGHT': [
_defs_weight_paint.generate_from_brushes,
_brush_tool,
_defs_weight_paint.gradient,
None,
(
@@ -3845,7 +3641,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
'PAINT_GREASE_PENCIL': [
_defs_view3d_generic.cursor,
None,
_defs_grease_pencil_paint.generate_from_brushes,
_brush_tool,
_defs_grease_pencil_paint.trim,
None,
_defs_grease_pencil_paint.eyedropper,
@@ -3862,7 +3658,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
'PAINT_GPENCIL': [
_defs_view3d_generic.cursor,
None,
_defs_gpencil_paint.generate_from_brushes,
_brush_tool,
_defs_gpencil_paint.cutter,
None,
_defs_gpencil_paint.eyedropper,
@@ -3898,7 +3694,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
'SCULPT_GPENCIL': [
_defs_gpencil_sculpt.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
lambda context: (
@@ -3908,17 +3704,17 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
],
'WEIGHT_GPENCIL': [
_defs_gpencil_weight.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
],
'WEIGHT_GREASE_PENCIL': [
_defs_grease_pencil_weight.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
],
'VERTEX_GPENCIL': [
_defs_gpencil_vertex.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
None,
@@ -3940,7 +3736,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
],
'SCULPT_CURVES': [
_defs_curves_sculpt.generate_from_brushes,
_brush_tool,
None,
*_tools_annotate,
],

View File

@@ -100,7 +100,7 @@ class VIEW3D_HT_tool_header(Header):
pass
elif tool_mode == 'PARTICLE':
# Disable, only shows "Brush" panel, which is already in the top-bar.
# if tool.has_datablock:
# if tool.use_brushes:
# layout.popover_group(context=".paint_common", **popover_kw)
pass
elif tool_mode == 'PAINT_GPENCIL':
@@ -244,7 +244,7 @@ class VIEW3D_HT_tool_header(Header):
class _draw_tool_settings_context_mode:
@staticmethod
def SCULPT(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
paint = context.tool_settings.sculpt
@@ -306,7 +306,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def PAINT_TEXTURE(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
paint = context.tool_settings.image_paint
@@ -323,7 +323,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def PAINT_VERTEX(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
paint = context.tool_settings.vertex_paint
@@ -340,7 +340,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def PAINT_WEIGHT(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
paint = context.tool_settings.weight_paint
@@ -395,7 +395,7 @@ class _draw_tool_settings_context_mode:
row = layout.row(align=True)
row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
return False
elif not tool.has_datablock:
elif not tool.use_brushes:
return False
tool_settings = context.tool_settings
@@ -431,7 +431,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def SCULPT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
tool_settings = context.tool_settings
@@ -449,7 +449,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def SCULPT_GREASE_PENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
paint = context.tool_settings.gpencil_sculpt_paint
@@ -507,7 +507,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def WEIGHT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
tool_settings = context.tool_settings
@@ -525,7 +525,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def WEIGHT_GREASE_PENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
paint = context.tool_settings.gpencil_weight_paint
@@ -544,7 +544,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def VERTEX_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
tool_settings = context.tool_settings
@@ -590,7 +590,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def PARTICLE(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
# See: `VIEW3D_PT_tools_brush`, basically a duplicate
@@ -628,7 +628,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def SCULPT_CURVES(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
tool_settings = context.tool_settings
@@ -716,7 +716,7 @@ class _draw_tool_settings_context_mode:
@staticmethod
def PAINT_GREASE_PENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
if (tool is None) or (not tool.use_brushes):
return False
tool_settings = context.tool_settings

View File

@@ -319,8 +319,7 @@ class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel):
# If there is no active tool, then there can't be an active brush.
tool = None
if not tool_context.has_datablock:
# tool.has_datablock is always true for tools that use brushes.
if not tool_context.use_brushes:
tool = None
if tool is not None:
@@ -1577,7 +1576,7 @@ class VIEW3D_PT_tools_particlemode_options_display(View3DPanel, Panel):
def tool_use_brush(context):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool and tool.has_datablock is False:
if tool and tool.use_brushes is False:
return False
return True

View File

@@ -1734,7 +1734,7 @@ bool paint_brush_tool_poll(bContext *C)
{
/* Check the current tool is a brush. */
bToolRef *tref = area->runtime.tool;
if (tref && tref->runtime && tref->runtime->data_block[0]) {
if (tref && tref->runtime && (tref->runtime->flag & TOOLREF_FLAG_USE_BRUSHES)) {
return true;
}
}

View File

@@ -30,6 +30,7 @@ enum {
* Typically gizmos handle this but some tools (such as the knife tool) don't use a gizmo.
*/
TOOLREF_FLAG_FALLBACK_KEYMAP = (1 << 0),
TOOLREF_FLAG_USE_BRUSHES = (1 << 1),
};
#

View File

@@ -191,6 +191,12 @@ static bool rna_WorkSpaceTool_has_datablock_get(PointerRNA *ptr)
return (tref->runtime) ? (tref->runtime->data_block[0] != '\0') : false;
}
static bool rna_WorkSpaceTool_use_brushes_get(PointerRNA *ptr)
{
bToolRef *tref = static_cast<bToolRef *>(ptr->data);
return (tref->runtime) ? ((tref->runtime->flag & TOOLREF_FLAG_USE_BRUSHES) != 0) : false;
}
static void rna_WorkSpaceTool_widget_get(PointerRNA *ptr, char *value)
{
bToolRef *tref = static_cast<bToolRef *>(ptr->data);
@@ -295,10 +301,17 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Paint Canvas", "Does this tool use a painting canvas");
RNA_define_verify_sdna(false);
prop = RNA_def_property(srna, "has_datablock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Has Data-Block", "");
RNA_def_property_boolean_funcs(prop, "rna_WorkSpaceTool_has_datablock_get", nullptr);
prop = RNA_def_property(srna, "use_brushes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Uses Brushes", "");
RNA_def_property_boolean_funcs(prop, "rna_WorkSpaceTool_use_brushes_get", nullptr);
RNA_define_verify_sdna(true);
prop = RNA_def_property(srna, "widget", PROP_STRING, PROP_NONE);

View File

@@ -124,6 +124,11 @@ void RNA_api_workspace_tool(StructRNA *srna)
static const EnumPropertyItem options_items[] = {
{TOOLREF_FLAG_FALLBACK_KEYMAP, "KEYMAP_FALLBACK", 0, "Fallback", ""},
{TOOLREF_FLAG_USE_BRUSHES,
"USE_BRUSHES",
0,
"Uses Brushes",
"Allow this tool to use brushes via the asset system"},
{0, nullptr, 0, nullptr, nullptr},
};

View File

@@ -156,10 +156,12 @@ static void toolsystem_ref_link(const bContext *C, WorkSpace *workspace, bToolRe
}
}
if (tref_rt->data_block[0]) {
if (tref_rt->flag & TOOLREF_FLAG_USE_BRUSHES) {
Main *bmain = CTX_data_main(C);
if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE) &&
tref_rt->data_block[0])
{
const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
if (i != -1) {
@@ -779,7 +781,7 @@ void WM_toolsystem_update_from_context(
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
return tref_rt && (tref_rt->data_block[0] != '\0');
return tref_rt && (tref_rt->flag & TOOLREF_FLAG_USE_BRUSHES);
}
void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,