Blender  V2.93
outliner_tree.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <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_cachefile_types.h"
32 #include "DNA_camera_types.h"
33 #include "DNA_collection_types.h"
34 #include "DNA_constraint_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_hair_types.h"
38 #include "DNA_key_types.h"
39 #include "DNA_light_types.h"
40 #include "DNA_lightprobe_types.h"
41 #include "DNA_linestyle_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_mesh_types.h"
44 #include "DNA_meta_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_particle_types.h"
47 #include "DNA_pointcloud_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_sequence_types.h"
50 #include "DNA_shader_fx_types.h"
51 #include "DNA_simulation_types.h"
52 #include "DNA_speaker_types.h"
53 #include "DNA_volume_types.h"
54 #include "DNA_world_types.h"
55 
56 #include "BLI_blenlib.h"
57 #include "BLI_fnmatch.h"
58 #include "BLI_listbase.h"
59 #include "BLI_mempool.h"
60 #include "BLI_utildefines.h"
61 
62 #include "BLT_translation.h"
63 
64 #include "BKE_armature.h"
65 #include "BKE_layer.h"
66 #include "BKE_lib_id.h"
67 #include "BKE_main.h"
68 #include "BKE_modifier.h"
69 #include "BKE_outliner_treehash.h"
70 
71 #include "ED_screen.h"
72 
73 #include "RNA_access.h"
74 
75 #include "UI_interface.h"
76 
77 #include "outliner_intern.h"
78 #include "tree/tree_display.h"
79 #include "tree/tree_element.h"
80 
81 #ifdef WIN32
82 # include "BLI_math_base.h" /* M_PI */
83 #endif
84 
85 /* prototypes */
86 static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
87 
88 /* ********************************************************* */
89 /* Persistent Data */
90 
91 static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
92 {
93  BLI_mempool *ts = space_outliner->treestore;
94 
95  if (ts) {
96  TreeStoreElem *tselem;
97  int unused = 0;
98 
99  /* each element used once, for ID blocks with more users to have each a treestore */
100  BLI_mempool_iter iter;
101 
102  BLI_mempool_iternew(ts, &iter);
103  while ((tselem = BLI_mempool_iterstep(&iter))) {
104  tselem->used = 0;
105  }
106 
107  /* cleanup only after reading file or undo step, and always for
108  * RNA data-blocks view in order to save memory */
109  if (space_outliner->storeflag & SO_TREESTORE_CLEANUP) {
110  space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP;
111 
112  BLI_mempool_iternew(ts, &iter);
113  while ((tselem = BLI_mempool_iterstep(&iter))) {
114  if (tselem->id == NULL) {
115  unused++;
116  }
117  }
118 
119  if (unused) {
120  if (BLI_mempool_len(ts) == unused) {
122  space_outliner->treestore = NULL;
123  if (space_outliner->runtime->treehash) {
124  BKE_outliner_treehash_free(space_outliner->runtime->treehash);
125  space_outliner->runtime->treehash = NULL;
126  }
127  }
128  else {
129  TreeStoreElem *tsenew;
131  sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER);
132  BLI_mempool_iternew(ts, &iter);
133  while ((tselem = BLI_mempool_iterstep(&iter))) {
134  if (tselem->id) {
135  tsenew = BLI_mempool_alloc(new_ts);
136  *tsenew = *tselem;
137  }
138  }
140  space_outliner->treestore = new_ts;
141  if (space_outliner->runtime->treehash) {
142  /* update hash table to fix broken pointers */
144  space_outliner->treestore);
145  }
146  }
147  }
148  }
149  else if (space_outliner->runtime->treehash) {
151  }
152  }
153 }
154 
155 static void check_persistent(
156  SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
157 {
158  if (space_outliner->treestore == NULL) {
159  /* if treestore was not created in readfile.c, create it here */
160  space_outliner->treestore = BLI_mempool_create(
161  sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
162  }
163  if (space_outliner->runtime->treehash == NULL) {
165  space_outliner->treestore);
166  }
167 
168  /* find any unused tree element in treestore and mark it as used
169  * (note that there may be multiple unused elements in case of linked objects) */
171  space_outliner->runtime->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(space_outliner->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(space_outliner->runtime->treehash, tselem);
187 }
188 
189 /* ********************************************************* */
190 /* Tree Management */
191 
193 {
196  }
197 }
198 
200 {
201  outliner_free_tree(&space_outliner->tree);
202  outliner_storage_cleanup(space_outliner);
203 }
204 
212 {
213  BLI_assert(BLI_findindex(parent_subtree, element) > -1);
214  BLI_remlink(parent_subtree, element);
215 
216  outliner_free_tree(&element->subtree);
217 
218  if (element->flag & TE_FREE_NAME) {
219  MEM_freeN((void *)element->name);
220  }
223 }
224 
225 /* ********************************************************* */
226 
227 /* -------------------------------------------------------- */
228 
230 {
231  int exclude_flags = outliner_exclude_filter_get(space_outliner);
232  /* Need to rebuild tree to re-apply filter if select/active changed while filtering based on
233  * select/active. */
234  return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
235 }
236 
242 {
243  return ELEM(space_outliner->outlinevis, SO_DATA_API);
244 }
245 
246 /* special handling of hierarchical non-lib data */
247 static void outliner_add_bone(SpaceOutliner *space_outliner,
248  ListBase *lb,
249  ID *id,
250  Bone *curBone,
251  TreeElement *parent,
252  int *a)
253 {
254  TreeElement *te = outliner_add_element(space_outliner, lb, id, parent, TSE_BONE, *a);
255 
256  (*a)++;
257  te->name = curBone->name;
258  te->directdata = curBone;
259 
260  LISTBASE_FOREACH (Bone *, child_bone, &curBone->childbase) {
261  outliner_add_bone(space_outliner, &te->subtree, id, child_bone, te, a);
262  }
263 }
264 
266 {
267  if (adt) {
268  return (adt->action || adt->drivers.first || adt->nla_tracks.first);
269  }
270  return false;
271 }
272 
273 #ifdef WITH_FREESTYLE
274 static void outliner_add_line_styles(SpaceOutliner *space_outliner,
275  ListBase *lb,
276  Scene *sce,
277  TreeElement *te)
278 {
279  ViewLayer *view_layer;
280  FreestyleLineSet *lineset;
281 
282  for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
283  for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
285  if (linestyle) {
287  }
288  }
289  }
290  for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
291  for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
293  if (linestyle) {
294  if (!(linestyle->id.tag & LIB_TAG_DOIT)) {
295  continue;
296  }
298  outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0);
299  }
300  }
301  }
302 }
303 #endif
304 
305 /* Can be inlined if necessary. */
306 static void outliner_add_object_contents(SpaceOutliner *space_outliner,
307  TreeElement *te,
308  TreeStoreElem *tselem,
309  Object *ob)
310 {
311  if (outliner_animdata_test(ob->adt)) {
312  outliner_add_element(space_outliner, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
313  }
314 
315  outliner_add_element(space_outliner,
316  &te->subtree,
317  ob->poselib,
318  te,
319  TSE_SOME_ID,
320  0); /* XXX FIXME.. add a special type for this. */
321 
322  if (ob->proxy && !ID_IS_LINKED(ob)) {
323  outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
324  }
325 
326  outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
327 
328  if (ob->pose) {
329  bArmature *arm = ob->data;
331  space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
332  tenla->name = IFACE_("Pose");
333 
334  /* channels undefined in editmode, but we want the 'tenla' pose icon itself */
335  if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
336  int const_index = 1000; /* ensure unique id for bone constraints */
337  int a;
338  LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) {
340  space_outliner, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
341  ten->name = pchan->name;
342  ten->directdata = pchan;
343  pchan->temp = (void *)ten;
344 
345  if (!BLI_listbase_is_empty(&pchan->constraints)) {
346  /* Object *target; */
348  space_outliner, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
349  tenla1->name = IFACE_("Constraints");
350  /* char *str; */
351 
352  LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
354  space_outliner, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
355 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
356  target = get_constraint_target(con, &str);
357  if (str && str[0]) {
358  ten1->name = str;
359  }
360  else if (target) {
361  ten1->name = target->id.name + 2;
362  }
363  else {
364  ten1->name = con->name;
365  }
366 #endif
367  ten1->name = con->name;
368  ten1->directdata = con;
369  /* possible add all other types links? */
370  }
371  const_index++;
372  }
373  }
374  /* make hierarchy */
375  TreeElement *ten = tenla->subtree.first;
376  while (ten) {
377  TreeElement *nten = ten->next, *par;
378  tselem = TREESTORE(ten);
379  if (tselem->type == TSE_POSE_CHANNEL) {
380  bPoseChannel *pchan = (bPoseChannel *)ten->directdata;
381  if (pchan->parent) {
382  BLI_remlink(&tenla->subtree, ten);
383  par = (TreeElement *)pchan->parent->temp;
384  BLI_addtail(&par->subtree, ten);
385  ten->parent = par;
386  }
387  }
388  ten = nten;
389  }
390  }
391 
392  /* Pose Groups */
393  if (!BLI_listbase_is_empty(&ob->pose->agroups)) {
394  TreeElement *ten_bonegrp = outliner_add_element(
395  space_outliner, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
396  ten_bonegrp->name = IFACE_("Bone Groups");
397 
398  int index;
399  LISTBASE_FOREACH_INDEX (bActionGroup *, agrp, &ob->pose->agroups, index) {
401  space_outliner, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, index);
402  ten->name = agrp->name;
403  ten->directdata = agrp;
404  }
405  }
406  }
407 
408  for (int a = 0; a < ob->totcol; a++) {
409  outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a);
410  }
411 
412  if (!BLI_listbase_is_empty(&ob->constraints)) {
414  space_outliner, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
415  tenla->name = IFACE_("Constraints");
416 
417  int index;
418  LISTBASE_FOREACH_INDEX (bConstraint *, con, &ob->constraints, index) {
420  space_outliner, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, index);
421 #if 0 /* disabled due to constraints system targets recode... code here needs review */
422  target = get_constraint_target(con, &str);
423  if (str && str[0]) {
424  ten->name = str;
425  }
426  else if (target) {
427  ten->name = target->id.name + 2;
428  }
429  else {
430  ten->name = con->name;
431  }
432 #endif
433  ten->name = con->name;
434  ten->directdata = con;
435  /* possible add all other types links? */
436  }
437  }
438 
439  if (!BLI_listbase_is_empty(&ob->modifiers)) {
441  space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
442  ten_mod->name = IFACE_("Modifiers");
443 
444  int index;
445  LISTBASE_FOREACH_INDEX (ModifierData *, md, &ob->modifiers, index) {
447  space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
448  ten->name = md->name;
449  ten->directdata = md;
450 
451  if (md->type == eModifierType_Lattice) {
452  outliner_add_element(space_outliner,
453  &ten->subtree,
454  ((LatticeModifierData *)md)->object,
455  ten,
457  0);
458  }
459  else if (md->type == eModifierType_Curve) {
460  outliner_add_element(space_outliner,
461  &ten->subtree,
462  ((CurveModifierData *)md)->object,
463  ten,
465  0);
466  }
467  else if (md->type == eModifierType_Armature) {
468  outliner_add_element(space_outliner,
469  &ten->subtree,
470  ((ArmatureModifierData *)md)->object,
471  ten,
473  0);
474  }
475  else if (md->type == eModifierType_Hook) {
476  outliner_add_element(space_outliner,
477  &ten->subtree,
478  ((HookModifierData *)md)->object,
479  ten,
481  0);
482  }
483  else if (md->type == eModifierType_ParticleSystem) {
484  ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
485  TreeElement *ten_psys;
486 
487  ten_psys = outliner_add_element(space_outliner, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0);
488  ten_psys->directdata = psys;
489  ten_psys->name = psys->part->id.name + 2;
490  }
491  }
492  }
493 
494  /* Grease Pencil modifiers. */
497  space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
498  ten_mod->name = IFACE_("Modifiers");
499 
500  int index;
503  space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
504  ten->name = md->name;
505  ten->directdata = md;
506 
507  if (md->type == eGpencilModifierType_Armature) {
508  outliner_add_element(space_outliner,
509  &ten->subtree,
510  ((ArmatureGpencilModifierData *)md)->object,
511  ten,
513  0);
514  }
515  else if (md->type == eGpencilModifierType_Hook) {
516  outliner_add_element(space_outliner,
517  &ten->subtree,
518  ((HookGpencilModifierData *)md)->object,
519  ten,
521  0);
522  }
523  else if (md->type == eGpencilModifierType_Lattice) {
524  outliner_add_element(space_outliner,
525  &ten->subtree,
526  ((LatticeGpencilModifierData *)md)->object,
527  ten,
529  0);
530  }
531  }
532  }
533 
534  /* Grease Pencil effects. */
535  if (!BLI_listbase_is_empty(&ob->shader_fx)) {
537  space_outliner, &te->subtree, ob, te, TSE_GPENCIL_EFFECT_BASE, 0);
538  ten_fx->name = IFACE_("Effects");
539 
540  int index;
541  LISTBASE_FOREACH_INDEX (ShaderFxData *, fx, &ob->shader_fx, index) {
543  space_outliner, &ten_fx->subtree, ob, ten_fx, TSE_GPENCIL_EFFECT, index);
544  ten->name = fx->name;
545  ten->directdata = fx;
546 
547  if (fx->type == eShaderFxType_Swirl) {
548  outliner_add_element(space_outliner,
549  &ten->subtree,
550  ((SwirlShaderFxData *)fx)->object,
551  ten,
553  0);
554  }
555  }
556  }
557 
558  /* vertex groups */
559  if (!BLI_listbase_is_empty(&ob->defbase)) {
561  space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
562  tenla->name = IFACE_("Vertex Groups");
563 
564  int index;
565  LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, &ob->defbase, index) {
567  space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index);
568  ten->name = defgroup->name;
569  ten->directdata = defgroup;
570  }
571  }
572 
573  /* duplicated group */
574  if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) {
576  space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0);
577  }
578 }
579 
580 /* Can be inlined if necessary. */
581 static void outliner_add_id_contents(SpaceOutliner *space_outliner,
582  TreeElement *te,
583  TreeStoreElem *tselem,
584  ID *id)
585 {
586  /* tuck pointer back in object, to construct hierarchy */
587  if (GS(id->name) == ID_OB) {
588  id->newid = (ID *)te;
589  }
590 
591  /* expand specific data always */
592  switch (GS(id->name)) {
593  case ID_LI:
594  case ID_SCE:
595  BLI_assert(!"ID type expected to be expanded through new tree-element design");
596  break;
597  case ID_OB: {
598  outliner_add_object_contents(space_outliner, te, tselem, (Object *)id);
599  break;
600  }
601  case ID_ME: {
602  Mesh *me = (Mesh *)id;
603 
604  if (outliner_animdata_test(me->adt)) {
605  outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0);
606  }
607 
608  outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0);
609  for (int a = 0; a < me->totcol; a++) {
610  outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a);
611  }
612  /* could do tfaces with image links, but the images are not grouped nicely.
613  * would require going over all tfaces, sort images in use. etc... */
614  break;
615  }
616  case ID_CU: {
617  Curve *cu = (Curve *)id;
618 
619  if (outliner_animdata_test(cu->adt)) {
620  outliner_add_element(space_outliner, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
621  }
622 
623  for (int a = 0; a < cu->totcol; a++) {
624  outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a);
625  }
626  break;
627  }
628  case ID_MB: {
629  MetaBall *mb = (MetaBall *)id;
630 
631  if (outliner_animdata_test(mb->adt)) {
632  outliner_add_element(space_outliner, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
633  }
634 
635  for (int a = 0; a < mb->totcol; a++) {
636  outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a);
637  }
638  break;
639  }
640  case ID_MA: {
641  Material *ma = (Material *)id;
642  if (outliner_animdata_test(ma->adt)) {
643  outliner_add_element(space_outliner, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
644  }
645  break;
646  }
647  case ID_TE: {
648  Tex *tex = (Tex *)id;
650  outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
651  }
652  outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0);
653  break;
654  }
655  case ID_CA: {
656  Camera *ca = (Camera *)id;
657  if (outliner_animdata_test(ca->adt)) {
658  outliner_add_element(space_outliner, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
659  }
660  break;
661  }
662  case ID_CF: {
663  CacheFile *cache_file = (CacheFile *)id;
664  if (outliner_animdata_test(cache_file->adt)) {
665  outliner_add_element(space_outliner, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
666  }
667 
668  break;
669  }
670  case ID_LA: {
671  Light *la = (Light *)id;
672  if (outliner_animdata_test(la->adt)) {
673  outliner_add_element(space_outliner, &te->subtree, la, te, TSE_ANIM_DATA, 0);
674  }
675  break;
676  }
677  case ID_SPK: {
678  Speaker *spk = (Speaker *)id;
679  if (outliner_animdata_test(spk->adt)) {
680  outliner_add_element(space_outliner, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
681  }
682  break;
683  }
684  case ID_LP: {
685  LightProbe *prb = (LightProbe *)id;
686  if (outliner_animdata_test(prb->adt)) {
687  outliner_add_element(space_outliner, &te->subtree, prb, te, TSE_ANIM_DATA, 0);
688  }
689  break;
690  }
691  case ID_WO: {
692  World *wrld = (World *)id;
693  if (outliner_animdata_test(wrld->adt)) {
694  outliner_add_element(space_outliner, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
695  }
696  break;
697  }
698  case ID_KE: {
699  Key *key = (Key *)id;
700  if (outliner_animdata_test(key->adt)) {
701  outliner_add_element(space_outliner, &te->subtree, key, te, TSE_ANIM_DATA, 0);
702  }
703  break;
704  }
705  case ID_AC: {
706  /* XXX do we want to be exposing the F-Curves here? */
707  /* bAction *act = (bAction *)id; */
708  break;
709  }
710  case ID_AR: {
711  bArmature *arm = (bArmature *)id;
712 
713  if (outliner_animdata_test(arm->adt)) {
714  outliner_add_element(space_outliner, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
715  }
716 
717  if (arm->edbo) {
718  int a = 0;
719  LISTBASE_FOREACH_INDEX (EditBone *, ebone, arm->edbo, a) {
721  space_outliner, &te->subtree, id, te, TSE_EBONE, a);
722  ten->directdata = ebone;
723  ten->name = ebone->name;
724  ebone->temp.p = ten;
725  }
726  /* make hierarchy */
727  TreeElement *ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
728  while (ten) {
729  TreeElement *nten = ten->next, *par;
730  EditBone *ebone = (EditBone *)ten->directdata;
731  if (ebone->parent) {
732  BLI_remlink(&te->subtree, ten);
733  par = ebone->parent->temp.p;
734  BLI_addtail(&par->subtree, ten);
735  ten->parent = par;
736  }
737  ten = nten;
738  }
739  }
740  else {
741  /* do not extend Armature when we have posemode */
742  tselem = TREESTORE(te->parent);
743  if (GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) {
744  /* pass */
745  }
746  else {
747  int a = 0;
748  LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
749  outliner_add_bone(space_outliner, &te->subtree, id, bone, te, &a);
750  }
751  }
752  }
753  break;
754  }
755  case ID_LS: {
757 
759  outliner_add_element(space_outliner, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
760  }
761 
762  for (int a = 0; a < MAX_MTEX; a++) {
763  if (linestyle->mtex[a]) {
764  outliner_add_element(space_outliner, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
765  }
766  }
767  break;
768  }
769  case ID_GD: {
770  bGPdata *gpd = (bGPdata *)id;
771 
772  if (outliner_animdata_test(gpd->adt)) {
773  outliner_add_element(space_outliner, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
774  }
775 
776  /* TODO: base element for layers? */
777  int index = 0;
778  LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl, &gpd->layers) {
779  outliner_add_element(space_outliner, &te->subtree, gpl, te, TSE_GP_LAYER, index);
780  index++;
781  }
782  break;
783  }
784  case ID_GR: {
785  /* Don't expand for instances, creates too many elements. */
786  if (!(te->parent && te->parent->idcode == ID_OB)) {
787  Collection *collection = (Collection *)id;
788  outliner_add_collection_recursive(space_outliner, collection, te);
789  }
790  break;
791  }
792  case ID_HA: {
793  Hair *hair = (Hair *)id;
794  if (outliner_animdata_test(hair->adt)) {
795  outliner_add_element(space_outliner, &te->subtree, hair, te, TSE_ANIM_DATA, 0);
796  }
797  break;
798  }
799  case ID_PT: {
800  PointCloud *pointcloud = (PointCloud *)id;
801  if (outliner_animdata_test(pointcloud->adt)) {
802  outliner_add_element(space_outliner, &te->subtree, pointcloud, te, TSE_ANIM_DATA, 0);
803  }
804  break;
805  }
806  case ID_VO: {
807  Volume *volume = (Volume *)id;
808  if (outliner_animdata_test(volume->adt)) {
809  outliner_add_element(space_outliner, &te->subtree, volume, te, TSE_ANIM_DATA, 0);
810  }
811  break;
812  }
813  case ID_SIM: {
816  outliner_add_element(space_outliner, &te->subtree, simulation, te, TSE_ANIM_DATA, 0);
817  }
818  break;
819  }
820  default:
821  break;
822  }
823 }
824 
833  ListBase *lb,
834  void *idv,
835  TreeElement *parent,
836  short type,
837  short index)
838 {
839  ID *id = idv;
840 
842  id = ((PointerRNA *)idv)->owner_id;
843  if (!id) {
844  id = ((PointerRNA *)idv)->data;
845  }
846  }
847  else if (type == TSE_GP_LAYER) {
848  /* idv is the layer its self */
849  id = TREESTORE(parent)->id;
850  }
851 
852  /* exceptions */
853  if (type == TSE_ID_BASE) {
854  /* pass */
855  }
856  else if (id == NULL) {
857  return NULL;
858  }
859 
860  if (type == 0) {
861  /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
863  }
864 
865  TreeElement *te = MEM_callocN(sizeof(TreeElement), __func__);
866  /* add to the visual tree */
867  BLI_addtail(lb, te);
868  /* add to the storage */
869  check_persistent(space_outliner, te, id, type, index);
870  TreeStoreElem *tselem = TREESTORE(te);
871 
872  /* if we are searching for something expand to see child elements */
873  if (SEARCHING_OUTLINER(space_outliner)) {
874  tselem->flag |= TSE_CHILDSEARCH;
875  }
876 
877  te->parent = parent;
878  te->index = index; /* For data arrays. */
879 
880  /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some
881  * support this, eventually this should replace `TreeElement` entirely. */
883  if (te->type) {
884  /* Element types ported to the new design are expected to have their name set at this point! */
885  BLI_assert(te->name != NULL);
886  }
887 
889  /* pass */
890  }
892  /* pass */
893  }
895  /* pass */
896  }
897  else if (type == TSE_GP_LAYER) {
898  /* pass */
899  }
901  /* pass */
902  }
903  else if (type == TSE_ID_BASE) {
904  /* pass */
905  }
906  else if (type == TSE_SOME_ID) {
907  if (!te->type) {
908  BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design");
909  }
910  }
912  if (!te->type) {
913  BLI_assert(!"Expected override types to be ported to new Outliner tree-element design");
914  }
915  }
916  else {
917  /* Other cases must be caught above. */
918  BLI_assert(TSE_IS_REAL_ID(tselem));
919 
920  /* The new type design sets the name already, don't override that here. We need to figure out
921  * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */
922  if (!te->type) {
923  te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */
924  }
925  te->idcode = GS(id->name);
926  }
927 
929  outliner_tree_element_type_expand(te->type, space_outliner);
930  }
931  else if (type == TSE_SOME_ID) {
932  /* ID types not (fully) ported to new design yet. */
933  if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) {
934  outliner_add_id_contents(space_outliner, te, tselem, id);
935  outliner_tree_element_type_post_expand(te->type, space_outliner);
936  }
937  }
938  else if (ELEM(type,
941  TSE_NLA,
944  TSE_GP_LAYER)) {
945  /* Should already use new AbstractTreeElement design. */
946  BLI_assert(0);
947  }
948  else if (type == TSE_SEQUENCE) {
949  Sequence *seq = (Sequence *)idv;
950 
951  /*
952  * The idcode is a little hack, but the outliner
953  * only check te->idcode if te->type is equal to zero,
954  * so this is "safe".
955  */
956  te->idcode = seq->type;
957  te->directdata = seq;
958  te->name = seq->name + 2;
959 
960  if (!(seq->type & SEQ_TYPE_EFFECT)) {
961  /*
962  * This work like the sequence.
963  * If the sequence have a name (not default name)
964  * show it, in other case put the filename.
965  */
966 
967  if (seq->type == SEQ_TYPE_META) {
968  LISTBASE_FOREACH (Sequence *, p, &seq->seqbase) {
969  outliner_add_element(space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
970  }
971  }
972  else {
974  space_outliner, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
975  }
976  }
977  }
978  else if (type == TSE_SEQ_STRIP) {
979  Strip *strip = (Strip *)idv;
980 
981  if (strip->dir[0] != '\0') {
982  te->name = strip->dir;
983  }
984  else {
985  te->name = IFACE_("Strip None");
986  }
987  te->directdata = strip;
988  }
989  else if (type == TSE_SEQUENCE_DUP) {
990  Sequence *seq = (Sequence *)idv;
991 
992  te->idcode = seq->type;
993  te->directdata = seq;
994  te->name = seq->strip->stripdata->name;
995  }
997  PointerRNA *ptr = (PointerRNA *)idv;
998 
999  /* Don't display arrays larger, weak but index is stored as a short,
1000  * also the outliner isn't intended for editing such large data-sets. */
1001  BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!")
1002  const int tot_limit = SHRT_MAX;
1003 
1004  /* we do lazy build, for speed and to avoid infinite recursion */
1005 
1006  if (ptr->data == NULL) {
1007  te->name = IFACE_("(empty)");
1008  }
1009  else if (type == TSE_RNA_STRUCT) {
1010  /* struct */
1012 
1013  if (te->name) {
1014  te->flag |= TE_FREE_NAME;
1015  }
1016  else {
1017  te->name = RNA_struct_ui_name(ptr->type);
1018  }
1019 
1020  /* If searching don't expand RNA entries */
1021  if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
1022  tselem->flag &= ~TSE_CHILDSEARCH;
1023  }
1024 
1026  int tot = RNA_property_collection_length(ptr, iterprop);
1027  CLAMP_MAX(tot, tot_limit);
1028 
1029  /* auto open these cases */
1030  if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) {
1031  if (!tselem->used) {
1032  tselem->flag &= ~TSE_CLOSED;
1033  }
1034  }
1035 
1036  if (TSELEM_OPEN(tselem, space_outliner)) {
1037  for (int a = 0; a < tot; a++) {
1038  PointerRNA propptr;
1039  RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
1040  if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
1042  space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
1043  }
1044  }
1045  }
1046  else if (tot) {
1047  te->flag |= TE_LAZY_CLOSED;
1048  }
1049 
1050  te->rnaptr = *ptr;
1051  }
1052  else if (type == TSE_RNA_PROPERTY) {
1053  /* property */
1054  PointerRNA propptr;
1056  RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
1057 
1058  PropertyRNA *prop = propptr.data;
1059  PropertyType proptype = RNA_property_type(prop);
1060 
1061  te->name = RNA_property_ui_name(prop);
1062  te->directdata = prop;
1063  te->rnaptr = *ptr;
1064 
1065  /* If searching don't expand RNA entries */
1066  if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
1067  tselem->flag &= ~TSE_CHILDSEARCH;
1068  }
1069 
1070  if (proptype == PROP_POINTER) {
1071  PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
1072 
1073  if (pptr.data) {
1074  if (TSELEM_OPEN(tselem, space_outliner)) {
1076  space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
1077  }
1078  else {
1079  te->flag |= TE_LAZY_CLOSED;
1080  }
1081  }
1082  }
1083  else if (proptype == PROP_COLLECTION) {
1084  int tot = RNA_property_collection_length(ptr, prop);
1085  CLAMP_MAX(tot, tot_limit);
1086 
1087  if (TSELEM_OPEN(tselem, space_outliner)) {
1088  for (int a = 0; a < tot; a++) {
1089  PointerRNA pptr;
1090  RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
1092  space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
1093  }
1094  }
1095  else if (tot) {
1096  te->flag |= TE_LAZY_CLOSED;
1097  }
1098  }
1099  else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
1100  int tot = RNA_property_array_length(ptr, prop);
1101  CLAMP_MAX(tot, tot_limit);
1102 
1103  if (TSELEM_OPEN(tselem, space_outliner)) {
1104  for (int a = 0; a < tot; a++) {
1106  space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
1107  }
1108  }
1109  else if (tot) {
1110  te->flag |= TE_LAZY_CLOSED;
1111  }
1112  }
1113  }
1114  else if (type == TSE_RNA_ARRAY_ELEM) {
1115  PropertyRNA *prop = parent->directdata;
1116 
1117  te->directdata = prop;
1118  te->rnaptr = *ptr;
1119  te->index = index;
1120 
1121  char c = RNA_property_array_item_char(prop, index);
1122 
1123  te->name = MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName");
1124  if (c) {
1125  sprintf((char *)te->name, " %c", c);
1126  }
1127  else {
1128  sprintf((char *)te->name, " %d", index + 1);
1129  }
1130  te->flag |= TE_FREE_NAME;
1131  }
1132  }
1133 
1134  return te;
1135 }
1136 
1137 /* ======================================================= */
1138 
1140 {
1141  te->name = BKE_collection_ui_name_get(collection);
1142  te->directdata = collection;
1143 }
1144 
1146  ListBase *tree,
1147  Collection *collection,
1148  TreeElement *parent)
1149 {
1150  LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1151  outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0);
1152  }
1153 }
1154 
1156  Collection *collection,
1157  TreeElement *ten)
1158 {
1159  outliner_add_collection_init(ten, collection);
1160 
1161  LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
1163  space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0);
1164  }
1165 
1166  if (space_outliner->outlinevis != SO_SCENES) {
1167  outliner_add_collection_objects(space_outliner, &ten->subtree, collection, ten);
1168  }
1169 
1170  return ten;
1171 }
1172 
1173 /* ======================================================= */
1174 /* Generic Tree Building helpers - order these are called is top to bottom */
1175 
1176 /* Hierarchy --------------------------------------------- */
1177 
1178 /* make sure elements are correctly nested */
1180 {
1181  /* build hierarchy */
1182  /* XXX also, set extents here... */
1183  TreeElement *te = lb->first;
1184  while (te) {
1185  TreeElement *ten = te->next;
1186  TreeStoreElem *tselem = TREESTORE(te);
1187 
1188  if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
1189  Object *ob = (Object *)tselem->id;
1190  if (ob->parent && ob->parent->id.newid) {
1191  BLI_remlink(lb, te);
1192  TreeElement *tep = (TreeElement *)ob->parent->id.newid;
1193  BLI_addtail(&tep->subtree, te);
1194  te->parent = tep;
1195  }
1196  }
1197  te = ten;
1198  }
1199 }
1200 
1201 /* Sorting ------------------------------------------------------ */
1202 
1203 typedef struct tTreeSort {
1205  ID *id;
1206  const char *name;
1207  short idcode;
1209 
1210 /* alphabetical comparator, trying to put objects first */
1211 static int treesort_alpha_ob(const void *v1, const void *v2)
1212 {
1213  const tTreeSort *x1 = v1, *x2 = v2;
1214 
1215  /* first put objects last (hierarchy) */
1216  int comp = (x1->idcode == ID_OB);
1217  if (x2->idcode == ID_OB) {
1218  comp += 2;
1219  }
1220 
1221  if (comp == 1) {
1222  return 1;
1223  }
1224  if (comp == 2) {
1225  return -1;
1226  }
1227  if (comp == 3) {
1228  /* Among objects first come the ones in the collection, followed by the ones not on it.
1229  * This way we can have the dashed lines in a separate style connecting the former. */
1230  if ((x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) !=
1231  (x2->te->flag & TE_CHILD_NOT_IN_COLLECTION)) {
1232  return (x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) ? 1 : -1;
1233  }
1234 
1235  comp = BLI_strcasecmp_natural(x1->name, x2->name);
1236 
1237  if (comp > 0) {
1238  return 1;
1239  }
1240  if (comp < 0) {
1241  return -1;
1242  }
1243  return 0;
1244  }
1245  return 0;
1246 }
1247 
1248 /* Move children that are not in the collection to the end of the list. */
1249 static int treesort_child_not_in_collection(const void *v1, const void *v2)
1250 {
1251  const tTreeSort *x1 = v1, *x2 = v2;
1252 
1253  /* Among objects first come the ones in the collection, followed by the ones not on it.
1254  * This way we can have the dashed lines in a separate style connecting the former. */
1255  if ((x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) != (x2->te->flag & TE_CHILD_NOT_IN_COLLECTION)) {
1256  return (x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) ? 1 : -1;
1257  }
1258  return 0;
1259 }
1260 
1261 /* alphabetical comparator */
1262 static int treesort_alpha(const void *v1, const void *v2)
1263 {
1264  const tTreeSort *x1 = v1, *x2 = v2;
1265 
1266  int comp = BLI_strcasecmp_natural(x1->name, x2->name);
1267 
1268  if (comp > 0) {
1269  return 1;
1270  }
1271  if (comp < 0) {
1272  return -1;
1273  }
1274  return 0;
1275 }
1276 
1277 /* this is nice option for later? doesn't look too useful... */
1278 #if 0
1279 static int treesort_obtype_alpha(const void *v1, const void *v2)
1280 {
1281  const tTreeSort *x1 = v1, *x2 = v2;
1282 
1283  /* first put objects last (hierarchy) */
1284  if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
1285  return 1;
1286  }
1287  else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
1288  return -1;
1289  }
1290  else {
1291  /* 2nd we check ob type */
1292  if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
1293  if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
1294  return 1;
1295  }
1296  else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
1297  return -1;
1298  }
1299  else {
1300  return 0;
1301  }
1302  }
1303  else {
1304  int comp = BLI_strcasecmp_natural(x1->name, x2->name);
1305 
1306  if (comp > 0) {
1307  return 1;
1308  }
1309  else if (comp < 0) {
1310  return -1;
1311  }
1312  return 0;
1313  }
1314  }
1315 }
1316 #endif
1317 
1318 /* sort happens on each subtree individual */
1319 static void outliner_sort(ListBase *lb)
1320 {
1321  TreeElement *te = lb->last;
1322  if (te == NULL) {
1323  return;
1324  }
1325  TreeStoreElem *tselem = TREESTORE(te);
1326 
1327  /* sorting rules; only object lists, ID lists, or deformgroups */
1328  if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
1329  ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
1330  int totelem = BLI_listbase_count(lb);
1331 
1332  if (totelem > 1) {
1333  tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
1334  tTreeSort *tp = tear;
1335  int skip = 0;
1336 
1337  for (te = lb->first; te; te = te->next, tp++) {
1338  tselem = TREESTORE(te);
1339  tp->te = te;
1340  tp->name = te->name;
1341  tp->idcode = te->idcode;
1342 
1343  if (!ELEM(tselem->type, TSE_SOME_ID, TSE_DEFGROUP)) {
1344  tp->idcode = 0; /* Don't sort this. */
1345  }
1346  if (tselem->type == TSE_ID_BASE) {
1347  tp->idcode = 1; /* Do sort this. */
1348  }
1349 
1350  tp->id = tselem->id;
1351  }
1352 
1353  /* just sort alphabetically */
1354  if (tear->idcode == 1) {
1355  qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
1356  }
1357  else {
1358  /* keep beginning of list */
1359  for (tp = tear, skip = 0; skip < totelem; skip++, tp++) {
1360  if (tp->idcode) {
1361  break;
1362  }
1363  }
1364 
1365  if (skip < totelem) {
1366  qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
1367  }
1368  }
1369 
1370  BLI_listbase_clear(lb);
1371  tp = tear;
1372  while (totelem--) {
1373  BLI_addtail(lb, tp->te);
1374  tp++;
1375  }
1376  MEM_freeN(tear);
1377  }
1378  }
1379 
1380  LISTBASE_FOREACH (TreeElement *, te_iter, lb) {
1381  outliner_sort(&te_iter->subtree);
1382  }
1383 }
1384 
1386 {
1387  TreeElement *te = lb->last;
1388  if (te == NULL) {
1389  return;
1390  }
1391  TreeStoreElem *tselem = TREESTORE(te);
1392 
1393  /* Sorting rules: only object lists. */
1394  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1395  int totelem = BLI_listbase_count(lb);
1396 
1397  if (totelem > 1) {
1398  tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
1399  tTreeSort *tp = tear;
1400 
1401  for (te = lb->first; te; te = te->next, tp++) {
1402  tselem = TREESTORE(te);
1403  tp->te = te;
1404  tp->name = te->name;
1405  tp->idcode = te->idcode;
1406  tp->id = tselem->id;
1407  }
1408 
1409  qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection);
1410 
1411  BLI_listbase_clear(lb);
1412  tp = tear;
1413  while (totelem--) {
1414  BLI_addtail(lb, tp->te);
1415  tp++;
1416  }
1417  MEM_freeN(tear);
1418  }
1419  }
1420 
1421  LISTBASE_FOREACH (TreeElement *, te_iter, lb) {
1422  outliner_collections_children_sort(&te_iter->subtree);
1423  }
1424 }
1425 
1426 /* Filtering ----------------------------------------------- */
1427 
1430  int ys;
1432 
1438  ARegion *region,
1439  OutlinerTreeElementFocus *focus)
1440 {
1441  View2D *v2d = &region->v2d;
1442 
1443  if (focus->tselem != NULL) {
1444  outliner_set_coordinates(region, space_outliner);
1445 
1446  TreeElement *te_new = outliner_find_tree_element(&space_outliner->tree, focus->tselem);
1447 
1448  if (te_new != NULL) {
1449  int ys_new = te_new->ys;
1450  int ys_old = focus->ys;
1451 
1452  float y_move = MIN2(ys_new - ys_old, -v2d->cur.ymax);
1453  BLI_rctf_translate(&v2d->cur, 0, y_move);
1454  }
1455  else {
1456  return;
1457  }
1458  }
1459 }
1460 
1462 {
1464 }
1465 
1467 {
1468  TreeStoreElem *tselem = TREESTORE(te);
1469  return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB));
1470 }
1471 
1476  const SpaceOutliner *space_outliner,
1477  TreeElement *te,
1478  const float limit,
1479  bool (*callback_test)(TreeElement *))
1480 {
1481  if (callback_test(te)) {
1482  return te;
1483  }
1484 
1485  if (TSELEM_OPEN(te->store_elem, space_outliner)) {
1486  TreeElement *te_iter, *te_sub;
1487  for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
1489  space_outliner, te_iter, limit, callback_test);
1490  if (te_sub != NULL) {
1491  return te_sub;
1492  }
1493  }
1494  }
1495 
1496  return NULL;
1497 }
1498 
1510  const float view_co,
1511  const float view_co_limit)
1512 {
1513  TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_co);
1514 
1515  bool (*callback_test)(TreeElement *);
1516  if ((space_outliner->outlinevis == SO_VIEW_LAYER) &&
1517  (space_outliner->filter & SO_FILTER_NO_COLLECTION)) {
1518  callback_test = test_object_callback;
1519  }
1520  else {
1521  callback_test = test_collection_callback;
1522  }
1523 
1524  while (te != NULL) {
1526  space_outliner, te, view_co_limit, callback_test);
1527  if (te_sub != NULL) {
1528  /* Skip the element if it was not visible to start with. */
1529  if (te->ys + UI_UNIT_Y > view_co_limit) {
1530  return te_sub;
1531  }
1532  return NULL;
1533  }
1534 
1535  if (te->next) {
1536  te = te->next;
1537  continue;
1538  }
1539 
1540  if (te->parent == NULL) {
1541  break;
1542  }
1543 
1544  while (te->parent) {
1545  if (te->parent->next) {
1546  te = te->parent->next;
1547  break;
1548  }
1549  te = te->parent;
1550  }
1551  }
1552 
1553  return NULL;
1554 }
1555 
1564  ARegion *region,
1565  OutlinerTreeElementFocus *focus)
1566 {
1567  float limit = region->v2d.cur.ymin;
1568 
1569  outliner_set_coordinates(region, space_outliner);
1570 
1572  space_outliner, region->v2d.cur.ymax, limit);
1573 
1574  if (te != NULL) {
1575  focus->tselem = TREESTORE(te);
1576  focus->ys = te->ys;
1577  }
1578  else {
1579  focus->tselem = NULL;
1580  }
1581 }
1582 
1583 static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner)
1584 {
1585  int exclude_filter = space_outliner->filter & ~SO_FILTER_OB_STATE;
1586 
1587  if (space_outliner->search_string[0] != 0) {
1588  exclude_filter |= SO_FILTER_SEARCH;
1589  }
1590  else {
1591  exclude_filter &= ~SO_FILTER_SEARCH;
1592  }
1593 
1594  /* Let's have this for the collection options at first. */
1595  if (!SUPPORT_FILTER_OUTLINER(space_outliner)) {
1596  return (exclude_filter & SO_FILTER_SEARCH);
1597  }
1598 
1599  if (space_outliner->filter & SO_FILTER_NO_OBJECT) {
1600  exclude_filter |= SO_FILTER_OB_TYPE;
1601  }
1602 
1603  switch (space_outliner->filter_state) {
1604  case SO_FILTER_OB_VISIBLE:
1605  exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
1606  break;
1607  case SO_FILTER_OB_SELECTED:
1608  exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
1609  break;
1610  case SO_FILTER_OB_ACTIVE:
1611  exclude_filter |= SO_FILTER_OB_STATE_ACTIVE;
1612  break;
1614  exclude_filter |= SO_FILTER_OB_STATE_SELECTABLE;
1615  break;
1616  }
1617 
1618  return exclude_filter;
1619 }
1620 
1621 static bool outliner_element_visible_get(ViewLayer *view_layer,
1622  TreeElement *te,
1623  const int exclude_filter)
1624 {
1625  if ((exclude_filter & SO_FILTER_ANY) == 0) {
1626  return true;
1627  }
1628 
1629  TreeStoreElem *tselem = TREESTORE(te);
1630  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1631  if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) {
1632  return false;
1633  }
1634 
1635  Object *ob = (Object *)tselem->id;
1636  Base *base = (Base *)te->directdata;
1637  BLI_assert((base == NULL) || (base->object == ob));
1638 
1639  if (exclude_filter & SO_FILTER_OB_TYPE) {
1640  switch (ob->type) {
1641  case OB_MESH:
1642  if (exclude_filter & SO_FILTER_NO_OB_MESH) {
1643  return false;
1644  }
1645  break;
1646  case OB_ARMATURE:
1647  if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) {
1648  return false;
1649  }
1650  break;
1651  case OB_EMPTY:
1652  if (exclude_filter & SO_FILTER_NO_OB_EMPTY) {
1653  return false;
1654  }
1655  break;
1656  case OB_LAMP:
1657  if (exclude_filter & SO_FILTER_NO_OB_LAMP) {
1658  return false;
1659  }
1660  break;
1661  case OB_CAMERA:
1662  if (exclude_filter & SO_FILTER_NO_OB_CAMERA) {
1663  return false;
1664  }
1665  break;
1666  default:
1667  if (exclude_filter & SO_FILTER_NO_OB_OTHERS) {
1668  return false;
1669  }
1670  break;
1671  }
1672  }
1673 
1674  if (exclude_filter & SO_FILTER_OB_STATE) {
1675  if (base == NULL) {
1676  base = BKE_view_layer_base_find(view_layer, ob);
1677 
1678  if (base == NULL) {
1679  return false;
1680  }
1681  }
1682 
1683  bool is_visible = true;
1684  if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
1685  if ((base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
1686  is_visible = false;
1687  }
1688  }
1689  else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
1690  if ((base->flag & BASE_SELECTED) == 0) {
1691  is_visible = false;
1692  }
1693  }
1694  else if (exclude_filter & SO_FILTER_OB_STATE_SELECTABLE) {
1695  if ((base->flag & BASE_SELECTABLE) == 0) {
1696  is_visible = false;
1697  }
1698  }
1699  else {
1700  BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
1701  if (base != BASACT(view_layer)) {
1702  is_visible = false;
1703  }
1704  }
1705 
1706  if (exclude_filter & SO_FILTER_OB_STATE_INVERSE) {
1707  is_visible = !is_visible;
1708  }
1709 
1710  return is_visible;
1711  }
1712 
1713  if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
1714  (te->parent->idcode == ID_OB)) {
1715  if (exclude_filter & SO_FILTER_NO_CHILDREN) {
1716  return false;
1717  }
1718  }
1719  }
1720  else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
1721  (te->parent->idcode == ID_OB)) {
1722  if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
1723  return false;
1724  }
1725  }
1726 
1727  return true;
1728 }
1729 
1730 static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
1731 {
1732  int fn_flag = 0;
1733 
1734  if ((flags & SO_FIND_CASE_SENSITIVE) == 0) {
1735  fn_flag |= FNM_CASEFOLD;
1736  }
1737 
1738  return fnmatch(name, te->name, fn_flag) == 0;
1739 }
1740 
1742 {
1743  TreeStoreElem *tselem = TREESTORE(te);
1744 
1745  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1746  return true;
1747  }
1748 
1749  /* Collection instance datablocks should not be extracted. */
1750  if (outliner_is_collection_tree_element(te) && !(te->parent && te->parent->idcode == ID_OB)) {
1751  return true;
1752  }
1753 
1754  return false;
1755 }
1756 
1758  ListBase *parent_subtree)
1759 {
1760  TreeElement *te_next = element->next;
1761 
1763  TreeElement *te_prev = NULL;
1764  for (TreeElement *te = element->subtree.last; te; te = te_prev) {
1765  te_prev = te->prev;
1766 
1768  continue;
1769  }
1770 
1771  te_next = te;
1772  BLI_remlink(&element->subtree, te);
1773  BLI_insertlinkafter(parent_subtree, element->prev, te);
1774  te->parent = element->parent;
1775  }
1776  }
1777 
1778  outliner_free_tree_element(element, parent_subtree);
1779  return te_next;
1780 }
1781 
1782 static int outliner_filter_subtree(SpaceOutliner *space_outliner,
1783  ViewLayer *view_layer,
1784  ListBase *lb,
1785  const char *search_string,
1786  const int exclude_filter)
1787 {
1788  TreeElement *te, *te_next;
1789  TreeStoreElem *tselem;
1790 
1791  for (te = lb->first; te; te = te_next) {
1792  te_next = te->next;
1793  if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
1794  /* Don't free the tree, but extract the children from the parent and add to this tree. */
1795  /* This also needs filtering the subtree prior (see T69246). */
1797  space_outliner, view_layer, &te->subtree, search_string, exclude_filter);
1798  te_next = outliner_extract_children_from_subtree(te, lb);
1799  continue;
1800  }
1801  if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
1802  /* Filter subtree too. */
1804  space_outliner, view_layer, &te->subtree, search_string, exclude_filter);
1805  continue;
1806  }
1807 
1808  if (!outliner_filter_has_name(te, search_string, space_outliner->search_flags)) {
1809  /* item isn't something we're looking for, but...
1810  * - if the subtree is expanded, check if there are any matches that can be easily found
1811  * so that searching for "cu" in the default scene will still match the Cube
1812  * - otherwise, we can't see within the subtree and the item doesn't match,
1813  * so these can be safely ignored (i.e. the subtree can get freed)
1814  */
1815  tselem = TREESTORE(te);
1816 
1817  /* flag as not a found item */
1818  tselem->flag &= ~TSE_SEARCHMATCH;
1819 
1820  if ((!TSELEM_OPEN(tselem, space_outliner)) ||
1822  space_outliner, view_layer, &te->subtree, search_string, exclude_filter) == 0) {
1824  }
1825  }
1826  else {
1827  tselem = TREESTORE(te);
1828 
1829  /* flag as a found item - we can then highlight it */
1830  tselem->flag |= TSE_SEARCHMATCH;
1831 
1832  /* filter subtree too */
1834  space_outliner, view_layer, &te->subtree, search_string, exclude_filter);
1835  }
1836  }
1837 
1838  /* if there are still items in the list, that means that there were still some matches */
1839  return (BLI_listbase_is_empty(lb) == false);
1840 }
1841 
1842 static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer)
1843 {
1844  char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2];
1845  char *search_string;
1846 
1847  const int exclude_filter = outliner_exclude_filter_get(space_outliner);
1848 
1849  if (exclude_filter == 0) {
1850  return;
1851  }
1852 
1853  if (space_outliner->search_flags & SO_FIND_COMPLETE) {
1854  search_string = space_outliner->search_string;
1855  }
1856  else {
1857  /* Implicitly add heading/trailing wildcards if needed. */
1858  BLI_strncpy_ensure_pad(search_buff, space_outliner->search_string, '*', sizeof(search_buff));
1859  search_string = search_buff;
1860  }
1861 
1863  space_outliner, view_layer, &space_outliner->tree, search_string, exclude_filter);
1864 }
1865 
1866 /* ======================================================= */
1867 /* Main Tree Building API */
1868 
1869 /* Main entry point for building the tree data-structure that the outliner represents. */
1871  Scene *scene,
1872  ViewLayer *view_layer,
1873  SpaceOutliner *space_outliner,
1874  ARegion *region)
1875 {
1876  /* Are we looking for something - we want to tag parents to filter child matches
1877  * - NOT in data-blocks view - searching all data-blocks takes way too long to be useful
1878  * - this variable is only set once per tree build */
1879  if (space_outliner->search_string[0] != 0 && space_outliner->outlinevis != SO_DATA_API) {
1880  space_outliner->search_flags |= SO_SEARCH_RECURSIVE;
1881  }
1882  else {
1883  space_outliner->search_flags &= ~SO_SEARCH_RECURSIVE;
1884  }
1885 
1886  if (space_outliner->runtime->treehash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) &&
1887  space_outliner->treestore) {
1889  space_outliner->treestore);
1890  }
1891  space_outliner->storeflag &= ~SO_TREESTORE_REBUILD;
1892 
1893  if (region->do_draw & RGN_DRAW_NO_REBUILD) {
1894  return;
1895  }
1896 
1898  outliner_store_scrolling_position(space_outliner, region, &focus);
1899 
1900  outliner_free_tree(&space_outliner->tree);
1901  outliner_storage_cleanup(space_outliner);
1903 
1904  space_outliner->runtime->tree_display = outliner_tree_display_create(space_outliner->outlinevis,
1905  space_outliner);
1906 
1907  /* All tree displays should be created as sub-classes of AbstractTreeDisplay. */
1908  BLI_assert(space_outliner->runtime->tree_display != NULL);
1909 
1910  TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer};
1911  space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display,
1912  &source_data);
1913 
1914  if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
1915  outliner_sort(&space_outliner->tree);
1916  }
1917  else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) {
1918  /* We group the children that are in the collection before the ones that are not.
1919  * This way we can try to draw them in a different style altogether.
1920  * We also have to respect the original order of the elements in case alphabetical
1921  * sorting is not enabled. This keep object data and modifiers before its children. */
1922  outliner_collections_children_sort(&space_outliner->tree);
1923  }
1924 
1925  outliner_filter_tree(space_outliner, view_layer);
1926  outliner_restore_scrolling_position(space_outliner, region, &focus);
1927 
1928  BKE_main_id_clear_newpoins(mainvar);
1929 }
const char * BKE_collection_ui_name_get(struct Collection *collection)
Definition: collection.c:776
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:394
void BKE_main_id_clear_newpoins(struct Main *bmain)
Definition: lib_id.c:1738
void BKE_outliner_treehash_clear_used(void *treehash)
struct TreeStoreElem * BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
void * BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore)
void * BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore)
void BKE_outliner_treehash_free(void *treehash)
void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem)
#define BLI_STATIC_ASSERT(a, msg)
Definition: BLI_assert.h:86
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
Definition: BLI_listbase.h:184
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:180
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
Definition: BLI_mempool.c:537
@ BLI_MEMPOOL_ALLOW_ITER
Definition: BLI_mempool.h:85
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_mempool.c:645
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int totelem, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_mempool.c:268
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_mempool.c:334
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:757
int BLI_mempool_len(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:454
void BLI_rctf_translate(struct rctf *rect, float x, float y)
Definition: rct.c:604
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:666
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:766
char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:132
#define CLAMP_MAX(a, c)
#define ELEM(...)
#define MIN2(a, b)
#define IFACE_(msgid)
@ LIB_TAG_DOIT
Definition: DNA_ID.h:554
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
@ ID_CA
Definition: DNA_ID_enums.h:68
@ ID_AR
Definition: DNA_ID_enums.h:78
@ ID_CF
Definition: DNA_ID_enums.h:90
@ ID_LI
Definition: DNA_ID_enums.h:58
@ ID_TE
Definition: DNA_ID_enums.h:64
@ ID_VO
Definition: DNA_ID_enums.h:95
@ ID_LA
Definition: DNA_ID_enums.h:67
@ ID_KE
Definition: DNA_ID_enums.h:70
@ ID_SCE
Definition: DNA_ID_enums.h:57
@ ID_LS
Definition: DNA_ID_enums.h:87
@ ID_GD
Definition: DNA_ID_enums.h:83
@ ID_LP
Definition: DNA_ID_enums.h:92
@ ID_HA
Definition: DNA_ID_enums.h:93
@ ID_WO
Definition: DNA_ID_enums.h:71
@ ID_SIM
Definition: DNA_ID_enums.h:96
@ ID_MA
Definition: DNA_ID_enums.h:63
@ ID_AC
Definition: DNA_ID_enums.h:79
@ ID_ME
Definition: DNA_ID_enums.h:60
@ ID_GR
Definition: DNA_ID_enums.h:77
@ ID_SPK
Definition: DNA_ID_enums.h:75
@ ID_MB
Definition: DNA_ID_enums.h:62
@ ID_OB
Definition: DNA_ID_enums.h:59
@ ID_PT
Definition: DNA_ID_enums.h:94
@ ID_CU
Definition: DNA_ID_enums.h:61
Object groups, one object can be in many groups at once.
@ eGpencilModifierType_Lattice
@ eGpencilModifierType_Hook
@ eGpencilModifierType_Armature
@ BASE_SELECTABLE
@ BASE_VISIBLE_VIEWLAYER
@ BASE_SELECTED
@ eModifierType_ParticleSystem
@ eModifierType_Curve
@ eModifierType_Lattice
@ eModifierType_Hook
@ eModifierType_Armature
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ OB_DUPLICOLLECTION
@ OB_EMPTY
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
#define TSE_IS_REAL_ID(_tse)
@ TSE_PROXY
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_MODIFIER_BASE
@ TSE_GP_LAYER
@ TSE_SEQUENCE_DUP
@ TSE_RNA_ARRAY_ELEM
@ TSE_SEQUENCE
@ TSE_GPENCIL_EFFECT
@ TSE_POSEGRP_BASE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_ANIM_DATA
@ TSE_LIBRARY_OVERRIDE
@ TSE_RNA_PROPERTY
@ TSE_LIBRARY_OVERRIDE_BASE
@ TSE_EBONE
@ TSE_NLA_TRACK
@ TSE_BONE
@ TSE_LINKED_PSYS
@ TSE_DEFGROUP_BASE
@ TSE_CONSTRAINT
@ TSE_SCENE_COLLECTION_BASE
@ TSE_LAYER_COLLECTION
@ TSE_SEQ_STRIP
@ TSE_GPENCIL_EFFECT_BASE
@ TSE_LINKED_OB
@ TSE_NLA
@ TSE_ID_BASE
@ TSE_SOME_ID
@ TSE_DRIVER_BASE
@ TSE_NLA_ACTION
@ TSE_MODIFIER
@ TSE_POSEGRP
@ TSE_RNA_STRUCT
@ TSE_POSE_BASE
@ TSE_DEFGROUP
@ TSE_CHILDSEARCH
@ TSE_CLOSED
@ TSE_SEARCHMATCH
#define BASACT(_view_layer)
@ RGN_DRAW_NO_REBUILD
@ SEQ_TYPE_META
@ SEQ_TYPE_EFFECT
@ eShaderFxType_Swirl
@ SO_FIND_COMPLETE
@ SO_SEARCH_RECURSIVE
@ SO_FIND_CASE_SENSITIVE
#define SO_FILTER_OB_STATE
@ SO_FILTER_OB_STATE_ACTIVE
@ SO_FILTER_NO_OB_MESH
@ SO_FILTER_NO_OB_CAMERA
@ SO_FILTER_NO_CHILDREN
@ SO_FILTER_SEARCH
@ SO_FILTER_NO_OB_CONTENT
@ SO_FILTER_NO_OB_LAMP
@ SO_FILTER_OB_STATE_SELECTABLE
@ SO_FILTER_OB_STATE_INVERSE
@ SO_FILTER_OB_STATE_SELECTED
@ SO_FILTER_OB_STATE_VISIBLE
@ SO_FILTER_NO_OBJECT
@ SO_FILTER_NO_OB_OTHERS
@ SO_FILTER_NO_OB_EMPTY
@ SO_FILTER_NO_COLLECTION
@ SO_FILTER_NO_OB_ARMATURE
#define SO_FILTER_OB_TYPE
@ SO_SKIP_SORT_ALPHA
@ SO_FILTER_OB_SELECTABLE
@ SO_FILTER_OB_SELECTED
@ SO_FILTER_OB_VISIBLE
@ SO_FILTER_OB_ACTIVE
@ SO_TREESTORE_CLEANUP
@ SO_TREESTORE_REBUILD
#define SO_FILTER_ANY
@ SO_DATA_API
@ SO_VIEW_LAYER
@ SO_SCENES
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
PropertyType
Definition: RNA_types.h:72
@ PROP_FLOAT
Definition: RNA_types.h:75
@ PROP_BOOLEAN
Definition: RNA_types.h:73
@ PROP_INT
Definition: RNA_types.h:74
@ PROP_POINTER
Definition: RNA_types.h:78
@ PROP_COLLECTION
Definition: RNA_types.h:79
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define MAX_MTEX
Definition: Stroke.h:45
#define UI_UNIT_Y
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMVert * v2
Scene scene
FreestyleLineStyle linestyle
Simulation simulation
void * tree
#define str(s)
#define GS(x)
Definition: iris.c:241
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
bool outliner_is_collection_tree_element(const TreeElement *te)
void outliner_set_coordinates(ARegion *region, SpaceOutliner *space_outliner)
#define TREESTORE_ID_TYPE(_id)
#define SEARCHING_OUTLINER(sov)
@ TE_CHILD_NOT_IN_COLLECTION
@ TE_FREE_NAME
@ TE_LAZY_CLOSED
#define SUPPORT_FILTER_OUTLINER(space_outliner_)
TreeElement * outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
#define TREESTORE(a)
TreeElement * outliner_find_item_at_y(const SpaceOutliner *space_outliner, const ListBase *tree, float view_co_y)
#define TSELEM_OPEN(telm, sv)
TreeElement * outliner_add_collection_recursive(SpaceOutliner *space_outliner, Collection *collection, TreeElement *ten)
static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter)
static void outliner_store_scrolling_position(SpaceOutliner *space_outliner, ARegion *region, OutlinerTreeElementFocus *focus)
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner)
static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer)
bool outliner_animdata_test(const AnimData *adt)
static TreeElement * outliner_find_first_desired_element_at_y(const SpaceOutliner *space_outliner, const float view_co, const float view_co_limit)
static bool outliner_element_is_collection_or_object(TreeElement *te)
bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *space_outliner)
void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOutliner *space_outliner, ARegion *region)
static int outliner_filter_subtree(SpaceOutliner *space_outliner, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter)
static int treesort_alpha(const void *v1, const void *v2)
BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner, ListBase *tree, Collection *collection, TreeElement *parent)
static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
Definition: outliner_tree.c:91
void outliner_free_tree(ListBase *tree)
static bool test_collection_callback(TreeElement *te)
static void outliner_add_id_contents(SpaceOutliner *space_outliner, TreeElement *te, TreeStoreElem *tselem, ID *id)
struct tTreeSort tTreeSort
static int treesort_child_not_in_collection(const void *v1, const void *v2)
BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
static void outliner_sort(ListBase *lb)
TreeElement * outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, TreeElement *parent, short type, short index)
static void check_persistent(SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
static void outliner_add_object_contents(SpaceOutliner *space_outliner, TreeElement *te, TreeStoreElem *tselem, Object *ob)
bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner)
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
static void outliner_restore_scrolling_position(SpaceOutliner *space_outliner, ARegion *region, OutlinerTreeElementFocus *focus)
static bool test_object_callback(TreeElement *te)
void outliner_cleanup_tree(SpaceOutliner *space_outliner)
void outliner_make_object_parent_hierarchy(ListBase *lb)
static void outliner_add_bone(SpaceOutliner *space_outliner, ListBase *lb, ID *id, Bone *curBone, TreeElement *parent, int *a)
static TreeElement * outliner_find_first_desired_element_at_y_recursive(const SpaceOutliner *space_outliner, TreeElement *te, const float limit, bool(*callback_test)(TreeElement *))
static void outliner_collections_children_sort(ListBase *lb)
static TreeElement * outliner_extract_children_from_subtree(TreeElement *element, ListBase *parent_subtree)
static int treesort_alpha_ob(const void *v1, const void *v2)
struct OutlinerTreeElementFocus OutlinerTreeElementFocus
char * RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len)
Definition: rna_access.c:1049
const char * RNA_struct_ui_name(const StructRNA *type)
Definition: rna_access.c:728
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1155
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3641
int RNA_property_collection_lookup_int(PointerRNA *ptr, PropertyRNA *prop, int key, PointerRNA *r_ptr)
Definition: rna_access.c:4212
char RNA_property_array_item_char(PropertyRNA *prop, int index)
Definition: rna_access.c:1250
int RNA_property_flag(PropertyRNA *prop)
Definition: rna_access.c:1192
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1218
PropertyRNA * RNA_struct_iterator_property(StructRNA *type)
Definition: rna_access.c:771
int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3903
const char * RNA_property_ui_name(const PropertyRNA *prop)
Definition: rna_access.c:2043
bAction * action
ListBase drivers
ListBase nla_tracks
char name[64]
ListBase childbase
struct AnimData * adt
struct AnimData * adt
struct Material ** mat
short totcol
struct AnimData * adt
struct EditBone * parent
Definition: BKE_armature.h:55
void * p
Definition: BKE_armature.h:114
union EditBone::@2 temp
struct FreestyleLineStyle * linestyle
struct FreestyleLineSet * next
struct AnimData * adt
struct MTex * mtex[18]
struct AnimData * adt
Definition: DNA_ID.h:273
int tag
Definition: DNA_ID.h:292
struct ID * newid
Definition: DNA_ID.h:275
char name[66]
Definition: DNA_ID.h:283
struct AnimData * adt
Definition: DNA_key_types.h:81
struct AnimData * adt
struct AnimData * adt
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
struct Tex * tex
Definition: BKE_main.h:116
struct AnimData * adt
struct AnimData * adt
struct Material ** mat
short totcol
struct Key * key
short totcol
struct AnimData * adt
struct Material ** mat
struct bAction * poselib
short transflag
ListBase defbase
ListBase constraints
struct Collection * instance_collection
struct bPose * pose
ListBase modifiers
ListBase greasepencil_modifiers
struct Material ** mat
struct Object * proxy
ListBase shader_fx
struct AnimData * adt
struct Object * parent
void * data
ParticleSettings * part
struct AnimData * adt
struct StructRNA * type
Definition: RNA_types.h:51
void * data
Definition: RNA_types.h:52
ListBase view_layers
ListBase seqbase
struct AnimData * adt
struct GHash * treehash
struct TreeDisplay * tree_display
char search_string[64]
SpaceOutliner_Runtime * runtime
struct BLI_mempool * treestore
struct AnimData * adt
char name[256]
StripElem * stripdata
char dir[768]
struct AnimData * adt
struct Image * ima
struct TreeElement * parent
ListBase subtree
struct TreeElementType * type
TreeStoreElem * store_elem
void * directdata
struct TreeElement * prev
PointerRNA rnaptr
const char * name
struct TreeElement * next
The data to build the tree from.
Definition: tree_display.h:39
struct Main * bmain
Definition: tree_display.h:40
struct FreestyleConfig freestyle_config
struct ViewLayer * next
struct AnimData * adt
struct AnimData * adt
struct AnimData * adt
ListBase bonebase
ListBase * edbo
ListBase layers
struct AnimData * adt
struct bPoseChannel * parent
ListBase chanbase
ListBase agroups
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
const char * name
TreeElement * te
void outliner_tree_display_destroy(TreeDisplay **tree_display)
Definition: tree_display.cc:59
ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data)
Definition: tree_display.cc:65
TreeDisplay * outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner)
Definition: tree_display.cc:27
void outliner_tree_element_type_free(TreeElementType **type)
bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner)
TreeElementType * outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv)
bool outliner_tree_element_type_is_expand_valid(TreeElementType *type)
void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner)
void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner)
PointerRNA * ptr
Definition: wm_files.c:3157