Files
test/tests/python/bl_brush_test.py
Sean Kim 4ecde8dc53 Paint: Allow duplicating essential brushes into current file
With the release of the brush assets project in 4.3, most brush
management moved out of the current .blend file into either the
essentials library or user-created libraries.

With this change, a number of workflows became more difficult:
* Handling a large library of texture and texture properties for brushes
  due to ID linkage constraints.
* Having local tweaks to a brush without bloating the the asset library
  and reducing discoverability.

This commit introduces an intermediate step to assist with both of the
preceding pain points. The `brush.asset_save_as` operator is extended
to allow saving into the current blend file via the `Duplicate Asset`
context menu entry.

Additionally, these features help ease authoring brush assets in general
from the UI instead of requiring manual datablock management.

This allows brushes to be stored alongside other data inside a specific
blend file.

Related to #129655 and [1].

[1] https://blender.community/c/rightclickselect/XYMA/

Pull Request: https://projects.blender.org/blender/blender/pulls/138105
2025-05-20 22:02:42 +02:00

70 lines
3.1 KiB
Python

# SPDX-FileCopyrightText: 2025 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
import sys
import unittest
import bpy
class AssetActivateTest(unittest.TestCase):
def setUp(self):
# Test case isn't specific to Sculpt Mode, but we need a paint mode in general.
bpy.ops.object.mode_set(mode='SCULPT')
bpy.ops.brush.asset_activate(
asset_library_type='ESSENTIALS',
relative_asset_identifier='brushes/essentials_brushes-mesh_sculpt.blend/Brush/Draw')
def test_loads_essential_asset(self):
result = bpy.ops.brush.asset_activate(
asset_library_type='ESSENTIALS',
relative_asset_identifier='brushes/essentials_brushes-mesh_sculpt.blend/Brush/Smooth')
self.assertEqual({'FINISHED'}, result)
def test_toggle_when_brush_differs_sets_specified_brush(self):
"""Test that using the 'Toggle' parameter when the brush is not active still activates the correct brush"""
bpy.ops.brush.asset_activate(
asset_library_type='ESSENTIALS',
relative_asset_identifier='brushes/essentials_brushes-mesh_sculpt.blend/Brush/Mask',
use_toggle=True)
self.assertEqual(bpy.context.tool_settings.sculpt.brush.name, 'Mask')
def test_toggle_when_brush_matches_sets_previous_brush(self):
"""Test that using the 'Toggle' parameter when the brush is active activates the previously activated brush"""
bpy.ops.brush.asset_activate(
asset_library_type='ESSENTIALS',
relative_asset_identifier='brushes/essentials_brushes-mesh_sculpt.blend/Brush/Mask',
use_toggle=True)
self.assertEqual(bpy.context.tool_settings.sculpt.brush.name, 'Mask')
bpy.ops.brush.asset_activate(
asset_library_type='ESSENTIALS',
relative_asset_identifier='brushes/essentials_brushes-mesh_sculpt.blend/Brush/Mask',
use_toggle=True)
self.assertEqual(bpy.context.tool_settings.sculpt.brush.name, 'Draw')
class AssetSaveAsTest(unittest.TestCase):
def setUp(self):
# Test case isn't specific to Sculpt Mode, but we need a paint mode in general.
bpy.ops.object.mode_set(mode='SCULPT')
bpy.ops.brush.asset_activate(
asset_library_type='ESSENTIALS',
relative_asset_identifier='brushes/essentials_brushes-mesh_sculpt.blend/Brush/Smooth')
def test_saves_asset_locally(self):
"""Test that saving an asset to the local creates a copy correctly"""
result = bpy.ops.brush.asset_save_as(name="Local Copy", asset_library_reference="LOCAL", catalog_path="")
self.assertEqual({'FINISHED'}, result)
self.assertTrue("Local Copy" in bpy.data.brushes)
local_brush = bpy.data.brushes["Local Copy"]
self.assertEqual(local_brush.sculpt_tool, 'SMOOTH')
self.assertGreaterEqual(local_brush.users, 1)
if __name__ == "__main__":
# Drop all arguments before "--", or everything if the delimiter is absent. Keep the executable path.
unittest.main(argv=sys.argv[:1] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []))