Cleanup: style, use braces for editor/spaces
[blender.git] / source / blender / editors / space_outliner / outliner_tree.c
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
20 /** \file
21  * \ingroup spoutliner
22  */
23
24 #include <math.h>
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_anim_types.h"
30 #include "DNA_armature_types.h"
31 #include "DNA_constraint_types.h"
32 #include "DNA_camera_types.h"
33 #include "DNA_cachefile_types.h"
34 #include "DNA_collection_types.h"
35 #include "DNA_gpencil_types.h"
36 #include "DNA_key_types.h"
37 #include "DNA_light_types.h"
38 #include "DNA_material_types.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_meta_types.h"
41 #include "DNA_lightprobe_types.h"
42 #include "DNA_particle_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_world_types.h"
45 #include "DNA_sequence_types.h"
46 #include "DNA_speaker_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_linestyle_types.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_utildefines.h"
52 #include "BLI_mempool.h"
53 #include "BLI_fnmatch.h"
54
55 #include "BLT_translation.h"
56
57 #include "BKE_fcurve.h"
58 #include "BKE_idcode.h"
59 #include "BKE_layer.h"
60 #include "BKE_library.h"
61 #include "BKE_main.h"
62 #include "BKE_modifier.h"
63 #include "BKE_outliner_treehash.h"
64 #include "BKE_sequencer.h"
65
66 #include "DEG_depsgraph.h"
67 #include "DEG_depsgraph_build.h"
68
69 #include "ED_armature.h"
70 #include "ED_screen.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "RNA_access.h"
76
77 #include "UI_interface.h"
78
79 #include "outliner_intern.h"
80
81 #ifdef WIN32
82 #  include "BLI_math_base.h" /* M_PI */
83 #endif
84
85 /* prototypes */
86 static TreeElement *outliner_add_collection_recursive(
87         SpaceOutliner *soops, Collection *collection, TreeElement *ten);
88 static void outliner_make_object_parent_hierarchy(ListBase *lb);
89
90 /* ********************************************************* */
91 /* Persistent Data */
92
93 static void outliner_storage_cleanup(SpaceOutliner *soops)
94 {
95         BLI_mempool *ts = soops->treestore;
96
97         if (ts) {
98                 TreeStoreElem *tselem;
99                 int unused = 0;
100
101                 /* each element used once, for ID blocks with more users to have each a treestore */
102                 BLI_mempool_iter iter;
103
104                 BLI_mempool_iternew(ts, &iter);
105                 while ((tselem = BLI_mempool_iterstep(&iter))) {
106                         tselem->used = 0;
107                 }
108
109                 /* cleanup only after reading file or undo step, and always for
110                  * RNA datablocks view in order to save memory */
111                 if (soops->storeflag & SO_TREESTORE_CLEANUP) {
112                         soops->storeflag &= ~SO_TREESTORE_CLEANUP;
113
114                         BLI_mempool_iternew(ts, &iter);
115                         while ((tselem = BLI_mempool_iterstep(&iter))) {
116                                 if (tselem->id == NULL) {
117                                         unused++;
118                                 }
119                         }
120
121                         if (unused) {
122                                 if (BLI_mempool_len(ts) == unused) {
123                                         BLI_mempool_destroy(ts);
124                                         soops->treestore = NULL;
125                                         if (soops->treehash) {
126                                                 BKE_outliner_treehash_free(soops->treehash);
127                                                 soops->treehash = NULL;
128                                         }
129                                 }
130                                 else {
131                                         TreeStoreElem *tsenew;
132                                         BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused,
133                                                                                  512, BLI_MEMPOOL_ALLOW_ITER);
134                                         BLI_mempool_iternew(ts, &iter);
135                                         while ((tselem = BLI_mempool_iterstep(&iter))) {
136                                                 if (tselem->id) {
137                                                         tsenew = BLI_mempool_alloc(new_ts);
138                                                         *tsenew = *tselem;
139                                                 }
140                                         }
141                                         BLI_mempool_destroy(ts);
142                                         soops->treestore = new_ts;
143                                         if (soops->treehash) {
144                                                 /* update hash table to fix broken pointers */
145                                                 BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
146                                         }
147                                 }
148                         }
149                 }
150                 else if (soops->treehash) {
151                         BKE_outliner_treehash_clear_used(soops->treehash);
152                 }
153         }
154 }
155
156 static void check_persistent(SpaceOutliner *soops, TreeElement *te, ID *id, short type, short nr)
157 {
158         TreeStoreElem *tselem;
159
160         if (soops->treestore == NULL) {
161                 /* if treestore was not created in readfile.c, create it here */
162                 soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
163
164         }
165         if (soops->treehash == NULL) {
166                 soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
167         }
168
169         /* find any unused tree element in treestore and mark it as used
170          * (note that there may be multiple unused elements in case of linked objects) */
171         tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
172         if (tselem) {
173                 te->store_elem = tselem;
174                 tselem->used = 1;
175                 return;
176         }
177
178         /* add 1 element to treestore */
179         tselem = BLI_mempool_alloc(soops->treestore);
180         tselem->type = type;
181         tselem->nr = type ? nr : 0;
182         tselem->id = id;
183         tselem->used = 0;
184         tselem->flag = TSE_CLOSED;
185         te->store_elem = tselem;
186         BKE_outliner_treehash_add_element(soops->treehash, tselem);
187 }
188
189 /* ********************************************************* */
190 /* Tree Management */
191
192 void outliner_free_tree(ListBase *tree)
193 {
194         for (TreeElement *element = tree->first, *element_next; element; element = element_next) {
195                 element_next = element->next;
196                 outliner_free_tree_element(element, tree);
197         }
198 }
199
200 void outliner_cleanup_tree(SpaceOutliner *soops)
201 {
202         outliner_free_tree(&soops->tree);
203         outliner_storage_cleanup(soops);
204 }
205
206 /**
207  * Free \a element and its sub-tree and remove its link in \a parent_subtree.
208  *
209  * \note Does not remove the #TreeStoreElem of \a element!
210  * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
211  */
212 void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
213 {
214         BLI_assert(BLI_findindex(parent_subtree, element) > -1);
215         BLI_remlink(parent_subtree, element);
216
217         outliner_free_tree(&element->subtree);
218
219         if (element->flag & TE_FREE_NAME) {
220                 MEM_freeN((void *)element->name);
221         }
222         MEM_freeN(element);
223 }
224
225
226 /* ********************************************************* */
227
228 /* Prototype, see functions below */
229 static TreeElement *outliner_add_element(SpaceOutliner *soops, ListBase *lb, void *idv,
230                                          TreeElement *parent, short type, short index);
231
232 /* -------------------------------------------------------- */
233
234 /* special handling of hierarchical non-lib data */
235 static void outliner_add_bone(SpaceOutliner *soops, ListBase *lb, ID *id, Bone *curBone,
236                               TreeElement *parent, int *a)
237 {
238         TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
239
240         (*a)++;
241         te->name = curBone->name;
242         te->directdata = curBone;
243
244         for (curBone = curBone->childbase.first; curBone; curBone = curBone->next) {
245                 outliner_add_bone(soops, &te->subtree, id, curBone, te, a);
246         }
247 }
248
249 static bool outliner_animdata_test(AnimData *adt)
250 {
251         if (adt) {
252                 return (adt->action || adt->drivers.first || adt->nla_tracks.first);
253         }
254         return false;
255 }
256
257 #ifdef WITH_FREESTYLE
258 static void outliner_add_line_styles(SpaceOutliner *soops, ListBase *lb, Scene *sce, TreeElement *te)
259 {
260         ViewLayer *view_layer;
261         FreestyleLineSet *lineset;
262
263         for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
264                 for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
265                         FreestyleLineStyle *linestyle = lineset->linestyle;
266                         if (linestyle) {
267                                 linestyle->id.tag |= LIB_TAG_DOIT;
268                         }
269                 }
270         }
271         for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
272                 for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
273                         FreestyleLineStyle *linestyle = lineset->linestyle;
274                         if (linestyle) {
275                                 if (!(linestyle->id.tag & LIB_TAG_DOIT)) {
276                                         continue;
277                                 }
278                                 linestyle->id.tag &= ~LIB_TAG_DOIT;
279                                 outliner_add_element(soops, lb, linestyle, te, 0, 0);
280                         }
281                 }
282         }
283 }
284 #endif
285
286 static void outliner_add_scene_contents(SpaceOutliner *soops, ListBase *lb, Scene *sce, TreeElement *te)
287 {
288         /* View layers */
289         TreeElement *ten = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
290         ten->name = IFACE_("View Layers");
291
292         ViewLayer *view_layer;
293         for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
294                 TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0);
295                 tenlay->name = view_layer->name;
296                 tenlay->directdata = view_layer;
297         }
298
299         /* Collections */
300         ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0);
301         ten->name = IFACE_("Scene Collection");
302         outliner_add_collection_recursive(soops, sce->master_collection, ten);
303
304         /* Objects */
305         ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
306         ten->name = IFACE_("Objects");
307         FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
308         {
309                 outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0);
310         }
311         FOREACH_SCENE_OBJECT_END;
312         outliner_make_object_parent_hierarchy(&ten->subtree);
313
314         /* Animation Data */
315         if (outliner_animdata_test(sce->adt)) {
316                 outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
317         }
318
319 }
320
321 // can be inlined if necessary
322 static void outliner_add_object_contents(SpaceOutliner *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
323 {
324         if (outliner_animdata_test(ob->adt)) {
325                 outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
326         }
327
328         outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
329
330         if (ob->proxy && !ID_IS_LINKED(ob)) {
331                 outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
332         }
333
334         outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
335
336         outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
337
338         if (ob->pose) {
339                 bArmature *arm = ob->data;
340                 bPoseChannel *pchan;
341                 TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
342
343                 tenla->name = IFACE_("Pose");
344
345                 /* channels undefined in editmode, but we want the 'tenla' pose icon itself */
346                 if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
347                         TreeElement *ten;
348                         int a = 0, const_index = 1000;    /* ensure unique id for bone constraints */
349
350                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) {
351                                 ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
352                                 ten->name = pchan->name;
353                                 ten->directdata = pchan;
354                                 pchan->temp = (void *)ten;
355
356                                 if (pchan->constraints.first) {
357                                         //Object *target;
358                                         bConstraint *con;
359                                         TreeElement *ten1;
360                                         TreeElement *tenla1 = outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
361                                         //char *str;
362
363                                         tenla1->name = IFACE_("Constraints");
364                                         for (con = pchan->constraints.first; con; con = con->next, const_index++) {
365                                                 ten1 = outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
366 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
367                                                 target = get_constraint_target(con, &str);
368                                                 if (str && str[0]) ten1->name = str;
369                                                 else if (target) ten1->name = target->id.name + 2;
370                                                 else ten1->name = con->name;
371 #endif
372                                                 ten1->name = con->name;
373                                                 ten1->directdata = con;
374                                                 /* possible add all other types links? */
375                                         }
376                                 }
377                         }
378                         /* make hierarchy */
379                         ten = tenla->subtree.first;
380                         while (ten) {
381                                 TreeElement *nten = ten->next, *par;
382                                 tselem = TREESTORE(ten);
383                                 if (tselem->type == TSE_POSE_CHANNEL) {
384                                         pchan = (bPoseChannel *)ten->directdata;
385                                         if (pchan->parent) {
386                                                 BLI_remlink(&tenla->subtree, ten);
387                                                 par = (TreeElement *)pchan->parent->temp;
388                                                 BLI_addtail(&par->subtree, ten);
389                                                 ten->parent = par;
390                                         }
391                                 }
392                                 ten = nten;
393                         }
394                 }
395
396                 /* Pose Groups */
397                 if (ob->pose->agroups.first) {
398                         bActionGroup *agrp;
399                         TreeElement *ten_bonegrp = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
400                         int a = 0;
401
402                         ten_bonegrp->name = IFACE_("Bone Groups");
403                         for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) {
404                                 TreeElement *ten;
405                                 ten = outliner_add_element(soops, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a);
406                                 ten->name = agrp->name;
407                                 ten->directdata = agrp;
408                         }
409                 }
410         }
411
412         for (int a = 0; a < ob->totcol; a++) {
413                 outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
414         }
415
416         if (ob->constraints.first) {
417                 //Object *target;
418                 bConstraint *con;
419                 TreeElement *ten;
420                 TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
421                 //char *str;
422                 int a;
423
424                 tenla->name = IFACE_("Constraints");
425                 for (con = ob->constraints.first, a = 0; con; con = con->next, a++) {
426                         ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
427 #if 0 /* disabled due to constraints system targets recode... code here needs review */
428                         target = get_constraint_target(con, &str);
429                         if (str && str[0]) ten->name = str;
430                         else if (target) ten->name = target->id.name + 2;
431                         else ten->name = con->name;
432 #endif
433                         ten->name = con->name;
434                         ten->directdata = con;
435                         /* possible add all other types links? */
436                 }
437         }
438
439         if (ob->modifiers.first) {
440                 ModifierData *md;
441                 TreeElement *ten_mod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
442                 int index;
443
444                 ten_mod->name = IFACE_("Modifiers");
445                 for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) {
446                         TreeElement *ten = outliner_add_element(soops, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
447                         ten->name = md->name;
448                         ten->directdata = md;
449
450                         if (md->type == eModifierType_Lattice) {
451                                 outliner_add_element(soops, &ten->subtree, ((LatticeModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
452                         }
453                         else if (md->type == eModifierType_Curve) {
454                                 outliner_add_element(soops, &ten->subtree, ((CurveModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
455                         }
456                         else if (md->type == eModifierType_Armature) {
457                                 outliner_add_element(soops, &ten->subtree, ((ArmatureModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
458                         }
459                         else if (md->type == eModifierType_Hook) {
460                                 outliner_add_element(soops, &ten->subtree, ((HookModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
461                         }
462                         else if (md->type == eModifierType_ParticleSystem) {
463                                 ParticleSystem *psys = ((ParticleSystemModifierData *) md)->psys;
464                                 TreeElement *ten_psys;
465
466                                 ten_psys = outliner_add_element(soops, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0);
467                                 ten_psys->directdata = psys;
468                                 ten_psys->name = psys->part->id.name + 2;
469                         }
470                 }
471         }
472
473         /* vertex groups */
474         if (ob->defbase.first) {
475                 bDeformGroup *defgroup;
476                 TreeElement *ten;
477                 TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
478                 int a;
479
480                 tenla->name = IFACE_("Vertex Groups");
481                 for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) {
482                         ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
483                         ten->name = defgroup->name;
484                         ten->directdata = defgroup;
485                 }
486         }
487
488         /* duplicated group */
489         if (ob->instance_collection) {
490                 outliner_add_element(soops, &te->subtree, ob->instance_collection, te, 0, 0);
491         }
492 }
493
494
495 // can be inlined if necessary
496 static void outliner_add_id_contents(SpaceOutliner *soops, TreeElement *te, TreeStoreElem *tselem, ID *id)
497 {
498         /* tuck pointer back in object, to construct hierarchy */
499         if (GS(id->name) == ID_OB) {
500                 id->newid = (ID *)te;
501         }
502
503         /* expand specific data always */
504         switch (GS(id->name)) {
505                 case ID_LI:
506                 {
507                         te->name = ((Library *)id)->name;
508                         break;
509                 }
510                 case ID_SCE:
511                 {
512                         outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
513                         break;
514                 }
515                 case ID_OB:
516                 {
517                         outliner_add_object_contents(soops, te, tselem, (Object *)id);
518                         break;
519                 }
520                 case ID_ME:
521                 {
522                         Mesh *me = (Mesh *)id;
523                         int a;
524
525                         if (outliner_animdata_test(me->adt)) {
526                                 outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0);
527                         }
528
529                         outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
530                         for (a = 0; a < me->totcol; a++) {
531                                 outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
532                         }
533                         /* could do tfaces with image links, but the images are not grouped nicely.
534                          * would require going over all tfaces, sort images in use. etc... */
535                         break;
536                 }
537                 case ID_CU:
538                 {
539                         Curve *cu = (Curve *)id;
540                         int a;
541
542                         if (outliner_animdata_test(cu->adt)) {
543                                 outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
544                         }
545
546                         for (a = 0; a < cu->totcol; a++) {
547                                 outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
548                         }
549                         break;
550                 }
551                 case ID_MB:
552                 {
553                         MetaBall *mb = (MetaBall *)id;
554                         int a;
555
556                         if (outliner_animdata_test(mb->adt)) {
557                                 outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
558                         }
559
560                         for (a = 0; a < mb->totcol; a++) {
561                                 outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
562                         }
563                         break;
564                 }
565                 case ID_MA:
566                 {
567                         Material *ma = (Material *)id;
568
569                         if (outliner_animdata_test(ma->adt)) {
570                                 outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
571                         }
572                         break;
573                 }
574                 case ID_TE:
575                 {
576                         Tex *tex = (Tex *)id;
577
578                         if (outliner_animdata_test(tex->adt)) {
579                                 outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
580                         }
581                         outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
582                         break;
583                 }
584                 case ID_CA:
585                 {
586                         Camera *ca = (Camera *)id;
587
588                         if (outliner_animdata_test(ca->adt)) {
589                                 outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
590                         }
591                         break;
592                 }
593                 case ID_CF:
594                 {
595                         CacheFile *cache_file = (CacheFile *)id;
596
597                         if (outliner_animdata_test(cache_file->adt)) {
598                                 outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
599                         }
600
601                         break;
602                 }
603                 case ID_LA:
604                 {
605                         Light *la = (Light *)id;
606
607                         if (outliner_animdata_test(la->adt)) {
608                                 outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0);
609                         }
610                         break;
611                 }
612                 case ID_SPK:
613                 {
614                         Speaker *spk = (Speaker *)id;
615
616                         if (outliner_animdata_test(spk->adt)) {
617                                 outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
618                         }
619                         break;
620                 }
621                 case ID_LP:
622                 {
623                         LightProbe *prb = (LightProbe *)id;
624
625                         if (outliner_animdata_test(prb->adt)) {
626                                 outliner_add_element(soops, &te->subtree, prb, te, TSE_ANIM_DATA, 0);
627                         }
628                         break;
629                 }
630                 case ID_WO:
631                 {
632                         World *wrld = (World *)id;
633
634                         if (outliner_animdata_test(wrld->adt)) {
635                                 outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
636                         }
637                         break;
638                 }
639                 case ID_KE:
640                 {
641                         Key *key = (Key *)id;
642
643                         if (outliner_animdata_test(key->adt)) {
644                                 outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0);
645                         }
646                         break;
647                 }
648                 case ID_AC:
649                 {
650                         // XXX do we want to be exposing the F-Curves here?
651                         //bAction *act = (bAction *)id;
652                         break;
653                 }
654                 case ID_AR:
655                 {
656                         bArmature *arm = (bArmature *)id;
657                         int a = 0;
658
659                         if (outliner_animdata_test(arm->adt)) {
660                                 outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
661                         }
662
663                         if (arm->edbo) {
664                                 EditBone *ebone;
665                                 TreeElement *ten;
666
667                                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next, a++) {
668                                         ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
669                                         ten->directdata = ebone;
670                                         ten->name = ebone->name;
671                                         ebone->temp.p = ten;
672                                 }
673                                 /* make hierarchy */
674                                 ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
675                                 while (ten) {
676                                         TreeElement *nten = ten->next, *par;
677                                         ebone = (EditBone *)ten->directdata;
678                                         if (ebone->parent) {
679                                                 BLI_remlink(&te->subtree, ten);
680                                                 par = ebone->parent->temp.p;
681                                                 BLI_addtail(&par->subtree, ten);
682                                                 ten->parent = par;
683                                         }
684                                         ten = nten;
685                                 }
686                         }
687                         else {
688                                 /* do not extend Armature when we have posemode */
689                                 tselem = TREESTORE(te->parent);
690                                 if (GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) {
691                                         /* pass */
692                                 }
693                                 else {
694                                         Bone *curBone;
695                                         for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
696                                                 outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
697                                         }
698                                 }
699                         }
700                         break;
701                 }
702                 case ID_LS:
703                 {
704                         FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
705                         int a;
706
707                         if (outliner_animdata_test(linestyle->adt)) {
708                                 outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
709                         }
710
711                         for (a = 0; a < MAX_MTEX; a++) {
712                                 if (linestyle->mtex[a]) {
713                                         outliner_add_element(soops, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
714                                 }
715                         }
716                         break;
717                 }
718                 case ID_GD:
719                 {
720                         bGPdata *gpd = (bGPdata *)id;
721                         bGPDlayer *gpl;
722                         int a = 0;
723
724                         if (outliner_animdata_test(gpd->adt)) {
725                                 outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
726                         }
727
728                         // TODO: base element for layers?
729                         for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
730                                 outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a);
731                                 a++;
732                         }
733                         break;
734                 }
735                 case ID_GR:
736                 {
737                         /* Don't expand for instances, creates too many elements. */
738                         if (!(te->parent && te->parent->idcode == ID_OB)) {
739                                 Collection *collection = (Collection *)id;
740                                 outliner_add_collection_recursive(soops, collection, te);
741                         }
742                 }
743                 default:
744                         break;
745         }
746 }
747
748 // TODO: this function needs to be split up! It's getting a bit too large...
749 // Note: "ID" is not always a real ID
750 static TreeElement *outliner_add_element(SpaceOutliner *soops, ListBase *lb, void *idv,
751                                          TreeElement *parent, short type, short index)
752 {
753         TreeElement *te;
754         TreeStoreElem *tselem;
755         ID *id = idv;
756
757         if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
758                 id = ((PointerRNA *)idv)->id.data;
759                 if (!id) {
760                         id = ((PointerRNA *)idv)->data;
761                 }
762         }
763         else if (type == TSE_GP_LAYER) {
764                 /* idv is the layer its self */
765                 id = TREESTORE(parent)->id;
766         }
767
768         /* exceptions */
769         if (type == TSE_ID_BASE) {
770                 /* pass */
771         }
772         else if (id == NULL) {
773                 return NULL;
774         }
775
776         if (type == 0) {
777                 /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
778                 BLI_assert(TREESTORE_ID_TYPE(id));
779         }
780
781         te = MEM_callocN(sizeof(TreeElement), "tree elem");
782         /* add to the visual tree */
783         BLI_addtail(lb, te);
784         /* add to the storage */
785         check_persistent(soops, te, id, type, index);
786         tselem = TREESTORE(te);
787
788         /* if we are searching for something expand to see child elements */
789         if (SEARCHING_OUTLINER(soops)) {
790                 tselem->flag |= TSE_CHILDSEARCH;
791         }
792
793         te->parent = parent;
794         te->index = index;   // for data arrays
795         if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
796                 /* pass */
797         }
798         else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
799                 /* pass */
800         }
801         else if (type == TSE_ANIM_DATA) {
802                 /* pass */
803         }
804         else if (type == TSE_GP_LAYER) {
805                 /* pass */
806         }
807         else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
808                 /* pass */
809         }
810         else if (type == TSE_ID_BASE) {
811                 /* pass */
812         }
813         else {
814                 /* do here too, for blend file viewer, own ID_LI then shows file name */
815                 if (GS(id->name) == ID_LI) {
816                         te->name = ((Library *)id)->name;
817                 }
818                 else {
819                         te->name = id->name + 2; // default, can be overridden by Library or non-ID data
820                 }
821                 te->idcode = GS(id->name);
822         }
823
824         if (type == 0) {
825                 TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
826
827                 /* ID datablock */
828                 if (tsepar == NULL || tsepar->type != TSE_ID_BASE || soops->filter_id_type) {
829                         outliner_add_id_contents(soops, te, tselem, id);
830                 }
831         }
832         else if (type == TSE_ANIM_DATA) {
833                 IdAdtTemplate *iat = (IdAdtTemplate *)idv;
834                 AnimData *adt = (AnimData *)iat->adt;
835
836                 /* this element's info */
837                 te->name = IFACE_("Animation");
838                 te->directdata = adt;
839
840                 /* Action */
841                 outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
842
843                 /* Drivers */
844                 if (adt->drivers.first) {
845                         TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
846                         ID *lastadded = NULL;
847                         FCurve *fcu;
848
849                         ted->name = IFACE_("Drivers");
850
851                         for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
852                                 if (fcu->driver && fcu->driver->variables.first) {
853                                         ChannelDriver *driver = fcu->driver;
854                                         DriverVar *dvar;
855
856                                         for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
857                                                 /* loop over all targets used here */
858                                                 DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
859                                                 {
860                                                         if (lastadded != dtar->id) {
861                                                                 // XXX this lastadded check is rather lame, and also fails quite badly...
862                                                                 outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
863                                                                 lastadded = dtar->id;
864                                                         }
865                                                 }
866                                                 DRIVER_TARGETS_LOOPER_END;
867                                         }
868                                 }
869                         }
870                 }
871
872                 /* NLA Data */
873                 if (adt->nla_tracks.first) {
874                         TreeElement *tenla = outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0);
875                         NlaTrack *nlt;
876                         int a = 0;
877
878                         tenla->name = IFACE_("NLA Tracks");
879
880                         for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
881                                 TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
882                                 NlaStrip *strip;
883                                 TreeElement *ten;
884                                 int b = 0;
885
886                                 tenlt->name = nlt->name;
887
888                                 for (strip = nlt->strips.first; strip; strip = strip->next, b++) {
889                                         ten = outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b);
890                                         if (ten) {
891                                                 ten->directdata = strip;
892                                         }
893                                 }
894                         }
895                 }
896         }
897         else if (type == TSE_GP_LAYER) {
898                 bGPDlayer *gpl = (bGPDlayer *)idv;
899
900                 te->name = gpl->info;
901                 te->directdata = gpl;
902         }
903         else if (type == TSE_SEQUENCE) {
904                 Sequence *seq = (Sequence *) idv;
905                 Sequence *p;
906
907                 /*
908                  * The idcode is a little hack, but the outliner
909                  * only check te->idcode if te->type is equal to zero,
910                  * so this is "safe".
911                  */
912                 te->idcode = seq->type;
913                 te->directdata = seq;
914                 te->name = seq->name + 2;
915
916                 if (!(seq->type & SEQ_TYPE_EFFECT)) {
917                         /*
918                          * This work like the sequence.
919                          * If the sequence have a name (not default name)
920                          * show it, in other case put the filename.
921                          */
922
923                         if (seq->type == SEQ_TYPE_META) {
924                                 p = seq->seqbase.first;
925                                 while (p) {
926                                         outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
927                                         p = p->next;
928                                 }
929                         }
930                         else {
931                                 outliner_add_element(soops, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
932                         }
933                 }
934         }
935         else if (type == TSE_SEQ_STRIP) {
936                 Strip *strip = (Strip *)idv;
937
938                 if (strip->dir[0] != '\0') {
939                         te->name = strip->dir;
940                 }
941                 else {
942                         te->name = IFACE_("Strip None");
943                 }
944                 te->directdata = strip;
945         }
946         else if (type == TSE_SEQUENCE_DUP) {
947                 Sequence *seq = (Sequence *)idv;
948
949                 te->idcode = seq->type;
950                 te->directdata = seq;
951                 te->name = seq->strip->stripdata->name;
952         }
953         else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
954                 PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
955                 PropertyRNA *prop, *iterprop;
956                 PropertyType proptype;
957
958                 /* Don't display arrays larger, weak but index is stored as a short,
959                  * also the outliner isn't intended for editing such large data-sets. */
960                 BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!");
961                 const int tot_limit = SHRT_MAX;
962
963                 int a, tot;
964
965                 /* we do lazy build, for speed and to avoid infinite recursion */
966
967                 if (ptr->data == NULL) {
968                         te->name = IFACE_("(empty)");
969                 }
970                 else if (type == TSE_RNA_STRUCT) {
971                         /* struct */
972                         te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
973
974                         if (te->name) {
975                                 te->flag |= TE_FREE_NAME;
976                         }
977                         else {
978                                 te->name = RNA_struct_ui_name(ptr->type);
979                         }
980
981                         /* If searching don't expand RNA entries */
982                         if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) {
983                                 tselem->flag &= ~TSE_CHILDSEARCH;
984                         }
985
986                         iterprop = RNA_struct_iterator_property(ptr->type);
987                         tot = RNA_property_collection_length(ptr, iterprop);
988                         CLAMP_MAX(tot, tot_limit);
989
990                         /* auto open these cases */
991                         if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) {
992                                 if (!tselem->used) {
993                                         tselem->flag &= ~TSE_CLOSED;
994                                 }
995                         }
996
997                         if (TSELEM_OPEN(tselem, soops)) {
998                                 for (a = 0; a < tot; a++) {
999                                         RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
1000                                         if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
1001                                                 outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
1002                                         }
1003                                 }
1004                         }
1005                         else if (tot) {
1006                                 te->flag |= TE_LAZY_CLOSED;
1007                         }
1008
1009                         te->rnaptr = *ptr;
1010                 }
1011                 else if (type == TSE_RNA_PROPERTY) {
1012                         /* property */
1013                         iterprop = RNA_struct_iterator_property(ptr->type);
1014                         RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
1015
1016                         prop = propptr.data;
1017                         proptype = RNA_property_type(prop);
1018
1019                         te->name = RNA_property_ui_name(prop);
1020                         te->directdata = prop;
1021                         te->rnaptr = *ptr;
1022
1023                         /* If searching don't expand RNA entries */
1024                         if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) {
1025                                 tselem->flag &= ~TSE_CHILDSEARCH;
1026                         }
1027
1028                         if (proptype == PROP_POINTER) {
1029                                 pptr = RNA_property_pointer_get(ptr, prop);
1030
1031                                 if (pptr.data) {
1032                                         if (TSELEM_OPEN(tselem, soops)) {
1033                                                 outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
1034                                         }
1035                                         else {
1036                                                 te->flag |= TE_LAZY_CLOSED;
1037                                         }
1038                                 }
1039                         }
1040                         else if (proptype == PROP_COLLECTION) {
1041                                 tot = RNA_property_collection_length(ptr, prop);
1042                                 CLAMP_MAX(tot, tot_limit);
1043
1044                                 if (TSELEM_OPEN(tselem, soops)) {
1045                                         for (a = 0; a < tot; a++) {
1046                                                 RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
1047                                                 outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
1048                                         }
1049                                 }
1050                                 else if (tot) {
1051                                         te->flag |= TE_LAZY_CLOSED;
1052                                 }
1053                         }
1054                         else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
1055                                 tot = RNA_property_array_length(ptr, prop);
1056                                 CLAMP_MAX(tot, tot_limit);
1057
1058                                 if (TSELEM_OPEN(tselem, soops)) {
1059                                         for (a = 0; a < tot; a++) {
1060                                                 outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
1061                                         }
1062                                 }
1063                                 else if (tot) {
1064                                         te->flag |= TE_LAZY_CLOSED;
1065                                 }
1066                         }
1067                 }
1068                 else if (type == TSE_RNA_ARRAY_ELEM) {
1069                         char c;
1070
1071                         prop = parent->directdata;
1072
1073                         te->directdata = prop;
1074                         te->rnaptr = *ptr;
1075                         te->index = index;
1076
1077                         c = RNA_property_array_item_char(prop, index);
1078
1079                         te->name = MEM_callocN(sizeof(char) * 20, "OutlinerRNAArrayName");
1080                         if (c) {
1081                                 sprintf((char *)te->name, "  %c", c);
1082                         }
1083                         else {
1084                                 sprintf((char *)te->name, "  %d", index + 1);
1085                         }
1086                         te->flag |= TE_FREE_NAME;
1087                 }
1088         }
1089         else if (type == TSE_KEYMAP) {
1090                 wmKeyMap *km = (wmKeyMap *)idv;
1091                 wmKeyMapItem *kmi;
1092                 char opname[OP_MAX_TYPENAME];
1093
1094                 te->directdata = idv;
1095                 te->name = km->idname;
1096
1097                 if (TSELEM_OPEN(tselem, soops)) {
1098                         int a = 0;
1099
1100                         for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
1101                                 const char *key = WM_key_event_string(kmi->type, false);
1102
1103                                 if (key[0]) {
1104                                         wmOperatorType *ot = NULL;
1105
1106                                         if (kmi->propvalue) {
1107                                                 /* pass */
1108                                         }
1109                                         else {
1110                                                 ot = WM_operatortype_find(kmi->idname, 0);
1111                                         }
1112
1113                                         if (ot || kmi->propvalue) {
1114                                                 TreeElement *ten = outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a);
1115
1116                                                 ten->directdata = kmi;
1117
1118                                                 if (kmi->propvalue) {
1119                                                         ten->name = IFACE_("Modal map, not yet");
1120                                                 }
1121                                                 else {
1122                                                         WM_operator_py_idname(opname, ot->idname);
1123                                                         ten->name = BLI_strdup(opname);
1124                                                         ten->flag |= TE_FREE_NAME;
1125                                                 }
1126                                         }
1127                                 }
1128                         }
1129                 }
1130                 else {
1131                         te->flag |= TE_LAZY_CLOSED;
1132                 }
1133         }
1134
1135         return te;
1136 }
1137
1138 /* ======================================================= */
1139 /* Sequencer mode tree building */
1140
1141 /* Helped function to put duplicate sequence in the same tree. */
1142 static int need_add_seq_dup(Sequence *seq)
1143 {
1144         Sequence *p;
1145
1146         if ((!seq->strip) || (!seq->strip->stripdata)) {
1147                 return 1;
1148         }
1149
1150         /*
1151          * First check backward, if we found a duplicate
1152          * sequence before this, don't need it, just return.
1153          */
1154         p = seq->prev;
1155         while (p) {
1156                 if ((!p->strip) || (!p->strip->stripdata)) {
1157                         p = p->prev;
1158                         continue;
1159                 }
1160
1161                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
1162                         return 2;
1163                 }
1164                 p = p->prev;
1165         }
1166
1167         p = seq->next;
1168         while (p) {
1169                 if ((!p->strip) || (!p->strip->stripdata)) {
1170                         p = p->next;
1171                         continue;
1172                 }
1173
1174                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
1175                         return 0;
1176                 }
1177                 p = p->next;
1178         }
1179         return(1);
1180 }
1181
1182 static void outliner_add_seq_dup(SpaceOutliner *soops, Sequence *seq, TreeElement *te, short index)
1183 {
1184         /* TreeElement *ch; */ /* UNUSED */
1185         Sequence *p;
1186
1187         p = seq;
1188         while (p) {
1189                 if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
1190                         p = p->next;
1191                         continue;
1192                 }
1193
1194                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
1195                         /* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
1196                 }
1197                 p = p->next;
1198         }
1199 }
1200
1201
1202 /* ----------------------------------------------- */
1203
1204 static const char *outliner_idcode_to_plural(short idcode)
1205 {
1206         const char *propname = BKE_idcode_to_name_plural(idcode);
1207         PropertyRNA *prop = RNA_struct_type_find_property(&RNA_BlendData, propname);
1208         return (prop) ? RNA_property_ui_name(prop) : "UNKNOWN";
1209 }
1210
1211 static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type)
1212 {
1213         if (id->lib != lib) {
1214                 return false;
1215         }
1216
1217         if (filter_id_type == ID_GR) {
1218                 /* Don't show child collections of non-scene master collection,
1219                  * they are already shown as children. */
1220                 Collection *collection = (Collection *)id;
1221                 bool has_non_scene_parent = false;
1222
1223                 for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
1224                         if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
1225                                 has_non_scene_parent = true;
1226                         }
1227                 }
1228
1229                 if (has_non_scene_parent) {
1230                         return false;
1231                 }
1232         }
1233
1234         return true;
1235 }
1236
1237 static TreeElement *outliner_add_library_contents(Main *mainvar, SpaceOutliner *soops, ListBase *lb, Library *lib)
1238 {
1239         TreeElement *ten, *tenlib = NULL;
1240         ListBase *lbarray[MAX_LIBARRAY];
1241         int a, tot;
1242         short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0;
1243
1244         if (filter_id_type) {
1245                 lbarray[0] = which_libbase(mainvar, soops->filter_id_type);
1246                 tot = 1;
1247         }
1248         else {
1249                 tot = set_listbasepointers(mainvar, lbarray);
1250         }
1251
1252         for (a = 0; a < tot; a++) {
1253                 if (lbarray[a] && lbarray[a]->first) {
1254                         ID *id = lbarray[a]->first;
1255
1256                         /* check if there's data in current lib */
1257                         for (; id; id = id->next) {
1258                                 if (id->lib == lib) {
1259                                         break;
1260                                 }
1261                         }
1262
1263                         if (id) {
1264                                 if (!tenlib) {
1265                                         /* Create library tree element on demand, depending if there are any datablocks. */
1266                                         if (lib) {
1267                                                 tenlib = outliner_add_element(soops, lb, lib, NULL, 0, 0);
1268                                         }
1269                                         else {
1270                                                 tenlib = outliner_add_element(soops, lb, mainvar, NULL, TSE_ID_BASE, 0);
1271                                                 tenlib->name = IFACE_("Current File");
1272                                         }
1273                                 }
1274
1275                                 /* Create datablock list parent element on demand. */
1276                                 if (filter_id_type) {
1277                                         ten = tenlib;
1278                                 }
1279                                 else {
1280                                         ten = outliner_add_element(soops, &tenlib->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
1281                                         ten->directdata = lbarray[a];
1282                                         ten->name = outliner_idcode_to_plural(GS(id->name));
1283                                 }
1284
1285                                 for (id = lbarray[a]->first; id; id = id->next) {
1286                                         if (outliner_library_id_show(lib, id, filter_id_type)) {
1287                                                 outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
1288                                         }
1289                                 }
1290                         }
1291                 }
1292         }
1293
1294         return tenlib;
1295 }
1296
1297 static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOutliner *soops)
1298 {
1299         TreeElement *ten;
1300         ListBase *lbarray[MAX_LIBARRAY];
1301         int a, tot;
1302         short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0;
1303
1304         if (filter_id_type) {
1305                 lbarray[0] = which_libbase(mainvar, soops->filter_id_type);
1306                 tot = 1;
1307         }
1308         else {
1309                 tot = set_listbasepointers(mainvar, lbarray);
1310         }
1311
1312         for (a = 0; a < tot; a++) {
1313                 if (lbarray[a] && lbarray[a]->first) {
1314                         ID *id = lbarray[a]->first;
1315
1316                         /* check if there are any datablocks of this type which are orphans */
1317                         for (; id; id = id->next) {
1318                                 if (ID_REAL_USERS(id) <= 0) {
1319                                         break;
1320                                 }
1321                         }
1322
1323                         if (id) {
1324                                 /* header for this type of datablock */
1325                                 if (filter_id_type) {
1326                                         ten = NULL;
1327                                 }
1328                                 else {
1329                                         ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
1330                                         ten->directdata = lbarray[a];
1331                                         ten->name = outliner_idcode_to_plural(GS(id->name));
1332                                 }
1333
1334                                 /* add the orphaned datablocks - these will not be added with any subtrees attached */
1335                                 for (id = lbarray[a]->first; id; id = id->next) {
1336                                         if (ID_REAL_USERS(id) <= 0) {
1337                                                 outliner_add_element(soops, (ten) ? &ten->subtree : &soops->tree, id, ten, 0, 0);
1338                                         }
1339                                 }
1340                         }
1341                 }
1342         }
1343 }
1344
1345 static void outliner_add_layer_collection_objects(
1346         SpaceOutliner *soops, ListBase *tree, ViewLayer *layer,
1347         LayerCollection *lc, TreeElement *ten)
1348 {
1349         for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
1350                 Base *base = BKE_view_layer_base_find(layer, cob->ob);
1351                 TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0);
1352                 te_object->directdata = base;
1353
1354                 if (!(base->flag & BASE_VISIBLE)) {
1355                         te_object->flag |= TE_DISABLED;
1356                 }
1357         }
1358 }
1359
1360 static void outliner_add_layer_collections_recursive(
1361         SpaceOutliner *soops, ListBase *tree, ViewLayer *layer,
1362         ListBase *layer_collections, TreeElement *parent_ten,
1363         const bool show_objects)
1364 {
1365         for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) {
1366                 ID *id = &lc->collection->id;
1367                 TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0);
1368
1369                 ten->name = id->name + 2;
1370                 ten->directdata = lc;
1371
1372                 /* Open by default. */
1373                 TreeStoreElem *tselem = TREESTORE(ten);
1374                 if (!tselem->used) {
1375                         tselem->flag &= ~TSE_CLOSED;
1376                 }
1377
1378                 const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
1379                 if (exclude ||
1380                     ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0))
1381                 {
1382                         ten->flag |= TE_DISABLED;
1383                 }
1384
1385                 outliner_add_layer_collections_recursive(soops, &ten->subtree, layer, &lc->layer_collections, ten, show_objects);
1386                 if (!exclude && show_objects) {
1387                         outliner_add_layer_collection_objects(soops, &ten->subtree, layer, lc, ten);
1388                 }
1389         }
1390 }
1391
1392 static void outliner_add_view_layer(SpaceOutliner *soops, ListBase *tree, TreeElement *parent,
1393                                     ViewLayer *layer, const bool show_objects)
1394 {
1395         /* First layer collection is for master collection, don't show it. */
1396         LayerCollection *lc = layer->layer_collections.first;
1397         if (lc == NULL) {
1398                 return;
1399         }
1400
1401         outliner_add_layer_collections_recursive(soops, tree, layer, &lc->layer_collections, parent, show_objects);
1402         if (show_objects) {
1403                 outliner_add_layer_collection_objects(soops, tree, layer, lc, parent);
1404         }
1405 }
1406
1407 BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
1408 {
1409         te->name = BKE_collection_ui_name_get(collection);
1410         te->directdata = collection;
1411 }
1412
1413 BLI_INLINE void outliner_add_collection_objects(
1414         SpaceOutliner *soops, ListBase *tree, Collection *collection, TreeElement *parent)
1415 {
1416         for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
1417                 outliner_add_element(soops, tree, cob->ob, parent, 0, 0);
1418         }
1419 }
1420
1421 static TreeElement *outliner_add_collection_recursive(
1422         SpaceOutliner *soops, Collection *collection, TreeElement *ten)
1423 {
1424         outliner_add_collection_init(ten, collection);
1425
1426         for (CollectionChild *child = collection->children.first; child; child = child->next) {
1427                 outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0);
1428         }
1429
1430         if (soops->outlinevis != SO_SCENES) {
1431                 outliner_add_collection_objects(soops, &ten->subtree, collection, ten);
1432         }
1433
1434         return ten;
1435 }
1436
1437 /* ======================================================= */
1438 /* Generic Tree Building helpers - order these are called is top to bottom */
1439
1440 /* Hierarchy --------------------------------------------- */
1441
1442 /* make sure elements are correctly nested */
1443 static void outliner_make_object_parent_hierarchy(ListBase *lb)
1444 {
1445         TreeElement *te, *ten, *tep;
1446         TreeStoreElem *tselem;
1447
1448         /* build hierarchy */
1449         // XXX also, set extents here...
1450         te = lb->first;
1451         while (te) {
1452                 ten = te->next;
1453                 tselem = TREESTORE(te);
1454
1455                 if (tselem->type == 0 && te->idcode == ID_OB) {
1456                         Object *ob = (Object *)tselem->id;
1457                         if (ob->parent && ob->parent->id.newid) {
1458                                 BLI_remlink(lb, te);
1459                                 tep = (TreeElement *)ob->parent->id.newid;
1460                                 BLI_addtail(&tep->subtree, te);
1461                                 // set correct parent pointers
1462                                 for (te = tep->subtree.first; te; te = te->next) {
1463                                         te->parent = tep;
1464                                 }
1465                         }
1466                 }
1467                 te = ten;
1468         }
1469 }
1470
1471 /* Sorting ------------------------------------------------------ */
1472
1473 typedef struct tTreeSort {
1474         TreeElement *te;
1475         ID *id;
1476         const char *name;
1477         short idcode;
1478 } tTreeSort;
1479
1480 /* alphabetical comparator, tryping to put objects first */
1481 static int treesort_alpha_ob(const void *v1, const void *v2)
1482 {
1483         const tTreeSort *x1 = v1, *x2 = v2;
1484         int comp;
1485
1486         /* first put objects last (hierarchy) */
1487         comp = (x1->idcode == ID_OB);
1488         if (x2->idcode == ID_OB) {
1489                 comp += 2;
1490         }
1491
1492         if (comp == 1) {
1493                 return 1;
1494         }
1495         else if (comp == 2) {
1496                 return -1;
1497         }
1498         else if (comp == 3) {
1499                 comp = strcmp(x1->name, x2->name);
1500
1501                 if (comp > 0) {
1502                         return 1;
1503                 }
1504                 else if (comp < 0) {
1505                         return -1;
1506                 }
1507                 return 0;
1508         }
1509         return 0;
1510 }
1511
1512 /* alphabetical comparator */
1513 static int treesort_alpha(const void *v1, const void *v2)
1514 {
1515         const tTreeSort *x1 = v1, *x2 = v2;
1516         int comp;
1517
1518         comp = strcmp(x1->name, x2->name);
1519
1520         if (comp > 0) {
1521                 return 1;
1522         }
1523         else if (comp < 0) {
1524                 return -1;
1525         }
1526         return 0;
1527 }
1528
1529
1530 /* this is nice option for later? doesn't look too useful... */
1531 #if 0
1532 static int treesort_obtype_alpha(const void *v1, const void *v2)
1533 {
1534         const tTreeSort *x1 = v1, *x2 = v2;
1535
1536         /* first put objects last (hierarchy) */
1537         if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
1538                 return 1;
1539         }
1540         else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
1541                 return -1;
1542         }
1543         else {
1544                 /* 2nd we check ob type */
1545                 if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
1546                         if      (((Object *)x1->id)->type > ((Object *)x2->id)->type) return  1;
1547                         else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
1548                         else return 0;
1549                 }
1550                 else {
1551                         int comp = strcmp(x1->name, x2->name);
1552
1553                         if      (comp > 0) return  1;
1554                         else if (comp < 0) return -1;
1555                         return 0;
1556                 }
1557         }
1558 }
1559 #endif
1560
1561 /* sort happens on each subtree individual */
1562 static void outliner_sort(ListBase *lb)
1563 {
1564         TreeElement *te;
1565         TreeStoreElem *tselem;
1566
1567         te = lb->last;
1568         if (te == NULL) {
1569                 return;
1570         }
1571         tselem = TREESTORE(te);
1572
1573         /* sorting rules; only object lists, ID lists, or deformgroups */
1574         if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) {
1575                 int totelem = BLI_listbase_count(lb);
1576
1577                 if (totelem > 1) {
1578                         tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
1579                         tTreeSort *tp = tear;
1580                         int skip = 0;
1581
1582                         for (te = lb->first; te; te = te->next, tp++) {
1583                                 tselem = TREESTORE(te);
1584                                 tp->te = te;
1585                                 tp->name = te->name;
1586                                 tp->idcode = te->idcode;
1587
1588                                 if (tselem->type && tselem->type != TSE_DEFGROUP) {
1589                                         tp->idcode = 0;  // don't sort this
1590                                 }
1591                                 if (tselem->type == TSE_ID_BASE) {
1592                                         tp->idcode = 1; // do sort this
1593                                 }
1594
1595                                 tp->id = tselem->id;
1596                         }
1597
1598                         /* just sort alphabetically */
1599                         if (tear->idcode == 1) {
1600                                 qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
1601                         }
1602                         else {
1603                                 /* keep beginning of list */
1604                                 for (tp = tear, skip = 0; skip < totelem; skip++, tp++) {
1605                                         if (tp->idcode) {
1606                                                 break;
1607                                         }
1608                                 }
1609
1610                                 if (skip < totelem) {
1611                                         qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
1612                                 }
1613                         }
1614
1615                         BLI_listbase_clear(lb);
1616                         tp = tear;
1617                         while (totelem--) {
1618                                 BLI_addtail(lb, tp->te);
1619                                 tp++;
1620                         }
1621                         MEM_freeN(tear);
1622                 }
1623         }
1624
1625         for (te = lb->first; te; te = te->next) {
1626                 outliner_sort(&te->subtree);
1627         }
1628 }
1629
1630 /* Filtering ----------------------------------------------- */
1631
1632 typedef struct OutlinerTreeElementFocus {
1633         TreeStoreElem *tselem;
1634         int ys;
1635 } OutlinerTreeElementFocus;
1636
1637 /**
1638  * Bring the outliner scrolling back to where it was in relation to the original focus element
1639  * Caller is expected to handle redrawing of ARegion.
1640  */
1641 static void outliner_restore_scrolling_position(SpaceOutliner *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
1642 {
1643         View2D *v2d = &ar->v2d;
1644         int ytop;
1645
1646         if (focus->tselem != NULL) {
1647                 outliner_set_coordinates(ar, soops);
1648
1649                 TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem);
1650
1651                 if (te_new != NULL) {
1652                         int ys_new, ys_old;
1653
1654                         ys_new = te_new->ys;
1655                         ys_old = focus->ys;
1656
1657                         ytop = v2d->cur.ymax + (ys_new - ys_old) -1;
1658                         if (ytop > 0) {
1659                                 ytop = 0;
1660                         }
1661
1662                         v2d->cur.ymax = (float)ytop;
1663                         v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
1664                 }
1665                 else {
1666                         return;
1667                 }
1668         }
1669 }
1670
1671 static bool test_collection_callback(TreeElement *te)
1672 {
1673         return outliner_is_collection_tree_element(te);
1674 }
1675
1676 static bool test_object_callback(TreeElement *te)
1677 {
1678         TreeStoreElem *tselem = TREESTORE(te);
1679         return ((tselem->type == 0) && (te->idcode == ID_OB));
1680 }
1681
1682 /**
1683  * See if TreeElement or any of its children pass the callback_test.
1684  */
1685 static TreeElement *outliner_find_first_desired_element_at_y_recursive(
1686         const SpaceOutliner *soops,
1687         TreeElement *te,
1688         const float limit,
1689         bool (*callback_test)(TreeElement *))
1690 {
1691         if (callback_test(te)) {
1692                 return te;
1693         }
1694
1695         if (TSELEM_OPEN(te->store_elem, soops)) {
1696                 TreeElement *te_iter, *te_sub;
1697                 for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
1698                         te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test);
1699                         if (te_sub != NULL) {
1700                                 return te_sub;
1701                         }
1702                 }
1703         }
1704
1705         return NULL;
1706 }
1707
1708 /**
1709  * Find the first element that passes a test starting from a reference vertical coordinate
1710  *
1711  * If the element that is in the position is not what we are looking for, keep looking for its
1712  * children, siblings, and eventually, aunts, cousins, distant families, ... etc.
1713  *
1714  * Basically we keep going up and down the outliner tree from that point forward, until we find
1715  * what we are looking for. If we are past the visible range and we can't find a valid element
1716  * we return NULL.
1717  */
1718 static TreeElement *outliner_find_first_desired_element_at_y(
1719         const SpaceOutliner *soops,
1720         const float view_co,
1721         const float view_co_limit)
1722 {
1723         TreeElement *te, *te_sub;
1724         te = outliner_find_item_at_y(soops, &soops->tree, view_co);
1725
1726         bool (*callback_test)(TreeElement *);
1727         if ((soops->outlinevis == SO_VIEW_LAYER) &&
1728              (soops->filter & SO_FILTER_NO_COLLECTION))
1729         {
1730                 callback_test = test_object_callback;
1731         }
1732         else {
1733                 callback_test = test_collection_callback;
1734         }
1735
1736         while (te != NULL) {
1737                 te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test);
1738                 if (te_sub != NULL) {
1739                         /* Skip the element if it was not visible to start with. */
1740                         if (te->ys + UI_UNIT_Y > view_co_limit) {
1741                                 return te_sub;
1742                         }
1743                         else {
1744                                 return NULL;
1745                         }
1746                 }
1747
1748                 if (te->next) {
1749                         te = te->next;
1750                         continue;
1751                 }
1752
1753                 if (te->parent == NULL) {
1754                         break;
1755                 }
1756
1757                 while (te->parent) {
1758                         if (te->parent->next) {
1759                                 te = te->parent->next;
1760                                 break;
1761                         }
1762                         te = te->parent;
1763                 }
1764         }
1765
1766         return NULL;
1767 }
1768
1769 /**
1770  * Store information of current outliner scrolling status to be restored later
1771  *
1772  * Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus
1773  * struct to retrieve this element later to make sure it is in the same original position as before filtering
1774  */
1775 static void outliner_store_scrolling_position(SpaceOutliner *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
1776 {
1777         TreeElement *te;
1778         float limit = ar->v2d.cur.ymin;
1779
1780         outliner_set_coordinates(ar, soops);
1781
1782         te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit);
1783
1784         if (te != NULL) {
1785                 focus->tselem = TREESTORE(te);
1786                 focus->ys = te->ys;
1787         }
1788         else {
1789                 focus->tselem = NULL;
1790         }
1791 }
1792
1793 static int outliner_exclude_filter_get(SpaceOutliner *soops)
1794 {
1795         int exclude_filter = soops->filter & ~SO_FILTER_OB_STATE;
1796
1797         if (soops->search_string[0] != 0) {
1798                 exclude_filter |= SO_FILTER_SEARCH;
1799         }
1800         else {
1801                 exclude_filter &= ~SO_FILTER_SEARCH;
1802         }
1803
1804         /* Let's have this for the collection options at first. */
1805         if (!SUPPORT_FILTER_OUTLINER(soops)) {
1806                 return (exclude_filter & SO_FILTER_SEARCH);
1807         }
1808
1809         if (soops->filter & SO_FILTER_NO_OBJECT) {
1810                 exclude_filter |= SO_FILTER_OB_TYPE;
1811         }
1812
1813         switch (soops->filter_state) {
1814                 case SO_FILTER_OB_VISIBLE:
1815                         exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
1816                         break;
1817                 case SO_FILTER_OB_SELECTED:
1818                         exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
1819                         break;
1820                 case SO_FILTER_OB_ACTIVE:
1821                         exclude_filter |= SO_FILTER_OB_STATE_ACTIVE;
1822                         break;
1823         }
1824
1825         return exclude_filter;
1826 }
1827
1828 static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter)
1829 {
1830         if ((exclude_filter & SO_FILTER_ANY) == 0) {
1831                 return true;
1832         }
1833
1834         TreeStoreElem *tselem = TREESTORE(te);
1835         if ((tselem->type == 0) && (te->idcode == ID_OB)) {
1836                 if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) {
1837                         return false;
1838                 }
1839
1840                 Object *ob = (Object *)tselem->id;
1841                 Base *base = (Base *)te->directdata;
1842                 BLI_assert((base == NULL) || (base->object == ob));
1843
1844                 if (exclude_filter & SO_FILTER_OB_TYPE) {
1845                         switch (ob->type) {
1846                                 case OB_MESH:
1847                                         if (exclude_filter & SO_FILTER_NO_OB_MESH) {
1848                                                 return false;
1849                                         }
1850                                         break;
1851                                 case OB_ARMATURE:
1852                                         if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) {
1853                                                 return false;
1854                                         }
1855                                         break;
1856                                 case OB_EMPTY:
1857                                         if (exclude_filter & SO_FILTER_NO_OB_EMPTY) {
1858                                                 return false;
1859                                         }
1860                                         break;
1861                                 case OB_LAMP:
1862                                         if (exclude_filter & SO_FILTER_NO_OB_LAMP) {
1863                                                 return false;
1864                                         }
1865                                         break;
1866                                 case OB_CAMERA:
1867                                         if (exclude_filter & SO_FILTER_NO_OB_CAMERA) {
1868                                                 return false;
1869                                         }
1870                                         break;
1871                                 default:
1872                                         if (exclude_filter & SO_FILTER_NO_OB_OTHERS) {
1873                                                 return false;
1874                                         }
1875                                         break;
1876                         }
1877                 }
1878
1879                 if (exclude_filter & SO_FILTER_OB_STATE) {
1880                         if (base == NULL) {
1881                                 base = BKE_view_layer_base_find(view_layer, ob);
1882
1883                                 if (base == NULL) {
1884                                         return false;
1885                                 }
1886                         }
1887
1888                         if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
1889                                 if ((base->flag & BASE_VISIBLE) == 0) {
1890                                         return false;
1891                                 }
1892                         }
1893                         else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
1894                                 if ((base->flag & BASE_SELECTED) == 0) {
1895                                         return false;
1896                                 }
1897                         }
1898                         else {
1899                                 BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
1900                                 if (base != BASACT(view_layer)) {
1901                                         return false;
1902                                 }
1903                         }
1904                 }
1905
1906                 if ((te->parent != NULL) &&
1907                     (TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB))
1908                 {
1909                         if (exclude_filter & SO_FILTER_NO_CHILDREN) {
1910                                 return false;
1911                         }
1912                 }
1913         }
1914         else if (te->parent != NULL &&
1915                  TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB)
1916         {
1917                 if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
1918                         return false;
1919                 }
1920         }
1921
1922         return true;
1923 }
1924
1925 static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
1926 {
1927         int fn_flag = 0;
1928
1929         if ((flags & SO_FIND_CASE_SENSITIVE) == 0) {
1930                 fn_flag |= FNM_CASEFOLD;
1931         }
1932
1933         return fnmatch(name, te->name, fn_flag) == 0;
1934 }
1935
1936 static int outliner_filter_subtree(
1937         SpaceOutliner *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter)
1938 {
1939         TreeElement *te, *te_next;
1940         TreeStoreElem *tselem;
1941
1942         for (te = lb->first; te; te = te_next) {
1943                 te_next = te->next;
1944
1945                 if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
1946                         outliner_free_tree_element(te, lb);
1947                         continue;
1948                 }
1949                 else if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
1950                         /* Filter subtree too. */
1951                         outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
1952                         continue;
1953                 }
1954
1955                 if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
1956                         /* item isn't something we're looking for, but...
1957                          * - if the subtree is expanded, check if there are any matches that can be easily found
1958                          *     so that searching for "cu" in the default scene will still match the Cube
1959                          * - otherwise, we can't see within the subtree and the item doesn't match,
1960                          *     so these can be safely ignored (i.e. the subtree can get freed)
1961                          */
1962                         tselem = TREESTORE(te);
1963
1964                         /* flag as not a found item */
1965                         tselem->flag &= ~TSE_SEARCHMATCH;
1966
1967                         if ((!TSELEM_OPEN(tselem, soops)) ||
1968                             outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0)
1969                         {
1970                                 outliner_free_tree_element(te, lb);
1971                         }
1972                 }
1973                 else {
1974                         tselem = TREESTORE(te);
1975
1976                         /* flag as a found item - we can then highlight it */
1977                         tselem->flag |= TSE_SEARCHMATCH;
1978
1979                         /* filter subtree too */
1980                         outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
1981                 }
1982         }
1983
1984         /* if there are still items in the list, that means that there were still some matches */
1985         return (BLI_listbase_is_empty(lb) == false);
1986 }
1987
1988 static void outliner_filter_tree(SpaceOutliner *soops, ViewLayer *view_layer)
1989 {
1990         char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2];
1991         char *search_string;
1992
1993         const int exclude_filter = outliner_exclude_filter_get(soops);
1994
1995         if (exclude_filter == 0) {
1996                 return;
1997         }
1998
1999         if (soops->search_flags & SO_FIND_COMPLETE) {
2000                 search_string = soops->search_string;
2001         }
2002         else {
2003                 /* Implicitly add heading/trailing wildcards if needed. */
2004                 BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
2005                 search_string = search_buff;
2006         }
2007
2008         outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter);
2009 }
2010
2011 /* ======================================================= */
2012 /* Main Tree Building API */
2013
2014 /* Main entry point for building the tree data-structure that the outliner represents */
2015 // TODO: split each mode into its own function?
2016 void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, ARegion *ar)
2017 {
2018         TreeElement *te = NULL, *ten;
2019         TreeStoreElem *tselem;
2020         /* on first view, we open scenes */
2021         int show_opened = !soops->treestore || !BLI_mempool_len(soops->treestore);
2022
2023         /* Are we looking for something - we want to tag parents to filter child matches
2024          * - NOT in datablocks view - searching all datablocks takes way too long to be useful
2025          * - this variable is only set once per tree build */
2026         if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATA_API) {
2027                 soops->search_flags |= SO_SEARCH_RECURSIVE;
2028         }
2029         else {
2030                 soops->search_flags &= ~SO_SEARCH_RECURSIVE;
2031         }
2032
2033         if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD) && soops->treestore) {
2034                 soops->storeflag &= ~SO_TREESTORE_REBUILD;
2035                 BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
2036         }
2037
2038         if (ar->do_draw & RGN_DRAW_NO_REBUILD) {
2039                 return;
2040         }
2041
2042         OutlinerTreeElementFocus focus;
2043         outliner_store_scrolling_position(soops, ar, &focus);
2044
2045         outliner_free_tree(&soops->tree);
2046         outliner_storage_cleanup(soops);
2047
2048         /* options */
2049         if (soops->outlinevis == SO_LIBRARIES) {
2050                 Library *lib;
2051
2052                 /* current file first - mainvar provides tselem with unique pointer - not used */
2053                 ten = outliner_add_library_contents(mainvar, soops, &soops->tree, NULL);
2054                 if (ten) {
2055                         tselem = TREESTORE(ten);
2056                         if (!tselem->used) {
2057                                 tselem->flag &= ~TSE_CLOSED;
2058                         }
2059                 }
2060
2061                 for (lib = mainvar->libraries.first; lib; lib = lib->id.next) {
2062                         ten = outliner_add_library_contents(mainvar, soops, &soops->tree, lib);
2063                         if (ten) {
2064                                 lib->id.newid = (ID *)ten;
2065                         }
2066
2067                 }
2068                 /* make hierarchy */
2069                 ten = soops->tree.first;
2070                 if (ten != NULL) {
2071                         ten = ten->next;  /* first one is main */
2072                         while (ten) {
2073                                 TreeElement *nten = ten->next, *par;
2074                                 tselem = TREESTORE(ten);
2075                                 lib = (Library *)tselem->id;
2076                                 if (lib && lib->parent) {
2077                                         par = (TreeElement *)lib->parent->id.newid;
2078                                         if (tselem->id->tag & LIB_TAG_INDIRECT) {
2079                                                 /* Only remove from 'first level' if lib is not also directly used. */
2080                                                 BLI_remlink(&soops->tree, ten);
2081                                                 BLI_addtail(&par->subtree, ten);
2082                                                 ten->parent = par;
2083                                         }
2084                                         else {
2085                                                 /* Else, make a new copy of the libtree for our parent. */
2086                                                 TreeElement *dupten = outliner_add_library_contents(mainvar, soops, &par->subtree, lib);
2087                                                 if (dupten) {
2088                                                         dupten->parent = par;
2089                                                 }
2090                                         }
2091                                 }
2092                                 ten = nten;
2093                         }
2094                 }
2095                 /* restore newid pointers */
2096                 for (lib = mainvar->libraries.first; lib; lib = lib->id.next) {
2097                         lib->id.newid = NULL;
2098                 }
2099
2100         }
2101         else if (soops->outlinevis == SO_SCENES) {
2102                 Scene *sce;
2103                 for (sce = mainvar->scenes.first; sce; sce = sce->id.next) {
2104                         te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
2105                         tselem = TREESTORE(te);
2106
2107                         if (sce == scene && show_opened) {
2108                                 tselem->flag &= ~TSE_CLOSED;
2109                         }
2110
2111                         outliner_make_object_parent_hierarchy(&te->subtree);
2112                 }
2113         }
2114         else if (soops->outlinevis == SO_SEQUENCE) {
2115                 Sequence *seq;
2116                 Editing *ed = BKE_sequencer_editing_get(scene, false);
2117                 int op;
2118
2119                 if (ed == NULL) {
2120                         return;
2121                 }
2122
2123                 seq = ed->seqbasep->first;
2124                 if (!seq) {
2125                         return;
2126                 }
2127
2128                 while (seq) {
2129                         op = need_add_seq_dup(seq);
2130                         if (op == 1) {
2131                                 /* ten = */ outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE, 0);
2132                         }
2133                         else if (op == 0) {
2134                                 ten = outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0);
2135                                 outliner_add_seq_dup(soops, seq, ten, 0);
2136                         }
2137                         seq = seq->next;
2138                 }
2139         }
2140         else if (soops->outlinevis == SO_DATA_API) {
2141                 PointerRNA mainptr;
2142
2143                 RNA_main_pointer_create(mainvar, &mainptr);
2144
2145                 ten = outliner_add_element(soops, &soops->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1);
2146
2147                 if (show_opened) {
2148                         tselem = TREESTORE(ten);
2149                         tselem->flag &= ~TSE_CLOSED;
2150                 }
2151         }
2152         else if (soops->outlinevis == SO_ID_ORPHANS) {
2153                 outliner_add_orphaned_datablocks(mainvar, soops);
2154         }
2155         else if (soops->outlinevis == SO_VIEW_LAYER) {
2156                 if (soops->filter & SO_FILTER_NO_COLLECTION) {
2157                         /* Show objects in the view layer. */
2158                         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
2159                                 TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
2160                                 te_object->directdata = base;
2161                         }
2162
2163                         outliner_make_object_parent_hierarchy(&soops->tree);
2164                 }
2165                 else {
2166                         /* Show collections in the view layer. */
2167                         ten = outliner_add_element(soops, &soops->tree, scene, NULL, TSE_VIEW_COLLECTION_BASE, 0);
2168                         ten->name = IFACE_("Scene Collection");
2169                         TREESTORE(ten)->flag &= ~TSE_CLOSED;
2170
2171                         bool show_objects = !(soops->filter & SO_FILTER_NO_OBJECT);
2172                         outliner_add_view_layer(soops, &ten->subtree, ten, view_layer, show_objects);
2173                 }
2174         }
2175
2176         if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
2177                 outliner_sort(&soops->tree);
2178         }
2179
2180         outliner_filter_tree(soops, view_layer);
2181         outliner_restore_scrolling_position(soops, ar, &focus);
2182
2183         BKE_main_id_clear_newpoins(mainvar);
2184 }