Sculpt/Paint: Add asset shelf option to filter brushes by the active tool #128450

Closed
Julian Eisel wants to merge 6 commits from JulianEisel/blender:temp-brush-asset-filter-by-tool into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 80 additions and 10 deletions

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Menu
from bpy.types import Menu, Panel
class BrushAssetShelf:
@ -18,12 +18,43 @@ class BrushAssetShelf:
def poll(cls, context):
return hasattr(context, "object") and context.object and context.object.mode == cls.mode
@classmethod
def has_tool_with_brush_type(cls, context, brush_type):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
space_type = context.space_data.type
brush_type_items = bpy.types.Brush.bl_rna.properties[cls.tool_prop].enum_items
tool_helper_cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
for item in ToolSelectPanelHelper._tools_flatten(
tool_helper_cls.tools_from_context(context, mode=context.mode),
):
if item is None:
continue
if item.idname in {
"builtin.arc",
"builtin.curve",
"builtin.line",
"builtin.box",
"builtin.circle",
"builtin.polyline",
}:
continue
if item.options is None or ('USE_BRUSHES' not in item.options):
continue
if item.brush_type is not None:
if brush_type_items[item.brush_type].value == brush_type:
return True
return False
@classmethod
def brush_type_poll(cls, context, asset):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context)
if not tool or tool.brush_type == 'ANY':
if not tool:
return True
if not cls.brush_type_prop or not cls.tool_prop:
return True
@ -33,9 +64,14 @@ class BrushAssetShelf:
# certain brush type.
if asset_brush_type is None:
return False
brush_type_items = bpy.types.Brush.bl_rna.properties[cls.tool_prop].enum_items
return brush_type_items[asset_brush_type].identifier == tool.brush_type
# For the general brush that supports any brush type, filter out brushes that show up for
# other tools already.
if tool.brush_type == 'ANY':
return not cls.has_tool_with_brush_type(context, asset_brush_type)
brush_type_items = bpy.types.Brush.bl_rna.properties[cls.tool_prop].enum_items
return brush_type_items[tool.brush_type].value == asset_brush_type
@classmethod
def asset_poll(cls, asset):
@ -45,12 +81,13 @@ class BrushAssetShelf:
return False
context = bpy.context
prefs = context.preferences
is_asset_shelf_region = context.region and context.region.type == 'ASSET_SHELF'
# Show all brushes in the permanent asset shelf region. Otherwise filter out brushes that
# Show all brushes in the popup asset shelves. Otherwise filter out brushes that
# are incompatible with the tool.
if not is_asset_shelf_region and not cls.brush_type_poll(context, asset):
return False
if is_asset_shelf_region and prefs.view.use_filter_brushes_by_tool:
return cls.brush_type_poll(context, asset)
return True
@ -112,6 +149,25 @@ class BrushAssetShelf:
)
class VIEW3D_PT_brush_asset_shelf_filter(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Filter"
bl_parent_id = "ASSETSHELF_PT_display"
@classmethod
def poll(cls, context):
if context.asset_shelf is None:
return False
return context.asset_shelf.bl_idname == BrushAssetShelf.get_shelf_name_from_context(context)
def draw(self, context):
layout = self.layout
prefs = context.preferences
layout.prop(prefs.view, "use_filter_brushes_by_tool", text="By Active Tool")
class UnifiedPaintPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@ -1828,6 +1884,7 @@ def brush_basic_grease_pencil_vertex_settings(layout, context, brush, *, compact
classes = (
VIEW3D_PT_brush_asset_shelf_filter,
VIEW3D_MT_tools_projectpaint_clone,
)

View File

@ -31,7 +31,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 0
#define BLENDER_FILE_SUBVERSION 1
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -946,7 +946,7 @@ void blo_do_versions_userdef(UserDef *userdef)
if (!USER_VERSION_ATLEAST(400, 24)) {
/* Clear deprecated USER_MENUFIXEDORDER user flag for reuse. */
userdef->uiflag &= ~USER_UIFLAG_UNUSED_4;
userdef->uiflag &= ~(1 << 23);
}
if (!USER_VERSION_ATLEAST(400, 26)) {
@ -1064,6 +1064,10 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->sequencer_editor_flag |= USER_SEQ_ED_CONNECT_STRIPS_BY_DEFAULT;
}
if (!USER_VERSION_ATLEAST(403, 30)) {
userdef->uiflag |= USER_FILTER_BRUSHES_BY_TOOL;
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a USER_VERSION_ATLEAST check.

View File

@ -1294,7 +1294,8 @@ typedef enum eUserpref_UI_Flag {
USER_ZOOM_TO_MOUSEPOS = (1 << 20),
USER_SHOW_FPS = (1 << 21),
USER_REGISTER_ALL_USERS = (1 << 22),
USER_UIFLAG_UNUSED_4 = (1 << 23), /* Cleared. */
/** Actually implemented in .py. */
USER_FILTER_BRUSHES_BY_TOOL = (1 << 23),
USER_CONTINUOUS_MOUSE = (1 << 24),
USER_ZOOM_INVERT = (1 << 25),
USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */

View File

@ -5323,6 +5323,14 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, nullptr, "uiflag", USER_PLAINMENUS);
RNA_def_property_ui_text(prop, "Toolbox Column Layout", "Use a column layout for toolbox");
prop = RNA_def_property(srna, "use_filter_brushes_by_tool", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "uiflag", USER_FILTER_BRUSHES_BY_TOOL);
RNA_def_property_ui_text(prop,
"Filter Brushes by Tool",
"Only show brushes applicable for the currently active tool in the "
"asset shelf. Stored in the Preferences, which may have to be saved "
"manually if Auto-Save Preferences is disabled");
static const EnumPropertyItem header_align_items[] = {
{0, "NONE", 0, "Keep Existing", "Keep existing header alignment"},
{USER_HEADER_FROM_PREF, "TOP", 0, "Top", "Top aligned on load"},