Blender  V2.93
outliner_dragdrop.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <string.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "DNA_collection_types.h"
29 #include "DNA_material_types.h"
30 #include "DNA_object_types.h"
31 #include "DNA_space_types.h"
32 
33 #include "BLI_listbase.h"
34 
35 #include "BLT_translation.h"
36 
37 #include "BKE_collection.h"
38 #include "BKE_context.h"
39 #include "BKE_layer.h"
40 #include "BKE_main.h"
41 #include "BKE_material.h"
42 #include "BKE_object.h"
43 #include "BKE_report.h"
44 
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_build.h"
47 
48 #include "ED_object.h"
49 #include "ED_outliner.h"
50 #include "ED_screen.h"
51 
52 #include "UI_interface.h"
53 #include "UI_view2d.h"
54 
55 #include "RNA_access.h"
56 
57 #include "WM_api.h"
58 #include "WM_types.h"
59 
60 #include "outliner_intern.h"
61 
63 
64 /* ******************** Drop Target Find *********************** */
65 
67  const float fmval[2],
68  const bool children)
69 {
70  if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
71  /* name and first icon */
72  if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) {
73  return te;
74  }
75  }
76  /* Not it. Let's look at its children. */
77  if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
78  LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
79  TreeElement *te_valid = outliner_dropzone_element(te_sub, fmval, children);
80  if (te_valid) {
81  return te_valid;
82  }
83  }
84  }
85  return NULL;
86 }
87 
88 /* Find tree element to drop into. */
89 static TreeElement *outliner_dropzone_find(const SpaceOutliner *space_outliner,
90  const float fmval[2],
91  const bool children)
92 {
93  LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
94  TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
95  if (te_valid) {
96  return te_valid;
97  }
98  }
99  return NULL;
100 }
101 
103 {
104  ARegion *region = CTX_wm_region(C);
105  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
106  float fmval[2];
107  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
108 
109  return outliner_dropzone_find(space_outliner, fmval, true);
110 }
111 
112 static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode)
113 {
114  TreeElement *te = outliner_drop_find(C, event);
115  TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
116 
117  if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) {
118  return tselem->id;
119  }
120  return NULL;
121 }
122 
123 /* Find tree element to drop into, with additional before and after reorder support. */
125  const wmEvent *event,
126  TreeElementInsertType *r_insert_type)
127 {
128  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
129  ARegion *region = CTX_wm_region(C);
130  TreeElement *te_hovered;
131  float view_mval[2];
132 
133  /* Empty tree, e.g. while filtered. */
134  if (BLI_listbase_is_empty(&space_outliner->tree)) {
135  return NULL;
136  }
137 
139  &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
140  te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
141 
142  if (te_hovered) {
143  /* Mouse hovers an element (ignoring x-axis),
144  * now find out how to insert the dragged item exactly. */
145  const float margin = UI_UNIT_Y * (1.0f / 4);
146 
147  if (view_mval[1] < (te_hovered->ys + margin)) {
148  if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner) &&
149  !BLI_listbase_is_empty(&te_hovered->subtree)) {
150  /* inserting after a open item means we insert into it, but as first child */
151  if (BLI_listbase_is_empty(&te_hovered->subtree)) {
152  *r_insert_type = TE_INSERT_INTO;
153  return te_hovered;
154  }
155  *r_insert_type = TE_INSERT_BEFORE;
156  return te_hovered->subtree.first;
157  }
158  *r_insert_type = TE_INSERT_AFTER;
159  return te_hovered;
160  }
161  if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
162  *r_insert_type = TE_INSERT_BEFORE;
163  return te_hovered;
164  }
165  *r_insert_type = TE_INSERT_INTO;
166  return te_hovered;
167  }
168 
169  /* Mouse doesn't hover any item (ignoring x-axis),
170  * so it's either above list bounds or below. */
171  TreeElement *first = space_outliner->tree.first;
172  TreeElement *last = space_outliner->tree.last;
173 
174  if (view_mval[1] < last->ys) {
175  *r_insert_type = TE_INSERT_AFTER;
176  return last;
177  }
178  if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
179  *r_insert_type = TE_INSERT_BEFORE;
180  return first;
181  }
182  BLI_assert(0);
183  return NULL;
184 }
185 
186 typedef bool (*CheckTypeFn)(TreeElement *te);
187 
189  TreeElement *te)
190 {
191  while (te != NULL) {
192  if (check_type(te)) {
193  return te;
194  }
195  te = te->parent;
196  }
197  return NULL;
198 }
199 
201 {
203 }
204 
206 {
207  TreeStoreElem *tselem = TREESTORE(te);
208  return (tselem->type == TSE_SOME_ID) && te->idcode == ID_OB;
209 }
210 
212 {
213  TreeStoreElem *tselem = TREESTORE(te);
214  return tselem->type == TSE_POSE_CHANNEL;
215 }
216 
218  const wmEvent *event,
219  TreeElementInsertType *r_insert_type)
220 {
221  TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
222  if (!te) {
223  return NULL;
224  }
225 
227  te);
228  if (!collection_te) {
229  return NULL;
230  }
231  Collection *collection = outliner_collection_from_tree_element(collection_te);
232 
233  if (collection_te != te) {
234  *r_insert_type = TE_INSERT_INTO;
235  }
236 
237  /* We can't insert before/after master collection. */
238  if (collection->flag & COLLECTION_IS_MASTER) {
239  *r_insert_type = TE_INSERT_INTO;
240  }
241 
242  return collection_te;
243 }
244 
246  TreeElement *drop_te,
247  TreeElementInsertType insert_type,
248  ListBase *listbase)
249 {
250  /* Find the element to insert after. NULL is the start of the list. */
251  if (drag_te->index < drop_te->index) {
252  if (insert_type == TE_INSERT_BEFORE) {
253  drop_te = drop_te->prev;
254  }
255  }
256  else {
257  if (insert_type == TE_INSERT_AFTER) {
258  drop_te = drop_te->next;
259  }
260  }
261 
262  if (drop_te == NULL) {
263  return 0;
264  }
265 
266  return BLI_findindex(listbase, drop_te->directdata);
267 }
268 
269 /* ******************** Parent Drop Operator *********************** */
270 
271 static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
272 {
273  TreeStoreElem *tselem = TREESTORE(te);
274  if ((te->idcode != ID_OB) || (tselem->type != TSE_SOME_ID)) {
275  return false;
276  }
277 
278  Object *potential_parent = (Object *)tselem->id;
279 
280  if (potential_parent == potential_child) {
281  return false;
282  }
283  if (BKE_object_is_child_recursive(potential_child, potential_parent)) {
284  return false;
285  }
286  if (potential_parent == potential_child->parent) {
287  return false;
288  }
289 
290  /* check that parent/child are both in the same scene */
292 
293  /* currently outliner organized in a way that if there's no parent scene
294  * element for object it means that all displayed objects belong to
295  * active scene and parenting them is allowed (sergey) */
296  if (scene) {
297  LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
298  if (BKE_view_layer_base_find(view_layer, potential_child)) {
299  return true;
300  }
301  }
302  return false;
303  }
304  return true;
305 }
306 
308 {
309  switch (space_outliner->outlinevis) {
310  case SO_VIEW_LAYER:
311  return space_outliner->filter & SO_FILTER_NO_COLLECTION;
312  case SO_SCENES:
313  return true;
314  default:
315  return false;
316  }
317 }
318 
320  wmDrag *drag,
321  const wmEvent *event,
322  const char **UNUSED(r_tooltip))
323 {
324  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
325 
326  bool changed = outliner_flag_set(&space_outliner->tree, TSE_DRAG_ANY, false);
327  if (changed) {
329  }
330 
331  Object *potential_child = (Object *)WM_drag_get_local_ID(drag, ID_OB);
332  if (!potential_child) {
333  return false;
334  }
335 
336  if (!allow_parenting_without_modifier_key(space_outliner)) {
337  if (!event->shift) {
338  return false;
339  }
340  }
341 
342  TreeElement *te = outliner_drop_find(C, event);
343  if (!te) {
344  return false;
345  }
346 
347  if (parent_drop_allowed(te, potential_child)) {
348  TREESTORE(te)->flag |= TSE_DRAG_INTO;
350  return true;
351  }
352 
353  return false;
354 }
355 
357  ReportList *reports,
358  wmDragID *drag,
359  Object *parent,
360  short parent_type,
361  const bool keep_transform)
362 {
363  Main *bmain = CTX_data_main(C);
364  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
365 
366  TreeElement *te = outliner_find_id(space_outliner, &space_outliner->tree, &parent->id);
368 
369  if (scene == NULL) {
370  /* currently outliner organized in a way, that if there's no parent scene
371  * element for object it means that all displayed objects belong to
372  * active scene and parenting them is allowed (sergey)
373  */
374 
376  }
377 
378  bool parent_set = false;
379  bool linked_objects = false;
380 
381  for (wmDragID *drag_id = drag; drag_id; drag_id = drag_id->next) {
382  if (GS(drag_id->id->name) == ID_OB) {
383  Object *object = (Object *)drag_id->id;
384 
385  /* Do nothing to linked data */
386  if (ID_IS_LINKED(object)) {
387  linked_objects = true;
388  continue;
389  }
390 
392  reports, C, scene, object, parent, parent_type, false, keep_transform, NULL)) {
393  parent_set = true;
394  }
395  }
396  }
397 
398  if (linked_objects) {
399  BKE_report(reports, RPT_INFO, "Can't edit library linked object(s)");
400  }
401 
402  if (parent_set) {
406  }
407 }
408 
409 static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
410 {
411  TreeElement *te = outliner_drop_find(C, event);
412  TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
413 
414  if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) {
415  return OPERATOR_CANCELLED;
416  }
417 
418  Object *par = (Object *)tselem->id;
420 
421  if (ELEM(NULL, ob, par)) {
422  return OPERATOR_CANCELLED;
423  }
424  if (ob == par) {
425  return OPERATOR_CANCELLED;
426  }
427 
428  if (event->custom != EVT_DATA_DRAGDROP) {
429  return OPERATOR_CANCELLED;
430  }
431 
432  ListBase *lb = event->customdata;
433  wmDrag *drag = lb->first;
434 
435  parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
436 
437  return OPERATOR_FINISHED;
438 }
439 
441 {
442  /* identifiers */
443  ot->name = "Drop to Set Parent (hold Alt to keep transforms)";
444  ot->description = "Drag to parent in Outliner";
445  ot->idname = "OUTLINER_OT_parent_drop";
446 
447  /* api callbacks */
449 
451 
452  /* flags */
454 }
455 
456 /* ******************** Parent Clear Operator *********************** */
457 
459  wmDrag *drag,
460  const wmEvent *event,
461  const char **UNUSED(r_tooltip))
462 {
463  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
464 
465  if (!allow_parenting_without_modifier_key(space_outliner)) {
466  if (!event->shift) {
467  return false;
468  }
469  }
470 
471  Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
472  if (!ob) {
473  return false;
474  }
475  if (!ob->parent) {
476  return false;
477  }
478 
479  TreeElement *te = outliner_drop_find(C, event);
480  if (te) {
481  TreeStoreElem *tselem = TREESTORE(te);
482  ID *id = tselem->id;
483  if (!id) {
484  return true;
485  }
486 
487  switch (GS(id->name)) {
488  case ID_OB:
490  case ID_GR:
491  return event->shift || ELEM(tselem->type, TSE_LIBRARY_OVERRIDE_BASE);
492  default:
493  return true;
494  }
495  }
496  else {
497  return true;
498  }
499 }
500 
501 static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
502 {
503  Main *bmain = CTX_data_main(C);
504 
505  if (event->custom != EVT_DATA_DRAGDROP) {
506  return OPERATOR_CANCELLED;
507  }
508 
509  ListBase *lb = event->customdata;
510  wmDrag *drag = lb->first;
511 
512  LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
513  if (GS(drag_id->id->name) == ID_OB) {
514  Object *object = (Object *)drag_id->id;
515 
517  }
518  }
519 
523  return OPERATOR_FINISHED;
524 }
525 
527 {
528  /* identifiers */
529  ot->name = "Drop to Clear Parent (hold Alt to keep transforms)";
530  ot->description = "Drag to clear parent in Outliner";
531  ot->idname = "OUTLINER_OT_parent_clear";
532 
533  /* api callbacks */
535 
537 
538  /* flags */
540 }
541 
542 /* ******************** Scene Drop Operator *********************** */
543 
545  wmDrag *drag,
546  const wmEvent *event,
547  const char **UNUSED(r_tooltip))
548 {
549  /* Ensure item under cursor is valid drop target */
550  Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
551  return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL));
552 }
553 
554 static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
555 {
556  Main *bmain = CTX_data_main(C);
559 
560  if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
561  return OPERATOR_CANCELLED;
562  }
563 
564  if (BKE_scene_has_object(scene, ob)) {
565  return OPERATOR_CANCELLED;
566  }
567 
568  Collection *collection;
569  if (scene != CTX_data_scene(C)) {
570  /* when linking to an inactive scene link to the master collection */
571  collection = scene->master_collection;
572  }
573  else {
574  collection = CTX_data_collection(C);
575  }
576 
577  BKE_collection_object_add(bmain, collection, ob);
578 
579  LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
580  Base *base = BKE_view_layer_base_find(view_layer, ob);
581  if (base) {
583  }
584  }
585 
587 
590 
591  return OPERATOR_FINISHED;
592 }
593 
595 {
596  /* identifiers */
597  ot->name = "Drop Object to Scene";
598  ot->description = "Drag object to scene in Outliner";
599  ot->idname = "OUTLINER_OT_scene_drop";
600 
601  /* api callbacks */
603 
605 
606  /* flags */
608 }
609 
610 /* ******************** Material Drop Operator *********************** */
611 
613  wmDrag *drag,
614  const wmEvent *event,
615  const char **UNUSED(r_tooltip))
616 {
617  /* Ensure item under cursor is valid drop target */
619  return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL));
620 }
621 
622 static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
623 {
624  Main *bmain = CTX_data_main(C);
625  Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB);
627 
628  if (ELEM(NULL, ob, ma)) {
629  return OPERATOR_CANCELLED;
630  }
631 
632  /* only drop grease pencil material on grease pencil objects */
633  if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) {
634  return OPERATOR_CANCELLED;
635  }
636 
638 
642 
643  return OPERATOR_FINISHED;
644 }
645 
647 {
648  /* identifiers */
649  ot->name = "Drop Material on Object";
650  ot->description = "Drag material to object in Outliner";
651  ot->idname = "OUTLINER_OT_material_drop";
652 
653  /* api callbacks */
655 
657 
658  /* flags */
660 }
661 
662 /* ******************** Data Stack Drop Operator *********************** */
663 
664 /* A generic operator to allow drag and drop for modifiers, constraints,
665  * and shader effects which all share the same UI stack layout.
666  *
667  * The following operations are allowed:
668  * - Reordering within an object.
669  * - Copying a single modifier/constraint/effect to another object.
670  * - Copying (linking) an object's modifiers/constraints/effects to another. */
671 
672 typedef enum eDataStackDropAction {
677 
678 typedef struct StackDropData {
684 
689 
691  Object *ob,
692  bPoseChannel *pchan,
693  TreeElement *te,
694  TreeStoreElem *tselem,
695  void *directdata)
696 {
697  StackDropData *drop_data = MEM_callocN(sizeof(*drop_data), "datastack drop data");
698 
699  drop_data->ob_parent = ob;
700  drop_data->pchan_parent = pchan;
701  drop_data->drag_tselem = tselem;
702  drop_data->drag_directdata = directdata;
703  drop_data->drag_index = te->index;
704 
705  drag->poin = drop_data;
706  drag->flags |= WM_DRAG_FREE_DATA;
707 }
708 
709 static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData *drop_data)
710 {
711  if (!ELEM(drop_data->drag_tselem->type,
712  TSE_MODIFIER,
718  return false;
719  }
720 
721  TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
722  if (!te_target) {
723  return false;
724  }
725  TreeStoreElem *tselem_target = TREESTORE(te_target);
726 
727  if (drop_data->drag_tselem == tselem_target) {
728  return false;
729  }
730 
731  Object *ob = NULL;
733  te_target);
734  if (object_te) {
735  ob = (Object *)TREESTORE(object_te)->id;
736  }
737 
738  bPoseChannel *pchan = NULL;
740  if (pchan_te) {
741  pchan = (bPoseChannel *)pchan_te->directdata;
742  }
743  if (pchan) {
744  ob = NULL;
745  }
746 
747  if (ob && ID_IS_LINKED(&ob->id)) {
748  return false;
749  }
750 
751  /* Drag a base for linking. */
752  if (ELEM(drop_data->drag_tselem->type,
756  drop_data->insert_type = TE_INSERT_INTO;
757  drop_data->drop_action = DATA_STACK_DROP_LINK;
758 
759  if (pchan && pchan != drop_data->pchan_parent) {
760  drop_data->drop_te = pchan_te;
761  tselem_target = TREESTORE(pchan_te);
762  }
763  else if (ob && ob != drop_data->ob_parent) {
764  drop_data->drop_te = object_te;
765  tselem_target = TREESTORE(object_te);
766  }
767  else {
768  return false;
769  }
770  }
771  else if (ob || pchan) {
772  /* Drag a single item. */
773  if (pchan && pchan != drop_data->pchan_parent) {
774  drop_data->insert_type = TE_INSERT_INTO;
775  drop_data->drop_action = DATA_STACK_DROP_COPY;
776  drop_data->drop_te = pchan_te;
777  tselem_target = TREESTORE(pchan_te);
778  }
779  else if (ob && ob != drop_data->ob_parent) {
780  drop_data->insert_type = TE_INSERT_INTO;
781  drop_data->drop_action = DATA_STACK_DROP_COPY;
782  drop_data->drop_te = object_te;
783  tselem_target = TREESTORE(object_te);
784  }
785  else if (tselem_target->type == drop_data->drag_tselem->type) {
786  if (drop_data->insert_type == TE_INSERT_INTO) {
787  return false;
788  }
790  drop_data->drop_te = te_target;
791  }
792  else {
793  return false;
794  }
795  }
796  else {
797  return false;
798  }
799 
800  return true;
801 }
802 
803 /* Ensure that grease pencil and object data remain separate. */
805 {
806  TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
807  Object *ob_parent = drop_data->ob_parent;
808  Object *ob_dst = (Object *)tselem->id;
809 
810  /* Don't allow data to be moved between objects and bones. */
811  if (tselem->type == TSE_CONSTRAINT) {
812  }
813  else if ((drop_data->pchan_parent && tselem->type != TSE_POSE_CHANNEL) ||
814  (!drop_data->pchan_parent && tselem->type == TSE_POSE_CHANNEL)) {
815  return false;
816  }
817 
818  switch (drop_data->drag_tselem->type) {
819  case TSE_MODIFIER_BASE:
820  case TSE_MODIFIER:
821  if (ob_parent->type == OB_GPENCIL) {
822  return ob_dst->type == OB_GPENCIL;
823  }
824  else if (ob_parent->type != OB_GPENCIL) {
825  return ob_dst->type != OB_GPENCIL;
826  }
827  break;
828  case TSE_CONSTRAINT_BASE:
829  case TSE_CONSTRAINT:
830 
831  break;
833  case TSE_GPENCIL_EFFECT:
834  return ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL;
835  break;
836  }
837 
838  return true;
839 }
840 
842  wmDrag *drag,
843  const wmEvent *event,
844  const char **r_tooltip)
845 {
846  if (drag->type != WM_DRAG_DATASTACK) {
847  return false;
848  }
849 
850  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
851  ARegion *region = CTX_wm_region(C);
852  bool changed = outliner_flag_set(
853  &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
854 
855  StackDropData *drop_data = drag->poin;
856  if (!drop_data) {
857  return false;
858  }
859 
860  if (!datastack_drop_init(C, event, drop_data)) {
861  return false;
862  }
863 
864  if (!datastack_drop_are_types_valid(drop_data)) {
865  return false;
866  }
867 
868  TreeStoreElem *tselem_target = TREESTORE(drop_data->drop_te);
869  switch (drop_data->insert_type) {
870  case TE_INSERT_BEFORE:
871  tselem_target->flag |= TSE_DRAG_BEFORE;
872  break;
873  case TE_INSERT_AFTER:
874  tselem_target->flag |= TSE_DRAG_AFTER;
875  break;
876  case TE_INSERT_INTO:
877  tselem_target->flag |= TSE_DRAG_INTO;
878  break;
879  }
880 
881  switch (drop_data->drop_action) {
883  *r_tooltip = TIP_("Reorder");
884  break;
886  if (drop_data->pchan_parent) {
887  *r_tooltip = TIP_("Copy to bone");
888  }
889  else {
890  *r_tooltip = TIP_("Copy to object");
891  }
892  break;
894  if (drop_data->pchan_parent) {
895  *r_tooltip = TIP_("Link all to bone");
896  }
897  else {
898  *r_tooltip = TIP_("Link all to object");
899  }
900  break;
901  }
902 
903  if (changed) {
905  }
906 
907  return true;
908 }
909 
910 static void datastack_drop_link(bContext *C, StackDropData *drop_data)
911 {
912  Main *bmain = CTX_data_main(C);
913  TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
914  Object *ob_dst = (Object *)tselem->id;
915 
916  switch (drop_data->drag_tselem->type) {
917  case TSE_MODIFIER_BASE:
918  ED_object_modifier_link(C, ob_dst, drop_data->ob_parent);
919  break;
920  case TSE_CONSTRAINT_BASE: {
921  ListBase *src;
922 
923  if (drop_data->pchan_parent) {
924  src = &drop_data->pchan_parent->constraints;
925  }
926  else {
927  src = &drop_data->ob_parent->constraints;
928  }
929 
930  ListBase *dst;
931  if (tselem->type == TSE_POSE_CHANNEL) {
932  bPoseChannel *pchan = (bPoseChannel *)drop_data->drop_te->directdata;
933  dst = &pchan->constraints;
934  }
935  else {
936  dst = &ob_dst->constraints;
937  }
938 
939  ED_object_constraint_link(bmain, ob_dst, dst, src);
940  break;
941  }
943  if (ob_dst->type != OB_GPENCIL) {
944  return;
945  }
946 
947  ED_object_shaderfx_link(ob_dst, drop_data->ob_parent);
948  break;
949  }
950 }
951 
952 static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
953 {
954  Main *bmain = CTX_data_main(C);
955 
956  TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
957  Object *ob_dst = (Object *)tselem->id;
958 
959  switch (drop_data->drag_tselem->type) {
960  case TSE_MODIFIER:
961  if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
963  }
964  else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
966  C, ob_dst, drop_data->ob_parent, drop_data->drag_directdata);
967  }
968  break;
969  case TSE_CONSTRAINT:
970  if (tselem->type == TSE_POSE_CHANNEL) {
972  bmain, ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata);
973  }
974  else {
975  ED_object_constraint_copy_for_object(bmain, ob_dst, drop_data->drag_directdata);
976  }
977  break;
978  case TSE_GPENCIL_EFFECT: {
979  if (ob_dst->type != OB_GPENCIL) {
980  return;
981  }
982 
983  ED_object_shaderfx_copy(ob_dst, drop_data->drag_directdata);
984  break;
985  }
986  }
987 }
988 
989 static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropData *drop_data)
990 {
991  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
992 
993  TreeElement *drag_te = outliner_find_tree_element(&space_outliner->tree, drop_data->drag_tselem);
994  if (!drag_te) {
995  return;
996  }
997 
998  TreeElement *drop_te = drop_data->drop_te;
999  TreeElementInsertType insert_type = drop_data->insert_type;
1000 
1001  Object *ob = drop_data->ob_parent;
1002 
1003  int index = 0;
1004  switch (drop_data->drag_tselem->type) {
1005  case TSE_MODIFIER:
1006  if (ob->type == OB_GPENCIL) {
1007  index = outliner_get_insert_index(
1008  drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
1009  ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
1010  }
1011  else if (ob->type != OB_GPENCIL) {
1012  index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
1013  ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
1014  }
1015  break;
1016  case TSE_CONSTRAINT:
1017  if (drop_data->pchan_parent) {
1018  index = outliner_get_insert_index(
1019  drag_te, drop_te, insert_type, &drop_data->pchan_parent->constraints);
1020  }
1021  else {
1022  index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
1023  }
1024  ED_object_constraint_move_to_index(ob, drop_data->drag_directdata, index);
1025 
1026  break;
1027  case TSE_GPENCIL_EFFECT:
1028  index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
1029  ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index);
1030  }
1031 }
1032 
1033 static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1034 {
1035  if (event->custom != EVT_DATA_DRAGDROP) {
1036  return OPERATOR_CANCELLED;
1037  }
1038 
1039  ListBase *lb = event->customdata;
1040  wmDrag *drag = lb->first;
1041  StackDropData *drop_data = drag->poin;
1042 
1043  switch (drop_data->drop_action) {
1044  case DATA_STACK_DROP_LINK:
1045  datastack_drop_link(C, drop_data);
1046  break;
1047  case DATA_STACK_DROP_COPY:
1048  datastack_drop_copy(C, drop_data);
1049  break;
1051  datastack_drop_reorder(C, op->reports, drop_data);
1052  break;
1053  }
1054 
1055  return OPERATOR_FINISHED;
1056 }
1057 
1059 {
1060  /* identifiers */
1061  ot->name = "Data Stack Drop";
1062  ot->description = "Copy or reorder modifiers, constraints, and effects";
1063  ot->idname = "OUTLINER_OT_datastack_drop";
1064 
1065  /* api callbacks */
1067 
1069 
1070  /* flags */
1072 }
1073 
1074 /* ******************** Collection Drop Operator *********************** */
1075 
1076 typedef struct CollectionDrop {
1079 
1083 
1085 {
1086  /* Can't change linked parent collections. */
1087  if (!id || ID_IS_LINKED(id)) {
1088  return NULL;
1089  }
1090 
1091  /* Also support dropping into/from scene collection. */
1092  if (GS(id->name) == ID_SCE) {
1093  return ((Scene *)id)->master_collection;
1094  }
1095  if (GS(id->name) == ID_GR) {
1096  return (Collection *)id;
1097  }
1098 
1099  return NULL;
1100 }
1101 
1103  wmDrag *drag,
1104  const wmEvent *event,
1106 {
1107  /* Get collection to drop into. */
1108  TreeElementInsertType insert_type;
1109  TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
1110  if (!te) {
1111  return false;
1112  }
1113 
1115  if (ID_IS_LINKED(to_collection)) {
1116  return false;
1117  }
1118  /* Currently this should not be allowed (might be supported in the future though...). */
1119  if (ID_IS_OVERRIDE_LIBRARY(to_collection)) {
1120  return false;
1121  }
1122 
1123  /* Get drag datablocks. */
1124  if (drag->type != WM_DRAG_ID) {
1125  return false;
1126  }
1127 
1128  wmDragID *drag_id = drag->ids.first;
1129  if (drag_id == NULL) {
1130  return false;
1131  }
1132 
1133  ID *id = drag_id->id;
1134  if (!(id && ELEM(GS(id->name), ID_GR, ID_OB))) {
1135  return false;
1136  }
1137 
1138  /* Get collection to drag out of. */
1139  ID *parent = drag_id->from_parent;
1140  Collection *from_collection = collection_parent_from_ID(parent);
1141  if (event->ctrl) {
1142  from_collection = NULL;
1143  }
1144 
1145  /* Get collections. */
1146  if (GS(id->name) == ID_GR) {
1147  if (id == &to_collection->id) {
1148  return false;
1149  }
1150  }
1151  else {
1152  insert_type = TE_INSERT_INTO;
1153  }
1154 
1155  data->from = from_collection;
1156  data->to = to_collection;
1157  data->te = te;
1158  data->insert_type = insert_type;
1159 
1160  return true;
1161 }
1162 
1164  wmDrag *drag,
1165  const wmEvent *event,
1166  const char **r_tooltip)
1167 {
1168  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1169  ARegion *region = CTX_wm_region(C);
1170  bool changed = outliner_flag_set(
1171  &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
1172 
1174  if (!event->shift && collection_drop_init(C, drag, event, &data)) {
1175  TreeElement *te = data.te;
1176  TreeStoreElem *tselem = TREESTORE(te);
1177  if (!data.from || event->ctrl) {
1178  tselem->flag |= TSE_DRAG_INTO;
1179  changed = true;
1180  *r_tooltip = TIP_("Link inside Collection");
1181  }
1182  else {
1183  switch (data.insert_type) {
1184  case TE_INSERT_BEFORE:
1185  tselem->flag |= TSE_DRAG_BEFORE;
1186  changed = true;
1187  if (te->prev && outliner_is_collection_tree_element(te->prev)) {
1188  *r_tooltip = TIP_("Move between collections");
1189  }
1190  else {
1191  *r_tooltip = TIP_("Move before collection");
1192  }
1193  break;
1194  case TE_INSERT_AFTER:
1195  tselem->flag |= TSE_DRAG_AFTER;
1196  changed = true;
1197  if (te->next && outliner_is_collection_tree_element(te->next)) {
1198  *r_tooltip = TIP_("Move between collections");
1199  }
1200  else {
1201  *r_tooltip = TIP_("Move after collection");
1202  }
1203  break;
1204  case TE_INSERT_INTO: {
1205  tselem->flag |= TSE_DRAG_INTO;
1206  changed = true;
1207 
1208  /* Check the type of the drag IDs to avoid the incorrect "Shift to parent"
1209  * for collections. Checking the type of the first ID works fine here since
1210  * all drag IDs are the same type. */
1211  wmDragID *drag_id = (wmDragID *)drag->ids.first;
1212  const bool is_object = (GS(drag_id->id->name) == ID_OB);
1213  if (is_object) {
1214  *r_tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)");
1215  }
1216  else {
1217  *r_tooltip = TIP_("Move inside collection (Ctrl to link)");
1218  }
1219  break;
1220  }
1221  }
1222  }
1223  if (changed) {
1225  }
1226  return true;
1227  }
1228  if (changed) {
1230  }
1231  return false;
1232 }
1233 
1234 static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
1235 {
1236  Main *bmain = CTX_data_main(C);
1238 
1239  if (event->custom != EVT_DATA_DRAGDROP) {
1240  return OPERATOR_CANCELLED;
1241  }
1242 
1243  ListBase *lb = event->customdata;
1244  wmDrag *drag = lb->first;
1245 
1247  if (!collection_drop_init(C, drag, event, &data)) {
1248  return OPERATOR_CANCELLED;
1249  }
1250 
1251  /* Before/after insert handling. */
1252  Collection *relative = NULL;
1253  bool relative_after = false;
1254 
1255  if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
1256  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1257 
1258  relative = data.to;
1259  relative_after = (data.insert_type == TE_INSERT_AFTER);
1260 
1261  TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, NULL, data.te);
1262  data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL;
1263  }
1264 
1265  if (!data.to) {
1266  return OPERATOR_CANCELLED;
1267  }
1268 
1269  if (BKE_collection_is_empty(data.to)) {
1270  TREESTORE(data.te)->flag &= ~TSE_CLOSED;
1271  }
1272 
1273  LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
1274  /* Ctrl enables linking, so we don't need a from collection then. */
1275  Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
1276 
1277  if (GS(drag_id->id->name) == ID_OB) {
1278  /* Move/link object into collection. */
1279  Object *object = (Object *)drag_id->id;
1280 
1281  if (from) {
1282  BKE_collection_object_move(bmain, scene, data.to, from, object);
1283  }
1284  else {
1285  BKE_collection_object_add(bmain, data.to, object);
1286  }
1287  }
1288  else if (GS(drag_id->id->name) == ID_GR) {
1289  /* Move/link collection into collection. */
1290  Collection *collection = (Collection *)drag_id->id;
1291 
1292  if (collection != from) {
1293  BKE_collection_move(bmain, data.to, from, relative, relative_after, collection);
1294  }
1295  }
1296 
1297  if (from) {
1299  }
1300  }
1301 
1302  /* Update dependency graph. */
1304  DEG_relations_tag_update(bmain);
1306 
1307  return OPERATOR_FINISHED;
1308 }
1309 
1311 {
1312  /* identifiers */
1313  ot->name = "Move to Collection";
1314  ot->description = "Drag to move to collection in Outliner";
1315  ot->idname = "OUTLINER_OT_collection_drop";
1316 
1317  /* api callbacks */
1320 
1321  /* flags */
1323 }
1324 
1325 /* ********************* Outliner Drag Operator ******************** */
1326 
1327 #define OUTLINER_DRAG_SCOLL_OUTSIDE_PAD 7 /* In UI units */
1328 
1330  ARegion *region,
1331  const wmEvent *event)
1332 {
1333  /* note: using EVT_TWEAK_ events to trigger dragging is fine,
1334  * it sends coordinates from where dragging was started */
1335  const float my = UI_view2d_region_to_view_y(&region->v2d, event->mval[1]);
1336  return outliner_find_item_at_y(space_outliner, &space_outliner->tree, my);
1337 }
1338 
1340  wmOperator *UNUSED(op),
1341  const wmEvent *event)
1342 {
1343  ARegion *region = CTX_wm_region(C);
1344  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1345  TreeElement *te = outliner_item_drag_element_find(space_outliner, region, event);
1346 
1347  if (!te) {
1349  }
1350 
1351  TreeStoreElem *tselem = TREESTORE(te);
1353  if (!data.drag_id) {
1355  }
1356 
1357  float view_mval[2];
1359  &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
1360  if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
1362  }
1363  if (outliner_is_co_within_mode_column(space_outliner, view_mval)) {
1365  }
1366 
1367  /* Scroll the view when dragging near edges, but not
1368  * when the drag goes too far outside the region. */
1369  {
1370  wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true);
1371  PointerRNA op_ptr;
1373  RNA_int_set(&op_ptr, "outside_padding", OUTLINER_DRAG_SCOLL_OUTSIDE_PAD);
1375  WM_operator_properties_free(&op_ptr);
1376  }
1377 
1378  const bool use_datastack_drag = ELEM(tselem->type,
1379  TSE_MODIFIER,
1385 
1386  const int wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID;
1387  wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, NULL, 0.0, WM_DRAG_NOP);
1388 
1389  if (use_datastack_drag) {
1390  TreeElement *te_bone = NULL;
1391  bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone);
1392  datastack_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata);
1393  }
1394  else if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
1395  /* For collections and objects we cheat and drag all selected. */
1396 
1397  /* Only drag element under mouse if it was not selected before. */
1398  if ((tselem->flag & TSE_SELECTED) == 0) {
1399  outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
1400  tselem->flag |= TSE_SELECTED;
1401  }
1402 
1403  /* Gather all selected elements. */
1404  struct IDsSelectedData selected = {
1405  .selected_array = {NULL, NULL},
1406  };
1407 
1408  if (GS(data.drag_id->name) == ID_OB) {
1409  outliner_tree_traverse(space_outliner,
1410  &space_outliner->tree,
1411  0,
1412  TSE_SELECTED,
1414  &selected);
1415  }
1416  else {
1417  outliner_tree_traverse(space_outliner,
1418  &space_outliner->tree,
1419  0,
1420  TSE_SELECTED,
1422  &selected);
1423  }
1424 
1425  LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) {
1426  TreeElement *te_selected = (TreeElement *)link->data;
1427  ID *id;
1428 
1429  if (GS(data.drag_id->name) == ID_OB) {
1430  id = TREESTORE(te_selected)->id;
1431  }
1432  else {
1433  /* Keep collection hierarchies intact when dragging. */
1434  bool parent_selected = false;
1435  for (TreeElement *te_parent = te_selected->parent; te_parent;
1436  te_parent = te_parent->parent) {
1437  if (outliner_is_collection_tree_element(te_parent)) {
1438  if (TREESTORE(te_parent)->flag & TSE_SELECTED) {
1439  parent_selected = true;
1440  break;
1441  }
1442  }
1443  }
1444 
1445  if (parent_selected) {
1446  continue;
1447  }
1448 
1449  id = &outliner_collection_from_tree_element(te_selected)->id;
1450  }
1451 
1452  /* Find parent collection. */
1453  Collection *parent = NULL;
1454 
1455  if (te_selected->parent) {
1456  for (TreeElement *te_parent = te_selected->parent; te_parent;
1457  te_parent = te_parent->parent) {
1458  if (outliner_is_collection_tree_element(te_parent)) {
1459  parent = outliner_collection_from_tree_element(te_parent);
1460  break;
1461  }
1462  }
1463  }
1464  else {
1466  parent = scene->master_collection;
1467  }
1468 
1469  WM_drag_add_local_ID(drag, id, &parent->id);
1470  }
1471 
1472  BLI_freelistN(&selected.selected_array);
1473  }
1474  else {
1475  /* Add single ID. */
1476  WM_drag_add_local_ID(drag, data.drag_id, data.drag_parent);
1477  }
1478 
1479  ED_outliner_select_sync_from_outliner(C, space_outliner);
1480 
1482 }
1483 
1484 /* Outliner drag and drop. This operator mostly exists to support dragging
1485  * from outliner text instead of only from the icon, and also to show a
1486  * hint in the status-bar key-map. */
1487 
1489 {
1490  ot->name = "Drag and Drop";
1491  ot->idname = "OUTLINER_OT_item_drag_drop";
1492  ot->description = "Drag and drop element to another place";
1493 
1496 }
1497 
1498 #undef OUTLINER_DRAG_SCOLL_OUTSIDE_PAD
1499 
1500 /* *************************** Drop Boxes ************************** */
1501 
1502 /* region dropbox definition */
1504 {
1506 
1507  WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL, NULL);
1508  WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL, NULL);
1509  WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL, NULL);
1510  WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL, NULL);
1511  WM_dropbox_add(lb, "OUTLINER_OT_datastack_drop", datastack_drop_poll, NULL, NULL);
1512  WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL, NULL);
1513 }
bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob)
Definition: collection.c:1134
bool BKE_collection_is_empty(const struct Collection *collection)
bool BKE_collection_move(struct Main *bmain, struct Collection *to_parent, struct Collection *from_parent, struct Collection *relative, bool relative_after, struct Collection *collection)
Definition: collection.c:1918
void BKE_collection_object_move(struct Main *bmain, struct Scene *scene, struct Collection *collection_dst, struct Collection *collection_src, struct Object *ob)
Definition: collection.c:1367
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
Definition: context.c:836
struct Collection * CTX_data_collection(const bContext *C)
Definition: context.c:1092
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
bool BKE_scene_has_object(struct Scene *scene, struct Object *ob)
Definition: layer.c:1527
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:394
General operations, lookup, etc. for materials.
@ BKE_MAT_ASSIGN_USERPREF
Definition: BKE_material.h:71
void BKE_object_material_assign(struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type)
Definition: material.c:850
General operations, lookup, etc. for blender objects.
bool BKE_object_is_child_recursive(const struct Object *ob_parent, const struct Object *ob_child)
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define UNUSED(x)
#define ELEM(...)
#define TIP_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:445
@ ID_SCE
Definition: DNA_ID_enums.h:57
@ ID_MA
Definition: DNA_ID_enums.h:63
@ ID_GR
Definition: DNA_ID_enums.h:77
@ ID_OB
Definition: DNA_ID_enums.h:59
Object groups, one object can be in many groups at once.
@ COLLECTION_IS_MASTER
Object is a sort of wrapper for general info.
@ OB_GPENCIL
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_MODIFIER_BASE
@ TSE_GPENCIL_EFFECT
@ TSE_LIBRARY_OVERRIDE_BASE
@ TSE_CONSTRAINT
@ TSE_GPENCIL_EFFECT_BASE
@ TSE_SOME_ID
@ TSE_MODIFIER
@ TSE_DRAG_AFTER
@ TSE_HIGHLIGHTED_ANY
@ TSE_SELECTED
@ TSE_DRAG_INTO
@ TSE_CLOSED
@ TSE_DRAG_BEFORE
@ TSE_DRAG_ANY
@ RGN_TYPE_WINDOW
@ SPACE_OUTLINER
@ SO_FILTER_NO_COLLECTION
@ SO_VIEW_LAYER
@ SO_SCENES
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
bool ED_object_parent_set(struct ReportList *reports, const struct bContext *C, struct Scene *scene, struct Object *const ob, struct Object *const par, int partype, const bool xmirror, const bool keep_transform, const int vert_par[3])
void ED_object_modifier_link(struct bContext *C, struct Object *ob_dst, struct Object *ob_src)
@ CLEAR_PARENT_ALL
Definition: ED_object.h:152
@ CLEAR_PARENT_KEEP_TRANSFORM
Definition: ED_object.h:153
void ED_object_shaderfx_link(struct Object *dst, struct Object *src)
bool ED_object_gpencil_modifier_move_to_index(struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md, const int index)
void ED_object_parent_clear(struct Object *ob, const int type)
@ PAR_OBJECT
Definition: ED_object.h:130
void ED_object_modifier_copy_to_object(struct bContext *C, struct Object *ob_dst, struct Object *ob_src, struct ModifierData *md)
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:98
void ED_object_constraint_copy_for_pose(struct Main *bmain, struct Object *ob_dst, struct bPoseChannel *pchan, struct bConstraint *con)
void ED_object_shaderfx_copy(struct Object *dst, struct ShaderFxData *fx)
bool ED_object_shaderfx_move_to_index(struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx, const int index)
void ED_object_constraint_link(struct Main *bmain, struct Object *ob_dst, struct ListBase *dst, struct ListBase *src)
bool ED_object_modifier_move_to_index(struct ReportList *reports, struct Object *ob, struct ModifierData *md, const int index)
@ BA_SELECT
Definition: ED_object.h:147
bool ED_object_constraint_move_to_index(struct Object *ob, struct bConstraint *con, const int index)
void ED_object_gpencil_modifier_copy_to_object(struct Object *ob_dst, struct GpencilModifierData *md)
void ED_object_constraint_copy_for_object(struct Main *bmain, struct Object *ob_dst, struct bConstraint *con)
void ED_outliner_select_sync_from_outliner(struct bContext *C, struct SpaceOutliner *space_outliner)
void ED_region_tag_redraw_no_rebuild(struct ARegion *region)
Definition: area.c:686
bool ED_operator_outliner_active(struct bContext *C)
Definition: screen_ops.c:259
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
#define UI_UNIT_Y
#define UI_UNIT_X
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
float UI_view2d_region_to_view_y(const struct View2D *v2d, float y)
Definition: view2d.c:1664
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:197
@ WM_DRAG_NOP
Definition: WM_types.h:883
@ WM_DRAG_FREE_DATA
Definition: WM_types.h:884
#define ND_OB_SELECT
Definition: WM_types.h:342
#define NC_SCENE
Definition: WM_types.h:279
#define ND_PARENT
Definition: WM_types.h:368
#define NC_MATERIAL
Definition: WM_types.h:281
#define ND_TRANSFORM
Definition: WM_types.h:357
#define ND_LAYER
Definition: WM_types.h:350
#define ND_OB_SHADING
Definition: WM_types.h:358
#define ND_SPACE_VIEW3D
Definition: WM_types.h:423
#define WM_DRAG_ID
Definition: WM_types.h:873
#define NC_OBJECT
Definition: WM_types.h:280
#define ND_SHADING_LINKS
Definition: WM_types.h:379
#define WM_DRAG_DATASTACK
Definition: WM_types.h:880
#define NC_SPACE
Definition: WM_types.h:293
StackEntry * from
Scene scene
#define GS(x)
Definition: iris.c:241
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
Collection * outliner_collection_from_tree_element(const TreeElement *te)
TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
bool outliner_is_collection_tree_element(const TreeElement *te)
static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(r_tooltip))
static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event, CollectionDrop *data)
static bool allow_parenting_without_modifier_key(SpaceOutliner *space_outliner)
static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static TreeElement * outliner_data_from_tree_element_and_parents(CheckTypeFn check_type, TreeElement *te)
static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(r_tooltip))
void OUTLINER_OT_material_drop(wmOperatorType *ot)
void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
static bool is_pchan_element(TreeElement *te)
bool(* CheckTypeFn)(TreeElement *te)
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static bool is_collection_element(TreeElement *te)
static ID * outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode)
static int outliner_get_insert_index(TreeElement *drag_te, TreeElement *drop_te, TreeElementInsertType insert_type, ListBase *listbase)
static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **r_tooltip)
static TreeElement * outliner_dropzone_find(const SpaceOutliner *space_outliner, const float fmval[2], const bool children)
static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static TreeElement * outliner_item_drag_element_find(SpaceOutliner *space_outliner, ARegion *region, const wmEvent *event)
static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static TreeElement * outliner_drop_find(bContext *C, const wmEvent *event)
static bool is_object_element(TreeElement *te)
static void datastack_drop_link(bContext *C, StackDropData *drop_data)
static TreeElement * outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children)
void OUTLINER_OT_parent_drop(wmOperatorType *ot)
void outliner_dropboxes(void)
static TreeElement * outliner_drop_insert_collection_find(bContext *C, const wmEvent *event, TreeElementInsertType *r_insert_type)
static Collection * collection_parent_from_ID(ID *id)
void OUTLINER_OT_collection_drop(wmOperatorType *ot)
static bool datastack_drop_are_types_valid(StackDropData *drop_data)
static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropData *drop_data)
static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **r_tooltip)
static void datastack_drop_data_init(wmDrag *drag, Object *ob, bPoseChannel *pchan, TreeElement *te, TreeStoreElem *tselem, void *directdata)
static TreeElement * outliner_drop_insert_find(bContext *C, const wmEvent *event, TreeElementInsertType *r_insert_type)
eDataStackDropAction
@ DATA_STACK_DROP_LINK
@ DATA_STACK_DROP_COPY
@ DATA_STACK_DROP_REORDER
void OUTLINER_OT_scene_drop(wmOperatorType *ot)
struct StackDropData StackDropData
struct CollectionDrop CollectionDrop
static void parent_drop_set_parents(bContext *C, ReportList *reports, wmDragID *drag, Object *parent, short parent_type, const bool keep_transform)
void OUTLINER_OT_datastack_drop(wmOperatorType *ot)
void OUTLINER_OT_parent_clear(wmOperatorType *ot)
#define OUTLINER_DRAG_SCOLL_OUTSIDE_PAD
static bool parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(r_tooltip))
static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(r_tooltip))
static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData *drop_data)
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
bool outliner_flag_set(ListBase *lb, short flag, short set)
TreeElementInsertType
@ TE_INSERT_AFTER
@ TE_INSERT_BEFORE
@ TE_INSERT_INTO
bool outliner_tree_traverse(const SpaceOutliner *space_outliner, ListBase *tree, int filter_te_flag, int filter_tselem_flag, TreeTraversalFunc func, void *customdata)
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
TreeElement * outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
#define TREESTORE(a)
TreeElement * outliner_find_item_at_y(const SpaceOutliner *space_outliner, const ListBase *tree, float view_co_y)
struct bPoseChannel * outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te)
TreeElement * outliner_find_id(struct SpaceOutliner *space_outliner, ListBase *lb, const struct ID *id)
TreeElement * outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te)
struct ID * outliner_search_back(TreeElement *te, short idcode)
#define TSELEM_OPEN(telm, sv)
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
TreeElement * te
TreeElementInsertType insert_type
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
struct ListBase selected_array
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct MaterialGPencilStyle * gp_style
ListBase constraints
ListBase modifiers
ListBase greasepencil_modifiers
ListBase shader_fx
struct Object * parent
struct Collection * master_collection
ListBase view_layers
TreeElement * drop_te
eDataStackDropAction drop_action
TreeStoreElem * drag_tselem
TreeElementInsertType insert_type
bPoseChannel * pchan_parent
struct TreeElement * parent
ListBase subtree
void * directdata
struct TreeElement * prev
struct TreeElement * next
ListBase constraints
struct ID * id
Definition: WM_types.h:891
struct ID * from_parent
Definition: WM_types.h:892
struct wmDragID * next
Definition: WM_types.h:890
unsigned int flags
Definition: WM_types.h:919
void * poin
Definition: WM_types.h:908
ListBase ids
Definition: WM_types.h:922
int type
Definition: WM_types.h:907
short custom
Definition: WM_types.h:627
short shift
Definition: WM_types.h:618
short ctrl
Definition: WM_types.h:618
int mval[2]
Definition: WM_types.h:583
short alt
Definition: WM_types.h:618
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
const char * description
Definition: WM_types.h:726
struct ReportList * reports
wmDropBox * WM_dropbox_add(ListBase *lb, const char *idname, bool(*poll)(bContext *, wmDrag *, const wmEvent *, const char **), void(*copy)(wmDrag *, wmDropBox *), void(*cancel)(struct Main *, wmDrag *, wmDropBox *))
Definition: wm_dragdrop.c:96
ID * WM_drag_get_local_ID(const wmDrag *drag, short idcode)
Definition: wm_dragdrop.c:335
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
Definition: wm_dragdrop.c:77
ID * WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode)
Definition: wm_dragdrop.c:350
wmDrag * WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
Definition: wm_dragdrop.c:140
void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent)
Definition: wm_dragdrop.c:312
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
@ EVT_DATA_DRAGDROP
wmOperatorType * ot
Definition: wm_files.c:3156
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:584
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:711