Blender  V3.3
outliner_tree.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include <cmath>
9 #include <cstring>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_anim_types.h"
14 #include "DNA_armature_types.h"
15 #include "DNA_cachefile_types.h"
16 #include "DNA_camera_types.h"
17 #include "DNA_collection_types.h"
18 #include "DNA_constraint_types.h"
19 #include "DNA_curves_types.h"
21 #include "DNA_gpencil_types.h"
22 #include "DNA_key_types.h"
23 #include "DNA_light_types.h"
24 #include "DNA_lightprobe_types.h"
25 #include "DNA_linestyle_types.h"
26 #include "DNA_material_types.h"
27 #include "DNA_mesh_types.h"
28 #include "DNA_meta_types.h"
29 #include "DNA_object_types.h"
30 #include "DNA_particle_types.h"
31 #include "DNA_pointcloud_types.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_sequence_types.h"
34 #include "DNA_shader_fx_types.h"
35 #include "DNA_simulation_types.h"
36 #include "DNA_speaker_types.h"
37 #include "DNA_volume_types.h"
38 #include "DNA_world_types.h"
39 
40 #include "BLI_blenlib.h"
41 #include "BLI_fnmatch.h"
42 #include "BLI_listbase.h"
43 #include "BLI_mempool.h"
44 #include "BLI_utildefines.h"
45 
46 #include "BLT_translation.h"
47 
48 #include "BKE_armature.h"
49 #include "BKE_deform.h"
50 #include "BKE_layer.h"
51 #include "BKE_lib_id.h"
52 #include "BKE_main.h"
53 #include "BKE_modifier.h"
54 #include "BKE_outliner_treehash.h"
55 
56 #include "ED_screen.h"
57 
58 #include "RNA_access.h"
59 
60 #include "UI_interface.h"
61 #include "UI_resources.h"
62 
63 #include "outliner_intern.hh"
64 #include "tree/common.hh"
65 #include "tree/tree_display.hh"
66 #include "tree/tree_element.hh"
67 
68 #ifdef WIN32
69 # include "BLI_math_base.h" /* M_PI */
70 #endif
71 
72 using namespace blender::ed::outliner;
73 
74 /* prototypes */
75 static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
76 
77 /* -------------------------------------------------------------------- */
81 static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
82 {
83  BLI_mempool *ts = space_outliner->treestore;
84 
85  if (ts) {
86  TreeStoreElem *tselem;
87  int unused = 0;
88 
89  /* each element used once, for ID blocks with more users to have each a treestore */
90  BLI_mempool_iter iter;
91 
92  BLI_mempool_iternew(ts, &iter);
93  while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
94  tselem->used = 0;
95  }
96 
97  /* cleanup only after reading file or undo step, and always for
98  * RNA data-blocks view in order to save memory */
99  if (space_outliner->storeflag & SO_TREESTORE_CLEANUP) {
100  space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP;
101 
102  BLI_mempool_iternew(ts, &iter);
103  while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
104  if (tselem->id == nullptr) {
105  unused++;
106  }
107  }
108 
109  if (unused) {
110  if (BLI_mempool_len(ts) == unused) {
112  space_outliner->treestore = nullptr;
113  if (space_outliner->runtime->treehash) {
114  BKE_outliner_treehash_free(space_outliner->runtime->treehash);
115  space_outliner->runtime->treehash = nullptr;
116  }
117  }
118  else {
119  TreeStoreElem *tsenew;
121  sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER);
122  BLI_mempool_iternew(ts, &iter);
123  while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
124  if (tselem->id) {
125  tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts));
126  *tsenew = *tselem;
127  }
128  }
130  space_outliner->treestore = new_ts;
131  if (space_outliner->runtime->treehash) {
132  /* update hash table to fix broken pointers */
134  space_outliner->treestore);
135  }
136  }
137  }
138  }
139  else if (space_outliner->runtime->treehash) {
141  }
142  }
143 }
144 
145 static void check_persistent(
146  SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
147 {
148  if (space_outliner->treestore == nullptr) {
149  /* if treestore was not created in readfile.c, create it here */
150  space_outliner->treestore = BLI_mempool_create(
151  sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
152  }
153  if (space_outliner->runtime->treehash == nullptr) {
154  space_outliner->runtime->treehash = reinterpret_cast<GHash *>(
156  }
157 
158  /* find any unused tree element in treestore and mark it as used
159  * (note that there may be multiple unused elements in case of linked objects) */
161  space_outliner->runtime->treehash, type, nr, id);
162  if (tselem) {
163  te->store_elem = tselem;
164  tselem->used = 1;
165  return;
166  }
167 
168  /* add 1 element to treestore */
169  tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore));
170  tselem->type = type;
171  tselem->nr = type ? nr : 0;
172  tselem->id = id;
173  tselem->used = 0;
174  tselem->flag = TSE_CLOSED;
175  te->store_elem = tselem;
176  BKE_outliner_treehash_add_element(space_outliner->runtime->treehash, tselem);
177 }
178 
181 /* -------------------------------------------------------------------- */
186 {
189  }
190 }
191 
193 {
194  outliner_free_tree(&space_outliner->tree);
195  outliner_storage_cleanup(space_outliner);
196 }
197 
199 {
200  BLI_assert(BLI_findindex(parent_subtree, element) > -1);
201  BLI_remlink(parent_subtree, element);
202 
203  outliner_free_tree(&element->subtree);
204 
205  if (element->flag & TE_FREE_NAME) {
206  MEM_freeN((void *)element->name);
207  }
208  element->abstract_element = nullptr;
209  MEM_delete(element);
210 }
211 
212 /* ********************************************************* */
213 
214 /* -------------------------------------------------------- */
215 
217 {
218  int exclude_flags = outliner_exclude_filter_get(space_outliner);
219  /* Need to rebuild tree to re-apply filter if select/active changed while filtering based on
220  * select/active. */
221  return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
222 }
223 
224 /* special handling of hierarchical non-lib data */
225 static void outliner_add_bone(SpaceOutliner *space_outliner,
226  ListBase *lb,
227  ID *id,
228  Bone *curBone,
229  TreeElement *parent,
230  int *a)
231 {
232  TreeElement *te = outliner_add_element(space_outliner, lb, id, parent, TSE_BONE, *a);
233 
234  (*a)++;
235  te->name = curBone->name;
236  te->directdata = curBone;
237 
238  LISTBASE_FOREACH (Bone *, child_bone, &curBone->childbase) {
239  outliner_add_bone(space_outliner, &te->subtree, id, child_bone, te, a);
240  }
241 }
242 
243 #ifdef WITH_FREESTYLE
244 static void outliner_add_line_styles(SpaceOutliner *space_outliner,
245  ListBase *lb,
246  Scene *sce,
247  TreeElement *te)
248 {
249  ViewLayer *view_layer;
250  FreestyleLineSet *lineset;
251 
252  for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
253  for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
255  if (linestyle) {
257  }
258  }
259  }
260  for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
261  for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
263  if (linestyle) {
264  if (!(linestyle->id.tag & LIB_TAG_DOIT)) {
265  continue;
266  }
268  outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0);
269  }
270  }
271  }
272 }
273 #endif
274 
275 /* Can be inlined if necessary. */
276 static void outliner_add_object_contents(SpaceOutliner *space_outliner,
277  TreeElement *te,
278  TreeStoreElem *tselem,
279  Object *ob)
280 {
281  if (outliner_animdata_test(ob->adt)) {
282  outliner_add_element(space_outliner, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
283  }
284 
285  /* FIXME: add a special type for this. */
286  outliner_add_element(space_outliner, &te->subtree, ob->poselib, te, TSE_SOME_ID, 0);
287 
288  outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
289 
290  if (ob->pose) {
291  bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
293  space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
294  tenla->name = IFACE_("Pose");
295 
296  /* channels undefined in editmode, but we want the 'tenla' pose icon itself */
297  if ((arm->edbo == nullptr) && (ob->mode & OB_MODE_POSE)) {
298  int const_index = 1000; /* ensure unique id for bone constraints */
299  int a;
300  LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) {
302  space_outliner, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
303  ten->name = pchan->name;
304  ten->directdata = pchan;
305  pchan->temp = (void *)ten;
306 
307  if (!BLI_listbase_is_empty(&pchan->constraints)) {
308  /* Object *target; */
310  space_outliner, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
311  tenla1->name = IFACE_("Constraints");
312  /* char *str; */
313 
314  LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
316  space_outliner, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
317 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
318  target = get_constraint_target(con, &str);
319  if (str && str[0]) {
320  ten1->name = str;
321  }
322  else if (target) {
323  ten1->name = target->id.name + 2;
324  }
325  else {
326  ten1->name = con->name;
327  }
328 #endif
329  ten1->name = con->name;
330  ten1->directdata = con;
331  /* possible add all other types links? */
332  }
333  const_index++;
334  }
335  }
336  /* make hierarchy */
337  TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first);
338  while (ten) {
339  TreeElement *nten = ten->next, *par;
340  tselem = TREESTORE(ten);
341  if (tselem->type == TSE_POSE_CHANNEL) {
342  bPoseChannel *pchan = (bPoseChannel *)ten->directdata;
343  if (pchan->parent) {
344  BLI_remlink(&tenla->subtree, ten);
345  par = (TreeElement *)pchan->parent->temp;
346  BLI_addtail(&par->subtree, ten);
347  ten->parent = par;
348  }
349  }
350  ten = nten;
351  }
352  }
353 
354  /* Pose Groups */
355  if (!BLI_listbase_is_empty(&ob->pose->agroups)) {
356  TreeElement *ten_bonegrp = outliner_add_element(
357  space_outliner, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
358  ten_bonegrp->name = IFACE_("Bone Groups");
359 
360  int index;
361  LISTBASE_FOREACH_INDEX (bActionGroup *, agrp, &ob->pose->agroups, index) {
363  space_outliner, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, index);
364  ten->name = agrp->name;
365  ten->directdata = agrp;
366  }
367  }
368  }
369 
370  for (int a = 0; a < ob->totcol; a++) {
371  outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a);
372  }
373 
374  if (!BLI_listbase_is_empty(&ob->constraints)) {
376  space_outliner, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
377  tenla->name = IFACE_("Constraints");
378 
379  int index;
380  LISTBASE_FOREACH_INDEX (bConstraint *, con, &ob->constraints, index) {
382  space_outliner, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, index);
383 #if 0 /* disabled due to constraints system targets recode... code here needs review */
384  target = get_constraint_target(con, &str);
385  if (str && str[0]) {
386  ten->name = str;
387  }
388  else if (target) {
389  ten->name = target->id.name + 2;
390  }
391  else {
392  ten->name = con->name;
393  }
394 #endif
395  ten->name = con->name;
396  ten->directdata = con;
397  /* possible add all other types links? */
398  }
399  }
400 
401  if (!BLI_listbase_is_empty(&ob->modifiers)) {
403  space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
404  ten_mod->name = IFACE_("Modifiers");
405 
406  int index;
407  LISTBASE_FOREACH_INDEX (ModifierData *, md, &ob->modifiers, index) {
409  space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
410  ten->name = md->name;
411  ten->directdata = md;
412 
413  if (md->type == eModifierType_Lattice) {
414  outliner_add_element(space_outliner,
415  &ten->subtree,
416  ((LatticeModifierData *)md)->object,
417  ten,
419  0);
420  }
421  else if (md->type == eModifierType_Curve) {
422  outliner_add_element(space_outliner,
423  &ten->subtree,
424  ((CurveModifierData *)md)->object,
425  ten,
427  0);
428  }
429  else if (md->type == eModifierType_Armature) {
430  outliner_add_element(space_outliner,
431  &ten->subtree,
432  ((ArmatureModifierData *)md)->object,
433  ten,
435  0);
436  }
437  else if (md->type == eModifierType_Hook) {
438  outliner_add_element(space_outliner,
439  &ten->subtree,
440  ((HookModifierData *)md)->object,
441  ten,
443  0);
444  }
445  else if (md->type == eModifierType_ParticleSystem) {
446  ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
447  TreeElement *ten_psys;
448 
449  ten_psys = outliner_add_element(space_outliner, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0);
450  ten_psys->directdata = psys;
451  ten_psys->name = psys->part->id.name + 2;
452  }
453  }
454  }
455 
456  /* Grease Pencil modifiers. */
459  space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
460  ten_mod->name = IFACE_("Modifiers");
461 
462  int index;
465  space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
466  ten->name = md->name;
467  ten->directdata = md;
468 
469  if (md->type == eGpencilModifierType_Armature) {
470  outliner_add_element(space_outliner,
471  &ten->subtree,
472  ((ArmatureGpencilModifierData *)md)->object,
473  ten,
475  0);
476  }
477  else if (md->type == eGpencilModifierType_Hook) {
478  outliner_add_element(space_outliner,
479  &ten->subtree,
480  ((HookGpencilModifierData *)md)->object,
481  ten,
483  0);
484  }
485  else if (md->type == eGpencilModifierType_Lattice) {
486  outliner_add_element(space_outliner,
487  &ten->subtree,
488  ((LatticeGpencilModifierData *)md)->object,
489  ten,
491  0);
492  }
493  }
494  }
495 
496  /* Grease Pencil effects. */
497  if (!BLI_listbase_is_empty(&ob->shader_fx)) {
499  space_outliner, &te->subtree, ob, te, TSE_GPENCIL_EFFECT_BASE, 0);
500  ten_fx->name = IFACE_("Effects");
501 
502  int index;
503  LISTBASE_FOREACH_INDEX (ShaderFxData *, fx, &ob->shader_fx, index) {
505  space_outliner, &ten_fx->subtree, ob, ten_fx, TSE_GPENCIL_EFFECT, index);
506  ten->name = fx->name;
507  ten->directdata = fx;
508 
509  if (fx->type == eShaderFxType_Swirl) {
510  outliner_add_element(space_outliner,
511  &ten->subtree,
512  ((SwirlShaderFxData *)fx)->object,
513  ten,
515  0);
516  }
517  }
518  }
519 
520  /* vertex groups */
521  if (ELEM(ob->type, OB_MESH, OB_GPENCIL, OB_LATTICE)) {
522  const ListBase *defbase = BKE_object_defgroup_list(ob);
523  if (!BLI_listbase_is_empty(defbase)) {
525  space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
526  tenla->name = IFACE_("Vertex Groups");
527 
528  int index;
529  LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, defbase, index) {
531  space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index);
532  ten->name = defgroup->name;
533  ten->directdata = defgroup;
534  }
535  }
536  }
537 
538  /* duplicated group */
539  if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) {
541  space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0);
542  }
543 }
544 
545 /* Can be inlined if necessary. */
546 static void outliner_add_id_contents(SpaceOutliner *space_outliner,
547  TreeElement *te,
548  TreeStoreElem *tselem,
549  ID *id)
550 {
551  /* tuck pointer back in object, to construct hierarchy */
552  if (GS(id->name) == ID_OB) {
553  id->newid = (ID *)te;
554  }
555 
556  /* expand specific data always */
557  switch (GS(id->name)) {
558  case ID_LI:
559  case ID_SCE:
560  BLI_assert_msg(0, "ID type expected to be expanded through new tree-element design");
561  break;
562  case ID_OB: {
563  outliner_add_object_contents(space_outliner, te, tselem, (Object *)id);
564  break;
565  }
566  case ID_ME: {
567  Mesh *me = (Mesh *)id;
568 
569  if (outliner_animdata_test(me->adt)) {
570  outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0);
571  }
572 
573  outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0);
574  for (int a = 0; a < me->totcol; a++) {
575  outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a);
576  }
577  /* could do tfaces with image links, but the images are not grouped nicely.
578  * would require going over all tfaces, sort images in use. etc... */
579  break;
580  }
581  case ID_CU_LEGACY: {
582  Curve *cu = (Curve *)id;
583 
584  if (outliner_animdata_test(cu->adt)) {
585  outliner_add_element(space_outliner, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
586  }
587 
588  for (int a = 0; a < cu->totcol; a++) {
589  outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a);
590  }
591  break;
592  }
593  case ID_MB: {
594  MetaBall *mb = (MetaBall *)id;
595 
596  if (outliner_animdata_test(mb->adt)) {
597  outliner_add_element(space_outliner, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
598  }
599 
600  for (int a = 0; a < mb->totcol; a++) {
601  outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a);
602  }
603  break;
604  }
605  case ID_MA: {
606  Material *ma = (Material *)id;
607  if (outliner_animdata_test(ma->adt)) {
608  outliner_add_element(space_outliner, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
609  }
610  break;
611  }
612  case ID_TE: {
613  Tex *tex = (Tex *)id;
615  outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
616  }
617  outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0);
618  break;
619  }
620  case ID_CA: {
621  Camera *ca = (Camera *)id;
622  if (outliner_animdata_test(ca->adt)) {
623  outliner_add_element(space_outliner, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
624  }
625  break;
626  }
627  case ID_CF: {
628  CacheFile *cache_file = (CacheFile *)id;
629  if (outliner_animdata_test(cache_file->adt)) {
630  outliner_add_element(space_outliner, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
631  }
632 
633  break;
634  }
635  case ID_LA: {
636  Light *la = (Light *)id;
637  if (outliner_animdata_test(la->adt)) {
638  outliner_add_element(space_outliner, &te->subtree, la, te, TSE_ANIM_DATA, 0);
639  }
640  break;
641  }
642  case ID_SPK: {
643  Speaker *spk = (Speaker *)id;
644  if (outliner_animdata_test(spk->adt)) {
645  outliner_add_element(space_outliner, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
646  }
647  break;
648  }
649  case ID_LP: {
650  LightProbe *prb = (LightProbe *)id;
651  if (outliner_animdata_test(prb->adt)) {
652  outliner_add_element(space_outliner, &te->subtree, prb, te, TSE_ANIM_DATA, 0);
653  }
654  break;
655  }
656  case ID_WO: {
657  World *wrld = (World *)id;
658  if (outliner_animdata_test(wrld->adt)) {
659  outliner_add_element(space_outliner, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
660  }
661  break;
662  }
663  case ID_KE: {
664  Key *key = (Key *)id;
665  if (outliner_animdata_test(key->adt)) {
666  outliner_add_element(space_outliner, &te->subtree, key, te, TSE_ANIM_DATA, 0);
667  }
668  break;
669  }
670  case ID_AC: {
671  /* XXX do we want to be exposing the F-Curves here? */
672  /* bAction *act = (bAction *)id; */
673  break;
674  }
675  case ID_AR: {
676  bArmature *arm = (bArmature *)id;
677 
678  if (outliner_animdata_test(arm->adt)) {
679  outliner_add_element(space_outliner, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
680  }
681 
682  if (arm->edbo) {
683  int a = 0;
684  LISTBASE_FOREACH_INDEX (EditBone *, ebone, arm->edbo, a) {
686  space_outliner, &te->subtree, id, te, TSE_EBONE, a);
687  ten->directdata = ebone;
688  ten->name = ebone->name;
689  ebone->temp.p = ten;
690  }
691  /* make hierarchy */
692  TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>(
693  ((EditBone *)arm->edbo->first)->temp.p) :
694  nullptr;
695  while (ten) {
696  TreeElement *nten = ten->next, *par;
697  EditBone *ebone = (EditBone *)ten->directdata;
698  if (ebone->parent) {
699  BLI_remlink(&te->subtree, ten);
700  par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p);
701  BLI_addtail(&par->subtree, ten);
702  ten->parent = par;
703  }
704  ten = nten;
705  }
706  }
707  else {
708  /* do not extend Armature when we have posemode */
709  tselem = TREESTORE(te->parent);
710  if (TSE_IS_REAL_ID(tselem) && GS(tselem->id->name) == ID_OB &&
711  ((Object *)tselem->id)->mode & OB_MODE_POSE) {
712  /* pass */
713  }
714  else {
715  int a = 0;
716  LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
717  outliner_add_bone(space_outliner, &te->subtree, id, bone, te, &a);
718  }
719  }
720  }
721  break;
722  }
723  case ID_LS: {
725 
727  outliner_add_element(space_outliner, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
728  }
729 
730  for (int a = 0; a < MAX_MTEX; a++) {
731  if (linestyle->mtex[a]) {
732  outliner_add_element(space_outliner, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
733  }
734  }
735  break;
736  }
737  case ID_GD: {
738  bGPdata *gpd = (bGPdata *)id;
739 
740  if (outliner_animdata_test(gpd->adt)) {
741  outliner_add_element(space_outliner, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
742  }
743 
744  /* TODO: base element for layers? */
745  int index = 0;
746  LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl, &gpd->layers) {
747  outliner_add_element(space_outliner, &te->subtree, gpl, te, TSE_GP_LAYER, index);
748  index++;
749  }
750  break;
751  }
752  case ID_GR: {
753  /* Don't expand for instances, creates too many elements. */
754  if (!(te->parent && te->parent->idcode == ID_OB)) {
755  Collection *collection = (Collection *)id;
756  outliner_add_collection_recursive(space_outliner, collection, te);
757  }
758  break;
759  }
760  case ID_CV: {
761  Curves *curves = (Curves *)id;
762  if (outliner_animdata_test(curves->adt)) {
763  outliner_add_element(space_outliner, &te->subtree, curves, te, TSE_ANIM_DATA, 0);
764  }
765  break;
766  }
767  case ID_PT: {
768  PointCloud *pointcloud = (PointCloud *)id;
769  if (outliner_animdata_test(pointcloud->adt)) {
770  outliner_add_element(space_outliner, &te->subtree, pointcloud, te, TSE_ANIM_DATA, 0);
771  }
772  break;
773  }
774  case ID_VO: {
775  Volume *volume = (Volume *)id;
776  if (outliner_animdata_test(volume->adt)) {
777  outliner_add_element(space_outliner, &te->subtree, volume, te, TSE_ANIM_DATA, 0);
778  }
779  break;
780  }
781  case ID_SIM: {
784  outliner_add_element(space_outliner, &te->subtree, simulation, te, TSE_ANIM_DATA, 0);
785  }
786  break;
787  }
788  default:
789  break;
790  }
791 }
792 
793 namespace blender::ed::outliner {
794 
796  ListBase *lb,
797  void *idv,
798  TreeElement *parent,
799  short type,
800  short index,
801  const bool expand)
802 {
803  ID *id = reinterpret_cast<ID *>(idv);
804 
806  id = ((PointerRNA *)idv)->owner_id;
807  if (!id) {
808  id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data);
809  }
810  }
811  else if (type == TSE_GP_LAYER) {
812  /* idv is the layer itself */
813  id = TREESTORE(parent)->id;
814  }
815  else if (ELEM(type, TSE_GENERIC_LABEL)) {
816  id = nullptr;
817  }
818 
819  /* exceptions */
821  /* pass */
822  }
823  else if (id == nullptr) {
824  return nullptr;
825  }
826 
827  if (type == 0) {
828  /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
830  }
831 
832  TreeElement *te = MEM_new<TreeElement>(__func__);
833  /* add to the visual tree */
834  BLI_addtail(lb, te);
835  /* add to the storage */
836  check_persistent(space_outliner, te, id, type, index);
837  TreeStoreElem *tselem = TREESTORE(te);
838 
839  /* if we are searching for something expand to see child elements */
840  if (SEARCHING_OUTLINER(space_outliner)) {
841  tselem->flag |= TSE_CHILDSEARCH;
842  }
843 
844  te->parent = parent;
845  te->index = index; /* For data arrays. */
846 
847  /* New inheritance based element representation. Not all element types support this yet,
848  * eventually it should replace #TreeElement entirely. */
850  if (te->abstract_element) {
851  /* Element types ported to the new design are expected to have their name set at this point! */
852  BLI_assert(te->name != nullptr);
853  }
854 
856  /* pass */
857  }
859  /* pass */
860  }
862  /* pass */
863  }
864  else if (type == TSE_GP_LAYER) {
865  /* pass */
866  }
868  /* pass */
869  }
870  else if (ELEM(type, TSE_ID_BASE, TSE_GENERIC_LABEL)) {
871  /* pass */
872  }
873  else if (type == TSE_SOME_ID) {
874  if (!te->abstract_element) {
875  BLI_assert_msg(0, "Expected this ID type to be ported to new Outliner tree-element design");
876  }
877  }
878  else if (ELEM(type,
882  if (!te->abstract_element) {
883  BLI_assert_msg(0,
884  "Expected override types to be ported to new Outliner tree-element design");
885  }
886  }
887  else {
888  /* Other cases must be caught above. */
889  BLI_assert(TSE_IS_REAL_ID(tselem));
890 
891  /* The new type design sets the name already, don't override that here. We need to figure out
892  * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */
893  if (!te->abstract_element) {
894  te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */
895  }
896  te->idcode = GS(id->name);
897  }
898 
899  if (!expand) {
900  /* Pass */
901  }
902  else if (te->abstract_element && te->abstract_element->isExpandValid()) {
903  tree_element_expand(*te->abstract_element, *space_outliner);
904  }
905  else if (type == TSE_SOME_ID) {
906  /* ID types not (fully) ported to new design yet. */
907  if (te->abstract_element->expandPoll(*space_outliner)) {
908  outliner_add_id_contents(space_outliner, te, tselem, id);
909  }
910  }
911  else if (ELEM(type,
914  TSE_NLA,
917  TSE_GP_LAYER,
921  TSE_SEQUENCE,
925  BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
926  }
927 
928  return te;
929 }
930 
931 } // namespace blender::ed::outliner
932 
933 /* ======================================================= */
934 
936 {
937  te->name = BKE_collection_ui_name_get(collection);
938  te->directdata = collection;
939 }
940 
942  ListBase *tree,
943  Collection *collection,
944  TreeElement *parent)
945 {
946  LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
947  outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0);
948  }
949 }
950 
952  Collection *collection,
953  TreeElement *ten)
954 {
955  outliner_add_collection_init(ten, collection);
956 
957  LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
959  space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0);
960  }
961 
962  if (space_outliner->outlinevis != SO_SCENES) {
963  outliner_add_collection_objects(space_outliner, &ten->subtree, collection, ten);
964  }
965 
966  return ten;
967 }
968 
971 /* ======================================================= */
972 /* Generic Tree Building helpers - order these are called is top to bottom */
973 
974 /* -------------------------------------------------------------------- */
978 struct tTreeSort {
980  ID *id;
981  const char *name;
982  short idcode;
983 };
984 
985 /* alphabetical comparator, trying to put objects first */
986 static int treesort_alpha_ob(const void *v1, const void *v2)
987 {
988  const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
989  const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
990 
991  /* first put objects last (hierarchy) */
992  int comp = (x1->idcode == ID_OB);
993  if (x2->idcode == ID_OB) {
994  comp += 2;
995  }
996 
997  if (comp == 1) {
998  return 1;
999  }
1000  if (comp == 2) {
1001  return -1;
1002  }
1003  if (comp == 3) {
1004  /* Among objects first come the ones in the collection, followed by the ones not on it.
1005  * This way we can have the dashed lines in a separate style connecting the former. */
1006  if ((x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) !=
1007  (x2->te->flag & TE_CHILD_NOT_IN_COLLECTION)) {
1008  return (x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) ? 1 : -1;
1009  }
1010 
1011  comp = BLI_strcasecmp_natural(x1->name, x2->name);
1012 
1013  if (comp > 0) {
1014  return 1;
1015  }
1016  if (comp < 0) {
1017  return -1;
1018  }
1019  return 0;
1020  }
1021  return 0;
1022 }
1023 
1024 /* Move children that are not in the collection to the end of the list. */
1025 static int treesort_child_not_in_collection(const void *v1, const void *v2)
1026 {
1027  const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
1028  const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
1029 
1030  /* Among objects first come the ones in the collection, followed by the ones not on it.
1031  * This way we can have the dashed lines in a separate style connecting the former. */
1032  if ((x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) != (x2->te->flag & TE_CHILD_NOT_IN_COLLECTION)) {
1033  return (x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) ? 1 : -1;
1034  }
1035  return 0;
1036 }
1037 
1038 /* alphabetical comparator */
1039 static int treesort_alpha(const void *v1, const void *v2)
1040 {
1041  const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
1042  const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
1043 
1044  int comp = BLI_strcasecmp_natural(x1->name, x2->name);
1045 
1046  if (comp > 0) {
1047  return 1;
1048  }
1049  if (comp < 0) {
1050  return -1;
1051  }
1052  return 0;
1053 }
1054 
1055 /* this is nice option for later? doesn't look too useful... */
1056 #if 0
1057 static int treesort_obtype_alpha(const void *v1, const void *v2)
1058 {
1059  const tTreeSort *x1 = v1, *x2 = v2;
1060 
1061  /* first put objects last (hierarchy) */
1062  if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
1063  return 1;
1064  }
1065  else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
1066  return -1;
1067  }
1068  else {
1069  /* 2nd we check ob type */
1070  if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
1071  if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
1072  return 1;
1073  }
1074  else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
1075  return -1;
1076  }
1077  else {
1078  return 0;
1079  }
1080  }
1081  else {
1082  int comp = BLI_strcasecmp_natural(x1->name, x2->name);
1083 
1084  if (comp > 0) {
1085  return 1;
1086  }
1087  else if (comp < 0) {
1088  return -1;
1089  }
1090  return 0;
1091  }
1092  }
1093 }
1094 #endif
1095 
1096 /* sort happens on each subtree individual */
1097 static void outliner_sort(ListBase *lb)
1098 {
1099  TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
1100  if (last_te == nullptr) {
1101  return;
1102  }
1103  TreeStoreElem *last_tselem = TREESTORE(last_te);
1104 
1105  /* Sorting rules; only object lists, ID lists, or deform-groups. */
1106  if (ELEM(last_tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
1107  ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB))) {
1108  int totelem = BLI_listbase_count(lb);
1109 
1110  if (totelem > 1) {
1111  tTreeSort *tear = reinterpret_cast<tTreeSort *>(
1112  MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
1113  tTreeSort *tp = tear;
1114  int skip = 0;
1115 
1116  LISTBASE_FOREACH (TreeElement *, te, lb) {
1117  TreeStoreElem *tselem = TREESTORE(te);
1118  tp->te = te;
1119  tp->name = te->name;
1120  tp->idcode = te->idcode;
1121 
1122  if (!ELEM(tselem->type, TSE_SOME_ID, TSE_DEFGROUP)) {
1123  tp->idcode = 0; /* Don't sort this. */
1124  }
1125  if (tselem->type == TSE_ID_BASE) {
1126  tp->idcode = 1; /* Do sort this. */
1127  }
1128 
1129  tp->id = tselem->id;
1130  tp++;
1131  }
1132 
1133  /* just sort alphabetically */
1134  if (tear->idcode == 1) {
1135  qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
1136  }
1137  else {
1138  /* keep beginning of list */
1139  for (tp = tear, skip = 0; skip < totelem; skip++, tp++) {
1140  if (tp->idcode) {
1141  break;
1142  }
1143  }
1144 
1145  if (skip < totelem) {
1146  qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
1147  }
1148  }
1149 
1150  BLI_listbase_clear(lb);
1151  tp = tear;
1152  while (totelem--) {
1153  BLI_addtail(lb, tp->te);
1154  tp++;
1155  }
1156  MEM_freeN(tear);
1157  }
1158  }
1159 
1160  LISTBASE_FOREACH (TreeElement *, te_iter, lb) {
1161  outliner_sort(&te_iter->subtree);
1162  }
1163 }
1164 
1166 {
1167  TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
1168  if (last_te == nullptr) {
1169  return;
1170  }
1171  TreeStoreElem *last_tselem = TREESTORE(last_te);
1172 
1173  /* Sorting rules: only object lists. */
1174  if ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB)) {
1175  int totelem = BLI_listbase_count(lb);
1176 
1177  if (totelem > 1) {
1178  tTreeSort *tear = reinterpret_cast<tTreeSort *>(
1179  MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
1180  tTreeSort *tp = tear;
1181 
1182  LISTBASE_FOREACH (TreeElement *, te, lb) {
1183  TreeStoreElem *tselem = TREESTORE(te);
1184  tp->te = te;
1185  tp->name = te->name;
1186  tp->idcode = te->idcode;
1187  tp->id = tselem->id;
1188  tp++;
1189  }
1190 
1191  qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection);
1192 
1193  BLI_listbase_clear(lb);
1194  tp = tear;
1195  while (totelem--) {
1196  BLI_addtail(lb, tp->te);
1197  tp++;
1198  }
1199  MEM_freeN(tear);
1200  }
1201  }
1202 
1203  LISTBASE_FOREACH (TreeElement *, te_iter, lb) {
1204  outliner_collections_children_sort(&te_iter->subtree);
1205  }
1206 }
1207 
1210 /* -------------------------------------------------------------------- */
1216  int ys;
1217 };
1218 
1224  ARegion *region,
1225  OutlinerTreeElementFocus *focus)
1226 {
1227  View2D *v2d = &region->v2d;
1228 
1229  if (focus->tselem != nullptr) {
1230  outliner_set_coordinates(region, space_outliner);
1231 
1232  TreeElement *te_new = outliner_find_tree_element(&space_outliner->tree, focus->tselem);
1233 
1234  if (te_new != nullptr) {
1235  int ys_new = te_new->ys;
1236  int ys_old = focus->ys;
1237 
1238  float y_move = MIN2(ys_new - ys_old, -v2d->cur.ymax);
1239  BLI_rctf_translate(&v2d->cur, 0, y_move);
1240  }
1241  else {
1242  return;
1243  }
1244  }
1245 }
1246 
1248 {
1250 }
1251 
1253 {
1254  TreeStoreElem *tselem = TREESTORE(te);
1255  return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB));
1256 }
1257 
1262  const SpaceOutliner *space_outliner,
1263  TreeElement *te,
1264  const float limit,
1265  bool (*callback_test)(TreeElement *))
1266 {
1267  if (callback_test(te)) {
1268  return te;
1269  }
1270 
1271  if (TSELEM_OPEN(te->store_elem, space_outliner)) {
1272  LISTBASE_FOREACH (TreeElement *, te_iter, &te->subtree) {
1274  space_outliner, te_iter, limit, callback_test);
1275  if (te_sub != nullptr) {
1276  return te_sub;
1277  }
1278  }
1279  }
1280 
1281  return nullptr;
1282 }
1283 
1295  const float view_co,
1296  const float view_co_limit)
1297 {
1298  TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_co);
1299 
1300  bool (*callback_test)(TreeElement *);
1301  if ((space_outliner->outlinevis == SO_VIEW_LAYER) &&
1302  (space_outliner->filter & SO_FILTER_NO_COLLECTION)) {
1303  callback_test = test_object_callback;
1304  }
1305  else {
1306  callback_test = test_collection_callback;
1307  }
1308 
1309  while (te != nullptr) {
1311  space_outliner, te, view_co_limit, callback_test);
1312  if (te_sub != nullptr) {
1313  /* Skip the element if it was not visible to start with. */
1314  if (te->ys + UI_UNIT_Y > view_co_limit) {
1315  return te_sub;
1316  }
1317  return nullptr;
1318  }
1319 
1320  if (te->next) {
1321  te = te->next;
1322  continue;
1323  }
1324 
1325  if (te->parent == nullptr) {
1326  break;
1327  }
1328 
1329  while (te->parent) {
1330  if (te->parent->next) {
1331  te = te->parent->next;
1332  break;
1333  }
1334  te = te->parent;
1335  }
1336  }
1337 
1338  return nullptr;
1339 }
1340 
1349  ARegion *region,
1350  OutlinerTreeElementFocus *focus)
1351 {
1352  float limit = region->v2d.cur.ymin;
1353 
1354  outliner_set_coordinates(region, space_outliner);
1355 
1357  space_outliner, region->v2d.cur.ymax, limit);
1358 
1359  if (te != nullptr) {
1360  focus->tselem = TREESTORE(te);
1361  focus->ys = te->ys;
1362  }
1363  else {
1364  focus->tselem = nullptr;
1365  }
1366 }
1367 
1368 static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner)
1369 {
1370  int exclude_filter = space_outliner->filter & ~SO_FILTER_OB_STATE;
1371 
1372  if (space_outliner->search_string[0] != 0) {
1373  exclude_filter |= SO_FILTER_SEARCH;
1374  }
1375  else {
1376  exclude_filter &= ~SO_FILTER_SEARCH;
1377  }
1378 
1379  /* Let's have this for the collection options at first. */
1380  if (!SUPPORT_FILTER_OUTLINER(space_outliner)) {
1381  return (exclude_filter & SO_FILTER_SEARCH);
1382  }
1383 
1384  if (space_outliner->filter & SO_FILTER_NO_OBJECT) {
1385  exclude_filter |= SO_FILTER_OB_TYPE;
1386  }
1387 
1388  switch (space_outliner->filter_state) {
1389  case SO_FILTER_OB_VISIBLE:
1390  exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
1391  break;
1392  case SO_FILTER_OB_SELECTED:
1393  exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
1394  break;
1395  case SO_FILTER_OB_ACTIVE:
1396  exclude_filter |= SO_FILTER_OB_STATE_ACTIVE;
1397  break;
1399  exclude_filter |= SO_FILTER_OB_STATE_SELECTABLE;
1400  break;
1401  }
1402 
1403  return exclude_filter;
1404 }
1405 
1406 static bool outliner_element_visible_get(ViewLayer *view_layer,
1407  TreeElement *te,
1408  const int exclude_filter)
1409 {
1410  if ((exclude_filter & SO_FILTER_ANY) == 0) {
1411  return true;
1412  }
1413 
1414  TreeStoreElem *tselem = TREESTORE(te);
1415  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1416  if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) {
1417  return false;
1418  }
1419 
1420  Object *ob = (Object *)tselem->id;
1421  Base *base = (Base *)te->directdata;
1422  BLI_assert((base == nullptr) || (base->object == ob));
1423 
1424  if (exclude_filter & SO_FILTER_OB_TYPE) {
1425  switch (ob->type) {
1426  case OB_MESH:
1427  if (exclude_filter & SO_FILTER_NO_OB_MESH) {
1428  return false;
1429  }
1430  break;
1431  case OB_ARMATURE:
1432  if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) {
1433  return false;
1434  }
1435  break;
1436  case OB_EMPTY:
1437  if (exclude_filter & SO_FILTER_NO_OB_EMPTY) {
1438  return false;
1439  }
1440  break;
1441  case OB_LAMP:
1442  if (exclude_filter & SO_FILTER_NO_OB_LAMP) {
1443  return false;
1444  }
1445  break;
1446  case OB_CAMERA:
1447  if (exclude_filter & SO_FILTER_NO_OB_CAMERA) {
1448  return false;
1449  }
1450  break;
1451  default:
1452  if (exclude_filter & SO_FILTER_NO_OB_OTHERS) {
1453  return false;
1454  }
1455  break;
1456  }
1457  }
1458 
1459  if (exclude_filter & SO_FILTER_OB_STATE) {
1460  if (base == nullptr) {
1461  base = BKE_view_layer_base_find(view_layer, ob);
1462 
1463  if (base == nullptr) {
1464  return false;
1465  }
1466  }
1467 
1468  bool is_visible = true;
1469  if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
1470  if ((base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
1471  is_visible = false;
1472  }
1473  }
1474  else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
1475  if ((base->flag & BASE_SELECTED) == 0) {
1476  is_visible = false;
1477  }
1478  }
1479  else if (exclude_filter & SO_FILTER_OB_STATE_SELECTABLE) {
1480  if ((base->flag & BASE_SELECTABLE) == 0) {
1481  is_visible = false;
1482  }
1483  }
1484  else {
1485  BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
1486  if (base != BASACT(view_layer)) {
1487  is_visible = false;
1488  }
1489  }
1490 
1491  if (exclude_filter & SO_FILTER_OB_STATE_INVERSE) {
1492  is_visible = !is_visible;
1493  }
1494 
1495  return is_visible;
1496  }
1497 
1498  if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
1499  (te->parent->idcode == ID_OB)) {
1500  if (exclude_filter & SO_FILTER_NO_CHILDREN) {
1501  return false;
1502  }
1503  }
1504  }
1505  else if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
1506  (te->parent->idcode == ID_OB)) {
1507  if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
1508  return false;
1509  }
1510  }
1511 
1512  return true;
1513 }
1514 
1515 static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
1516 {
1517  int fn_flag = 0;
1518 
1519  if ((flags & SO_FIND_CASE_SENSITIVE) == 0) {
1520  fn_flag |= FNM_CASEFOLD;
1521  }
1522 
1523  return fnmatch(name, te->name, fn_flag) == 0;
1524 }
1525 
1527 {
1528  TreeStoreElem *tselem = TREESTORE(te);
1529 
1530  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1531  return true;
1532  }
1533 
1534  /* Collection instance datablocks should not be extracted. */
1535  if (outliner_is_collection_tree_element(te) && !(te->parent && te->parent->idcode == ID_OB)) {
1536  return true;
1537  }
1538 
1539  return false;
1540 }
1541 
1543  ListBase *parent_subtree)
1544 {
1545  TreeElement *te_next = element->next;
1546 
1548  TreeElement *te_prev = nullptr;
1549  for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te;
1550  te = te_prev) {
1551  te_prev = te->prev;
1552 
1554  continue;
1555  }
1556 
1557  te_next = te;
1558  BLI_remlink(&element->subtree, te);
1559  BLI_insertlinkafter(parent_subtree, element->prev, te);
1560  te->parent = element->parent;
1561  }
1562  }
1563 
1564  outliner_free_tree_element(element, parent_subtree);
1565  return te_next;
1566 }
1567 
1568 static int outliner_filter_subtree(SpaceOutliner *space_outliner,
1569  ViewLayer *view_layer,
1570  ListBase *lb,
1571  const char *search_string,
1572  const int exclude_filter)
1573 {
1574  TreeElement *te, *te_next;
1575  TreeStoreElem *tselem;
1576 
1577  for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) {
1578  te_next = te->next;
1579  if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
1580  /* Don't free the tree, but extract the children from the parent and add to this tree. */
1581  /* This also needs filtering the subtree prior (see T69246). */
1583  space_outliner, view_layer, &te->subtree, search_string, exclude_filter);
1584  te_next = outliner_extract_children_from_subtree(te, lb);
1585  continue;
1586  }
1587  if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
1588  /* Filter subtree too. */
1590  space_outliner, view_layer, &te->subtree, search_string, exclude_filter);
1591  continue;
1592  }
1593 
1594  if (!outliner_filter_has_name(te, search_string, space_outliner->search_flags)) {
1595  /* item isn't something we're looking for, but...
1596  * - if the subtree is expanded, check if there are any matches that can be easily found
1597  * so that searching for "cu" in the default scene will still match the Cube
1598  * - otherwise, we can't see within the subtree and the item doesn't match,
1599  * so these can be safely ignored (i.e. the subtree can get freed)
1600  */
1601  tselem = TREESTORE(te);
1602 
1603  /* flag as not a found item */
1604  tselem->flag &= ~TSE_SEARCHMATCH;
1605 
1606  if ((!TSELEM_OPEN(tselem, space_outliner)) ||
1608  space_outliner, view_layer, &te->subtree, search_string, exclude_filter) == 0) {
1610  }
1611  }
1612  else {
1613  tselem = TREESTORE(te);
1614 
1615  /* flag as a found item - we can then highlight it */
1616  tselem->flag |= TSE_SEARCHMATCH;
1617 
1618  /* filter subtree too */
1620  space_outliner, view_layer, &te->subtree, search_string, exclude_filter);
1621  }
1622  }
1623 
1624  /* if there are still items in the list, that means that there were still some matches */
1625  return (BLI_listbase_is_empty(lb) == false);
1626 }
1627 
1628 static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer)
1629 {
1630  char search_buff[sizeof(((struct SpaceOutliner *)nullptr)->search_string) + 2];
1631  char *search_string;
1632 
1633  const int exclude_filter = outliner_exclude_filter_get(space_outliner);
1634 
1635  if (exclude_filter == 0) {
1636  return;
1637  }
1638 
1639  if (space_outliner->search_flags & SO_FIND_COMPLETE) {
1640  search_string = space_outliner->search_string;
1641  }
1642  else {
1643  /* Implicitly add heading/trailing wildcards if needed. */
1644  BLI_strncpy_ensure_pad(search_buff, space_outliner->search_string, '*', sizeof(search_buff));
1645  search_string = search_buff;
1646  }
1647 
1649  space_outliner, view_layer, &space_outliner->tree, search_string, exclude_filter);
1650 }
1651 
1653 {
1654  ID *id_iter;
1655  FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
1656  id_iter->newid = nullptr;
1657  }
1659 }
1660 
1663 /* -------------------------------------------------------------------- */
1668  Scene *scene,
1669  ViewLayer *view_layer,
1670  SpaceOutliner *space_outliner,
1671  ARegion *region)
1672 {
1673  /* Are we looking for something - we want to tag parents to filter child matches
1674  * - NOT in data-blocks view - searching all data-blocks takes way too long to be useful
1675  * - this variable is only set once per tree build */
1676  if (space_outliner->search_string[0] != 0 && space_outliner->outlinevis != SO_DATA_API) {
1677  space_outliner->search_flags |= SO_SEARCH_RECURSIVE;
1678  }
1679  else {
1680  space_outliner->search_flags &= ~SO_SEARCH_RECURSIVE;
1681  }
1682 
1683  if (space_outliner->runtime->treehash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) &&
1684  space_outliner->treestore) {
1686  space_outliner->treestore);
1687  }
1688  space_outliner->storeflag &= ~SO_TREESTORE_REBUILD;
1689 
1690  if (region->do_draw & RGN_DRAW_NO_REBUILD) {
1691  BLI_assert_msg(space_outliner->runtime->tree_display != nullptr,
1692  "Skipping rebuild before tree was built properly, a full redraw should be "
1693  "triggered instead");
1694  return;
1695  }
1696 
1698  outliner_store_scrolling_position(space_outliner, region, &focus);
1699 
1700  outliner_free_tree(&space_outliner->tree);
1701  outliner_storage_cleanup(space_outliner);
1702 
1704  space_outliner->outlinevis, *space_outliner);
1705 
1706  /* All tree displays should be created as sub-classes of AbstractTreeDisplay. */
1707  BLI_assert(space_outliner->runtime->tree_display != nullptr);
1708 
1709  TreeSourceData source_data{*mainvar, *scene, *view_layer};
1710  space_outliner->tree = space_outliner->runtime->tree_display->buildTree(source_data);
1711 
1712  if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
1713  outliner_sort(&space_outliner->tree);
1714  }
1715  else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) {
1716  /* We group the children that are in the collection before the ones that are not.
1717  * This way we can try to draw them in a different style altogether.
1718  * We also have to respect the original order of the elements in case alphabetical
1719  * sorting is not enabled. This keep object data and modifiers before its children. */
1720  outliner_collections_children_sort(&space_outliner->tree);
1721  }
1722 
1723  outliner_filter_tree(space_outliner, view_layer);
1724  outliner_restore_scrolling_position(space_outliner, region, &focus);
1725 
1726  /* `ID.newid` pointer is abused when building tree, DO NOT call #BKE_main_id_newptr_and_tag_clear
1727  * as this expects valid IDs in this pointer, not random unknown data. */
1729 }
1730 
const char * BKE_collection_ui_name_get(struct Collection *collection)
Definition: collection.c:736
support for deformation groups and hooks.
const struct ListBase * BKE_object_defgroup_list(const struct Object *ob)
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:367
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:361
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_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define BLI_INLINE
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
Definition: BLI_listbase.h:348
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
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:498
@ BLI_MEMPOOL_ALLOW_ITER
Definition: BLI_mempool.h:107
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_mempool.c:577
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:434
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition: BLI_mempool.c:253
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
Definition: BLI_mempool.c:319
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:707
void BLI_rctf_translate(struct rctf *rect, float x, float y)
Definition: rct.c:566
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:719
char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, char pad, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:78
#define ELEM(...)
#define MIN2(a, b)
#define IFACE_(msgid)
@ LIB_TAG_DOIT
Definition: DNA_ID.h:707
@ ID_CA
Definition: DNA_ID_enums.h:56
@ ID_AR
Definition: DNA_ID_enums.h:66
@ ID_CF
Definition: DNA_ID_enums.h:78
@ ID_LI
Definition: DNA_ID_enums.h:46
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_VO
Definition: DNA_ID_enums.h:83
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_KE
Definition: DNA_ID_enums.h:58
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_LS
Definition: DNA_ID_enums.h:75
@ ID_GD
Definition: DNA_ID_enums.h:71
@ ID_CV
Definition: DNA_ID_enums.h:81
@ ID_LP
Definition: DNA_ID_enums.h:80
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_SIM
Definition: DNA_ID_enums.h:84
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_AC
Definition: DNA_ID_enums.h:67
@ ID_CU_LEGACY
Definition: DNA_ID_enums.h:49
@ ID_ME
Definition: DNA_ID_enums.h:48
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_SPK
Definition: DNA_ID_enums.h:63
@ ID_MB
Definition: DNA_ID_enums.h:50
@ ID_OB
Definition: DNA_ID_enums.h:47
@ ID_PT
Definition: DNA_ID_enums.h:82
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_LATTICE
@ OB_EMPTY
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_GPENCIL
@ OB_DUPLICOLLECTION
#define TSE_IS_REAL_ID(_tse)
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_LIBRARY_OVERRIDE_OPERATION
@ 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_GENERIC_LABEL
@ 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
@ 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.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
#define MAX_MTEX
Definition: Stroke.h:31
#define UI_UNIT_Y
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static std::unique_ptr< AbstractTreeDisplay > createFromDisplayMode(int mode, SpaceOutliner &space_outliner)
Definition: tree_display.cc:18
static std::unique_ptr< AbstractTreeElement > createFromType(int type, TreeElement &legacy_te, void *idv)
Definition: tree_element.cc:33
bool outliner_animdata_test(const AnimData *adt)
Definition: common.cc:59
Scene scene
FreestyleLineStyle linestyle
Simulation simulation
void * tree
#define str(s)
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static unsigned a[3]
Definition: RandGen.cpp:78
TreeElement * outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, TreeElement *parent, short type, short index, const bool expand)
void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
bool outliner_is_collection_tree_element(const TreeElement *te)
void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
#define TREESTORE_ID_TYPE(_id)
#define SEARCHING_OUTLINER(sov)
#define SUPPORT_FILTER_OUTLINER(space_outliner_)
@ TE_CHILD_NOT_IN_COLLECTION
@ TE_FREE_NAME
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)
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)
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)
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)
static void check_persistent(SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
static void outliner_clear_newid_from_main(Main *bmain)
static void outliner_add_object_contents(SpaceOutliner *space_outliner, TreeElement *te, TreeStoreElem *tselem, Object *ob)
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)
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)
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:41
void * p
Definition: BKE_armature.h:107
union EditBone::@3 temp
struct FreestyleLineStyle * linestyle
struct FreestyleLineSet * next
struct AnimData * adt
struct MTex * mtex[18]
Definition: DNA_ID.h:368
int tag
Definition: DNA_ID.h:387
struct ID * newid
Definition: DNA_ID.h:370
char name[66]
Definition: DNA_ID.h:378
struct AnimData * adt
Definition: DNA_key_types.h:65
struct AnimData * adt
struct AnimData * adt
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
struct Tex * tex
Definition: BKE_main.h:121
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 constraints
struct Collection * instance_collection
struct bPose * pose
ListBase modifiers
ListBase greasepencil_modifiers
struct Material ** mat
ListBase shader_fx
struct AnimData * adt
void * data
ParticleSettings * part
struct AnimData * adt
ListBase view_layers
struct AnimData * adt
std::unique_ptr< outliner::AbstractTreeDisplay > tree_display
struct GHash * treehash
char search_string[64]
SpaceOutliner_Runtime * runtime
struct BLI_mempool * treestore
struct AnimData * adt
struct AnimData * adt
struct Image * ima
struct TreeElement * parent
std::unique_ptr< outliner::AbstractTreeElement > abstract_element
ListBase subtree
TreeStoreElem * store_elem
struct TreeElement * prev
const char * name
struct TreeElement * next
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
The data to build the tree from.
Definition: tree_display.hh:43
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
const char * name
TreeElement * te
Establish and manage Outliner trees for different display modes.