diff --git a/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py b/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py index 1f5f0ee17b0..9fa63e73591 100644 --- a/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py +++ b/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py @@ -107,10 +107,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True): kmi_hack_properties = kmi_hack.properties kmi_hack.active = False - kmi_hack_brush_select = keymap.keymap_items.new("paint.brush_select", 'NONE', 'PRESS') - kmi_hack_brush_select_properties = kmi_hack_brush_select.properties - kmi_hack_brush_select.active = False - if use_release_confirm or use_tap_reset: kmi_toolbar = wm.keyconfigs.find_item_from_operator( idname="wm.toolbar", @@ -169,47 +165,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True): include={'KEYBOARD'}, )[1] - if kmi_found is None: - if item.data_block: - # PAINT_OT_brush_select - mode = context.active_object.mode - # See: BKE_paint_get_tool_prop_id_from_paintmode - if space_type == 'IMAGE_EDITOR': - if context.space_data.mode == 'PAINT': - attr = "image_tool" - else: - attr = None - elif space_type == 'VIEW_3D': - attr = { - 'SCULPT': "sculpt_tool", - 'VERTEX_PAINT': "vertex_tool", - 'WEIGHT_PAINT': "weight_tool", - 'TEXTURE_PAINT': "image_tool", - 'PAINT_GPENCIL': "gpencil_tool", - 'PAINT_GREASE_PENCIL': "gpencil_tool", - 'VERTEX_GPENCIL': "gpencil_vertex_tool", - 'SCULPT_GPENCIL': "gpencil_sculpt_tool", - 'WEIGHT_GPENCIL': "gpencil_weight_tool", - 'SCULPT_CURVES': "curves_sculpt_tool", - }.get(mode, None) - else: - attr = None - - if attr is not None: - setattr(kmi_hack_brush_select_properties, attr, item.data_block) - kmi_found = wm.keyconfigs.find_item_from_operator( - idname="paint.brush_select", - context='INVOKE_REGION_WIN', - properties=kmi_hack_brush_select_properties, - include={'KEYBOARD'}, - )[1] - elif mode in {'EDIT', 'PARTICLE_EDIT', 'SCULPT_GPENCIL'}: - # Doesn't use brushes - pass - else: - print("Unsupported mode:", mode) - del mode, attr - else: kmi_found = None @@ -402,7 +357,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True): if use_hack_properties: keymap.keymap_items.remove(kmi_hack) - keymap.keymap_items.remove(kmi_hack_brush_select) # Keep last so we can try add a key without any modifiers # in the case this toolbar was activated with modifiers. diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index ca5e35c0b19..e12cc684b92 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -5599,27 +5599,37 @@ def km_sculpt(params): op_menu_pie("VIEW3D_MT_sculpt_automasking_pie", {"type": 'A', "alt": True, "value": 'PRESS'}), op_menu_pie("VIEW3D_MT_sculpt_face_sets_edit_pie", {"type": 'W', "value": 'PRESS', "alt": True}), *_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event), - # Tools - ("paint.brush_select", {"type": 'V', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'DRAW')]}), - ("paint.brush_select", {"type": 'S', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'SMOOTH')]}), - ("paint.brush_select", {"type": 'P', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'PINCH')]}), - ("paint.brush_select", {"type": 'I', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'INFLATE')]}), - ("paint.brush_select", {"type": 'G', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'GRAB')]}), - ("paint.brush_select", {"type": 'T', "value": 'PRESS', "shift": True}, - {"properties": [("sculpt_tool", 'SCRAPE')]}), - ("paint.brush_select", {"type": 'C', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'CLAY_STRIPS')]}), - ("paint.brush_select", {"type": 'C', "value": 'PRESS', "shift": True}, - {"properties": [("sculpt_tool", 'CREASE')]}), - ("paint.brush_select", {"type": 'K', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'SNAKE_HOOK')]}), - ("paint.brush_select", {"type": 'M', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'MASK'), ("toggle", True), ("create_missing", True)]}), + # Brushes + ("brush.asset_select", {"type": 'V', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Draw")]}), + ("brush.asset_select", {"type": 'S', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Smooth")]}), + ("brush.asset_select", {"type": 'P', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Pinch/Magnify")]}), + ("brush.asset_select", {"type": 'I', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Inflate/Deflate")]}), + ("brush.asset_select", {"type": 'G', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Grab")]}), + ("brush.asset_select", {"type": 'T', "value": 'PRESS', "shift": True}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Scrape/Fill")]}), + ("brush.asset_select", {"type": 'C', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Clay Strips")]}), + ("brush.asset_select", {"type": 'C', "value": 'PRESS', "shift": True}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Crease")]}), + ("brush.asset_select", {"type": 'K', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Snake Hook")]}), + ("brush.asset_select", {"type": 'M', "value": 'PRESS'}, + {"properties": [("asset_library_type", 'ESSENTIALS'), + ("relative_asset_identifier", "brushes/essentials_brushes.blend/Brush/Mask")]}), ]) # Lasso Masking. diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index 6a686d479ca..bcab5c42cec 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -2,24 +2,67 @@ # # SPDX-License-Identifier: GPL-2.0-or-later +import bpy from bpy.types import Menu class BrushAssetShelf: bl_options = {'DEFAULT_VISIBLE', 'NO_ASSET_DRAG', 'STORE_ENABLED_CATALOGS_IN_PREFERENCES'} + bl_activate_operator = "BRUSH_OT_asset_select" bl_default_preview_size = 48 @classmethod def poll(cls, context): - prefs = context.preferences - if not prefs.experimental.use_extended_asset_browser: - return False - - return context.mode == 'SCULPT' + return context.object and context.object.mode == cls.mode @classmethod def asset_poll(cls, asset): - return asset.id_type == 'BRUSH' + if asset.id_type != 'BRUSH': + return False + if hasattr(cls, "mode_prop"): + return asset.metadata.get(cls.mode_prop, False) + return True + + @classmethod + def get_active_asset(cls): + paint_settings = UnifiedPaintPanel.paint_settings(bpy.context) + return paint_settings.brush_asset_reference if paint_settings else None + + @classmethod + def draw_context_menu(self, context, asset, layout): + # Currently this menu adds operators that deal with the affected brush and don't take the + # asset into account. Luckily that is okay for now, since right clicking in the grid view + # also activates the item. + layout.menu_contents("VIEW3D_MT_brush_context_menu") + + @staticmethod + def get_shelf_name_from_context(context): + mode_map = { + 'SCULPT': "VIEW3D_AST_brush_sculpt", + 'PAINT_VERTEX': "VIEW3D_AST_brush_vertex_paint", + 'PAINT_WEIGHT': "VIEW3D_AST_brush_weight_paint", + 'PAINT_TEXTURE': "VIEW3D_AST_brush_texture_paint", + 'PAINT_2D': "IMAGE_AST_brush_paint", + 'PAINT_GPENCIL': "VIEW3D_AST_brush_gpencil_paint", + 'SCULPT_GPENCIL': "VIEW3D_AST_brush_gpencil_sculpt", + 'WEIGHT_GPENCIL': "VIEW3D_AST_brush_gpencil_weight", + 'VERTEX_GPENCIL': "VIEW3D_AST_brush_gpencil_vertex", + 'SCULPT_CURVES': "VIEW3D_AST_brush_sculpt_curves", + 'PAINT_GREASE_PENCIL': "VIEW3D_AST_brush_grease_pencil_paint", + } + mode = UnifiedPaintPanel.get_brush_mode(context) + return mode_map[mode] + + @staticmethod + def draw_popup_selector(layout, context, brush, show_name=True): + preview_icon_id = brush.preview.icon_id if brush and brush.preview else 0 + + layout.template_asset_shelf_popover( + BrushAssetShelf.get_shelf_name_from_context(context), + name=brush.name if (brush and show_name) else None, + icon='BRUSH_DATA' if not preview_icon_id else 'NONE', + icon_value=preview_icon_id, + ) class UnifiedPaintPanel: @@ -156,7 +199,7 @@ class BrushPanel(UnifiedPaintPanel): class BrushSelectPanel(BrushPanel): - bl_label = "Brushes" + bl_label = "Brush Asset" def draw(self, context): layout = self.layout @@ -164,20 +207,18 @@ class BrushSelectPanel(BrushPanel): brush = settings.brush row = layout.row() - large_preview = True - if large_preview: - row.column().template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8, hide_buttons=False) - else: - row.column().template_ID(settings, "brush", new="brush.add") + + col = row.column(align=True) + BrushAssetShelf.draw_popup_selector(col, context, brush, show_name=False) + if brush: + col.prop(brush, "name", text="") + + if brush is None: + return + col = row.column() col.menu("VIEW3D_MT_brush_context_menu", icon='DOWNARROW_HLT', text="") - if brush is not None: - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") - - if brush.use_custom_icon: - layout.prop(brush, "icon_filepath", text="") - class ColorPalettePanel(BrushPanel): bl_label = "Color Palette" @@ -993,6 +1034,9 @@ def brush_settings_advanced(layout, context, brush, popover=False): use_frontface = False if mode == 'SCULPT': + layout.prop(brush, "sculpt_tool") + layout.separator() + capabilities = brush.sculpt_capabilities use_accumulate = capabilities.has_accumulate use_frontface = True @@ -1083,6 +1127,9 @@ def brush_settings_advanced(layout, context, brush, popover=False): # 3D and 2D Texture Paint. elif mode in {'PAINT_TEXTURE', 'PAINT_2D'}: + layout.prop(brush, "image_tool") + layout.separator() + capabilities = brush.image_paint_capabilities use_accumulate = capabilities.has_accumulate @@ -1110,6 +1157,9 @@ def brush_settings_advanced(layout, context, brush, popover=False): # Vertex Paint # elif mode == 'PAINT_VERTEX': + layout.prop(brush, "vertex_tool") + layout.separator() + layout.prop(brush, "use_alpha") if brush.vertex_tool != 'SMEAR': use_accumulate = True @@ -1117,10 +1167,17 @@ def brush_settings_advanced(layout, context, brush, popover=False): # Weight Paint elif mode == 'PAINT_WEIGHT': + layout.prop(brush, "weight_tool") + layout.separator() + if brush.weight_tool != 'SMEAR': use_accumulate = True use_frontface = True + # Sculpt Curves + elif mode == 'SCULPT_CURVES': + layout.prop(brush, "curves_sculpt_tool") + # Draw shared settings. if use_accumulate: layout.prop(brush, "use_accumulate") @@ -1128,6 +1185,29 @@ def brush_settings_advanced(layout, context, brush, popover=False): if use_frontface: layout.prop(brush, "use_frontface", text="Front Faces Only") + # Brush modes + header, panel = layout.panel("modes", default_closed=True) + header.label(text="Modes") + if panel: + panel.use_property_split = True + panel.use_property_decorate = False + + col = panel.column(align=True) + col.prop(brush, "use_paint_sculpt", text="Sculpt") + col.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt") + col.prop(brush, "use_paint_vertex", text="Vertex Paint") + col.prop(brush, "use_paint_weight", text="Weight Paint") + col.prop(brush, "use_paint_image", text="Texture Paint") + col.prop(brush, "use_paint_sculpt_curves", text="Sculpt Curves") + + if len(brush.icon_filepath) > 0: + header, panel = layout.panel("legacy", default_closed=True) + header.label(text="Legacy Icon") + if panel: + panel.label(text="Brush icons have moved to the asset preview image", icon='ERROR') + panel.prop(brush, "use_custom_icon") + panel.prop(brush, "icon_filepath") + def draw_color_settings(context, layout, brush, color_type=False): """Draw color wheel and gradient settings.""" diff --git a/scripts/startup/bl_ui/space_image.py b/scripts/startup/bl_ui/space_image.py index adc754bcf79..ca319eaa14f 100644 --- a/scripts/startup/bl_ui/space_image.py +++ b/scripts/startup/bl_ui/space_image.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later from bpy.types import ( + AssetShelf, Header, Menu, Panel, @@ -23,6 +24,7 @@ from bl_ui.properties_paint_common import ( SmoothStrokePanel, FalloffPanel, DisplayPanel, + BrushAssetShelf, ) from bl_ui.properties_grease_pencil_common import ( AnnotationDataPanel, @@ -763,9 +765,10 @@ class _draw_tool_settings_context_mode: return paint = context.tool_settings.image_paint - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - brush = paint.brush + + BrushAssetShelf.draw_popup_selector(layout, context, brush) + if brush is None: return @@ -1181,7 +1184,7 @@ class IMAGE_PT_udim_tiles(Panel): class IMAGE_PT_paint_select(Panel, ImagePaintPanel, BrushSelectPanel): - bl_label = "Brushes" + bl_label = "Brush Asset" bl_context = ".paint_common_2d" bl_category = "Tool" @@ -1219,8 +1222,8 @@ class IMAGE_PT_paint_settings_advanced(Panel, ImagePaintPanel): settings = context.tool_settings.image_paint brush = settings.brush - - brush_settings_advanced(layout.column(), context, brush, self.is_popover) + if brush: + brush_settings_advanced(layout.column(), context, brush, self.is_popover) class IMAGE_PT_paint_color(Panel, ImagePaintPanel): @@ -1233,16 +1236,17 @@ class IMAGE_PT_paint_color(Panel, ImagePaintPanel): def poll(cls, context): settings = context.tool_settings.image_paint brush = settings.brush + if not brush: + return False capabilities = brush.image_paint_capabilities - return capabilities.has_color def draw(self, context): layout = self.layout settings = context.tool_settings.image_paint brush = settings.brush - - draw_color_settings(context, layout, brush, color_type=True) + if brush: + draw_color_settings(context, layout, brush, color_type=True) class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel, ColorPalettePanel): @@ -1687,6 +1691,18 @@ class IMAGE_PT_annotation(AnnotationDataPanel, Panel): # Grease Pencil drawing tools. +class ImageAssetShelf(BrushAssetShelf): + bl_space_type = "IMAGE_EDITOR" + + +class IMAGE_AST_brush_paint(ImageAssetShelf, AssetShelf): + mode_prop = "use_paint_image" + + @classmethod + def poll(cls, context): + return context.space_data and context.space_data.ui_mode == 'PAINT' + + classes = ( IMAGE_MT_view, IMAGE_MT_view_zoom, @@ -1756,6 +1772,7 @@ classes = ( IMAGE_PT_overlay_uv_edit_geometry, IMAGE_PT_overlay_texture_paint, IMAGE_PT_overlay_image, + IMAGE_AST_brush_paint, ) diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 6ba88ce096f..a7795686cf8 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -18,7 +18,9 @@ from bl_ui.space_toolsystem_common import ( ToolSelectPanelHelper, ToolDef, ) - +from bl_ui.properties_paint_common import ( + BrushAssetShelf, +) from bpy.app.translations import pgettext_tip as tip_ @@ -1396,16 +1398,23 @@ class _defs_sculpt: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="brush.sculpt.", - type=bpy.types.Brush, - attr="sculpt_tool", - # TODO(@ideasman42): we may want to enable this, - # it causes awkward grouping with 2x column button layout. - use_separators=False, - ) + # 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 + ) + ) + ] @ToolDef.from_fn def hide_border(): @@ -1726,13 +1735,23 @@ class _defs_vertex_paint: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="brush.paint_vertex.", - type=bpy.types.Brush, - attr="vertex_tool", - ) + # 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: @@ -1747,14 +1766,24 @@ class _defs_texture_paint: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="brush.paint_texture.", - type=bpy.types.Brush, - attr="image_tool", - cursor='PAINT_CROSS', - ) + # 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 + ) + ) + ] class _defs_weight_paint: @@ -1774,13 +1803,23 @@ class _defs_weight_paint: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="brush.paint_weight.", - type=bpy.types.Brush, - attr="weight_tool", - ) + # 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(): @@ -1853,36 +1892,25 @@ class _defs_weight_paint: class _defs_paint_grease_pencil: - # FIXME: Replace brush tools with code below once they are all implemented: - # - # @staticmethod - # def generate_from_brushes(context): - # return generate_from_enum_ex( - # context, - # idname_prefix="builtin_brush.", - # icon_prefix="brush.gpencil_draw.", - # type=bpy.types.Brush, - # attr="gpencil_tool", - # cursor='DOT', - # ) - - @ToolDef.from_fn - def draw(): - return dict( - idname="builtin_brush.Draw", - label="Draw", - icon="brush.gpencil_draw.draw", - data_block='DRAW', - ) - - @ToolDef.from_fn - def erase(): - return dict( - idname="builtin_brush.Erase", - label="Erase", - icon="brush.gpencil_draw.erase", - data_block='ERASE', - ) + @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(): @@ -1925,7 +1953,8 @@ class _defs_paint_grease_pencil: row = layout.row(align=True) tool_settings = context.scene.tool_settings settings = tool_settings.gpencil_paint - row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) + + BrushAssetShelf.draw_popup_selector(row, context, brush) from bl_ui.properties_paint_common import ( brush_basic_grease_pencil_paint_settings, @@ -2307,7 +2336,8 @@ class _defs_gpencil_paint: row = layout.row(align=True) tool_settings = context.scene.tool_settings settings = tool_settings.gpencil_paint - row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) + + BrushAssetShelf.draw_popup_selector(layout, context, brush) from bl_ui.properties_paint_common import ( brush_basic_gpencil_paint_settings, @@ -2320,17 +2350,23 @@ class _defs_gpencil_paint: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="brush.gpencil_draw.", - type=bpy.types.Brush, - attr="gpencil_tool", - cursor='DOT', - tooldef_keywords=dict( - operator="gpencil.draw", - ), - ) + # 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(): @@ -2686,16 +2722,23 @@ class _defs_gpencil_sculpt: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="ops.gpencil.sculpt_", - type=bpy.types.Brush, - attr="gpencil_sculpt_tool", - tooldef_keywords=dict( - operator="gpencil.sculpt_paint", - ), - ) + # 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: @@ -2716,33 +2759,46 @@ class _defs_grease_pencil_sculpt: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="ops.gpencil.sculpt_", - type=bpy.types.Brush, - # Uses GPv2 tool settings - attr="gpencil_sculpt_tool", - tooldef_keywords=dict( - operator="grease_pencil.sculpt_paint", - ), - ) + # 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): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="ops.gpencil.sculpt_", - type=bpy.types.Brush, - attr="gpencil_weight_tool", - tooldef_keywords=dict( - operator="gpencil.weight_paint", - ), - ) + # 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 + ) + ) + ] class _defs_grease_pencil_weight: @@ -2766,17 +2822,23 @@ class _defs_curves_sculpt: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="ops.curves.sculpt_", - type=bpy.types.Brush, - attr="curves_sculpt_tool", - icon_map={ - # Use the generic icon for selection painting. - "ops.curves.sculpt_selection_paint": "ops.generic.select_paint", - }, - ) + # 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 + ) + ) + ] class _defs_gpencil_vertex: @@ -2798,17 +2860,23 @@ class _defs_gpencil_vertex: @staticmethod def generate_from_brushes(context): - return generate_from_enum_ex( - context, - idname_prefix="builtin_brush.", - icon_prefix="brush.paint_vertex.", - type=bpy.types.Brush, - attr="gpencil_vertex_tool", - cursor='DOT', - tooldef_keywords=dict( - operator="gpencil.vertex_paint", - ), - ) + # 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: @@ -3500,8 +3568,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): 'PAINT_GREASE_PENCIL': [ _defs_view3d_generic.cursor, None, - _defs_paint_grease_pencil.draw, - _defs_paint_grease_pencil.erase, + _defs_paint_grease_pencil.generate_from_brushes, _defs_paint_grease_pencil.cutter, _defs_paint_grease_pencil.tint, None, diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 765cff43078..b8bdb09e313 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -236,9 +236,10 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.sculpt - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - brush = paint.brush + + BrushAssetShelf.draw_popup_selector(layout, context, brush) + if brush is None: return False @@ -297,9 +298,10 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.image_paint - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - brush = paint.brush + + BrushAssetShelf.draw_popup_selector(layout, context, brush) + if brush is None: return False @@ -313,9 +315,10 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.vertex_paint - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - brush = paint.brush + + BrushAssetShelf.draw_popup_selector(layout, context, brush) + if brush is None: return False @@ -329,8 +332,10 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.weight_paint - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) brush = paint.brush + + BrushAssetShelf.draw_popup_selector(layout, context, brush) + if brush is None: return False @@ -392,7 +397,8 @@ class _draw_tool_settings_context_mode: row = layout.row(align=True) settings = tool_settings.gpencil_paint - row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) + + BrushAssetShelf.draw_popup_selector(layout, context, brush) if ob and brush.gpencil_tool in {'FILL', 'DRAW'}: from bl_ui.properties_paint_common import ( @@ -420,6 +426,8 @@ class _draw_tool_settings_context_mode: paint = tool_settings.gpencil_sculpt_paint brush = paint.brush + BrushAssetShelf.draw_popup_selector(layout, context, brush) + from bl_ui.properties_paint_common import ( brush_basic_gpencil_sculpt_settings, ) @@ -433,12 +441,12 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.gpencil_sculpt_paint - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - brush = paint.brush if brush is None: return False + BrushAssetShelf.draw_popup_selector(layout, context, brush) + tool_settings = context.tool_settings capabilities = brush.sculpt_capabilities @@ -494,7 +502,7 @@ class _draw_tool_settings_context_mode: paint = tool_settings.gpencil_weight_paint brush = paint.brush - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) + BrushAssetShelf.draw_popup_selector(layout, context, brush) brush_basic_gpencil_weight_settings(layout, context, brush, compact=True) @@ -509,12 +517,12 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.gpencil_weight_paint - layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - brush = paint.brush if brush is None: return False + BrushAssetShelf.draw_popup_selector(layout, context, brush) + brush_basic_grease_pencil_weight_settings(layout, context, brush, compact=True) layout.popover("VIEW3D_PT_tools_grease_pencil_weight_options", text="Options") @@ -533,7 +541,8 @@ class _draw_tool_settings_context_mode: row = layout.row(align=True) settings = tool_settings.gpencil_vertex_paint - row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) + + BrushAssetShelf.draw_popup_selector(layout, context, brush) if brush.gpencil_vertex_tool not in {'BLUR', 'AVERAGE', 'SMEAR'}: row.separator(factor=0.4) @@ -686,7 +695,8 @@ class _draw_tool_settings_context_mode: return False row = layout.row(align=True) - row.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) + + BrushAssetShelf.draw_popup_selector(layout, context, brush) grease_pencil_tool = brush.gpencil_tool @@ -3523,23 +3533,6 @@ class VIEW3D_MT_make_links(Menu): layout.operator("object.datalayout_transfer") -class VIEW3D_MT_brush_paint_modes(Menu): - bl_label = "Enabled Modes" - - def draw(self, context): - layout = self.layout - - settings = UnifiedPaintPanel.paint_settings(context) - brush = settings.brush - - layout.prop(brush, "use_paint_sculpt", text="Sculpt") - layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt") - layout.prop(brush, "use_paint_vertex", text="Vertex Paint") - layout.prop(brush, "use_paint_weight", text="Weight Paint") - layout.prop(brush, "use_paint_image", text="Texture Paint") - layout.prop(brush, "use_paint_sculpt_curves", text="Sculpt Curves") - - class VIEW3D_MT_paint_vertex(Menu): bl_label = "Paint" @@ -9087,11 +9080,58 @@ class VIEW3D_PT_viewport_debug(Panel): layout.prop(overlay, "use_debug_freeze_view_culling") -class VIEW3D_AST_sculpt_brushes(BrushAssetShelf, bpy.types.AssetShelf): - # Experimental: Asset shelf for sculpt brushes, only shows up if both the - # "Asset Shelf" and the "Extended Asset Browser" experimental features are - # enabled. - bl_space_type = 'VIEW_3D' +class View3DAssetShelf(BrushAssetShelf): + bl_space_type = "VIEW_3D" + + +class VIEW3D_AST_brush_sculpt(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'SCULPT' + mode_prop = "use_paint_sculpt" + + +class VIEW3D_AST_brush_sculpt_curves(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'SCULPT_CURVES' + mode_prop = "use_paint_sculpt_curves" + + +class VIEW3D_AST_brush_vertex_paint(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'VERTEX_PAINT' + mode_prop = "use_paint_vertex" + + +class VIEW3D_AST_brush_weight_paint(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'WEIGHT_PAINT' + mode_prop = "use_paint_weight" + + +class VIEW3D_AST_brush_texture_paint(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'TEXTURE_PAINT' + mode_prop = "use_paint_image" + + +class VIEW3D_AST_brush_gpencil_paint(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'PAINT_GPENCIL' + mode_prop = "use_paint_grease_pencil" + + +class VIEW3D_AST_brush_grease_pencil_paint(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'PAINT_GREASE_PENCIL' + mode_prop = "use_paint_grease_pencil" + + +class VIEW3D_AST_brush_gpencil_sculpt(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'SCULPT_GPENCIL' + mode_prop = "use_sculpt_grease_pencil" + + +class VIEW3D_AST_brush_gpencil_vertex(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'VERTEX_GPENCIL' + mode_prop = "use_vertex_grease_pencil" + + +class VIEW3D_AST_brush_gpencil_weight(View3DAssetShelf, bpy.types.AssetShelf): + mode = 'WEIGHT_GPENCIL' + mode_prop = "use_weight_grease_pencil" classes = ( @@ -9173,7 +9213,6 @@ classes = ( VIEW3D_MT_object_cleanup, VIEW3D_MT_make_single_user, VIEW3D_MT_make_links, - VIEW3D_MT_brush_paint_modes, VIEW3D_MT_paint_vertex, VIEW3D_MT_hook, VIEW3D_MT_vertex_group, @@ -9359,7 +9398,16 @@ classes = ( VIEW3D_PT_curves_sculpt_parameter_falloff, VIEW3D_PT_curves_sculpt_grow_shrink_scaling, VIEW3D_PT_viewport_debug, - VIEW3D_AST_sculpt_brushes, + VIEW3D_AST_brush_sculpt, + VIEW3D_AST_brush_sculpt_curves, + VIEW3D_AST_brush_vertex_paint, + VIEW3D_AST_brush_weight_paint, + VIEW3D_AST_brush_texture_paint, + VIEW3D_AST_brush_gpencil_paint, + VIEW3D_AST_brush_grease_pencil_paint, + VIEW3D_AST_brush_gpencil_sculpt, + VIEW3D_AST_brush_gpencil_vertex, + VIEW3D_AST_brush_gpencil_weight, ) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index e919341d385..e4b02fd7eb9 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -28,6 +28,7 @@ from bl_ui.properties_paint_common import ( brush_settings, brush_settings_advanced, draw_color_settings, + BrushAssetShelf, ) from bl_ui.utils import PresetPanel @@ -43,25 +44,22 @@ class VIEW3D_MT_brush_context_menu(Menu): # skip if no active brush if not brush: - layout.label(text="No Brushes currently available", icon='INFO') + layout.label(text="No brush selected", icon='INFO') return - # brush paint modes - layout.menu("VIEW3D_MT_brush_paint_modes") + if brush.is_asset_library_data: + layout.operator("brush.asset_save_as", text="Duplicate Asset...", icon='DUPLICATE') + layout.operator("brush.asset_delete", text="Delete Asset") - # brush tool + layout.separator() - if context.image_paint_object: - layout.prop_menu_enum(brush, "image_tool") - elif context.vertex_paint_object: - layout.prop_menu_enum(brush, "vertex_tool") - elif context.weight_paint_object: - layout.prop_menu_enum(brush, "weight_tool") - elif context.sculpt_object: - layout.prop_menu_enum(brush, "sculpt_tool") - layout.operator("brush.reset") - elif context.tool_settings.curves_sculpt: - layout.prop_menu_enum(brush, "curves_sculpt_tool") + layout.operator("brush.asset_edit_metadata", text="Edit Metadata") + layout.operator("brush.asset_load_preview", text="Edit Preview Image...") + layout.operator("brush.asset_update", text="Update Asset") + layout.operator("brush.asset_revert", text="Revert to Asset") + else: + layout.operator("brush.asset_save_as", text="Save As Asset...", icon='FILE_TICK') + layout.operator("brush.asset_delete", text="Delete") class VIEW3D_MT_brush_gpencil_context_menu(Menu): @@ -87,9 +85,6 @@ class VIEW3D_MT_brush_gpencil_context_menu(Menu): layout.label(text="No Brushes currently available", icon='INFO') return - layout.operator("gpencil.brush_reset") - layout.operator("gpencil.brush_reset_all") - class View3DPanel: bl_space_type = 'VIEW_3D' @@ -359,7 +354,7 @@ class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel): # TODO, move to space_view3d.py class VIEW3D_PT_tools_brush_select(Panel, View3DPaintBrushPanel, BrushSelectPanel): bl_context = ".paint_common" - bl_label = "Brushes" + bl_label = "Brush Asset" # TODO, move to space_view3d.py @@ -1603,30 +1598,8 @@ class GreasePencilPaintPanel: return True -class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePencilPaintPanel): - bl_label = "Brushes" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - tool_settings = context.scene.tool_settings - gpencil_paint = tool_settings.gpencil_paint - - row = layout.row() - row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8) - - col = row.column() - col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="") - - if context.mode == 'PAINT_GPENCIL': - brush = tool_settings.gpencil_paint.brush - if brush is not None: - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") - - if brush.use_custom_icon: - layout.row().prop(brush, "icon_filepath", text="") +class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePencilPaintPanel, BrushSelectPanel): + bl_label = "Brush Asset" class VIEW3D_PT_tools_grease_pencil_brush_settings(Panel, View3DPanel, GreasePencilPaintPanel): @@ -2014,30 +1987,8 @@ class GreasePencilSculptPanel: return True -class VIEW3D_PT_tools_grease_pencil_sculpt_select(Panel, View3DPanel, GreasePencilSculptPanel): - bl_label = "Brushes" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - tool_settings = context.scene.tool_settings - gpencil_paint = tool_settings.gpencil_sculpt_paint - - row = layout.row() - row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8) - - col = row.column() - col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="") - - if context.mode == 'SCULPT_GPENCIL': - brush = tool_settings.gpencil_sculpt_paint.brush - if brush is not None: - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") - - if (brush.use_custom_icon): - layout.row().prop(brush, "icon_filepath", text="") +class VIEW3D_PT_tools_grease_pencil_sculpt_select(Panel, View3DPanel, GreasePencilSculptPanel, BrushSelectPanel): + bl_label = "Brush Asset" class VIEW3D_PT_tools_grease_pencil_sculpt_settings(Panel, View3DPanel, GreasePencilSculptPanel): @@ -2126,30 +2077,8 @@ class GreasePencilWeightPanel: return True -class VIEW3D_PT_tools_grease_pencil_weight_paint_select(View3DPanel, Panel, GreasePencilWeightPanel): - bl_label = "Brushes" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - tool_settings = context.scene.tool_settings - gpencil_paint = tool_settings.gpencil_weight_paint - - row = layout.row() - row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8) - - col = row.column() - col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="") - - if context.mode in {'WEIGHT_GPENCIL', 'WEIGHT_GREASE_PENCIL'}: - brush = tool_settings.gpencil_weight_paint.brush - if brush is not None: - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") - - if (brush.use_custom_icon): - layout.row().prop(brush, "icon_filepath", text="") +class VIEW3D_PT_tools_grease_pencil_weight_paint_select(View3DPanel, Panel, GreasePencilWeightPanel, BrushSelectPanel): + bl_label = "Brush Asset" class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, GreasePencilWeightPanel): @@ -2225,30 +2154,8 @@ class GreasePencilVertexPanel: return True -class VIEW3D_PT_tools_grease_pencil_vertex_paint_select(View3DPanel, Panel, GreasePencilVertexPanel): - bl_label = "Brushes" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - tool_settings = context.scene.tool_settings - gpencil_paint = tool_settings.gpencil_vertex_paint - - row = layout.row() - row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8) - - col = row.column() - col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="") - - if context.mode == 'VERTEX_GPENCIL': - brush = tool_settings.gpencil_vertex_paint.brush - if brush is not None: - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") - - if (brush.use_custom_icon): - layout.row().prop(brush, "icon_filepath", text="") +class VIEW3D_PT_tools_grease_pencil_vertex_paint_select(View3DPanel, Panel, GreasePencilVertexPanel, BrushSelectPanel): + bl_label = "Brush Asset" class VIEW3D_PT_tools_grease_pencil_vertex_paint_settings(Panel, View3DPanel, GreasePencilVertexPanel): @@ -2520,29 +2427,8 @@ class GreasePencilV3PaintPanel: return True -class VIEW3D_PT_tools_grease_pencil_v3_brush_select(Panel, View3DPanel, GreasePencilV3PaintPanel): - bl_label = "Brushes" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - tool_settings = context.scene.tool_settings - gpencil_paint = tool_settings.gpencil_paint - - row = layout.row() - row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8) - - col = row.column() - col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="") - - brush = tool_settings.gpencil_paint.brush - if brush is not None: - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") - - if brush.use_custom_icon: - layout.row().prop(brush, "icon_filepath", text="") +class VIEW3D_PT_tools_grease_pencil_v3_brush_select(Panel, View3DPanel, GreasePencilV3PaintPanel, BrushSelectPanel): + bl_label = "Brush Asset" class VIEW3D_PT_tools_grease_pencil_v3_brush_settings(Panel, View3DPanel, GreasePencilV3PaintPanel): diff --git a/source/blender/blenkernel/BKE_asset_edit.hh b/source/blender/blenkernel/BKE_asset_edit.hh new file mode 100644 index 00000000000..113f1407015 --- /dev/null +++ b/source/blender/blenkernel/BKE_asset_edit.hh @@ -0,0 +1,69 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + */ + +#pragma once + +/** + * Editing of datablocks from asset libraries, separate from the current open + * blend file. + * + * Each asset blend file is loaded into a separate main database, including the + * asset datablocks and their dependencies. These datablocks are all tagged with + * LIB_TAG_ASSET_EDIT_MAIN. These can not be linked with other datablocks in the + * current blend file. + * + * For editable assets in user asset libraries, each asset is stored in its own + * blend file. This way the blend file can be easily saved, reloaded and deleted. + * + * This mechanism is currently only used for brush assets. + */ + +#include +#include + +#include "BLI_string_ref.hh" + +#include "AS_asset_catalog.hh" + +#include "DNA_ID_enums.h" + +struct bUserAssetLibrary; +struct AssetMetaData; +struct AssetWeakReference; +struct ID; +struct Main; +struct ReportList; + +namespace blender::bke { + +/** Get datablock from weak reference, loading the blend file as needed. */ +ID *asset_edit_id_from_weak_reference(Main &global_main, + ID_Type id_type, + const AssetWeakReference &weak_ref); + +/** Get main database that a given asset datablock corresponds to. */ +Main *asset_edit_main(const ID &id); + +/** Asset editing operations. */ + +bool asset_edit_id_is_editable(const ID &id); + +std::optional asset_edit_id_save_as(Main &global_main, + const ID &id, + StringRef name, + const bUserAssetLibrary &user_library, + ReportList &reports); + +bool asset_edit_id_save(Main &global_main, const ID &id, ReportList &reports); +bool asset_edit_id_revert(Main &global_main, const ID &id, ReportList &reports); +bool asset_edit_id_delete(Main &global_main, const ID &id, ReportList &reports); + +/** Clean up on exit. */ +void asset_edit_main_free_all(); + +} // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index cf00cbc74ef..5f8b4884718 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -29,7 +29,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 29 +#define BLENDER_FILE_SUBVERSION 30 /* 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 diff --git a/source/blender/blenkernel/BKE_blendfile.hh b/source/blender/blenkernel/BKE_blendfile.hh index 5f2205f883f..a5cf1be5f93 100644 --- a/source/blender/blenkernel/BKE_blendfile.hh +++ b/source/blender/blenkernel/BKE_blendfile.hh @@ -19,6 +19,11 @@ struct ReportList; struct UserDef; struct WorkspaceConfigFileData; +/** + * The suffix used for blendfiles managed by the asset system. + */ +#define BLENDER_ASSET_FILE_SUFFIX ".asset.blend" + /** * Check whether given path ends with a blend file compatible extension * (`.blend`, `.ble` or `.blend.gz`). diff --git a/source/blender/blenkernel/BKE_brush.hh b/source/blender/blenkernel/BKE_brush.hh index 83630a52b14..e0e4289c670 100644 --- a/source/blender/blenkernel/BKE_brush.hh +++ b/source/blender/blenkernel/BKE_brush.hh @@ -38,10 +38,6 @@ void BKE_brush_system_exit(); * another is assumed to be used by the caller. */ Brush *BKE_brush_add(Main *bmain, const char *name, eObjectMode ob_mode); -/** - * Add a new gp-brush. - */ -Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode); /** * Delete a Brush. */ @@ -57,24 +53,6 @@ Brush *BKE_brush_first_search(Main *bmain, eObjectMode ob_mode); void BKE_brush_sculpt_reset(Brush *brush); -/** - * Create a set of grease pencil Drawing presets. - */ -void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, bool reset); -/** - * Create a set of grease pencil Vertex Paint presets. - */ -void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, bool reset); -/** - * Create a set of grease pencil Sculpt Paint presets. - */ -void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, bool reset); -/** - * Create a set of grease pencil Weight Paint presets. - */ -void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, bool reset); -void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, short type); - void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], @@ -185,16 +163,5 @@ void BKE_brush_scale_size(int *r_brush_size, */ bool BKE_brush_has_cube_tip(const Brush *brush, PaintMode paint_mode); -/* Accessors */ -#define BKE_brush_tool_get(brush, p) \ - (CHECK_TYPE_ANY(brush, Brush *, const Brush *), \ - *(const char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset)) -#define BKE_brush_tool_set(brush, p, tool) \ - { \ - CHECK_TYPE_ANY(brush, Brush *); \ - *(char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset) = tool; \ - } \ - ((void)0) - /* debugging only */ void BKE_brush_debug_print_state(Brush *br); diff --git a/source/blender/blenkernel/BKE_context.hh b/source/blender/blenkernel/BKE_context.hh index ebd8a137881..d868ba3f146 100644 --- a/source/blender/blenkernel/BKE_context.hh +++ b/source/blender/blenkernel/BKE_context.hh @@ -347,6 +347,7 @@ int ctx_data_list_count(const bContext *C, /* Data Context Members */ Main *CTX_data_main(const bContext *C); +Main *CTX_data_main_from_id(const bContext *C, const ID *id); Scene *CTX_data_scene(const bContext *C); /** * This is tricky. Sometimes the user overrides the render_layer diff --git a/source/blender/blenkernel/BKE_lib_id.hh b/source/blender/blenkernel/BKE_lib_id.hh index 36d83c8bb23..6f1c0bbd712 100644 --- a/source/blender/blenkernel/BKE_lib_id.hh +++ b/source/blender/blenkernel/BKE_lib_id.hh @@ -205,6 +205,8 @@ enum { * duplicate scene/collections, or objects. */ LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING = 1 << 28, + /* Copy asset metadata. */ + LIB_ID_COPY_ASSET_METADATA = 1 << 29, /* *** Helper 'defines' gathering most common flag sets. *** */ /** Shape-keys are not real ID's, more like local data to geometry IDs. */ @@ -708,12 +710,6 @@ void BKE_library_make_local( void BKE_id_tag_set_atomic(ID *id, int tag); void BKE_id_tag_clear_atomic(ID *id, int tag); -/** - * Check that given ID pointer actually is in G_MAIN. - * Main intended use is for debug asserts in places we cannot easily get rid of #G_Main. - */ -bool BKE_id_is_in_global_main(ID *id); - bool BKE_id_can_be_asset(const ID *id); /** diff --git a/source/blender/blenkernel/BKE_main.hh b/source/blender/blenkernel/BKE_main.hh index e83867a3d6d..b977ed7a3d4 100644 --- a/source/blender/blenkernel/BKE_main.hh +++ b/source/blender/blenkernel/BKE_main.hh @@ -143,6 +143,14 @@ struct Main { * could try to use more refined detection on load. */ bool has_forward_compatibility_issues; + /** + * The currently opened .blend file was created as an asset library storage. + * + * This is used to warn the user when they try to save it from Blender UI, since this will likely + * break the automatic management from the asset library system. + */ + bool is_asset_repository; + /** Commit timestamp from `buildinfo`. */ uint64_t build_commit_timestamp; /** Commit Hash from `buildinfo`. */ @@ -183,6 +191,11 @@ struct Main { */ bool is_global_main; + /** + * True if main used to store weakly referenced assets. + */ + bool is_asset_edit_main; + BlendThumbnail *blen_thumb; Library *curlib; @@ -301,6 +314,17 @@ void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &report */ bool BKE_main_is_empty(Main *bmain); +/** + * Check whether the bmain has issues, e.g. for reporting in the status bar. + */ +bool BKE_main_has_issues(const Main *bmain); + +/** + * Check whether user confirmation should be required when overwriting this `bmain` into its source + * blendfile. + */ +bool BKE_main_needs_overwrite_confirm(const Main *bmain); + void BKE_main_lock(Main *bmain); void BKE_main_unlock(Main *bmain); @@ -489,6 +513,20 @@ ListBase *which_libbase(Main *bmain, short type); */ int set_listbasepointers(Main *main, ListBase *lb[]); +/** + * Return main database this ID is a member of. + * + * This works for the global main database and asset edit databases. + * So only datablocks that are directly editable in the user interface. + * + * Use this in operator and draw code instead of assuming the main + * in the context owns datablocks. + * + * Optionally can verify that this datablock is one of these databases. + * This is slow and mainly meant for asserts. + */ +Main *BKE_main_from_id(Main *global_main, const ID *id, bool verify = false); + #define MAIN_VERSION_FILE_ATLEAST(main, ver, subver) \ ((main)->versionfile > (ver) || \ ((main)->versionfile == (ver) && (main)->subversionfile >= (subver))) diff --git a/source/blender/blenkernel/BKE_node.hh b/source/blender/blenkernel/BKE_node.hh index 609ef7a7093..a9424067fe7 100644 --- a/source/blender/blenkernel/BKE_node.hh +++ b/source/blender/blenkernel/BKE_node.hh @@ -402,7 +402,7 @@ struct bNodeTreeType { /* callbacks */ /* Iteration over all node classes. */ - void (*foreach_nodeclass)(Scene *scene, void *calldata, bNodeClassCallback func); + void (*foreach_nodeclass)(void *calldata, bNodeClassCallback func); /* Check visibility in the node editor */ bool (*poll)(const bContext *C, bNodeTreeType *ntreetype); /* Select a node tree from the context */ diff --git a/source/blender/blenkernel/BKE_paint.hh b/source/blender/blenkernel/BKE_paint.hh index 8499fc1ef22..82b188c3afa 100644 --- a/source/blender/blenkernel/BKE_paint.hh +++ b/source/blender/blenkernel/BKE_paint.hh @@ -8,6 +8,8 @@ * \ingroup bke */ +#include + #include "BLI_array.hh" #include "BLI_bit_vector.hh" #include "BLI_math_matrix_types.hh" @@ -23,6 +25,7 @@ #include "BKE_pbvh.hh" +struct AssetWeakReference; struct BMFace; struct BMLog; struct BMesh; @@ -183,24 +186,42 @@ void BKE_paint_free(Paint *p); */ void BKE_paint_copy(const Paint *src, Paint *tar, int flag); -void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint); - void BKE_paint_cavity_curve_preset(Paint *p, int preset); eObjectMode BKE_paint_object_mode_from_paintmode(PaintMode mode); bool BKE_paint_ensure_from_paintmode(Main *bmain, Scene *sce, PaintMode mode); Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode); const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(PaintMode mode); -const char *BKE_paint_get_tool_enum_translation_context_from_paintmode(PaintMode mode); -const char *BKE_paint_get_tool_prop_id_from_paintmode(PaintMode mode); uint BKE_paint_get_brush_tool_offset_from_paintmode(PaintMode mode); Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer); Paint *BKE_paint_get_active_from_context(const bContext *C); PaintMode BKE_paintmode_get_active_from_context(const bContext *C); PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref); + +/* Paint brush retrieval and assignment. */ + Brush *BKE_paint_brush(Paint *paint); -const Brush *BKE_paint_brush_for_read(const Paint *p); -void BKE_paint_brush_set(Paint *paint, Brush *br); +const Brush *BKE_paint_brush_for_read(const Paint *paint); +Brush *BKE_paint_brush_from_essentials(Main *bmain, const char *name); + +bool BKE_paint_brush_set(Paint *paint, Brush *brush); +bool BKE_paint_brush_set_default(Main *bmain, Paint *paint); +bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name); + +void BKE_paint_brush_set_default_references(ToolSettings *ts); + +void BKE_paint_brush_validate(Main *bmain, Paint *paint); + +/** + * Set the active brush of given paint struct, and store the weak asset reference to it. + * \note Takes ownership of the given `weak_asset_reference`. + */ +bool BKE_paint_brush_asset_set(Paint *paint, + Brush *brush, + const AssetWeakReference &weak_asset_reference); + +/* Paint palette. */ + Palette *BKE_paint_palette(Paint *paint); void BKE_paint_palette_set(Paint *p, Palette *palette); void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, int add_index); @@ -253,19 +274,6 @@ void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, f void BKE_paint_stroke_get_average(const Scene *scene, const Object *ob, float stroke[3]); -/* Tool slot API. */ - -void BKE_paint_toolslots_init_from_main(Main *bmain); -void BKE_paint_toolslots_len_ensure(Paint *paint, int len); -void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush); -void BKE_paint_toolslots_brush_update(Paint *paint); -/** - * Run this to ensure brush types are set for each slot on entering modes - * (for new scenes for example). - */ -void BKE_paint_brush_validate(Main *bmain, Paint *paint); -Brush *BKE_paint_toolslots_brush_get(Paint *paint, int slot_index); - /* .blend I/O */ void BKE_paint_blend_write(BlendWriter *writer, Paint *paint); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1b019bfee03..9ca3329f011 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -66,6 +66,7 @@ set(SRC intern/armature_update.cc intern/asset.cc intern/asset_weak_reference.cc + intern/asset_edit.cc intern/attribute.cc intern/attribute_access.cc intern/attribute_math.cc @@ -254,7 +255,6 @@ set(SRC intern/packedFile.cc intern/paint.cc intern/paint_canvas.cc - intern/paint_toolslots.cc intern/particle.cc intern/particle_child.cc intern/particle_distribute.cc @@ -335,6 +335,7 @@ set(SRC BKE_appdir.hh BKE_armature.hh BKE_asset.hh + BKE_asset_edit.hh BKE_attribute.h BKE_attribute.hh BKE_attribute_math.hh diff --git a/source/blender/blenkernel/intern/asset_edit.cc b/source/blender/blenkernel/intern/asset_edit.cc new file mode 100644 index 00000000000..ce5f305fa37 --- /dev/null +++ b/source/blender/blenkernel/intern/asset_edit.cc @@ -0,0 +1,531 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + */ + +#include +#include + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_vector.hh" + +#include "DNA_space_types.h" + +#include "AS_asset_identifier.hh" +#include "AS_asset_library.hh" + +#include "BKE_asset.hh" +#include "BKE_asset_edit.hh" +#include "BKE_blendfile.hh" +#include "BKE_blendfile_link_append.hh" +#include "BKE_global.hh" +#include "BKE_idtype.hh" +#include "BKE_lib_id.hh" +#include "BKE_lib_remap.hh" +#include "BKE_library.hh" +#include "BKE_main.hh" +#include "BKE_packedFile.h" +#include "BKE_preferences.h" +#include "BKE_report.hh" + +#include "BLO_read_write.hh" +#include "BLO_readfile.hh" +#include "BLO_writefile.hh" + +#include "DNA_asset_types.h" + +#include "MEM_guardedalloc.h" + +namespace blender::bke { + +/** + * Asset library blend file, with editable contents. + */ +struct AssetEditBlend { + std::string filepath; + Main *main; + bool is_editable = false; + + AssetEditBlend(const std::string &filepath); + ~AssetEditBlend(); + + AssetEditBlend(const AssetEditBlend &) = delete; + AssetEditBlend(AssetEditBlend &&other); + AssetEditBlend &operator=(AssetEditBlend &&other); + + ID *ensure_id(ID_Type id_type, const char *asset_name); + void reload(Main &global_main); + void clear_users(Main &global_main); +}; + +AssetEditBlend::AssetEditBlend(const std::string &filepath) + : filepath(std::move(filepath)), main(BKE_main_new()) +{ + this->main->is_asset_edit_main = true; + BLI_assert(!BLI_path_is_rel(filepath.c_str())); + + /* Simple check, based on being a writable .asset.blend file in a user asset library. */ + this->is_editable = StringRef(filepath).endswith(BLENDER_ASSET_FILE_SUFFIX) && + BKE_preferences_asset_library_containing_path(&U, filepath.c_str()) && + BLI_file_is_writable(filepath.c_str()); +} + +AssetEditBlend::~AssetEditBlend() +{ + if (main) { + BKE_main_free(main); + } +} + +AssetEditBlend::AssetEditBlend(AssetEditBlend &&other) + : filepath(std::exchange(other.filepath, "")), main(std::exchange(other.main, nullptr)) +{ +} +AssetEditBlend &AssetEditBlend::operator=(AssetEditBlend &&other) +{ + if (this == &other) { + return *this; + } + this->filepath = std::exchange(other.filepath, ""); + this->main = std::exchange(other.main, nullptr); + return *this; +} + +ID *AssetEditBlend::ensure_id(const ID_Type id_type, const char *asset_name) +{ + /* Check if we have the asset already. */ + ID *local_asset = BKE_libblock_find_name(this->main, id_type, asset_name); + if (local_asset) { + BLI_assert(ID_IS_ASSET(local_asset)); + return local_asset; + } + + /* Load asset from asset library. */ + LibraryLink_Params lapp_params{}; + lapp_params.bmain = this->main; + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_flag_set(lapp_context, BLO_LIBLINK_FORCE_INDIRECT, true); + BKE_blendfile_link_append_context_flag_set(lapp_context, 0, true); + + BKE_blendfile_link_append_context_library_add(lapp_context, filepath.c_str(), nullptr); + + BlendfileLinkAppendContextItem *lapp_item = BKE_blendfile_link_append_context_item_add( + lapp_context, asset_name, id_type, nullptr); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0); + + BKE_blendfile_link(lapp_context, nullptr); + BKE_blendfile_append(lapp_context, nullptr); + + local_asset = BKE_blendfile_link_append_context_item_newid_get(lapp_context, lapp_item); + + BKE_blendfile_link_append_context_free(lapp_context); + + BKE_main_id_tag_all(this->main, LIB_TAG_ASSET_EDIT_MAIN, true); + + /* Verify that the name matches. It must for referencing the same asset again to work. */ + BLI_assert(local_asset == nullptr || STREQ(local_asset->name + 2, asset_name)); + + return local_asset; +} + +static std::string asset_root_path_for_save(const bUserAssetLibrary &user_library, + const ID_Type id_type) +{ + BLI_assert(user_library.dirpath[0] != '\0'); + + char libpath[FILE_MAX]; + BLI_strncpy(libpath, user_library.dirpath, sizeof(libpath)); + BLI_path_slash_native(libpath); + BLI_path_normalize(libpath); + + /* Capitalize folder name. Ideally this would already available in + * the type info to work correctly with multiple words. */ + const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_idcode(id_type); + std::string name = id_type_info->name_plural; + name[0] = BLI_toupper_ascii(name[0]); + + return std::string(libpath) + SEP + "Saved" + SEP + name; +} + +static std::string asset_blendfile_path_for_save(const bUserAssetLibrary &user_library, + const StringRef base_name, + const ID_Type id_type, + ReportList &reports) +{ + std::string root_path = asset_root_path_for_save(user_library, id_type); + BLI_assert(!root_path.empty()); + + if (!BLI_dir_create_recursive(root_path.c_str())) { + BKE_report(&reports, RPT_ERROR, "Failed to create asset library directory to save asset"); + return ""; + } + + /* Make sure filename only contains valid characters for filesystem. */ + char base_name_filesafe[FILE_MAXFILE]; + BLI_strncpy(base_name_filesafe, + base_name.data(), + std::min(sizeof(base_name_filesafe), size_t(base_name.size() + 1))); + BLI_path_make_safe_filename(base_name_filesafe); + + const std::string filepath = root_path + SEP + base_name_filesafe + BLENDER_ASSET_FILE_SUFFIX; + + if (!BLI_is_file(filepath.c_str())) { + return filepath; + } + + /* Avoid overwriting existing file by adding number suffix. */ + for (int i = 1;; i++) { + const std::string filepath = root_path + SEP + base_name_filesafe + "_" + std::to_string(i++) + + BLENDER_ASSET_FILE_SUFFIX; + if (!BLI_is_file((filepath.c_str()))) { + return filepath; + } + } + + return ""; +} + +static void asset_main_create_expander(void * /*handle*/, Main * /*bmain*/, void *vid) +{ + ID *id = static_cast(vid); + + if (id && (id->tag & LIB_TAG_DOIT) == 0) { + id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT; + } +} + +static Main *asset_main_create_from_ID(Main *bmain_src, ID &id_asset, ID **id_asset_new) +{ + /* Tag asset ID and its dependencies. */ + ID *id_src; + FOREACH_MAIN_ID_BEGIN (bmain_src, id_src) { + id_src->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT); + } + FOREACH_MAIN_ID_END; + + id_asset.tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT; + + BLO_main_expander(asset_main_create_expander); + BLO_expand_main(nullptr, bmain_src); + + /* Create main and copy all tagged datablocks. */ + Main *bmain_dst = BKE_main_new(); + STRNCPY(bmain_dst->filepath, bmain_src->filepath); + + blender::bke::id::IDRemapper id_remapper; + + FOREACH_MAIN_ID_BEGIN (bmain_src, id_src) { + if (id_src->tag & LIB_TAG_DOIT) { + /* Note that this will not copy Library datablocks, and all copied + * datablocks will become local as a result. */ + ID *id_dst = BKE_id_copy_ex(bmain_dst, + id_src, + nullptr, + LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_DEG_TAG | + ((id_src == &id_asset) ? LIB_ID_COPY_ASSET_METADATA : 0)); + id_remapper.add(id_src, id_dst); + if (id_src == &id_asset) { + *id_asset_new = id_dst; + } + } + else { + id_remapper.add(id_src, nullptr); + } + + id_src->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT); + } + FOREACH_MAIN_ID_END; + + /* Remap datablock pointers. */ + BKE_libblock_remap_multiple_raw(bmain_dst, id_remapper, ID_REMAP_SKIP_USER_CLEAR); + + /* Compute reference counts. */ + ID *id_dst; + FOREACH_MAIN_ID_BEGIN (bmain_dst, id_dst) { + id_dst->tag &= ~LIB_TAG_NO_USER_REFCOUNT; + } + FOREACH_MAIN_ID_END; + BKE_main_id_refcount_recompute(bmain_dst, false); + + return bmain_dst; +} + +static bool asset_write_in_library(Main *bmain, + const ID &id_const, + const StringRef name, + const StringRefNull filepath, + std::string &final_full_file_path, + ReportList &reports) +{ + ID &id = const_cast(id_const); + + ID *new_id = nullptr; + Main *new_main = asset_main_create_from_ID(bmain, id, &new_id); + + std::string new_name = name; + BKE_libblock_rename(new_main, new_id, new_name.c_str()); + id_fake_user_set(new_id); + + BlendFileWriteParams blend_file_write_params{}; + blend_file_write_params.remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE; + + BKE_packedfile_pack_all(new_main, nullptr, false); + + const int write_flags = G_FILE_COMPRESS; + const bool success = BLO_write_file( + new_main, filepath.c_str(), write_flags, &blend_file_write_params, &reports); + + if (success) { + const IDTypeInfo *idtype = BKE_idtype_get_info_from_id(&id); + final_full_file_path = std::string(filepath) + SEP + std::string(idtype->name) + SEP + name; + } + + BKE_main_free(new_main); + + return success; +} + +void AssetEditBlend::reload(Main &global_main) +{ + Main *old_main = this->main; + this->main = BKE_main_new(); + this->main->is_asset_edit_main = true; + + /* Fill fresh main database with same datablock as before. */ + LibraryLink_Params lapp_params{}; + lapp_params.bmain = this->main; + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_flag_set(lapp_context, BLO_LIBLINK_FORCE_INDIRECT, true); + BKE_blendfile_link_append_context_flag_set(lapp_context, 0, true); + + BKE_blendfile_link_append_context_library_add(lapp_context, this->filepath.c_str(), nullptr); + + /* Requests all existing datablocks to be appended again. */ + ID *old_id; + FOREACH_MAIN_ID_BEGIN (old_main, old_id) { + ID_Type old_id_code = GS(old_id->name); + if (BKE_idtype_idcode_is_linkable(old_id_code)) { + BlendfileLinkAppendContextItem *lapp_item = BKE_blendfile_link_append_context_item_add( + lapp_context, old_id->name + 2, old_id_code, nullptr); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0); + } + } + FOREACH_MAIN_ID_END; + + BKE_blendfile_link(lapp_context, nullptr); + BKE_blendfile_append(lapp_context, nullptr); + + BKE_blendfile_link_append_context_free(lapp_context); + + BKE_main_id_tag_all(this->main, LIB_TAG_ASSET_EDIT_MAIN, true); + + /* Remap old to new. */ + bke::id::IDRemapper mappings; + FOREACH_MAIN_ID_BEGIN (old_main, old_id) { + ID *new_id = BKE_libblock_find_name(this->main, GS(old_id->name), old_id->name + 2); + mappings.add(old_id, new_id); + } + FOREACH_MAIN_ID_END; + BKE_libblock_remap_multiple(&global_main, mappings, 0); + + /* Free old database. */ + BKE_main_free(old_main); +} + +void AssetEditBlend::clear_users(Main &global_main) +{ + /* Remap old to null pointer. */ + bke::id::IDRemapper mappings; + ID *old_id; + FOREACH_MAIN_ID_BEGIN (this->main, old_id) { + mappings.add(old_id, nullptr); + } + FOREACH_MAIN_ID_END; + BKE_libblock_remap_multiple(&global_main, mappings, 0); +} + +/** + * Public API + */ + +static Vector &asset_edit_blend_get_all() +{ + static Vector mains; + return mains; +} + +static AssetEditBlend *asset_edit_blend_from_id(const ID &id) +{ + BLI_assert(id.tag & LIB_TAG_ASSET_EDIT_MAIN); + + /* TODO: It would be good to make this more efficient, though it's unlikely to be a bottleneck + * for brush assets. It's not easy to add a hash map here because it needs to be kept up to date + * as the main database is edited, which can be done in many places. So this would require hooks + * quite deep in ID management. */ + for (AssetEditBlend &asset_blend : asset_edit_blend_get_all()) { + ListBase *lb = which_libbase(asset_blend.main, GS(id.name)); + LISTBASE_FOREACH (ID *, other_id, lb) { + if (&id == other_id) { + return &asset_blend; + } + } + } + + BLI_assert_unreachable(); + return nullptr; +} + +Main *asset_edit_main(const ID &id) +{ + const AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); + return (asset_blend) ? asset_blend->main : nullptr; +} + +static AssetEditBlend &asset_edit_blend_file_ensure(const StringRef filepath) +{ + for (AssetEditBlend &asset_blend : asset_edit_blend_get_all()) { + if (asset_blend.filepath == filepath) { + return asset_blend; + } + } + + asset_edit_blend_get_all().append_as(filepath); + return asset_edit_blend_get_all().last(); +} + +std::optional asset_edit_id_save_as(Main &global_main, + const ID &id, + const StringRef name, + const bUserAssetLibrary &user_library, + ReportList &reports) +{ + const std::string filepath = asset_blendfile_path_for_save( + user_library, name, GS(id.name), reports); + + /* Save to asset library. */ + Main *asset_main = BKE_main_from_id(&global_main, &id); + + std::string final_full_asset_filepath; + const bool success = asset_write_in_library( + asset_main, id, name, filepath, final_full_asset_filepath, reports); + if (!success) { + BKE_report(&reports, RPT_ERROR, "Failed to write to asset library"); + return std::nullopt; + } + + BKE_reportf(&reports, RPT_INFO, "Saved \"%s\"", filepath.c_str()); + + return final_full_asset_filepath; +} + +bool asset_edit_id_save(Main & /*global_main*/, const ID &id, ReportList &reports) +{ + AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); + if (asset_blend == nullptr) { + return false; + } + + std::string final_full_asset_filepath; + const bool success = asset_write_in_library(asset_blend->main, + id, + id.name + 2, + asset_blend->filepath.c_str(), + final_full_asset_filepath, + reports); + + if (!success) { + BKE_report(&reports, RPT_ERROR, "Failed to write to asset library"); + return false; + } + + return true; +} + +bool asset_edit_id_revert(Main &global_main, const ID &id, ReportList & /*reports*/) +{ + AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); + if (asset_blend == nullptr) { + return false; + } + + /* Reload entire main, including texture dependencies. This relies on there + * being only a single asset per blend file. */ + asset_blend->reload(global_main); + + return true; +} + +bool asset_edit_id_delete(Main &global_main, const ID &id, ReportList &reports) +{ + AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); + if (asset_blend == nullptr) { + return false; + } + + if (BLI_delete(asset_blend->filepath.c_str(), false, false) != 0) { + BKE_report(&reports, RPT_ERROR, "Failed to delete asset library file"); + return false; + } + + asset_blend->clear_users(global_main); + + int index = 0; + for (AssetEditBlend &asset_blend_iter : asset_edit_blend_get_all()) { + if (&asset_blend_iter == asset_blend) { + asset_edit_blend_get_all().remove(index); + break; + } + index++; + } + + return true; +} + +ID *asset_edit_id_from_weak_reference(Main &global_main, + const ID_Type id_type, + const AssetWeakReference &weak_ref) +{ + char asset_full_path_buffer[FILE_MAX_LIBEXTRA]; + char *asset_lib_path, *asset_group, *asset_name; + + AS_asset_full_path_explode_from_weak_ref( + &weak_ref, asset_full_path_buffer, &asset_lib_path, &asset_group, &asset_name); + if (asset_lib_path == nullptr && asset_group == nullptr && asset_name == nullptr) { + return nullptr; + } + + BLI_assert(asset_name != nullptr); + + /* Find asset in current blend file. */ + if (asset_lib_path == nullptr) { + ID *local_asset = BKE_libblock_find_name(&global_main, id_type, asset_name); + BLI_assert(local_asset == nullptr || ID_IS_ASSET(local_asset)); + return local_asset; + } + + /* If weak reference resolves to a null library path, assume we are in local asset case. */ + AssetEditBlend &asset_blend = asset_edit_blend_file_ensure(asset_lib_path); + return asset_blend.ensure_id(id_type, asset_name); +} + +bool asset_edit_id_is_editable(const ID &id) +{ + if (!(id.tag & LIB_TAG_ASSET_EDIT_MAIN)) { + return false; + } + + const AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); + return (asset_blend) ? asset_blend->is_editable : false; +} + +void asset_edit_main_free_all() +{ + asset_edit_blend_get_all().clear_and_shrink(); +} + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/blender.cc b/source/blender/blenkernel/intern/blender.cc index 21e554ae367..70eaadb689e 100644 --- a/source/blender/blenkernel/intern/blender.cc +++ b/source/blender/blenkernel/intern/blender.cc @@ -23,6 +23,7 @@ #include "BKE_addon.h" #include "BKE_asset.hh" +#include "BKE_asset_edit.hh" #include "BKE_blender.hh" /* own include */ #include "BKE_blender_user_menu.hh" /* own include */ #include "BKE_blender_version.h" /* own include */ @@ -60,6 +61,11 @@ void BKE_blender_free() BKE_blender_globals_clear(); + /* Free separate data-bases after #BKE_blender_globals_clear in case any data-blocks in the + * global main use pointers to asset main data-blocks when they're freed. That generally + * shouldn't happen but it's better to be safe. */ + blender::bke::asset_edit_main_free_all(); + if (G.log.file != nullptr) { fclose(static_cast(G.log.file)); } diff --git a/source/blender/blenkernel/intern/blendfile.cc b/source/blender/blenkernel/intern/blendfile.cc index 49d09149266..e6f479580bc 100644 --- a/source/blender/blenkernel/intern/blendfile.cc +++ b/source/blender/blenkernel/intern/blendfile.cc @@ -675,6 +675,9 @@ static void setup_app_data(bContext *C, * (but may have a null `curscreen`). */ else if (ELEM(nullptr, bfd->curscreen, bfd->curscene)) { BKE_report(reports->reports, RPT_WARNING, "Library file, loading empty scene"); + if (blender::StringRefNull(bfd->main->filepath).endswith(BLENDER_ASSET_FILE_SUFFIX)) { + bfd->main->is_asset_repository = true; + } mode = LOAD_UI_OFF; } else if (G.fileflags & G_FILE_NO_UI) { @@ -1259,6 +1262,15 @@ UserDef *BKE_blendfile_userdef_from_defaults() BKE_preferences_extension_repo_add_default(userdef); BKE_preferences_extension_repo_add_default_user(userdef); + { + BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + userdef, "VIEW3D_AST_brush_sculpt", "Brushes/Mesh/Sculpt/Cloth"); + BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + userdef, "VIEW3D_AST_brush_sculpt", "Brushes/Mesh/Sculpt/General"); + BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + userdef, "VIEW3D_AST_brush_sculpt", "Brushes/Mesh/Sculpt/Painting"); + } + return userdef; } diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 896af0690d9..0339db23902 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -5,6 +5,7 @@ /** \file * \ingroup bke */ +#include #include #include "MEM_guardedalloc.h" @@ -20,10 +21,12 @@ #include "BLT_translation.hh" +#include "BKE_asset.hh" #include "BKE_bpath.hh" #include "BKE_brush.hh" #include "BKE_colortools.hh" #include "BKE_gpencil_legacy.h" +#include "BKE_idprop.hh" #include "BKE_idtype.hh" #include "BKE_lib_id.hh" #include "BKE_lib_query.hh" @@ -378,38 +381,44 @@ static void brush_blend_read_after_liblink(BlendLibReader * /*reader*/, ID *id) } } -static int brush_undo_preserve_cb(LibraryIDLinkCallbackData *cb_data) +static void brush_asset_metadata_ensure(void *asset_ptr, AssetMetaData *asset_data) { - BlendLibReader *reader = (BlendLibReader *)cb_data->user_data; - ID *self_id = cb_data->self_id; - ID *id_old = *cb_data->id_pointer; - /* Old data has not been remapped to new values of the pointers, if we want to keep the old - * pointer here we need its new address. */ - ID *id_old_new = id_old != nullptr ? BLO_read_get_new_id_address( - reader, self_id, ID_IS_LINKED(self_id), id_old) : - nullptr; - BLI_assert(id_old_new == nullptr || ELEM(id_old, id_old_new, id_old_new->orig_id)); - if (cb_data->cb_flag & IDWALK_CB_USER) { - id_us_plus_no_lib(id_old_new); - id_us_min(id_old); + using namespace blender; + using namespace blender::bke; + + Brush *brush = reinterpret_cast(asset_ptr); + BLI_assert(GS(brush->id.name) == ID_BR); + + /* Most names copied from brush RNA (not all are available there though). */ + constexpr std::array mode_map{ + std::pair{"use_paint_sculpt", OB_MODE_SCULPT}, + std::pair{"use_paint_vertex", OB_MODE_VERTEX_PAINT}, + std::pair{"use_paint_weight", OB_MODE_WEIGHT_PAINT}, + std::pair{"use_paint_image", OB_MODE_TEXTURE_PAINT}, + /* Sculpt UVs in the image editor while in edit mode. */ + std::pair{"use_paint_uv_sculpt", OB_MODE_EDIT}, + std::pair{"use_paint_grease_pencil", OB_MODE_PAINT_GPENCIL_LEGACY}, + /* Note: Not defined in brush RNA, own name. */ + std::pair{"use_sculpt_grease_pencil", OB_MODE_SCULPT_GPENCIL_LEGACY}, + std::pair{"use_vertex_grease_pencil", OB_MODE_VERTEX_GPENCIL_LEGACY}, + std::pair{"use_weight_grease_pencil", OB_MODE_WEIGHT_GPENCIL_LEGACY}, + std::pair{"use_paint_sculpt_curves", OB_MODE_SCULPT_CURVES}, + }; + + for (const auto &mode_mapping : mode_map) { + /* Only add bools for supported modes. */ + if (!(brush->ob_mode & mode_mapping.second)) { + continue; + } + auto mode_property = idprop::create_bool(mode_mapping.first, true); + BKE_asset_metadata_idprop_ensure(asset_data, mode_property.release()); } - *cb_data->id_pointer = id_old_new; - return IDWALK_RET_NOP; } -static void brush_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old) -{ - /* Whole Brush is preserved across undo-steps. */ - BKE_lib_id_swap(nullptr, id_new, id_old, false, 0); - - /* `id_new` now has content from `id_old`, we need to ensure those old ID pointers are valid. - * NOTE: Since we want to re-use all old pointers here, code is much simpler than for Scene. */ - BKE_library_foreach_ID_link(nullptr, id_new, brush_undo_preserve_cb, reader, IDWALK_NOP); - - /* NOTE: We do not swap IDProperties, as dealing with potential ID pointers in those would be - * fairly delicate. */ - std::swap(id_new->properties, id_old->properties); -} +static AssetTypeInfo AssetType_BR = { + /*pre_save_fn*/ brush_asset_metadata_ensure, + /*on_mark_asset_fn*/ brush_asset_metadata_ensure, +}; IDTypeInfo IDType_ID_BR = { /*id_code*/ ID_BR, @@ -421,8 +430,8 @@ IDTypeInfo IDType_ID_BR = { /*name*/ "Brush", /*name_plural*/ N_("brushes"), /*translation_context*/ BLT_I18NCONTEXT_ID_BRUSH, - /*flags*/ IDTYPE_FLAGS_NO_ANIMDATA, - /*asset_type_info*/ nullptr, + /*flags*/ IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_NO_MEMFILE_UNDO, + /*asset_type_info*/ &AssetType_BR, /*init_data*/ brush_init_data, /*copy_data*/ brush_copy_data, @@ -437,7 +446,7 @@ IDTypeInfo IDType_ID_BR = { /*blend_read_data*/ brush_blend_read_data, /*blend_read_after_liblink*/ brush_blend_read_after_liblink, - /*blend_read_undo_preserve*/ brush_undo_preserve, + /*blend_read_undo_preserve*/ nullptr, /*lib_override_apply_post*/ nullptr, }; @@ -525,6 +534,14 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode) if (ob_mode == OB_MODE_SCULPT_CURVES) { BKE_brush_init_curves_sculpt_settings(brush); } + else if (ELEM(ob_mode, + OB_MODE_PAINT_GPENCIL_LEGACY, + OB_MODE_SCULPT_GPENCIL_LEGACY, + OB_MODE_WEIGHT_GPENCIL_LEGACY, + OB_MODE_VERTEX_GPENCIL_LEGACY)) + { + BKE_brush_init_gpencil_settings(brush); + } return brush; } @@ -541,7 +558,6 @@ void BKE_brush_init_gpencil_settings(Brush *brush) brush->gpencil_settings->draw_strength = 1.0f; brush->gpencil_settings->draw_jitter = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; /* curves */ brush->gpencil_settings->curve_sensitivity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); @@ -556,45 +572,6 @@ void BKE_brush_init_gpencil_settings(Brush *brush) brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); } -Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode) -{ - Paint *paint = nullptr; - Brush *brush; - switch (mode) { - case OB_MODE_PAINT_GPENCIL_LEGACY: { - paint = &ts->gp_paint->paint; - break; - } - case OB_MODE_SCULPT_GPENCIL_LEGACY: { - paint = &ts->gp_sculptpaint->paint; - break; - } - case OB_MODE_WEIGHT_GPENCIL_LEGACY: { - paint = &ts->gp_weightpaint->paint; - break; - } - case OB_MODE_VERTEX_GPENCIL_LEGACY: { - paint = &ts->gp_vertexpaint->paint; - break; - } - default: - paint = &ts->gp_paint->paint; - } - - brush = BKE_brush_add(bmain, name, mode); - - BKE_paint_brush_set(paint, brush); - id_us_min(&brush->id); - - brush->size = 3; - - /* grease pencil basic settings */ - BKE_brush_init_gpencil_settings(brush); - - /* return brush */ - return brush; -} - bool BKE_brush_delete(Main *bmain, Brush *brush) { if (brush->id.tag & LIB_TAG_INDIRECT) { @@ -611,1031 +588,6 @@ bool BKE_brush_delete(Main *bmain, Brush *brush) return true; } -/** Local grease pencil curve mapping preset. */ -using eGPCurveMappingPreset = enum eGPCurveMappingPreset { - GPCURVE_PRESET_PENCIL = 0, - GPCURVE_PRESET_INK = 1, - GPCURVE_PRESET_INKNOISE = 2, - GPCURVE_PRESET_MARKER = 3, - GPCURVE_PRESET_CHISEL_SENSIVITY = 4, - GPCURVE_PRESET_CHISEL_STRENGTH = 5, -}; - -static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, eGPCurveMappingPreset preset) -{ - if (cuma->curve) { - MEM_freeN(cuma->curve); - } - - cuma->totpoint = tot; - cuma->curve = (CurveMapPoint *)MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__); - - switch (preset) { - case GPCURVE_PRESET_PENCIL: - cuma->curve[0].x = 0.0f; - cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.75115f; - cuma->curve[1].y = 0.25f; - cuma->curve[2].x = 1.0f; - cuma->curve[2].y = 1.0f; - break; - case GPCURVE_PRESET_INK: - cuma->curve[0].x = 0.0f; - cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.63448f; - cuma->curve[1].y = 0.375f; - cuma->curve[2].x = 1.0f; - cuma->curve[2].y = 1.0f; - break; - case GPCURVE_PRESET_INKNOISE: - cuma->curve[0].x = 0.0f; - cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.55f; - cuma->curve[1].y = 0.45f; - cuma->curve[2].x = 0.85f; - cuma->curve[2].y = 1.0f; - break; - case GPCURVE_PRESET_MARKER: - cuma->curve[0].x = 0.0f; - cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.38f; - cuma->curve[1].y = 0.22f; - cuma->curve[2].x = 0.65f; - cuma->curve[2].y = 0.68f; - cuma->curve[3].x = 1.0f; - cuma->curve[3].y = 1.0f; - break; - case GPCURVE_PRESET_CHISEL_SENSIVITY: - cuma->curve[0].x = 0.0f; - cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.25f; - cuma->curve[1].y = 0.40f; - cuma->curve[2].x = 1.0f; - cuma->curve[2].y = 1.0f; - break; - case GPCURVE_PRESET_CHISEL_STRENGTH: - cuma->curve[0].x = 0.0f; - cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.31f; - cuma->curve[1].y = 0.22f; - cuma->curve[2].x = 0.61f; - cuma->curve[2].y = 0.88f; - cuma->curve[3].x = 1.0f; - cuma->curve[3].y = 1.0f; - break; - default: - break; - } - - MEM_SAFE_FREE(cuma->table); -} - -void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) -{ -#define SMOOTH_STROKE_RADIUS 40 -#define SMOOTH_STROKE_FACTOR 0.9f -#define ACTIVE_SMOOTH 0.35f - - CurveMapping *custom_curve = nullptr; - - /* Optionally assign a material preset. */ - enum { - PRESET_MATERIAL_NONE = 0, - PRESET_MATERIAL_DOT_STROKE, - } material_preset = PRESET_MATERIAL_NONE; - - /* Set general defaults at brush level. */ - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - - brush->rgb[0] = 0.498f; - brush->rgb[1] = 1.0f; - brush->rgb[2] = 0.498f; - - brush->secondary_rgb[0] = 1.0f; - brush->secondary_rgb[1] = 1.0f; - brush->secondary_rgb[2] = 1.0f; - - brush->curve_preset = BRUSH_CURVE_SMOOTH; - - if (brush->gpencil_settings == nullptr) { - return; - } - - /* Set preset type. */ - brush->gpencil_settings->preset_type = type; - - /* Set vertex mix factor. */ - brush->gpencil_settings->vertex_mode = GPPAINT_MODE_BOTH; - brush->gpencil_settings->vertex_factor = 1.0f; - brush->gpencil_settings->material_alt = nullptr; - - switch (type) { - case GP_BRUSH_PRESET_AIRBRUSH: { - brush->size = 300.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.4f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 0.9f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_tool = GPAINT_TOOL_DRAW; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH; - - zero_v3(brush->secondary_rgb); - - material_preset = PRESET_MATERIAL_DOT_STROKE; - - break; - } - case GP_BRUSH_PRESET_INK_PEN: { - - brush->size = 60.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 1.0f; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO); - BKE_curvemapping_init(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK); - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_INK_PEN_ROUGH: { - brush->size = 60.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 1.0f; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 2; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->simplify_f = 0.000f; - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.6f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO); - BKE_curvemapping_init(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE); - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_MARKER_BOLD: { - brush->size = 150.0f; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.3f; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO); - BKE_curvemapping_init(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER); - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_MARKER_CHISEL: { - brush->size = 150.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 1.0f; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.3f; - brush->gpencil_settings->draw_angle = DEG2RAD(35.0f); - brush->gpencil_settings->draw_angle_factor = 0.5f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO); - BKE_curvemapping_init(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_CHISEL_SENSIVITY); - - custom_curve = brush->gpencil_settings->curve_strength; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO); - BKE_curvemapping_init(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_CHISEL_STRENGTH); - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_PEN: { - brush->size = 25.0f; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_STRENGTH_PRESSURE; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 1; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_PENCIL_SOFT: { - brush->size = 80.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.4f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 0.8f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->simplify_f = 0.000f; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - - material_preset = PRESET_MATERIAL_DOT_STROKE; - - break; - } - case GP_BRUSH_PRESET_PENCIL: { - brush->size = 20.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.6f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_FILL_AREA: { - brush->size = 5.0f; - - brush->gpencil_settings->fill_threshold = 0.1f; - brush->gpencil_settings->fill_simplylvl = 1; - brush->gpencil_settings->fill_factor = 1.0f; - - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->hardness = 1.0f; - copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 1; - brush->gpencil_settings->dilate_pixels = 1; - - brush->gpencil_settings->flag |= GP_BRUSH_FILL_SHOW_EXTENDLINES; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; - brush->gpencil_tool = GPAINT_TOOL_FILL; - brush->gpencil_settings->vertex_mode = GPPAINT_MODE_FILL; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_ERASER_SOFT: { - brush->size = 30.0f; - brush->gpencil_settings->draw_strength = 0.5f; - brush->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; - 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 = 10.0f; - - break; - } - case GP_BRUSH_PRESET_ERASER_HARD: { - brush->size = 30.0f; - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; - brush->gpencil_settings->era_strength_f = 100.0f; - brush->gpencil_settings->era_thickness_f = 50.0f; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; - brush->gpencil_tool = GPAINT_TOOL_ERASE; - - break; - } - case GP_BRUSH_PRESET_ERASER_POINT: { - brush->size = 30.0f; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; - brush->gpencil_tool = GPAINT_TOOL_ERASE; - - break; - } - case GP_BRUSH_PRESET_ERASER_STROKE: { - brush->size = 30.0f; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; - - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; - brush->gpencil_tool = GPAINT_TOOL_ERASE; - - break; - } - case GP_BRUSH_PRESET_TINT: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_TINT; - brush->gpencil_tool = GPAINT_TOOL_TINT; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.8f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_VERTEX_DRAW: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_DRAW; - brush->gpencil_vertex_tool = GPVERTEX_TOOL_DRAW; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.8f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_VERTEX_BLUR: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; - brush->gpencil_vertex_tool = GPVERTEX_TOOL_BLUR; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.8f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_VERTEX_AVERAGE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_AVERAGE; - brush->gpencil_vertex_tool = GPVERTEX_TOOL_AVERAGE; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.8f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_VERTEX_SMEAR: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_SMEAR; - brush->gpencil_vertex_tool = GPVERTEX_TOOL_SMEAR; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.8f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_VERTEX_REPLACE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_REPLACE; - brush->gpencil_vertex_tool = GPVERTEX_TOOL_REPLACE; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.8f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - - zero_v3(brush->secondary_rgb); - break; - } - case GP_BRUSH_PRESET_SMOOTH_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_SMOOTH; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_SMOOTH; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_STRENGTH_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_STRENGTH; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_STRENGTH; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_THICKNESS_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_THICKNESS; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_THICKNESS; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.5f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_GRAB_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_GRAB; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_GRAB; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; - - brush->size = 25.0f; - - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_PUSH_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_PUSH; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_PUSH; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_TWIST_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_TWIST; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_TWIST; - - brush->size = 50.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_PINCH_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_PINCH; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_PINCH; - - brush->size = 50.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.5f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_RANDOMIZE_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_RANDOMIZE; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_RANDOMIZE; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->gpencil_settings->draw_strength = 0.5f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_CLONE_STROKE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_CLONE; - brush->gpencil_sculpt_tool = GPSCULPT_TOOL_CLONE; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; - - brush->size = 25.0f; - - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_WEIGHT_DRAW: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_WEIGHT; - brush->gpencil_weight_tool = GPWEIGHT_TOOL_DRAW; - - brush->size = 25.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->alpha = 0.3f; - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_WEIGHT_BLUR: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; - brush->gpencil_weight_tool = GPWEIGHT_TOOL_BLUR; - - brush->size = 50.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->alpha = 0.3f; - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_WEIGHT_AVERAGE: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; - brush->gpencil_weight_tool = GPWEIGHT_TOOL_AVERAGE; - - brush->size = 50.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->alpha = 0.3f; - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - case GP_BRUSH_PRESET_WEIGHT_SMEAR: { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; - brush->gpencil_weight_tool = GPWEIGHT_TOOL_SMEAR; - - brush->size = 50.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - - brush->alpha = 0.3f; - brush->gpencil_settings->draw_strength = 0.3f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; - brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - - break; - } - default: - break; - } - - switch (material_preset) { - case PRESET_MATERIAL_NONE: - break; - case PRESET_MATERIAL_DOT_STROKE: { - /* Create and link Black Dots material to brush. - * This material is required because the brush uses the material - * to define how the stroke is drawn. */ - const char *ma_id = "Dots Stroke"; - Material *ma = (Material *)BLI_findstring(&bmain->materials, ma_id, offsetof(ID, name) + 2); - if (ma == nullptr) { - ma = BKE_gpencil_material_add(bmain, ma_id); - ma->gp_style->mode = GP_MATERIAL_MODE_DOT; - BLI_assert(ma->id.us == 1); - id_us_min(&ma->id); - } - - BKE_gpencil_brush_material_set(brush, ma); - - /* Pin the material to the brush. */ - brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED; - break; - } - } -} - -static Brush *gpencil_brush_ensure( - Main *bmain, ToolSettings *ts, const char *brush_name, eObjectMode mode, bool *r_is_new) -{ - *r_is_new = false; - Brush *brush = (Brush *)BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); - - /* If the brush exist, but the type is not GPencil or the mode is wrong, create a new one. */ - if ((brush != nullptr) && ((brush->gpencil_settings == nullptr) || (brush->ob_mode != mode))) { - brush = nullptr; - } - - if (brush == nullptr) { - brush = BKE_brush_add_gpencil(bmain, ts, brush_name, mode); - *r_is_new = true; - } - - if (brush->gpencil_settings == nullptr) { - BKE_brush_init_gpencil_settings(brush); - } - - return brush; -} - -void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool reset) -{ - bool is_new = false; - - Paint *paint = &ts->gp_paint->paint; - Brush *brush_prev = BKE_paint_brush(paint); - Brush *brush, *deft_draw; - /* Airbrush brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_AIRBRUSH); - } - - /* Ink Pen brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Ink Pen", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN); - } - - /* Ink Pen Rough brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Ink Pen Rough", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN_ROUGH); - } - - /* Marker Bold brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Marker Bold", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_BOLD); - } - - /* Marker Chisel brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Marker Chisel", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_CHISEL); - } - - /* Pen brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Pen", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PEN); - } - - /* Pencil Soft brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Pencil Soft", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL_SOFT); - } - - /* Pencil brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Pencil", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL); - } - deft_draw = brush; /* save default brush. */ - - /* Fill brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Fill Area", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_FILL_AREA); - } - - /* Soft Eraser brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Eraser Soft", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_SOFT); - } - - /* Hard Eraser brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Eraser Hard", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_HARD); - } - - /* Point Eraser brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Eraser Point", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_POINT); - } - - /* Stroke Eraser brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Eraser Stroke", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_STROKE); - } - - /* Tint brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Tint", OB_MODE_PAINT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TINT); - } - - /* Set default Draw brush. */ - if ((reset == false) && (brush_prev != nullptr)) { - BKE_paint_brush_set(paint, brush_prev); - } - else { - BKE_paint_brush_set(paint, deft_draw); - } -} - -void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool reset) -{ - bool is_new = false; - - Paint *vertexpaint = &ts->gp_vertexpaint->paint; - Brush *brush_prev = BKE_paint_brush(vertexpaint); - Brush *brush, *deft_vertex; - /* Vertex Draw brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_DRAW); - } - deft_vertex = brush; /* save default brush. */ - - /* Vertex Blur brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Vertex Blur", OB_MODE_VERTEX_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_BLUR); - } - /* Vertex Average brush. */ - brush = gpencil_brush_ensure( - bmain, ts, "Vertex Average", OB_MODE_VERTEX_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_AVERAGE); - } - /* Vertex Smear brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Vertex Smear", OB_MODE_VERTEX_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_SMEAR); - } - /* Vertex Replace brush. */ - brush = gpencil_brush_ensure( - bmain, ts, "Vertex Replace", OB_MODE_VERTEX_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_REPLACE); - } - - /* Set default Vertex brush. */ - if ((reset == false) && (brush_prev != nullptr)) { - BKE_paint_brush_set(vertexpaint, brush_prev); - } - else { - BKE_paint_brush_set(vertexpaint, deft_vertex); - } -} - -void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool reset) -{ - bool is_new = false; - - Paint *sculptpaint = &ts->gp_sculptpaint->paint; - Brush *brush_prev = BKE_paint_brush(sculptpaint); - Brush *brush, *deft_sculpt; - - /* Smooth brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Smooth Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_SMOOTH_STROKE); - } - deft_sculpt = brush; - - /* Strength brush. */ - brush = gpencil_brush_ensure( - bmain, ts, "Strength Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_STRENGTH_STROKE); - } - - /* Thickness brush. */ - brush = gpencil_brush_ensure( - bmain, ts, "Thickness Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_THICKNESS_STROKE); - } - - /* Grab brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Grab Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_GRAB_STROKE); - } - - /* Push brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Push Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PUSH_STROKE); - } - - /* Twist brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Twist Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TWIST_STROKE); - } - - /* Pinch brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Pinch Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PINCH_STROKE); - } - - /* Randomize brush. */ - brush = gpencil_brush_ensure( - bmain, ts, "Randomize Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_RANDOMIZE_STROKE); - } - - /* Clone brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Clone Stroke", OB_MODE_SCULPT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_CLONE_STROKE); - } - - /* Set default brush. */ - if ((reset == false) && (brush_prev != nullptr)) { - BKE_paint_brush_set(sculptpaint, brush_prev); - } - else { - BKE_paint_brush_set(sculptpaint, deft_sculpt); - } -} - -void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool reset) -{ - bool is_new = false; - - Paint *weightpaint = &ts->gp_weightpaint->paint; - Brush *brush_prev = BKE_paint_brush(weightpaint); - Brush *brush, *deft_weight; - - /* Weight Draw brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Weight Draw", OB_MODE_WEIGHT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_DRAW); - } - deft_weight = brush; /* save default brush. */ - - /* Weight Blur brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Weight Blur", OB_MODE_WEIGHT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_BLUR); - } - - /* Weight Average brush. */ - brush = gpencil_brush_ensure( - bmain, ts, "Weight Average", OB_MODE_WEIGHT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_AVERAGE); - } - - /* Weight Smear brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Weight Smear", OB_MODE_WEIGHT_GPENCIL_LEGACY, &is_new); - if ((reset) || (is_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_SMEAR); - } - - /* Set default brush. */ - if ((reset == false) && (brush_prev != nullptr)) { - BKE_paint_brush_set(weightpaint, brush_prev); - } - else { - BKE_paint_brush_set(weightpaint, deft_weight); - } -} - void BKE_brush_init_curves_sculpt_settings(Brush *brush) { if (brush->curves_sculpt_settings == nullptr) { diff --git a/source/blender/blenkernel/intern/context.cc b/source/blender/blenkernel/intern/context.cc index 0186d8ed12e..8d49d3fc29d 100644 --- a/source/blender/blenkernel/intern/context.cc +++ b/source/blender/blenkernel/intern/context.cc @@ -1058,6 +1058,11 @@ Main *CTX_data_main(const bContext *C) return C->data.main; } +Main *CTX_data_main_from_id(const bContext *C, const ID *id) +{ + return BKE_main_from_id(CTX_data_main(C), id); +} + void CTX_data_main_set(bContext *C, Main *bmain) { C->data.main = bmain; diff --git a/source/blender/blenkernel/intern/lib_id.cc b/source/blender/blenkernel/intern/lib_id.cc index f41801a16fc..b82ea8004de 100644 --- a/source/blender/blenkernel/intern/lib_id.cc +++ b/source/blender/blenkernel/intern/lib_id.cc @@ -1334,6 +1334,9 @@ void *BKE_libblock_alloc_in_lib(Main *bmain, if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) { DEG_id_type_tag(bmain, type); } + if (bmain->is_asset_edit_main) { + id->tag |= LIB_TAG_ASSET_EDIT_MAIN; + } } else { BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2); @@ -1556,10 +1559,20 @@ void BKE_libblock_copy_in_lib(Main *bmain, } } + if (flag & LIB_ID_COPY_ASSET_METADATA) { + if (id->asset_data) { + new_id->asset_data = BKE_asset_metadata_copy(id->asset_data); + } + } + if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) { DEG_id_type_tag(bmain, GS(new_id->name)); } + if (bmain && bmain->is_asset_edit_main) { + new_id->tag |= LIB_TAG_ASSET_EDIT_MAIN; + } + *r_newid = new_id; } @@ -2215,13 +2228,6 @@ void BKE_id_tag_clear_atomic(ID *id, int tag) atomic_fetch_and_and_int32(&id->tag, ~tag); } -bool BKE_id_is_in_global_main(ID *id) -{ - /* We do not want to fail when id is nullptr here, even though this is a bit strange behavior... - */ - return (id == nullptr || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1); -} - bool BKE_id_can_be_asset(const ID *id) { return !ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY(id) && diff --git a/source/blender/blenkernel/intern/main.cc b/source/blender/blenkernel/intern/main.cc index e823b11f745..bcc56d96494 100644 --- a/source/blender/blenkernel/intern/main.cc +++ b/source/blender/blenkernel/intern/main.cc @@ -24,6 +24,7 @@ #include "DNA_ID.h" +#include "BKE_asset_edit.hh" #include "BKE_bpath.hh" #include "BKE_global.hh" #include "BKE_idtype.hh" @@ -445,6 +446,16 @@ bool BKE_main_is_empty(Main *bmain) return result; } +bool BKE_main_has_issues(const Main *bmain) +{ + return bmain->has_forward_compatibility_issues || bmain->is_asset_repository; +} + +bool BKE_main_needs_overwrite_confirm(const Main *bmain) +{ + return bmain->has_forward_compatibility_issues || bmain->is_asset_repository; +} + void BKE_main_lock(Main *bmain) { BLI_spin_lock((SpinLock *)bmain->lock); @@ -955,3 +966,34 @@ int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/]) return (INDEX_ID_MAX - 1); } + +Main *BKE_main_from_id(Main *global_main, const ID *id, const bool verify) +{ + if (id == nullptr || (id->tag & LIB_TAG_NO_MAIN)) { + return nullptr; + } + if (id->tag & LIB_TAG_ASSET_EDIT_MAIN) { + return blender::bke::asset_edit_main(*id); + } + + if (verify) { + /* This is rather expensive, so don't do by default and assume valid input. */ + if (BLI_findindex(which_libbase(global_main, GS(id->name)), id) == -1) { + return nullptr; + } + } + else { +/* Debug assert, especially for places that pass in G_MAIN. */ +#ifndef NDEBUG + if (id->flag & LIB_EMBEDDED_DATA) { + const ID *id_owner = BKE_id_owner_get(const_cast(id)); + BLI_assert(BLI_findindex(which_libbase(global_main, GS(id_owner->name)), id_owner) != -1); + } + else { + BLI_assert(BLI_findindex(which_libbase(global_main, GS(id->name)), id) != -1); + } +#endif + } + + return global_main; +} diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 2e0261a9aa5..36492544ed9 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -13,6 +13,7 @@ #include "DNA_object_enums.h" #include "MEM_guardedalloc.h" +#include "DNA_asset_types.h" #include "DNA_brush_types.h" #include "DNA_defaults.h" #include "DNA_gpencil_legacy_types.h" @@ -33,12 +34,15 @@ #include "BLI_math_matrix.h" #include "BLI_math_matrix.hh" #include "BLI_math_vector.h" +#include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_utildefines.h" #include "BLI_vector.hh" #include "BLT_translation.hh" +#include "BKE_asset.hh" +#include "BKE_asset_edit.hh" #include "BKE_attribute.hh" #include "BKE_brush.hh" #include "BKE_ccg.h" @@ -444,61 +448,6 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(const PaintMode m return nullptr; } -const char *BKE_paint_get_tool_prop_id_from_paintmode(const PaintMode mode) -{ - switch (mode) { - case PaintMode::Sculpt: - return "sculpt_tool"; - case PaintMode::Vertex: - return "vertex_tool"; - case PaintMode::Weight: - return "weight_tool"; - case PaintMode::Texture2D: - case PaintMode::Texture3D: - return "image_tool"; - case PaintMode::GPencil: - return "gpencil_tool"; - case PaintMode::VertexGPencil: - return "gpencil_vertex_tool"; - case PaintMode::SculptGPencil: - return "gpencil_sculpt_tool"; - case PaintMode::WeightGPencil: - return "gpencil_weight_tool"; - case PaintMode::SculptCurves: - return "curves_sculpt_tool"; - case PaintMode::SculptGreasePencil: - return "gpencil_sculpt_tool"; - case PaintMode::Invalid: - break; - } - - /* Invalid paint mode. */ - return nullptr; -} - -const char *BKE_paint_get_tool_enum_translation_context_from_paintmode(const PaintMode mode) -{ - switch (mode) { - case PaintMode::Sculpt: - case PaintMode::GPencil: - case PaintMode::Texture2D: - case PaintMode::Texture3D: - return BLT_I18NCONTEXT_ID_BRUSH; - case PaintMode::Vertex: - case PaintMode::Weight: - case PaintMode::VertexGPencil: - case PaintMode::SculptGPencil: - case PaintMode::WeightGPencil: - case PaintMode::SculptCurves: - case PaintMode::SculptGreasePencil: - case PaintMode::Invalid: - break; - } - - /* Invalid paint mode. */ - return BLT_I18NCONTEXT_DEFAULT; -} - Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) { if (sce && view_layer) { @@ -663,68 +612,237 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref) return PaintMode::Invalid; } -Brush *BKE_paint_brush(Paint *p) +static bool paint_brush_set_from_asset_reference(Main *bmain, Paint *paint) { - return (Brush *)BKE_paint_brush_for_read((const Paint *)p); + /* Attempt to restore a valid active brush from brush asset information. */ + if (paint->brush != nullptr) { + return false; + } + if (paint->brush_asset_reference == nullptr) { + return false; + } + + Brush *brush = reinterpret_cast(blender::bke::asset_edit_id_from_weak_reference( + *bmain, ID_BR, *paint->brush_asset_reference)); + BLI_assert(brush == nullptr || (brush->id.tag & LIB_TAG_ASSET_EDIT_MAIN)); + + /* Ensure we have a brush with appropriate mode to assign. + * Could happen if contents of asset blend was manually changed. */ + if (brush == nullptr || (paint->runtime.ob_mode & brush->ob_mode) == 0) { + MEM_delete(paint->brush_asset_reference); + paint->brush_asset_reference = nullptr; + return false; + } + + paint->brush = brush; + return true; } -const Brush *BKE_paint_brush_for_read(const Paint *p) +Brush *BKE_paint_brush(Paint *paint) { - return p ? p->brush : nullptr; + return (Brush *)BKE_paint_brush_for_read((const Paint *)paint); } -void BKE_paint_brush_set(Paint *p, Brush *br) +const Brush *BKE_paint_brush_for_read(const Paint *paint) { - if (p) { - id_us_min((ID *)p->brush); - id_us_plus((ID *)br); - p->brush = br; + return paint ? paint->brush : nullptr; +} - BKE_paint_toolslots_brush_update(p); +bool BKE_paint_brush_set(Paint *paint, Brush *brush) +{ + if (paint == nullptr || paint->brush == brush) { + return false; + } + if (brush && (paint->runtime.ob_mode & brush->ob_mode) == 0) { + return false; + } + + paint->brush = brush; + return true; +} + +static void paint_brush_asset_update(Paint &paint, + Brush *brush, + const AssetWeakReference &brush_asset_reference) +{ + BLI_assert(&brush_asset_reference != paint.brush_asset_reference); + MEM_delete(paint.brush_asset_reference); + paint.brush_asset_reference = nullptr; + + if (brush == nullptr || brush != paint.brush || !(brush->id.tag & LIB_TAG_ASSET_EDIT_MAIN)) { + return; + } + + paint.brush_asset_reference = MEM_new(__func__, brush_asset_reference); +} + +bool BKE_paint_brush_asset_set(Paint *paint, + Brush *brush, + const AssetWeakReference &weak_asset_reference) +{ + /* Should not happen for users if brush assets are properly filtered by mode, but still protect + * against it in case of invalid API usage. */ + if (brush && paint->runtime.ob_mode != brush->ob_mode) { + return false; + } + + BKE_paint_brush_set(paint, brush); + paint_brush_asset_update(*paint, brush, weak_asset_reference); + return true; +} + +Brush *BKE_paint_brush_from_essentials(Main *bmain, const char *name) +{ + AssetWeakReference weak_ref; + weak_ref.asset_library_type = eAssetLibraryType::ASSET_LIBRARY_ESSENTIALS; + weak_ref.relative_asset_identifier = BLI_sprintfN("brushes/essentials_brushes.blend/Brush/%s", + name); + + return reinterpret_cast( + blender::bke::asset_edit_id_from_weak_reference(*bmain, ID_BR, weak_ref)); +} + +static void paint_brush_set_essentials_reference(Paint *paint, const char *name) +{ + /* Set brush asset reference to a named brush in the essentials asset library. */ + MEM_delete(paint->brush_asset_reference); + + AssetWeakReference *weak_ref = MEM_new(__func__); + weak_ref->asset_library_type = eAssetLibraryType::ASSET_LIBRARY_ESSENTIALS; + weak_ref->relative_asset_identifier = BLI_sprintfN("brushes/essentials_brushes.blend/Brush/%s", + name); + paint->brush_asset_reference = weak_ref; + paint->brush = nullptr; +} + +static void paint_brush_set_default_reference(Paint *paint) +{ + const char *name = nullptr; + + switch (paint->runtime.ob_mode) { + case OB_MODE_SCULPT: + name = "Draw"; + break; + case OB_MODE_VERTEX_PAINT: + name = "Paint Vertex"; + break; + case OB_MODE_WEIGHT_PAINT: + name = "Paint Weight"; + break; + case OB_MODE_TEXTURE_PAINT: + name = "Paint Texture"; + break; + case OB_MODE_SCULPT_CURVES: + name = "Comb Curves"; + break; + case OB_MODE_PAINT_GPENCIL_LEGACY: + name = "Pencil"; + break; + case OB_MODE_VERTEX_GPENCIL_LEGACY: + name = "Paint Point Color"; + break; + case OB_MODE_SCULPT_GPENCIL_LEGACY: + name = "Smooth Stroke"; + break; + case OB_MODE_WEIGHT_GPENCIL_LEGACY: + name = "Paint Point Weight"; + break; + default: + BLI_assert_unreachable(); + return; + } + + if (name) { + paint_brush_set_essentials_reference(paint, name); } } -void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint) +void BKE_paint_brush_set_default_references(ToolSettings *ts) +{ + if (ts->sculpt) { + paint_brush_set_default_reference(&ts->sculpt->paint); + } + if (ts->curves_sculpt) { + paint_brush_set_default_reference(&ts->curves_sculpt->paint); + } + if (ts->wpaint) { + paint_brush_set_default_reference(&ts->wpaint->paint); + } + if (ts->vpaint) { + paint_brush_set_default_reference(&ts->vpaint->paint); + } + if (ts->gp_paint) { + paint_brush_set_default_reference(&ts->gp_paint->paint); + } + if (ts->gp_vertexpaint) { + paint_brush_set_default_reference(&ts->gp_vertexpaint->paint); + } + if (ts->gp_sculptpaint) { + paint_brush_set_default_reference(&ts->gp_sculptpaint->paint); + } + if (ts->gp_weightpaint) { + paint_brush_set_default_reference(&ts->gp_weightpaint->paint); + } + paint_brush_set_default_reference(&ts->imapaint.paint); +} + +bool BKE_paint_brush_set_default(Main *bmain, Paint *paint) +{ + paint_brush_set_default_reference(paint); + return paint_brush_set_from_asset_reference(bmain, paint); +} + +bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name) +{ + paint_brush_set_essentials_reference(paint, name); + return paint_brush_set_from_asset_reference(bmain, paint); +} + +void BKE_paint_brush_validate(Main *bmain, Paint *paint) +{ + /* Clear brush with invalid mode. Unclear if this can still happen, + * but kept from old paint toolslots code. */ + Brush *brush = BKE_paint_brush(paint); + if (brush && (paint->runtime.ob_mode & brush->ob_mode) == 0) { + BKE_paint_brush_set(paint, nullptr); + BKE_paint_brush_set_default(bmain, paint); + } +} + +static void paint_runtime_init(const ToolSettings *ts, Paint *paint) { if (paint == &ts->imapaint.paint) { - paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool); paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT; } else if (ts->sculpt && paint == &ts->sculpt->paint) { - paint->runtime.tool_offset = offsetof(Brush, sculpt_tool); paint->runtime.ob_mode = OB_MODE_SCULPT; } else if (ts->vpaint && paint == &ts->vpaint->paint) { - paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool); paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT; } else if (ts->wpaint && paint == &ts->wpaint->paint) { - paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool); paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT; } else if (ts->gp_paint && paint == &ts->gp_paint->paint) { - paint->runtime.tool_offset = offsetof(Brush, gpencil_tool); paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL_LEGACY; } else if (ts->gp_vertexpaint && paint == &ts->gp_vertexpaint->paint) { - paint->runtime.tool_offset = offsetof(Brush, gpencil_vertex_tool); paint->runtime.ob_mode = OB_MODE_VERTEX_GPENCIL_LEGACY; } else if (ts->gp_sculptpaint && paint == &ts->gp_sculptpaint->paint) { - paint->runtime.tool_offset = offsetof(Brush, gpencil_sculpt_tool); paint->runtime.ob_mode = OB_MODE_SCULPT_GPENCIL_LEGACY; } else if (ts->gp_weightpaint && paint == &ts->gp_weightpaint->paint) { - paint->runtime.tool_offset = offsetof(Brush, gpencil_weight_tool); paint->runtime.ob_mode = OB_MODE_WEIGHT_GPENCIL_LEGACY; } else if (ts->curves_sculpt && paint == &ts->curves_sculpt->paint) { - paint->runtime.tool_offset = offsetof(Brush, curves_sculpt_tool); paint->runtime.ob_mode = OB_MODE_SCULPT_CURVES; } else { BLI_assert_unreachable(); } + + paint->runtime.initialized = true; } uint BKE_paint_get_brush_tool_offset_from_paintmode(const PaintMode mode) @@ -1091,17 +1209,15 @@ eObjectMode BKE_paint_object_mode_from_paintmode(const PaintMode mode) } } -bool BKE_paint_ensure(Main * /*bmain*/, ToolSettings *ts, Paint **r_paint) +bool BKE_paint_ensure(Main *bmain, ToolSettings *ts, Paint **r_paint) { Paint *paint = nullptr; if (*r_paint) { - /* Tool offset should never be 0 for initialized paint settings, so it's a reliable way to - * check if already initialized. */ - if ((*r_paint)->runtime.tool_offset == 0) { + if (!(*r_paint)->runtime.initialized) { /* Currently only image painting is initialized this way, others have to be allocated. */ BLI_assert(ELEM(*r_paint, (Paint *)&ts->imapaint)); - BKE_paint_runtime_init(ts, *r_paint); + paint_runtime_init(ts, *r_paint); } else { BLI_assert(ELEM(*r_paint, @@ -1117,13 +1233,13 @@ bool BKE_paint_ensure(Main * /*bmain*/, ToolSettings *ts, Paint **r_paint) (Paint *)&ts->imapaint)); #ifndef NDEBUG Paint paint_test = **r_paint; - BKE_paint_runtime_init(ts, *r_paint); + paint_runtime_init(ts, *r_paint); /* Swap so debug doesn't hide errors when release fails. */ std::swap(**r_paint, paint_test); BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode); - BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset); #endif } + paint_brush_set_from_asset_reference(bmain, *r_paint); return true; } @@ -1166,7 +1282,8 @@ bool BKE_paint_ensure(Main * /*bmain*/, ToolSettings *ts, Paint **r_paint) *r_paint = paint; - BKE_paint_runtime_init(ts, paint); + paint_runtime_init(ts, paint); + BKE_paint_brush_set_default(bmain, paint); return false; } @@ -1178,18 +1295,6 @@ void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3]) BKE_paint_ensure_from_paintmode(bmain, sce, mode); - /* If there's no brush, create one */ - Brush *brush = BKE_paint_brush(paint); - if (brush == nullptr) { - eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode); - brush = BKE_brush_first_search(bmain, ob_mode); - if (!brush) { - brush = BKE_brush_add(bmain, "Brush", ob_mode); - id_us_min(&brush->id); /* Fake user only. */ - } - BKE_paint_brush_set(paint, brush); - } - copy_v3_v3_uchar(paint->paint_cursor_col, col); paint->paint_cursor_col[3] = 128; ups->last_stroke_valid = false; @@ -1203,23 +1308,21 @@ void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3]) void BKE_paint_free(Paint *paint) { BKE_curvemapping_free(paint->cavity_curve); - MEM_SAFE_FREE(paint->tool_slots); + MEM_delete(paint->brush_asset_reference); } -void BKE_paint_copy(const Paint *src, Paint *tar, const int flag) +void BKE_paint_copy(const Paint *src, Paint *dst, const int flag) { - tar->brush = src->brush; - tar->cavity_curve = BKE_curvemapping_copy(src->cavity_curve); - tar->tool_slots = static_cast(MEM_dupallocN(src->tool_slots)); + dst->brush = src->brush; + dst->cavity_curve = BKE_curvemapping_copy(src->cavity_curve); + + if (src->brush_asset_reference) { + dst->brush_asset_reference = MEM_new(__func__, + *src->brush_asset_reference); + } 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 != nullptr) { - for (int i = 0; i < tar->tool_slots_len; i++) { - id_us_plus((ID *)tar->tool_slots[i].brush); - } - } + id_us_plus((ID *)dst->palette); } } @@ -1240,7 +1343,9 @@ void BKE_paint_blend_write(BlendWriter *writer, Paint *p) if (p->cavity_curve) { BKE_curvemapping_blend_write(writer, p->cavity_curve); } - BLO_write_struct_array(writer, PaintToolSlot, p->tool_slots_len, p->tool_slots); + if (p->brush_asset_reference) { + BKE_asset_weak_reference_write(writer, p->brush_asset_reference); + } } void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Paint *p) @@ -1253,17 +1358,13 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain BKE_paint_cavity_curve_preset(p, CURVE_PRESET_LINE); } - BLO_read_struct_array(reader, PaintToolSlot, p->tool_slots_len, &p->tool_slots); - - /* Workaround for invalid data written in older versions. */ - const size_t expected_size = sizeof(PaintToolSlot) * p->tool_slots_len; - if (p->tool_slots && MEM_allocN_len(p->tool_slots) < expected_size) { - MEM_freeN(p->tool_slots); - p->tool_slots = static_cast(MEM_callocN(expected_size, "PaintToolSlot")); + BLO_read_struct(reader, AssetWeakReference, &p->brush_asset_reference); + if (p->brush_asset_reference) { + BKE_asset_weak_reference_read(reader, p->brush_asset_reference); } p->paint_cursor = nullptr; - BKE_paint_runtime_init(scene->toolsettings, p); + paint_runtime_init(scene->toolsettings, p); } bool paint_is_grid_face_hidden(const blender::BoundedBitSpan grid_hidden, diff --git a/source/blender/blenkernel/intern/paint_toolslots.cc b/source/blender/blenkernel/intern/paint_toolslots.cc deleted file mode 100644 index 7480890d0d4..00000000000 --- a/source/blender/blenkernel/intern/paint_toolslots.cc +++ /dev/null @@ -1,167 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#include - -#include "MEM_guardedalloc.h" - -#include "DNA_brush_types.h" -#include "DNA_scene_types.h" - -#include "BLI_utildefines.h" - -#include "BKE_brush.hh" -#include "BKE_lib_id.hh" -#include "BKE_main.hh" -#include "BKE_paint.hh" - -/* -------------------------------------------------------------------- */ -/** \name Tool Slot Initialization / Versioning - * - * These functions run to update old files (while versioning), - * take care only to perform low-level functions here. - * \{ */ - -void BKE_paint_toolslots_len_ensure(Paint *paint, int len) -{ - /* Tool slots are 'uchar'. */ - BLI_assert(len <= UCHAR_MAX); - if (paint->tool_slots_len < len) { - paint->tool_slots = static_cast( - MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len)); - paint->tool_slots_len = len; - } -} - -static void paint_toolslots_init(Main *bmain, Paint *paint) -{ - if (paint == nullptr) { - return; - } - const eObjectMode ob_mode = eObjectMode(paint->runtime.ob_mode); - BLI_assert(paint->runtime.tool_offset && ob_mode); - for (Brush *brush = static_cast(bmain->brushes.first); brush; - brush = static_cast(brush->id.next)) - { - if (brush->ob_mode & ob_mode) { - const int slot_index = BKE_brush_tool_get(brush, paint); - BKE_paint_toolslots_len_ensure(paint, slot_index + 1); - if (paint->tool_slots[slot_index].brush == nullptr) { - paint->tool_slots[slot_index].brush = brush; - id_us_plus(&brush->id); - } - } - } -} - -/** - * Initialize runtime since this is called from versioning code. - */ -static void paint_toolslots_init_with_runtime(Main *bmain, ToolSettings *ts, Paint *paint) -{ - if (paint == nullptr) { - return; - } - - /* Needed so #Paint_Runtime is updated when versioning. */ - BKE_paint_runtime_init(ts, paint); - paint_toolslots_init(bmain, paint); -} - -void BKE_paint_toolslots_init_from_main(Main *bmain) -{ - for (Scene *scene = static_cast(bmain->scenes.first); scene; - scene = static_cast(scene->id.next)) - { - ToolSettings *ts = scene->toolsettings; - paint_toolslots_init_with_runtime(bmain, ts, &ts->imapaint.paint); - if (ts->sculpt) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->sculpt->paint); - } - if (ts->vpaint) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->vpaint->paint); - } - if (ts->wpaint) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->wpaint->paint); - } - if (ts->gp_paint) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_paint->paint); - } - if (ts->gp_vertexpaint) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_vertexpaint->paint); - } - if (ts->gp_sculptpaint) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_sculptpaint->paint); - } - if (ts->gp_weightpaint) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_weightpaint->paint); - } - if (ts->curves_sculpt) { - paint_toolslots_init_with_runtime(bmain, ts, &ts->curves_sculpt->paint); - } - } -} - -/** \} */ - -void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush) -{ - const uint tool_offset = paint->runtime.tool_offset; - UNUSED_VARS_NDEBUG(tool_offset); - BLI_assert(tool_offset != 0); - const int slot_index = BKE_brush_tool_get(brush, paint); - BKE_paint_toolslots_len_ensure(paint, slot_index + 1); - PaintToolSlot *tslot = &paint->tool_slots[slot_index]; - id_us_plus(&brush->id); - if (tslot->brush) { - id_us_min(&tslot->brush->id); - } - tslot->brush = brush; -} - -void BKE_paint_toolslots_brush_update(Paint *paint) -{ - if (paint->brush == nullptr) { - return; - } - BKE_paint_toolslots_brush_update_ex(paint, paint->brush); -} - -void BKE_paint_brush_validate(Main *bmain, Paint *paint) -{ - /* Clear slots with invalid slots or mode (unlikely but possible). */ - const uint tool_offset = paint->runtime.tool_offset; - UNUSED_VARS_NDEBUG(tool_offset); - const eObjectMode ob_mode = eObjectMode(paint->runtime.ob_mode); - BLI_assert(tool_offset && ob_mode); - for (int i = 0; i < paint->tool_slots_len; i++) { - PaintToolSlot *tslot = &paint->tool_slots[i]; - if (tslot->brush) { - if ((i != BKE_brush_tool_get(tslot->brush, paint)) || (tslot->brush->ob_mode & ob_mode) == 0) - { - id_us_min(&tslot->brush->id); - tslot->brush = nullptr; - } - } - } - - /* Unlikely but possible the active brush is not currently using a slot. */ - BKE_paint_toolslots_brush_update(paint); - - /* Fill slots from brushes. */ - paint_toolslots_init(bmain, paint); -} - -Brush *BKE_paint_toolslots_brush_get(Paint *paint, int slot_index) -{ - if (slot_index < paint->tool_slots_len) { - PaintToolSlot *tslot = &paint->tool_slots[slot_index]; - return tslot->brush; - } - return nullptr; -} diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 9a620c168ac..ca5a58e5f79 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -590,27 +590,7 @@ static void scene_foreach_paint(LibraryForeachIDData *data, SCENE_FOREACH_UNDO_RESTORE, reader, &paint_old->brush, - IDWALK_CB_USER); - - for (int i = 0; i < paint_old->tool_slots_len; i++) { - /* This is a bit tricky. - * - In case we do not do `undo_restore`, `paint` and `paint_old` pointers are the same, so - * this is equivalent to simply looping over slots from `paint`. - * - In case we do `undo_restore`, we only want to consider the slots from the old one, since - * those are the one we keep in the end. - * + In case the new data has less valid slots, we feed in a dummy null pointer. - * + In case the new data has more valid slots, the extra ones are ignored. - */ - brush_tmp = nullptr; - brush_p = (paint && i < paint->tool_slots_len) ? &paint->tool_slots[i].brush : &brush_tmp; - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER_P(data, - brush_p, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - &paint_old->tool_slots[i].brush, - IDWALK_CB_USER); - } + IDWALK_CB_NOP); Palette *palette_tmp = nullptr; Palette **palette_p = paint ? &paint->palette : &palette_tmp; diff --git a/source/blender/blenloader/intern/versioning_280.cc b/source/blender/blenloader/intern/versioning_280.cc index 5f6d070fa86..7242aff0434 100644 --- a/source/blender/blenloader/intern/versioning_280.cc +++ b/source/blender/blenloader/intern/versioning_280.cc @@ -2554,7 +2554,6 @@ void do_versions_after_linking_280(FileData *fd, Main *bmain) brush->gpencil_tool = brush->gpencil_settings->brush_type; } } - BKE_paint_toolslots_init_from_main(bmain); } if (!MAIN_VERSION_FILE_ATLEAST(bmain, 280, 38)) { @@ -2837,9 +2836,6 @@ void do_versions_after_linking_280(FileData *fd, Main *bmain) Material *ma; /* Pen Soft brush. */ brush = (Brush *)do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft"); - if (brush) { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; - } do_versions_rename_id(bmain, ID_BR, "Draw Pencil", "Pencil"); do_versions_rename_id(bmain, ID_BR, "Draw Pen", "Pen"); do_versions_rename_id(bmain, ID_BR, "Draw Ink", "Ink Pen"); diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index c1cc615d26a..894a80d472f 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -27,6 +27,7 @@ #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_workspace_types.h" #include "DNA_world_types.h" #include "DNA_defaults.h" @@ -50,6 +51,7 @@ #include "BKE_armature.hh" #include "BKE_attribute.hh" #include "BKE_colortools.hh" +#include "BKE_context.hh" #include "BKE_curve.hh" #include "BKE_effect.h" #include "BKE_grease_pencil.hh" @@ -59,6 +61,7 @@ #include "BKE_mesh_legacy_convert.hh" #include "BKE_nla.h" #include "BKE_node_runtime.hh" +#include "BKE_paint.hh" #include "BKE_scene.hh" #include "BKE_tracking.h" @@ -2060,6 +2063,33 @@ static bool seq_filter_bilinear_to_auto(Sequence *seq, void * /*user_data*/) return true; } +static void update_paint_modes_for_brush_assets(Main &bmain) +{ + /* Replace paint brushes with a reference to the default brush asset for that mode. */ + LISTBASE_FOREACH (Scene *, scene, &bmain.scenes) { + BKE_paint_brush_set_default_references(scene->toolsettings); + } + + /* Replace persistent tool references with the new single builtin brush tool. */ + LISTBASE_FOREACH (WorkSpace *, workspace, &bmain.workspaces) { + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { + if (tref->space_type != SPACE_VIEW3D) { + continue; + } + if (!ELEM(tref->mode, + CTX_MODE_SCULPT, + CTX_MODE_SCULPT_CURVES, + CTX_MODE_PAINT_TEXTURE, + CTX_MODE_PAINT_VERTEX, + CTX_MODE_PAINT_WEIGHT)) + { + continue; + } + STRNCPY(tref->idname, "builtin.brush"); + } + } +} + static void image_settings_avi_to_ffmpeg(Scene *scene) { if (ELEM(scene->r.im_format.imtype, R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG)) { @@ -3405,6 +3435,10 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 30)) { + update_paint_modes_for_brush_assets(*bmain); + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index 33a596fa3f6..59d483b34b3 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -21,6 +21,7 @@ #include "BLI_math_rotation.h" #include "BLI_math_vector.h" #include "BLI_math_vector_types.hh" +#include "BLI_mempool.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -451,43 +452,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) BLO_update_defaults_workspace(workspace, app_template); } - /* New grease pencil brushes and vertex paint setup. */ + /* Grease pencil materials and paint modes setup. */ { - /* Update Grease Pencil brushes. */ - Brush *brush; - - /* Pencil brush. */ - do_versions_rename_id(bmain, ID_BR, "Draw Pencil", "Pencil"); - - /* Pen brush. */ - do_versions_rename_id(bmain, ID_BR, "Draw Pen", "Pen"); - - /* Pen Soft brush. */ - brush = reinterpret_cast( - do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft")); - if (brush) { - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; - } - - /* Ink Pen brush. */ - do_versions_rename_id(bmain, ID_BR, "Draw Ink", "Ink Pen"); - - /* Ink Pen Rough brush. */ - do_versions_rename_id(bmain, ID_BR, "Draw Noise", "Ink Pen Rough"); - - /* Marker Bold brush. */ - do_versions_rename_id(bmain, ID_BR, "Draw Marker", "Marker Bold"); - - /* Marker Chisel brush. */ - do_versions_rename_id(bmain, ID_BR, "Draw Block", "Marker Chisel"); - - /* Remove useless Fill Area.001 brush. */ - brush = static_cast( - BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2)); - if (brush) { - BKE_id_delete(bmain, brush); - } - /* Rename and fix materials and enable default object lights on. */ if (app_template && STREQ(app_template, "2D_Animation")) { Material *ma = nullptr; @@ -538,23 +504,10 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } } - /* Reset all grease pencil brushes. */ + /* Reset grease pencil paint modes. */ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { ToolSettings *ts = scene->toolsettings; - if (ts->gp_paint) { - BKE_brush_gpencil_paint_presets(bmain, ts, true); - } - if (ts->gp_sculptpaint) { - BKE_brush_gpencil_sculpt_presets(bmain, ts, true); - } - if (ts->gp_vertexpaint) { - BKE_brush_gpencil_vertex_presets(bmain, ts, true); - } - if (ts->gp_weightpaint) { - BKE_brush_gpencil_weight_presets(bmain, ts, true); - } - /* Ensure new Paint modes. */ BKE_paint_ensure_from_paintmode(bmain, scene, PaintMode::VertexGPencil); BKE_paint_ensure_from_paintmode(bmain, scene, PaintMode::SculptGPencil); @@ -710,203 +663,24 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) /* Brushes */ { - /* Enable for UV sculpt (other brush types will be created as needed), - * without this the grab brush will be active but not selectable from the list. */ - const char *brush_name = "Grab"; - Brush *brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (brush) { - brush->ob_mode |= OB_MODE_EDIT; - } - } - - LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { - brush->blur_kernel_radius = 2; - - /* Use full strength for all non-sculpt brushes, - * when painting we want to use full color/weight always. - * - * Note that sculpt is an exception, - * its values are overwritten by #BKE_brush_sculpt_reset below. */ - brush->alpha = 1.0; - - /* Enable anti-aliasing by default. */ - brush->sampling_flag |= BRUSH_PAINT_ANTIALIASING; - - /* By default, each brush should use a single input sample. */ - brush->input_samples = 1; - } - - { - /* Change the spacing of the Smear brush to 3.0% */ - const char *brush_name; - Brush *brush; - - brush_name = "Smear"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (brush) { - brush->spacing = 3.0; - } - - brush_name = "Draw Sharp"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_DRAW_SHARP; - } - - brush_name = "Elastic Deform"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_ELASTIC_DEFORM; - } - - brush_name = "Pose"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_POSE; - } - - brush_name = "Multi-plane Scrape"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_MULTIPLANE_SCRAPE; - } - - brush_name = "Clay Thumb"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_CLAY_THUMB; - } - - brush_name = "Cloth"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_CLOTH; - } - - brush_name = "Slide Relax"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_SLIDE_RELAX; - } - - brush_name = "Paint"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_PAINT; - } - - brush_name = "Smear"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_SMEAR; - } - - brush_name = "Boundary"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_BOUNDARY; - } - - brush_name = "Simplify"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_SIMPLIFY; - } - - brush_name = "Draw Face Sets"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_DRAW_FACE_SETS; - } - - brush_name = "Multires Displacement Eraser"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER; - } - - brush_name = "Multires Displacement Smear"; - brush = static_cast( - BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); - if (!brush) { - brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); - id_us_min(&brush->id); - brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_SMEAR; - } - } - - { - LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { - /* Use the same tool icon color in the brush cursor */ - if (brush->ob_mode & OB_MODE_SCULPT) { - BLI_assert(brush->sculpt_tool != 0); - BKE_brush_sculpt_reset(brush); + /* Remove default brushes replaced by assets. Also remove outliner `treestore` that may point + * to brushes. Normally the treestore is updated properly but it doesn't seem to update during + * versioning code. It's not helpful anyway. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space_link, &area->spacedata) { + if (space_link->spacetype == SPACE_OUTLINER) { + SpaceOutliner *space_outliner = reinterpret_cast(space_link); + if (space_outliner->treestore) { + BLI_mempool_destroy(space_outliner->treestore); + space_outliner->treestore = nullptr; + } + } + } } - - /* Set the default texture mapping. - * Do it for all brushes, since some of them might be coming from the startup file. */ - brush->mtex.brush_map_mode = MTEX_MAP_MODE_VIEW; - brush->mask_mtex.brush_map_mode = MTEX_MAP_MODE_VIEW; } - } - - { - const Brush *default_brush = DNA_struct_default_get(Brush); - LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { - brush->automasking_start_normal_limit = default_brush->automasking_start_normal_limit; - brush->automasking_start_normal_falloff = default_brush->automasking_start_normal_falloff; - - brush->automasking_view_normal_limit = default_brush->automasking_view_normal_limit; - brush->automasking_view_normal_falloff = default_brush->automasking_view_normal_falloff; - } - } - - { - LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { - if (!brush->automasking_cavity_curve) { - brush->automasking_cavity_curve = BKE_sculpt_default_cavity_curve(); - } + LISTBASE_FOREACH_MUTABLE (Brush *, brush, &bmain->brushes) { + BKE_id_delete(bmain, brush); } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index 389d1a6a70c..07a3762495c 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -950,6 +950,15 @@ void blo_do_versions_userdef(UserDef *userdef) } } + { + BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + userdef, "VIEW3D_AST_brush_sculpt", "Brushes/Mesh/Sculpt/Cloth"); + BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + userdef, "VIEW3D_AST_brush_sculpt", "Brushes/Mesh/Sculpt/General"); + BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + userdef, "VIEW3D_AST_brush_sculpt", "Brushes/Mesh/Sculpt/Painting"); + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a USER_VERSION_ATLEAST check. diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index 1ad84a1c0d2..3e387636b46 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -34,6 +34,7 @@ set(SRC intern/asset_shelf.cc intern/asset_shelf_asset_view.cc intern/asset_shelf_catalog_selector.cc + intern/asset_shelf_popup.cc intern/asset_shelf_regiondata.cc intern/asset_shelf_settings.cc intern/asset_temp_id_consumer.cc diff --git a/source/blender/editors/asset/ED_asset_shelf.hh b/source/blender/editors/asset/ED_asset_shelf.hh index a9a3751d0a6..0c4d8817197 100644 --- a/source/blender/editors/asset/ED_asset_shelf.hh +++ b/source/blender/editors/asset/ED_asset_shelf.hh @@ -21,6 +21,7 @@ struct BlendDataReader; struct BlendWriter; struct Main; struct SpaceType; +struct uiBlock; struct RegionPollParams; struct wmWindowManager; @@ -73,15 +74,25 @@ void header_regiontype_register(ARegionType *region_type, const int space_type); void type_register(std::unique_ptr type); void type_unregister(const AssetShelfType &shelf_type); /** - * Poll an asset shelf type for display as a permanent region in a space of a given type (the - * type's #bl_space_type). + * Poll an asset shelf type for display as a popup. Doesn't check for space-type (the type's + * #bl_space_type) since popups should ignore this to allow displaying in any space. + * + * Permanent/non-popup asset shelf regions should use #type_poll_for_space_type() instead. */ -bool type_poll(const bContext &C, const AssetShelfType *shelf_type, const int space_type); - +bool type_poll_for_popup(const bContext &C, const AssetShelfType *shelf_type); AssetShelfType *type_find_from_idname(const StringRef idname); /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Asset Shelf Popup + * \{ */ + +uiBlock *popup_block_create(const bContext *C, ARegion *region, AssetShelfType *shelf_type); +void type_popup_unlink(const AssetShelfType &shelf_type); + +/** \} */ + /* -------------------------------------------------------------------- */ void type_unlink(const Main &bmain, const AssetShelfType &shelf_type); diff --git a/source/blender/editors/asset/ED_asset_type.hh b/source/blender/editors/asset/ED_asset_type.hh index bc77dc35a3a..23ac0c94aa3 100644 --- a/source/blender/editors/asset/ED_asset_type.hh +++ b/source/blender/editors/asset/ED_asset_type.hh @@ -16,7 +16,8 @@ namespace blender::ed::asset { bool id_type_is_non_experimental(const ID *id); #define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS \ - (FILTER_ID_MA | FILTER_ID_GR | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO | FILTER_ID_NT) + (FILTER_ID_BR | FILTER_ID_MA | FILTER_ID_GR | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO | \ + FILTER_ID_NT) /** * Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset, @@ -39,6 +40,6 @@ int64_t types_supported_as_filter_flags(); * Should start with a consonant, so usages can prefix it with "a" (not "an"). */ #define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING \ - "Material, Collection, Object, Pose Action, Node Group or World" + "Material, Collection, Object, Brush, Pose Action, Node Group or World" } // namespace blender::ed::asset diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 419f5094d7c..5209e612d77 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -272,6 +272,7 @@ void AssetList::clear(const bContext *C) filelist_readjob_stop(files, CTX_wm_manager(C)); filelist_freelib(files); filelist_clear(files); + filelist_tag_force_reset(files); WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST, nullptr); } diff --git a/source/blender/editors/asset/intern/asset_shelf.cc b/source/blender/editors/asset/intern/asset_shelf.cc index 685e1b85f84..3be22915f14 100644 --- a/source/blender/editors/asset/intern/asset_shelf.cc +++ b/source/blender/editors/asset/intern/asset_shelf.cc @@ -13,6 +13,7 @@ #include "AS_asset_catalog_path.hh" #include "AS_asset_library.hh" +#include "BLI_function_ref.hh" #include "BLI_string.h" #include "BKE_context.hh" @@ -76,14 +77,11 @@ void type_unregister(const AssetShelfType &shelf_type) shelf_types.remove(it - shelf_types.begin()); } -bool type_poll(const bContext &C, const AssetShelfType *shelf_type, const int space_type) +static bool type_poll_no_spacetype_check(const bContext &C, const AssetShelfType *shelf_type) { if (!shelf_type) { return false; } - if (shelf_type->space_type && (space_type != shelf_type->space_type)) { - return false; - } #ifndef NDEBUG const Vector> &shelf_types = static_shelf_types(); @@ -98,6 +96,31 @@ bool type_poll(const bContext &C, const AssetShelfType *shelf_type, const int sp return !shelf_type->poll || shelf_type->poll(&C, shelf_type); } +bool type_poll_for_popup(const bContext &C, const AssetShelfType *shelf_type) +{ + return type_poll_no_spacetype_check(C, shelf_type); +} + +/** + * Poll an asset shelf type for display as a permanent region in a space of a given type (the + * type's #bl_space_type). + * + * Popup asset shelves should use #type_poll_for_popup() instead. + */ +static bool type_poll_for_non_popup(const bContext &C, + const AssetShelfType *shelf_type, + const int space_type) +{ + if (!shelf_type) { + return false; + } + if (shelf_type->space_type && (space_type != shelf_type->space_type)) { + return false; + } + + return type_poll_no_spacetype_check(C, shelf_type); +} + AssetShelfType *type_find_from_idname(const StringRef idname) { for (const std::unique_ptr &shelf_type : static_shelf_types()) { @@ -186,7 +209,8 @@ static AssetShelf *update_active_shelf(const bContext &C, /* Case 1: */ if (shelf_regiondata.active_shelf && - type_poll(C, ensure_shelf_has_type(*shelf_regiondata.active_shelf), space_type)) + type_poll_for_non_popup( + C, ensure_shelf_has_type(*shelf_regiondata.active_shelf), space_type)) { /* Not a strong precondition, but if this is wrong something weird might be going on. */ BLI_assert(shelf_regiondata.active_shelf == shelf_regiondata.shelves.first); @@ -200,7 +224,7 @@ static AssetShelf *update_active_shelf(const bContext &C, continue; } - if (type_poll(C, ensure_shelf_has_type(*shelf), space_type)) { + if (type_poll_for_non_popup(C, ensure_shelf_has_type(*shelf), space_type)) { /* Found a valid previously activated shelf, reactivate it. */ activate_shelf(shelf_regiondata, *shelf); return shelf; @@ -209,7 +233,7 @@ static AssetShelf *update_active_shelf(const bContext &C, /* Case 3: */ for (const std::unique_ptr &shelf_type : static_shelf_types()) { - if (type_poll(C, shelf_type.get(), space_type)) { + if (type_poll_for_non_popup(C, shelf_type.get(), space_type)) { AssetShelf *new_shelf = create_shelf_from_type(*shelf_type); BLI_addhead(&shelf_regiondata.shelves, new_shelf); /* Moves ownership to the regiondata. */ @@ -258,7 +282,7 @@ static bool asset_shelf_space_poll(const bContext *C, const SpaceLink *space_lin { /* Is there any asset shelf type registered that returns true for it's poll? */ for (const std::unique_ptr &shelf_type : static_shelf_types()) { - if (type_poll(*C, shelf_type.get(), space_link->spacetype)) { + if (type_poll_for_non_popup(*C, shelf_type.get(), space_link->spacetype)) { return true; } } @@ -842,6 +866,8 @@ void type_unlink(const Main &bmain, const AssetShelfType &shelf_type) } } } + + type_popup_unlink(shelf_type); } /** \} */ diff --git a/source/blender/editors/asset/intern/asset_shelf.hh b/source/blender/editors/asset/intern/asset_shelf.hh index 234e345ad55..9270d631861 100644 --- a/source/blender/editors/asset/intern/asset_shelf.hh +++ b/source/blender/editors/asset/intern/asset_shelf.hh @@ -46,6 +46,8 @@ void send_redraw_notifier(const bContext &C); AssetShelfType *ensure_shelf_has_type(AssetShelf &shelf); AssetShelf *create_shelf_from_type(AssetShelfType &type); +void library_selector_draw(const bContext *C, uiLayout *layout, AssetShelf &shelf); + /** * Deep-copies \a shelf_regiondata into newly allocated memory. Must be freed using * #regiondata_free(). diff --git a/source/blender/editors/asset/intern/asset_shelf_asset_view.cc b/source/blender/editors/asset/intern/asset_shelf_asset_view.cc index 34599b015d9..12a871e9dfa 100644 --- a/source/blender/editors/asset/intern/asset_shelf_asset_view.cc +++ b/source/blender/editors/asset/intern/asset_shelf_asset_view.cc @@ -11,6 +11,7 @@ #include "AS_asset_library.hh" #include "AS_asset_representation.hh" +#include "BKE_asset.hh" #include "BKE_screen.hh" #include "BLI_fnmatch.h" @@ -44,12 +45,13 @@ class AssetView : public ui::AbstractGridView { * end of the string, for `fnmatch()` to work. */ char search_string[sizeof(AssetShelfSettings::search_string) + 2] = ""; std::optional catalog_filter_ = std::nullopt; + bool is_popup_ = false; friend class AssetViewItem; friend class AssetDragController; public: - AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf); + AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf, bool is_popup); void build_items() override; bool begin_filtering(const bContext &C) const override; @@ -70,6 +72,7 @@ class AssetViewItem : public ui::PreviewGridItem { void disable_asset_drag(); void build_grid_tile(uiLayout &layout) const override; void build_context_menu(bContext &C, uiLayout &column) const override; + void on_activate(bContext &C) override; std::optional should_be_active() const override; bool is_filtered_visible() const override; @@ -86,8 +89,10 @@ class AssetDragController : public ui::AbstractViewItemDragController { void *create_drag_data() const override; }; -AssetView::AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf) - : library_ref_(library_ref), shelf_(shelf) +AssetView::AssetView(const AssetLibraryReference &library_ref, + const AssetShelf &shelf, + const bool is_popup) + : library_ref_(library_ref), shelf_(shelf), is_popup_(is_popup) { if (shelf.settings.search_string[0]) { BLI_strncpy_ensure_pad( @@ -236,6 +241,14 @@ void AssetViewItem::build_context_menu(bContext &C, uiLayout &column) const } } +void AssetViewItem::on_activate(bContext & /*C*/) +{ + const AssetView &asset_view = dynamic_cast(this->get_view()); + if (asset_view.is_popup_) { + UI_popup_menu_close_from_but(reinterpret_cast(this->view_item_button())); + } +} + std::optional AssetViewItem::should_be_active() const { const AssetView &asset_view = dynamic_cast(this->get_view()); @@ -290,7 +303,8 @@ void build_asset_view(uiLayout &layout, BLI_assert(tile_width != 0); BLI_assert(tile_height != 0); - std::unique_ptr asset_view = std::make_unique(library_ref, shelf); + const bool is_popup = region.regiontype == RGN_TYPE_TEMPORARY; + std::unique_ptr asset_view = std::make_unique(library_ref, shelf, is_popup); asset_view->set_catalog_filter(catalog_filter_from_shelf_settings(shelf.settings, *library)); asset_view->set_tile_size(tile_width, tile_height); diff --git a/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc b/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc index 9446f75cb2e..4a9c4c6e60a 100644 --- a/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc +++ b/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc @@ -174,32 +174,37 @@ void AssetCatalogSelectorTree::update_shelf_settings_from_enabled_catalogs() }); } +void library_selector_draw(const bContext *C, uiLayout *layout, AssetShelf &shelf) +{ + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + PointerRNA shelf_ptr = RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_AssetShelf, &shelf); + + uiLayout *row = uiLayoutRow(layout, true); + uiItemR(row, &shelf_ptr, "asset_library_reference", UI_ITEM_NONE, "", ICON_NONE); + if (shelf.settings.asset_library_reference.type != ASSET_LIBRARY_LOCAL) { + uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh"); + } +} + static void catalog_selector_panel_draw(const bContext *C, Panel *panel) { - const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C); AssetShelf *shelf = active_shelf_from_context(C); if (!shelf) { return; } uiLayout *layout = panel->layout; - uiBlock *block = uiLayoutGetBlock(layout); - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + library_selector_draw(C, layout, *shelf); - PointerRNA shelf_ptr = RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_AssetShelf, shelf); - - uiLayout *row = uiLayoutRow(layout, true); - uiItemR(row, &shelf_ptr, "asset_library_reference", UI_ITEM_NONE, "", ICON_NONE); - if (library_ref->type != ASSET_LIBRARY_LOCAL) { - uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh"); - } - - asset_system::AssetLibrary *library = list::library_get_once_available(*library_ref); + asset_system::AssetLibrary *library = list::library_get_once_available( + shelf->settings.asset_library_reference); if (!library) { return; } + uiBlock *block = uiLayoutGetBlock(layout); ui::AbstractTreeView *tree_view = UI_block_add_view( *block, "asset catalog tree view", diff --git a/source/blender/editors/asset/intern/asset_shelf_popup.cc b/source/blender/editors/asset/intern/asset_shelf_popup.cc new file mode 100644 index 00000000000..c4c989a4a4e --- /dev/null +++ b/source/blender/editors/asset/intern/asset_shelf_popup.cc @@ -0,0 +1,208 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edasset + */ + +#include "asset_shelf.hh" + +#include "BKE_screen.hh" + +#include "BLT_translation.hh" + +#include "UI_interface_c.hh" +#include "UI_tree_view.hh" + +#include "ED_asset_filter.hh" +#include "ED_asset_list.hh" +#include "ED_asset_shelf.hh" + +#include "RNA_access.hh" +#include "RNA_prototypes.h" + +namespace blender::ed::asset::shelf { + +class StaticPopupShelves { + public: + Vector popup_shelves; + + ~StaticPopupShelves() + { + for (AssetShelf *shelf : popup_shelves) { + MEM_delete(shelf); + } + } + + static Vector &shelves() + { + static StaticPopupShelves storage; + return storage.popup_shelves; + } +}; + +void type_popup_unlink(const AssetShelfType &shelf_type) +{ + for (AssetShelf *shelf : StaticPopupShelves::shelves()) { + if (shelf->type == &shelf_type) { + shelf->type = nullptr; + } + } +} + +static AssetShelf *get_shelf_for_popup(const bContext *C, AssetShelfType &shelf_type) +{ + Vector &popup_shelves = StaticPopupShelves::shelves(); + + for (AssetShelf *shelf : popup_shelves) { + if (STREQ(shelf->idname, shelf_type.idname)) { + if (type_poll_for_popup(*C, ensure_shelf_has_type(*shelf))) { + return shelf; + } + break; + } + } + + if (type_poll_for_popup(*C, &shelf_type)) { + AssetShelf *new_shelf = create_shelf_from_type(shelf_type); + new_shelf->settings.display_flag |= ASSETSHELF_SHOW_NAMES; + popup_shelves.append(new_shelf); + return new_shelf; + } + + return nullptr; +} + +class AssetCatalogTreeView : public ui::AbstractTreeView { + AssetShelf &shelf_; + asset_system::AssetCatalogTree catalog_tree_; + + public: + AssetCatalogTreeView(const asset_system::AssetLibrary &library, AssetShelf &shelf) + : shelf_(shelf) + { + catalog_tree_ = build_filtered_catalog_tree( + library, + shelf_.settings.asset_library_reference, + [this](const asset_system::AssetRepresentation &asset) { + return (!shelf_.type->asset_poll || shelf_.type->asset_poll(shelf_.type, &asset)); + }); + } + + void build_tree() override + { + if (catalog_tree_.is_empty()) { + auto &item = this->add_tree_item(RPT_("No applicable assets found"), + ICON_INFO); + item.disable_interaction(); + return; + } + + auto &all_item = this->add_tree_item(IFACE_("All")); + all_item.set_on_activate_fn([this](bContext &C, ui::BasicTreeViewItem &) { + settings_set_all_catalog_active(shelf_.settings); + send_redraw_notifier(C); + }); + all_item.set_is_active_fn( + [this]() { return settings_is_all_catalog_active(shelf_.settings); }); + all_item.uncollapse_by_default(); + + catalog_tree_.foreach_root_item([&, this]( + const asset_system::AssetCatalogTreeItem &catalog_item) { + ui::BasicTreeViewItem &item = this->build_catalog_items_recursive(all_item, catalog_item); + item.uncollapse_by_default(); + }); + } + + ui::BasicTreeViewItem &build_catalog_items_recursive( + ui::TreeViewOrItem &parent_view_item, + const asset_system::AssetCatalogTreeItem &catalog_item) const + { + ui::BasicTreeViewItem &view_item = parent_view_item.add_tree_item( + catalog_item.get_name()); + + std::string catalog_path = catalog_item.catalog_path().str(); + view_item.set_on_activate_fn([this, catalog_path](bContext &C, ui::BasicTreeViewItem &) { + settings_set_active_catalog(shelf_.settings, catalog_path); + send_redraw_notifier(C); + }); + view_item.set_is_active_fn([this, catalog_path]() { + return settings_is_active_catalog(shelf_.settings, catalog_path); + }); + + catalog_item.foreach_child( + [&view_item, this](const asset_system::AssetCatalogTreeItem &child) { + build_catalog_items_recursive(view_item, child); + }); + + return view_item; + } +}; + +static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf) +{ + const asset_system::AssetLibrary *library = list::library_get_once_available( + shelf.settings.asset_library_reference); + if (!library) { + return; + } + + uiBlock *block = uiLayoutGetBlock(&layout); + ui::AbstractTreeView *tree_view = UI_block_add_view( + *block, + "asset shelf catalog tree view", + std::make_unique(*library, shelf)); + + ui::TreeViewBuilder::build_tree_view(*tree_view, layout); +} + +uiBlock *popup_block_create(const bContext *C, ARegion *region, AssetShelfType *shelf_type) +{ + bScreen *screen = CTX_wm_screen(C); + uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER); + UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); + UI_block_bounds_set_normal(block, 0.3f * U.widget_unit); + UI_block_direction_set(block, UI_DIR_DOWN); + + AssetShelf *shelf = get_shelf_for_popup(C, *shelf_type); + if (!shelf) { + BLI_assert_unreachable(); + return block; + } + + const uiStyle *style = UI_style_get_dpi(); + + const int layout_width = UI_UNIT_X * 40; + const int left_col_width = 10 * UI_UNIT_X; + const int right_col_width = layout_width - left_col_width; + uiLayout *layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, layout_width, 0, 0, style); + + PointerRNA library_ref_ptr = RNA_pointer_create( + &screen->id, &RNA_AssetLibraryReference, &shelf->settings.asset_library_reference); + uiLayoutSetContextPointer(layout, "asset_library_reference", &library_ref_ptr); + + uiLayout *row = uiLayoutRow(layout, false); + uiLayout *catalogs_col = uiLayoutColumn(row, false); + uiLayoutSetUnitsX(catalogs_col, left_col_width / UI_UNIT_X); + uiLayoutSetFixedSize(catalogs_col, true); + library_selector_draw(C, catalogs_col, *shelf); + catalog_tree_draw(*catalogs_col, *shelf); + + uiLayout *right_col = uiLayoutColumn(row, false); + uiLayout *sub = uiLayoutRow(right_col, false); + /* Same as file/asset browser header. */ + PointerRNA shelf_ptr = RNA_pointer_create(&screen->id, &RNA_AssetShelf, shelf); + uiItemR(sub, &shelf_ptr, "search_filter", UI_ITEM_R_IMMEDIATE, "", ICON_VIEWZOOM); + + uiLayout *asset_view_col = uiLayoutColumn(right_col, false); + uiLayoutSetUnitsX(asset_view_col, right_col_width / UI_UNIT_X); + uiLayoutSetFixedSize(asset_view_col, true); + build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C, *region); + + return block; +} + +} // namespace blender::ed::asset::shelf diff --git a/source/blender/editors/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc index bca873e615b..2fb73c9e646 100644 --- a/source/blender/editors/asset/intern/asset_type.cc +++ b/source/blender/editors/asset/intern/asset_type.cc @@ -20,7 +20,7 @@ bool id_type_is_non_experimental(const ID *id) { /* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and * #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS() with this! */ - return ELEM(GS(id->name), ID_MA, ID_GR, ID_OB, ID_AC, ID_WO, ID_NT); + return ELEM(GS(id->name), ID_BR, ID_MA, ID_GR, ID_OB, ID_AC, ID_WO, ID_NT); } bool id_type_is_supported(const ID *id) diff --git a/source/blender/editors/gpencil_legacy/gpencil_data.cc b/source/blender/editors/gpencil_legacy/gpencil_data.cc index 2514a98bdba..b9102befc31 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_data.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_data.cc @@ -1952,283 +1952,6 @@ void GPENCIL_OT_material_lock_unused(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************ */ -/* Drawing Brushes Operators */ - -/* ******************* Brush resets ************************** */ -static int gpencil_brush_reset_exec(bContext *C, wmOperator * /*op*/) -{ - Main *bmain = CTX_data_main(C); - ToolSettings *ts = CTX_data_tool_settings(C); - const enum eContextObjectMode mode = CTX_data_mode_enum(C); - - switch (mode) { - case CTX_MODE_PAINT_GPENCIL_LEGACY: { - Paint *paint = &ts->gp_paint->paint; - Brush *brush = BKE_paint_brush(paint); - if (brush && brush->gpencil_settings) { - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); - } - break; - } - case CTX_MODE_SCULPT_GPENCIL_LEGACY: { - Paint *paint = &ts->gp_sculptpaint->paint; - Brush *brush = BKE_paint_brush(paint); - if (brush && brush->gpencil_settings) { - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); - } - break; - } - case CTX_MODE_WEIGHT_GPENCIL_LEGACY: { - Paint *paint = &ts->gp_weightpaint->paint; - Brush *brush = BKE_paint_brush(paint); - if (brush && brush->gpencil_settings) { - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); - } - break; - } - case CTX_MODE_VERTEX_GPENCIL_LEGACY: { - Paint *paint = &ts->gp_vertexpaint->paint; - Brush *brush = BKE_paint_brush(paint); - if (brush && brush->gpencil_settings) { - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); - } - break; - } - default: - break; - } - - /* notifiers */ - WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_brush_reset(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Reset Brush"; - ot->idname = "GPENCIL_OT_brush_reset"; - ot->description = "Reset brush to default parameters"; - - /* api callbacks */ - ot->exec = gpencil_brush_reset_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static Brush *gpencil_brush_get_first_by_mode(Main *bmain, - Paint * /*paint*/, - const enum eContextObjectMode mode, - char tool) -{ - Brush *brush_next = nullptr; - for (Brush *brush = static_cast(bmain->brushes.first); brush; brush = brush_next) { - brush_next = static_cast(brush->id.next); - - if (brush->gpencil_settings == nullptr) { - continue; - } - - if ((mode == CTX_MODE_PAINT_GPENCIL_LEGACY) && (brush->gpencil_tool == tool)) { - return brush; - } - - if ((mode == CTX_MODE_SCULPT_GPENCIL_LEGACY) && (brush->gpencil_sculpt_tool == tool)) { - return brush; - } - - if ((mode == CTX_MODE_WEIGHT_GPENCIL_LEGACY) && (brush->gpencil_weight_tool == tool)) { - return brush; - } - - if ((mode == CTX_MODE_VERTEX_GPENCIL_LEGACY) && (brush->gpencil_vertex_tool == tool)) { - return brush; - } - } - - return nullptr; -} - -static void gpencil_brush_delete_mode_brushes(Main *bmain, - Paint *paint, - const enum eContextObjectMode mode) -{ - Brush *brush_active = BKE_paint_brush(paint); - Brush *brush_next = nullptr; - for (Brush *brush = static_cast(bmain->brushes.first); brush; brush = brush_next) { - brush_next = static_cast(brush->id.next); - - if ((brush->gpencil_settings == nullptr) && (brush->ob_mode != OB_MODE_PAINT_GPENCIL_LEGACY)) { - continue; - } - - short preset = (brush->gpencil_settings) ? brush->gpencil_settings->preset_type : - short(GP_BRUSH_PRESET_UNKNOWN); - - if (preset != GP_BRUSH_PRESET_UNKNOWN) { - /* Verify to delete only the brushes of the current mode. */ - if (mode == CTX_MODE_PAINT_GPENCIL_LEGACY) { - if ((preset < GP_BRUSH_PRESET_AIRBRUSH) || (preset > GP_BRUSH_PRESET_TINT)) { - continue; - } - if ((brush_active) && (brush_active->gpencil_tool != brush->gpencil_tool)) { - continue; - } - } - - if (mode == CTX_MODE_SCULPT_GPENCIL_LEGACY) { - if ((preset < GP_BRUSH_PRESET_SMOOTH_STROKE) || (preset > GP_BRUSH_PRESET_CLONE_STROKE)) { - continue; - } - if ((brush_active) && (brush_active->gpencil_sculpt_tool != brush->gpencil_sculpt_tool)) { - continue; - } - } - - if (mode == CTX_MODE_WEIGHT_GPENCIL_LEGACY) { - if ((preset < GP_BRUSH_PRESET_WEIGHT_DRAW) || (preset > GP_BRUSH_PRESET_WEIGHT_SMEAR)) { - continue; - } - if ((brush_active) && (brush_active->gpencil_weight_tool != brush->gpencil_weight_tool)) { - continue; - } - } - - if (mode == CTX_MODE_VERTEX_GPENCIL_LEGACY) { - if ((preset < GP_BRUSH_PRESET_VERTEX_DRAW) || (preset > GP_BRUSH_PRESET_VERTEX_REPLACE)) { - continue; - } - if ((brush_active) && (brush_active->gpencil_vertex_tool != brush->gpencil_vertex_tool)) { - continue; - } - } - } - - /* Before delete, un-pin any material of the brush. */ - if ((brush->gpencil_settings) && (brush->gpencil_settings->material != nullptr)) { - brush->gpencil_settings->material = nullptr; - brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED; - } - - BKE_brush_delete(bmain, brush); - if (brush == brush_active) { - brush_active = nullptr; - } - } -} - -static int gpencil_brush_reset_all_exec(bContext *C, wmOperator * /*op*/) -{ - Main *bmain = CTX_data_main(C); - ToolSettings *ts = CTX_data_tool_settings(C); - const enum eContextObjectMode mode = CTX_data_mode_enum(C); - Paint *paint = nullptr; - - switch (mode) { - case CTX_MODE_PAINT_GPENCIL_LEGACY: { - paint = &ts->gp_paint->paint; - break; - } - case CTX_MODE_SCULPT_GPENCIL_LEGACY: { - paint = &ts->gp_sculptpaint->paint; - break; - } - case CTX_MODE_WEIGHT_GPENCIL_LEGACY: { - paint = &ts->gp_weightpaint->paint; - break; - } - case CTX_MODE_VERTEX_GPENCIL_LEGACY: { - paint = &ts->gp_vertexpaint->paint; - break; - } - default: - break; - } - - char tool = '0'; - if (paint) { - Brush *brush_active = BKE_paint_brush(paint); - if (brush_active) { - switch (mode) { - case CTX_MODE_PAINT_GPENCIL_LEGACY: { - tool = brush_active->gpencil_tool; - break; - } - case CTX_MODE_SCULPT_GPENCIL_LEGACY: { - tool = brush_active->gpencil_sculpt_tool; - break; - } - case CTX_MODE_WEIGHT_GPENCIL_LEGACY: { - tool = brush_active->gpencil_weight_tool; - break; - } - case CTX_MODE_VERTEX_GPENCIL_LEGACY: { - tool = brush_active->gpencil_vertex_tool; - break; - } - default: { - tool = brush_active->gpencil_tool; - break; - } - } - } - - gpencil_brush_delete_mode_brushes(bmain, paint, mode); - - switch (mode) { - case CTX_MODE_PAINT_GPENCIL_LEGACY: { - BKE_brush_gpencil_paint_presets(bmain, ts, true); - break; - } - case CTX_MODE_SCULPT_GPENCIL_LEGACY: { - BKE_brush_gpencil_sculpt_presets(bmain, ts, true); - break; - } - case CTX_MODE_WEIGHT_GPENCIL_LEGACY: { - BKE_brush_gpencil_weight_presets(bmain, ts, true); - break; - } - case CTX_MODE_VERTEX_GPENCIL_LEGACY: { - BKE_brush_gpencil_vertex_presets(bmain, ts, true); - break; - } - default: { - break; - } - } - - BKE_paint_brush_validate(bmain, paint); - - /* Set Again the first brush of the mode. */ - Brush *deft_brush = gpencil_brush_get_first_by_mode(bmain, paint, mode, tool); - if (deft_brush) { - BKE_paint_brush_set(paint, deft_brush); - } - /* notifiers */ - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr); - } - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_brush_reset_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Reset All Brushes"; - ot->idname = "GPENCIL_OT_brush_reset_all"; - ot->description = "Delete all mode brushes and recreate a default set"; - - /* api callbacks */ - ot->exec = gpencil_brush_reset_all_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /*********************** Vertex Groups ***********************************/ static bool gpencil_vertex_group_poll(bContext *C) diff --git a/source/blender/editors/gpencil_legacy/gpencil_edit.cc b/source/blender/editors/gpencil_legacy/gpencil_edit.cc index b3ff26148d3..2703264b4af 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_edit.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_edit.cc @@ -423,16 +423,13 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_ensure(bmain, ts, (Paint **)&ts->gp_paint); BKE_paint_ensure(bmain, ts, (Paint **)&ts->gp_vertexpaint); - BKE_brush_gpencil_paint_presets(bmain, ts, false); - /* Ensure Palette by default. */ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); Paint *paint = &ts->gp_paint->paint; Brush *brush = BKE_paint_brush(paint); - /* if not exist, create a new one */ - if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) { - BKE_brush_gpencil_paint_presets(bmain, ts, true); + if (brush && !brush->gpencil_settings) { + BKE_brush_init_gpencil_settings(brush); } BKE_paint_brush_validate(bmain, &ts->gp_paint->paint); } @@ -573,10 +570,6 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) if (mode == OB_MODE_SCULPT_GPENCIL_LEGACY) { /* Be sure we have brushes. */ BKE_paint_ensure(bmain, ts, (Paint **)&ts->gp_sculptpaint); - - const bool reset_mode = (BKE_paint_brush(&ts->gp_sculptpaint->paint) == nullptr); - BKE_brush_gpencil_sculpt_presets(bmain, ts, reset_mode); - BKE_paint_brush_validate(bmain, &ts->gp_sculptpaint->paint); } @@ -717,9 +710,6 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) ED_paint_cursor_start(weight_paint, grease_pencil_poll_weight_cursor); } - const bool reset_mode = (BKE_paint_brush(weight_paint) == nullptr); - BKE_brush_gpencil_weight_presets(bmain, ts, reset_mode); - BKE_paint_brush_validate(bmain, weight_paint); } @@ -832,9 +822,6 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_ensure(bmain, ts, (Paint **)&ts->gp_paint); BKE_paint_ensure(bmain, ts, (Paint **)&ts->gp_vertexpaint); - const bool reset_mode = (BKE_paint_brush(&ts->gp_vertexpaint->paint) == nullptr); - BKE_brush_gpencil_vertex_presets(bmain, ts, reset_mode); - BKE_paint_brush_validate(bmain, &ts->gp_vertexpaint->paint); /* Ensure Palette by default. */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_fill.cc b/source/blender/editors/gpencil_legacy/gpencil_fill.cc index b0c66af13c9..d8cc90ab544 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_fill.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_fill.cc @@ -26,6 +26,7 @@ #include "DNA_object_types.h" #include "DNA_windowmanager_types.h" +#include "BKE_brush.hh" #include "BKE_context.hh" #include "BKE_deform.hh" #include "BKE_gpencil_geom_legacy.h" @@ -2405,6 +2406,9 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op) /* save filling parameters */ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); + if (brush && !brush->gpencil_settings) { + BKE_brush_init_gpencil_settings(brush); + } tgpf->brush = brush; tgpf->flag = brush->gpencil_settings->flag; tgpf->fill_threshold = brush->gpencil_settings->fill_threshold; diff --git a/source/blender/editors/gpencil_legacy/gpencil_intern.hh b/source/blender/editors/gpencil_legacy/gpencil_intern.hh index 5f067b177b7..48d36911c55 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_intern.hh +++ b/source/blender/editors/gpencil_legacy/gpencil_intern.hh @@ -619,9 +619,6 @@ void GPENCIL_OT_extract_palette_vertex(wmOperatorType *ot); void GPENCIL_OT_transform_fill(wmOperatorType *ot); void GPENCIL_OT_reset_transform_fill(wmOperatorType *ot); -void GPENCIL_OT_brush_reset(wmOperatorType *ot); -void GPENCIL_OT_brush_reset_all(wmOperatorType *ot); - /* undo stack ---------- */ void gpencil_undo_init(bGPdata *gpd); diff --git a/source/blender/editors/gpencil_legacy/gpencil_merge.cc b/source/blender/editors/gpencil_legacy/gpencil_merge.cc index 6e85e908ec7..dd46944cc70 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_merge.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_merge.cc @@ -85,7 +85,6 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps, static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints) { - Main *bmain = CTX_data_main(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); bGPdata *gpd = static_cast(ob->data); @@ -99,12 +98,9 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo Paint *paint = &ts->gp_paint->paint; Brush *brush = BKE_paint_brush(paint); - /* if not exist, create a new one */ - if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) { - /* create new brushes */ - BKE_brush_gpencil_paint_presets(bmain, ts, false); + if (brush && !brush->gpencil_settings) { + BKE_brush_init_gpencil_settings(brush); } - brush = BKE_paint_brush(paint); /* frame */ short add_frame_mode; diff --git a/source/blender/editors/gpencil_legacy/gpencil_ops.cc b/source/blender/editors/gpencil_legacy/gpencil_ops.cc index a50cdd40057..26de6fc6841 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_ops.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_ops.cc @@ -715,9 +715,6 @@ void ED_operatortypes_gpencil_legacy() WM_operatortype_append(GPENCIL_OT_transform_fill); WM_operatortype_append(GPENCIL_OT_reset_transform_fill); - WM_operatortype_append(GPENCIL_OT_brush_reset); - WM_operatortype_append(GPENCIL_OT_brush_reset_all); - /* vertex groups */ WM_operatortype_append(GPENCIL_OT_vertex_group_assign); WM_operatortype_append(GPENCIL_OT_vertex_group_remove_from); diff --git a/source/blender/editors/gpencil_legacy/gpencil_paint.cc b/source/blender/editors/gpencil_legacy/gpencil_paint.cc index 6470e29e59b..22cac4d295c 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_paint.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_paint.cc @@ -1914,90 +1914,17 @@ static void gpencil_session_validatebuffer(tGPsdata *p) } } -/* helper to get default eraser and create one if no eraser brush */ -static Brush *gpencil_get_default_eraser(Main *bmain, ToolSettings *ts) -{ - Brush *brush_dft = nullptr; - Paint *paint = &ts->gp_paint->paint; - Brush *brush_prev = BKE_paint_brush(paint); - for (Brush *brush = static_cast(bmain->brushes.first); brush; - brush = static_cast(brush->id.next)) - { - if (brush->gpencil_settings == nullptr) { - continue; - } - if ((brush->ob_mode == OB_MODE_PAINT_GPENCIL_LEGACY) && - (brush->gpencil_tool == GPAINT_TOOL_ERASE)) - { - /* save first eraser to use later if no default */ - if (brush_dft == nullptr) { - brush_dft = brush; - } - /* found default */ - if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) { - return brush; - } - } - } - /* if no default, but exist eraser brush, return this and set as default */ - if (brush_dft) { - brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER; - return brush_dft; - } - /* create a new soft eraser brush */ - - brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser", OB_MODE_PAINT_GPENCIL_LEGACY); - brush_dft->size = 30.0f; - brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER; - brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; - brush_dft->gpencil_tool = GPAINT_TOOL_ERASE; - brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; - - /* reset current brush */ - BKE_paint_brush_set(paint, brush_prev); - - return brush_dft; -} - -/* helper to set default eraser and disable others */ -static void gpencil_set_default_eraser(Main *bmain, Brush *brush_dft) -{ - if (brush_dft == nullptr) { - return; - } - - for (Brush *brush = static_cast(bmain->brushes.first); brush; - brush = static_cast(brush->id.next)) - { - if ((brush->gpencil_settings) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) { - if (brush == brush_dft) { - brush->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER; - } - else if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) { - brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER; - } - } - } -} - /* initialize a drawing brush */ static void gpencil_init_drawing_brush(bContext *C, tGPsdata *p) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); - Paint *paint = &ts->gp_paint->paint; - bool changed = false; Brush *brush = BKE_paint_brush(paint); - /* if not exist, create a new one */ - if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) { - /* create new brushes */ - BKE_brush_gpencil_paint_presets(bmain, ts, true); - changed = true; - brush = BKE_paint_brush(paint); + if (brush == nullptr) { + return; } + /* Be sure curves are initialized. */ BKE_curvemapping_init(brush->gpencil_settings->curve_sensitivity); BKE_curvemapping_init(brush->gpencil_settings->curve_strength); @@ -2010,23 +1937,18 @@ static void gpencil_init_drawing_brush(bContext *C, tGPsdata *p) BKE_curvemapping_init(brush->gpencil_settings->curve_rand_value); /* Assign to temp #tGPsdata */ - p->brush = BKE_paint_brush(paint); + p->brush = brush; if (p->brush->gpencil_tool != GPAINT_TOOL_ERASE) { - p->eraser = gpencil_get_default_eraser(p->bmain, ts); + /* TODO: make this work again with "Smooth Eraser" essentials brush. + * See od gpencil_set_default_eraser and gpencil_set_default_eraser. */ + p->eraser = p->brush; } else { p->eraser = p->brush; } - /* set new eraser as default */ - gpencil_set_default_eraser(p->bmain, p->eraser); /* use radius of eraser */ p->radius = short(p->eraser->size); - - /* Need this update to synchronize brush with draw manager. */ - if (changed) { - DEG_id_tag_update(&scene->id, ID_RECALC_SYNC_TO_EVAL); - } } /* initialize a paint brush and a default color if not exist */ @@ -2125,6 +2047,10 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) /* set brush and create a new one if null */ gpencil_init_drawing_brush(C, p); + if (p->brush == nullptr) { + p->status = GP_STATUS_ERROR; + return false; + } /* setup active color */ /* region where paint was originated */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_primitive.cc b/source/blender/editors/gpencil_legacy/gpencil_primitive.cc index 69ca6b636fe..6a59eb95828 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_primitive.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_primitive.cc @@ -1212,15 +1212,11 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) /* if brush doesn't exist, create a new set (fix damaged files from old versions) */ Brush *brush = BKE_paint_brush(paint); - if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) { - BKE_brush_gpencil_paint_presets(bmain, ts, true); + if (brush && !brush->gpencil_settings) { + BKE_brush_init_gpencil_settings(brush); } - /* Set Draw brush. */ - brush = BKE_paint_toolslots_brush_get(paint, 0); - - BKE_brush_tool_set(brush, paint, 0); - BKE_paint_brush_set(paint, brush); + /* Set brush. */ tgpi->brush = brush; /* control points */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.cc b/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.cc index 2f582141d53..04548eb45e8 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.cc @@ -1204,6 +1204,9 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) Paint *paint = &ts->gp_sculptpaint->paint; Brush *brush = BKE_paint_brush(paint); + if (brush && !brush->gpencil_settings) { + BKE_brush_init_gpencil_settings(brush); + } gso->brush = brush; BKE_curvemapping_init(gso->brush->curve); @@ -2177,9 +2180,10 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA * static Brush *gpencil_sculpt_get_smooth_brush(tGP_BrushEditData *gso) { Main *bmain = gso->bmain; - Brush *brush = static_cast( - BLI_findstring(&bmain->brushes, "Smooth Stroke", offsetof(ID, name) + 2)); - + Brush *brush = BKE_paint_brush_from_essentials(bmain, "Smooth Stroke"); + if (brush && !brush->gpencil_settings) { + BKE_brush_init_gpencil_settings(brush); + } return brush; } diff --git a/source/blender/editors/gpencil_legacy/gpencil_utils.cc b/source/blender/editors/gpencil_legacy/gpencil_utils.cc index 6c505caf73e..d1e06b664db 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_utils.cc +++ b/source/blender/editors/gpencil_legacy/gpencil_utils.cc @@ -1429,13 +1429,6 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob) ToolSettings *ts = CTX_data_tool_settings(C); BKE_paint_ensure(bmain, ts, (Paint **)&ts->gp_paint); - Paint *paint = &ts->gp_paint->paint; - Brush *brush = BKE_paint_brush(paint); - /* if not exist, create a new one */ - if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) { - /* create new brushes */ - BKE_brush_gpencil_paint_presets(bmain, ts, true); - } /* ensure a color exists and is assigned to object */ BKE_gpencil_object_material_ensure_from_active_input_toolsettings(bmain, ob, ts); diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_primitive.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_primitive.cc index 1bf4a8818df..184536f663d 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_primitive.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_primitive.cc @@ -676,6 +676,9 @@ static int grease_pencil_primitive_invoke(bContext *C, wmOperator *op, const wmE Paint *paint = &vc.scene->toolsettings->gp_paint->paint; ptd.brush = BKE_paint_brush(paint); + if (ptd.brush->gpencil_settings == nullptr) { + BKE_brush_init_gpencil_settings(ptd.brush); + } ptd.settings = ptd.brush->gpencil_settings; BKE_curvemapping_init(ptd.settings->curve_sensitivity); diff --git a/source/blender/editors/include/ED_util.hh b/source/blender/editors/include/ED_util.hh index a4b5b7fa2e9..d3d7e7011b9 100644 --- a/source/blender/editors/include/ED_util.hh +++ b/source/blender/editors/include/ED_util.hh @@ -121,9 +121,5 @@ void apply_keyb_grid( bool shift, bool ctrl, float *val, float fac1, float fac2, float fac3, int invert); /* where else to go ? */ -void unpack_menu(bContext *C, - const char *opname, - const char *id_name, - const char *abs_name, - const char *folder, - PackedFile *pf); +void unpack_menu( + bContext *C, const char *opname, const char *abs_name, const char *folder, PackedFile *pf); diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index 772632f32f5..804bcd92fb3 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -710,6 +710,18 @@ uiLayout *UI_popup_menu_layout(uiPopupMenu *pup); void UI_popup_menu_reports(bContext *C, ReportList *reports) ATTR_NONNULL(); int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) ATTR_NONNULL(1, 2); +/** + * If \a block is displayed in a popup menu, tag it for closing. + * \param is_cancel: If set to true, the popup will be closed as being cancelled (e.g. when + * pressing escape) as opposed to being handled successfully. + */ +void UI_popup_menu_close(const uiBlock *block, bool is_cancel = false); +/** + * Version of #UI_popup_menu_close() that can be called on a button contained in a popup menu + * block. Convenience since the block may not be available. + */ +void UI_popup_menu_close_from_but(const uiBut *but, bool is_cancel = false); + /** * Allow setting menu return value from externals. * E.g. WM might need to do this for exiting files correctly. @@ -1491,6 +1503,10 @@ uiBut *uiDefIconMenuBut(uiBlock *block, short height, const char *tip); +/** + * Note that \a fun can set the #UI_BLOCK_KEEP_OPEN flag to the block it creates, to allow + * refreshing the popup. That is, redrawing the layout, potentially affecting the popup size. + */ uiBut *uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, @@ -2706,6 +2722,13 @@ void uiTemplateAssetView(uiLayout *layout, const char *drag_opname, PointerRNA *r_drag_op_properties); +namespace blender::ui { + +void template_asset_shelf_popover( + uiLayout &layout, const bContext &C, StringRefNull asset_shelf_id, StringRef name, int icon); + +} + void uiTemplateLightLinkingCollection(uiLayout *layout, uiLayout *context_layout, PointerRNA *ptr, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index b7184589fdf..ecdb3ff924a 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -5,6 +5,7 @@ set(INC . ../include + ../asset ../../asset_system ../../blenkernel ../../blenloader @@ -64,6 +65,7 @@ set(SRC regions/interface_regions.cc interface_string_search.cc interface_style.cc + templates/interface_template_asset_shelf_popover.cc templates/interface_template_asset_view.cc templates/interface_template_attribute_search.cc templates/interface_template_bone_collection_tree.cc diff --git a/source/blender/editors/interface/interface_handlers.cc b/source/blender/editors/interface/interface_handlers.cc index eeafe8cb0f3..3d80a97305f 100644 --- a/source/blender/editors/interface/interface_handlers.cc +++ b/source/blender/editors/interface/interface_handlers.cc @@ -4048,6 +4048,8 @@ static void ui_do_but_textedit( if (changed || (retval == WM_UI_HANDLER_BREAK)) { ED_region_tag_redraw(data->region); + /* In case of popup regions, tag for popup refreshing too (contents may have changed). */ + ED_region_tag_refresh_ui(data->region); } } @@ -11503,6 +11505,8 @@ static int ui_handle_menus_recursive(bContext *C, if (!menu->retvalue) { ui_handle_viewlist_items_hover(event, menu->region); } + /* Handle mouse clicks on overlapping view item button. */ + ui_handle_view_item_event(C, event, but, menu->region); if (do_towards_reinit) { ui_mouse_motion_towards_reinit(menu, event->xy); diff --git a/source/blender/editors/interface/interface_icons.cc b/source/blender/editors/interface/interface_icons.cc index 89a3dc7c6fd..bc187dcd4be 100644 --- a/source/blender/editors/interface/interface_icons.cc +++ b/source/blender/editors/interface/interface_icons.cc @@ -543,92 +543,6 @@ static void vicon_gplayer_color_draw(Icon *icon, int x, int y, int w, int h) immUnbindProgram(); } -static void init_brush_icons() -{ - -# define INIT_BRUSH_ICON(icon_id, name) \ - { \ - const uchar *rect = (const uchar *)datatoc_##name##_png; \ - const int size = datatoc_##name##_png_size; \ - DrawInfo *di = def_internal_icon(nullptr, icon_id, 0, 0, w, ICON_TYPE_BUFFER, 0); \ - di->data.buffer.image->datatoc_rect = rect; \ - di->data.buffer.image->datatoc_size = size; \ - } \ - ((void)0) - /* end INIT_BRUSH_ICON */ - - const int w = 96; /* warning, brush size hardcoded in C, but it gets scaled */ - - INIT_BRUSH_ICON(ICON_BRUSH_BLOB, blob); - INIT_BRUSH_ICON(ICON_BRUSH_BLUR, blur); - INIT_BRUSH_ICON(ICON_BRUSH_CLAY, clay); - INIT_BRUSH_ICON(ICON_BRUSH_CLAY_STRIPS, claystrips); - INIT_BRUSH_ICON(ICON_BRUSH_CLONE, clone); - INIT_BRUSH_ICON(ICON_BRUSH_CREASE, crease); - INIT_BRUSH_ICON(ICON_BRUSH_SCULPT_DRAW, draw); - INIT_BRUSH_ICON(ICON_BRUSH_FILL, fill); - INIT_BRUSH_ICON(ICON_BRUSH_FLATTEN, flatten); - INIT_BRUSH_ICON(ICON_BRUSH_GRAB, grab); - INIT_BRUSH_ICON(ICON_BRUSH_INFLATE, inflate); - INIT_BRUSH_ICON(ICON_BRUSH_LAYER, layer); - INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask); - INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix); - INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge); - INIT_BRUSH_ICON(ICON_BRUSH_PAINT_SELECT, paint_select); - INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch); - INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape); - INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear); - INIT_BRUSH_ICON(ICON_BRUSH_SMOOTH, smooth); - INIT_BRUSH_ICON(ICON_BRUSH_SNAKE_HOOK, snake_hook); - INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften); - INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw); - INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill); - INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask); - INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb); - INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist); - - /* grease pencil sculpt */ - INIT_BRUSH_ICON(ICON_GPBRUSH_SMOOTH, gp_brush_smooth); - INIT_BRUSH_ICON(ICON_GPBRUSH_THICKNESS, gp_brush_thickness); - INIT_BRUSH_ICON(ICON_GPBRUSH_STRENGTH, gp_brush_strength); - INIT_BRUSH_ICON(ICON_GPBRUSH_GRAB, gp_brush_grab); - INIT_BRUSH_ICON(ICON_GPBRUSH_PUSH, gp_brush_push); - INIT_BRUSH_ICON(ICON_GPBRUSH_TWIST, gp_brush_twist); - INIT_BRUSH_ICON(ICON_GPBRUSH_PINCH, gp_brush_pinch); - INIT_BRUSH_ICON(ICON_GPBRUSH_RANDOMIZE, gp_brush_randomize); - INIT_BRUSH_ICON(ICON_GPBRUSH_CLONE, gp_brush_clone); - INIT_BRUSH_ICON(ICON_GPBRUSH_WEIGHT, gp_brush_weight); - - /* grease pencil drawing brushes */ - INIT_BRUSH_ICON(ICON_GPBRUSH_PENCIL, gp_brush_pencil); - INIT_BRUSH_ICON(ICON_GPBRUSH_PEN, gp_brush_pen); - INIT_BRUSH_ICON(ICON_GPBRUSH_INK, gp_brush_ink); - INIT_BRUSH_ICON(ICON_GPBRUSH_INKNOISE, gp_brush_inknoise); - INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block); - INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker); - INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill); - INIT_BRUSH_ICON(ICON_GPBRUSH_AIRBRUSH, gp_brush_airbrush); - INIT_BRUSH_ICON(ICON_GPBRUSH_CHISEL, gp_brush_chisel); - INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft); - INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard); - INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke); - - /* Curves sculpt. */ - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_ADD, curves_sculpt_add); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_COMB, curves_sculpt_comb); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_CUT, curves_sculpt_cut); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DELETE, curves_sculpt_delete); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DENSITY, curves_sculpt_density); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_GROW_SHRINK, curves_sculpt_grow_shrink); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PINCH, curves_sculpt_pinch); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PUFF, curves_sculpt_puff); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SLIDE, curves_sculpt_slide); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SMOOTH, curves_sculpt_smooth); - INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SNAKE_HOOK, curves_sculpt_snake_hook); - -# undef INIT_BRUSH_ICON -} - static DrawInfo *g_di_event_list = nullptr; int UI_icon_from_event_type(short event_type, short event_value) @@ -1401,7 +1315,6 @@ void UI_icons_init() init_iconfile_list(&iconfilelist); UI_icons_reload_internal_textures(); init_internal_icons(); - init_brush_icons(); init_event_icons(); #endif } @@ -2221,176 +2134,6 @@ static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs) } } -static int ui_id_brush_get_icon(const bContext *C, ID *id) -{ - Brush *br = (Brush *)id; - - if (br->flag & BRUSH_CUSTOM_ICON) { - BKE_icon_id_ensure(id); - ui_id_icon_render(C, id, true); - } - else { - Object *ob = CTX_data_active_object(C); - const EnumPropertyItem *items = nullptr; - PaintMode paint_mode = PaintMode::Invalid; - ScrArea *area = CTX_wm_area(C); - char space_type = area->spacetype; - /* Fallback to 3D view. */ - if (space_type == SPACE_PROPERTIES) { - space_type = SPACE_VIEW3D; - } - - /* XXX: this is not nice, should probably make brushes - * be strictly in one paint mode only to avoid - * checking various context stuff here */ - - if ((space_type == SPACE_VIEW3D) && ob) { - if (ob->mode & OB_MODE_SCULPT) { - paint_mode = PaintMode::Sculpt; - } - else if (ob->mode & OB_MODE_VERTEX_PAINT) { - paint_mode = PaintMode::Vertex; - } - else if (ob->mode & OB_MODE_WEIGHT_PAINT) { - paint_mode = PaintMode::Weight; - } - else if (ob->mode & OB_MODE_TEXTURE_PAINT) { - paint_mode = PaintMode::Texture3D; - } - else if (ob->mode & OB_MODE_SCULPT_CURVES) { - paint_mode = PaintMode::SculptCurves; - } - } - else if (space_type == SPACE_IMAGE) { - if (area->spacetype == space_type) { - const SpaceImage *sima = static_cast(area->spacedata.first); - if (sima->mode == SI_MODE_PAINT) { - paint_mode = PaintMode::Texture2D; - } - } - } - - /* reset the icon */ - if ((ob != nullptr) && (ob->mode & OB_MODE_ALL_PAINT_GPENCIL) && - (br->gpencil_settings != nullptr)) - { - switch (br->gpencil_settings->icon_id) { - case GP_BRUSH_ICON_PENCIL: - br->id.icon_id = ICON_GPBRUSH_PENCIL; - break; - case GP_BRUSH_ICON_PEN: - br->id.icon_id = ICON_GPBRUSH_PEN; - break; - case GP_BRUSH_ICON_INK: - br->id.icon_id = ICON_GPBRUSH_INK; - break; - case GP_BRUSH_ICON_INKNOISE: - br->id.icon_id = ICON_GPBRUSH_INKNOISE; - break; - case GP_BRUSH_ICON_BLOCK: - br->id.icon_id = ICON_GPBRUSH_BLOCK; - break; - case GP_BRUSH_ICON_MARKER: - br->id.icon_id = ICON_GPBRUSH_MARKER; - break; - case GP_BRUSH_ICON_FILL: - br->id.icon_id = ICON_GPBRUSH_FILL; - break; - case GP_BRUSH_ICON_AIRBRUSH: - br->id.icon_id = ICON_GPBRUSH_AIRBRUSH; - break; - case GP_BRUSH_ICON_CHISEL: - br->id.icon_id = ICON_GPBRUSH_CHISEL; - break; - case GP_BRUSH_ICON_ERASE_SOFT: - br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT; - break; - case GP_BRUSH_ICON_ERASE_HARD: - br->id.icon_id = ICON_GPBRUSH_ERASE_HARD; - break; - case GP_BRUSH_ICON_ERASE_STROKE: - br->id.icon_id = ICON_GPBRUSH_ERASE_STROKE; - break; - case GP_BRUSH_ICON_TINT: - br->id.icon_id = ICON_BRUSH_TEXDRAW; - break; - case GP_BRUSH_ICON_VERTEX_DRAW: - br->id.icon_id = ICON_BRUSH_MIX; - break; - case GP_BRUSH_ICON_VERTEX_BLUR: - br->id.icon_id = ICON_BRUSH_BLUR; - break; - case GP_BRUSH_ICON_VERTEX_AVERAGE: - br->id.icon_id = ICON_BRUSH_BLUR; - break; - case GP_BRUSH_ICON_VERTEX_SMEAR: - br->id.icon_id = ICON_BRUSH_BLUR; - break; - case GP_BRUSH_ICON_VERTEX_REPLACE: - br->id.icon_id = ICON_BRUSH_MIX; - break; - case GP_BRUSH_ICON_GPBRUSH_SMOOTH: - br->id.icon_id = ICON_GPBRUSH_SMOOTH; - break; - case GP_BRUSH_ICON_GPBRUSH_THICKNESS: - br->id.icon_id = ICON_GPBRUSH_THICKNESS; - break; - case GP_BRUSH_ICON_GPBRUSH_STRENGTH: - br->id.icon_id = ICON_GPBRUSH_STRENGTH; - break; - case GP_BRUSH_ICON_GPBRUSH_RANDOMIZE: - br->id.icon_id = ICON_GPBRUSH_RANDOMIZE; - break; - case GP_BRUSH_ICON_GPBRUSH_GRAB: - br->id.icon_id = ICON_GPBRUSH_GRAB; - break; - case GP_BRUSH_ICON_GPBRUSH_PUSH: - br->id.icon_id = ICON_GPBRUSH_PUSH; - break; - case GP_BRUSH_ICON_GPBRUSH_TWIST: - br->id.icon_id = ICON_GPBRUSH_TWIST; - break; - case GP_BRUSH_ICON_GPBRUSH_PINCH: - br->id.icon_id = ICON_GPBRUSH_PINCH; - break; - case GP_BRUSH_ICON_GPBRUSH_CLONE: - br->id.icon_id = ICON_GPBRUSH_CLONE; - break; - case GP_BRUSH_ICON_GPBRUSH_WEIGHT: - br->id.icon_id = ICON_GPBRUSH_WEIGHT; - break; - case GP_BRUSH_ICON_GPBRUSH_BLUR: - br->id.icon_id = ICON_BRUSH_BLUR; - break; - case GP_BRUSH_ICON_GPBRUSH_AVERAGE: - br->id.icon_id = ICON_BRUSH_BLUR; - break; - case GP_BRUSH_ICON_GPBRUSH_SMEAR: - br->id.icon_id = ICON_BRUSH_BLUR; - break; - default: - br->id.icon_id = ICON_GPBRUSH_PEN; - break; - } - return id->icon_id; - } - - if (paint_mode != PaintMode::Invalid) { - items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - const uint tool_offset = BKE_paint_get_brush_tool_offset_from_paintmode(paint_mode); - const int tool_type = *(char *)POINTER_OFFSET(br, tool_offset); - if (!items || !RNA_enum_icon_from_value(items, tool_type, &id->icon_id)) { - id->icon_id = 0; - } - } - else { - id->icon_id = 0; - } - } - - return id->icon_id; -} - static int ui_id_screen_get_icon(const bContext *C, ID *id) { BKE_icon_id_ensure(id); @@ -2406,9 +2149,6 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big) /* icon */ switch (GS(id->name)) { - case ID_BR: - iconid = ui_id_brush_get_icon(C, id); - break; case ID_MA: /* fall through */ case ID_TE: /* fall through */ case ID_IM: /* fall through */ diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index f45e2b43177..4fb239959c4 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -979,6 +979,10 @@ uiBlock *ui_popup_block_refresh(bContext *C, ARegion *butregion, uiBut *but); +/** + * Note that callbacks can set the #UI_BLOCK_KEEP_OPEN flag to the block it creates, to allow + * refreshing the popup. That is, redrawing the layout, potentially affecting the popup size. + */ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but, diff --git a/source/blender/editors/interface/regions/interface_region_menu_popup.cc b/source/blender/editors/interface/regions/interface_region_menu_popup.cc index 8ff63becedc..cdd70651bda 100644 --- a/source/blender/editors/interface/regions/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/regions/interface_region_menu_popup.cc @@ -764,4 +764,14 @@ bool UI_popup_block_name_exists(const bScreen *screen, const blender::StringRef return false; } +void UI_popup_menu_close(const uiBlock *block, const bool is_cancel) +{ + UI_popup_menu_retval_set(block, is_cancel ? UI_RETURN_CANCEL : UI_RETURN_OK, true); +} + +void UI_popup_menu_close_from_but(const uiBut *but, const bool is_cancel) +{ + UI_popup_menu_close(but->block, is_cancel); +} + /** \} */ diff --git a/source/blender/editors/interface/regions/interface_region_popup.cc b/source/blender/editors/interface/regions/interface_region_popup.cc index 4c7cdac4849..ff7dded0164 100644 --- a/source/blender/editors/interface/regions/interface_region_popup.cc +++ b/source/blender/editors/interface/regions/interface_region_popup.cc @@ -897,6 +897,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, uiBlock *block = ui_popup_block_refresh(C, handle, butregion, but); handle = block->handle; + if (block->flag & UI_BLOCK_KEEP_OPEN) { + handle->can_refresh = true; + } + /* keep centered on window resizing */ if (block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) { type.listener = ui_block_region_popup_window_listener; diff --git a/source/blender/editors/interface/regions/interface_region_tooltip.cc b/source/blender/editors/interface/regions/interface_region_tooltip.cc index 045e7e05401..1093909ccd8 100644 --- a/source/blender/editors/interface/regions/interface_region_tooltip.cc +++ b/source/blender/editors/interface/regions/interface_region_tooltip.cc @@ -571,7 +571,6 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* There are different kinds of shortcuts: * * - Direct access to the tool (as if the toolbar button is pressed). - * - The key is bound to a brush type (not the exact brush name). * - The key is assigned to the operator itself * (bypassing the tool, executing the operator). * @@ -579,36 +578,6 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is */ std::string shortcut = UI_but_string_get_operator_keymap(*C, *but); - if (shortcut.empty()) { - const PaintMode paint_mode = BKE_paintmode_get_active_from_context(C); - const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - if (tool_attr != nullptr) { - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - const char *tool_id_lstrip = strrchr(tool_id, '.'); - const int tool_id_offset = tool_id_lstrip ? ((tool_id_lstrip - tool_id) + 1) : 0; - const int i = RNA_enum_from_name(items, tool_id + tool_id_offset); - - if (i != -1) { - wmOperatorType *ot = WM_operatortype_find("paint.brush_select", true); - PointerRNA op_props; - WM_operator_properties_create_ptr(&op_props, ot); - RNA_enum_set(&op_props, tool_attr, items[i].value); - - /* Check for direct access to the tool. */ - if (std::optional shortcut_brush = WM_key_event_operator_string( - C, - ot->idname, - WM_OP_INVOKE_REGION_WIN, - static_cast(op_props.data), - true)) - { - shortcut = *shortcut_brush; - } - WM_operator_properties_free(&op_props); - } - } - } - if (shortcut.empty()) { /* Check for direct access to the tool. */ if (std::optional shortcut_toolbar = WM_key_event_operator_string( diff --git a/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc b/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc new file mode 100644 index 00000000000..421a5d00547 --- /dev/null +++ b/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc @@ -0,0 +1,67 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edinterface + */ + +#include "BKE_context.hh" +#include "BKE_screen.hh" + +#include "RNA_access.hh" + +#include "UI_interface_c.hh" +#include "UI_resources.hh" +#include "interface_intern.hh" + +#include "ED_asset_shelf.hh" + +namespace blender::ui { + +static uiBlock *asset_shelf_block_fn(bContext *C, ARegion *region, void *arg_shelf_type) +{ + AssetShelfType *shelf_type = reinterpret_cast(arg_shelf_type); + return ed::asset::shelf::popup_block_create(C, region, shelf_type); +} + +void template_asset_shelf_popover(uiLayout &layout, + const bContext &C, + const StringRefNull asset_shelf_id, + const StringRef name, + const BIFIconID icon) +{ + AssetShelfType *shelf_type = ed::asset::shelf::type_find_from_idname(asset_shelf_id); + if (!shelf_type) { + RNA_warning("Asset shelf type not found: %s", asset_shelf_id.c_str()); + return; + } + + const ARegion *region = CTX_wm_region(&C); + const bool use_big_size = !RGN_TYPE_IS_HEADER_ANY(region->regiontype); + const bool use_preview_icon = use_big_size; + const short width = [&]() -> short { + if (use_big_size) { + return UI_UNIT_X * 6; + } + return UI_UNIT_X * (name.is_empty() ? 1.6f : 7); + }(); + const short height = UI_UNIT_Y * (use_big_size ? 6 : 1); + + uiBlock *block = uiLayoutGetBlock(&layout); + uiBut *but = uiDefBlockBut( + block, asset_shelf_block_fn, shelf_type, name, 0, 0, width, height, "Select an asset"); + if (use_preview_icon) { + ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW); + } + else { + ui_def_but_icon(but, icon, UI_HAS_ICON); + UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT); + } + + if (ed::asset::shelf::type_poll_for_popup(C, shelf_type) == false) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } +} + +} // namespace blender::ui diff --git a/source/blender/editors/interface/templates/interface_templates.cc b/source/blender/editors/interface/templates/interface_templates.cc index e3ac2d50885..1f8fc74c8e7 100644 --- a/source/blender/editors/interface/templates/interface_templates.cc +++ b/source/blender/editors/interface/templates/interface_templates.cc @@ -962,6 +962,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) TemplateID *template_ui = (TemplateID *)arg_litem; PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); ID *id = static_cast(idptr.data); + Main *bmain = CTX_data_main_from_id(C, id); const int event = POINTER_AS_INT(arg_event); const char *undo_push_label = nullptr; @@ -1012,7 +1013,6 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - Main *bmain = CTX_data_main(C); if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label); } @@ -1033,7 +1033,6 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_OVERRIDE: if (id && ID_IS_OVERRIDE_LIBRARY(id)) { - Main *bmain = CTX_data_main(C); if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label); } @@ -1054,14 +1053,12 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) /* make copy */ if (do_scene_obj) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); blender::ed::object::object_single_user_make(bmain, scene, (Object *)id); WM_event_add_notifier(C, NC_WINDOW, nullptr); DEG_relations_tag_update(bmain); } else { - Main *bmain = CTX_data_main(C); id_single_user(C, id, &template_ui->ptr, template_ui->prop); DEG_relations_tag_update(bmain); } @@ -1767,10 +1764,12 @@ static void ui_template_id(uiLayout *layout, flag |= UI_ID_OPEN; } + Main *bmain = (ptr->owner_id) ? CTX_data_main_from_id(C, ptr->owner_id) : CTX_data_main(C); + StructRNA *type = RNA_property_pointer_type(ptr, prop); short idcode = RNA_type_to_ID_code(type); template_ui->idcode = idcode; - template_ui->idlb = which_libbase(CTX_data_main(C), idcode); + template_ui->idlb = which_libbase(bmain, idcode); /* create UI elements for this template * - template_ID makes a copy of the template data and assigns it to the relevant buttons @@ -6363,13 +6362,47 @@ void uiTemplateInputStatus(uiLayout *layout, bContext *C) } } +static void ui_template_status_info_warnings_messages(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + std::string &warning_message, + std::string ®ular_message, + std::string &tooltip_message) +{ + tooltip_message = ""; + char statusbar_info_flag = U.statusbar_flag; + + if (bmain->has_forward_compatibility_issues) { + warning_message = ED_info_statusbar_string_ex( + bmain, scene, view_layer, STATUSBAR_SHOW_VERSION); + statusbar_info_flag &= ~STATUSBAR_SHOW_VERSION; + + char writer_ver_str[12]; + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1); + tooltip_message += fmt::format(RPT_("File saved by newer Blender\n({}), expect loss of data"), + writer_ver_str); + } + if (bmain->is_asset_repository) { + if (!tooltip_message.empty()) { + tooltip_message += "\n\n"; + } + tooltip_message += RPT_( + "This file is managed by the Blender asset system\n" + "and is expected to contain a single asset data-block.\n" + "Take care to avoid data loss when editing assets."); + } + + regular_message = ED_info_statusbar_string_ex(bmain, scene, view_layer, statusbar_info_flag); +} + void uiTemplateStatusInfo(uiLayout *layout, bContext *C) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - if (!bmain->has_forward_compatibility_issues) { + if (!BKE_main_has_issues(bmain)) { const char *status_info_txt = ED_info_statusbar_string(bmain, scene, view_layer); uiItemL(layout, status_info_txt, ICON_NONE); return; @@ -6378,13 +6411,13 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C) /* Blender version part is shown as warning area when there are forward compatibility issues with * currently loaded .blend file. */ - const char *status_info_txt = ED_info_statusbar_string_ex( - bmain, scene, view_layer, (U.statusbar_flag & ~STATUSBAR_SHOW_VERSION)); - uiItemL(layout, status_info_txt, ICON_NONE); + std::string warning_message; + std::string regular_message; + std::string tooltip_message; + ui_template_status_info_warnings_messages( + bmain, scene, view_layer, warning_message, regular_message, tooltip_message); - status_info_txt = ED_info_statusbar_string_ex(bmain, scene, view_layer, STATUSBAR_SHOW_VERSION); - - uiBut *but; + uiItemL(layout, regular_message.c_str(), ICON_NONE); const uiStyle *style = UI_style_get(); uiLayout *ui_abs = uiLayoutAbsolute(layout, false); @@ -6392,25 +6425,26 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C) eUIEmbossType previous_emboss = UI_block_emboss_get(block); UI_fontstyle_set(&style->widgetlabel); - int width = int( - BLF_width(style->widgetlabel.uifont_id, status_info_txt, strlen(status_info_txt))); - width = max_ii(width, int(10 * UI_SCALE_FAC)); + const int width = max_ii(int(BLF_width(style->widgetlabel.uifont_id, + warning_message.c_str(), + warning_message.length())), + int(10 * UI_SCALE_FAC)); UI_block_align_begin(block); /* Background for icon. */ - but = uiDefBut(block, - UI_BTYPE_ROUNDBOX, - 0, - "", - 0, - 0, - UI_UNIT_X + (6 * UI_SCALE_FAC), - UI_UNIT_Y, - nullptr, - 0.0f, - 0.0f, - ""); + uiBut *but = uiDefBut(block, + UI_BTYPE_ROUNDBOX, + 0, + "", + 0, + 0, + UI_UNIT_X + (6 * UI_SCALE_FAC), + UI_UNIT_Y, + nullptr, + 0.0f, + 0.0f, + ""); /* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */ UI_GetThemeColorType4ubv(TH_INFO_WARNING, SPACE_INFO, but->col); @@ -6435,14 +6469,13 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C) UI_block_align_end(block); UI_block_emboss_set(block, UI_EMBOSS_NONE); - /* The report icon itself. */ - static char compat_error_msg[256]; - char writer_ver_str[12]; - BKE_blender_version_blendfile_string_from_values( - writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1); - SNPRINTF(compat_error_msg, - RPT_("File saved by newer Blender\n(%s), expect loss of data"), - writer_ver_str); + /* Tool tips have to be static currently. + * FIXME This is a horrible requirement from uiBut, should probably just store an std::string for + * the tooltip as well? */ + static char tooltip_static_storage[256]; + BLI_strncpy(tooltip_static_storage, tooltip_message.c_str(), sizeof(tooltip_static_storage)); + + /* The warning icon itself. */ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, @@ -6454,23 +6487,25 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C) nullptr, 0.0f, 0.0f, - compat_error_msg); + tooltip_static_storage); UI_GetThemeColorType4ubv(TH_INFO_WARNING_TEXT, SPACE_INFO, but->col); but->col[3] = 255; /* This theme color is RBG only, so have to set alpha here. */ - /* The report message. */ - but = uiDefBut(block, - UI_BTYPE_BUT, - 0, - status_info_txt, - UI_UNIT_X, - 0, - short(width + UI_UNIT_X), - UI_UNIT_Y, - nullptr, - 0.0f, - 0.0f, - compat_error_msg); + /* The warning message, if any. */ + if (!warning_message.empty()) { + but = uiDefBut(block, + UI_BTYPE_BUT, + 0, + warning_message.c_str(), + UI_UNIT_X, + 0, + short(width + UI_UNIT_X), + UI_UNIT_Y, + nullptr, + 0.0f, + 0.0f, + tooltip_static_storage); + } UI_block_emboss_set(block, previous_emboss); } diff --git a/source/blender/editors/interface/views/grid_view.cc b/source/blender/editors/interface/views/grid_view.cc index da0234530b8..e2b0da22b43 100644 --- a/source/blender/editors/interface/views/grid_view.cc +++ b/source/blender/editors/interface/views/grid_view.cc @@ -205,12 +205,12 @@ GridViewItemDropTarget::GridViewItemDropTarget(AbstractGridView &view) : view_(v * side(s) as well. */ class BuildOnlyVisibleButtonsHelper { - const View2D &v2d_; const AbstractGridView &grid_view_; const GridViewStyle &style_; const int cols_per_row_ = 0; - /* Indices of items within the view. Calculated by constructor */ - IndexRange visible_items_range_{}; + /* Indices of items within the view. Calculated by constructor. If this is unset it means all + * items/buttons should be drawn. */ + std::optional visible_items_range_; public: BuildOnlyVisibleButtonsHelper(const View2D &v2d, @@ -222,30 +222,34 @@ class BuildOnlyVisibleButtonsHelper { void fill_layout_after_visible(uiBlock &block) const; private: - IndexRange get_visible_range() const; + IndexRange get_visible_range(const View2D &v2d) const; void add_spacer_button(uiBlock &block, int row_count) const; }; BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d, const AbstractGridView &grid_view, const int cols_per_row) - : v2d_(v2d), grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row) + : grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row) { - visible_items_range_ = this->get_visible_range(); + if ((v2d.flag & V2D_IS_INIT) && grid_view.get_item_count_filtered()) { + visible_items_range_ = this->get_visible_range(v2d); + } } -IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range() const +IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range(const View2D &v2d) const { + BLI_assert(v2d.flag & V2D_IS_INIT); + int first_idx_in_view = 0; - const float scroll_ofs_y = std::abs(v2d_.cur.ymax - v2d_.tot.ymax); + const float scroll_ofs_y = std::abs(v2d.cur.ymax - v2d.tot.ymax); if (!IS_EQF(scroll_ofs_y, 0)) { const int scrolled_away_rows = int(scroll_ofs_y) / style_.tile_height; first_idx_in_view = scrolled_away_rows * cols_per_row_; } - const int view_height = BLI_rcti_size_y(&v2d_.mask); + const int view_height = BLI_rcti_size_y(&v2d.mask); const int count_rows_in_view = std::max(view_height / style_.tile_height, 1); const int max_items_in_view = (count_rows_in_view + 1) * cols_per_row_; @@ -255,12 +259,15 @@ IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range() const bool BuildOnlyVisibleButtonsHelper::is_item_visible(const int item_idx) const { - return visible_items_range_.contains(item_idx); + return !visible_items_range_ || visible_items_range_->contains(item_idx); } void BuildOnlyVisibleButtonsHelper::fill_layout_before_visible(uiBlock &block) const { - const int first_idx_in_view = visible_items_range_.first(); + if (!visible_items_range_ || visible_items_range_->is_empty()) { + return; + } + const int first_idx_in_view = visible_items_range_->first(); if (first_idx_in_view < 1) { return; } @@ -271,8 +278,11 @@ void BuildOnlyVisibleButtonsHelper::fill_layout_before_visible(uiBlock &block) c void BuildOnlyVisibleButtonsHelper::fill_layout_after_visible(uiBlock &block) const { + if (!visible_items_range_ || visible_items_range_->is_empty()) { + return; + } const int last_item_idx = grid_view_.get_item_count_filtered() - 1; - const int last_visible_idx = visible_items_range_.last(); + const int last_visible_idx = visible_items_range_->last(); if (last_item_idx > last_visible_idx) { const int remaining_rows = (cols_per_row_ > 0) ? ceilf((last_item_idx - last_visible_idx) / @@ -346,7 +356,13 @@ void GridViewLayoutBuilder::build_from_view(const AbstractGridView &grid_view, uiLayout &layout = *uiLayoutColumn(parent_layout, true); const GridViewStyle &style = grid_view.get_style(); - const int cols_per_row = std::max(uiLayoutGetWidth(&layout) / style.tile_width, 1); + /* We might not actually know the width available for the grid view. Let's just assume that + * either there is a fixed width defined via #uiLayoutSetUnitsX() or that the layout is close to + * the root level and inherits its width. Might need a more reliable method. */ + const int guessed_layout_width = (uiLayoutGetUnitsX(parent_layout) > 0) ? + uiLayoutGetUnitsX(parent_layout) * UI_UNIT_X : + uiLayoutGetWidth(parent_layout); + const int cols_per_row = std::max(guessed_layout_width / style.tile_width, 1); BuildOnlyVisibleButtonsHelper build_visible_helper(v2d, grid_view, cols_per_row); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 131504df439..44f68f126e1 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -35,6 +35,7 @@ #include "BKE_anim_data.hh" #include "BKE_animsys.h" #include "BKE_appdir.hh" +#include "BKE_asset.hh" #include "BKE_blender_copybuffer.hh" #include "BKE_brush.hh" #include "BKE_context.hh" @@ -822,12 +823,15 @@ void MATERIAL_OT_new(wmOperatorType *ot) static int new_texture_exec(bContext *C, wmOperator * /*op*/) { - Tex *tex = static_cast(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data); - Main *bmain = CTX_data_main(C); PointerRNA ptr; PropertyRNA *prop; + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + + Main *bmain = (ptr.owner_id) ? CTX_data_main_from_id(C, ptr.owner_id) : CTX_data_main(C); + /* add or copy texture */ + Tex *tex = static_cast(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data); if (tex) { tex = (Tex *)BKE_id_copy(bmain, &tex->id); } @@ -836,8 +840,6 @@ static int new_texture_exec(bContext *C, wmOperator * /*op*/) } /* hook into UI */ - UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - if (prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer use also increases user, so this compensates it */ diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 2ad34c5097f..33953dc23cb 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -4,8 +4,12 @@ set(INC ../include + ../asset ../uvedit + ../../asset_system ../../blenkernel + ../../blenlib + ../../blenloader ../../blentranslation ../../bmesh ../../draw @@ -26,6 +30,7 @@ set(INC_SYS ) set(SRC + brush_asset_ops.cc curves_sculpt_add.cc curves_sculpt_brush.cc curves_sculpt_comb.cc diff --git a/source/blender/editors/sculpt_paint/brush_asset_ops.cc b/source/blender/editors/sculpt_paint/brush_asset_ops.cc new file mode 100644 index 00000000000..cc288af6662 --- /dev/null +++ b/source/blender/editors/sculpt_paint/brush_asset_ops.cc @@ -0,0 +1,814 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "DNA_brush_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" + +#include "BKE_asset.hh" +#include "BKE_asset_edit.hh" +#include "BKE_blendfile.hh" +#include "BKE_brush.hh" +#include "BKE_context.hh" +#include "BKE_paint.hh" +#include "BKE_preferences.h" +#include "BKE_preview_image.hh" +#include "BKE_report.hh" + +#include "AS_asset_catalog_path.hh" +#include "AS_asset_catalog_tree.hh" +#include "AS_asset_library.hh" +#include "AS_asset_representation.hh" + +#include "RNA_access.hh" +#include "RNA_define.hh" + +#include "ED_asset_handle.hh" +#include "ED_asset_library.hh" +#include "ED_asset_list.hh" +#include "ED_asset_mark_clear.hh" +#include "ED_asset_menu_utils.hh" +#include "ED_asset_shelf.hh" + +#include "UI_interface_icons.hh" +#include "UI_resources.hh" + +#include "BLT_translation.hh" + +#include "WM_api.hh" +#include "WM_toolsystem.hh" + +#include "paint_intern.hh" + +namespace blender::ed::sculpt_paint { + +static int brush_asset_select_exec(bContext *C, wmOperator *op) +{ + /* This operator currently covers both cases: the file/asset browser file list and the asset list + * used for the asset-view template. Once the asset list design is used by the Asset Browser, + * this can be simplified to just that case. */ + Main *bmain = CTX_data_main(C); + const asset_system::AssetRepresentation *asset = + asset::operator_asset_reference_props_get_asset_from_all_library(*C, *op->ptr, op->reports); + if (!asset) { + return OPERATOR_CANCELLED; + } + + AssetWeakReference brush_asset_reference = asset->make_weak_reference(); + Brush *brush = reinterpret_cast( + bke::asset_edit_id_from_weak_reference(*bmain, ID_BR, brush_asset_reference)); + + Paint *paint = BKE_paint_get_active_from_context(C); + + if (!BKE_paint_brush_asset_set(paint, brush, brush_asset_reference)) { + /* Note brush datablock was still added, so was not a no-op. */ + BKE_report(op->reports, RPT_WARNING, "Unable to select brush, wrong object mode"); + return OPERATOR_FINISHED; + } + + WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, nullptr); + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr); + WM_toolsystem_ref_set_by_id(C, "builtin.brush"); + + return OPERATOR_FINISHED; +} + +void BRUSH_OT_asset_select(wmOperatorType *ot) +{ + ot->name = "Select Brush Asset"; + ot->description = "Select a brush asset as current sculpt and paint tool"; + ot->idname = "BRUSH_OT_asset_select"; + + ot->exec = brush_asset_select_exec; + + asset::operator_asset_reference_props_register(*ot->srna); +} + +/* FIXME Quick dirty hack to generate a weak ref from 'raw' paths. + * This needs to be properly implemented in assetlib code. + */ +static AssetWeakReference brush_asset_create_weakref_hack(const bUserAssetLibrary *user_asset_lib, + const std::string &file_path) +{ + AssetWeakReference asset_weak_ref{}; + + StringRef asset_root_path = user_asset_lib->dirpath; + BLI_assert(file_path.find(asset_root_path) == 0); + std::string relative_asset_path = file_path.substr(size_t(asset_root_path.size()) + 1); + + asset_weak_ref.asset_library_type = ASSET_LIBRARY_CUSTOM; + asset_weak_ref.asset_library_identifier = BLI_strdup(user_asset_lib->name); + asset_weak_ref.relative_asset_identifier = BLI_strdupn(relative_asset_path.c_str(), + relative_asset_path.size()); + + return asset_weak_ref; +} + +static std::optional library_to_library_ref( + const asset_system::AssetLibrary &library) +{ + for (const AssetLibraryReference &ref : asset_system::all_valid_asset_library_refs()) { + const std::string root_path = AS_asset_library_root_path_from_library_ref(ref); + /* Use #BLI_path_cmp_normalized because `library.root_path()` ends with a slash while + * `root_path` doesn't. */ + if (BLI_path_cmp_normalized(root_path.c_str(), library.root_path().c_str()) == 0) { + return ref; + } + } + return std::nullopt; +} + +static AssetLibraryReference user_library_to_library_ref(const bUserAssetLibrary &user_library) +{ + AssetLibraryReference library_ref{}; + library_ref.custom_library_index = BLI_findindex(&U.asset_libraries, &user_library); + library_ref.type = ASSET_LIBRARY_CUSTOM; + return library_ref; +} + +static const bUserAssetLibrary *library_ref_to_user_library( + const AssetLibraryReference &library_ref) +{ + if (library_ref.type != ASSET_LIBRARY_CUSTOM) { + return nullptr; + } + return static_cast( + BLI_findlink(&U.asset_libraries, library_ref.custom_library_index)); +} + +static void refresh_asset_library(const bContext *C, const AssetLibraryReference &library_ref) +{ + asset::list::clear(&library_ref, C); + /* TODO: Should the all library reference be automatically cleared? */ + AssetLibraryReference all_lib_ref = asset_system::all_library_reference(); + asset::list::clear(&all_lib_ref, C); +} + +static void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library) +{ + refresh_asset_library(C, user_library_to_library_ref(user_library)); +} + +static bool brush_asset_save_as_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; + if (paint == nullptr || brush == nullptr) { + return false; + } + if (!paint->brush_asset_reference) { + /* The brush should always be an imported asset. We use this asset reference to find + * which library and catalog the brush came from, as defaults for the popup. */ + return false; + } + + if (BLI_listbase_is_empty(&U.asset_libraries)) { + CTX_wm_operator_poll_msg_set(C, "No asset library available to save to"); + return false; + } + + return true; +} + +static const bUserAssetLibrary *get_asset_library_from_prop(PointerRNA &ptr) +{ + const int enum_value = RNA_enum_get(&ptr, "asset_library_reference"); + const AssetLibraryReference lib_ref = asset::library_reference_from_enum_value(enum_value); + return BKE_preferences_asset_library_find_index(&U, lib_ref.custom_library_index); +} + +static asset_system::AssetCatalog &asset_library_ensure_catalog( + asset_system::AssetLibrary &library, const asset_system::AssetCatalogPath &path) +{ + if (asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog_by_path(path)) { + return *catalog; + } + return *library.catalog_service().create_catalog(path); +} + +static asset_system::AssetCatalog &asset_library_ensure_catalogs_in_path( + asset_system::AssetLibrary &library, const asset_system::AssetCatalogPath &path) +{ + /* Adding multiple catalogs in a path at a time with #AssetCatalogService::create_catalog() + * doesn't work; add each potentially new catalog in the hierarchy manually here. */ + asset_system::AssetCatalogPath parent = ""; + path.iterate_components([&](StringRef component_name, bool /*is_last_component*/) { + asset_library_ensure_catalog(library, parent / component_name); + parent = parent / component_name; + }); + return *library.catalog_service().find_catalog_by_path(path); +} + +static void show_catalog_in_asset_shelf(const bContext &C, const StringRefNull catalog_path) +{ + /* Enable catalog in all visible asset shelves. */ + wmWindowManager *wm = CTX_wm_manager(&C); + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + const bScreen *screen = WM_window_get_active_screen(win); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + const AssetShelf *shelf = asset::shelf::active_shelf_from_area(area); + if (shelf && BKE_preferences_asset_shelf_settings_ensure_catalog_path_enabled( + &U, shelf->idname, catalog_path.c_str())) + { + U.runtime.is_dirty = true; + } + } + } +} + +static int brush_asset_save_as_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; + + /* Determine file path to save to. */ + PropertyRNA *name_prop = RNA_struct_find_property(op->ptr, "name"); + char name[MAX_NAME] = ""; + if (RNA_property_is_set(op->ptr, name_prop)) { + RNA_property_string_get(op->ptr, name_prop, name); + } + if (name[0] == '\0') { + STRNCPY(name, brush->id.name + 2); + } + + const bUserAssetLibrary *user_library = get_asset_library_from_prop(*op->ptr); + if (!user_library) { + return OPERATOR_CANCELLED; + } + + asset_system::AssetLibrary *library = AS_asset_library_load( + bmain, user_library_to_library_ref(*user_library)); + if (!library) { + BKE_report(op->reports, RPT_ERROR, "Failed to load asset library"); + return OPERATOR_CANCELLED; + } + + /* Turn brush into asset if it isn't yet. */ + if (!ID_IS_ASSET(&brush->id)) { + asset::mark_id(&brush->id); + asset::generate_preview(C, &brush->id); + } + BLI_assert(ID_IS_ASSET(&brush->id)); + + /* Add asset to catalog. */ + char catalog_path[MAX_NAME]; + RNA_string_get(op->ptr, "catalog_path", catalog_path); + + AssetMetaData &meta_data = *brush->id.asset_data; + if (catalog_path[0]) { + const asset_system::AssetCatalog &catalog = asset_library_ensure_catalogs_in_path( + *library, catalog_path); + BKE_asset_metadata_catalog_id_set(&meta_data, catalog.catalog_id, catalog.simple_name.c_str()); + } + + const std::optional final_full_asset_filepath = bke::asset_edit_id_save_as( + *bmain, brush->id, name, *user_library, *op->reports); + if (!final_full_asset_filepath) { + return OPERATOR_CANCELLED; + } + + library->catalog_service().write_to_disk(*final_full_asset_filepath); + show_catalog_in_asset_shelf(*C, catalog_path); + + AssetWeakReference new_brush_weak_ref = brush_asset_create_weakref_hack( + user_library, *final_full_asset_filepath); + + brush = reinterpret_cast( + bke::asset_edit_id_from_weak_reference(*bmain, ID_BR, new_brush_weak_ref)); + + if (!BKE_paint_brush_asset_set(paint, brush, new_brush_weak_ref)) { + /* Note brush sset was still saved in editable asset library, so was not a no-op. */ + BKE_report(op->reports, RPT_WARNING, "Unable to activate just-saved brush asset"); + } + + refresh_asset_library(C, *user_library); + WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_ADDED, nullptr); + WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); + + return OPERATOR_FINISHED; +} + +static bool library_is_editable(const AssetLibraryReference &library) +{ + if (library.type == ASSET_LIBRARY_ESSENTIALS) { + return false; + } + return true; +} + +static int brush_asset_save_as_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference; + const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref( + *C, brush_weak_ref, op->reports); + if (!asset) { + return OPERATOR_CANCELLED; + } + const asset_system::AssetLibrary &library = asset->owner_asset_library(); + const std::optional library_ref = library_to_library_ref(library); + if (!library_ref) { + BLI_assert_unreachable(); + return OPERATOR_CANCELLED; + } + + RNA_string_set(op->ptr, "name", asset->get_name().c_str()); + + /* If the library isn't saved from the operator's last execution, find the current library or the + * first library if the current library isn't editable. */ + if (!RNA_struct_property_is_set_ex(op->ptr, "asset_library_reference", false)) { + if (library_is_editable(*library_ref)) { + RNA_enum_set(op->ptr, + "asset_library_reference", + asset::library_reference_to_enum_value(&*library_ref)); + } + else { + const AssetLibraryReference first_library = user_library_to_library_ref( + *static_cast(U.asset_libraries.first)); + RNA_enum_set(op->ptr, + "asset_library_reference", + asset::library_reference_to_enum_value(&first_library)); + } + } + + /* By default, put the new asset in the same catalog as the existing asset. */ + if (!RNA_struct_property_is_set(op->ptr, "catalog_path")) { + const asset_system::CatalogID &id = asset->get_metadata().catalog_id; + if (const asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog(id)) { + RNA_string_set(op->ptr, "catalog_path", catalog->path.c_str()); + } + } + + return WM_operator_props_dialog_popup(C, op, 400, std::nullopt, IFACE_("Save")); +} + +static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext * /*C*/, + PointerRNA * /*ptr*/, + PropertyRNA * /*prop*/, + bool *r_free) +{ + const EnumPropertyItem *items = asset::library_reference_to_rna_enum_itemf(false); + if (!items) { + *r_free = false; + return nullptr; + } + + *r_free = true; + return items; +} + +static void visit_library_catalogs_catalog_for_search( + const Main &bmain, + const bUserAssetLibrary &user_library, + const StringRef edit_text, + const FunctionRef visit_fn) +{ + const asset_system::AssetLibrary *library = AS_asset_library_load( + &bmain, user_library_to_library_ref(user_library)); + if (!library) { + return; + } + + if (!edit_text.is_empty()) { + const asset_system::AssetCatalogPath edit_path = edit_text; + if (!library->catalog_service().find_catalog_by_path(edit_path)) { + visit_fn(StringPropertySearchVisitParams{edit_path.str(), std::nullopt, ICON_ADD}); + } + } + + const asset_system::AssetCatalogTree &full_tree = library->catalog_service().catalog_tree(); + full_tree.foreach_item([&](const asset_system::AssetCatalogTreeItem &item) { + visit_fn(StringPropertySearchVisitParams{item.catalog_path().str(), std::nullopt}); + }); +} + +static void visit_library_prop_catalogs_catalog_for_search_fn( + const bContext *C, + PointerRNA *ptr, + PropertyRNA * /*prop*/, + const char *edit_text, + FunctionRef visit_fn) +{ + /* NOTE: Using the all library would also be a valid choice. */ + if (const bUserAssetLibrary *user_library = get_asset_library_from_prop(*ptr)) { + visit_library_catalogs_catalog_for_search( + *CTX_data_main(C), *user_library, edit_text, visit_fn); + } +} + +void BRUSH_OT_asset_save_as(wmOperatorType *ot) +{ + ot->name = "Save as Brush Asset"; + ot->description = + "Save a copy of the active brush asset into the default asset library, and make it the " + "active brush"; + ot->idname = "BRUSH_OT_asset_save_as"; + + ot->exec = brush_asset_save_as_exec; + ot->invoke = brush_asset_save_as_invoke; + ot->poll = brush_asset_save_as_poll; + + ot->prop = RNA_def_string( + ot->srna, "name", nullptr, MAX_NAME, "Name", "Name for the new brush asset"); + + PropertyRNA *prop = RNA_def_property(ot->srna, "asset_library_reference", PROP_ENUM, PROP_NONE); + RNA_def_enum_funcs(prop, rna_asset_library_reference_itemf); + RNA_def_property_ui_text(prop, "Library", "Asset library used to store the new brush"); + + prop = RNA_def_string( + ot->srna, "catalog_path", nullptr, MAX_NAME, "Catalog", "Catalog to use for the new asset"); + RNA_def_property_string_search_func_runtime( + prop, visit_library_prop_catalogs_catalog_for_search_fn, PROP_STRING_SEARCH_SUGGESTION); +} + +static int brush_asset_edit_metadata_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + BLI_assert(ID_IS_ASSET(&brush->id)); + const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference; + const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref( + *C, brush_weak_ref, op->reports); + if (!asset) { + return OPERATOR_CANCELLED; + } + const asset_system::AssetLibrary &library_const = asset->owner_asset_library(); + const AssetLibraryReference library_ref = *library_to_library_ref(library_const); + asset_system::AssetLibrary *library = AS_asset_library_load(bmain, library_ref); + + char catalog_path[MAX_NAME]; + RNA_string_get(op->ptr, "catalog_path", catalog_path); + + AssetMetaData &meta_data = *brush->id.asset_data; + MEM_SAFE_FREE(meta_data.author); + meta_data.author = RNA_string_get_alloc(op->ptr, "author", nullptr, 0, nullptr); + MEM_SAFE_FREE(meta_data.description); + meta_data.description = RNA_string_get_alloc(op->ptr, "description", nullptr, 0, nullptr); + + if (catalog_path[0]) { + const asset_system::AssetCatalog &catalog = asset_library_ensure_catalogs_in_path( + *library, catalog_path); + BKE_asset_metadata_catalog_id_set(&meta_data, catalog.catalog_id, catalog.simple_name.c_str()); + } + + if (!bke::asset_edit_id_save(*bmain, brush->id, *op->reports)) { + return OPERATOR_CANCELLED; + } + + char asset_full_path_buffer[FILE_MAX_LIBEXTRA]; + char *file_path = nullptr; + AS_asset_full_path_explode_from_weak_ref( + &brush_weak_ref, asset_full_path_buffer, &file_path, nullptr, nullptr); + if (!file_path) { + BLI_assert_unreachable(); + return OPERATOR_CANCELLED; + } + + library->catalog_service().write_to_disk(file_path); + + refresh_asset_library(C, library_ref); + WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr); + + return OPERATOR_FINISHED; +} + +static int brush_asset_edit_metadata_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) +{ + const Paint *paint = BKE_paint_get_active_from_context(C); + const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference; + const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref( + *C, brush_weak_ref, op->reports); + if (!asset) { + return OPERATOR_CANCELLED; + } + const asset_system::AssetLibrary &library = asset->owner_asset_library(); + const AssetMetaData &meta_data = asset->get_metadata(); + + if (!RNA_struct_property_is_set(op->ptr, "catalog_path")) { + const asset_system::CatalogID &id = meta_data.catalog_id; + if (const asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog(id)) { + RNA_string_set(op->ptr, "catalog_path", catalog->path.c_str()); + } + } + if (!RNA_struct_property_is_set(op->ptr, "author")) { + RNA_string_set(op->ptr, "author", meta_data.author ? meta_data.author : ""); + } + if (!RNA_struct_property_is_set(op->ptr, "description")) { + RNA_string_set(op->ptr, "description", meta_data.description ? meta_data.description : ""); + } + + return WM_operator_props_dialog_popup(C, op, 400, std::nullopt, IFACE_("Edit Metadata")); +} + +static void visit_active_library_catalogs_catalog_for_search_fn( + const bContext *C, + PointerRNA * /*ptr*/, + PropertyRNA * /*prop*/, + const char *edit_text, + FunctionRef visit_fn) +{ + const Paint *paint = BKE_paint_get_active_from_context(C); + const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference; + const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref( + *C, brush_weak_ref, nullptr); + if (!asset) { + return; + } + const asset_system::AssetLibrary &library = asset->owner_asset_library(); + + /* NOTE: Using the all library would also be a valid choice. */ + visit_library_catalogs_catalog_for_search( + *CTX_data_main(C), + *library_ref_to_user_library(*library_to_library_ref(library)), + edit_text, + visit_fn); +} + +static bool brush_asset_edit_metadata_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; + if (paint == nullptr || brush == nullptr) { + return false; + } + if (!ID_IS_ASSET(&brush->id)) { + BLI_assert_unreachable(); + return false; + } + const AssetWeakReference *brush_weak_ref = paint->brush_asset_reference; + if (!brush_weak_ref) { + BLI_assert_unreachable(); + return false; + } + const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref( + *C, *brush_weak_ref, nullptr); + if (!asset) { + BLI_assert_unreachable(); + return false; + } + const std::optional library_ref = library_to_library_ref( + asset->owner_asset_library()); + if (!library_ref) { + BLI_assert_unreachable(); + return false; + } + if (!library_is_editable(*library_ref)) { + CTX_wm_operator_poll_msg_set(C, "Asset library is not editable"); + return false; + } + if (!bke::asset_edit_id_is_editable(brush->id)) { + CTX_wm_operator_poll_msg_set(C, "Asset file is not editable"); + return false; + } + return true; +} + +void BRUSH_OT_asset_edit_metadata(wmOperatorType *ot) +{ + ot->name = "Edit Metadata"; + ot->description = "Edit asset information like the catalog, preview image, tags, or author"; + ot->idname = "BRUSH_OT_asset_edit_metadata"; + + ot->exec = brush_asset_edit_metadata_exec; + ot->invoke = brush_asset_edit_metadata_invoke; + ot->poll = brush_asset_edit_metadata_poll; + + PropertyRNA *prop = RNA_def_string( + ot->srna, "catalog_path", nullptr, MAX_NAME, "Catalog", "The asset's catalog path"); + RNA_def_property_string_search_func_runtime( + prop, visit_active_library_catalogs_catalog_for_search_fn, PROP_STRING_SEARCH_SUGGESTION); + RNA_def_string(ot->srna, "author", nullptr, MAX_NAME, "Author", ""); + RNA_def_string(ot->srna, "description", nullptr, MAX_NAME, "Description", ""); +} + +static int brush_asset_load_preview_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + BLI_assert(ID_IS_ASSET(&brush->id)); + const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference; + const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref( + *C, brush_weak_ref, op->reports); + if (!asset) { + return OPERATOR_CANCELLED; + } + const AssetLibraryReference library_ref = *library_to_library_ref(asset->owner_asset_library()); + + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + if (!BLI_is_file(filepath)) { + BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", filepath); + return OPERATOR_CANCELLED; + } + + BKE_previewimg_id_custom_set(&brush->id, filepath); + + if (!bke::asset_edit_id_save(*bmain, brush->id, *op->reports)) { + return OPERATOR_CANCELLED; + } + + refresh_asset_library(C, library_ref); + WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr); + + return OPERATOR_FINISHED; +} + +static int brush_asset_load_preview_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (RNA_struct_property_is_set(op->ptr, "filepath")) { + return brush_asset_load_preview_exec(C, op); + } + return WM_operator_filesel(C, op, event); +} + +void BRUSH_OT_asset_load_preview(wmOperatorType *ot) +{ + ot->name = "Load Preview Image"; + ot->description = "Choose a preview image for the brush"; + ot->idname = "BRUSH_OT_asset_load_preview"; + + ot->exec = brush_asset_load_preview_exec; + ot->invoke = brush_asset_load_preview_invoke; + ot->poll = brush_asset_edit_metadata_poll; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, + FILE_SPECIAL, + FILE_OPENFILE, + WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +static bool brush_asset_delete_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; + if (paint == nullptr || brush == nullptr) { + return false; + } + if (!paint->brush_asset_reference) { + return false; + } + + /* Asset brush, check if belongs to an editable blend file. */ + if (ID_IS_ASSET(brush)) { + if (!bke::asset_edit_id_is_editable(brush->id)) { + CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable"); + return false; + } + } + + return true; +} + +static int brush_asset_delete_exec(bContext *C, wmOperator *op) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + Main *bmain = CTX_data_main(C); + + bUserAssetLibrary *library = BKE_preferences_asset_library_find_by_name( + &U, paint->brush_asset_reference->asset_library_identifier); + if (!library) { + return OPERATOR_CANCELLED; + } + + bke::asset_edit_id_delete(*bmain, brush->id, *op->reports); + + refresh_asset_library(C, *library); + + BKE_paint_brush_set_default(bmain, paint); + + WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_REMOVED, nullptr); + WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr); + + return OPERATOR_FINISHED; +} + +static int brush_asset_delete_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) +{ + return WM_operator_confirm_ex( + C, + op, + IFACE_("Delete Brush Asset"), + IFACE_("Permanently delete brush asset blend file. This can't be undone."), + IFACE_("Delete"), + ALERT_ICON_WARNING, + false); +} + +void BRUSH_OT_asset_delete(wmOperatorType *ot) +{ + ot->name = "Delete Brush Asset"; + ot->description = "Delete the active brush asset both from the local session and asset library"; + ot->idname = "BRUSH_OT_asset_delete"; + + ot->exec = brush_asset_delete_exec; + ot->invoke = brush_asset_delete_invoke; + ot->poll = brush_asset_delete_poll; +} + +static bool brush_asset_update_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; + if (paint == nullptr || brush == nullptr) { + return false; + } + + if ((brush->id.tag & LIB_TAG_ASSET_EDIT_MAIN) == 0) { + return false; + } + + if (!(paint->brush_asset_reference && ID_IS_ASSET(brush))) { + return false; + } + + if (!bke::asset_edit_id_is_editable(brush->id)) { + CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable"); + return false; + } + + return true; +} + +static int brush_asset_update_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + const AssetWeakReference *asset_weak_ref = paint->brush_asset_reference; + + const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_by_name( + &U, asset_weak_ref->asset_library_identifier); + if (!user_library) { + return OPERATOR_CANCELLED; + } + + BLI_assert(ID_IS_ASSET(brush)); + + bke::asset_edit_id_save(*bmain, brush->id, *op->reports); + + refresh_asset_library(C, *user_library); + WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr); + WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); + + return OPERATOR_FINISHED; +} + +void BRUSH_OT_asset_update(wmOperatorType *ot) +{ + ot->name = "Update Brush Asset"; + ot->description = "Update the active brush asset in the asset library with current settings"; + ot->idname = "BRUSH_OT_asset_update"; + + ot->exec = brush_asset_update_exec; + ot->poll = brush_asset_update_poll; +} + +static bool brush_asset_revert_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; + if (paint == nullptr || brush == nullptr) { + return false; + } + + return paint->brush_asset_reference && (brush->id.tag & LIB_TAG_ASSET_EDIT_MAIN); +} + +static int brush_asset_revert_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + + bke::asset_edit_id_revert(*bmain, brush->id, *op->reports); + + WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr); + WM_main_add_notifier(NC_TEXTURE | ND_NODES, nullptr); + + return OPERATOR_FINISHED; +} + +void BRUSH_OT_asset_revert(wmOperatorType *ot) +{ + ot->name = "Revert Brush Asset"; + ot->description = + "Revert the active brush settings to the default values from the asset library"; + ot->idname = "BRUSH_OT_asset_revert"; + + ot->exec = brush_asset_revert_exec; + ot->poll = brush_asset_revert_poll; +} + +} // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/paint_intern.hh b/source/blender/editors/sculpt_paint/paint_intern.hh index 7f3a96cbc15..24a66a9a050 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.hh +++ b/source/blender/editors/sculpt_paint/paint_intern.hh @@ -108,6 +108,14 @@ bool paint_stroke_started(PaintStroke *stroke); bool paint_brush_tool_poll(bContext *C); +void BRUSH_OT_asset_select(wmOperatorType *ot); +void BRUSH_OT_asset_save_as(wmOperatorType *ot); +void BRUSH_OT_asset_edit_metadata(wmOperatorType *ot); +void BRUSH_OT_asset_load_preview(wmOperatorType *ot); +void BRUSH_OT_asset_delete(wmOperatorType *ot); +void BRUSH_OT_asset_update(wmOperatorType *ot); +void BRUSH_OT_asset_revert(wmOperatorType *ot); + } // namespace blender::ed::sculpt_paint /** diff --git a/source/blender/editors/sculpt_paint/paint_ops.cc b/source/blender/editors/sculpt_paint/paint_ops.cc index 1bc976f1ad4..36495ee6e6a 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_ops.cc @@ -47,222 +47,6 @@ #include "paint_intern.hh" #include "sculpt_intern.hh" -/* Brush operators */ -static int brush_add_exec(bContext *C, wmOperator * /*op*/) -{ - // int type = RNA_enum_get(op->ptr, "type"); - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *br = BKE_paint_brush(paint); - Main *bmain = CTX_data_main(C); - PaintMode mode = BKE_paintmode_get_active_from_context(C); - - if (br) { - br = (Brush *)BKE_id_copy(bmain, &br->id); - } - else { - br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paintmode(mode)); - } - id_us_min(&br->id); /* fake user only */ - - BKE_paint_brush_set(paint, br); - - return OPERATOR_FINISHED; -} - -static void BRUSH_OT_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Brush"; - ot->description = "Add brush by mode type"; - ot->idname = "BRUSH_OT_add"; - - /* api callbacks */ - ot->exec = brush_add_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool, - enum eContextObjectMode mode) -{ - switch (mode) { - case CTX_MODE_PAINT_GPENCIL_LEGACY: { - if (STREQ(tool->runtime->data_block, "DRAW")) { - return GP_BRUSH_PRESET_PENCIL; - } - if (STREQ(tool->runtime->data_block, "FILL")) { - return GP_BRUSH_PRESET_FILL_AREA; - } - if (STREQ(tool->runtime->data_block, "ERASE")) { - return GP_BRUSH_PRESET_ERASER_SOFT; - } - if (STREQ(tool->runtime->data_block, "TINT")) { - return GP_BRUSH_PRESET_TINT; - } - break; - } - case CTX_MODE_SCULPT_GPENCIL_LEGACY: { - if (STREQ(tool->runtime->data_block, "SMOOTH")) { - return GP_BRUSH_PRESET_SMOOTH_STROKE; - } - if (STREQ(tool->runtime->data_block, "STRENGTH")) { - return GP_BRUSH_PRESET_STRENGTH_STROKE; - } - if (STREQ(tool->runtime->data_block, "THICKNESS")) { - return GP_BRUSH_PRESET_THICKNESS_STROKE; - } - if (STREQ(tool->runtime->data_block, "GRAB")) { - return GP_BRUSH_PRESET_GRAB_STROKE; - } - if (STREQ(tool->runtime->data_block, "PUSH")) { - return GP_BRUSH_PRESET_PUSH_STROKE; - } - if (STREQ(tool->runtime->data_block, "TWIST")) { - return GP_BRUSH_PRESET_TWIST_STROKE; - } - if (STREQ(tool->runtime->data_block, "PINCH")) { - return GP_BRUSH_PRESET_PINCH_STROKE; - } - if (STREQ(tool->runtime->data_block, "RANDOMIZE")) { - return GP_BRUSH_PRESET_RANDOMIZE_STROKE; - } - if (STREQ(tool->runtime->data_block, "CLONE")) { - return GP_BRUSH_PRESET_CLONE_STROKE; - } - break; - } - case CTX_MODE_WEIGHT_GPENCIL_LEGACY: { - if (STREQ(tool->runtime->data_block, "DRAW")) { - return GP_BRUSH_PRESET_WEIGHT_DRAW; - } - if (STREQ(tool->runtime->data_block, "BLUR")) { - return GP_BRUSH_PRESET_WEIGHT_BLUR; - } - if (STREQ(tool->runtime->data_block, "AVERAGE")) { - return GP_BRUSH_PRESET_WEIGHT_AVERAGE; - } - if (STREQ(tool->runtime->data_block, "SMEAR")) { - return GP_BRUSH_PRESET_WEIGHT_SMEAR; - } - break; - } - case CTX_MODE_VERTEX_GPENCIL_LEGACY: { - if (STREQ(tool->runtime->data_block, "DRAW")) { - return GP_BRUSH_PRESET_VERTEX_DRAW; - } - if (STREQ(tool->runtime->data_block, "BLUR")) { - return GP_BRUSH_PRESET_VERTEX_BLUR; - } - if (STREQ(tool->runtime->data_block, "AVERAGE")) { - return GP_BRUSH_PRESET_VERTEX_AVERAGE; - } - if (STREQ(tool->runtime->data_block, "SMEAR")) { - return GP_BRUSH_PRESET_VERTEX_SMEAR; - } - if (STREQ(tool->runtime->data_block, "REPLACE")) { - return GP_BRUSH_PRESET_VERTEX_REPLACE; - } - break; - } - default: - return GP_BRUSH_PRESET_UNKNOWN; - } - return GP_BRUSH_PRESET_UNKNOWN; -} - -static int brush_add_gpencil_exec(bContext *C, wmOperator * /*op*/) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *br = BKE_paint_brush(paint); - Main *bmain = CTX_data_main(C); - - if (br) { - br = (Brush *)BKE_id_copy(bmain, &br->id); - } - else { - /* Get the active tool to determine what type of brush is active. */ - bScreen *screen = CTX_wm_screen(C); - if (screen == nullptr) { - return OPERATOR_CANCELLED; - } - - bToolRef *tool = nullptr; - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - if (area->spacetype == SPACE_VIEW3D) { - /* Check the current tool is a brush. */ - bToolRef *tref = area->runtime.tool; - if (tref && tref->runtime && tref->runtime->data_block[0]) { - tool = tref; - break; - } - } - } - - if (tool == nullptr) { - return OPERATOR_CANCELLED; - } - - /* Get Brush mode base on context mode. */ - const enum eContextObjectMode mode = CTX_data_mode_enum(C); - eObjectMode obmode = OB_MODE_PAINT_GPENCIL_LEGACY; - switch (mode) { - case CTX_MODE_PAINT_GPENCIL_LEGACY: - obmode = OB_MODE_PAINT_GPENCIL_LEGACY; - break; - case CTX_MODE_SCULPT_GPENCIL_LEGACY: - obmode = OB_MODE_SCULPT_GPENCIL_LEGACY; - break; - case CTX_MODE_WEIGHT_GPENCIL_LEGACY: - obmode = OB_MODE_WEIGHT_GPENCIL_LEGACY; - break; - case CTX_MODE_VERTEX_GPENCIL_LEGACY: - obmode = OB_MODE_VERTEX_GPENCIL_LEGACY; - break; - default: - return OPERATOR_CANCELLED; - break; - } - - /* Get brush preset using the actual tool. */ - eGPBrush_Presets preset = gpencil_get_brush_preset_from_tool(tool, mode); - - /* Capitalize Brush name first letter using the tool name. */ - char name[64]; - STRNCPY(name, tool->runtime->data_block); - BLI_str_tolower_ascii(name, sizeof(name)); - name[0] = BLI_toupper_ascii(name[0]); - - /* Create the brush and assign default values. */ - br = BKE_brush_add(bmain, name, obmode); - if (br) { - BKE_brush_init_gpencil_settings(br); - BKE_gpencil_brush_preset_set(bmain, br, preset); - } - } - - if (br) { - id_us_min(&br->id); /* fake user only */ - BKE_paint_brush_set(paint, br); - } - - return OPERATOR_FINISHED; -} - -static void BRUSH_OT_add_gpencil(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Drawing Brush"; - ot->description = "Add brush for Grease Pencil"; - ot->idname = "BRUSH_OT_add_gpencil"; - - /* api callbacks */ - ot->exec = brush_add_gpencil_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - static int brush_scale_size_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -734,303 +518,6 @@ static void PALETTE_OT_join(wmOperatorType *ot) RNA_def_string(ot->srna, "palette", nullptr, MAX_ID_NAME - 2, "Palette", "Name of the Palette"); } -static int brush_reset_exec(bContext *C, wmOperator * /*op*/) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); - Object *ob = CTX_data_active_object(C); - - if (!ob || !brush) { - return OPERATOR_CANCELLED; - } - - /* TODO: other modes */ - if (ob->mode & OB_MODE_SCULPT) { - BKE_brush_sculpt_reset(brush); - } - else { - return OPERATOR_CANCELLED; - } - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - - return OPERATOR_FINISHED; -} - -static void BRUSH_OT_reset(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Reset Brush"; - ot->description = "Return brush to defaults based on current tool"; - ot->idname = "BRUSH_OT_reset"; - - /* api callbacks */ - ot->exec = brush_reset_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int brush_tool(const Brush *brush, size_t tool_offset) -{ - return *(((char *)brush) + tool_offset); -} - -static void brush_tool_set(const Brush *brush, size_t tool_offset, int tool) -{ - *(((char *)brush) + tool_offset) = tool; -} - -static Brush *brush_tool_cycle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool) -{ - Brush *brush, *first_brush; - - if (!brush_orig && !(brush_orig = static_cast(bmain->brushes.first))) { - return nullptr; - } - - if (brush_tool(brush_orig, paint->runtime.tool_offset) != tool) { - /* If current brush's tool is different from what we need, - * start cycling from the beginning of the list. - * Such logic will activate the same exact brush not relating from - * which tool user requests other tool. - */ - - /* Try to tool-slot first. */ - first_brush = BKE_paint_toolslots_brush_get(paint, tool); - if (first_brush == nullptr) { - first_brush = static_cast(bmain->brushes.first); - } - } - else { - /* If user wants to switch to brush with the same tool as - * currently active brush do a cycling via all possible - * brushes with requested tool. */ - first_brush = brush_orig->id.next ? static_cast(brush_orig->id.next) : - static_cast(bmain->brushes.first); - } - - /* get the next brush with the active tool */ - brush = first_brush; - do { - if ((brush->ob_mode & paint->runtime.ob_mode) && - (brush_tool(brush, paint->runtime.tool_offset) == tool)) - { - return brush; - } - - brush = brush->id.next ? static_cast(brush->id.next) : - static_cast(bmain->brushes.first); - } while (brush != first_brush); - - return nullptr; -} - -static Brush *brush_tool_toggle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool) -{ - if (!brush_orig || brush_tool(brush_orig, paint->runtime.tool_offset) != tool) { - Brush *br; - /* if the current brush is not using the desired tool, look - * for one that is */ - br = brush_tool_cycle(bmain, paint, brush_orig, tool); - /* store the previously-selected brush */ - if (br) { - br->toggle_brush = brush_orig; - } - - return br; - } - if (brush_orig->toggle_brush) { - /* if current brush is using the desired tool, try to toggle - * back to the previously selected brush. */ - return brush_orig->toggle_brush; - } - return nullptr; -} - -/** The name of the active tool is "builtin_brush." concatenated with the returned string. */ -static blender::StringRefNull curves_active_tool_name_get(const eBrushCurvesSculptTool tool) -{ - switch (tool) { - case CURVES_SCULPT_TOOL_COMB: - return "comb"; - case CURVES_SCULPT_TOOL_DELETE: - return "delete"; - case CURVES_SCULPT_TOOL_SNAKE_HOOK: - return "snake_hook"; - case CURVES_SCULPT_TOOL_ADD: - return "add"; - case CURVES_SCULPT_TOOL_GROW_SHRINK: - return "grow_shrink"; - case CURVES_SCULPT_TOOL_SELECTION_PAINT: - return "selection_paint"; - case CURVES_SCULPT_TOOL_PINCH: - return "pinch"; - case CURVES_SCULPT_TOOL_SMOOTH: - return "smooth"; - case CURVES_SCULPT_TOOL_PUFF: - return "puff"; - case CURVES_SCULPT_TOOL_DENSITY: - return "density"; - case CURVES_SCULPT_TOOL_SLIDE: - return "slide"; - } - return ""; -} - -static bool brush_generic_tool_set(bContext *C, - Main *bmain, - Paint *paint, - const int tool, - const char *tool_name, - const bool create_missing, - const bool toggle) -{ - Brush *brush, *brush_orig = BKE_paint_brush(paint); - - if (toggle) { - brush = brush_tool_toggle(bmain, paint, brush_orig, tool); - } - else { - brush = brush_tool_cycle(bmain, paint, brush_orig, tool); - } - - if (((brush == nullptr) && create_missing) && - ((brush_orig == nullptr) || brush_tool(brush_orig, paint->runtime.tool_offset) != tool)) - { - brush = BKE_brush_add(bmain, tool_name, eObjectMode(paint->runtime.ob_mode)); - id_us_min(&brush->id); /* fake user only */ - brush_tool_set(brush, paint->runtime.tool_offset, tool); - brush->toggle_brush = brush_orig; - } - - if (brush) { - BKE_paint_brush_set(paint, brush); - BKE_paint_invalidate_overlay_all(); - - WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); - - /* Tool System - * This is needed for when there is a non-sculpt tool active (transform for e.g.). - * In case we are toggling (and the brush changed to the toggle_brush), we need to get the - * tool_name again. */ - int tool_result = brush_tool(brush, paint->runtime.tool_offset); - PaintMode paint_mode = BKE_paintmode_get_active_from_context(C); - - if (paint_mode == PaintMode::SculptCurves) { - tool_name = curves_active_tool_name_get(eBrushCurvesSculptTool(tool)).c_str(); - } - else { - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - RNA_enum_name_from_value(items, tool_result, &tool_name); - } - - char tool_id[MAX_NAME]; - SNPRINTF(tool_id, "builtin_brush.%s", tool_name); - WM_toolsystem_ref_set_by_id(C, tool_id); - - return true; - } - return false; -} - -static const PaintMode brush_select_paint_modes[] = { - PaintMode::Sculpt, - PaintMode::Vertex, - PaintMode::Weight, - PaintMode::Texture3D, - PaintMode::GPencil, - PaintMode::VertexGPencil, - PaintMode::SculptGPencil, - PaintMode::WeightGPencil, - PaintMode::SculptCurves, - PaintMode::SculptGreasePencil, -}; - -static int brush_select_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - const bool create_missing = RNA_boolean_get(op->ptr, "create_missing"); - const bool toggle = RNA_boolean_get(op->ptr, "toggle"); - const char *tool_name = "Brush"; - int tool = 0; - - PaintMode paint_mode = PaintMode::Invalid; - for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) { - paint_mode = brush_select_paint_modes[i]; - const char *op_prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, op_prop_id); - if (RNA_property_is_set(op->ptr, prop)) { - tool = RNA_property_enum_get(op->ptr, prop); - break; - } - } - - if (paint_mode == PaintMode::Invalid) { - return OPERATOR_CANCELLED; - } - - Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - if (paint == nullptr) { - return OPERATOR_CANCELLED; - } - - if (paint_mode == PaintMode::SculptCurves) { - tool_name = curves_active_tool_name_get(eBrushCurvesSculptTool(tool)).c_str(); - } - else { - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - RNA_enum_name_from_value(items, tool, &tool_name); - } - - if (brush_generic_tool_set(C, bmain, paint, tool, tool_name, create_missing, toggle)) { - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -static void PAINT_OT_brush_select(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Brush Select"; - ot->description = "Select a paint mode's brush by tool type"; - ot->idname = "PAINT_OT_brush_select"; - - /* api callbacks */ - ot->exec = brush_select_exec; - - /* flags */ - ot->flag = 0; - - /* props */ - /* All properties are hidden, so as not to show the redo panel. */ - for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) { - const PaintMode paint_mode = brush_select_paint_modes[i]; - const char *prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - /* Prevent a duplicate `gpencil_sculpt_tool` property. */ - if (RNA_struct_type_find_property_no_base(ot->srna, prop_id)) { - continue; - } - prop = RNA_def_enum( - ot->srna, prop_id, BKE_paint_get_tool_enum_from_paintmode(paint_mode), 0, prop_id, ""); - RNA_def_property_translation_context( - prop, BKE_paint_get_tool_enum_translation_context_from_paintmode(paint_mode)); - RNA_def_property_flag(prop, PROP_HIDDEN); - } - - prop = RNA_def_boolean( - ot->srna, "toggle", false, "Toggle", "Toggle between two brushes rather than cycling"); - RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); - prop = RNA_def_boolean(ot->srna, - "create_missing", - false, - "Create Missing", - "If the requested brush type does not exist, create a new brush"); - RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); -} - /***** Stencil Control *****/ enum StencilControlMode { @@ -1483,18 +970,19 @@ void ED_operatortypes_paint() WM_operatortype_append(PAINTCURVE_OT_cursor); /* brush */ - WM_operatortype_append(BRUSH_OT_add); - WM_operatortype_append(BRUSH_OT_add_gpencil); WM_operatortype_append(BRUSH_OT_scale_size); WM_operatortype_append(BRUSH_OT_curve_preset); WM_operatortype_append(BRUSH_OT_sculpt_curves_falloff_preset); - WM_operatortype_append(BRUSH_OT_reset); WM_operatortype_append(BRUSH_OT_stencil_control); WM_operatortype_append(BRUSH_OT_stencil_fit_image_aspect); WM_operatortype_append(BRUSH_OT_stencil_reset_transform); - - /* NOTE: particle uses a different system, can be added with existing operators in `wm.py`. */ - WM_operatortype_append(PAINT_OT_brush_select); + WM_operatortype_append(BRUSH_OT_asset_select); + WM_operatortype_append(BRUSH_OT_asset_save_as); + WM_operatortype_append(BRUSH_OT_asset_edit_metadata); + WM_operatortype_append(BRUSH_OT_asset_load_preview); + WM_operatortype_append(BRUSH_OT_asset_delete); + WM_operatortype_append(BRUSH_OT_asset_update); + WM_operatortype_append(BRUSH_OT_asset_revert); /* image */ WM_operatortype_append(PAINT_OT_texture_paint_toggle); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index a62da4ea788..7b8faf16c66 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -420,19 +420,17 @@ bool mode_toggle_poll_test(bContext *C) void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache) { - Main *bmain = CTX_data_main(C); Brush *brush = BKE_paint_brush(paint); /* The current brush should match with what we have stored in the cache. */ BLI_assert(brush == cache->brush); - /* If saved_active_brush_name is not set, brush was not switched/affected in + /* If saved_active_brush is not set, brush was not switched/affected in * smooth_brush_toggle_on(). */ - Brush *saved_active_brush = (Brush *)BKE_libblock_find_name( - bmain, ID_BR, cache->saved_active_brush_name); - if (saved_active_brush) { + if (cache->saved_active_brush) { Scene *scene = CTX_data_scene(C); BKE_brush_size_set(scene, brush, cache->saved_smooth_size); - BKE_paint_brush_set(paint, saved_active_brush); + BKE_paint_brush_set(paint, cache->saved_active_brush); + cache->saved_active_brush = nullptr; } } /* Initialize the stroke cache invariants from operator properties */ @@ -577,24 +575,27 @@ void last_stroke_update(Scene *scene, const float location[3]) /* -------------------------------------------------------------------- */ void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + Brush *cur_brush = BKE_paint_brush(paint); /* Switch to the blur (smooth) brush if possible. */ - /* NOTE: used for both vertexpaint and weightpaint, VPAINT_TOOL_BLUR & WPAINT_TOOL_BLUR are the - * same, see comments for eBrushVertexPaintTool & eBrushWeightPaintTool. */ - Brush *smooth_brush = BKE_paint_toolslots_brush_get(paint, WPAINT_TOOL_BLUR); + BKE_paint_brush_set_essentials(bmain, + paint, + (paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT) ? "Blur Weight" : + "Blur Vertex"); + Brush *smooth_brush = BKE_paint_brush(paint); + if (!smooth_brush) { + BKE_paint_brush_set(paint, cur_brush); CLOG_WARN(&LOG, "Switching to the blur (smooth) brush not possible, corresponding brush not"); - cache->saved_active_brush_name[0] = '\0'; + cache->saved_active_brush = nullptr; return; } - Brush *cur_brush = paint->brush; int cur_brush_size = BKE_brush_size_get(scene, cur_brush); - STRNCPY(cache->saved_active_brush_name, cur_brush->id.name + 2); - - BKE_paint_brush_set(paint, smooth_brush); + cache->saved_active_brush = cur_brush; cache->saved_smooth_size = BKE_brush_size_get(scene, smooth_brush); BKE_brush_size_set(scene, smooth_brush, cur_brush_size); BKE_curvemapping_init(smooth_brush->curve); diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index db3cbec300e..99931a48cc4 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -4200,8 +4200,9 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Brush *cur_brush = paint->brush; + Brush *cur_brush = BKE_paint_brush(paint); if (cur_brush->sculpt_tool == SCULPT_TOOL_MASK) { cache->saved_mask_brush_tool = cur_brush->mask_tool; @@ -4220,18 +4221,20 @@ static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache } /* Switch to the smooth brush if possible. */ - Brush *smooth_brush = BKE_paint_toolslots_brush_get(paint, SCULPT_TOOL_SMOOTH); + BKE_paint_brush_set_essentials(bmain, paint, "Smooth"); + Brush *smooth_brush = BKE_paint_brush(paint); + if (!smooth_brush) { + BKE_paint_brush_set(paint, cur_brush); CLOG_WARN(&LOG, "Switching to the smooth brush not possible, corresponding brush not"); - cache->saved_active_brush_name[0] = '\0'; + cache->saved_active_brush = nullptr; return; } int cur_brush_size = BKE_brush_size_get(scene, cur_brush); - STRNCPY(cache->saved_active_brush_name, cur_brush->id.name + 2); + cache->saved_active_brush = cur_brush; - BKE_paint_brush_set(paint, smooth_brush); cache->saved_smooth_size = BKE_brush_size_get(scene, smooth_brush); BKE_brush_size_set(scene, smooth_brush, cur_brush_size); BKE_curvemapping_init(smooth_brush->curve); @@ -4239,7 +4242,6 @@ static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache) { - Main *bmain = CTX_data_main(C); Brush *brush = BKE_paint_brush(paint); if (brush->sculpt_tool == SCULPT_TOOL_MASK) { @@ -4257,14 +4259,13 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache return; } - /* If saved_active_brush_name is not set, brush was not switched/affected in + /* If saved_active_brush is not set, brush was not switched/affected in * smooth_brush_toggle_on(). */ - Brush *saved_active_brush = (Brush *)BKE_libblock_find_name( - bmain, ID_BR, cache->saved_active_brush_name); - if (saved_active_brush) { + if (cache->saved_active_brush) { Scene *scene = CTX_data_scene(C); BKE_brush_size_set(scene, brush, cache->saved_smooth_size); - BKE_paint_brush_set(paint, saved_active_brush); + BKE_paint_brush_set(paint, cache->saved_active_brush); + cache->saved_active_brush = nullptr; } } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index 5992f9d1404..ddf43f59c69 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -508,7 +508,7 @@ struct StrokeCache { float vertex_rotation; /* amount to rotate the vertices when using rotate brush */ Dial *dial; - char saved_active_brush_name[MAX_ID_NAME]; + Brush *saved_active_brush; char saved_mask_brush_tool; int saved_smooth_size; /* smooth tool copies the size of the current tool */ bool alt_smooth; diff --git a/source/blender/editors/sound/sound_ops.cc b/source/blender/editors/sound/sound_ops.cc index d67bf355bb0..1962fdba665 100644 --- a/source/blender/editors/sound/sound_ops.cc +++ b/source/blender/editors/sound/sound_ops.cc @@ -797,15 +797,14 @@ static int sound_unpack_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); int method = RNA_enum_get(op->ptr, "method"); - bSound *sound = nullptr; + Editing *ed = CTX_data_scene(C)->ed; - /* find the supplied image by name */ - if (RNA_struct_property_is_set(op->ptr, "id")) { - char sndname[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "id", sndname); - sound = static_cast(BLI_findstring(&bmain->sounds, sndname, offsetof(ID, name) + 2)); + if (!ed || !ed->act_seq || ed->act_seq->type != SEQ_TYPE_SOUND_RAM) { + return OPERATOR_CANCELLED; } + bSound *sound = ed->act_seq->sound; + if (!sound || !sound->packedfile) { return OPERATOR_CANCELLED; } @@ -824,17 +823,12 @@ static int sound_unpack_exec(bContext *C, wmOperator *op) static int sound_unpack_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { Editing *ed = CTX_data_scene(C)->ed; - bSound *sound; - - if (RNA_struct_property_is_set(op->ptr, "id")) { - return sound_unpack_exec(C, op); - } if (!ed || !ed->act_seq || ed->act_seq->type != SEQ_TYPE_SOUND_RAM) { return OPERATOR_CANCELLED; } - sound = ed->act_seq->sound; + bSound *sound = ed->act_seq->sound; if (!sound || !sound->packedfile) { return OPERATOR_CANCELLED; @@ -846,8 +840,7 @@ static int sound_unpack_invoke(bContext *C, wmOperator *op, const wmEvent * /*ev "AutoPack is enabled, so image will be packed again on file save"); } - unpack_menu( - C, "SOUND_OT_unpack", sound->id.name + 2, sound->filepath, "sounds", sound->packedfile); + unpack_menu(C, "SOUND_OT_unpack", sound->filepath, "sounds", sound->packedfile); return OPERATOR_FINISHED; } @@ -870,9 +863,6 @@ static void SOUND_OT_unpack(wmOperatorType *ot) /* properties */ RNA_def_enum( ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack"); - /* XXX: weak!, will fail with library, name collisions */ - RNA_def_string( - ot->srna, "id", nullptr, MAX_ID_NAME - 2, "Sound Name", "Sound data-block name to unpack"); } /* ******************************************************* */ diff --git a/source/blender/editors/space_image/image_ops.cc b/source/blender/editors/space_image/image_ops.cc index 293764bb38e..a8b6dc51ccc 100644 --- a/source/blender/editors/space_image/image_ops.cc +++ b/source/blender/editors/space_image/image_ops.cc @@ -1323,7 +1323,6 @@ static Image *image_open_single(Main *bmain, static int image_open_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); ScrArea *area = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); ImageUser *iuser = nullptr; @@ -1338,6 +1337,11 @@ static int image_open_exec(bContext *C, wmOperator *op) image_open_init(C, op); } + ImageOpenData *iod = static_cast(op->customdata); + + Main *bmain = (iod->pprop.ptr.owner_id) ? CTX_data_main_from_id(C, iod->pprop.ptr.owner_id) : + CTX_data_main(C); + ListBase ranges = ED_image_filesel_detect_sequences(bmain, op, use_udim); LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) { Image *ima_range = image_open_single(bmain, op, range, use_multiview); @@ -1357,9 +1361,6 @@ static int image_open_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* hook into UI */ - ImageOpenData *iod = static_cast(op->customdata); - if (iod->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer use also increases user, so this compensates it */ @@ -1816,6 +1817,7 @@ void IMAGE_OT_replace(wmOperatorType *ot) * \{ */ struct ImageSaveData { + Main *bmain; ImageUser *iuser; Image *image; ImageSaveOptions opts; @@ -1855,16 +1857,16 @@ static bool save_image_op( static ImageSaveData *image_save_as_init(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Image *image = image_from_context(C); ImageUser *iuser = image_user_from_context(C); Scene *scene = CTX_data_scene(C); ImageSaveData *isd = static_cast(MEM_callocN(sizeof(*isd), __func__)); + isd->bmain = CTX_data_main_from_id(C, &image->id); isd->image = image; isd->iuser = iuser; - if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true, false)) { + if (!BKE_image_save_options_init(&isd->opts, isd->bmain, scene, image, iuser, true, false)) { BKE_image_save_options_free(&isd->opts); MEM_freeN(isd); return nullptr; @@ -1910,7 +1912,6 @@ static void image_save_as_free(wmOperator *op) static int image_save_as_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); ImageSaveData *isd; if (op->customdata) { @@ -1923,10 +1924,10 @@ static int image_save_as_exec(bContext *C, wmOperator *op) } } - image_save_options_from_op(bmain, &isd->opts, op); + image_save_options_from_op(isd->bmain, &isd->opts, op); BKE_image_save_options_update(&isd->opts, isd->image); - save_image_op(bmain, isd->image, isd->iuser, op, &isd->opts); + save_image_op(isd->bmain, isd->image, isd->iuser, op, &isd->opts); if (isd->opts.save_copy == false) { BKE_image_free_packedfiles(isd->image); @@ -1937,12 +1938,11 @@ static int image_save_as_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool image_save_as_check(bContext *C, wmOperator *op) +static bool image_save_as_check(bContext * /*C*/, wmOperator *op) { - Main *bmain = CTX_data_main(C); ImageSaveData *isd = static_cast(op->customdata); - image_save_options_from_op(bmain, &isd->opts, op); + image_save_options_from_op(isd->bmain, &isd->opts, op); BKE_image_save_options_update(&isd->opts, isd->image); return WM_operator_filesel_ensure_ext_imtype(op, &isd->opts.im_format); @@ -2124,8 +2124,8 @@ static bool image_save_poll(bContext *C) static int image_save_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Image *image = image_from_context(C); + Main *bmain = CTX_data_main_from_id(C, &image->id); ImageUser *iuser = image_user_from_context(C); Scene *scene = CTX_data_scene(C); ImageSaveOptions opts; @@ -2458,8 +2458,8 @@ void IMAGE_OT_save_all_modified(wmOperatorType *ot) static int image_reload_exec(bContext *C, wmOperator * /*op*/) { - Main *bmain = CTX_data_main(C); Image *ima = image_from_context(C); + Main *bmain = CTX_data_main_from_id(C, &ima->id); ImageUser *iuser = image_user_from_context(C); if (!ima) { @@ -2467,7 +2467,7 @@ static int image_reload_exec(bContext *C, wmOperator * /*op*/) } /* XXX BKE_packedfile_unpack_image frees image buffers */ - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); DEG_id_tag_update(&ima->id, 0); @@ -2528,9 +2528,7 @@ static void image_new_free(wmOperator *op) static int image_new_exec(bContext *C, wmOperator *op) { - SpaceImage *sima; Image *ima; - Main *bmain; PropertyRNA *prop; char name_buffer[MAX_ID_NAME - 2]; const char *name; @@ -2538,9 +2536,12 @@ static int image_new_exec(bContext *C, wmOperator *op) int width, height, floatbuf, gen_type, alpha; int stereo3d; + ImageNewData *data = image_new_init(C, op); + /* retrieve state */ - sima = CTX_wm_space_image(C); - bmain = CTX_data_main(C); + SpaceImage *sima = CTX_wm_space_image(C); + Main *bmain = (data->pprop.ptr.owner_id) ? CTX_data_main_from_id(C, data->pprop.ptr.owner_id) : + CTX_data_main(C); prop = RNA_struct_find_property(op->ptr, "name"); RNA_property_string_get(op->ptr, prop, name_buffer); @@ -2582,8 +2583,6 @@ static int image_new_exec(bContext *C, wmOperator *op) } /* hook into UI */ - ImageNewData *data = image_new_init(C, op); - if (data->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer use also increases user, so this compensates it */ @@ -3255,28 +3254,16 @@ void IMAGE_OT_resize(wmOperatorType *ot) /** \name Pack Operator * \{ */ -static bool image_pack_test(bContext *C, wmOperator *op) +static int image_pack_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); if (!ima) { - return false; + return OPERATOR_CANCELLED; } if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported"); - return false; - } - - return true; -} - -static int image_pack_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Image *ima = image_from_context(C); - - if (!image_pack_test(C, op)) { return OPERATOR_CANCELLED; } @@ -3284,6 +3271,7 @@ static int image_pack_exec(bContext *C, wmOperator *op) BKE_image_memorypack(ima); } else { + Main *bmain = CTX_data_main_from_id(C, &ima->id); BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id)); } @@ -3314,20 +3302,9 @@ void IMAGE_OT_pack(wmOperatorType *ot) static int image_unpack_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Image *ima = image_from_context(C); int method = RNA_enum_get(op->ptr, "method"); - /* find the supplied image by name */ - if (RNA_struct_property_is_set(op->ptr, "id")) { - char imaname[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "id", imaname); - ima = static_cast(BLI_findstring(&bmain->images, imaname, offsetof(ID, name) + 2)); - if (!ima) { - ima = image_from_context(C); - } - } - if (!ima || !BKE_image_has_packedfile(ima)) { return OPERATOR_CANCELLED; } @@ -3344,9 +3321,10 @@ static int image_unpack_exec(bContext *C, wmOperator *op) } /* XXX BKE_packedfile_unpack_image frees image buffers */ - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + Main *bmain = CTX_data_main_from_id(C, &ima->id); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - BKE_packedfile_unpack_image(CTX_data_main(C), op->reports, ima, ePF_FileStatus(method)); + BKE_packedfile_unpack_image(bmain, op->reports, ima, ePF_FileStatus(method)); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); @@ -3357,10 +3335,6 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent * /*ev { Image *ima = image_from_context(C); - if (RNA_struct_property_is_set(op->ptr, "id")) { - return image_unpack_exec(C, op); - } - if (!ima || !BKE_image_has_packedfile(ima)) { return OPERATOR_CANCELLED; } @@ -3378,7 +3352,6 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent * /*ev unpack_menu(C, "IMAGE_OT_unpack", - ima->id.name + 2, ima->filepath, "textures", BKE_image_has_packedfile(ima) ? @@ -3405,9 +3378,6 @@ void IMAGE_OT_unpack(wmOperatorType *ot) /* properties */ RNA_def_enum( ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack"); - /* XXX, weak!, will fail with library, name collisions */ - RNA_def_string( - ot->srna, "id", nullptr, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack"); } /** \} */ diff --git a/source/blender/editors/space_node/clipboard.cc b/source/blender/editors/space_node/clipboard.cc index 302e80bb6d2..fd565bfc74d 100644 --- a/source/blender/editors/space_node/clipboard.cc +++ b/source/blender/editors/space_node/clipboard.cc @@ -335,9 +335,9 @@ void NODE_OT_clipboard_copy(wmOperatorType *ot) static int node_clipboard_paste_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &tree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(C, &tree.id); NodeClipboard &clipboard = get_node_clipboard(); if (clipboard.nodes.is_empty()) { @@ -351,7 +351,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) "Some nodes references to other IDs could not be restored, will be left empty"); } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); node_deselect_all(tree); diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index 04905d92650..242342eb739 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -95,11 +95,12 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams ¶ms) nullptr); socket_iface->init_from_socket_instance(¶ms.socket); params.node_tree.tree_interface.active_item_set(&socket_iface->item); + Main *bmain = CTX_data_main_from_id(¶ms.C, ¶ms.node_tree.id); bNode &group_input = params.add_node("NodeGroupInput"); /* This is necessary to create the new sockets in the other input nodes. */ - ED_node_tree_propagate_change(¶ms.C, CTX_data_main(¶ms.C), ¶ms.node_tree); + ED_node_tree_propagate_change(¶ms.C, bmain, ¶ms.node_tree); /* Hide the new input in all other group input nodes, to avoid making them taller. */ for (bNode *node : params.node_tree.all_nodes()) { @@ -123,8 +124,7 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams ¶ms) socket->flag &= ~SOCK_HIDDEN; nodeAddLink(¶ms.node_tree, &group_input, socket, ¶ms.node, ¶ms.socket); - bke::node_socket_move_default_value( - *CTX_data_main(¶ms.C), params.node_tree, params.socket, *socket); + bke::node_socket_move_default_value(*bmain, params.node_tree, params.socket, *socket); } } @@ -201,7 +201,7 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree, search_link_ops.append( {asset_name + " " + UI_MENU_ARROW_SEP + socket_name, [&asset, socket_property, in_out](nodes::LinkSearchOpParams ¶ms) { - Main &bmain = *CTX_data_main(¶ms.C); + Main &bmain = *CTX_data_main_from_id(¶ms.C, ¶ms.node_tree.id); bNode &node = params.add_node(params.node_tree.typeinfo->group_idname); node.flag &= ~NODE_OPTIONS; @@ -345,7 +345,6 @@ static void link_drag_search_update_fn( static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &node_tree = *snode.edittree; LinkDragSearchStorage &storage = *static_cast(arg1); @@ -379,6 +378,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) /* Ideally it would be possible to tag the node tree in some way so it updates only after the * translate operation is finished, but normally moving nodes around doesn't cause updates. */ + Main &bmain = *CTX_data_main_from_id(C, &node_tree.id); ED_node_tree_propagate_change(C, &bmain, &node_tree); /* Start translation operator with the new node. */ diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 529ed7c16d6..68afda2db1a 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -71,8 +71,8 @@ static void position_node_based_on_mouse(bNode &node, const float2 &location) bNode *add_node(const bContext &C, const StringRef idname, const float2 &location) { SpaceNode &snode = *CTX_wm_space_node(&C); - Main &bmain = *CTX_data_main(&C); bNodeTree &node_tree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(&C, &node_tree.id); node_deselect_all(node_tree); @@ -93,8 +93,8 @@ bNode *add_node(const bContext &C, const StringRef idname, const float2 &locatio bNode *add_static_node(const bContext &C, int type, const float2 &location) { SpaceNode &snode = *CTX_wm_space_node(&C); - Main &bmain = *CTX_data_main(&C); bNodeTree &node_tree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(&C, &node_tree.id); node_deselect_all(node_tree); @@ -145,6 +145,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) const ARegion ®ion = *CTX_wm_region(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(C, &ntree.id); Vector path; RNA_BEGIN (op->ptr, itemptr, "path") { @@ -168,7 +169,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) ntree.ensure_topology_cache(); const Vector frame_nodes = ntree.nodes_by_type("NodeFrame"); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per * output socket is useful because it allows reusing reroutes for connected intersections. @@ -223,7 +224,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) } } - ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); + ED_node_tree_propagate_change(C, &bmain, &ntree); return OPERATOR_FINISHED; } @@ -291,9 +292,9 @@ static bool node_group_add_poll(const bNodeTree &node_tree, static int node_add_group_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; + Main *bmain = CTX_data_main_from_id(C, &ntree->id); bNodeTree *node_group = reinterpret_cast( WM_operator_properties_id_lookup_from_name_or_session_uid(bmain, op->ptr, ID_NT)); @@ -304,7 +305,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); const char *node_idname = node_group_idname(C); if (node_idname[0] == '\0') { @@ -398,9 +399,9 @@ static bool add_node_group_asset(const bContext &C, const asset_system::AssetRepresentation &asset, ReportList &reports) { - Main &bmain = *CTX_data_main(&C); SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree &edit_tree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(&C, &edit_tree.id); bNodeTree *node_group = reinterpret_cast( asset::asset_local_id_ensure_imported(bmain, asset)); @@ -414,7 +415,7 @@ static bool add_node_group_asset(const bContext &C, return false; } - ED_preview_kill_jobs(CTX_wm_manager(&C), CTX_data_main(&C)); + ED_preview_kill_jobs(CTX_wm_manager(&C), &bmain); bNode *group_node = add_node( C, ntreeTypeFind(node_group->idname)->group_idname, snode.runtime->cursor); @@ -510,9 +511,9 @@ void NODE_OT_add_group_asset(wmOperatorType *ot) static int node_add_object_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; + Main *bmain = CTX_data_main_from_id(C, &ntree->id); Object *object = reinterpret_cast( WM_operator_properties_id_lookup_from_name_or_session_uid(bmain, op->ptr, ID_OB)); @@ -521,7 +522,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor); if (!object_node) { @@ -596,9 +597,9 @@ void NODE_OT_add_object(wmOperatorType *ot) static int node_add_collection_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(C, &ntree.id); Collection *collection = reinterpret_cast( WM_operator_properties_id_lookup_from_name_or_session_uid(bmain, op->ptr, ID_GR)); @@ -607,7 +608,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor); if (!collection_node) { @@ -736,8 +737,10 @@ static int node_add_file_modal(bContext *C, wmOperator *op, const wmEvent *event static int node_add_file_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(C, &node_tree.id); + int type = 0; switch (snode.nodetree->type) { case NTREE_SHADER: @@ -807,14 +810,13 @@ static int node_add_file_exec(bContext *C, wmOperator *op) } /* Set new nodes as selected. */ - bNodeTree &node_tree = *snode.edittree; node_deselect_all(node_tree); for (bNode *node : nodes) { nodeSetSelected(node, true); } ED_node_set_active(bmain, &snode, &node_tree, nodes[0], nullptr); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); ED_node_tree_propagate_change(C, bmain, snode.edittree); DEG_relations_tag_update(bmain); @@ -898,15 +900,16 @@ static bool node_add_mask_poll(bContext *C) static int node_add_mask_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(C, &node_tree.id); ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uid(bmain, op->ptr, ID_MSK); if (!mask) { return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); bNode *node = add_static_node(*C, CMP_NODE_MASK, snode.runtime->cursor); @@ -949,9 +952,9 @@ void NODE_OT_add_mask(wmOperatorType *ot) static int node_add_material_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; + Main *bmain = CTX_data_main_from_id(C, &ntree->id); Material *material = reinterpret_cast( WM_operator_properties_id_lookup_from_name_or_session_uid(bmain, op->ptr, ID_MA)); @@ -960,7 +963,7 @@ static int node_add_material_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); bNode *material_node = add_static_node(*C, GEO_NODE_INPUT_MATERIAL, snode->runtime->cursor); if (!material_node) { @@ -1028,16 +1031,10 @@ void NODE_OT_add_material(wmOperatorType *ot) static int new_node_tree_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); - Main *bmain = CTX_data_main(C); - bNodeTree *ntree; - PointerRNA ptr; - PropertyRNA *prop; const char *idname; - char treename_buf[MAX_ID_NAME - 2]; - const char *treename; if (RNA_struct_property_is_set(op->ptr, "type")) { - prop = RNA_struct_find_property(op->ptr, "type"); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type"); RNA_property_enum_identifier(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &idname); } else if (snode) { @@ -1052,6 +1049,8 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + char treename_buf[MAX_ID_NAME - 2]; + const char *treename; if (RNA_struct_property_is_set(op->ptr, "name")) { RNA_string_get(op->ptr, "name", treename_buf); treename = treename_buf; @@ -1061,11 +1060,16 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) treename = type->ui_name; } - ntree = ntreeAddTree(bmain, treename, idname); - /* Hook into UI. */ + PointerRNA ptr; + PropertyRNA *prop; UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + Main *bmain = (ptr.owner_id) ? CTX_data_main_from_id(C, ptr.owner_id) : CTX_data_main(C); + + /* Add node tree and assign. */ + bNodeTree *ntree = ntreeAddTree(bmain, treename, idname); + if (prop) { /* #RNA_property_pointer_set increases the user count, fixed here as the editor is the initial * user. */ diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index e3668b2f364..6ce46495717 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -2361,9 +2361,9 @@ static void node_draw_sockets(const View2D &v2d, static void node_panel_toggle_button_cb(bContext *C, void *panel_state_argv, void *ntree_argv) { - Main *bmain = CTX_data_main(C); bNodePanelState *panel_state = static_cast(panel_state_argv); bNodeTree *ntree = static_cast(ntree_argv); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); panel_state->flag ^= NODE_PANEL_COLLAPSED; diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index b13bed11152..9af9749abbd 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -373,7 +373,7 @@ void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_ { using namespace blender::ed::space_node; - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &nodetree->id); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -545,7 +545,7 @@ bool ED_node_supports_preview(SpaceNode *snode) void ED_node_shader_default(const bContext *C, ID *id) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, id); if (GS(id->name) == ID_MA) { /* Materials */ @@ -642,7 +642,8 @@ void ED_node_composit_default(const bContext *C, Scene *sce) bNodeSocket *tosock = (bNodeSocket *)out->inputs.first; nodeAddLink(sce->nodetree, in, fromsock, out, tosock); - BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr); + Main *bmain = CTX_data_main_from_id(C, &sce->nodetree->id); + BKE_ntree_update_main_tree(bmain, sce->nodetree, nullptr); } void ED_node_texture_default(const bContext *C, Tex *tex) @@ -670,7 +671,8 @@ void ED_node_texture_default(const bContext *C, Tex *tex) bNodeSocket *tosock = (bNodeSocket *)out->inputs.first; nodeAddLink(tex->nodetree, in, fromsock, out, tosock); - BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr); + Main *bmain = CTX_data_main_from_id(C, &tex->nodetree->id); + BKE_ntree_update_main_tree(bmain, tex->nodetree, nullptr); } namespace blender::ed::space_node { @@ -1364,9 +1366,9 @@ void remap_node_pairing(bNodeTree &dst_tree, const Map & static int node_duplicate_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; + Main *bmain = CTX_data_main_from_id(C, &ntree->id); const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); bool linked = RNA_boolean_get(op->ptr, "linked") || ((U.dupflag & USER_DUP_NTREE) == 0); const bool dupli_node_tree = !linked; @@ -1504,10 +1506,10 @@ void NODE_OT_duplicate(wmOperatorType *ot) /* Goes over all scenes, reads render layers. */ static int node_read_viewlayers_exec(bContext *C, wmOperator * /*op*/) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); Scene *curscene = CTX_data_scene(C); bNodeTree &edit_tree = *snode->edittree; + Main *bmain = CTX_data_main_from_id(C, &edit_tree.id); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); @@ -1698,7 +1700,8 @@ static int node_preview_toggle_exec(bContext *C, wmOperator * /*op*/) node_flag_toggle_exec(snode, NODE_PREVIEW); - ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1749,7 +1752,8 @@ static int node_deactivate_viewer_exec(bContext *C, wmOperator * /*op*/) } } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); + Main *bmain = CTX_data_main_from_id(C, &snode.edittree->id); + ED_node_tree_propagate_change(C, bmain, snode.edittree); return OPERATOR_FINISHED; } @@ -1803,13 +1807,14 @@ void NODE_OT_options_toggle(wmOperatorType *ot) static int node_socket_toggle_exec(bContext *C, wmOperator * /*op*/) { SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); /* Sanity checking (poll callback checks this already). */ if ((snode == nullptr) || (snode->edittree == nullptr)) { return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); /* Toggle for all selected nodes */ bool hidden = false; @@ -1828,7 +1833,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator * /*op*/) } } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); + ED_node_tree_propagate_change(C, bmain, snode->edittree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); /* Hack to force update of the button state after drawing, see #112462. */ @@ -1860,8 +1865,8 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot) static int node_mute_exec(bContext *C, wmOperator * /*op*/) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); @@ -1900,8 +1905,8 @@ void NODE_OT_mute_toggle(wmOperatorType *ot) static int node_delete_exec(bContext *C, wmOperator * /*op*/) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); @@ -1954,6 +1959,7 @@ static bool node_switch_view_poll(bContext *C) static int node_switch_view_exec(bContext *C, wmOperator * /*op*/) { SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { @@ -1962,7 +1968,7 @@ static int node_switch_view_exec(bContext *C, wmOperator * /*op*/) } } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1990,10 +1996,10 @@ void NODE_OT_switch_view_update(wmOperatorType *ot) static int node_delete_reconnect_exec(bContext *C, wmOperator * /*op*/) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); /* Delete paired nodes as well. */ node_select_paired(*snode->edittree); @@ -2056,7 +2062,8 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "file_path", file_path); ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format); - ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -2109,7 +2116,8 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator * return OPERATOR_CANCELLED; } - ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); + ED_node_tree_propagate_change(C, bmain, ntree); return OPERATOR_FINISHED; } @@ -2180,8 +2188,9 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) nimf->active_input++; } + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); BKE_ntree_update_tag_node_property(snode->edittree, node); - ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -2327,7 +2336,6 @@ static bool node_shader_script_update_text_recursive(RenderEngine *engine, static int node_shader_script_update_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); SpaceNode *snode = CTX_wm_space_node(C); PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript); @@ -2360,7 +2368,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op) Text *text = (Text *)CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; if (text) { - + Main *bmain = CTX_data_main(C); VectorSet done_trees; FOREACH_NODETREE_BEGIN (bmain, ntree, id) { @@ -2502,9 +2510,10 @@ static int clear_viewer_border_exec(bContext *C, wmOperator * /*op*/) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *btree = snode->nodetree; + Main *bmain = CTX_data_main_from_id(C, &btree->id); btree->flag &= ~NTREE_VIEWER_BORDER; - ED_node_tree_propagate_change(C, CTX_data_main(C), btree); + ED_node_tree_propagate_change(C, bmain, btree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -2553,7 +2562,8 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator * /*op*/) ntreeCompositCryptomatteAddSocket(ntree, node); - ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); + ED_node_tree_propagate_change(C, bmain, ntree); return OPERATOR_FINISHED; } @@ -2603,7 +2613,8 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator * /*op*/) return OPERATOR_CANCELLED; } - ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); + ED_node_tree_propagate_change(C, bmain, ntree); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 04b08a2474e..918d3c8a19d 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -211,7 +211,8 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) /* Make the output socket with the new type on the attribute input node active. */ nodes::update_node_declaration_and_sockets(*node_tree, *node); BKE_ntree_update_tag_node_property(node_tree, node); - ED_node_tree_propagate_change(C, CTX_data_main(C), node_tree); + Main *bmain = CTX_data_main_from_id(C, &node_tree->id); + ED_node_tree_propagate_change(C, bmain, node_tree); } } diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 824e01a5766..93b6fa6d8d2 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -169,10 +169,11 @@ static void remap_pairing(bNodeTree &dst_tree, static int node_group_edit_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); const char *node_idname = node_group_idname(C); const bool exit = RNA_boolean_get(op->ptr, "exit"); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); stop_preview_job(*CTX_wm_manager(C)); bNode *gnode = node_group_get_active(C, node_idname); @@ -452,8 +453,8 @@ static void node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) static int node_group_ungroup_exec(bContext *C, wmOperator * /*op*/) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); const char *node_idname = node_group_idname(C); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); @@ -474,7 +475,7 @@ static int node_group_ungroup_exec(bContext *C, wmOperator * /*op*/) for (bNode *node : nodes_to_ungroup) { node_group_ungroup(bmain, snode->edittree, node); } - ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr); + ED_node_tree_propagate_change(C, bmain, nullptr); return OPERATOR_FINISHED; } @@ -625,8 +626,8 @@ static const EnumPropertyItem node_group_separate_types[] = { static int node_group_separate_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main_from_id(C, &snode->edittree->id); int type = RNA_enum_get(op->ptr, "type"); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); @@ -660,7 +661,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op) /* switch to parent tree */ ED_node_tree_pop(snode); - ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr); + ED_node_tree_propagate_change(C, bmain, nullptr); return OPERATOR_FINISHED; } @@ -926,7 +927,7 @@ static void node_group_make_insert_selected(const bContext &C, bNode *gnode, const VectorSet &nodes_to_move) { - Main *bmain = CTX_data_main(&C); + Main *bmain = CTX_data_main_from_id(&C, &ntree.id); bNodeTree &group = *reinterpret_cast(gnode->id); BLI_assert(!nodes_to_move.contains(gnode)); @@ -1206,7 +1207,7 @@ static bNode *node_group_make_from_nodes(const bContext &C, const char *ntype, const char *ntreetype) { - Main *bmain = CTX_data_main(&C); + Main *bmain = CTX_data_main_from_id(&C, &ntree.id); float2 min, max; get_min_max_of_nodes(nodes_to_group, false, min, max); @@ -1232,9 +1233,9 @@ static int node_group_make_exec(bContext *C, wmOperator *op) bNodeTree &ntree = *snode.edittree; const char *ntree_idname = group_ntree_idname(C); const char *node_idname = node_group_idname(C); - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &ntree.id); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); stop_preview_job(*CTX_wm_manager(C)); VectorSet nodes_to_group = get_nodes_to_group(ntree, nullptr); @@ -1286,9 +1287,10 @@ static int node_group_insert_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; + Main *bmain = CTX_data_main_from_id(C, &ntree->id); const char *node_idname = node_group_idname(C); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); stop_preview_job(*CTX_wm_manager(C)); bNode *gnode = node_group_get_active(C, node_idname); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 5446bea1cab..da459140c24 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -576,7 +576,7 @@ static void finalize_viewer_link(const bContext &C, bNode &viewer_node, bNodeLink &viewer_link) { - Main *bmain = CTX_data_main(&C); + Main *bmain = CTX_data_main_from_id(&C, &snode.edittree->id); remove_links_to_unavailable_viewer_sockets(*snode.edittree, viewer_node); viewer_link.flag &= ~NODE_LINK_MUTED; viewer_node.flag &= ~NODE_MUTED; @@ -683,12 +683,13 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator * /*op*/) { SpaceNode &snode = *CTX_wm_space_node(C); bNode *node = nodeGetActive(snode.edittree); + Main *bmain = CTX_data_main_from_id(C, &snode.edittree->id); if (!node) { return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); bNodeSocket *socket_to_view = nullptr; LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { @@ -702,7 +703,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator * /*op*/) return OPERATOR_CANCELLED; } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); + ED_node_tree_propagate_change(C, bmain, snode.edittree); return OPERATOR_FINISHED; } @@ -1027,10 +1028,10 @@ static void node_remove_existing_links_if_needed(bNodeLinkDrag &nldrag, bNodeTre static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag) { - Main *bmain = CTX_data_main(&C); ARegion ®ion = *CTX_wm_region(&C); SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree &ntree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(&C, &ntree.id); /* Handle node links already occupying the socket. */ if (const bNodeSocket *linked_socket = nldrag.hovered_socket) { @@ -1353,9 +1354,9 @@ static std::unique_ptr node_link_init(ARegion ®ion, static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); ARegion ®ion = *CTX_wm_region(C); + Main *bmain = CTX_data_main_from_id(C, &snode.edittree->id); bool detach = RNA_boolean_get(op->ptr, "detach"); @@ -1366,7 +1367,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) UI_view2d_region_to_view(®ion.v2d, mval[0], mval[1], &cursor[0], &cursor[1]); RNA_float_set_array(op->ptr, "drag_start", cursor); - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); std::unique_ptr nldrag = node_link_init(region, snode, cursor, detach); if (!nldrag) { @@ -1433,12 +1434,12 @@ void NODE_OT_link(wmOperatorType *ot) /* Makes a link between selected output and input sockets. */ static int node_make_link_exec(bContext *C, wmOperator *op) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &node_tree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(C, &node_tree.id); const bool replace = RNA_boolean_get(op->ptr, "replace"); - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); snode_autoconnect(snode, true, replace); @@ -1446,7 +1447,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op) node_deselect_all_input_sockets(node_tree, false); node_deselect_all_output_sockets(node_tree, false); - ED_node_tree_propagate_change(C, &bmain, &node_tree); + ED_node_tree_propagate_change(C, bmain, &node_tree); return OPERATOR_FINISHED; } @@ -1478,7 +1479,6 @@ void NODE_OT_link_make(wmOperatorType *ot) static int cut_links_exec(bContext *C, wmOperator *op) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); const ARegion ®ion = *CTX_wm_region(C); @@ -1501,9 +1501,11 @@ static int cut_links_exec(bContext *C, wmOperator *op) bool found = false; + bNodeTree &node_tree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(C, &node_tree.id); + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - bNodeTree &node_tree = *snode.edittree; node_tree.ensure_topology_cache(); Set links_to_remove; @@ -1535,7 +1537,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) update_multi_input_indices_for_removed_links(*node); } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); + ED_node_tree_propagate_change(C, &bmain, &node_tree); if (found) { return OPERATOR_FINISHED; } @@ -1586,10 +1588,10 @@ bool all_links_muted(const bNodeSocket &socket) static int mute_links_exec(bContext *C, wmOperator *op) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); const ARegion ®ion = *CTX_wm_region(C); bNodeTree &ntree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(C, &ntree.id); Vector path; RNA_BEGIN (op->ptr, itemptr, "path") { @@ -1665,7 +1667,7 @@ static int mute_links_exec(bContext *C, wmOperator *op) } } - ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); + ED_node_tree_propagate_change(C, &bmain, &ntree); return OPERATOR_FINISHED; } @@ -1704,8 +1706,9 @@ static int detach_links_exec(bContext *C, wmOperator * /*op*/) { SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(C, &ntree.id); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); for (bNode *node : ntree.all_nodes()) { if (node->flag & SELECT) { @@ -1713,7 +1716,7 @@ static int detach_links_exec(bContext *C, wmOperator * /*op*/) } } - ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); + ED_node_tree_propagate_change(C, &bmain, &ntree); return OPERATOR_FINISHED; } @@ -1824,9 +1827,9 @@ static void node_join_attach_recursive(bNodeTree &ntree, static int node_join_exec(bContext *C, wmOperator * /*op*/) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(C, &ntree.id); const VectorSet selected_nodes = get_selected_nodes(ntree); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 5d0450e317f..e038d31472d 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -512,9 +512,9 @@ void NODE_OT_select_grouped(wmOperatorType *ot) void node_select_single(bContext &C, bNode &node) { - Main *bmain = CTX_data_main(&C); SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree &node_tree = *snode.edittree; + Main *bmain = CTX_data_main_from_id(&C, &node_tree.id); const Object *ob = CTX_data_active_object(&C); const Scene *scene = CTX_data_scene(&C); const wmWindowManager *wm = CTX_wm_manager(&C); @@ -543,9 +543,9 @@ static bool node_mouse_select(bContext *C, const int2 mval, SelectPick_Params *params) { - Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &node_tree = *snode.edittree; + Main &bmain = *CTX_data_main_from_id(C, &node_tree.id); ARegion ®ion = *CTX_wm_region(C); const Object *ob = CTX_data_active_object(C); const Scene *scene = CTX_data_scene(C); diff --git a/source/blender/editors/space_node/node_shader_preview.cc b/source/blender/editors/space_node/node_shader_preview.cc index b7fd483bd21..bd01c7e3d0a 100644 --- a/source/blender/editors/space_node/node_shader_preview.cc +++ b/source/blender/editors/space_node/node_shader_preview.cc @@ -803,7 +803,7 @@ static void ensure_nodetree_previews(const bContext &C, job_data->scene = scene; job_data->tree_previews = &tree_previews; - job_data->bmain = CTX_data_main(&C); + job_data->bmain = CTX_data_main_from_id(&C, &displayed_nodetree->id); job_data->mat_copy = duplicate_material(material); job_data->rendering_node = nullptr; job_data->rendering_AOVs = false; diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index 31d47ce5b66..d48787df732 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -195,7 +195,7 @@ static void node_socket_add_replace(const bContext *C, int type, NodeLinkItem *item) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); bNode *node_from; bNodeSocket *sock_from_tmp; bNode *node_prev = nullptr; @@ -600,7 +600,6 @@ static void node_menu_column_foreach_cb(void *calldata, int nclass, const char * static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); uiBlock *block = uiLayoutGetBlock(layout); uiBut *but = (uiBut *)but_p; @@ -608,6 +607,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ NodeLinkArg *arg = (NodeLinkArg *)but->func_argN; bNodeSocket *sock = arg->sock; bNodeTreeType *ntreetype = arg->ntree->typeinfo; + Main *bmain = CTX_data_main_from_id(C, &arg->ntree->id); UI_block_layout_set_current(block, layout); split = uiLayoutSplit(layout, 0.0f, false); @@ -617,7 +617,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ arg->layout = split; if (ntreetype && ntreetype->foreach_nodeclass) { - ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb); + ntreetype->foreach_nodeclass(arg, node_menu_column_foreach_cb); } column = uiLayoutColumn(split, false); @@ -722,9 +722,9 @@ static void ui_node_draw_input(uiLayout &layout, static void node_panel_toggle_button_cb(bContext *C, void *panel_state_argv, void *ntree_argv) { - Main *bmain = CTX_data_main(C); bNodePanelState *panel_state = static_cast(panel_state_argv); bNodeTree *ntree = static_cast(ntree_argv); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); panel_state->flag ^= NODE_PANEL_COLLAPSED; diff --git a/source/blender/editors/util/ed_util.cc b/source/blender/editors/util/ed_util.cc index 585064ad685..900bf404402 100644 --- a/source/blender/editors/util/ed_util.cc +++ b/source/blender/editors/util/ed_util.cc @@ -358,12 +358,8 @@ void apply_keyb_grid( } } -void unpack_menu(bContext *C, - const char *opname, - const char *id_name, - const char *abs_name, - const char *folder, - PackedFile *pf) +void unpack_menu( + bContext *C, const char *opname, const char *abs_name, const char *folder, PackedFile *pf) { Main *bmain = CTX_data_main(C); PointerRNA props_ptr; @@ -385,7 +381,6 @@ void unpack_menu(bContext *C, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_REMOVE); - RNA_string_set(&props_ptr, "id", id_name); if (blendfile_path[0] != '\0') { char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; @@ -399,7 +394,6 @@ void unpack_menu(bContext *C, uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL); - RNA_string_set(&props_ptr, "id", id_name); break; case PF_CMP_EQUAL: @@ -408,7 +402,6 @@ void unpack_menu(bContext *C, uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL); - RNA_string_set(&props_ptr, "id", id_name); break; case PF_CMP_DIFFERS: @@ -417,14 +410,12 @@ void unpack_menu(bContext *C, uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL); - RNA_string_set(&props_ptr, "id", id_name); SNPRINTF(line, IFACE_("Overwrite %s"), local_name); // uiItemEnumO_ptr(layout, ot, line, ICON_NONE, "method", PF_WRITE_LOCAL); uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL); - RNA_string_set(&props_ptr, "id", id_name); break; } } @@ -437,7 +428,6 @@ void unpack_menu(bContext *C, uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL); - RNA_string_set(&props_ptr, "id", id_name); break; case PF_CMP_EQUAL: SNPRINTF(line, IFACE_("Use %s (identical)"), abs_name); @@ -445,7 +435,6 @@ void unpack_menu(bContext *C, uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL); - RNA_string_set(&props_ptr, "id", id_name); break; case PF_CMP_DIFFERS: SNPRINTF(line, IFACE_("Use %s (differs)"), abs_name); @@ -453,14 +442,12 @@ void unpack_menu(bContext *C, uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL); - RNA_string_set(&props_ptr, "id", id_name); SNPRINTF(line, IFACE_("Overwrite %s"), abs_name); // uiItemEnumO_ptr(layout, ot, line, ICON_NONE, "method", PF_WRITE_ORIGINAL); uiItemFullO_ptr( layout, ot, line, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL); - RNA_string_set(&props_ptr, "id", id_name); break; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index c25223dcb66..64be752dbd2 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -1000,6 +1000,15 @@ enum { * RESET_NEVER */ LIB_TAG_NOT_ALLOCATED = 1 << 26, + /** + * ID is part of an asset #Main separate from the regular main database. + * + * RESET_NEVER + * + * Datablocks like this can not be linked to and from datablocks in regular main. + * They should stay isolated from each other. + */ + LIB_TAG_ASSET_EDIT_MAIN = 1 << 27, /* ------------------------------------------------------------------------------------------- */ diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index e338c0ed568..9c8ebb063cc 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -165,41 +165,6 @@ typedef enum eGP_BrushMode { GP_BRUSH_MODE_VERTEXCOLOR = 2, } eGP_BrushMode; -/* BrushGpencilSettings default brush icons */ -typedef enum eGP_BrushIcons { - GP_BRUSH_ICON_PENCIL = 1, - GP_BRUSH_ICON_PEN = 2, - GP_BRUSH_ICON_INK = 3, - GP_BRUSH_ICON_INKNOISE = 4, - GP_BRUSH_ICON_BLOCK = 5, - GP_BRUSH_ICON_MARKER = 6, - GP_BRUSH_ICON_FILL = 7, - GP_BRUSH_ICON_ERASE_SOFT = 8, - GP_BRUSH_ICON_ERASE_HARD = 9, - GP_BRUSH_ICON_ERASE_STROKE = 10, - GP_BRUSH_ICON_AIRBRUSH = 11, - GP_BRUSH_ICON_CHISEL = 12, - GP_BRUSH_ICON_TINT = 13, - GP_BRUSH_ICON_VERTEX_DRAW = 14, - GP_BRUSH_ICON_VERTEX_BLUR = 15, - GP_BRUSH_ICON_VERTEX_AVERAGE = 16, - GP_BRUSH_ICON_VERTEX_SMEAR = 17, - GP_BRUSH_ICON_VERTEX_REPLACE = 18, - GP_BRUSH_ICON_GPBRUSH_SMOOTH = 19, - GP_BRUSH_ICON_GPBRUSH_THICKNESS = 20, - GP_BRUSH_ICON_GPBRUSH_STRENGTH = 21, - GP_BRUSH_ICON_GPBRUSH_RANDOMIZE = 22, - GP_BRUSH_ICON_GPBRUSH_GRAB = 23, - GP_BRUSH_ICON_GPBRUSH_PUSH = 24, - GP_BRUSH_ICON_GPBRUSH_TWIST = 25, - GP_BRUSH_ICON_GPBRUSH_PINCH = 26, - GP_BRUSH_ICON_GPBRUSH_CLONE = 27, - GP_BRUSH_ICON_GPBRUSH_WEIGHT = 28, - GP_BRUSH_ICON_GPBRUSH_BLUR = 29, - GP_BRUSH_ICON_GPBRUSH_AVERAGE = 30, - GP_BRUSH_ICON_GPBRUSH_SMEAR = 31, -} eGP_BrushIcons; - typedef enum eBrushCurvePreset { BRUSH_CURVE_CUSTOM = 0, BRUSH_CURVE_SMOOTH = 1, diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 9d7f630ee0c..ad8a7562c04 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -59,7 +59,7 @@ typedef struct BrushGpencilSettings { char _pad2[2]; /* Type of caps: eGPDstroke_Caps. */ int8_t caps_type; - char _pad[5]; + char _pad[1]; int flag2; @@ -69,8 +69,6 @@ typedef struct BrushGpencilSettings { int fill_draw_mode; /** Type of gap filling extension to use. */ int fill_extend_mode; - /** Icon identifier. */ - int icon_id; /** Maximum distance before generate new point for very fast mouse movements. */ int input_samples; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index cfcd0eade5d..c37710e23a1 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -897,27 +897,26 @@ typedef struct TimeMarker { typedef struct Paint_Runtime { /** Avoid having to compare with scene pointer everywhere. */ - unsigned int tool_offset; + unsigned int initialized; unsigned short ob_mode; char _pad[2]; } Paint_Runtime; -/** We might want to store other things here. */ -typedef struct PaintToolSlot { - struct Brush *brush; -} PaintToolSlot; - /** Paint Tool Base. */ typedef struct Paint { + /** + * The active brush. Possibly null. Possibly stored in a separate #Main data-base and not user- + * counted. + * //TODO: Or always stored in a separate #Main? + */ struct Brush *brush; /** - * Each tool has its own active brush, - * The currently active tool is defined by the current 'brush'. + * A weak asset reference to the #brush, if not NULL. + * Used to attempt restoring the active brush from the AssetLibrary system, typically on + * file load. */ - struct PaintToolSlot *tool_slots; - int tool_slots_len; - char _pad1[4]; + struct AssetWeakReference *brush_asset_reference; struct Palette *palette; /** Cavity curve. */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index f50a9a10625..6d610fc1614 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -833,6 +833,7 @@ typedef struct AssetShelf { AssetShelfSettings settings; + /** Only for the permanent asset shelf regions, not asset shelves in temporary popups. */ short preferred_row_count; char _pad[6]; } AssetShelf; diff --git a/source/blender/makesrna/intern/makesrna.cc b/source/blender/makesrna/intern/makesrna.cc index 10ae8b482fc..66b1b445ed6 100644 --- a/source/blender/makesrna/intern/makesrna.cc +++ b/source/blender/makesrna/intern/makesrna.cc @@ -1269,14 +1269,30 @@ static char *rna_def_property_set_func( else { rna_print_data_get(f, dp); + PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop; + StructRNA *type = (pprop->type) ? rna_find_struct((const char *)pprop->type) : nullptr; + if (prop->flag & PROP_ID_SELF_CHECK) { + /* No pointers to self allowed. */ rna_print_id_get(f, dp); fprintf(f, " if (id == value.data) {\n"); fprintf(f, " return;\n"); fprintf(f, " }\n"); } + if (type && (type->flag & STRUCT_ID)) { + /* Can only assign pointers between datablocks in the same main database. */ + fprintf(f, " if (value.data) {\n"); + fprintf(f, " Main *owner_main = BKE_main_from_id(G_MAIN, ptr->owner_id);\n"); + fprintf(f, " Main *value_main = BKE_main_from_id(G_MAIN, (ID *)value.data);\n"); + fprintf(f, " if (owner_main && owner_main != value_main) {\n"); + fprintf(f, " return;\n"); + fprintf(f, " }\n"); + fprintf(f, " }\n"); + } + if (prop->flag & PROP_ID_REFCOUNT) { + /* Perform reference counting. */ fprintf(f, "\n if (data->%s) {\n", dp->dnaname); fprintf(f, " id_us_min((ID *)data->%s);\n", dp->dnaname); fprintf(f, " }\n"); @@ -1284,14 +1300,11 @@ static char *rna_def_property_set_func( fprintf(f, " id_us_plus((ID *)value.data);\n"); fprintf(f, " }\n"); } - else { - PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop; - StructRNA *type = (pprop->type) ? rna_find_struct((const char *)pprop->type) : nullptr; - if (type && (type->flag & STRUCT_ID)) { - fprintf(f, " if (value.data) {\n"); - fprintf(f, " id_lib_extern((ID *)value.data);\n"); - fprintf(f, " }\n"); - } + else if (type && (type->flag & STRUCT_ID)) { + /* Still mark linked data as used if not reference counting. */ + fprintf(f, " if (value.data) {\n"); + fprintf(f, " id_lib_extern((ID *)value.data);\n"); + fprintf(f, " }\n"); } fprintf(f, " *(void **)&data->%s = value.data;\n", dp->dnaname); @@ -3365,7 +3378,8 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA fprintf(f, ", "); } first = 0; - fprintf(f, "CTX_data_main(C)"); /* may have direct access later */ + /* May have direct access later. */ + fprintf(f, "(_ptr->owner_id) ? CTX_data_main_from_id(C, _ptr->owner_id) : CTX_data_main(C)"); } if (func->flag & FUNC_USE_CONTEXT) { @@ -4880,6 +4894,7 @@ static void rna_generate(BlenderRNA *brna, FILE *f, const char *filename, const fprintf(f, "#include \"BLI_utildefines.h\"\n\n"); fprintf(f, "#include \"BKE_context.hh\"\n"); + fprintf(f, "#include \"BKE_global.hh\"\n"); fprintf(f, "#include \"BKE_lib_id.hh\"\n"); fprintf(f, "#include \"BKE_main.hh\"\n"); fprintf(f, "#include \"BKE_report.hh\"\n"); diff --git a/source/blender/makesrna/intern/rna_ID.cc b/source/blender/makesrna/intern/rna_ID.cc index 22e6a86fe00..dcd0ede8913 100644 --- a/source/blender/makesrna/intern/rna_ID.cc +++ b/source/blender/makesrna/intern/rna_ID.cc @@ -289,10 +289,9 @@ int rna_ID_name_length(PointerRNA *ptr) void rna_ID_name_set(PointerRNA *ptr, const char *value) { ID *id = (ID *)ptr->data; - BLI_assert(BKE_id_is_in_global_main(id)); - BLI_assert(!ID_IS_LINKED(id)); + Main *bmain = BKE_main_from_id(G_MAIN, id); - BKE_libblock_rename(G_MAIN, id, value); + BKE_libblock_rename(bmain, id, value); if (GS(id->name) == ID_OB) { Object *ob = (Object *)id; @@ -300,6 +299,8 @@ void rna_ID_name_set(PointerRNA *ptr, const char *value) DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } } + + /* TODO: this does not update immediately in the asset shelf. */ } static int rna_ID_name_editable(const PointerRNA *ptr, const char **r_info) @@ -325,7 +326,7 @@ static int rna_ID_name_editable(const PointerRNA *ptr, const char **r_info) return 0; } } - else if (!BKE_id_is_in_global_main(id)) { + else if (BKE_main_from_id(G_MAIN, id, true) == nullptr) { if (r_info) { *r_info = N_("Datablocks not in global Main data-base cannot be renamed"); } @@ -1166,16 +1167,20 @@ bool rna_IDMaterials_assign_int(PointerRNA *ptr, int key, const PointerRNA *assi { ID *id = ptr->owner_id; short *totcol = BKE_id_material_len_p(id); - Material *mat_id = (Material *)assign_ptr->owner_id; - if (totcol && (key >= 0 && key < *totcol)) { - BLI_assert(BKE_id_is_in_global_main(id)); - BLI_assert(BKE_id_is_in_global_main(&mat_id->id)); - BKE_id_material_assign(G_MAIN, id, mat_id, key + 1); - return true; - } - else { + Material *mat = (Material *)assign_ptr->owner_id; + if (!(totcol && (key >= 0 && key < *totcol))) { return false; } + + Main *bmain = BKE_main_from_id(G_MAIN, id); + if (mat) { + if (bmain != BKE_main_from_id(G_MAIN, &mat->id)) { + return false; + } + } + + BKE_id_material_assign(bmain, id, mat, key + 1); + return true; } static void rna_IDMaterials_append_id(ID *id, Main *bmain, Material *ma) @@ -1226,8 +1231,8 @@ static void rna_IDMaterials_clear_id(ID *id, Main *bmain) static void rna_Library_filepath_set(PointerRNA *ptr, const char *value) { Library *lib = (Library *)ptr->data; - BLI_assert(BKE_id_is_in_global_main(&lib->id)); - BKE_library_filepath_set(G_MAIN, lib, value); + Main *bmain = BKE_main_from_id(G_MAIN, &lib->id); + BKE_library_filepath_set(bmain, lib, value); } /* ***** ImagePreview ***** */ @@ -2315,6 +2320,14 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Is Indirect", "Is this ID block linked indirectly"); + prop = RNA_def_property(srna, "is_asset_library_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "tag", LIB_TAG_ASSET_EDIT_MAIN); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Asset Library Data", + "This data-block is part of an asset library blend file, not the blend " + "file opened for editing"); + prop = RNA_def_property(srna, "library", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, nullptr, "lib"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_access.cc b/source/blender/makesrna/intern/rna_access.cc index 2ed5acb5d5f..496b7f2db67 100644 --- a/source/blender/makesrna/intern/rna_access.cc +++ b/source/blender/makesrna/intern/rna_access.cc @@ -2144,7 +2144,8 @@ static bool rna_property_editable_do(const PointerRNA *ptr, return false; } if (ID_IS_OVERRIDE_LIBRARY(id)) { - const bool is_liboverride_system = BKE_lib_override_library_is_system_defined(G_MAIN, id); + Main *main = BKE_main_from_id(G_MAIN, id); + const bool is_liboverride_system = BKE_lib_override_library_is_system_defined(main, id); if (!RNA_property_overridable_get(ptr, prop_orig)) { if (r_info != nullptr && (*r_info)[0] == '\0') { *r_info = N_("Can't edit this property from an override data-block"); @@ -2389,7 +2390,8 @@ bool RNA_property_update_check(PropertyRNA *prop) void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop) { - rna_property_update(C, CTX_data_main(C), CTX_data_scene(C), ptr, prop); + Main *bmain = (ptr->owner_id) ? CTX_data_main_from_id(C, ptr->owner_id) : CTX_data_main(C); + rna_property_update(C, bmain, CTX_data_scene(C), ptr, prop); } void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop) diff --git a/source/blender/makesrna/intern/rna_armature.cc b/source/blender/makesrna/intern/rna_armature.cc index a26c45580b9..6094a94981d 100644 --- a/source/blender/makesrna/intern/rna_armature.cc +++ b/source/blender/makesrna/intern/rna_armature.cc @@ -791,28 +791,36 @@ static void rna_EditBone_name_set(PointerRNA *ptr, const char *value) { bArmature *arm = (bArmature *)ptr->owner_id; EditBone *ebone = (EditBone *)ptr->data; - char oldname[sizeof(ebone->name)], newname[sizeof(ebone->name)]; + Main *main = BKE_main_from_id(G_MAIN, &arm->id); + if (main == nullptr) { + return; + } + + char oldname[sizeof(ebone->name)], newname[sizeof(ebone->name)]; /* need to be on the stack */ STRNCPY_UTF8(newname, value); STRNCPY(oldname, ebone->name); - BLI_assert(BKE_id_is_in_global_main(&arm->id)); - ED_armature_bone_rename(G_MAIN, arm, oldname, newname); + ED_armature_bone_rename(main, arm, oldname, newname); } static void rna_Bone_name_set(PointerRNA *ptr, const char *value) { bArmature *arm = (bArmature *)ptr->owner_id; Bone *bone = (Bone *)ptr->data; - char oldname[sizeof(bone->name)], newname[sizeof(bone->name)]; + Main *main = BKE_main_from_id(G_MAIN, &arm->id); + if (main == nullptr) { + return; + } + + char oldname[sizeof(bone->name)], newname[sizeof(bone->name)]; /* need to be on the stack */ STRNCPY_UTF8(newname, value); STRNCPY(oldname, bone->name); - BLI_assert(BKE_id_is_in_global_main(&arm->id)); - ED_armature_bone_rename(G_MAIN, arm, oldname, newname); + ED_armature_bone_rename(main, arm, oldname, newname); } static void rna_EditBone_connected_check(EditBone *ebone) diff --git a/source/blender/makesrna/intern/rna_brush.cc b/source/blender/makesrna/intern/rna_brush.cc index ebeb8e33777..94db3aa46c9 100644 --- a/source/blender/makesrna/intern/rna_brush.cc +++ b/source/blender/makesrna/intern/rna_brush.cc @@ -391,50 +391,6 @@ static EnumPropertyItem rna_enum_gpencil_brush_modes_items[] = { {GP_BRUSH_MODE_VERTEXCOLOR, "VERTEXCOLOR", 0, "Vertex Color", "Use always Vertex Color mode"}, {0, nullptr, 0, nullptr, nullptr}}; -static EnumPropertyItem rna_enum_gpencil_brush_paint_icons_items[] = { - {GP_BRUSH_ICON_PENCIL, "PENCIL", ICON_GPBRUSH_PENCIL, "Pencil", ""}, - {GP_BRUSH_ICON_PEN, "PEN", ICON_GPBRUSH_PEN, "Pen", ""}, - {GP_BRUSH_ICON_INK, "INK", ICON_GPBRUSH_INK, "Ink", ""}, - {GP_BRUSH_ICON_INKNOISE, "INKNOISE", ICON_GPBRUSH_INKNOISE, "Ink Noise", ""}, - {GP_BRUSH_ICON_BLOCK, "BLOCK", ICON_GPBRUSH_BLOCK, "Block", ""}, - {GP_BRUSH_ICON_MARKER, "MARKER", ICON_GPBRUSH_MARKER, "Marker", ""}, - {GP_BRUSH_ICON_AIRBRUSH, "AIRBRUSH", ICON_GPBRUSH_AIRBRUSH, "Airbrush", ""}, - {GP_BRUSH_ICON_CHISEL, "CHISEL", ICON_GPBRUSH_CHISEL, "Chisel", ""}, - {GP_BRUSH_ICON_FILL, "FILL", ICON_GPBRUSH_FILL, "Fill", ""}, - {GP_BRUSH_ICON_ERASE_SOFT, "SOFT", ICON_GPBRUSH_ERASE_SOFT, "Eraser Soft", ""}, - {GP_BRUSH_ICON_ERASE_HARD, "HARD", ICON_GPBRUSH_ERASE_HARD, "Eraser Hard", ""}, - {GP_BRUSH_ICON_ERASE_STROKE, "STROKE", ICON_GPBRUSH_ERASE_STROKE, "Eraser Stroke", ""}, - {0, nullptr, 0, nullptr, nullptr}, -}; - -static EnumPropertyItem rna_enum_gpencil_brush_sculpt_icons_items[] = { - {GP_BRUSH_ICON_GPBRUSH_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", ""}, - {GP_BRUSH_ICON_GPBRUSH_THICKNESS, "THICKNESS", ICON_GPBRUSH_THICKNESS, "Thickness", ""}, - {GP_BRUSH_ICON_GPBRUSH_STRENGTH, "STRENGTH", ICON_GPBRUSH_STRENGTH, "Strength", ""}, - {GP_BRUSH_ICON_GPBRUSH_RANDOMIZE, "RANDOMIZE", ICON_GPBRUSH_RANDOMIZE, "Randomize", ""}, - {GP_BRUSH_ICON_GPBRUSH_GRAB, "GRAB", ICON_GPBRUSH_GRAB, "Grab", ""}, - {GP_BRUSH_ICON_GPBRUSH_PUSH, "PUSH", ICON_GPBRUSH_PUSH, "Push", ""}, - {GP_BRUSH_ICON_GPBRUSH_TWIST, "TWIST", ICON_GPBRUSH_TWIST, "Twist", ""}, - {GP_BRUSH_ICON_GPBRUSH_PINCH, "PINCH", ICON_GPBRUSH_PINCH, "Pinch", ""}, - {GP_BRUSH_ICON_GPBRUSH_CLONE, "CLONE", ICON_GPBRUSH_CLONE, "Clone", ""}, - {0, nullptr, 0, nullptr, nullptr}, -}; - -static EnumPropertyItem rna_enum_gpencil_brush_weight_icons_items[] = { - {GP_BRUSH_ICON_GPBRUSH_WEIGHT, "DRAW", ICON_GPBRUSH_WEIGHT, "Draw", ""}, - {GP_BRUSH_ICON_GPBRUSH_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""}, - {GP_BRUSH_ICON_GPBRUSH_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""}, - {GP_BRUSH_ICON_GPBRUSH_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""}, - {0, nullptr, 0, nullptr, nullptr}, -}; -static EnumPropertyItem rna_enum_gpencil_brush_vertex_icons_items[] = { - {GP_BRUSH_ICON_VERTEX_DRAW, "DRAW", ICON_BRUSH_MIX, "Draw", ""}, - {GP_BRUSH_ICON_VERTEX_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""}, - {GP_BRUSH_ICON_VERTEX_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""}, - {GP_BRUSH_ICON_VERTEX_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""}, - {GP_BRUSH_ICON_VERTEX_REPLACE, "REPLACE", ICON_BRUSH_MIX, "Replace", ""}, - {0, nullptr, 0, nullptr, nullptr}, -}; #endif #ifdef RNA_RUNTIME @@ -774,20 +730,20 @@ static void rna_Brush_material_update(bContext * /*C*/, PointerRNA * /*ptr*/) static void rna_Brush_main_tex_update(bContext *C, PointerRNA *ptr) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Brush *br = (Brush *)ptr->data; + Main *bmain = CTX_data_main_from_id(C, &br->id); BKE_paint_invalidate_overlay_tex(scene, view_layer, br->mtex.tex); rna_Brush_update(bmain, scene, ptr); } static void rna_Brush_secondary_tex_update(bContext *C, PointerRNA *ptr) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Brush *br = (Brush *)ptr->data; + Main *bmain = CTX_data_main_from_id(C, &br->id); BKE_paint_invalidate_overlay_tex(scene, view_layer, br->mask_mtex.tex); rna_Brush_update(bmain, scene, ptr); } @@ -1113,33 +1069,6 @@ static void rna_BrushGpencilSettings_use_material_pin_update(bContext *C, Pointe WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, nullptr); } -static void rna_BrushGpencilSettings_eraser_mode_update(Main * /*bmain*/, - Scene *scene, - PointerRNA * /*ptr*/) -{ - ToolSettings *ts = scene->toolsettings; - Paint *paint = &ts->gp_paint->paint; - Brush *brush = BKE_paint_brush(paint); - - /* set eraser icon */ - 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; - break; - case GP_BRUSH_ERASER_HARD: - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; - break; - case GP_BRUSH_ERASER_STROKE: - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; - break; - default: - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; - break; - } - } -} - static bool rna_BrushGpencilSettings_material_poll(PointerRNA * /*ptr*/, PointerRNA value) { Material *ma = (Material *)value.data; @@ -1722,32 +1651,6 @@ static void rna_def_gpencil_options(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, nullptr); - /* brush standard icon */ - prop = RNA_def_property(srna, "gpencil_paint_icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, nullptr, "icon_id"); - RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_paint_icons_items); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Grease Pencil Icon", ""); - - prop = RNA_def_property(srna, "gpencil_sculpt_icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, nullptr, "icon_id"); - RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_sculpt_icons_items); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL); - RNA_def_property_ui_text(prop, "Grease Pencil Icon", ""); - - prop = RNA_def_property(srna, "gpencil_weight_icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, nullptr, "icon_id"); - RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_weight_icons_items); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Grease Pencil Icon", ""); - - prop = RNA_def_property(srna, "gpencil_vertex_icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, nullptr, "icon_id"); - RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_vertex_icons_items); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Grease Pencil Icon", ""); - /* Mode type. */ prop = RNA_def_property(srna, "vertex_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, nullptr, "vertex_mode"); @@ -1944,8 +1847,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mode", "Eraser Mode"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update( - prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_eraser_mode_update"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, nullptr); prop = RNA_def_property(srna, "caps_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, nullptr, "caps_type"); diff --git a/source/blender/makesrna/intern/rna_image.cc b/source/blender/makesrna/intern/rna_image.cc index 2e61263f202..de7cda37541 100644 --- a/source/blender/makesrna/intern/rna_image.cc +++ b/source/blender/makesrna/intern/rna_image.cc @@ -86,18 +86,23 @@ static void rna_Image_source_set(PointerRNA *ptr, int value) { Image *ima = (Image *)ptr->owner_id; - if (value != ima->source) { - ima->source = value; - BLI_assert(BKE_id_is_in_global_main(&ima->id)); - BKE_image_signal(G_MAIN, ima, nullptr, IMA_SIGNAL_SRC_CHANGE); - if (ima->source == IMA_SRC_TILED) { - BKE_image_signal(G_MAIN, ima, nullptr, IMA_SIGNAL_RELOAD); - } - - DEG_id_tag_update(&ima->id, 0); - DEG_id_tag_update(&ima->id, ID_RECALC_EDITORS | ID_RECALC_SOURCE); - DEG_relations_tag_update(G_MAIN); + if (value == ima->source) { + return; } + ima->source = value; + + Main *main = BKE_main_from_id(G_MAIN, &ima->id); + if (main == nullptr) { + return; + } + BKE_image_signal(main, ima, nullptr, IMA_SIGNAL_SRC_CHANGE); + if (ima->source == IMA_SRC_TILED) { + BKE_image_signal(main, ima, nullptr, IMA_SIGNAL_RELOAD); + } + + DEG_id_tag_update(&ima->id, 0); + DEG_id_tag_update(&ima->id, ID_RECALC_EDITORS | ID_RECALC_SOURCE); + DEG_relations_tag_update(main); } static void rna_Image_reload_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_image_api.cc b/source/blender/makesrna/intern/rna_image_api.cc index 2dc5e5bfcdd..538b849bfe5 100644 --- a/source/blender/makesrna/intern/rna_image_api.cc +++ b/source/blender/makesrna/intern/rna_image_api.cc @@ -56,7 +56,7 @@ static void rna_Image_save_render(Image *image, Scene *scene, const int quality) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &image->id); if (scene == nullptr) { scene = CTX_data_scene(C); diff --git a/source/blender/makesrna/intern/rna_light.cc b/source/blender/makesrna/intern/rna_light.cc index 1e5943185a4..1ad80d6d94f 100644 --- a/source/blender/makesrna/intern/rna_light.cc +++ b/source/blender/makesrna/intern/rna_light.cc @@ -78,7 +78,7 @@ static void rna_Light_use_nodes_update(bContext *C, PointerRNA *ptr) ED_node_shader_default(C, &la->id); } - rna_Light_update(CTX_data_main(C), CTX_data_scene(C), ptr); + rna_Light_update(CTX_data_main_from_id(C, &la->id), CTX_data_scene(C), ptr); } #else diff --git a/source/blender/makesrna/intern/rna_linestyle.cc b/source/blender/makesrna/intern/rna_linestyle.cc index 44cabed816f..a963816570a 100644 --- a/source/blender/makesrna/intern/rna_linestyle.cc +++ b/source/blender/makesrna/intern/rna_linestyle.cc @@ -368,13 +368,14 @@ static void rna_LineStyle_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA static void rna_LineStyle_use_nodes_update(bContext *C, PointerRNA *ptr) { + Main *bmain = CTX_data_main_from_id(C, ptr->owner_id); FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->data; if (linestyle->use_nodes && linestyle->nodetree == nullptr) { BKE_linestyle_default_shader(C, linestyle); } - rna_LineStyle_update(CTX_data_main(C), CTX_data_scene(C), ptr); + rna_LineStyle_update(bmain, CTX_data_scene(C), ptr); } static LineStyleModifier *rna_LineStyle_color_modifier_add(FreestyleLineStyle *linestyle, diff --git a/source/blender/makesrna/intern/rna_main_api.cc b/source/blender/makesrna/intern/rna_main_api.cc index 37ea486d456..101d108a42b 100644 --- a/source/blender/makesrna/intern/rna_main_api.cc +++ b/source/blender/makesrna/intern/rna_main_api.cc @@ -127,6 +127,15 @@ static void rna_Main_ID_remove(Main *bmain, id->name + 2); return; } + if (bmain != BKE_main_from_id(bmain, id)) { + BKE_reportf(reports, + RPT_ERROR, + "%s '%s' is part of a different main database and should be removed from there", + BKE_idtype_idcode_to_name(GS(id->name)), + id->name + 2); + return; + } + if (do_unlink) { BKE_id_delete(bmain, id); RNA_POINTER_INVALIDATE(id_ptr); diff --git a/source/blender/makesrna/intern/rna_material.cc b/source/blender/makesrna/intern/rna_material.cc index be8ce3beb05..b47cd97756a 100644 --- a/source/blender/makesrna/intern/rna_material.cc +++ b/source/blender/makesrna/intern/rna_material.cc @@ -153,7 +153,7 @@ static void rna_Material_texpaint_begin(CollectionPropertyIterator *iter, Pointe static void rna_Material_active_paint_texture_index_update(bContext *C, PointerRNA *ptr) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, ptr->owner_id); Material *ma = (Material *)ptr->owner_id; if (ma->use_nodes && ma->nodetree) { @@ -193,8 +193,8 @@ static void rna_Material_active_paint_texture_index_update(bContext *C, PointerR static void rna_Material_use_nodes_update(bContext *C, PointerRNA *ptr) { + Main *bmain = CTX_data_main_from_id(C, ptr->owner_id); Material *ma = (Material *)ptr->data; - Main *bmain = CTX_data_main(C); if (ma->use_nodes && ma->nodetree == nullptr) { ED_node_shader_default(C, &ma->id); diff --git a/source/blender/makesrna/intern/rna_node_socket.cc b/source/blender/makesrna/intern/rna_node_socket.cc index 9f16f8dcf50..70db4838638 100644 --- a/source/blender/makesrna/intern/rna_node_socket.cc +++ b/source/blender/makesrna/intern/rna_node_socket.cc @@ -401,13 +401,14 @@ void rna_NodeSocketStandard_vector_range( static void rna_NodeSocketStandard_value_update(bContext *C, PointerRNA *ptr) { /* default update */ - rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr); + Main *bmain = CTX_data_main_from_id(C, ptr->owner_id); + rna_NodeSocket_update(bmain, CTX_data_scene(C), ptr); } static void rna_NodeSocketStandard_value_and_relation_update(bContext *C, PointerRNA *ptr) { rna_NodeSocketStandard_value_update(C, ptr); - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, ptr->owner_id); DEG_relations_tag_update(bmain); } diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 8b22ca75fc7..4aef748f768 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -1084,7 +1084,7 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree, ntreeTexCheckCyclics(ntree); } - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); ED_node_tree_propagate_change(C, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); @@ -1279,7 +1279,7 @@ static bool rna_NodeTree_contains_tree(bNodeTree *tree, bNodeTree *sub_tree) static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); ntree->tree_interface.tag_items_changed(); ED_node_tree_propagate_change(nullptr, bmain, ntree); } @@ -2181,8 +2181,9 @@ void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr) static void rna_Node_socket_value_update(ID *id, bNode * /*node*/, bContext *C) { + Main *bmain = CTX_data_main_from_id(C, id); BKE_ntree_update_tag_all(reinterpret_cast(id)); - ED_node_tree_propagate_change(C, CTX_data_main(C), reinterpret_cast(id)); + ED_node_tree_propagate_change(C, bmain, reinterpret_cast(id)); } static void rna_Node_select_set(PointerRNA *ptr, bool value) @@ -3298,8 +3299,9 @@ static bool rna_Node_pair_with_output( int &output_node_id = zone_type.get_corresponding_output_id(*node); output_node_id = output_node->identifier; + Main *bmain = CTX_data_main_from_id(C, &ntree->id); BKE_ntree_update_tag_node_property(ntree, node); - ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); + ED_node_tree_propagate_change(C, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return true; } @@ -3540,7 +3542,8 @@ static bNodeSocket *rna_NodeOutputFile_slots_new( sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format); - ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); + Main *bmain = CTX_data_main_from_id(C, &ntree->id); + ED_node_tree_propagate_change(C, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return sock; diff --git a/source/blender/makesrna/intern/rna_object.cc b/source/blender/makesrna/intern/rna_object.cc index c1bda6480a3..91e2c8146e8 100644 --- a/source/blender/makesrna/intern/rna_object.cc +++ b/source/blender/makesrna/intern/rna_object.cc @@ -552,6 +552,14 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, ReportList *r return; } + Main *ob_main = BKE_main_from_id(G_MAIN, &ob->id); + if (id) { + if (ob_main != BKE_main_from_id(G_MAIN, id)) { + BKE_report(reports, RPT_ERROR, "Can't assign object data from different main database"); + return; + } + } + if (ob->type == OB_EMPTY) { if (ob->data) { id_us_min(static_cast(ob->data)); @@ -564,7 +572,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, ReportList *r } } else if (ob->type == OB_MESH) { - BKE_mesh_assign_object(G_MAIN, ob, reinterpret_cast(id)); + BKE_mesh_assign_object(ob_main, ob, reinterpret_cast(id)); } else { if (ob->data) { @@ -576,13 +584,13 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, ReportList *r id_us_plus(id); ob->data = id; - BKE_object_materials_test(G_MAIN, ob, id); + BKE_object_materials_test(ob_main, ob, id); if (GS(id->name) == ID_CU_LEGACY) { BKE_curve_type_test(ob); } else if (ob->type == OB_ARMATURE) { - BKE_pose_rebuild(G_MAIN, ob, static_cast(ob->data), true); + BKE_pose_rebuild(ob_main, ob, static_cast(ob->data), true); } } } @@ -1146,17 +1154,23 @@ static PointerRNA rna_Object_active_material_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Material, ma); } -static void rna_Object_active_material_set(PointerRNA *ptr, - PointerRNA value, - ReportList * /*reports*/) +static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value, ReportList *reports) { Object *ob = reinterpret_cast(ptr->owner_id); + Material *mat = reinterpret_cast(value.data); - DEG_id_tag_update(static_cast(value.data), 0); - BLI_assert(BKE_id_is_in_global_main(&ob->id)); - BLI_assert(BKE_id_is_in_global_main(static_cast(value.data))); - BKE_object_material_assign( - G_MAIN, ob, static_cast(value.data), ob->actcol, BKE_MAT_ASSIGN_EXISTING); + Main *ob_main = BKE_main_from_id(G_MAIN, &ob->id); + if (mat) { + Main *mat_main = BKE_main_from_id(G_MAIN, &mat->id); + if (ob_main != mat_main) { + BKE_report(reports, RPT_ERROR, "Can't assign material from other main database"); + return; + } + } + + DEG_id_tag_update(&mat->id, 0); + + BKE_object_material_assign(ob_main, ob, mat, ob->actcol, BKE_MAT_ASSIGN_EXISTING); if (ob->type == OB_GPENCIL_LEGACY) { /* Notifying material property in top-bar. */ @@ -1380,17 +1394,21 @@ static PointerRNA rna_MaterialSlot_material_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Material, ma); } -static void rna_MaterialSlot_material_set(PointerRNA *ptr, - PointerRNA value, - ReportList * /*reports*/) +static void rna_MaterialSlot_material_set(PointerRNA *ptr, PointerRNA value, ReportList *reports) { Object *ob = reinterpret_cast(ptr->owner_id); - int index = rna_MaterialSlot_index(ptr); + Material *mat = reinterpret_cast(value.data); - BLI_assert(BKE_id_is_in_global_main(&ob->id)); - BLI_assert(BKE_id_is_in_global_main(static_cast(value.data))); - BKE_object_material_assign( - G_MAIN, ob, static_cast(value.data), index + 1, BKE_MAT_ASSIGN_EXISTING); + Main *ob_main = BKE_main_from_id(G_MAIN, &ob->id); + if (mat) { + if (ob_main != BKE_main_from_id(G_MAIN, &mat->id)) { + BKE_report(reports, RPT_ERROR, "Can't assign material from other main database"); + return; + } + } + + int index = rna_MaterialSlot_index(ptr); + BKE_object_material_assign(ob_main, ob, mat, index + 1, BKE_MAT_ASSIGN_EXISTING); } static bool rna_MaterialSlot_material_poll(PointerRNA *ptr, PointerRNA value) @@ -1738,8 +1756,9 @@ bool rna_Object_constraints_override_apply(Main *bmain, static ModifierData *rna_Object_modifier_new( Object *object, bContext *C, ReportList *reports, const char *name, int type) { + Main *bmain = CTX_data_main_from_id(C, &object->id); ModifierData *md = blender::ed::object::modifier_add( - reports, CTX_data_main(C), CTX_data_scene(C), object, name, type); + reports, bmain, CTX_data_scene(C), object, name, type); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_ADDED, object); @@ -1751,9 +1770,9 @@ static void rna_Object_modifier_remove(Object *object, ReportList *reports, PointerRNA *md_ptr) { + Main *bmain = CTX_data_main_from_id(C, &object->id); ModifierData *md = static_cast(md_ptr->data); - if (blender::ed::object::modifier_remove( - reports, CTX_data_main(C), CTX_data_scene(C), object, md) == false) + if (blender::ed::object::modifier_remove(reports, bmain, CTX_data_scene(C), object, md) == false) { /* error is already set */ return; @@ -1766,7 +1785,8 @@ static void rna_Object_modifier_remove(Object *object, static void rna_Object_modifier_clear(Object *object, bContext *C) { - blender::ed::object::modifiers_clear(CTX_data_main(C), CTX_data_scene(C), object); + Main *bmain = CTX_data_main_from_id(C, &object->id); + blender::ed::object::modifiers_clear(bmain, CTX_data_scene(C), object); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); } @@ -1897,8 +1917,9 @@ bool rna_Object_modifiers_override_apply(Main *bmain, static GpencilModifierData *rna_Object_greasepencil_modifier_new( Object *object, bContext *C, ReportList *reports, const char *name, int type) { + Main *bmain = CTX_data_main_from_id(C, &object->id); return blender::ed::object::gpencil_modifier_add( - reports, CTX_data_main(C), CTX_data_scene(C), object, name, type); + reports, bmain, CTX_data_scene(C), object, name, type); } static void rna_Object_greasepencil_modifier_remove(Object *object, @@ -1906,10 +1927,9 @@ static void rna_Object_greasepencil_modifier_remove(Object *object, ReportList *reports, PointerRNA *gmd_ptr) { + Main *bmain = CTX_data_main_from_id(C, &object->id); GpencilModifierData *gmd = static_cast(gmd_ptr->data); - if (blender::ed::object::gpencil_modifier_remove(reports, CTX_data_main(C), object, gmd) == - false) - { + if (blender::ed::object::gpencil_modifier_remove(reports, bmain, object, gmd) == false) { /* error is already set */ return; } @@ -1921,7 +1941,8 @@ static void rna_Object_greasepencil_modifier_remove(Object *object, static void rna_Object_greasepencil_modifier_clear(Object *object, bContext *C) { - blender::ed::object::gpencil_modifier_clear(CTX_data_main(C), object); + Main *bmain = CTX_data_main_from_id(C, &object->id); + blender::ed::object::gpencil_modifier_clear(bmain, object); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); } @@ -1982,8 +2003,8 @@ bool rna_Object_greasepencil_modifiers_override_apply( static ShaderFxData *rna_Object_shaderfx_new( Object *object, bContext *C, ReportList *reports, const char *name, int type) { - return blender::ed::object::shaderfx_add( - reports, CTX_data_main(C), CTX_data_scene(C), object, name, type); + Main *bmain = CTX_data_main_from_id(C, &object->id); + return blender::ed::object::shaderfx_add(reports, bmain, CTX_data_scene(C), object, name, type); } static void rna_Object_shaderfx_remove(Object *object, @@ -1991,8 +2012,9 @@ static void rna_Object_shaderfx_remove(Object *object, ReportList *reports, PointerRNA *gmd_ptr) { + Main *bmain = CTX_data_main_from_id(C, &object->id); ShaderFxData *gmd = static_cast(gmd_ptr->data); - if (blender::ed::object::shaderfx_remove(reports, CTX_data_main(C), object, gmd) == false) { + if (blender::ed::object::shaderfx_remove(reports, bmain, object, gmd) == false) { /* error is already set */ return; } @@ -2004,7 +2026,8 @@ static void rna_Object_shaderfx_remove(Object *object, static void rna_Object_shaderfx_clear(Object *object, bContext *C) { - blender::ed::object::shaderfx_clear(CTX_data_main(C), object); + Main *bmain = CTX_data_main_from_id(C, &object->id); + blender::ed::object::shaderfx_clear(bmain, object); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); } diff --git a/source/blender/makesrna/intern/rna_object_api.cc b/source/blender/makesrna/intern/rna_object_api.cc index 3eea518473e..acac097c66d 100644 --- a/source/blender/makesrna/intern/rna_object_api.cc +++ b/source/blender/makesrna/intern/rna_object_api.cc @@ -463,7 +463,7 @@ static void rna_Object_to_curve_clear(Object *object) static PointerRNA rna_Object_shape_key_add( Object *ob, bContext *C, ReportList *reports, const char *name, bool from_mix) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &ob->id); KeyBlock *kb = nullptr; if ((kb = BKE_object_shapekey_insert(bmain, ob, name, from_mix))) { @@ -815,7 +815,7 @@ bool rna_Object_generate_gpencil_strokes(Object *ob, ob->id.name + 2); return false; } - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &ob->id); Scene *scene = CTX_data_scene(C); BKE_gpencil_convert_curve( diff --git a/source/blender/makesrna/intern/rna_pose.cc b/source/blender/makesrna/intern/rna_pose.cc index 03486682a32..09a47ce25c0 100644 --- a/source/blender/makesrna/intern/rna_pose.cc +++ b/source/blender/makesrna/intern/rna_pose.cc @@ -245,6 +245,11 @@ static float rna_PoseChannel_length_get(PointerRNA *ptr) static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value) { Object *ob = (Object *)ptr->owner_id; + Main *main = BKE_main_from_id(G_MAIN, &ob->id); + if (main == nullptr) { + return; + } + bPoseChannel *pchan = (bPoseChannel *)ptr->data; char oldname[sizeof(pchan->name)], newname[sizeof(pchan->name)]; @@ -252,9 +257,7 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value) STRNCPY_UTF8(newname, value); STRNCPY(oldname, pchan->name); - BLI_assert(BKE_id_is_in_global_main(&ob->id)); - BLI_assert(BKE_id_is_in_global_main(static_cast(ob->data))); - ED_armature_bone_rename(G_MAIN, static_cast(ob->data), oldname, newname); + ED_armature_bone_rename(main, static_cast(ob->data), oldname, newname); } /* See rna_Bone_update_renamed() */ diff --git a/source/blender/makesrna/intern/rna_scene.cc b/source/blender/makesrna/intern/rna_scene.cc index 7ffb11b945a..70f02bb5f15 100644 --- a/source/blender/makesrna/intern/rna_scene.cc +++ b/source/blender/makesrna/intern/rna_scene.cc @@ -1842,8 +1842,11 @@ void rna_ViewLayer_name_set(PointerRNA *ptr, const char *value) { Scene *scene = (Scene *)ptr->owner_id; ViewLayer *view_layer = (ViewLayer *)ptr->data; - BLI_assert(BKE_id_is_in_global_main(&scene->id)); - BKE_view_layer_rename(G_MAIN, scene, view_layer, value); + Main *main = BKE_main_from_id(G_MAIN, &scene->id); + if (main == nullptr) { + return; + } + BKE_view_layer_rename(main, scene, view_layer, value); } static void rna_SceneRenderView_name_set(PointerRNA *ptr, const char *value) @@ -1978,10 +1981,11 @@ static std::optional rna_SceneRenderView_path(const PointerRNA *ptr static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr) { Scene *scene = (Scene *)ptr->data; + Main *bmain = CTX_data_main_from_id(C, &scene->id); if (scene->use_nodes && scene->nodetree == nullptr) { ED_node_composit_default(C, scene); } - DEG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(bmain); } static void rna_Physics_relations_update(Main *bmain, Scene * /*scene*/, PointerRNA * /*ptr*/) @@ -2139,7 +2143,7 @@ static void rna_Scene_simplify_update_impl(Main *bmain, static void rna_Scene_use_simplify_update(bContext *C, PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &scene->id); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); rna_Scene_simplify_update_impl(bmain, scene, false, depsgraph); } @@ -2147,7 +2151,7 @@ static void rna_Scene_use_simplify_update(bContext *C, PointerRNA *ptr) static void rna_Scene_simplify_volume_update(bContext *C, PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main_from_id(C, &scene->id); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); if (scene->r.mode & R_SIMPLIFY) { rna_Scene_simplify_update_impl(bmain, scene, false, depsgraph); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.cc b/source/blender/makesrna/intern/rna_sculpt_paint.cc index f9bba65e0c0..29126ffa99c 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.cc +++ b/source/blender/makesrna/intern/rna_sculpt_paint.cc @@ -271,103 +271,30 @@ static std::optional rna_ParticleEdit_path(const PointerRNA * /*ptr return "tool_settings.particle_edit"; } -static bool rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value) +static PointerRNA rna_Paint_brush_get(PointerRNA *ptr) +{ + Paint *paint = static_cast(ptr->data); + Brush *brush = BKE_paint_brush(paint); + if (!brush) { + return PointerRNA_NULL; + } + return RNA_id_pointer_create(&brush->id); +} + +static void rna_Paint_brush_set(PointerRNA *ptr, PointerRNA value, ReportList * /*reports*/) +{ + Paint *paint = static_cast(ptr->data); + Brush *brush = static_cast(value.data); + BKE_paint_brush_set(paint, brush); + BKE_paint_invalidate_overlay_all(); +} + +static bool rna_Paint_brush_poll(PointerRNA *ptr, PointerRNA value) { const Paint *paint = static_cast(ptr->data); - Brush *brush = (Brush *)value.owner_id; - const uint tool_offset = paint->runtime.tool_offset; - const eObjectMode ob_mode = eObjectMode(paint->runtime.ob_mode); - UNUSED_VARS_NDEBUG(tool_offset); - BLI_assert(tool_offset && ob_mode); + const Brush *brush = static_cast(value.data); - if (brush->ob_mode & ob_mode) { - if (paint->brush) { - if (BKE_brush_tool_get(paint->brush, paint) == BKE_brush_tool_get(brush, paint)) { - 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->owner_id; - const PaintToolSlot *tslot = static_cast(ptr->data); - ToolSettings *ts = scene->toolsettings; - Brush *brush = (Brush *)value.owner_id; - 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->weightpaint_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_PAINT_GPENCIL_LEGACY; - } - else if (paint_contains_brush_slot(&ts->gp_vertexpaint->paint, tslot, &slot_index)) { - if (slot_index != brush->gpencil_vertex_tool) { - return false; - } - mode = OB_MODE_VERTEX_GPENCIL_LEGACY; - } - else if (paint_contains_brush_slot(&ts->gp_sculptpaint->paint, tslot, &slot_index)) { - if (slot_index != brush->gpencil_sculpt_tool) { - return false; - } - mode = OB_MODE_SCULPT_GPENCIL_LEGACY; - } - else if (paint_contains_brush_slot(&ts->gp_weightpaint->paint, tslot, &slot_index)) { - if (slot_index != brush->gpencil_weight_tool) { - return false; - } - mode = OB_MODE_WEIGHT_GPENCIL_LEGACY; - } - else if (paint_contains_brush_slot(&ts->curves_sculpt->paint, tslot, &slot_index)) { - if (slot_index != brush->curves_sculpt_tool) { - return false; - } - mode = OB_MODE_SCULPT_CURVES; - } - - return brush->ob_mode & mode; + return (brush == nullptr) || (paint->runtime.ob_mode & brush->ob_mode) != 0; } static void rna_Sculpt_update(bContext *C, PointerRNA * /*ptr*/) @@ -443,16 +370,6 @@ static std::optional rna_ParticleBrush_path(const PointerRNA * /*pt return "tool_settings.particle_edit.brush"; } -static void rna_Paint_brush_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) -{ - Paint *paint = static_cast(ptr->data); - Brush *br = paint->brush; - BKE_paint_invalidate_overlay_all(); - /* Needed because we're not calling 'BKE_paint_brush_set' which handles this. */ - BKE_paint_toolslots_brush_update(paint); - WM_main_add_notifier(NC_BRUSH | NA_SELECTED, br); -} - static void rna_ImaPaint_viewport_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA * /*ptr*/) { /* not the best solution maybe, but will refresh the 3D viewport */ @@ -600,20 +517,6 @@ 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", nullptr); - 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, nullptr, nullptr, nullptr, "rna_Brush_mode_with_tool_poll"); - RNA_def_property_ui_text(prop, "Brush", ""); -} - static void rna_def_paint(BlenderRNA *brna) { StructRNA *srna; @@ -625,25 +528,18 @@ static void rna_def_paint(BlenderRNA *brna) /* Global Settings */ prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_pointer_funcs(prop, nullptr, nullptr, nullptr, "rna_Brush_mode_poll"); + RNA_def_property_struct_type(prop, "Brush"); + RNA_def_property_pointer_funcs( + prop, "rna_Paint_brush_get", "rna_Paint_brush_set", nullptr, "rna_Paint_brush_poll"); RNA_def_property_ui_text(prop, "Brush", "Active Brush"); - RNA_def_property_update(prop, 0, "rna_Paint_brush_update"); + RNA_def_property_update(prop, NC_BRUSH | NA_SELECTED, nullptr); - /* paint_tool_slots */ - prop = RNA_def_property(srna, "tool_slots", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, nullptr, "tool_slots", "tool_slots_len"); - RNA_def_property_struct_type(prop, "PaintToolSlot"); - /* don't dereference pointer! */ - RNA_def_property_collection_funcs(prop, - nullptr, - nullptr, - nullptr, - "rna_iterator_array_get", - nullptr, - nullptr, - nullptr, - nullptr); - RNA_def_property_ui_text(prop, "Paint Tool Slots", ""); + prop = RNA_def_property(srna, "brush_asset_reference", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Brush Asset Reference", + "A weak reference to the matching brush asset, used e.g. to restore " + "the last used brush on file load"); prop = RNA_def_property(srna, "palette", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_EDITABLE); @@ -1706,7 +1602,6 @@ 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); diff --git a/source/blender/makesrna/intern/rna_space.cc b/source/blender/makesrna/intern/rna_space.cc index 66d36991bc1..3ffd7b074e2 100644 --- a/source/blender/makesrna/intern/rna_space.cc +++ b/source/blender/makesrna/intern/rna_space.cc @@ -1720,9 +1720,13 @@ static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, PointerRNA value, ReportList * /*reports*/) { - BLI_assert(BKE_id_is_in_global_main(static_cast(value.data))); SpaceImage *sima = static_cast(ptr->data); - ED_space_image_set(G_MAIN, sima, (Image *)value.data, false); + Image *image = reinterpret_cast(value.data); + Main *main = BKE_main_from_id(G_MAIN, &image->id); + if (main == nullptr) { + return; + } + ED_space_image_set(main, sima, image, false); } static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, diff --git a/source/blender/makesrna/intern/rna_texture.cc b/source/blender/makesrna/intern/rna_texture.cc index 208f87e7c31..6e6f18e574f 100644 --- a/source/blender/makesrna/intern/rna_texture.cc +++ b/source/blender/makesrna/intern/rna_texture.cc @@ -242,7 +242,8 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value) void rna_TextureSlotTexture_update(bContext *C, PointerRNA *ptr) { - DEG_relations_tag_update(CTX_data_main(C)); + Main *bmain = CTX_data_main_from_id(C, ptr->owner_id); + DEG_relations_tag_update(bmain); rna_TextureSlot_update(C, ptr); } @@ -440,6 +441,7 @@ static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, bool value) static void rna_Texture_use_nodes_update(bContext *C, PointerRNA *ptr) { Tex *tex = (Tex *)ptr->data; + Main *bmain = CTX_data_main_from_id(C, &tex->id); if (tex->use_nodes) { tex->type = 0; @@ -449,7 +451,7 @@ static void rna_Texture_use_nodes_update(bContext *C, PointerRNA *ptr) } } - rna_Texture_nodes_update(CTX_data_main(C), CTX_data_scene(C), ptr); + rna_Texture_nodes_update(bmain, CTX_data_scene(C), ptr); } static void rna_ImageTexture_mipmap_set(PointerRNA *ptr, bool value) diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index 86fffd5c54d..b0f260e0834 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -963,6 +963,20 @@ static int rna_ui_get_enum_icon(bContext *C, return icon; } +void rna_uiTemplateAssetShelfPopover(uiLayout *layout, + bContext *C, + const char *asset_shelf_id, + const char *name, + BIFIconID icon, + int icon_value) +{ + if (icon_value && !icon) { + icon = icon_value; + } + + blender::ui::template_asset_shelf_popover(*layout, *C, asset_shelf_id, name, icon); +} + #else static void api_ui_item_common_heading(FunctionRNA *func) @@ -2287,6 +2301,25 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "node", "Node", "Node", "Display inputs of this node"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + + func = RNA_def_function(srna, "template_asset_shelf_popover", "rna_uiTemplateAssetShelfPopover"); + RNA_def_function_ui_description(func, "Create a button to open an asset shelf in a popover"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm = RNA_def_string(func, + "asset_shelf", + nullptr, + 0, + "", + "Identifier of the asset shelf to display (`bl_idname`)"); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); + parm = RNA_def_string( + func, "name", nullptr, 0, "", "Optional name to indicate the active asset"); + RNA_def_property_clear_flag(parm, PROP_NEVER_NULL); + parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(parm, rna_enum_icon_items); + RNA_def_property_ui_text(parm, "Icon", "Override automatic icon of the item"); + parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item"); } #endif diff --git a/source/blender/makesrna/intern/rna_world.cc b/source/blender/makesrna/intern/rna_world.cc index 962f7d25c6e..22579377b76 100644 --- a/source/blender/makesrna/intern/rna_world.cc +++ b/source/blender/makesrna/intern/rna_world.cc @@ -76,16 +76,15 @@ static void rna_World_draw_update(Main * /*bmain*/, Scene * /*scene*/, PointerRN static void rna_World_use_nodes_update(bContext *C, PointerRNA *ptr) { World *wrld = (World *)ptr->data; - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main_from_id(C, &wrld->id); if (wrld->use_nodes && wrld->nodetree == nullptr) { ED_node_shader_default(C, &wrld->id); } DEG_relations_tag_update(bmain); - rna_World_update(bmain, scene, ptr); - rna_World_draw_update(bmain, scene, ptr); + rna_World_update(bmain, nullptr, ptr); + rna_World_draw_update(bmain, nullptr, ptr); } void rna_World_lightgroup_get(PointerRNA *ptr, char *value) diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index d8e2356c147..ecd28b33974 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -46,7 +46,7 @@ static void composite_get_from_context( *r_ntree = scene->nodetree; } -static void foreach_nodeclass(Scene * /*scene*/, void *calldata, bNodeClassCallback func) +static void foreach_nodeclass(void *calldata, bNodeClassCallback func) { func(calldata, NODE_CLASS_INPUT, N_("Input")); func(calldata, NODE_CLASS_OUTPUT, N_("Output")); diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 7343d2afa0f..f84ceb5e78a 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -71,7 +71,7 @@ static void geometry_node_tree_update(bNodeTree *ntree) ntree_update_reroute_nodes(ntree); } -static void foreach_nodeclass(Scene * /*scene*/, void *calldata, bNodeClassCallback func) +static void foreach_nodeclass(void *calldata, bNodeClassCallback func) { func(calldata, NODE_CLASS_INPUT, N_("Input")); func(calldata, NODE_CLASS_GEOMETRY, N_("Geometry")); diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 1ea1551ee43..7b7c6b85fe5 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -106,7 +106,7 @@ static void shader_get_from_context( } } -static void foreach_nodeclass(Scene * /*scene*/, void *calldata, bNodeClassCallback func) +static void foreach_nodeclass(void *calldata, bNodeClassCallback func) { func(calldata, NODE_CLASS_INPUT, N_("Input")); func(calldata, NODE_CLASS_OUTPUT, N_("Output")); diff --git a/source/blender/nodes/texture/node_texture_tree.cc b/source/blender/nodes/texture/node_texture_tree.cc index b05d5f2d4d5..4c9754e0150 100644 --- a/source/blender/nodes/texture/node_texture_tree.cc +++ b/source/blender/nodes/texture/node_texture_tree.cc @@ -77,7 +77,7 @@ static void texture_get_from_context( } } -static void foreach_nodeclass(Scene * /*scene*/, void *calldata, bNodeClassCallback func) +static void foreach_nodeclass(void *calldata, bNodeClassCallback func) { func(calldata, NODE_CLASS_INPUT, N_("Input")); func(calldata, NODE_CLASS_OUTPUT, N_("Output")); diff --git a/source/blender/python/bmesh/bmesh_py_types.cc b/source/blender/python/bmesh/bmesh_py_types.cc index a10de6d54ed..b3af6402f90 100644 --- a/source/blender/python/bmesh/bmesh_py_types.cc +++ b/source/blender/python/bmesh/bmesh_py_types.cc @@ -20,6 +20,7 @@ #include "BKE_customdata.hh" #include "BKE_global.hh" #include "BKE_lib_id.hh" +#include "BKE_main.hh" #include "BKE_mesh.hh" #include "BKE_mesh_runtime.hh" #include "BKE_object.hh" @@ -1226,8 +1227,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args) * anything in this case. */ } else { - BLI_assert(BKE_id_is_in_global_main(&mesh->id)); - bmain = G_MAIN; /* XXX UGLY! */ + bmain = BKE_main_from_id(G_MAIN, &mesh->id); /* XXX UGLY! */ params.calc_object_remap = true; } diff --git a/source/blender/python/gpu/gpu_py_offscreen.cc b/source/blender/python/gpu/gpu_py_offscreen.cc index 21129531910..10e149736ba 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.cc +++ b/source/blender/python/gpu/gpu_py_offscreen.cc @@ -18,7 +18,7 @@ #include "BLI_utildefines.h" #include "BKE_global.hh" -#include "BKE_lib_id.hh" /* For #BKE_id_is_in_global_main. */ +#include "BKE_main.hh" #include "BKE_scene.hh" #include "DNA_view3d_types.h" @@ -456,9 +456,8 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar return nullptr; } - BLI_assert(BKE_id_is_in_global_main(&scene->id)); - - depsgraph = BKE_scene_ensure_depsgraph(G_MAIN, scene, view_layer); + Main *main = BKE_main_from_id(G_MAIN, &scene->id); + depsgraph = BKE_scene_ensure_depsgraph(main, scene, view_layer); /* Disable 'bgl' state since it interfere with off-screen drawing, see: #84402. */ const bool is_bgl = GPU_bgl_get(); diff --git a/source/blender/python/intern/bpy_rna_anim.cc b/source/blender/python/intern/bpy_rna_anim.cc index 3eb877d73d6..31112b056c9 100644 --- a/source/blender/python/intern/bpy_rna_anim.cc +++ b/source/blender/python/intern/bpy_rna_anim.cc @@ -31,6 +31,7 @@ #include "BKE_global.hh" #include "BKE_idtype.hh" #include "BKE_lib_id.hh" +#include "BKE_main.hh" #include "BKE_report.hh" #include "RNA_access.hh" @@ -403,9 +404,9 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb } else { ID *id = self->ptr.owner_id; + Main *main = BKE_main_from_id(G_MAIN, id); - BLI_assert(BKE_id_is_in_global_main(id)); - CombinedKeyingResult combined_result = insert_keyframe(G_MAIN, + CombinedKeyingResult combined_result = insert_keyframe(main, *id, group_name, path_full, diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 17804679f86..b41ff540220 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -3632,7 +3632,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent * } if (blendfile_path[0] != '\0') { - if (CTX_data_main(C)->has_forward_compatibility_issues) { + if (BKE_main_needs_overwrite_confirm(CTX_data_main(C))) { wm_save_file_overwrite_dialog(C, op); ret = OPERATOR_INTERFACE; } @@ -3994,31 +3994,43 @@ static void file_overwrite_detailed_info_show(uiLayout *parent_layout, Main *bma * block. */ uiLayoutSetScaleY(layout, 0.70f); - char writer_ver_str[16]; - char current_ver_str[16]; - if (bmain->versionfile == BLENDER_VERSION) { - BKE_blender_version_blendfile_string_from_values( - writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile); - BKE_blender_version_blendfile_string_from_values( - current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION); - } - else { - BKE_blender_version_blendfile_string_from_values( - writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1); - BKE_blender_version_blendfile_string_from_values( - current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1); + if (bmain->has_forward_compatibility_issues) { + char writer_ver_str[16]; + char current_ver_str[16]; + if (bmain->versionfile == BLENDER_VERSION) { + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile); + BKE_blender_version_blendfile_string_from_values( + current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION); + } + else { + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1); + BKE_blender_version_blendfile_string_from_values( + current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1); + } + + char message_line1[256]; + char message_line2[256]; + SNPRINTF(message_line1, + RPT_("This file was saved by a newer version of Blender (%s)"), + writer_ver_str); + SNPRINTF(message_line2, + RPT_("Saving it with this Blender (%s) may cause loss of data"), + current_ver_str); + uiItemL(layout, message_line1, ICON_NONE); + uiItemL(layout, message_line2, ICON_NONE); } - char message_line1[256]; - char message_line2[256]; - SNPRINTF(message_line1, - RPT_("This file was saved by a newer version of Blender (%s)"), - writer_ver_str); - SNPRINTF(message_line2, - RPT_("Saving it with this Blender (%s) may cause loss of data"), - current_ver_str); - uiItemL(layout, message_line1, ICON_NONE); - uiItemL(layout, message_line2, ICON_NONE); + if (bmain->is_asset_repository) { + if (bmain->has_forward_compatibility_issues) { + uiItemS_ex(layout, 1.4f); + } + + uiItemL(layout, RPT_("This file is managed by the Blender asset system."), ICON_NONE); + uiItemL(layout, RPT_("and is expected to contain a single asset data-block."), ICON_NONE); + uiItemL(layout, RPT_("Take care to avoid data loss when editing assets."), ICON_NONE); + } } static void save_file_overwrite_cancel(bContext *C, void *arg_block, void * /*arg_data*/) @@ -4083,7 +4095,12 @@ static void save_file_overwrite_saveas(bContext *C, void *arg_block, void * /*ar wmWindow *win = CTX_wm_window(C); UI_popup_block_close(C, win, static_cast(arg_block)); - WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); + PointerRNA props_ptr; + wmOperatorType *ot = WM_operatortype_find("WM_OT_save_as_mainfile", false); + WM_operator_properties_create_ptr(&props_ptr, ot); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr); + WM_operator_properties_free(&props_ptr); } static void save_file_overwrite_saveas_button(uiBlock *block, wmGenericCallback *post_action) @@ -4119,8 +4136,27 @@ static uiBlock *block_create_save_file_overwrite_dialog(bContext *C, ARegion *re uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_WARNING); /* Title. */ - uiItemL_ex( - layout, RPT_("Overwrite file with an older Blender version?"), ICON_NONE, true, false); + if (bmain->has_forward_compatibility_issues) { + if (bmain->is_asset_repository) { + uiItemL_ex( + layout, + RPT_("Convert asset blend file to regular blend file with an older Blender version?"), + ICON_NONE, + true, + false); + } + else { + uiItemL_ex( + layout, RPT_("Overwrite file with an older Blender version?"), ICON_NONE, true, false); + } + } + else if (bmain->is_asset_repository) { + uiItemL_ex( + layout, RPT_("Convert asset blend file to regular blend file?"), ICON_NONE, true, false); + } + else { + BLI_assert_unreachable(); + } /* Filename. */ const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C)); @@ -4332,7 +4368,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION); - const bool needs_overwrite_confirm = bmain->has_forward_compatibility_issues; + const bool needs_overwrite_confirm = BKE_main_needs_overwrite_confirm(bmain); /* Title. */ uiItemL_ex(layout, RPT_("Save changes before closing?"), ICON_NONE, true, false); diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.cc b/source/blender/windowmanager/intern/wm_keymap_utils.cc index cb445e698e8..06311ac4108 100644 --- a/source/blender/windowmanager/intern/wm_keymap_utils.cc +++ b/source/blender/windowmanager/intern/wm_keymap_utils.cc @@ -210,7 +210,6 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C) wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) { /* Op types purposely skipped for now: - * BRUSH_OT * BOID_OT * BUTTONS_OT * CONSTRAINT_OT @@ -336,7 +335,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) km = WM_keymap_find_all( wm, "Paint Face Mask (Weight, Vertex, Texture)", SPACE_EMPTY, RGN_TYPE_WINDOW); } - else if (STRPREFIX(opname, "PAINT_OT")) { + else if (STRPREFIX(opname, "PAINT_OT") || STRPREFIX(opname, "BRUSH_OT")) { /* Check for relevant mode. */ switch (CTX_data_mode_enum(C)) { case CTX_MODE_PAINT_WEIGHT: diff --git a/source/blender/windowmanager/intern/wm_toolsystem.cc b/source/blender/windowmanager/intern/wm_toolsystem.cc index e0b192d46a8..e1fa044fb1f 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.cc +++ b/source/blender/windowmanager/intern/wm_toolsystem.cc @@ -174,43 +174,6 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre } } } - else { - const PaintMode paint_mode = BKE_paintmode_get_from_tool(tref); - BLI_assert(paint_mode != PaintMode::Invalid); - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - BLI_assert(items != nullptr); - - const int i = items ? RNA_enum_from_identifier(items, tref_rt->data_block) : -1; - if (i != -1) { - const int slot_index = items[i].value; - wmWindowManager *wm = static_cast(bmain->wm.first); - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - if (workspace == WM_window_get_active_workspace(win)) { - Scene *scene = WM_window_get_active_scene(win); - BKE_paint_ensure_from_paintmode(bmain, scene, paint_mode); - Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - Brush *brush = BKE_paint_toolslots_brush_get(paint, slot_index); - if (brush == nullptr) { - /* Could make into a function. */ - brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, items[i].name); - if (brush && slot_index == BKE_brush_tool_get(brush, paint)) { - /* Pass. */ - } - else { - brush = BKE_brush_add(bmain, items[i].name, eObjectMode(paint->runtime.ob_mode)); - - BKE_brush_tool_set(brush, paint, slot_index); - - if (paint_mode == PaintMode::Sculpt) { - BKE_brush_sculpt_reset(brush); - } - } - } - BKE_paint_brush_set(paint, brush); - } - } - } - } } } @@ -383,25 +346,6 @@ void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToo } } } - else { - const PaintMode paint_mode = BKE_paintmode_get_from_tool(tref); - Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - if (paint && paint->brush && items) { - const ID *brush = (ID *)paint->brush; - const char tool_type = BKE_brush_tool_get((Brush *)brush, paint); - const int i = RNA_enum_from_value(items, tool_type); - /* Possible when loading files from the future. */ - if (i != -1) { - const char *name = items[i].name; - const char *identifier = items[i].identifier; - if (!STREQ(tref_rt->data_block, identifier)) { - STRNCPY(tref_rt->data_block, identifier); - SNPRINTF(tref->idname, "builtin_brush.%s", name); - } - } - } - } } } @@ -711,26 +655,19 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) switch (tkey->space_type) { case SPACE_VIEW3D: switch (tkey->mode) { - /* Use the names of the enums for each brush tool. */ case CTX_MODE_SCULPT: case CTX_MODE_PAINT_VERTEX: case CTX_MODE_PAINT_WEIGHT: case CTX_MODE_PAINT_TEXTURE: case CTX_MODE_PAINT_GPENCIL_LEGACY: case CTX_MODE_PAINT_GREASE_PENCIL: - return "builtin_brush.Draw"; case CTX_MODE_SCULPT_GPENCIL_LEGACY: case CTX_MODE_SCULPT_GREASE_PENCIL: - return "builtin_brush.Push"; case CTX_MODE_WEIGHT_GPENCIL_LEGACY: case CTX_MODE_WEIGHT_GREASE_PENCIL: - return "builtin_brush.Weight"; case CTX_MODE_VERTEX_GPENCIL_LEGACY: - return "builtin_brush.Draw"; case CTX_MODE_SCULPT_CURVES: - return "builtin_brush.Density"; - /* End temporary hack. */ - + return "builtin.brush"; case CTX_MODE_PARTICLE: return "builtin_brush.Comb"; case CTX_MODE_EDIT_TEXT: @@ -740,7 +677,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) case SPACE_IMAGE: switch (tkey->mode) { case SI_MODE_PAINT: - return "builtin_brush.Draw"; + return "builtin.brush"; } break; case SPACE_NODE: { diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index a660aaccf81..58ec9d6108e 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1709,6 +1709,12 @@ install( set(ASSET_BUNDLE_DIR ${CMAKE_SOURCE_DIR}/release/datafiles/assets/publish/) +# TODO temporary change for development only. Remove before merging. +set(ASSET_BUNDLE_TESTING_DIR "${ASSET_BUNDLE_DIR}/../testing/") +if(EXISTS "${ASSET_BUNDLE_TESTING_DIR}") + set(ASSET_BUNDLE_DIR "${ASSET_BUNDLE_TESTING_DIR}") +endif() + if(EXISTS "${ASSET_BUNDLE_DIR}") install( DIRECTORY ${ASSET_BUNDLE_DIR}