diff options
26 files changed, 402 insertions, 2 deletions
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 97fc45189f2..23874abd8c9 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -352,6 +352,11 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non # 2) try register collected modules # removed, addons need to handle own registration now. + + from _bpy import _bl_owner_id_get, _bl_owner_id_set + owner_id_prev = _bl_owner_id_get() + _bl_owner_id_set(module_name) + # 3) try run the modules register function try: mod.register() @@ -363,6 +368,8 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non if default_set: _addon_remove(module_name) return None + finally: + _bl_owner_id_set(owner_id_prev) # * OK loaded successfully! * mod.__addon_enabled__ = True diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 6b06ff77ecd..5387af46d9d 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -766,7 +766,23 @@ class _GenericUI: # ensure menus always get default context operator_context_default = self.layout.operator_context + # Support filtering out by owner + workspace = context.workspace + if workspace.use_filter_by_owner: + owner_names = {owner_id.name for owner_id in workspace.owner_ids} + else: + owner_names = None + for func in draw_ls._draw_funcs: + + # Begin 'owner_id' filter. + if owner_names is not None: + owner_id = getattr(func, "_owner", None) + if owner_id is not None: + if func._owner not in owner_names: + continue + # End 'owner_id' filter. + # so bad menu functions don't stop # the entire menu from drawing try: @@ -782,6 +798,13 @@ class _GenericUI: return draw_funcs + @staticmethod + def _dyn_owner_apply(draw_func): + from _bpy import _bl_owner_id_get + owner_id = _bl_owner_id_get() + if owner_id is not None: + draw_func._owner = owner_id + @classmethod def is_extended(cls): return bool(getattr(cls.draw, "_draw_funcs", None)) @@ -793,6 +816,7 @@ class _GenericUI: takes the same arguments as the menus draw function """ draw_funcs = cls._dyn_ui_initialize() + cls._dyn_owner_apply(draw_func) draw_funcs.append(draw_func) @classmethod @@ -802,6 +826,7 @@ class _GenericUI: the menus draw function """ draw_funcs = cls._dyn_ui_initialize() + cls._dyn_owner_apply(draw_func) draw_funcs.insert(0, draw_func) @classmethod diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 022ee1576d8..1bbb3e9883e 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1887,6 +1887,37 @@ class WM_OT_addon_disable(Operator): return {'FINISHED'} +class WM_OT_owner_enable(Operator): + """Enable workspace owner ID""" + bl_idname = "wm.owner_enable" + bl_label = "Enable Add-on" + + owner_id = StringProperty( + name="UI Tag", + ) + + def execute(self, context): + workspace = context.workspace + workspace.owner_ids.new(self.owner_id) + return {'FINISHED'} + + +class WM_OT_owner_disable(Operator): + """Enable workspace owner ID""" + bl_idname = "wm.owner_disable" + bl_label = "Disable UI Tag" + + owner_id = StringProperty( + name="UI Tag", + ) + + def execute(self, context): + workspace = context.workspace + owner_id = workspace.owner_ids[self.owner_id] + workspace.owner_ids.remove(owner_id) + return {'FINISHED'} + + class WM_OT_theme_install(Operator): """Load and apply a Blender XML theme file""" bl_idname = "wm.theme_install" @@ -2384,5 +2415,7 @@ classes = ( WM_OT_properties_remove, WM_OT_sysinfo, WM_OT_theme_install, + WM_OT_owner_disable, + WM_OT_owner_enable, WM_OT_url_open, ) diff --git a/release/scripts/startup/bl_ui/properties_data_workspace.py b/release/scripts/startup/bl_ui/properties_data_workspace.py index dae798bee95..1ece70f5e14 100644 --- a/release/scripts/startup/bl_ui/properties_data_workspace.py +++ b/release/scripts/startup/bl_ui/properties_data_workspace.py @@ -61,6 +61,62 @@ class WORKSPACE_PT_workspace(WorkSpaceButtonsPanel, Panel): layout.prop(view_render, "engine", text="") +class WORKSPACE_PT_owner_ids(WorkSpaceButtonsPanel, Panel): + bl_label = "Show/Hide Add-ons" + bl_options = {'DEFAULT_CLOSED'} + + def draw_header(self, context): + workspace = context.workspace + self.layout.prop(workspace, "use_filter_by_owner", text="") + + def draw(self, context): + layout = self.layout + # align just to pack more tightly + col = layout.box().column(align=True) + + workspace = context.workspace + userpref = context.user_preferences + + col.active = workspace.use_filter_by_owner + + import addon_utils + addon_map = { + mod.__name__: ("%s: %s" % (mod.bl_info["category"], mod.bl_info["name"])) + for mod in addon_utils.modules() + } + owner_ids = {owner_id.name for owner_id in workspace.owner_ids} + + for addon in userpref.addons: + module_name = addon.module + text = addon_map[module_name] + is_enabled = module_name in owner_ids + row = col.row() + row.operator( + "wm.owner_disable" if is_enabled else "wm.owner_enable", + icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', + text="", + emboss=False, + ).owner_id = module_name + row.label(text) + if is_enabled: + owner_ids.remove(module_name) + + # Detect unused + if owner_ids: + layout.label(text="Unknown add-ons", icon='ERROR') + col = layout.box().column(align=True) + for module_name in sorted(owner_ids): + row = col.row() + row.operator( + "wm.owner_disable", + icon='CHECKBOX_HLT', + text="", + emboss=False, + ).owner_id = module_name + row.label(module_name) + + + class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel): _context_path = "workspace" _property_type = bpy.types.WorkSpace @@ -69,6 +125,7 @@ class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel): classes = ( WORKSPACE_PT_context, WORKSPACE_PT_workspace, + WORKSPACE_PT_owner_ids, WORKSPACE_PT_custom_props, ) diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 6669f3103da..3957641fe3f 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -194,6 +194,7 @@ typedef struct PanelType { char translation_context[BKE_ST_MAXNAME]; char context[BKE_ST_MAXNAME]; /* for buttons window */ char category[BKE_ST_MAXNAME]; /* for category tabs */ + char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */ int space_type; int region_type; @@ -264,6 +265,7 @@ typedef struct MenuType { char idname[BKE_ST_MAXNAME]; /* unique name */ char label[BKE_ST_MAXNAME]; /* for button text */ char translation_context[BKE_ST_MAXNAME]; + char owner_id[BKE_ST_MAXNAME]; /* optional, see: #wmOwnerID */ const char *description; /* verify if the menu should draw or not */ diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h index b309ae838d6..0aff79b7e30 100644 --- a/source/blender/blenkernel/BKE_workspace.h +++ b/source/blender/blenkernel/BKE_workspace.h @@ -136,6 +136,9 @@ void BKE_workspace_update_object_mode( struct Object *BKE_workspace_edit_object( struct WorkSpace *workspace, struct Scene *scene); +bool BKE_workspace_owner_id_check( + const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL(); + #undef GETTER_ATTRS #undef SETTER_ATTRS diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 9251c6630a5..301084e22fc 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -169,6 +169,7 @@ void BKE_workspace_free(WorkSpace *workspace) BKE_workspace_relations_free(&workspace->hook_layout_relations); BKE_workspace_relations_free(&workspace->scene_viewlayer_relations); + BLI_freelistN(&workspace->owner_ids); BLI_freelistN(&workspace->layouts); BLI_freelistN(&workspace->transform_orientations); @@ -535,3 +536,16 @@ Object *BKE_workspace_edit_object(WorkSpace *workspace, Scene *scene) return NULL; } +bool BKE_workspace_owner_id_check( + const WorkSpace *workspace, const char *owner_id) +{ + if ((*owner_id == '\0') || + ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0)) + { + return true; + } + else { + /* we could use hash lookup, for now this list is highly under < ~16 items. */ + return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL; + } +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d96be6a9f55..af97aeb8fc0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2904,6 +2904,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main link_list(fd, &workspace->hook_layout_relations); link_list(fd, &workspace->scene_viewlayer_relations); link_list(fd, BKE_workspace_transform_orientations_get(workspace)); + link_list(fd, &workspace->owner_ids); for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first; relation; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 64964a9de00..c09b6d627ff 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -3781,6 +3781,7 @@ static void write_workspace(WriteData *wd, WorkSpace *workspace) writelist(wd, DATA, WorkSpaceLayout, layouts); writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations); writelist(wd, DATA, WorkSpaceDataRelation, &workspace->scene_viewlayer_relations); + writelist(wd, DATA, wmOwnerID, &workspace->owner_ids); writelist(wd, DATA, TransformOrientation, transform_orientations); } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index f6a1e8913ff..ac577375a31 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -41,10 +41,10 @@ #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" - #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "RNA_access.h" #include "RNA_types.h" @@ -1824,6 +1824,7 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco) void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical) { + const WorkSpace *workspace = CTX_wm_workspace(C); ScrArea *sa = CTX_wm_area(C); uiStyle *style = UI_style_get_dpi(); uiBlock *block; @@ -1874,6 +1875,11 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c continue; } + /* If we're tagged, only use compatible. */ + if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { + continue; + } + /* draw panel */ if (pt->draw && (!pt->poll || pt->poll(C, pt))) { BLI_SMALLSTACK_PUSH(pt_stack, pt); diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 56c3c8ab976..cc1db43758b 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -312,6 +312,7 @@ typedef struct wmKeyMap { char idname[64]; /* global editor keymaps, or for more per space/region */ short spaceid; /* same IDs as in DNA_space_types.h */ short regionid; /* see above */ + char owner_id[64]; /* optional, see: #wmOwnerID */ short flag; /* general flags */ short kmi_id; /* last kmi id */ diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index dbcc278ea15..894119b1e72 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -77,6 +77,12 @@ typedef struct WorkSpaceLayout { char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */ } WorkSpaceLayout; +/** Optional tags, which features to use, aligned with #bAddon names by convention. */ +typedef struct wmOwnerID { + struct wmOwnerID *next, *prev; + char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */ +} wmOwnerID; + typedef struct WorkSpace { ID id; @@ -86,6 +92,9 @@ typedef struct WorkSpace { ListBase hook_layout_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */ ListBase scene_viewlayer_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */ + /* Feature tagging (use for addons) */ + ListBase owner_ids DNA_PRIVATE_WORKSPACE_READ_WRITE; /* wmOwnerID */ + /* Custom transform orientations */ ListBase transform_orientations DNA_PRIVATE_WORKSPACE; @@ -154,6 +163,7 @@ typedef struct WorkSpaceInstanceHook { typedef enum eWorkSpaceFlags { WORKSPACE_USE_SCENE_SETTINGS = (1 << 0), + WORKSPACE_USE_FILTER_BY_ORIGIN = (1 << 1), } eWorkSpaceFlags; #endif /* __DNA_WORKSPACE_TYPES_H__ */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 816a472559f..5e3cbeaa057 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -719,6 +719,7 @@ extern StructRNA RNA_WipeSequence; extern StructRNA RNA_WireframeModifier; extern StructRNA RNA_WoodTexture; extern StructRNA RNA_WorkSpace; +extern StructRNA RNA_wmOwnerIDs; extern StructRNA RNA_World; extern StructRNA RNA_WorldAmbientOcclusion; extern StructRNA RNA_WorldLighting; @@ -1303,6 +1304,10 @@ void RNA_property_override_status( PointerRNA *ptr, PropertyRNA *prop, const int index, bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked); +void RNA_struct_state_owner_set(const char *name); +const char *RNA_struct_state_owner_get(void); + + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 2a9b9ebe376..57eeb9e11e0 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -505,7 +505,6 @@ typedef struct ExtensionRNA { StructRNA *srna; StructCallbackFunc call; StructFreeFunc free; - } ExtensionRNA; #ifdef __cplusplus diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 1750c50b9da..0f47a461cda 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -7723,3 +7723,22 @@ bool RNA_path_resolved_create( return false; } } + +static char rna_struct_state_owner[64]; +void RNA_struct_state_owner_set(const char *name) +{ + if (name) { + BLI_strncpy(rna_struct_state_owner, name, sizeof(rna_struct_state_owner)); + } + else { + rna_struct_state_owner[0] = '\0'; + } +} + +const char *RNA_struct_state_owner_get(void) +{ + if (rna_struct_state_owner[0]) { + return rna_struct_state_owner; + } + return NULL; +} diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index f2527a8a5e9..40657b3a225 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -267,6 +267,13 @@ static StructRNA *rna_Panel_register( else BLI_addtail(&art->paneltypes, pt); + { + const char *owner_id = RNA_struct_state_owner_get(); + if (owner_id) { + BLI_strncpy(pt->owner_id, owner_id, sizeof(pt->owner_id)); + } + } + /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); @@ -773,6 +780,13 @@ static StructRNA *rna_Menu_register( mt->poll = (have_function[0]) ? menu_poll : NULL; mt->draw = (have_function[1]) ? menu_draw : NULL; + { + const char *owner_id = RNA_struct_state_owner_get(); + if (owner_id) { + BLI_strncpy(mt->owner_id, owner_id, sizeof(mt->owner_id)); + } + } + WM_menutype_add(mt); /* update while blender is running */ @@ -1023,6 +1037,10 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->category"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->owner_id"); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->space_type"); RNA_def_property_enum_items(prop, rna_enum_space_type_items); @@ -1290,6 +1308,10 @@ static void rna_def_menu(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->owner_id"); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_define_verify_sdna(1); } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index e827a099f5b..5110f4cc27a 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -2253,6 +2253,10 @@ static void rna_def_keyconfig(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", "Name of the key map"); RNA_def_struct_name_property(srna, prop); + prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "owner_id"); + RNA_def_property_ui_text(prop, "Owner", "Internal owner"); + prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spaceid"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c index d6de12407b0..bb40a12f5d5 100644 --- a/source/blender/makesrna/intern/rna_wm_manipulator.c +++ b/source/blender/makesrna/intern/rna_wm_manipulator.c @@ -806,6 +806,13 @@ static StructRNA *rna_ManipulatorGroup_register( wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_append_ptr( BPY_RNA_manipulatorgroup_wrapper, (void *)&dummywgt); + { + const char *owner_id = RNA_struct_state_owner_get(); + if (owner_id) { + BLI_strncpy(wgt->owner_id, owner_id, sizeof(wgt->owner_id)); + } + } + if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) { WM_manipulator_group_type_add_ptr_ex(wgt, mmap_type); @@ -1204,6 +1211,10 @@ static void rna_def_manipulatorgroup(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "Region Type", "The region where the panel is going to be used in"); + prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->owner_id"); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + /* bl_options */ static EnumPropertyItem manipulatorgroup_flag_items[] = { {WM_MANIPULATORGROUPTYPE_3D, "3D", 0, "3D", diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 5e0a4b97981..7ac4134f02b 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -52,6 +52,10 @@ #include "RNA_access.h" +static void rna_window_update_all(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + WM_main_add_notifier(NC_WINDOW, NULL); +} void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { @@ -79,8 +83,94 @@ static PointerRNA rna_workspace_transform_orientations_item_get(CollectionProper return rna_pointer_inherit_refine(&iter->parent, &RNA_TransformOrientation, transform_orientation); } +/* workspace.owner_ids */ + +static wmOwnerID *rna_WorkSpace_owner_ids_new( + WorkSpace *workspace, const char *name) +{ + wmOwnerID *owner_id = MEM_callocN(sizeof(*owner_id), __func__); + BLI_addtail(&workspace->owner_ids, owner_id); + BLI_strncpy(owner_id->name, name, sizeof(owner_id->name)); + WM_main_add_notifier(NC_WINDOW, NULL); + return owner_id; +} + +static void rna_WorkSpace_owner_ids_remove( + WorkSpace *workspace, ReportList *reports, PointerRNA *wstag_ptr) +{ + wmOwnerID *owner_id = wstag_ptr->data; + if (BLI_remlink_safe(&workspace->owner_ids, owner_id) == false) { + BKE_reportf(reports, RPT_ERROR, + "wmOwnerID '%s' not in workspace '%s'", + owner_id->name, workspace->id.name + 2); + return; + } + + MEM_freeN(owner_id); + RNA_POINTER_INVALIDATE(wstag_ptr); + + WM_main_add_notifier(NC_WINDOW, NULL); +} + +static void rna_WorkSpace_owner_ids_clear( + WorkSpace *workspace) +{ + BLI_freelistN(&workspace->owner_ids); + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace); +} + #else /* RNA_RUNTIME */ +static void rna_def_workspace_owner(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "wmOwnerID", NULL); + RNA_def_struct_sdna(srna, "wmOwnerID"); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text(srna, "Work Space UI Tag", ""); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); +} + +static void rna_def_workspace_owner_ids(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "wmOwnerIDs"); + srna = RNA_def_struct(brna, "wmOwnerIDs", NULL); + RNA_def_struct_sdna(srna, "WorkSpace"); + RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", ""); + + /* add owner_id */ + func = RNA_def_function(srna, "new", "rna_WorkSpace_owner_ids_new"); + RNA_def_function_ui_description(func, "Add ui tag"); + parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the tag"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* return type */ + parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", ""); + RNA_def_function_return(func, parm); + + /* remove owner_id */ + func = RNA_def_function(srna, "remove", "rna_WorkSpace_owner_ids_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Remove ui tag"); + /* owner_id to remove */ + parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "Tag to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + /* clear all modifiers */ + func = RNA_def_function(srna, "clear", "rna_WorkSpace_owner_ids_clear"); + RNA_def_function_ui_description(func, "Remove all tags"); +} + static void rna_def_workspace(BlenderRNA *brna) { StructRNA *srna; @@ -121,6 +211,11 @@ static void rna_def_workspace(BlenderRNA *brna) "rna_workspace_transform_orientations_item_get", NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Transform Orientations", ""); + prop = RNA_def_property(srna, "owner_ids", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "wmOwnerID"); + RNA_def_property_ui_text(prop, "UI Tags", ""); + rna_def_workspace_owner_ids(brna, prop); + prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_object_mode_items); RNA_def_property_ui_text(prop, "Mode", "Object interaction mode used in this window"); @@ -138,6 +233,13 @@ static void rna_def_workspace(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Scene Settings", "Use scene settings instead of workspace settings"); RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL); + + prop = RNA_def_property(srna, "use_filter_by_owner", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", WORKSPACE_USE_FILTER_BY_ORIGIN); + RNA_def_property_ui_text(prop, "Use UI Tags", + "Filter the UI by tags"); + RNA_def_property_update(prop, 0, "rna_window_update_all"); } static void rna_def_transform_orientation(BlenderRNA *brna) @@ -160,6 +262,7 @@ static void rna_def_transform_orientation(BlenderRNA *brna) void RNA_def_workspace(BlenderRNA *brna) { + rna_def_workspace_owner(brna); rna_def_workspace(brna); rna_def_transform_orientation(brna); } diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 0b791b6acaa..e07fa46424c 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -376,6 +376,9 @@ void BPy_init_modules(void) PyModule_AddObject(mod, meth_bpy_register_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_register_class, NULL)); PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL)); + PyModule_AddObject(mod, meth_bpy_owner_id_get.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_get, NULL)); + PyModule_AddObject(mod, meth_bpy_owner_id_set.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_set, NULL)); + /* add our own modules dir, this is a python package */ bpy_package_py = bpy_import_test("bpy"); } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 4ce9ba59a0b..2aff61dc2b8 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -8257,6 +8257,43 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla Py_RETURN_NONE; } +/* Access to 'owner_id' internal global. */ + +static PyObject *pyrna_bl_owner_id_get(PyObject *UNUSED(self)) +{ + const char *name = RNA_struct_state_owner_get(); + if (name) { + return PyUnicode_FromString(name); + } + Py_RETURN_NONE; +} + +static PyObject *pyrna_bl_owner_id_set(PyObject *UNUSED(self), PyObject *value) +{ + const char *name; + if (value == Py_None) { + name = NULL; + } + else if (PyUnicode_Check(value)) { + name = _PyUnicode_AsString(value); + } + else { + PyErr_Format(PyExc_ValueError, + "owner_set(...): " + "expected None or a string, not '%.200s'", Py_TYPE(value)->tp_name); + return NULL; + } + RNA_struct_state_owner_set(name); + Py_RETURN_NONE; +} + +PyMethodDef meth_bpy_owner_id_get = { + "_bl_owner_id_get", (PyCFunction)pyrna_bl_owner_id_get, METH_NOARGS, NULL, +}; +PyMethodDef meth_bpy_owner_id_set = { + "_bl_owner_id_set", (PyCFunction)pyrna_bl_owner_id_set, METH_O, NULL, +}; + /* currently this is fairly limited, we would need to make some way to split up * pyrna_callback_classmethod_... if we want more than one callback per type */ typedef struct BPyRNA_CallBack { diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index f666294666e..32a63acde40 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -225,4 +225,8 @@ int pyrna_prop_validity_check(BPy_PropertyRNA *self); extern PyMethodDef meth_bpy_register_class; extern PyMethodDef meth_bpy_unregister_class; +/* bpy.utils._bl_owner_(get/set) */ +extern PyMethodDef meth_bpy_owner_id_set; +extern PyMethodDef meth_bpy_owner_id_get; + #endif diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 344c2ff1725..54c2d7a3aef 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -341,6 +341,14 @@ void WM_menutype_free(void) bool WM_menutype_poll(bContext *C, MenuType *mt) { + /* If we're tagged, only use compatible. */ + if (mt->owner_id[0] != '\0') { + const WorkSpace *workspace = CTX_wm_workspace(C); + if (BKE_workspace_owner_id_check(workspace, mt->owner_id) == false) { + return false; + } + } + if (mt->poll != NULL) { return mt->poll(C, mt); } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 45ed44d83d6..e86e80dddf6 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -37,6 +37,7 @@ #include "DNA_space_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" #include "MEM_guardedalloc.h" @@ -49,6 +50,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "BLT_translation.h" @@ -341,6 +343,12 @@ static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid) km->spaceid = spaceid; km->regionid = regionid; + { + const char *owner_id = RNA_struct_state_owner_get(); + if (owner_id) { + BLI_strncpy(km->owner_id, owner_id, sizeof(km->owner_id)); + } + } return km; } @@ -401,6 +409,14 @@ bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap) bool WM_keymap_poll(bContext *C, wmKeyMap *keymap) { + /* If we're tagged, only use compatible. */ + if (keymap->owner_id[0] != '\0') { + const WorkSpace *workspace = CTX_wm_workspace(C); + if (BKE_workspace_owner_id_check(workspace, keymap->owner_id) == false) { + return false; + } + } + if (keymap->poll != NULL) { return keymap->poll(C); } diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h index 6d83f411db1..8a5580582d7 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h @@ -341,6 +341,7 @@ typedef struct wmManipulatorGroupTypeRef { typedef struct wmManipulatorGroupType { const char *idname; /* MAX_NAME */ const char *name; /* manipulator-group name - displayed in UI (keymap editor) */ + char owner_id[64]; /* MAX_NAME */ /* poll if manipulator-map should be visible */ wmManipulatorGroupFnPoll poll; diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c index 591e76dc37d..31861df1db2 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c @@ -44,6 +44,7 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_workspace.h" #include "RNA_access.h" #include "RNA_define.h" @@ -203,6 +204,13 @@ void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bC bool WM_manipulator_group_type_poll(const bContext *C, const struct wmManipulatorGroupType *wgt) { + /* If we're tagged, only use compatible. */ + if (wgt->owner_id[0] != '\0') { + const WorkSpace *workspace = CTX_wm_workspace(C); + if (BKE_workspace_owner_id_check(workspace, wgt->owner_id) == false) { + return false; + } + } /* Check for poll function, if manipulator-group belongs to an operator, also check if the operator is running. */ return (!wgt->poll || wgt->poll(C, (wmManipulatorGroupType *)wgt)); } |