[Bf-blender-cvs] [1572da858df] master: Outliner: Modifier/constraint/shaderfx drag and drop operator

Nathan Craddock noreply at git.blender.org
Tue Sep 15 23:36:00 CEST 2020


Commit: 1572da858df49af04e4ddb5dbb87a96e57ea6f14
Author: Nathan Craddock
Date:   Tue Sep 15 15:23:08 2020 -0600
Branches: master
https://developer.blender.org/rB1572da858df49af04e4ddb5dbb87a96e57ea6f14

Outliner: Modifier/constraint/shaderfx drag and drop operator

This adds an operator to allow drag and drop of modifiers, constraints,
and shader effects within the outliner. Referred to as "data stack" in
the code for simplicity.

The following operations are allowed:
* Reordering within an object or bone
* Copying a single modifier/constraint/effect to another object or bone
* Copying (linking) all modifiers/constraints/effects to another object
  or bone.

This complements the recent work done for panel-based modifier layouts
by allowing reordering in the outliner. It also makes it simple to copy
a single modifier/constraint/effect to another object.

Differential Revision: https://developer.blender.org/D8642

===================================================================

M	source/blender/editors/space_outliner/outliner_dragdrop.c
M	source/blender/editors/space_outliner/outliner_draw.c
M	source/blender/editors/space_outliner/outliner_intern.h
M	source/blender/editors/space_outliner/outliner_ops.c
M	source/blender/editors/space_outliner/outliner_select.c

===================================================================

diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 46a5f90f6c2..58f6f82c80d 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -26,7 +26,9 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_collection_types.h"
+#include "DNA_constraint_types.h"
 #include "DNA_material_types.h"
+#include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_space_types.h"
 
@@ -36,6 +38,7 @@
 #include "BLT_translation.h"
 
 #include "BKE_collection.h"
+#include "BKE_constraint.h"
 #include "BKE_context.h"
 #include "BKE_layer.h"
 #include "BKE_lib_id.h"
@@ -44,6 +47,7 @@
 #include "BKE_object.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
+#include "BKE_shader_fx.h"
 
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_build.h"
@@ -65,6 +69,8 @@
 
 #include "outliner_intern.h"
 
