|
|
|
|
@@ -453,6 +453,99 @@ static void outliner_do_libdata_operation(bContext *C,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef enum eOutlinerLibOpSelectionSet {
|
|
|
|
|
/* Only selected items. */
|
|
|
|
|
OUTLINER_LIB_SELECTIONSET_SELECTED,
|
|
|
|
|
/* Only content 'inside' selected items (their sub-tree). */
|
|
|
|
|
OUTLINER_LIB_LIB_SELECTIONSET_CONTENT,
|
|
|
|
|
/* Combining both options above. */
|
|
|
|
|
OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT,
|
|
|
|
|
} eOutlinerLibOpSelectionSet;
|
|
|
|
|
|
|
|
|
|
static const EnumPropertyItem prop_lib_op_selection_set[] = {
|
|
|
|
|
{OUTLINER_LIB_SELECTIONSET_SELECTED,
|
|
|
|
|
"SELECTED",
|
|
|
|
|
0,
|
|
|
|
|
"Selected",
|
|
|
|
|
"Apply the operation over selected data-blocks only"},
|
|
|
|
|
{OUTLINER_LIB_LIB_SELECTIONSET_CONTENT,
|
|
|
|
|
"CONTENT",
|
|
|
|
|
0,
|
|
|
|
|
"Content",
|
|
|
|
|
"Apply the operation over content of the selected items only (the data-blocks in their "
|
|
|
|
|
"sub-tree)"},
|
|
|
|
|
{OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT,
|
|
|
|
|
"SELECTED_AND_CONTENT",
|
|
|
|
|
0,
|
|
|
|
|
"Selected & Content",
|
|
|
|
|
"Apply the operation over selected data-blocks and all their dependencies"},
|
|
|
|
|
{0, nullptr, 0, nullptr, nullptr},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void outliner_do_libdata_operation_selection_set(bContext *C,
|
|
|
|
|
ReportList *reports,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
SpaceOutliner *space_outliner,
|
|
|
|
|
const ListBase &subtree,
|
|
|
|
|
const bool has_parent_selected,
|
|
|
|
|
outliner_operation_fn operation_fn,
|
|
|
|
|
eOutlinerLibOpSelectionSet selection_set,
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
const bool do_selected = ELEM(selection_set,
|
|
|
|
|
OUTLINER_LIB_SELECTIONSET_SELECTED,
|
|
|
|
|
OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT);
|
|
|
|
|
const bool do_content = ELEM(selection_set,
|
|
|
|
|
OUTLINER_LIB_LIB_SELECTIONSET_CONTENT,
|
|
|
|
|
OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT);
|
|
|
|
|
|
|
|
|
|
LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
|
|
|
|
|
/* Get needed data out in case element gets freed. */
|
|
|
|
|
TreeStoreElem *tselem = TREESTORE(element);
|
|
|
|
|
const ListBase subtree = element->subtree;
|
|
|
|
|
|
|
|
|
|
bool is_selected = tselem->flag & TSE_SELECTED;
|
|
|
|
|
if ((is_selected && do_selected) || (has_parent_selected && do_content)) {
|
|
|
|
|
if (((tselem->type == TSE_SOME_ID) && (element->idcode != 0)) ||
|
|
|
|
|
tselem->type == TSE_LAYER_COLLECTION) {
|
|
|
|
|
TreeStoreElem *tsep = element->parent ? TREESTORE(element->parent) : nullptr;
|
|
|
|
|
operation_fn(C, reports, scene, element, tsep, tselem, user_data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't access element from now on, it may be freed. Note that the open/collapsed state may
|
|
|
|
|
* also have been changed in the visitor callback. */
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
subtree,
|
|
|
|
|
is_selected || has_parent_selected,
|
|
|
|
|
operation_fn,
|
|
|
|
|
selection_set,
|
|
|
|
|
user_data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void outliner_do_libdata_operation_selection_set(bContext *C,
|
|
|
|
|
ReportList *reports,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
SpaceOutliner *space_outliner,
|
|
|
|
|
outliner_operation_fn operation_fn,
|
|
|
|
|
eOutlinerLibOpSelectionSet selection_set,
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
space_outliner->tree,
|
|
|
|
|
false,
|
|
|
|
|
operation_fn,
|
|
|
|
|
selection_set,
|
|
|
|
|
user_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
@@ -842,6 +935,20 @@ struct OutlinerLibOverrideData {
|
|
|
|
|
id_hierarchy_root_reference);
|
|
|
|
|
value.append(id_root_data);
|
|
|
|
|
}
|
|
|
|
|
void id_root_set(ID *id_hierarchy_root_reference)
|
|
|
|
|
{
|
|
|
|
|
OutlinerLiboverrideDataIDRoot id_root_data;
|
|
|
|
|
id_root_data.id_root_reference = nullptr;
|
|
|
|
|
id_root_data.id_hierarchy_root_override = nullptr;
|
|
|
|
|
id_root_data.id_instance_hint = nullptr;
|
|
|
|
|
id_root_data.is_override_instancing_object = false;
|
|
|
|
|
|
|
|
|
|
Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
|
|
|
|
|
id_hierarchy_root_reference);
|
|
|
|
|
if (value.is_empty()) {
|
|
|
|
|
value.append(id_root_data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override
|
|
|
|
|
@@ -860,17 +967,29 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *C,
|
|
|
|
|
const bool do_hierarchy = data->do_hierarchy;
|
|
|
|
|
ID *id_root_reference = tselem->id;
|
|
|
|
|
|
|
|
|
|
if (!BKE_idtype_idcode_is_linkable(GS(id_root_reference->name)) ||
|
|
|
|
|
(id_root_reference->flag & (LIB_EMBEDDED_DATA | LIB_EMBEDDED_DATA_LIB_OVERRIDE)) != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_assert(do_hierarchy);
|
|
|
|
|
UNUSED_VARS_NDEBUG(do_hierarchy);
|
|
|
|
|
|
|
|
|
|
printf("Adding %s as selected item to get editable override\n", id_root_reference->name);
|
|
|
|
|
data->selected_id_uid.add(id_root_reference->session_uuid);
|
|
|
|
|
|
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root_reference) && !ID_IS_LINKED(id_root_reference)) {
|
|
|
|
|
id_root_reference->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) {
|
|
|
|
|
/* If selected element is a (closed) collection, check all of its objects recursively, and also
|
|
|
|
|
* consider the armature ones as 'selected' (i.e. to not become system overrides). */
|
|
|
|
|
Collection *root_collection = reinterpret_cast<Collection *>(id_root_reference);
|
|
|
|
|
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (root_collection, object_iter) {
|
|
|
|
|
if (id_root_reference->lib == object_iter->id.lib && object_iter->type == OB_ARMATURE) {
|
|
|
|
|
printf("Adding %s as selected item to get editable override\n", object_iter->id.name);
|
|
|
|
|
data->selected_id_uid.add(object_iter->id.session_uuid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -983,6 +1102,17 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *C,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* While ideally this should not be needed, in practice user almost _never_ wants to actually
|
|
|
|
|
* create liboverrides for all data under a selected hierarchy node, and this has currently a
|
|
|
|
|
* dreadful consequences over performances (since it would call
|
|
|
|
|
* #BKE_lib_override_library_create over _all_ items in the hierarchy). So only the clearing of
|
|
|
|
|
* the system override flag is supported for non-selected items for now.
|
|
|
|
|
*/
|
|
|
|
|
const bool is_selected = tselem->flag & TSE_SELECTED;
|
|
|
|
|
if (!is_selected && data->id_hierarchy_roots.contains(id_hierarchy_root_reference)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data->id_root_add(id_hierarchy_root_reference,
|
|
|
|
|
id_root_reference,
|
|
|
|
|
id_instance_hint,
|
|
|
|
|
@@ -1133,23 +1263,6 @@ static void id_override_library_create_hierarchy_process(bContext *C,
|
|
|
|
|
FOREACH_MAIN_ID_END;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void id_override_library_toggle_flag_fn(bContext *UNUSED(C),
|
|
|
|
|
ReportList *UNUSED(reports),
|
|
|
|
|
Scene *UNUSED(scene),
|
|
|
|
|
TreeElement *UNUSED(te),
|
|
|
|
|
TreeStoreElem *UNUSED(tsep),
|
|
|
|
|
TreeStoreElem *tselem,
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(TSE_IS_REAL_ID(tselem));
|
|
|
|
|
ID *id = tselem->id;
|
|
|
|
|
|
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
|
|
|
|
const uint flag = POINTER_AS_UINT(user_data);
|
|
|
|
|
id->override_library->flag ^= flag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void id_override_library_reset_fn(bContext *C,
|
|
|
|
|
ReportList *UNUSED(reports),
|
|
|
|
|
Scene *UNUSED(scene),
|
|
|
|
|
@@ -1181,10 +1294,10 @@ static void id_override_library_reset_fn(bContext *C,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void id_override_library_resync_fn(bContext *C,
|
|
|
|
|
ReportList *reports,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
TreeElement *te,
|
|
|
|
|
static void id_override_library_resync_fn(bContext *UNUSED(C),
|
|
|
|
|
ReportList *UNUSED(reports),
|
|
|
|
|
Scene *UNUSED(scene),
|
|
|
|
|
TreeElement *UNUSED(te),
|
|
|
|
|
TreeStoreElem *UNUSED(tsep),
|
|
|
|
|
TreeStoreElem *tselem,
|
|
|
|
|
void *user_data)
|
|
|
|
|
@@ -1192,44 +1305,53 @@ static void id_override_library_resync_fn(bContext *C,
|
|
|
|
|
BLI_assert(TSE_IS_REAL_ID(tselem));
|
|
|
|
|
ID *id_root = tselem->id;
|
|
|
|
|
OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
|
|
|
|
|
const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce;
|
|
|
|
|
|
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
|
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
|
|
|
|
|
|
id_root->tag |= LIB_TAG_DOIT;
|
|
|
|
|
|
|
|
|
|
/* Tag all linked parents in tree hierarchy to be also overridden. */
|
|
|
|
|
while ((te = te->parent) != nullptr) {
|
|
|
|
|
if (!TSE_IS_REAL_ID(te->store_elem)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
te->store_elem->id->tag |= LIB_TAG_DOIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BlendFileReadReport report{};
|
|
|
|
|
report.reports = reports;
|
|
|
|
|
BKE_lib_override_library_resync(
|
|
|
|
|
bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report);
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_WINDOW, nullptr);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
|
|
|
|
|
CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (id_root->override_library->hierarchy_root != nullptr) {
|
|
|
|
|
id_root = id_root->override_library->hierarchy_root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data->id_root_set(id_root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void id_override_library_clear_hierarchy_fn(bContext *C,
|
|
|
|
|
/* Resync a hierarchy of library overrides. */
|
|
|
|
|
static void id_override_library_resync_hierarchy_process(bContext *C,
|
|
|
|
|
ReportList *reports,
|
|
|
|
|
OutlinerLibOverrideData &data)
|
|
|
|
|
{
|
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
const bool do_hierarchy_enforce = data.do_resync_hierarchy_enforce;
|
|
|
|
|
|
|
|
|
|
BlendFileReadReport report{};
|
|
|
|
|
report.reports = reports;
|
|
|
|
|
|
|
|
|
|
for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
|
|
|
|
|
BKE_lib_override_library_resync(bmain,
|
|
|
|
|
scene,
|
|
|
|
|
CTX_data_view_layer(C),
|
|
|
|
|
id_hierarchy_root,
|
|
|
|
|
nullptr,
|
|
|
|
|
do_hierarchy_enforce,
|
|
|
|
|
&report);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_WINDOW, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void id_override_library_clear_hierarchy_fn(bContext *UNUSED(C),
|
|
|
|
|
ReportList *UNUSED(reports),
|
|
|
|
|
Scene *UNUSED(scene),
|
|
|
|
|
TreeElement *te,
|
|
|
|
|
TreeElement *UNUSED(te),
|
|
|
|
|
TreeStoreElem *UNUSED(tsep),
|
|
|
|
|
TreeStoreElem *tselem,
|
|
|
|
|
void *UNUSED(user_data))
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
|
|
|
|
|
|
|
|
|
|
BLI_assert(TSE_IS_REAL_ID(tselem));
|
|
|
|
|
ID *id_root = tselem->id;
|
|
|
|
|
|
|
|
|
|
@@ -1238,22 +1360,23 @@ static void id_override_library_clear_hierarchy_fn(bContext *C,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
|
|
|
|
|
|
id_root->tag |= LIB_TAG_DOIT;
|
|
|
|
|
|
|
|
|
|
/* Tag all override parents in tree hierarchy to be also processed. */
|
|
|
|
|
while ((te = te->parent) != nullptr) {
|
|
|
|
|
if (!TSE_IS_REAL_ID(te->store_elem)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
te->store_elem->id->tag |= LIB_TAG_DOIT;
|
|
|
|
|
if (id_root->override_library->hierarchy_root != nullptr) {
|
|
|
|
|
id_root = id_root->override_library->hierarchy_root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BKE_lib_override_library_delete(bmain, id_root);
|
|
|
|
|
data->id_root_set(id_root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear (delete) a hierarchy of library overrides. */
|
|
|
|
|
static void id_override_library_clear_hierarchy_process(bContext *C,
|
|
|
|
|
ReportList *UNUSED(reports),
|
|
|
|
|
OutlinerLibOverrideData &data)
|
|
|
|
|
{
|
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
|
|
|
|
|
|
for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
|
|
|
|
|
BKE_lib_override_library_delete(bmain, id_hierarchy_root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_WINDOW, nullptr);
|
|
|
|
|
}
|
|
|
|
|
@@ -1493,6 +1616,250 @@ static void refreshdrivers_animdata_fn(int UNUSED(event),
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Library Overrides Operation Menu.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
enum eOutlinerLibOverrideOpTypes {
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_INVALID = 0,
|
|
|
|
|
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY,
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_RESET,
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE,
|
|
|
|
|
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY,
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE,
|
|
|
|
|
OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const EnumPropertyItem prop_liboverride_op_types[] = {
|
|
|
|
|
{OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_CREATE_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Create",
|
|
|
|
|
"Make a local override of the selected linked data-blocks, and their hierarchy of "
|
|
|
|
|
"dependencies"},
|
|
|
|
|
{OUTLINER_LIBOVERRIDE_OP_RESET,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESET",
|
|
|
|
|
0,
|
|
|
|
|
"Reset",
|
|
|
|
|
"Reset the selected local override to their linked references values"},
|
|
|
|
|
{OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE,
|
|
|
|
|
"OVERRIDE_LIBRARY_CLEAR_SINGLE",
|
|
|
|
|
0,
|
|
|
|
|
"Clear",
|
|
|
|
|
"Delete the selected local overrides and relink their usages to the linked data-blocks if "
|
|
|
|
|
"possible, else reset them and mark them as non editable"},
|
|
|
|
|
{0, nullptr, 0, nullptr, nullptr},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[] = {
|
|
|
|
|
{OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Resync",
|
|
|
|
|
"Rebuild the selected local overrides from their linked references, as well as their "
|
|
|
|
|
"hierarchies of dependencies"},
|
|
|
|
|
{OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
|
|
|
|
|
0,
|
|
|
|
|
"Resync Enforce",
|
|
|
|
|
"Rebuild the selected local overrides from their linked references, as well as their "
|
|
|
|
|
"hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. "
|
|
|
|
|
"ignoring existing overrides on data-blocks pointer properties)"},
|
|
|
|
|
{OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_DELETE_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Delete",
|
|
|
|
|
"Delete the selected local overrides (including their hierarchies of override dependencies) "
|
|
|
|
|
"and relink their usages to the linked data-blocks"},
|
|
|
|
|
{0, nullptr, 0, nullptr, nullptr},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool outliner_liboverride_operation_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
if (!outliner_operation_tree_element_poll(C)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
|
|
|
|
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
|
|
|
|
|
|
|
|
|
/* check for invalid states */
|
|
|
|
|
if (space_outliner == nullptr) {
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TreeElement *te = get_target_element(space_outliner);
|
|
|
|
|
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
|
|
|
|
|
|
|
|
|
const eOutlinerLibOpSelectionSet selection_set = static_cast<eOutlinerLibOpSelectionSet>(
|
|
|
|
|
RNA_enum_get(op->ptr, "selection_set"));
|
|
|
|
|
const eOutlinerLibOverrideOpTypes event = static_cast<eOutlinerLibOverrideOpTypes>(
|
|
|
|
|
RNA_enum_get(op->ptr, "type"));
|
|
|
|
|
switch (event) {
|
|
|
|
|
case OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
override_data.do_fully_editable = false;
|
|
|
|
|
|
|
|
|
|
outliner_do_libdata_operation_selection_set(
|
|
|
|
|
C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_create_hierarchy_pre_process_fn,
|
|
|
|
|
selection_set,
|
|
|
|
|
&override_data);
|
|
|
|
|
|
|
|
|
|
id_override_library_create_hierarchy_process(C, op->reports, override_data);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_LIBOVERRIDE_OP_RESET: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_reset_fn,
|
|
|
|
|
selection_set,
|
|
|
|
|
&override_data);
|
|
|
|
|
ED_undo_push(C, "Reset Overridden Data");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE: {
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_clear_single_fn,
|
|
|
|
|
selection_set,
|
|
|
|
|
nullptr);
|
|
|
|
|
ED_undo_push(C, "Clear Overridden Data");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_resync_fn,
|
|
|
|
|
OUTLINER_LIB_SELECTIONSET_SELECTED,
|
|
|
|
|
&override_data);
|
|
|
|
|
|
|
|
|
|
id_override_library_resync_hierarchy_process(C, op->reports, override_data);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Resync Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
override_data.do_resync_hierarchy_enforce = true;
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_resync_fn,
|
|
|
|
|
OUTLINER_LIB_SELECTIONSET_SELECTED,
|
|
|
|
|
&override_data);
|
|
|
|
|
|
|
|
|
|
id_override_library_resync_hierarchy_process(C, op->reports, override_data);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Resync Overridden Data Hierarchy Enforce");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
outliner_do_libdata_operation_selection_set(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_clear_hierarchy_fn,
|
|
|
|
|
OUTLINER_LIB_SELECTIONSET_SELECTED,
|
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
|
|
id_override_library_clear_hierarchy_process(C, op->reports, override_data);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Delete Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
/* Invalid - unhandled. */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* wrong notifier still... */
|
|
|
|
|
WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
|
|
|
|
|
|
|
|
|
|
/* XXX: this is just so that outliner is always up to date. */
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OUTLINER_OT_liboverride_operation(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Outliner Library Override Operation";
|
|
|
|
|
ot->idname = "OUTLINER_OT_liboverride_operation";
|
|
|
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
|
ot->exec = outliner_liboverride_operation_exec;
|
|
|
|
|
ot->poll = outliner_liboverride_operation_poll;
|
|
|
|
|
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
|
|
|
|
|
RNA_def_enum(ot->srna, "type", prop_liboverride_op_types, 0, "Library Override Operation", "");
|
|
|
|
|
ot->prop = RNA_def_enum(ot->srna,
|
|
|
|
|
"selection_set",
|
|
|
|
|
prop_lib_op_selection_set,
|
|
|
|
|
0,
|
|
|
|
|
"Selection Set",
|
|
|
|
|
"Over which part of the tree items to apply the operation");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Outliner Library Override Troubleshoot Operation";
|
|
|
|
|
ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation";
|
|
|
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
|
ot->exec = outliner_liboverride_operation_exec;
|
|
|
|
|
ot->poll = outliner_liboverride_operation_poll;
|
|
|
|
|
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
|
|
|
|
|
RNA_def_enum(ot->srna,
|
|
|
|
|
"type",
|
|
|
|
|
prop_liboverride_troubleshoot_op_types,
|
|
|
|
|
0,
|
|
|
|
|
"Library Override Troubleshoot Operation",
|
|
|
|
|
"");
|
|
|
|
|
ot->prop = RNA_def_enum(ot->srna,
|
|
|
|
|
"selection_set",
|
|
|
|
|
prop_lib_op_selection_set,
|
|
|
|
|
0,
|
|
|
|
|
"Selection Set",
|
|
|
|
|
"Over which part of the tree items to apply the operation");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Object Operation Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
@@ -2088,15 +2455,6 @@ enum eOutlinerIdOpTypes {
|
|
|
|
|
|
|
|
|
|
OUTLINER_IDOP_UNLINK,
|
|
|
|
|
OUTLINER_IDOP_LOCAL,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY,
|
|
|
|
|
OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
|
|
|
|
|
OUTLINER_IDOP_SINGLE,
|
|
|
|
|
OUTLINER_IDOP_DELETE,
|
|
|
|
|
OUTLINER_IDOP_REMAP,
|
|
|
|
|
@@ -2123,59 +2481,6 @@ static const EnumPropertyItem prop_id_op_types[] = {
|
|
|
|
|
"Remap Users",
|
|
|
|
|
"Make all users of selected data-blocks to use instead current (clicked) one"},
|
|
|
|
|
RNA_ENUM_ITEM_SEPR,
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
|
|
|
|
|
"OVERRIDE_LIBRARY_CREATE",
|
|
|
|
|
0,
|
|
|
|
|
"Make Library Override Single",
|
|
|
|
|
"Make a single, out-of-hierarchy local override of this linked data-block - only applies to "
|
|
|
|
|
"active Outliner item"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_CREATE_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Make Library Override Hierarchy",
|
|
|
|
|
"Make a local override of this linked data-block, and its hierarchy of dependencies - only "
|
|
|
|
|
"applies to active Outliner item"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
|
|
|
|
|
"OVERRIDE_LIBRARY_MAKE_EDITABLE",
|
|
|
|
|
0,
|
|
|
|
|
"Make Library Override Editable",
|
|
|
|
|
"Make the library override data-block editable"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESET",
|
|
|
|
|
0,
|
|
|
|
|
"Reset Library Override Single",
|
|
|
|
|
"Reset this local override to its linked values"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESET_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Reset Library Override Hierarchy",
|
|
|
|
|
"Reset this local override to its linked values, as well as its hierarchy of dependencies"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Resync Library Override Hierarchy",
|
|
|
|
|
"Rebuild this local override from its linked reference, as well as its hierarchy of "
|
|
|
|
|
"dependencies"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE,
|
|
|
|
|
"OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
|
|
|
|
|
0,
|
|
|
|
|
"Resync Library Override Hierarchy Enforce",
|
|
|
|
|
"Rebuild this local override from its linked reference, as well as its hierarchy of "
|
|
|
|
|
"dependencies, enforcing that hierarchy to match the linked data (i.e. ignoring exiting "
|
|
|
|
|
"overrides on data-blocks pointer properties)"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
|
|
|
|
|
"OVERRIDE_LIBRARY_CLEAR_SINGLE",
|
|
|
|
|
0,
|
|
|
|
|
"Clear Library Override Single",
|
|
|
|
|
"Delete this local override and relink its usages to the linked data-blocks if possible, "
|
|
|
|
|
"else reset it and mark it as non editable"},
|
|
|
|
|
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY,
|
|
|
|
|
"OVERRIDE_LIBRARY_CLEAR_HIERARCHY",
|
|
|
|
|
0,
|
|
|
|
|
"Clear Library Override Hierarchy",
|
|
|
|
|
"Delete this local override (including its hierarchy of override dependencies) and relink "
|
|
|
|
|
"its usages to the linked data-blocks"},
|
|
|
|
|
RNA_ENUM_ITEM_SEPR,
|
|
|
|
|
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
|
|
|
|
|
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
|
|
|
|
|
RNA_ENUM_ITEM_SEPR,
|
|
|
|
|
@@ -2208,33 +2513,6 @@ static bool outliner_id_operation_item_poll(bContext *C,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (enum_value) {
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE:
|
|
|
|
|
if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY:
|
|
|
|
|
if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id) || (ID_IS_LINKED(tselem->id))) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE:
|
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) {
|
|
|
|
|
if (tselem->id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET:
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY:
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY:
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE:
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY:
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE:
|
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
case OUTLINER_IDOP_SINGLE:
|
|
|
|
|
if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
|
|
|
|
|
return true;
|
|
|
|
|
@@ -2347,95 +2625,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
|
|
|
|
|
ED_undo_push(C, "Localized Data");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = false;
|
|
|
|
|
override_data.do_fully_editable = true;
|
|
|
|
|
|
|
|
|
|
outliner_do_libdata_operation(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_create_hierarchy_pre_process_fn,
|
|
|
|
|
&override_data);
|
|
|
|
|
|
|
|
|
|
id_override_library_create_hierarchy_process(C, op->reports, override_data);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Overridden Data");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
override_data.do_fully_editable = U.experimental.use_override_new_fully_editable;
|
|
|
|
|
|
|
|
|
|
outliner_do_libdata_operation(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_create_hierarchy_pre_process_fn,
|
|
|
|
|
&override_data);
|
|
|
|
|
|
|
|
|
|
id_override_library_create_hierarchy_process(C, op->reports, override_data);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: {
|
|
|
|
|
outliner_do_libdata_operation(C,
|
|
|
|
|
op->reports,
|
|
|
|
|
scene,
|
|
|
|
|
space_outliner,
|
|
|
|
|
id_override_library_toggle_flag_fn,
|
|
|
|
|
POINTER_FROM_UINT(IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED));
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Make Overridden Data Editable");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
outliner_do_libdata_operation(
|
|
|
|
|
C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data);
|
|
|
|
|
ED_undo_push(C, "Reset Overridden Data");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
outliner_do_libdata_operation(
|
|
|
|
|
C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data);
|
|
|
|
|
ED_undo_push(C, "Reset Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
outliner_do_libdata_operation(
|
|
|
|
|
C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
|
|
|
|
|
ED_undo_push(C, "Resync Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: {
|
|
|
|
|
OutlinerLibOverrideData override_data{};
|
|
|
|
|
override_data.do_hierarchy = true;
|
|
|
|
|
override_data.do_resync_hierarchy_enforce = true;
|
|
|
|
|
outliner_do_libdata_operation(
|
|
|
|
|
C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
|
|
|
|
|
ED_undo_push(C, "Resync Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: {
|
|
|
|
|
outliner_do_libdata_operation(
|
|
|
|
|
C, op->reports, scene, space_outliner, id_override_library_clear_hierarchy_fn, nullptr);
|
|
|
|
|
ED_undo_push(C, "Clear Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: {
|
|
|
|
|
outliner_do_libdata_operation(
|
|
|
|
|
C, op->reports, scene, space_outliner, id_override_library_clear_single_fn, nullptr);
|
|
|
|
|
ED_undo_push(C, "Clear Overridden Data Hierarchy");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OUTLINER_IDOP_SINGLE: {
|
|
|
|
|
/* make single user */
|
|
|
|
|
switch (idlevel) {
|
|
|
|
|
|