Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <bastien@blender.org>2022-05-17 17:09:28 +0300
committerBastien Montagne <bastien@blender.org>2022-05-17 17:09:28 +0300
commit8c9805fc628223984ad0c664b5a49b7f9eec0caa (patch)
tree3e7bf59bf86db2b94c90b30e287f9fd123940335 /source/blender/editors
parent939c2387a158722cafa84fc09f0eb13b67c603fe (diff)
Revert "Outliner: Remove the 'Remap data-block usages' operation."
This reverts commit 30534deced8dad16c566dd82db3edd462283de13. After discussion and feedback from users, it's better to keep this tool available until there is time to properly re-think the whole Outliner's contextual menu.
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc181
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh8
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.cc1
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc27
4 files changed, 217 insertions, 0 deletions
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index f4e28af3fca..1de45b0ec96 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -576,6 +576,187 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name ID Remap Operator
+ * \{ */
+
+static int outliner_id_remap_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
+
+ const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
+ ID *old_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
+ ID *new_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
+
+ /* check for invalid states */
+ if (space_outliner == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Invalid old/new ID pair ('%s' / '%s')",
+ old_id ? old_id->name : "Invalid ID",
+ new_id ? new_id->name : "Invalid ID");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ID_IS_LINKED(old_id)) {
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ "Old ID '%s' is linked from a library, indirect usages of this data-block will "
+ "not be remapped",
+ old_id->name);
+ }
+
+ BKE_libblock_remap(
+ bmain, old_id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+
+ /* recreate dependency graph to include new objects */
+ DEG_relations_tag_update(bmain);
+
+ /* Free gpu materials, some materials depend on existing objects,
+ * such as lights so freeing correctly refreshes. */
+ GPU_materials_free(bmain);
+
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool outliner_id_remap_find_tree_element(bContext *C,
+ wmOperator *op,
+ ListBase *tree,
+ const float y)
+{
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
+ if (y > te->ys && y < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->type == TSE_SOME_ID) && tselem->id) {
+ RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
+ RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
+ return true;
+ }
+ }
+ if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
+ ARegion *region = CTX_wm_region(C);
+ float fmval[2];
+
+ if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
+ }
+
+ return WM_operator_props_dialog_popup(C, op, 400);
+}
+
+static const EnumPropertyItem *outliner_id_itemf(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ if (C == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ EnumPropertyItem item_tmp = {0}, *item = nullptr;
+ int totitem = 0;
+ int i = 0;
+
+ short id_type = (short)RNA_enum_get(ptr, "id_type");
+ ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
+
+ for (; id; id = reinterpret_cast<ID *>(id->next)) {
+ item_tmp.identifier = item_tmp.name = id->name + 2;
+ item_tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OUTLINER_OT_id_remap(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Outliner ID Data Remap";
+ ot->idname = "OUTLINER_OT_id_remap";
+
+ /* callbacks */
+ ot->invoke = outliner_id_remap_invoke;
+ ot->exec = outliner_id_remap_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
+ /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
+ */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
+ RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN));
+
+ ot->prop = RNA_def_enum(ot->srna,
+ "new_id",
+ DummyRNA_NULL_items,
+ 0,
+ "New ID",
+ "New ID to remap all selected IDs' users to");
+ RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
+ RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
+}
+
+void id_remap_fn(bContext *C,
+ ReportList *UNUSED(reports),
+ Scene *UNUSED(scene),
+ TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep),
+ TreeStoreElem *tselem,
+ void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
+ PointerRNA op_props;
+
+ BLI_assert(tselem->id != nullptr);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
+
+ WM_operator_properties_free(&op_props);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name ID Copy Operator
* \{ */
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index 2fdf327cbee..f3bcb7b0f1e 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -442,6 +442,13 @@ void id_delete_fn(struct bContext *C,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
+void id_remap_fn(struct bContext *C,
+ struct ReportList *reports,
+ struct Scene *scene,
+ struct TreeElement *te,
+ struct TreeStoreElem *tsep,
+ struct TreeStoreElem *tselem,
+ void *user_data);
/**
* To retrieve coordinates with redrawing the entire tree.
@@ -516,6 +523,7 @@ void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_id_copy(struct wmOperatorType *ot);
void OUTLINER_OT_id_paste(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.cc b/source/blender/editors/space_outliner/outliner_ops.cc
index e053a94c572..8baac45666e 100644
--- a/source/blender/editors/space_outliner/outliner_ops.cc
+++ b/source/blender/editors/space_outliner/outliner_ops.cc
@@ -31,6 +31,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_id_delete);
+ WM_operatortype_append(OUTLINER_OT_id_remap);
WM_operatortype_append(OUTLINER_OT_id_copy);
WM_operatortype_append(OUTLINER_OT_id_paste);
WM_operatortype_append(OUTLINER_OT_data_operation);
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index cb1f2bd7204..cc81d5ed68d 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -1700,6 +1700,7 @@ enum {
OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
+ OL_OP_REMAP,
OL_OP_RENAME,
};
@@ -1707,6 +1708,11 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
+ {OL_OP_REMAP,
+ "REMAP",
+ 0,
+ "Remap Users",
+ "Make all users of selected data-blocks to use instead a new chosen one"},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
{0, nullptr, 0, nullptr, nullptr},
};
@@ -1768,6 +1774,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Deselect Objects";
selection_changed = true;
break;
+ case OL_OP_REMAP:
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
+ break;
case OL_OP_RENAME:
outliner_do_object_operation(
C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
@@ -1976,6 +1988,7 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
+ OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_COPY,
OUTLINER_IDOP_PASTE,
@@ -1993,6 +2006,11 @@ static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {OUTLINER_IDOP_REMAP,
+ "REMAP",
+ 0,
+ "Remap Users",
+ "Make all users of selected data-blocks to use instead current (clicked) one"},
{0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
@@ -2411,6 +2429,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
break;
}
+ case OUTLINER_IDOP_REMAP: {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
+ }
+ break;
+ }
case OUTLINER_IDOP_COPY: {
wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);