Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_outliner / outliner_collections.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation, Dalai Felinto
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/space_outliner/outliner_collections.c
24  *  \ingroup spoutliner
25  */
26
27 #include "BKE_context.h"
28 #include "BKE_collection.h"
29 #include "BKE_layer.h"
30 #include "BKE_main.h"
31 #include "BKE_report.h"
32
33 #include "DEG_depsgraph.h"
34 #include "DEG_depsgraph_build.h"
35
36 #include "BLI_listbase.h"
37
38 #include "ED_screen.h"
39
40 #include "WM_api.h"
41 #include "WM_types.h"
42
43 #include "RNA_access.h"
44 #include "RNA_define.h"
45 #include "RNA_enum_types.h"
46
47 #include "UI_resources.h"
48
49 #include "outliner_intern.h" /* own include */
50
51 /* -------------------------------------------------------------------- */
52
53 static LayerCollection *outliner_collection_active(bContext *C)
54 {
55         TODO_LAYER_OPERATORS;
56         /* consider that we may have overrides or objects active
57          * leading to no active collections */
58         return CTX_data_layer_collection(C);
59 }
60
61 SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te)
62 {
63         TreeStoreElem *tselem = TREESTORE(te);
64
65         if (tselem->type == TSE_SCENE_COLLECTION) {
66                 return te->directdata;
67         }
68         else if (tselem->type == TSE_LAYER_COLLECTION) {
69                 LayerCollection *lc = te->directdata;
70                 return lc->scene_collection;
71         }
72
73         return NULL;
74 }
75
76 #if 0
77 static CollectionOverride *outliner_override_active(bContext *UNUSED(C))
78 {
79         TODO_LAYER_OPERATORS;
80         TODO_LAYER_OVERRIDE;
81         return NULL;
82 }
83 #endif
84
85 /* -------------------------------------------------------------------- */
86 /* collection manager operators */
87
88 /**
89  * Recursively get the collection for a given index
90  */
91 static SceneCollection *scene_collection_from_index(ListBase *lb, const int number, int *i)
92 {
93         for (SceneCollection *sc = lb->first; sc; sc = sc->next) {
94                 if (*i == number) {
95                         return sc;
96                 }
97
98                 (*i)++;
99
100                 SceneCollection *sc_nested = scene_collection_from_index(&sc->scene_collections, number, i);
101                 if (sc_nested) {
102                         return sc_nested;
103                 }
104         }
105         return NULL;
106 }
107
108 static int collection_link_exec(bContext *C, wmOperator *op)
109 {
110         Scene *scene = CTX_data_scene(C);
111         SceneLayer *sl = CTX_data_scene_layer(C);
112         SceneCollection *sc_master = BKE_collection_master(scene);
113         SceneCollection *sc;
114
115         int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection");
116         if (scene_collection_index == 0) {
117                 sc = sc_master;
118         }
119         else {
120                 int index = 1;
121                 sc = scene_collection_from_index(&sc_master->scene_collections, scene_collection_index, &index);
122                 BLI_assert(sc);
123         }
124
125         BKE_collection_link(sl, sc);
126
127         DEG_relations_tag_update(CTX_data_main(C));
128
129         /* TODO(sergey): Use proper flag for tagging here. */
130         DEG_id_tag_update(&scene->id, 0);
131
132         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
133         return OPERATOR_FINISHED;
134 }
135
136 static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
137 {
138         if (BKE_collection_master(CTX_data_scene(C))->scene_collections.first == NULL) {
139                 RNA_enum_set(op->ptr, "scene_collection", 0);
140                 return collection_link_exec(C, op);
141         }
142         else {
143                 return WM_enum_search_invoke(C, op, event);
144         }
145 }
146
147 static void collection_scene_collection_itemf_recursive(
148         EnumPropertyItem *tmp, EnumPropertyItem **item, int *totitem, int *value, SceneCollection *sc)
149 {
150         tmp->value = *value;
151         tmp->icon = ICON_COLLAPSEMENU;
152         tmp->identifier = sc->name;
153         tmp->name = sc->name;
154         RNA_enum_item_add(item, totitem, tmp);
155
156         (*value)++;
157
158         for (SceneCollection *ncs = sc->scene_collections.first; ncs; ncs = ncs->next) {
159                 collection_scene_collection_itemf_recursive(tmp, item, totitem, value, ncs);
160         }
161 }
162
163 static EnumPropertyItem *collection_scene_collection_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
164 {
165         EnumPropertyItem tmp = {0, "", 0, "", ""};
166         EnumPropertyItem *item = NULL;
167         int value = 0, totitem = 0;
168
169         Scene *scene = CTX_data_scene(C);
170         SceneCollection *sc = BKE_collection_master(scene);
171
172         collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc);
173         RNA_enum_item_end(&item, &totitem);
174         *r_free = true;
175
176         return item;
177 }
178
179 void OUTLINER_OT_collection_link(wmOperatorType *ot)
180 {
181         PropertyRNA *prop;
182
183         /* identifiers */
184         ot->name = "Add Collection";
185         ot->idname = "OUTLINER_OT_collection_link";
186         ot->description = "Link a new collection to the active layer";
187
188         /* api callbacks */
189         ot->exec = collection_link_exec;
190         ot->invoke = collection_link_invoke;
191
192         /* flags */
193         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
194
195         prop = RNA_def_enum(ot->srna, "scene_collection", DummyRNA_NULL_items, 0, "Scene Collection", "");
196         RNA_def_enum_funcs(prop, collection_scene_collection_itemf);
197         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
198         ot->prop = prop;
199 }
200
201 /**
202  * Returns true if selected element is a collection directly
203  * linked to the active SceneLayer (not a nested collection)
204  */
205 static int collection_unlink_poll(bContext *C)
206 {
207         LayerCollection *lc = outliner_collection_active(C);
208
209         if (lc == NULL) {
210                 return 0;
211         }
212
213         SceneLayer *sl = CTX_data_scene_layer(C);
214         return BLI_findindex(&sl->layer_collections, lc) != -1 ? 1 : 0;
215 }
216
217 static int collection_unlink_exec(bContext *C, wmOperator *op)
218 {
219         LayerCollection *lc = outliner_collection_active(C);
220         SpaceOops *soops = CTX_wm_space_outliner(C);
221
222         if (lc == NULL) {
223                 BKE_report(op->reports, RPT_ERROR, "Active element is not a collection");
224                 return OPERATOR_CANCELLED;
225         }
226
227         SceneLayer *sl = CTX_data_scene_layer(C);
228         BKE_collection_unlink(sl, lc);
229
230         if (soops) {
231                 outliner_cleanup_tree(soops);
232         }
233
234         DEG_relations_tag_update(CTX_data_main(C));
235
236         /* TODO(sergey): Use proper flag for tagging here. */
237         DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
238
239         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
240         return OPERATOR_FINISHED;
241 }
242
243 void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
244 {
245         /* identifiers */
246         ot->name = "Add Collection";
247         ot->idname = "OUTLINER_OT_collection_unlink";
248         ot->description = "Unlink collection from the active layer";
249
250         /* api callbacks */
251         ot->exec = collection_unlink_exec;
252         ot->poll = collection_unlink_poll;
253
254         /* flags */
255         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
256 }
257
258 static int collection_new_exec(bContext *C, wmOperator *UNUSED(op))
259 {
260         Scene *scene = CTX_data_scene(C);
261         SceneLayer *sl = CTX_data_scene_layer(C);
262
263         SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
264         BKE_collection_link(sl, sc);
265
266         DEG_relations_tag_update(CTX_data_main(C));
267         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
268         return OPERATOR_FINISHED;
269 }
270
271 void OUTLINER_OT_collection_new(wmOperatorType *ot)
272 {
273         /* identifiers */
274         ot->name = "New Collection";
275         ot->idname = "OUTLINER_OT_collection_new";
276         ot->description = "Add a new collection to the scene, and link it to the active layer";
277
278         /* api callbacks */
279         ot->exec = collection_new_exec;
280
281         /* flags */
282         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
283 }
284
285 /**
286  * Returns true is selected element is a collection
287  */
288 static int collection_override_new_poll(bContext *(C))
289 {
290 #ifdef TODO_LAYER_OVERRIDE
291         /* disable for now, since it's not implemented */
292         (void) C;
293         return 0;
294 #else
295         return outliner_collection_active(C) ? 1 : 0;
296 #endif
297 }
298
299 static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
300 {
301         TODO_LAYER_OPERATORS;
302         TODO_LAYER_OVERRIDE;
303         BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet");
304         return OPERATOR_CANCELLED;
305 }
306
307 /* in the middle of renames remove s */
308 void OUTLINER_OT_collection_override_new(wmOperatorType *ot)
309 {
310         /* identifiers */
311         ot->name = "New Override";
312         ot->idname = "OUTLINER_OT_collection_override_new";
313         ot->description = "Add a new override to the active collection";
314
315         /* api callbacks */
316         ot->invoke = collection_override_new_invoke;
317         ot->poll = collection_override_new_poll;
318
319         /* flags */
320         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
321 }
322
323 struct CollectionDeleteData {
324         Scene *scene;
325         SpaceOops *soops;
326 };
327
328 static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdata)
329 {
330         struct CollectionDeleteData *data = customdata;
331         SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
332
333         if (!scene_collection) {
334                 return TRAVERSE_SKIP_CHILDS;
335         }
336
337         if (scene_collection == BKE_collection_master(data->scene)) {
338                 /* skip - showing warning/error message might be missleading
339                  * when deleting multiple collections, so just do nothing */
340         }
341         else {
342                 BKE_collection_remove(data->scene, scene_collection);
343         }
344
345         return TRAVERSE_CONTINUE;
346 }
347
348 static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
349 {
350         Scene *scene = CTX_data_scene(C);
351         SpaceOops *soops = CTX_wm_space_outliner(C);
352         struct CollectionDeleteData data = {.scene = scene, .soops = soops};
353
354         TODO_LAYER_OVERRIDE; /* handle overrides */
355         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_delete_cb, &data);
356
357         DEG_relations_tag_update(CTX_data_main(C));
358
359         /* TODO(sergey): Use proper flag for tagging here. */
360         DEG_id_tag_update(&scene->id, 0);
361
362         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
363
364         return OPERATOR_FINISHED;
365 }
366
367 void OUTLINER_OT_collections_delete(wmOperatorType *ot)
368 {
369         /* identifiers */
370         ot->name = "Delete";
371         ot->idname = "OUTLINER_OT_collections_delete";
372         ot->description = "Delete selected overrides or collections";
373
374         /* api callbacks */
375         ot->exec = collection_delete_exec;
376
377         /* flags */
378         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
379 }
380
381 static int collection_select_exec(bContext *C, wmOperator *op)
382 {
383         SceneLayer *sl = CTX_data_scene_layer(C);
384         const int collection_index = RNA_int_get(op->ptr, "collection_index");
385         sl->active_collection = collection_index;
386         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
387         return OPERATOR_FINISHED;
388 }
389
390 void OUTLINER_OT_collection_select(wmOperatorType *ot)
391 {
392         /* identifiers */
393         ot->name = "Select";
394         ot->idname = "OUTLINER_OT_collection_select";
395         ot->description = "Change active collection or override";
396
397         /* api callbacks */
398         ot->exec = collection_select_exec;
399
400         /* flags */
401         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
402
403         RNA_def_int(ot->srna, "collection_index", 0, 0, INT_MAX, "Index",
404                     "Index of collection to select", 0, INT_MAX);
405 }
406
407 #define ACTION_DISABLE 0
408 #define ACTION_ENABLE 1
409 #define ACTION_TOGGLE 2
410
411 static int collection_toggle_exec(bContext *C, wmOperator *op)
412 {
413         Main *bmain = CTX_data_main(C);
414         Scene *scene = CTX_data_scene(C);
415         SceneLayer *scene_layer = CTX_data_scene_layer(C);
416         int action = RNA_enum_get(op->ptr, "action");
417         LayerCollection *layer_collection = CTX_data_layer_collection(C);
418
419         if (layer_collection->flag & COLLECTION_DISABLED) {
420                 if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) {
421                         BKE_collection_enable(scene_layer, layer_collection);
422                 }
423                 else { /* ACTION_DISABLE */
424                         BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled",
425                                     layer_collection->scene_collection->name);
426                         return OPERATOR_CANCELLED;
427                 }
428         }
429         else {
430                 if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) {
431                         BKE_collection_disable(scene_layer, layer_collection);
432                 }
433                 else { /* ACTION_ENABLE */
434                         BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled",
435                                     layer_collection->scene_collection->name);
436                         return OPERATOR_CANCELLED;
437                 }
438         }
439
440         DEG_relations_tag_update(bmain);
441         /* TODO(sergey): Use proper flag for tagging here. */
442         DEG_id_tag_update(&scene->id, 0);
443
444         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
445         WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
446
447         return OPERATOR_FINISHED;
448 }
449
450 void OUTLINER_OT_collection_toggle(wmOperatorType *ot)
451 {
452         PropertyRNA *prop;
453
454         static EnumPropertyItem actions_items[] = {
455                 {ACTION_DISABLE, "DISABLE", 0, "Disable", "Disable selected markers"},
456                 {ACTION_ENABLE, "ENABLE", 0, "Enable", "Enable selected markers"},
457                 {ACTION_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
458                 {0, NULL, 0, NULL, NULL}
459         };
460
461         /* identifiers */
462         ot->name = "Toggle Collection";
463         ot->idname = "OUTLINER_OT_collection_toggle";
464         ot->description = "Deselect collection objects";
465
466         /* api callbacks */
467         ot->exec = collection_toggle_exec;
468
469         /* flags */
470         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
471
472         /* properties */
473         prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, "Collection Index", "Index of collection to toggle", 0, INT_MAX);
474         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
475         prop = RNA_def_enum(ot->srna, "action", actions_items, ACTION_TOGGLE, "Action", "Selection action to execute");
476         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
477 }
478
479 #undef ACTION_TOGGLE
480 #undef ACTION_ENABLE
481 #undef ACTION_DISABLE
482
483 /* -------------------------------------------------------------------- */
484
485 static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
486 {
487         TODO_LAYER_OPERATORS;
488         BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet");
489         return OPERATOR_CANCELLED;
490 }
491
492 void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
493 {
494         /* identifiers */
495         ot->name = "Add Objects";
496         ot->idname = "OUTLINER_OT_collection_objects_add";
497         ot->description = "Add selected objects to collection";
498
499         /* api callbacks */
500         ot->invoke = stubs_invoke;
501
502         /* flags */
503         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
504 }
505
506 void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
507 {
508         /* identifiers */
509         ot->name = "Remove Object";
510         ot->idname = "OUTLINER_OT_collection_objects_remove";
511         ot->description = "Remove objects from collection";
512
513         /* api callbacks */
514         ot->invoke = stubs_invoke;
515
516         /* flags */
517         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
518 }
519
520 void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
521 {
522         /* identifiers */
523         ot->name = "Select Objects";
524         ot->idname = "OUTLINER_OT_collection_objects_select";
525         ot->description = "Select collection objects";
526
527         /* api callbacks */
528         ot->invoke = stubs_invoke;
529
530         /* flags */
531         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
532 }
533
534 void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
535 {
536         /* identifiers */
537         ot->name = "Deselect Objects";
538         ot->idname = "OUTLINER_OT_collection_objects_deselect";
539         ot->description = "Deselect collection objects";
540
541         /* api callbacks */
542         ot->invoke = stubs_invoke;
543
544         /* flags */
545         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
546 }