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 const EnumPropertyItem *collection_scene_collection_itemf(
164         bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
165 {
166         EnumPropertyItem tmp = {0, "", 0, "", ""};
167         EnumPropertyItem *item = NULL;
168         int value = 0, totitem = 0;
169
170         Scene *scene = CTX_data_scene(C);
171         SceneCollection *sc = BKE_collection_master(scene);
172
173         collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc);
174         RNA_enum_item_end(&item, &totitem);
175         *r_free = true;
176
177         return item;
178 }
179
180 void OUTLINER_OT_collection_link(wmOperatorType *ot)
181 {
182         PropertyRNA *prop;
183
184         /* identifiers */
185         ot->name = "Add Collection";
186         ot->idname = "OUTLINER_OT_collection_link";
187         ot->description = "Link a new collection to the active layer";
188
189         /* api callbacks */
190         ot->exec = collection_link_exec;
191         ot->invoke = collection_link_invoke;
192
193         /* flags */
194         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
195
196         prop = RNA_def_enum(ot->srna, "scene_collection", DummyRNA_NULL_items, 0, "Scene Collection", "");
197         RNA_def_enum_funcs(prop, collection_scene_collection_itemf);
198         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
199         ot->prop = prop;
200 }
201
202 /**
203  * Returns true if selected element is a collection directly
204  * linked to the active SceneLayer (not a nested collection)
205  */
206 static int collection_unlink_poll(bContext *C)
207 {
208         LayerCollection *lc = outliner_collection_active(C);
209
210         if (lc == NULL) {
211                 return 0;
212         }
213
214         SceneLayer *sl = CTX_data_scene_layer(C);
215         return BLI_findindex(&sl->layer_collections, lc) != -1 ? 1 : 0;
216 }
217
218 static int collection_unlink_exec(bContext *C, wmOperator *op)
219 {
220         LayerCollection *lc = outliner_collection_active(C);
221         SpaceOops *soops = CTX_wm_space_outliner(C);
222
223         if (lc == NULL) {
224                 BKE_report(op->reports, RPT_ERROR, "Active element is not a collection");
225                 return OPERATOR_CANCELLED;
226         }
227
228         SceneLayer *sl = CTX_data_scene_layer(C);
229         BKE_collection_unlink(sl, lc);
230
231         if (soops) {
232                 outliner_cleanup_tree(soops);
233         }
234
235         DEG_relations_tag_update(CTX_data_main(C));
236
237         /* TODO(sergey): Use proper flag for tagging here. */
238         DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
239
240         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
241         return OPERATOR_FINISHED;
242 }
243
244 void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
245 {
246         /* identifiers */
247         ot->name = "Add Collection";
248         ot->idname = "OUTLINER_OT_collection_unlink";
249         ot->description = "Unlink collection from the active layer";
250
251         /* api callbacks */
252         ot->exec = collection_unlink_exec;
253         ot->poll = collection_unlink_poll;
254
255         /* flags */
256         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
257 }
258
259 static int collection_new_exec(bContext *C, wmOperator *UNUSED(op))
260 {
261         Scene *scene = CTX_data_scene(C);
262         SceneLayer *sl = CTX_data_scene_layer(C);
263
264         SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
265         BKE_collection_link(sl, sc);
266
267         DEG_relations_tag_update(CTX_data_main(C));
268         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
269         return OPERATOR_FINISHED;
270 }
271
272 void OUTLINER_OT_collection_new(wmOperatorType *ot)
273 {
274         /* identifiers */
275         ot->name = "New Collection";
276         ot->idname = "OUTLINER_OT_collection_new";
277         ot->description = "Add a new collection to the scene, and link it to the active layer";
278
279         /* api callbacks */
280         ot->exec = collection_new_exec;
281
282         /* flags */
283         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
284 }
285
286 /**
287  * Returns true is selected element is a collection
288  */
289 static int collection_override_new_poll(bContext *(C))
290 {
291 #ifdef TODO_LAYER_OVERRIDE
292         /* disable for now, since it's not implemented */
293         (void) C;
294         return 0;
295 #else
296         return outliner_collection_active(C) ? 1 : 0;
297 #endif
298 }
299
300 static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
301 {
302         TODO_LAYER_OPERATORS;
303         TODO_LAYER_OVERRIDE;
304         BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet");
305         return OPERATOR_CANCELLED;
306 }
307
308 /* in the middle of renames remove s */
309 void OUTLINER_OT_collection_override_new(wmOperatorType *ot)
310 {
311         /* identifiers */
312         ot->name = "New Override";
313         ot->idname = "OUTLINER_OT_collection_override_new";
314         ot->description = "Add a new override to the active collection";
315
316         /* api callbacks */
317         ot->invoke = collection_override_new_invoke;
318         ot->poll = collection_override_new_poll;
319
320         /* flags */
321         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
322 }
323
324 struct CollectionDeleteData {
325         Scene *scene;
326         SpaceOops *soops;
327 };
328
329 static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdata)
330 {
331         struct CollectionDeleteData *data = customdata;
332         SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
333
334         if (!scene_collection) {
335                 return TRAVERSE_SKIP_CHILDS;
336         }
337
338         if (scene_collection == BKE_collection_master(data->scene)) {
339                 /* skip - showing warning/error message might be missleading
340                  * when deleting multiple collections, so just do nothing */
341         }
342         else {
343                 BKE_collection_remove(data->scene, scene_collection);
344         }
345
346         return TRAVERSE_CONTINUE;
347 }
348
349 static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
350 {
351         Scene *scene = CTX_data_scene(C);
352         SpaceOops *soops = CTX_wm_space_outliner(C);
353         struct CollectionDeleteData data = {.scene = scene, .soops = soops};
354
355         TODO_LAYER_OVERRIDE; /* handle overrides */
356         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_delete_cb, &data);
357
358         DEG_relations_tag_update(CTX_data_main(C));
359
360         /* TODO(sergey): Use proper flag for tagging here. */
361         DEG_id_tag_update(&scene->id, 0);
362
363         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
364
365         return OPERATOR_FINISHED;
366 }
367
368 void OUTLINER_OT_collections_delete(wmOperatorType *ot)
369 {
370         /* identifiers */
371         ot->name = "Delete";
372         ot->idname = "OUTLINER_OT_collections_delete";
373         ot->description = "Delete selected overrides or collections";
374
375         /* api callbacks */
376         ot->exec = collection_delete_exec;
377
378         /* flags */
379         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
380 }
381
382 static int collection_select_exec(bContext *C, wmOperator *op)
383 {
384         SceneLayer *sl = CTX_data_scene_layer(C);
385         const int collection_index = RNA_int_get(op->ptr, "collection_index");
386         sl->active_collection = collection_index;
387         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
388         return OPERATOR_FINISHED;
389 }
390
391 void OUTLINER_OT_collection_select(wmOperatorType *ot)
392 {
393         /* identifiers */
394         ot->name = "Select";
395         ot->idname = "OUTLINER_OT_collection_select";
396         ot->description = "Change active collection or override";
397
398         /* api callbacks */
399         ot->exec = collection_select_exec;
400
401         /* flags */
402         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
403
404         RNA_def_int(ot->srna, "collection_index", 0, 0, INT_MAX, "Index",
405                     "Index of collection to select", 0, INT_MAX);
406 }
407
408 #define ACTION_DISABLE 0
409 #define ACTION_ENABLE 1
410 #define ACTION_TOGGLE 2
411
412 static int collection_toggle_exec(bContext *C, wmOperator *op)
413 {
414         Main *bmain = CTX_data_main(C);
415         Scene *scene = CTX_data_scene(C);
416         SceneLayer *scene_layer = CTX_data_scene_layer(C);
417         int action = RNA_enum_get(op->ptr, "action");
418         LayerCollection *layer_collection = CTX_data_layer_collection(C);
419
420         if (layer_collection->flag & COLLECTION_DISABLED) {
421                 if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) {
422                         BKE_collection_enable(scene_layer, layer_collection);
423                 }
424                 else { /* ACTION_DISABLE */
425                         BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled",
426                                     layer_collection->scene_collection->name);
427                         return OPERATOR_CANCELLED;
428                 }
429         }
430         else {
431                 if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) {
432                         BKE_collection_disable(scene_layer, layer_collection);
433                 }
434                 else { /* ACTION_ENABLE */
435                         BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled",
436                                     layer_collection->scene_collection->name);
437                         return OPERATOR_CANCELLED;
438                 }
439         }
440
441         DEG_relations_tag_update(bmain);
442         /* TODO(sergey): Use proper flag for tagging here. */
443         DEG_id_tag_update(&scene->id, 0);
444
445         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
446         WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
447
448         return OPERATOR_FINISHED;
449 }
450
451 void OUTLINER_OT_collection_toggle(wmOperatorType *ot)
452 {
453         PropertyRNA *prop;
454
455         static EnumPropertyItem actions_items[] = {
456                 {ACTION_DISABLE, "DISABLE", 0, "Disable", "Disable selected markers"},
457                 {ACTION_ENABLE, "ENABLE", 0, "Enable", "Enable selected markers"},
458                 {ACTION_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
459                 {0, NULL, 0, NULL, NULL}
460         };
461
462         /* identifiers */
463         ot->name = "Toggle Collection";
464         ot->idname = "OUTLINER_OT_collection_toggle";
465         ot->description = "Deselect collection objects";
466
467         /* api callbacks */
468         ot->exec = collection_toggle_exec;
469
470         /* flags */
471         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
472
473         /* properties */
474         prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, "Collection Index", "Index of collection to toggle", 0, INT_MAX);
475         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
476         prop = RNA_def_enum(ot->srna, "action", actions_items, ACTION_TOGGLE, "Action", "Selection action to execute");
477         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
478 }
479
480 #undef ACTION_TOGGLE
481 #undef ACTION_ENABLE
482 #undef ACTION_DISABLE
483
484 /* -------------------------------------------------------------------- */
485
486 static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
487 {
488         TODO_LAYER_OPERATORS;
489         BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet");
490         return OPERATOR_CANCELLED;
491 }
492
493 void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
494 {
495         /* identifiers */
496         ot->name = "Add Objects";
497         ot->idname = "OUTLINER_OT_collection_objects_add";
498         ot->description = "Add selected objects to collection";
499
500         /* api callbacks */
501         ot->invoke = stubs_invoke;
502
503         /* flags */
504         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
505 }
506
507 void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
508 {
509         /* identifiers */
510         ot->name = "Remove Object";
511         ot->idname = "OUTLINER_OT_collection_objects_remove";
512         ot->description = "Remove objects from collection";
513
514         /* api callbacks */
515         ot->invoke = stubs_invoke;
516
517         /* flags */
518         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
519 }
520
521 void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
522 {
523         /* identifiers */
524         ot->name = "Select Objects";
525         ot->idname = "OUTLINER_OT_collection_objects_select";
526         ot->description = "Select collection objects";
527
528         /* api callbacks */
529         ot->invoke = stubs_invoke;
530
531         /* flags */
532         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
533 }
534
535 void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
536 {
537         /* identifiers */
538         ot->name = "Deselect Objects";
539         ot->idname = "OUTLINER_OT_collection_objects_deselect";
540         ot->description = "Deselect collection objects";
541
542         /* api callbacks */
543         ot->invoke = stubs_invoke;
544
545         /* flags */
546         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
547 }