+static Collection *collection_parent_from_ID(ID *id);
+
 /* ******************** Drop Target Find *********************** */
 
 static TreeElement *outliner_dropzone_element(TreeElement *te,
@@ -146,7 +152,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
     const float margin = UI_UNIT_Y * (1.0f / 4);
 
     if (view_mval[1] < (te_hovered->ys + margin)) {
-      if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner)) {
+      if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner) &&
+          !BLI_listbase_is_empty(&te_hovered->subtree)) {
         /* inserting after a open item means we insert into it, but as first child */
         if (BLI_listbase_is_empty(&te_hovered->subtree)) {
           *r_insert_type = TE_INSERT_INTO;
@@ -183,20 +190,37 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
   return NULL;
 }
 
-static Collection *outliner_collection_from_tree_element_and_parents(TreeElement *te,
-                                                                     TreeElement **r_te)
+typedef bool (*CheckTypeFn)(TreeElement *te);
+
+static TreeElement *outliner_data_from_tree_element_and_parents(CheckTypeFn check_type,
+                                                                TreeElement *te)
 {
   while (te != NULL) {
-    Collection *collection = outliner_collection_from_tree_element(te);
-    if (collection) {
-      *r_te = te;
-      return collection;
+    if (check_type(te)) {
+      return te;
     }
     te = te->parent;
   }
   return NULL;
 }
 
+static bool is_collection_element(TreeElement *te)
+{
+  return outliner_is_collection_tree_element(te);
+}
+
+static bool is_object_element(TreeElement *te)
+{
+  TreeStoreElem *tselem = TREESTORE(te);
+  return tselem->type == 0 && te->idcode == ID_OB;
+}
+
+static bool is_pchan_element(TreeElement *te)
+{
+  TreeStoreElem *tselem = TREESTORE(te);
+  return tselem->type == TSE_POSE_CHANNEL;
+}
+
 static TreeElement *outliner_drop_insert_collection_find(bContext *C,
                                                          const wmEvent *event,
                                                          TreeElementInsertType *r_insert_type)
@@ -206,11 +230,12 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C,
     return NULL;
   }
 
-  TreeElement *collection_te;
-  Collection *collection = outliner_collection_from_tree_element_and_parents(te, &collection_te);
-  if (!collection) {
+  TreeElement *collection_te = outliner_data_from_tree_element_and_parents(is_collection_element,
+                                                                           te);
+  if (!collection_te) {
     return NULL;
   }
+  Collection *collection = outliner_collection_from_tree_element(collection_te);
 
   if (collection_te != te) {
     *r_insert_type = TE_INSERT_INTO;
@@ -224,6 +249,30 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C,
   return collection_te;
 }
 
+static int outliner_get_insert_index(TreeElement *drag_te,
+                                     TreeElement *drop_te,
+                                     TreeElementInsertType insert_type,
+                                     ListBase *listbase)
+{
+  /* Find the element to insert after. NULL is the start of the list. */
+  if (drag_te->index < drop_te->index) {
+    if (insert_type == TE_INSERT_BEFORE) {
+      drop_te = drop_te->prev;
+    }
+  }
+  else {
+    if (insert_type == TE_INSERT_AFTER) {
+      drop_te = drop_te->next;
+    }
+  }
+
+  if (drop_te == NULL) {
+    return 0;
+  }
+
+  return BLI_findindex(listbase, drop_te->directdata);
+}
+
 /* ******************** Parent Drop Operator *********************** */
 
 static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
@@ -616,6 +665,413 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
 }
 
+/* ******************** Data Stack Drop Operator *********************** */
+
+/* A generic operator to allow drag and drop for modifiers, constraints,
+ * and shader effects which all share the same UI stack layout.
+ *
+ * The following operations are allowed:
+ * - Reordering within an object.
+ * - Copying a single modifier/constraint/effect to another object.
+ * - Copying (linking) an object's modifiers/constraints/effects to another. */
+
+typedef enum eDataStackDropAction {
+  DATA_STACK_DROP_REORDER,
+  DATA_STACK_DROP_COPY,
+  DATA_STACK_DROP_LINK,
+} eDataStackDropAction;
+
+typedef struct StackDropData {
+  Object *ob_parent;
+  bPoseChannel *pchan_parent;
+  TreeStoreElem *drag_tselem;
+  void *drag_directdata;
+  int drag_index;
+
+  eDataStackDropAction drop_action;
+  TreeElement *drop_te;
+  TreeElementInsertType insert_type;
+} StackDropData;
+
+static void datastack_drop_data_init(wmDrag *drag,
+                                     Object *ob,
+                                     bPoseChannel *pchan,
+                                     TreeElement *te,
+                                     TreeStoreElem *tselem,
+                                     void *directdata)
+{
+  StackDropData *drop_data = MEM_callocN(sizeof(*drop_data), "datastack drop data");
+
+  drop_data->ob_parent = ob;
+  drop_data->pchan_parent = pchan;
+  drop_data->drag_tselem = tselem;
+  drop_data->drag_directdata = directdata;
+  drop_data->drag_index = te->index;
+
+  drag->poin = drop_data;
+  drag->flags |= WM_DRAG_FREE_DATA;
+}
+
+static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData *drop_data)
+{
+  if (!ELEM(drop_data->drag_tselem->type,
+            TSE_MODIFIER,
+            TSE_MODIFIER_BASE,
+            TSE_CONSTRAINT,
+            TSE_CONSTRAINT_BASE,
+            TSE_GPENCIL_EFFECT,
+            TSE_GPENCIL_EFFECT_BASE)) {
+    return false;
+  }
+
+  TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
+  if (!te_target) {
+    return false;
+  }
+  TreeStoreElem *tselem_target = TREESTORE(te_target);
+
+  if (drop_data->drag_tselem == tselem_target) {
+    return false;
+  }
+
+  Object *ob = NULL;
+  TreeElement *object_te = outliner_data_from_tree_element_and_parents(is_object_element,
+                                                                       te_target);
+  if (object_te) {
+    ob = (Object *)TREESTORE(object_te)->id;
+  }
+
+  bPoseChannel *pchan = NULL;
+  TreeElement *pchan_te = outliner_data_from_tree_element_and_parents(is_pchan_element, te_target);
+  if (pchan_te) {
+    pchan = (bPoseChannel *)pchan_te->directdata;
+  }
+  if (pchan) {
+    ob = NULL;
+  }
+
+  if (ob && ID_IS_LINKED(&ob->id)) {
+    return false;
+  }
+
+  /* Drag a base for linking. */
+  if (ELEM(drop_data->drag_tselem->type,
+           TSE_MODIFIER_BASE,
+           TSE_CONSTRAINT_BASE,
+           TSE_GPENCIL_EFFECT_BASE)) {
+    drop_data->insert_type = TE_INSERT_INTO;
+    drop_data->drop_action = DATA_STACK_DROP_LINK;
+
+    if (pchan && pchan != drop_data->pchan_parent) {
+      drop_data->drop_te = pchan_te;
+      tselem_target = TREESTORE(pchan_te);
+    }
+    else if (ob && ob != drop_data->ob_parent) {
+      drop_data->drop_te = object_te;
+      tselem_target = TREESTORE(object_te);
+    }
+    else {
+      return false;
+    }
+  }
+  else if (ob || pchan) {
+    /* Drag a single item. */
+    if (pchan && pchan != drop_data->pchan_parent) {
+      drop_data->insert_type = TE_INSERT_INTO;
+      drop_data->drop_action = DATA_STACK_DROP_COPY;
+      drop_data->drop_te = pchan_te;
+      tselem_target = TREESTORE(pchan_te);
+    }
+    else if (ob && ob != drop_data->ob_parent) {
+      drop_data->insert_type = TE_INSERT_INTO;
+      drop_data->drop_action = DATA_STACK_DROP_COPY;
+      drop_data->drop_te = object_te;
+      tselem_target = TREESTORE(object_te);
+    }
+    else if (tselem_target->type == drop_data->drag_tselem->type) {
+      if (drop_data->insert_type == TE_INSERT_INTO) {
+        return false;
+      }
+      drop_data->drop_action = DATA_STACK_DROP_REORDER;
+      drop_data->drop_te = te_target;
+    }
+    else {
+      return false;
+    }
+  }
+  else {
+    return false;
+  }
+
+  return true;
+}
+
+/* Ensure that grease pencil and object data remain separate. */
+static bool datastack_drop_are_types_valid(StackDropData *drop_data)
+{
+  TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
+  Object *ob_parent = drop_data->ob_parent;
+  Object *ob_dst = (Object *)tselem->id;
+
+  /* Don't allow data to be moved between objects and bones. */
+  if (tselem->type == TSE_CONSTRAINT) {
+  }
+  else if ((drop_data->pchan_parent && tselem->type != TSE_POSE_CHANNEL) ||
+           (!drop_data->pchan_parent && tselem->type == TSE_POSE_CHANNEL)) {
+    return false;
+  }
+
+  switch (drop_data->drag_tselem->type) {
+    case TSE_MODIFIER_BASE:
+    case TSE_MODIFIER:
+      if (ob_parent->type == OB_GPENCIL) {
+        return ob_dst->type == OB_GPENCIL;
+      }
+      else if (ob_parent->type != OB_GPENCIL) {
+        return ob_dst->type != OB_GPENCIL;
+      }
+      break;
+    case TSE_CONSTRAINT_BASE:
+    case TSE_CONSTRAINT:
+
+      break;
+    case TSE_GPENCIL_EFFECT_BASE:
+    case TSE_GPENCIL_EFFECT:
+      return ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GP

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list