diff --git a/scripts/startup/bl_operators/presets.py b/scripts/startup/bl_operators/presets.py index 1f588367dc7..d8a493a22ad 100644 --- a/scripts/startup/bl_operators/presets.py +++ b/scripts/startup/bl_operators/presets.py @@ -6,10 +6,12 @@ import bpy from bpy.types import ( Menu, Operator, + OperatorFileListElement, WindowManager, ) from bpy.props import ( BoolProperty, + CollectionProperty, StringProperty, ) from bpy.app.translations import ( @@ -622,7 +624,7 @@ class AddPresetOperator(AddPresetBase, Operator): ret = [] for prop_id, prop in operator_rna.properties.items(): - if not (prop.is_hidden or prop.is_skip_save): + if not prop.is_skip_preset: if prop_id not in properties_blacklist: ret.append("op.%s" % prop_id) @@ -655,6 +657,74 @@ class WM_MT_operator_presets(Menu): preset_operator = "script.execute_preset" +class WM_OT_operator_presets_cleanup(Operator): + bl_idname = "wm.operator_presets_cleanup" + bl_label = "Clean Up Operator Presets" + bl_description = "Remove outdated operator properties from presets that may cause problems" + + operator: StringProperty(name="operator") + properties: CollectionProperty(name="properties", type=OperatorFileListElement) + + def cleanup_preset(self, filepath, properties): + from pathlib import Path + file = Path(filepath) + if not (file.is_file() and filepath.suffix == ".py"): + return + lines = file.read_text().splitlines(True) + if len(lines) == 0: + return + new_lines = [] + for line in lines: + if not any(line.startswith(("op.%s" % prop)) for prop in properties): + new_lines.append(line) + file.write_text("".join(new_lines)) + + def cleanup_operators_presets(self, operators, properties): + base_preset_directory = bpy.utils.user_resource( + 'SCRIPTS', path="presets", create=False) + for operator in operators: + from pathlib import Path + operator_path = AddPresetOperator.operator_path(operator) + directory = Path(base_preset_directory, operator_path) + + if not directory.is_dir(): + continue + + for filepath in directory.iterdir(): + self.cleanup_preset(filepath, properties) + + def execute(self, context): + properties = [] + operators = [] + if self.operator: + operators.append(self.operator) + for prop in self.properties: + properties.append(prop.name) + else: + # Cleanup by default I/O Operators Presets + operators = ['WM_OT_alembic_export', + 'WM_OT_alembic_import', + 'WM_OT_collada_export', + 'WM_OT_collada_import', + 'WM_OT_gpencil_export_svg', + 'WM_OT_gpencil_export_pdf', + 'WM_OT_gpencil_export_svg', + 'WM_OT_gpencil_import_svg', + 'WM_OT_obj_export', + 'WM_OT_obj_import', + 'WM_OT_ply_export', + 'WM_OT_ply_import', + 'WM_OT_stl_export', + 'WM_OT_stl_import', + 'WM_OT_usd_export', + 'WM_OT_usd_import', + ] + properties = ["filepath", "directory", "files", "filename"] + + self.cleanup_operators_presets(operators, properties) + return {'FINISHED'} + + class AddPresetGpencilBrush(AddPresetBase, Operator): """Add or remove grease pencil brush preset""" bl_idname = "scene.gpencil_brush_preset_add" @@ -748,4 +818,5 @@ classes = ( AddPresetEEVEERaytracing, ExecutePreset, WM_MT_operator_presets, + WM_OT_operator_presets_cleanup, ) diff --git a/scripts/startup/bl_operators/userpref.py b/scripts/startup/bl_operators/userpref.py index 60f096a99cb..059fae0b440 100644 --- a/scripts/startup/bl_operators/userpref.py +++ b/scripts/startup/bl_operators/userpref.py @@ -148,6 +148,8 @@ class PREFERENCES_OT_copy_prev(Operator): # Reload preferences and `recent-files.txt`. bpy.ops.wm.read_userpref() bpy.ops.wm.read_history() + # Fix operator presets that have unwanted filepath properties + bpy.ops.wm.operator_presets_cleanup() # don't loose users work if they open the splash later. if bpy.data.is_saved is bpy.data.is_dirty is False: diff --git a/scripts/startup/bl_ui/space_topbar.py b/scripts/startup/bl_ui/space_topbar.py index 54a07d36faf..d7ea640d3a8 100644 --- a/scripts/startup/bl_ui/space_topbar.py +++ b/scripts/startup/bl_ui/space_topbar.py @@ -454,6 +454,7 @@ class TOPBAR_MT_blender_system(Menu): layout.separator() layout.operator("screen.spacedata_cleanup") + layout.operator("wm.operator_presets_cleanup") class TOPBAR_MT_templates_more(Menu): diff --git a/source/blender/makesrna/RNA_types.hh b/source/blender/makesrna/RNA_types.hh index 8108b9d791e..a42b6c8169d 100644 --- a/source/blender/makesrna/RNA_types.hh +++ b/source/blender/makesrna/RNA_types.hh @@ -179,7 +179,7 @@ enum PropertySubType { /* Make sure enums are updated with these */ /* HIGHEST FLAG IN USE: 1 << 31 - * FREE FLAGS: 11, 13, 14, 15. */ + * FREE FLAGS: 13, 14, 15. */ enum PropertyFlag { /** * Editable means the property is editable in the user @@ -212,9 +212,9 @@ enum PropertyFlag { PROP_ICONS_CONSECUTIVE = (1 << 12), PROP_ICONS_REVERSE = (1 << 8), - /** Hidden in the user interface. */ + /** Hidden in the user interface. Inherits #ROP_SKIP_PRESET. */ PROP_HIDDEN = (1 << 19), - /** Do not write in presets. */ + /** Do not use ghost values. Inherits #PROP_SKIP_PRESET. */ PROP_SKIP_SAVE = (1 << 28), /* numbers */ @@ -311,6 +311,9 @@ enum PropertyFlag { * as having the +/- operators available in the file browser. */ PROP_PATH_OUTPUT = (1 << 2), + + /** Do not write in presets. */ + PROP_SKIP_PRESET = (1 << 11), }; ENUM_OPERATORS(PropertyFlag, PROP_TEXTEDIT_UPDATE) diff --git a/source/blender/makesrna/intern/rna_rna.cc b/source/blender/makesrna/intern/rna_rna.cc index 1a26eb905d3..21b559c06be 100644 --- a/source/blender/makesrna/intern/rna_rna.cc +++ b/source/blender/makesrna/intern/rna_rna.cc @@ -154,8 +154,13 @@ const EnumPropertyItem rna_enum_property_unit_items[] = { }; const EnumPropertyItem rna_enum_property_flag_items[] = { - {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, - {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""}, + {PROP_HIDDEN, "HIDDEN", 0, "Hidden", "Hidden in the user interface. Inherits 'SKIP_PRESET'"}, + {PROP_SKIP_SAVE, + "SKIP_SAVE", + 0, + "Skip Save", + "Do not use ghost values. Inherits 'SKIP_PRESET'"}, + {PROP_SKIP_PRESET, "SKIP_PRESET", 0, "Skip Preset", "Do not write in presets"}, {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""}, {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""}, {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to each other", ""}, @@ -728,6 +733,12 @@ static bool rna_Property_is_skip_save_get(PointerRNA *ptr) return (prop->flag & PROP_SKIP_SAVE) != 0; } +static bool rna_Property_is_skip_preset_get(PointerRNA *ptr) +{ + PropertyRNA *prop = (PropertyRNA *)ptr->data; + return (prop->flag & (PROP_SKIP_SAVE | PROP_HIDDEN | PROP_SKIP_PRESET)) != 0; +} + static bool rna_Property_is_enum_flag_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; @@ -3136,7 +3147,12 @@ static void rna_def_property(BlenderRNA *brna) prop = RNA_def_property(srna, "is_skip_save", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Property_is_skip_save_get", nullptr); - RNA_def_property_ui_text(prop, "Skip Save", "True when the property is not saved in presets"); + RNA_def_property_ui_text(prop, "Skip Save", "True when the property uses ghost values"); + + prop = RNA_def_property(srna, "is_skip_preset", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_Property_is_skip_preset_get", nullptr); + RNA_def_property_ui_text(prop, "Skip Preset", "True when the property is not saved in presets"); prop = RNA_def_property(srna, "is_output", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/windowmanager/WM_api.hh b/source/blender/windowmanager/WM_api.hh index cd55cc0b61c..f98ed202331 100644 --- a/source/blender/windowmanager/WM_api.hh +++ b/source/blender/windowmanager/WM_api.hh @@ -901,6 +901,7 @@ enum eFileSel_Flag { WM_FILESEL_FILES = 1 << 4, /** Show the properties sidebar by default. */ WM_FILESEL_SHOW_PROPS = 1 << 5, + WM_FILESEL_SKIP_PATHS_PRESETS = 1 << 5, }; ENUM_OPERATORS(eFileSel_Flag, WM_FILESEL_SHOW_PROPS) diff --git a/source/blender/windowmanager/intern/wm_operator_props.cc b/source/blender/windowmanager/intern/wm_operator_props.cc index f7096c7f697..fad16982f65 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.cc +++ b/source/blender/windowmanager/intern/wm_operator_props.cc @@ -93,23 +93,27 @@ void WM_operator_properties_filesel(wmOperatorType *ot, }; if (flag & WM_FILESEL_FILEPATH) { - RNA_def_string_file_path(ot->srna, "filepath", nullptr, FILE_MAX, "File Path", "Path to file"); + prop = RNA_def_string_file_path( + ot->srna, "filepath", nullptr, FILE_MAX, "File Path", "Path to file"); + RNA_def_property_flag(prop, PROP_SKIP_PRESET); } if (flag & WM_FILESEL_DIRECTORY) { - RNA_def_string_dir_path( + prop = RNA_def_string_dir_path( ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Directory of the file"); + RNA_def_property_flag(prop, PROP_SKIP_PRESET); } if (flag & WM_FILESEL_FILENAME) { - RNA_def_string_file_name( + prop = RNA_def_string_file_name( ot->srna, "filename", nullptr, FILE_MAX, "File Name", "Name of the file"); + RNA_def_property_flag(prop, PROP_SKIP_PRESET); } if (flag & WM_FILESEL_FILES) { prop = RNA_def_collection_runtime( ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE | PROP_SKIP_PRESET); } if ((flag & WM_FILESEL_SHOW_PROPS) == 0) {