WorkSpace: UI filtering for add-ons

Allows for each workspace to have it's own add-ons on display.

Filtering for: Panels, Menus, Keymaps & Manipulators.
Automatically applies to add-ons at the moment.

Access from workspace, toggled off by default
once enabled, add-ons can be white-listed.

See D3076
This commit is contained in:
Campbell Barton 2018-03-01 01:26:02 +11:00
parent 80d1d9629e
commit d937d06c02
26 changed files with 402 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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 */

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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__ */

View File

@ -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

View File

@ -505,7 +505,6 @@ typedef struct ExtensionRNA {
StructRNA *srna;
StructCallbackFunc call;
StructFreeFunc free;
} ExtensionRNA;
#ifdef __cplusplus

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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",

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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 {

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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));
}