Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_outliner')
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt8
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc52
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc61
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh39
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc36
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc116
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc235
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc65
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc19
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.cc268
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.hh86
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_seq.cc111
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_seq.hh60
14 files changed, 750 insertions, 408 deletions
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index cac9d4131f8..d97f48bcb68 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -65,7 +65,9 @@ set(SRC
tree/tree_element_id_scene.cc
tree/tree_element_nla.cc
tree/tree_element_overrides.cc
+ tree/tree_element_rna.cc
tree/tree_element_scene_objects.cc
+ tree/tree_element_seq.cc
tree/tree_element_view_layer.cc
outliner_intern.hh
@@ -81,7 +83,9 @@ set(SRC
tree/tree_element_id_scene.hh
tree/tree_element_nla.hh
tree/tree_element_overrides.hh
+ tree/tree_element_rna.hh
tree/tree_element_scene_objects.hh
+ tree/tree_element_seq.hh
tree/tree_element_view_layer.hh
)
@@ -91,9 +95,5 @@ set(LIB
bf_editor_undo
)
-if(WITH_INTERNATIONAL)
- add_definitions(-DWITH_INTERNATIONAL)
-endif()
-
blender_add_lib(bf_editor_space_outliner "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index 6de8d9539a9..13c273d1ec9 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -81,6 +81,7 @@
#include "outliner_intern.hh"
#include "tree/tree_display.hh"
#include "tree/tree_element.hh"
+#include "tree/tree_element_rna.hh"
using namespace blender::ed::outliner;
@@ -1909,20 +1910,20 @@ static void outliner_draw_rnacols(ARegion *region, int sizex)
static void outliner_draw_rnabuts(
uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex, ListBase *lb)
{
- PointerRNA *ptr;
+ PointerRNA ptr;
PropertyRNA *prop;
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
- if (tselem->type == TSE_RNA_PROPERTY) {
- ptr = &te->rnaptr;
- prop = reinterpret_cast<PropertyRNA *>(te->directdata);
+ if (TreeElementRNAProperty *te_rna_prop = tree_element_cast<TreeElementRNAProperty>(te)) {
+ ptr = te_rna_prop->getPointerRNA();
+ prop = te_rna_prop->getPropertyRNA();
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (RNA_property_type(prop) == PROP_POINTER) {
uiBut *but = uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
"",
@@ -1935,7 +1936,7 @@ static void outliner_draw_rnabuts(
}
else if (RNA_property_type(prop) == PROP_ENUM) {
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
nullptr,
@@ -1947,7 +1948,7 @@ static void outliner_draw_rnabuts(
}
else {
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
"",
@@ -1959,12 +1960,13 @@ static void outliner_draw_rnabuts(
}
}
}
- else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
- ptr = &te->rnaptr;
- prop = reinterpret_cast<PropertyRNA *>(te->directdata);
+ else if (TreeElementRNAArrayElement *te_rna_array_elem =
+ tree_element_cast<TreeElementRNAArrayElement>(te)) {
+ ptr = te_rna_array_elem->getPointerRNA();
+ prop = te_rna_array_elem->getPropertyRNA();
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
te->index,
"",
@@ -2478,9 +2480,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_POSE_CHANNEL:
data.icon = ICON_BONE_DATA;
break;
- case TSE_PROXY:
- data.icon = ICON_GHOST_ENABLED;
- break;
case TSE_R_LAYER_BASE:
data.icon = ICON_RENDERLAYERS;
break;
@@ -2554,15 +2553,19 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_SEQUENCE_DUP:
data.icon = ICON_SEQ_STRIP_DUPLICATE;
break;
- case TSE_RNA_STRUCT:
- if (RNA_struct_is_ID(te->rnaptr.type)) {
- data.drag_id = (ID *)te->rnaptr.data;
- data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ case TSE_RNA_STRUCT: {
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
+ const PointerRNA &ptr = te_rna_struct->getPointerRNA();
+
+ if (RNA_struct_is_ID(ptr.type)) {
+ data.drag_id = reinterpret_cast<ID *>(ptr.data);
+ data.icon = RNA_struct_ui_icon(ptr.type);
}
else {
- data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ data.icon = RNA_struct_ui_icon(ptr.type);
}
break;
+ }
case TSE_LAYER_COLLECTION:
case TSE_SCENE_COLLECTION_BASE:
case TSE_VIEW_COLLECTION_BASE: {
@@ -2629,8 +2632,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case OB_LIGHTPROBE:
data.icon = ICON_OUTLINER_OB_LIGHTPROBE;
break;
- case OB_HAIR:
- data.icon = ICON_OUTLINER_OB_HAIR;
+ case OB_CURVES:
+ data.icon = ICON_OUTLINER_OB_CURVES;
break;
case OB_POINTCLOUD:
data.icon = ICON_OUTLINER_OB_POINTCLOUD;
@@ -2743,8 +2746,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case ID_GR:
data.icon = ICON_OUTLINER_COLLECTION;
break;
- case ID_HA:
- data.icon = ICON_OUTLINER_DATA_HAIR;
+ case ID_CV:
+ data.icon = ICON_OUTLINER_DATA_CURVES;
break;
case ID_PT:
data.icon = ICON_OUTLINER_DATA_POINTCLOUD;
@@ -3319,8 +3322,9 @@ static void outliner_draw_tree_element(bContext *C,
offsx += 2 * ufac;
}
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) ||
- ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) {
+ (te_rna_struct && RNA_struct_is_ID(te_rna_struct->getPointerRNA().type))) {
const BIFIconID lib_icon = (BIFIconID)UI_icon_from_library(tselem->id);
if (lib_icon != ICON_NONE) {
UI_icon_draw_alpha(
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index a10dbc94b34..b41b260b14a 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -74,6 +74,9 @@
#include "GPU_material.h"
#include "outliner_intern.hh"
+#include "tree/tree_element_rna.hh"
+
+using namespace blender::ed::outliner;
static void outliner_show_active(SpaceOutliner *space_outliner,
ARegion *region,
@@ -1714,11 +1717,6 @@ static void tree_element_to_path(TreeElement *te,
short *UNUSED(groupmode))
{
ListBase hierarchy = {nullptr, nullptr};
- LinkData *ld;
- TreeElement *tem, *temnext;
- TreeStoreElem *tse /* , *tsenext */ /* UNUSED */;
- PointerRNA *ptr, *nextptr;
- PropertyRNA *prop;
char *newpath = nullptr;
/* optimize tricks:
@@ -1738,20 +1736,19 @@ static void tree_element_to_path(TreeElement *te,
*/
/* step 1: flatten out hierarchy of parents into a flat chain */
- for (tem = te->parent; tem; tem = tem->parent) {
- ld = MEM_cnew<LinkData>("LinkData for tree_element_to_path()");
+ for (TreeElement *tem = te->parent; tem; tem = tem->parent) {
+ LinkData *ld = MEM_cnew<LinkData>("LinkData for tree_element_to_path()");
ld->data = tem;
BLI_addhead(&hierarchy, ld);
}
/* step 2: step down hierarchy building the path
* (NOTE: addhead in previous loop was needed so that we can loop like this) */
- for (ld = reinterpret_cast<LinkData *>(hierarchy.first); ld; ld = ld->next) {
+ LISTBASE_FOREACH (LinkData *, ld, &hierarchy) {
/* get data */
- tem = (TreeElement *)ld->data;
- tse = TREESTORE(tem);
- ptr = &tem->rnaptr;
- prop = reinterpret_cast<PropertyRNA *>(tem->directdata);
+ TreeElement *tem = (TreeElement *)ld->data;
+ TreeElementRNACommon *tem_rna = tree_element_cast<TreeElementRNACommon>(tem);
+ PointerRNA ptr = tem_rna->getPointerRNA();
/* check if we're looking for first ID, or appending to path */
if (*id) {
@@ -1759,19 +1756,19 @@ static void tree_element_to_path(TreeElement *te,
* - to prevent memory leaks, we must write to newpath not path,
* then free old path + swap them.
*/
- if (tse->type == TSE_RNA_PROPERTY) {
+ if (TreeElementRNAProperty *tem_rna_prop = tree_element_cast<TreeElementRNAProperty>(tem)) {
+ PropertyRNA *prop = tem_rna_prop->getPropertyRNA();
+
if (RNA_property_type(prop) == PROP_POINTER) {
/* for pointer we just append property name */
- newpath = RNA_path_append(*path, ptr, prop, 0, nullptr);
+ newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr);
}
else if (RNA_property_type(prop) == PROP_COLLECTION) {
char buf[128], *name;
- temnext = (TreeElement *)(ld->next->data);
- // tsenext = TREESTORE(temnext); /* UNUSED */
-
- nextptr = &temnext->rnaptr;
- name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), nullptr);
+ TreeElement *temnext = (TreeElement *)(ld->next->data);
+ PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->getPointerRNA();
+ name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr);
if (name) {
/* if possible, use name as a key in the path */
@@ -1789,6 +1786,7 @@ static void tree_element_to_path(TreeElement *te,
if (temsub == temnext) {
break;
}
+ index++;
}
newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
}
@@ -1808,11 +1806,11 @@ static void tree_element_to_path(TreeElement *te,
else {
/* no ID, so check if entry is RNA-struct,
* and if that RNA-struct is an ID datablock to extract info from. */
- if (tse->type == TSE_RNA_STRUCT) {
+ if (tree_element_cast<TreeElementRNAStruct>(tem)) {
/* ptr->data not ptr->owner_id seems to be the one we want,
* since ptr->data is sometimes the owner of this ID? */
- if (RNA_struct_is_ID(ptr->type)) {
- *id = reinterpret_cast<ID *>(ptr->data);
+ if (RNA_struct_is_ID(ptr.type)) {
+ *id = reinterpret_cast<ID *>(ptr.data);
/* clear path */
if (*path) {
@@ -1827,8 +1825,7 @@ static void tree_element_to_path(TreeElement *te,
/* step 3: if we've got an ID, add the current item to the path */
if (*id) {
/* add the active property to the path */
- ptr = &te->rnaptr;
- prop = reinterpret_cast<PropertyRNA *>(te->directdata);
+ PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->getPropertyRNA();
/* array checks */
if (tselem->type == TSE_RNA_ARRAY_ELEM) {
@@ -1886,9 +1883,12 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
+ TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna ? te_rna->getPointerRNA() : PointerRNA_NULL;
+ PropertyRNA *prop = te_rna ? te_rna->getPropertyRNA() : nullptr;
+
/* check if RNA-property described by this selected element is an animatable prop */
- if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, reinterpret_cast<PropertyRNA *>(te->directdata))) {
+ if (prop && RNA_property_animateable(&ptr, prop)) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -1901,8 +1901,7 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* array checks */
if (flag & KSP_FLAG_WHOLE_ARRAY) {
/* entire array was selected, so add drivers for all */
- arraylen = RNA_property_array_length(&te->rnaptr,
- reinterpret_cast<PropertyRNA *>(te->directdata));
+ arraylen = RNA_property_array_length(&ptr, prop);
}
else {
arraylen = array_index;
@@ -2084,8 +2083,10 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
short groupmode = KSP_GROUP_KSNAME;
/* check if RNA-property described by this selected element is an animatable prop */
- if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, reinterpret_cast<PropertyRNA *>(te->directdata))) {
+ const TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna->getPointerRNA();
+ if (te_rna && te_rna->getPropertyRNA() &&
+ RNA_property_animateable(&ptr, te_rna->getPropertyRNA())) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index 9065f7f9cc1..efbd8a32716 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -27,6 +27,9 @@
#include "RNA_types.h"
+/* Needed for `tree_element_cast()`. */
+#include "tree/tree_element.hh"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -54,10 +57,12 @@ class AbstractTreeDisplay;
class AbstractTreeElement;
} // namespace blender::ed::outliner
+namespace outliner = blender::ed::outliner;
+
struct SpaceOutliner_Runtime {
/** Object to create and manage the tree for a specific display type (View Layers, Scenes,
* Blender File, etc.). */
- std::unique_ptr<blender::ed::outliner::AbstractTreeDisplay> tree_display;
+ std::unique_ptr<outliner::AbstractTreeDisplay> tree_display;
/** Pointers to tree-store elements, grouped by `(id, type, nr)`
* in hash-table for faster searching. */
@@ -90,11 +95,12 @@ typedef struct TreeElement {
struct TreeElement *next, *prev, *parent;
/**
- * Handle to the new C++ object (a derived type of base #AbstractTreeElement) that should replace
- * #TreeElement. Step by step, data should be moved to it and operations based on the type should
- * become virtual methods of the class hierarchy.
+ * The new inheritance based representation of the element (a derived type of base
+ * #AbstractTreeElement) that should eventually replace #TreeElement. Step by step, data should
+ * be moved to it and operations based on the type should become virtual methods of the class
+ * hierarchy.
*/
- std::unique_ptr<blender::ed::outliner::AbstractTreeElement> type;
+ std::unique_ptr<outliner::AbstractTreeElement> abstract_element;
ListBase subtree;
int xs, ys; /* Do selection. */
@@ -104,8 +110,7 @@ typedef struct TreeElement {
short idcode; /* From TreeStore id. */
short xend; /* Width of item display, for select. */
const char *name;
- void *directdata; /* Armature Bones, Base, Sequence, Strip... */
- PointerRNA rnaptr; /* RNA Pointer. */
+ void *directdata; /* Armature Bones, Base, ... */
} TreeElement;
typedef struct TreeElementIcon {
@@ -140,7 +145,7 @@ typedef struct TreeElementIcon {
ID_GD, \
ID_LS, \
ID_LP, \
- ID_HA, \
+ ID_CV, \
ID_PT, \
ID_VO, \
ID_SIM) || /* Only in 'blendfile' mode ... :/ */ \
@@ -225,7 +230,7 @@ typedef enum {
* - not searching into RNA items helps but isn't the complete solution
*/
-#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE)
+#define SEARCHING_OUTLINER(sov) ((sov)->search_flags & SO_SEARCH_RECURSIVE)
/* is the current element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) \
@@ -686,3 +691,19 @@ int outliner_context(const struct bContext *C,
#ifdef __cplusplus
}
#endif
+
+namespace blender::ed::outliner {
+
+/**
+ * Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible.
+ * \return nullptr if the tree-element doesn't match the requested type \a TreeElementT or the
+ * element doesn't hold a C++ #AbstractTreeElement pendant yet.
+ */
+template<typename TreeElementT> TreeElementT *tree_element_cast(const TreeElement *te)
+{
+ static_assert(std::is_base_of_v<AbstractTreeElement, TreeElementT>,
+ "Requested tree-element type must be an AbstractTreeElement");
+ return dynamic_cast<TreeElementT *>(te->abstract_element.get());
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index c2a7bfb9b37..f256475c0da 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -80,6 +80,9 @@
#include "RNA_define.h"
#include "outliner_intern.hh"
+#include "tree/tree_element_seq.hh"
+
+using namespace blender::ed::outliner;
/**
* \note changes to selection are by convention and not essential.
@@ -676,7 +679,8 @@ static void tree_element_sequence_activate(bContext *C,
TreeElement *te,
const eOLSetState set)
{
- Sequence *seq = (Sequence *)te->directdata;
+ const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ Sequence *seq = &te_seq->getSequence();
Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -954,7 +958,8 @@ static eOLDrawState tree_element_posegroup_state_get(const ViewLayer *view_layer
static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const TreeElement *te)
{
- const Sequence *seq = (const Sequence *)te->directdata;
+ const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ const Sequence *seq = &te_seq->getSequence();
const Editing *ed = scene->ed;
if (ed && ed->act_seq == seq && seq->flag & SELECT) {
@@ -965,7 +970,9 @@ static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const Tr
static eOLDrawState tree_element_sequence_dup_state_get(const TreeElement *te)
{
- const Sequence *seq = (const Sequence *)te->directdata;
+ const TreeElementSequenceStripDuplicate *te_dup =
+ tree_element_cast<TreeElementSequenceStripDuplicate>(te);
+ const Sequence *seq = &te_dup->getSequence();
if (seq->flag & SELECT) {
return OL_DRAWSEL_NORMAL;
}
@@ -1191,7 +1198,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
case ID_AR:
case ID_GD:
case ID_LP:
- case ID_HA:
+ case ID_CV:
case ID_PT:
case ID_VO:
context = BCONTEXT_DATA;
@@ -1604,8 +1611,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
if (deselect_all) {
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, false);
- changed = true;
+ changed |= outliner_flag_set(&space_outliner->tree, TSE_SELECTED, false);
}
}
/* Don't allow toggle on scene collection */
@@ -1653,17 +1659,19 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
changed = true;
}
- if (changed) {
- if (rebuild_tree) {
- ED_region_tag_redraw(region);
- }
- else {
- ED_region_tag_redraw_no_rebuild(region);
- }
+ if (!changed) {
+ return OPERATOR_CANCELLED;
+ }
- ED_outliner_select_sync_from_outliner(C, space_outliner);
+ if (rebuild_tree) {
+ ED_region_tag_redraw(region);
+ }
+ else {
+ ED_region_tag_redraw_no_rebuild(region);
}
+ ED_outliner_select_sync_from_outliner(C, space_outliner);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 1c1a4f6f4c2..337649834a4 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -29,8 +29,8 @@
#include "DNA_armature_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_curves_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
@@ -96,9 +96,13 @@
#include "SEQ_sequencer.h"
#include "outliner_intern.hh"
+#include "tree/tree_element_rna.hh"
+#include "tree/tree_element_seq.hh"
static CLG_LogRef LOG = {"ed.outliner.tools"};
+using namespace blender::ed::outliner;
+
/* -------------------------------------------------------------------- */
/** \name ID/Library/Data Set/Un-link Utilities
* \{ */
@@ -160,7 +164,7 @@ static void get_element_operation_type(
case ID_CF:
case ID_WS:
case ID_LP:
- case ID_HA:
+ case ID_CV:
case ID_PT:
case ID_VO:
case ID_SIM:
@@ -258,10 +262,10 @@ static void unlink_material_fn(bContext *UNUSED(C),
totcol = mb->totcol;
matar = mb->mat;
}
- else if (GS(tsep->id->name) == ID_HA) {
- Hair *hair = (Hair *)tsep->id;
- totcol = hair->totcol;
- matar = hair->mat;
+ else if (GS(tsep->id->name) == ID_CV) {
+ Curves *curves = (Curves *)tsep->id;
+ totcol = curves->totcol;
+ matar = curves->mat;
}
else if (GS(tsep->id->name) == ID_PT) {
PointCloud *pointcloud = (PointCloud *)tsep->id;
@@ -760,38 +764,6 @@ static void id_local_fn(bContext *C,
}
}
-static void object_proxy_to_override_convert_fn(bContext *C,
- ReportList *reports,
- Scene *UNUSED(scene),
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
-{
- BLI_assert(TSE_IS_REAL_ID(tselem));
- ID *id_proxy = tselem->id;
- BLI_assert(GS(id_proxy->name) == ID_OB);
- Object *ob_proxy = (Object *)id_proxy;
- Scene *scene = CTX_data_scene(C);
-
- if (ob_proxy->proxy == nullptr) {
- return;
- }
-
- if (!BKE_lib_override_library_proxy_convert(
- CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy)) {
- BKE_reportf(
- reports,
- RPT_ERROR_INVALID_INPUT,
- "Could not create a library override from proxy '%s' (might use already local data?)",
- ob_proxy->id.name + 2);
- return;
- }
-
- DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_WINDOW, nullptr);
-}
-
struct OutlinerLibOverrideData {
bool do_hierarchy;
/**
@@ -855,8 +827,9 @@ static void id_override_library_create_fn(bContext *C,
if (!ID_IS_LINKED(te->store_elem->id)) {
break;
}
- /* If we'd need to override that aren't ID, but it is not overridable, abort. */
- if (!ID_IS_OVERRIDABLE_LIBRARY(te->store_elem->id)) {
+ /* If some element in the tree needs to be overridden, but its ID is not overridable,
+ * abort. */
+ if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(te->store_elem->id)) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
BKE_reportf(reports,
RPT_WARNING,
@@ -869,8 +842,13 @@ static void id_override_library_create_fn(bContext *C,
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
- success = BKE_lib_override_library_create(
- bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr);
+ success = BKE_lib_override_library_create(bmain,
+ CTX_data_scene(C),
+ CTX_data_view_layer(C),
+ nullptr,
+ id_root,
+ id_reference,
+ nullptr);
}
else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr;
@@ -1285,7 +1263,8 @@ static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem),
static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr)
{
- Sequence *seq = (Sequence *)te->directdata;
+ TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ Sequence *seq = &te_seq->getSequence();
Scene *scene = (Scene *)scene_ptr;
Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -1336,10 +1315,16 @@ static void data_select_linked_fn(int event,
TreeStoreElem *UNUSED(tselem),
void *C_v)
{
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
+ if (!te_rna_struct) {
+ return;
+ }
+
if (event == OL_DOP_SELECT_LINKED) {
- if (RNA_struct_is_ID(te->rnaptr.type)) {
+ const PointerRNA &ptr = te_rna_struct->getPointerRNA();
+ if (RNA_struct_is_ID(ptr.type)) {
bContext *C = (bContext *)C_v;
- ID *id = reinterpret_cast<ID *>(te->rnaptr.data);
+ ID *id = reinterpret_cast<ID *>(ptr.data);
ED_object_select_linked_by_id(C, id);
}
@@ -1520,7 +1505,6 @@ enum {
OL_OP_SELECT_HIERARCHY,
OL_OP_REMAP,
OL_OP_RENAME,
- OL_OP_PROXY_TO_OVERRIDE_CONVERT,
};
static const EnumPropertyItem prop_object_op_types[] = {
@@ -1533,11 +1517,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
"Remap Users",
"Make all users of selected data-blocks to use instead a new chosen one"},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
- {OL_OP_PROXY_TO_OVERRIDE_CONVERT,
- "OBJECT_PROXY_TO_OVERRIDE",
- 0,
- "Convert Proxy to Override",
- "Convert a Proxy object to a full library override, including all its dependencies"},
{0, nullptr, 0, nullptr, nullptr},
};
@@ -1602,15 +1581,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
str = "Rename Object";
}
- else if (event == OL_OP_PROXY_TO_OVERRIDE_CONVERT) {
- outliner_do_object_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- object_proxy_to_override_convert_fn);
- str = "Convert Proxy to Override";
- }
else {
BLI_assert(0);
return OPERATOR_CANCELLED;
@@ -1782,7 +1752,6 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
@@ -1824,11 +1793,6 @@ static const EnumPropertyItem prop_id_op_types[] = {
0,
"Make Library Override Hierarchy",
"Make a local override of this linked data-block, and its hierarchy of dependencies"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT,
- "OVERRIDE_LIBRARY_PROXY_CONVERT",
- 0,
- "Convert Proxy to Override",
- "Convert a Proxy object to a full library override, including all its dependencies"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
"OVERRIDE_LIBRARY_RESET",
0,
@@ -1901,16 +1865,6 @@ static bool outliner_id_operation_item_poll(bContext *C,
return true;
}
return false;
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT: {
- if (GS(tselem->id->name) == ID_OB) {
- Object *ob = (Object *)tselem->id;
-
- if ((ob != nullptr) && (ob->proxy != nullptr)) {
- return true;
- }
- }
- return false;
- }
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET:
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY:
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY:
@@ -2087,16 +2041,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Overridden Data Hierarchy");
break;
}
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT: {
- outliner_do_object_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- object_proxy_to_override_convert_fn);
- ED_undo_push(C, "Convert Proxy to Override");
- break;
- }
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index 3454a27ce13..60f5437ad88 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -32,9 +32,9 @@
#include "DNA_camera_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_curves_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
#include "DNA_key_types.h"
#include "DNA_light_types.h"
#include "DNA_lightprobe_types.h"
@@ -217,7 +217,7 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
if (element->flag & TE_FREE_NAME) {
MEM_freeN((void *)element->name);
}
- element->type = nullptr;
+ element->abstract_element = nullptr;
MEM_delete(element);
}
@@ -302,10 +302,6 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
/* FIXME: add a special type for this. */
outliner_add_element(space_outliner, &te->subtree, ob->poselib, te, TSE_SOME_ID, 0);
- if (ob->proxy && !ID_IS_LINKED(ob)) {
- outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
- }
-
outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
@@ -777,10 +773,10 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
break;
}
- case ID_HA: {
- Hair *hair = (Hair *)id;
- if (outliner_animdata_test(hair->adt)) {
- outliner_add_element(space_outliner, &te->subtree, hair, te, TSE_ANIM_DATA, 0);
+ case ID_CV: {
+ Curves *curves = (Curves *)id;
+ if (outliner_animdata_test(curves->adt)) {
+ outliner_add_element(space_outliner, &te->subtree, curves, te, TSE_ANIM_DATA, 0);
}
break;
}
@@ -860,10 +856,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->parent = parent;
te->index = index; /* For data arrays. */
- /* New C++ based type handle. Only some support this, eventually this should replace
- * `TreeElement` entirely. */
- te->type = AbstractTreeElement::createFromType(type, *te, idv);
- if (te->type) {
+ /* New inheritance based element representation. Not all element types support this yet,
+ * eventually it should replace #TreeElement entirely. */
+ te->abstract_element = AbstractTreeElement::createFromType(type, *te, idv);
+ if (te->abstract_element) {
/* Element types ported to the new design are expected to have their name set at this point! */
BLI_assert(te->name != nullptr);
}
@@ -887,12 +883,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
/* pass */
}
else if (type == TSE_SOME_ID) {
- if (!te->type) {
+ if (!te->abstract_element) {
BLI_assert_msg(0, "Expected this ID type to be ported to new Outliner tree-element design");
}
}
else if (ELEM(type, TSE_LIBRARY_OVERRIDE_BASE, TSE_LIBRARY_OVERRIDE)) {
- if (!te->type) {
+ if (!te->abstract_element) {
BLI_assert_msg(0,
"Expected override types to be ported to new Outliner tree-element design");
}
@@ -903,20 +899,20 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
/* The new type design sets the name already, don't override that here. We need to figure out
* how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */
- if (!te->type) {
+ if (!te->abstract_element) {
te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */
}
te->idcode = GS(id->name);
}
- if (te->type && te->type->isExpandValid()) {
- tree_element_expand(*te->type, *space_outliner);
+ if (te->abstract_element && te->abstract_element->isExpandValid()) {
+ tree_element_expand(*te->abstract_element, *space_outliner);
}
else if (type == TSE_SOME_ID) {
/* ID types not (fully) ported to new design yet. */
- if (te->type->expandPoll(*space_outliner)) {
+ if (te->abstract_element->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
- te->type->postExpand(*space_outliner);
+ te->abstract_element->postExpand(*space_outliner);
}
}
else if (ELEM(type,
@@ -925,195 +921,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
TSE_NLA,
TSE_NLA_ACTION,
TSE_NLA_TRACK,
- TSE_GP_LAYER)) {
- /* Should already use new AbstractTreeElement design. */
- BLI_assert(0);
- }
- else if (type == TSE_SEQUENCE) {
- Sequence *seq = (Sequence *)idv;
-
- /*
- * The idcode is a little hack, but the outliner
- * only check te->idcode if te->type is equal to zero,
- * so this is "safe".
- */
- te->idcode = seq->type;
- te->directdata = seq;
- te->name = seq->name + 2;
-
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- /*
- * This work like the sequence.
- * If the sequence have a name (not default name)
- * show it, in other case put the filename.
- */
-
- if (seq->type == SEQ_TYPE_META) {
- LISTBASE_FOREACH (Sequence *, p, &seq->seqbase) {
- outliner_add_element(space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
- }
- }
- else {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
- }
- }
- }
- else if (type == TSE_SEQ_STRIP) {
- Strip *strip = (Strip *)idv;
-
- if (strip->dir[0] != '\0') {
- te->name = strip->dir;
- }
- else {
- te->name = IFACE_("Strip None");
- }
- te->directdata = strip;
- }
- else if (type == TSE_SEQUENCE_DUP) {
- Sequence *seq = (Sequence *)idv;
-
- te->idcode = seq->type;
- te->directdata = seq;
- te->name = seq->strip->stripdata->name;
- }
- else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
- PointerRNA *ptr = (PointerRNA *)idv;
-
- /* Don't display arrays larger, weak but index is stored as a short,
- * also the outliner isn't intended for editing such large data-sets. */
- BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!")
- const int tot_limit = SHRT_MAX;
-
- /* we do lazy build, for speed and to avoid infinite recursion */
-
- if (ptr->data == nullptr) {
- te->name = IFACE_("(empty)");
- }
- else if (type == TSE_RNA_STRUCT) {
- /* struct */
- te->name = RNA_struct_name_get_alloc(ptr, nullptr, 0, nullptr);
-
- if (te->name) {
- te->flag |= TE_FREE_NAME;
- }
- else {
- te->name = RNA_struct_ui_name(ptr->type);
- }
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- int tot = RNA_property_collection_length(ptr, iterprop);
- CLAMP_MAX(tot, tot_limit);
-
- /* auto open these cases */
- if (!parent || (RNA_property_type(reinterpret_cast<PropertyRNA *>(parent->directdata))) ==
- PROP_POINTER) {
- if (!tselem->used) {
- tselem->flag &= ~TSE_CLOSED;
- }
- }
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA propptr;
- RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
- if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
- }
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
-
- te->rnaptr = *ptr;
- }
- else if (type == TSE_RNA_PROPERTY) {
- /* property */
- PointerRNA propptr;
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
-
- PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data);
- PropertyType proptype = RNA_property_type(prop);
-
- te->name = RNA_property_ui_name(prop);
- te->directdata = prop;
- te->rnaptr = *ptr;
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- if (proptype == PROP_POINTER) {
- PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
-
- if (pptr.data) {
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
- }
- else {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (proptype == PROP_COLLECTION) {
- int tot = RNA_property_collection_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA pptr;
- RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- int tot = RNA_property_array_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (type == TSE_RNA_ARRAY_ELEM) {
- PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(parent->directdata);
-
- te->directdata = prop;
- te->rnaptr = *ptr;
- te->index = index;
-
- char c = RNA_property_array_item_char(prop, index);
-
- te->name = reinterpret_cast<char *>(MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
- if (c) {
- sprintf((char *)te->name, " %c", c);
- }
- else {
- sprintf((char *)te->name, " %d", index + 1);
- }
- te->flag |= TE_FREE_NAME;
- }
+ TSE_GP_LAYER,
+ TSE_RNA_STRUCT,
+ TSE_RNA_PROPERTY,
+ TSE_RNA_ARRAY_ELEM,
+ TSE_SEQUENCE,
+ TSE_SEQ_STRIP,
+ TSE_SEQUENCE_DUP)) {
+ BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
}
if (tree_element_warnings_get(te, nullptr, nullptr)) {
diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc
index ea07f1d4611..0fb17fa3f47 100644
--- a/source/blender/editors/space_outliner/space_outliner.cc
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_outliner_treehash.h"
#include "BKE_screen.h"
@@ -405,45 +406,49 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)space_outliner_new;
}
-static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(old_id)) {
- return; /* ID type is not used by outliner. */
- }
+ BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT);
- if (space_outliner->search_tse.id == old_id) {
- space_outliner->search_tse.id = new_id;
+ if (!space_outliner->treestore) {
+ return;
}
- if (space_outliner->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(space_outliner->treestore, &iter);
- while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
- if (tselem->id == old_id) {
- tselem->id = new_id;
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+ bool unassigned = false;
+
+ BLI_mempool_iternew(space_outliner->treestore, &iter);
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_REMAPPED:
changed = true;
- }
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED:
+ changed = true;
+ unassigned = true;
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE:
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ break;
}
+ }
- /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
- * So runtime data might not have been created yet. */
- if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- space_outliner->storeflag |= SO_TREESTORE_REBUILD;
-
- if (new_id == nullptr) {
- /* Redraw is needed when removing data for multiple outlines show the same data.
- * without this, the stale data won't get fully flushed when this outliner
- * is not the active outliner the user is interacting with. See T85976. */
- ED_area_tag_redraw(area);
- }
+ /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
+ * So runtime data might not have been created yet. */
+ if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ space_outliner->storeflag |= SO_TREESTORE_REBUILD;
+
+ if (unassigned) {
+ /* Redraw is needed when removing data for multiple outlines show the same data.
+ * without this, the stale data won't get fully flushed when this outliner
+ * is not the active outliner the user is interacting with. See T85976. */
+ ED_area_tag_redraw(area);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index ea78f70f86d..5685d8964f5 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -33,7 +33,9 @@
#include "tree_element_id.hh"
#include "tree_element_nla.hh"
#include "tree_element_overrides.hh"
+#include "tree_element_rna.hh"
#include "tree_element_scene_objects.hh"
+#include "tree_element_seq.hh"
#include "tree_element_view_layer.hh"
#include "../outliner_intern.hh"
@@ -86,6 +88,23 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i
case TSE_LIBRARY_OVERRIDE:
return std::make_unique<TreeElementOverridesProperty>(
legacy_te, *static_cast<TreeElementOverridesData *>(idv));
+ case TSE_RNA_STRUCT:
+ return std::make_unique<TreeElementRNAStruct>(legacy_te,
+ *reinterpret_cast<PointerRNA *>(idv));
+ case TSE_RNA_PROPERTY:
+ return std::make_unique<TreeElementRNAProperty>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_RNA_ARRAY_ELEM:
+ return std::make_unique<TreeElementRNAArrayElement>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_SEQUENCE:
+ return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv));
+ case TSE_SEQ_STRIP:
+ return std::make_unique<TreeElementSequenceStrip>(legacy_te,
+ *reinterpret_cast<Strip *>(idv));
+ case TSE_SEQUENCE_DUP:
+ return std::make_unique<TreeElementSequenceStripDuplicate>(
+ legacy_te, *reinterpret_cast<Sequence *>(idv));
default:
break;
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
index afbbd171cf4..3289cb8ac76 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -69,7 +69,7 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
case ID_LP:
case ID_GD:
case ID_WS:
- case ID_HA:
+ case ID_CV:
case ID_PT:
case ID_VO:
case ID_SIM:
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
new file mode 100644
index 00000000000..7a9f1b6f0fa
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
@@ -0,0 +1,268 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include <climits>
+#include <iostream>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_outliner_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_element_rna.hh"
+
+namespace blender::ed::outliner {
+
+/* Don't display arrays larger, weak but index is stored as a short,
+ * also the outliner isn't intended for editing such large data-sets. */
+BLI_STATIC_ASSERT(sizeof(TreeElement::index) == 2, "Index is no longer short!")
+
+/* -------------------------------------------------------------------- */
+/* Common functionality (#TreeElementRNACommon Base Class) */
+
+TreeElementRNACommon::TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : AbstractTreeElement(legacy_te), rna_ptr_(rna_ptr)
+{
+ /* Create an empty tree-element. */
+ if (!isRNAValid()) {
+ legacy_te_.name = IFACE_("(empty)");
+ return;
+ }
+}
+
+bool TreeElementRNACommon::isExpandValid() const
+{
+ return true;
+}
+
+bool TreeElementRNACommon::isRNAValid() const
+{
+ return rna_ptr_.data != nullptr;
+}
+
+bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const
+{
+ return isRNAValid();
+}
+
+const PointerRNA &TreeElementRNACommon::getPointerRNA() const
+{
+ return rna_ptr_;
+}
+
+PropertyRNA *TreeElementRNACommon::getPropertyRNA() const
+{
+ return nullptr;
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Struct */
+
+TreeElementRNAStruct::TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_STRUCT);
+
+ if (!isRNAValid()) {
+ return;
+ }
+
+ legacy_te_.name = RNA_struct_name_get_alloc(&rna_ptr, nullptr, 0, nullptr);
+ if (legacy_te_.name) {
+ legacy_te_.flag |= TE_FREE_NAME;
+ }
+ else {
+ legacy_te_.name = RNA_struct_ui_name(rna_ptr.type);
+ }
+}
+
+void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA ptr = rna_ptr_;
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr.type);
+ int tot = RNA_property_collection_length(&ptr, iterprop);
+ CLAMP_MAX(tot, max_index);
+
+ TreeElementRNAProperty *parent_prop_te = legacy_te_.parent ?
+ tree_element_cast<TreeElementRNAProperty>(
+ legacy_te_.parent) :
+ nullptr;
+ /* auto open these cases */
+ if (!parent_prop_te || (RNA_property_type(parent_prop_te->getPropertyRNA()) == PROP_POINTER)) {
+ if (!tselem.used) {
+ tselem.flag &= ~TSE_CLOSED;
+ }
+ }
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA propptr;
+ RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr);
+ if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index);
+ }
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Property */
+
+TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_PROPERTY);
+
+ if (!isRNAValid()) {
+ return;
+ }
+
+ PointerRNA propptr;
+ PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type);
+ RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr);
+
+ PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data);
+
+ legacy_te_.name = RNA_property_ui_name(prop);
+ rna_prop_ = prop;
+}
+
+void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA rna_ptr = rna_ptr_;
+ PropertyType proptype = RNA_property_type(rna_prop_);
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ if (proptype == PROP_POINTER) {
+ PointerRNA pptr = RNA_property_pointer_get(&rna_ptr, rna_prop_);
+
+ if (pptr.data) {
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1);
+ }
+ else {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ }
+ else if (proptype == PROP_COLLECTION) {
+ int tot = RNA_property_collection_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA pptr;
+ RNA_property_collection_lookup_int(&rna_ptr, rna_prop_, index, &pptr);
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ int tot = RNA_property_array_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ outliner_add_element(&space_outliner,
+ &legacy_te_.subtree,
+ &rna_ptr,
+ &legacy_te_,
+ TSE_RNA_ARRAY_ELEM,
+ index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+}
+
+PropertyRNA *TreeElementRNAProperty::getPropertyRNA() const
+{
+ return rna_prop_;
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Array Element */
+
+TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_ARRAY_ELEM);
+
+ BLI_assert(legacy_te.parent && (legacy_te.parent->store_elem->type == TSE_RNA_PROPERTY));
+ legacy_te_.index = index;
+
+ char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index);
+
+ legacy_te_.name = reinterpret_cast<char *>(
+ MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
+ if (c) {
+ sprintf((char *)legacy_te_.name, " %c", c);
+ }
+ else {
+ sprintf((char *)legacy_te_.name, " %d", index + 1);
+ }
+ legacy_te_.flag |= TE_FREE_NAME;
+}
+
+PropertyRNA *TreeElementRNAArrayElement::getPropertyRNA() const
+{
+ /* Forward query to the parent (which is expected to be a #TreeElementRNAProperty). */
+ const TreeElementRNAProperty *parent_prop_te = tree_element_cast<TreeElementRNAProperty>(
+ legacy_te_.parent);
+ return parent_prop_te ? parent_prop_te->getPropertyRNA() : nullptr;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.hh b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
new file mode 100644
index 00000000000..1f107ddbf88
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include <limits>
+
+#include "RNA_types.h"
+
+#include "tree_element.hh"
+
+struct PointerRNA;
+
+namespace blender::ed::outliner {
+
+/**
+ * Base class for common behavior of RNA tree elements.
+ */
+class TreeElementRNACommon : public AbstractTreeElement {
+ protected:
+ constexpr static int max_index = std::numeric_limits<short>::max();
+ PointerRNA rna_ptr_;
+
+ public:
+ TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ bool isExpandValid() const override;
+ bool expandPoll(const SpaceOutliner &) const override;
+
+ const PointerRNA &getPointerRNA() const;
+ /**
+ * If this element represents a property or is part of a property (array element), this returns
+ * the property. Otherwise nullptr.
+ */
+ virtual PropertyRNA *getPropertyRNA() const;
+
+ bool isRNAValid() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAStruct : public TreeElementRNACommon {
+ public:
+ TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ void expand(SpaceOutliner &space_outliner) const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAProperty : public TreeElementRNACommon {
+ private:
+ PropertyRNA *rna_prop_ = nullptr;
+
+ public:
+ TreeElementRNAProperty(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+ void expand(SpaceOutliner &space_outliner) const override;
+
+ PropertyRNA *getPropertyRNA() const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAArrayElement : public TreeElementRNACommon {
+ public:
+ TreeElementRNAArrayElement(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+
+ PropertyRNA *getPropertyRNA() const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.cc b/source/blender/editors/space_outliner/tree/tree_element_seq.cc
new file mode 100644
index 00000000000..8d0b4c140c7
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_seq.cc
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_outliner_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.hh"
+#include "tree_element_seq.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementSequence::TreeElementSequence(TreeElement &legacy_te, Sequence &sequence)
+ : AbstractTreeElement(legacy_te), sequence_(sequence)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE);
+
+ /*
+ * The idcode is a little hack, but the outliner
+ * only check te->idcode if te->type is equal to zero,
+ * so this is "safe".
+ */
+ legacy_te.idcode = sequence_.type;
+ legacy_te.name = sequence_.name + 2;
+}
+
+bool TreeElementSequence::expandPoll(const SpaceOutliner & /*space_outliner*/) const
+{
+ return !(sequence_.type & SEQ_TYPE_EFFECT);
+}
+
+void TreeElementSequence::expand(SpaceOutliner &space_outliner) const
+{
+ /*
+ * This work like the sequence.
+ * If the sequence have a name (not default name)
+ * show it, in other case put the filename.
+ */
+
+ if (sequence_.type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, child, &sequence_.seqbase) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, child, &legacy_te_, TSE_SEQUENCE, 0);
+ }
+ }
+ else {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, sequence_.strip, &legacy_te_, TSE_SEQ_STRIP, 0);
+ }
+}
+
+Sequence &TreeElementSequence::getSequence() const
+{
+ return sequence_;
+}
+
+/* -------------------------------------------------------------------- */
+/* Strip */
+
+TreeElementSequenceStrip::TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip)
+ : AbstractTreeElement(legacy_te)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQ_STRIP);
+
+ if (strip.dir[0] != '\0') {
+ legacy_te_.name = strip.dir;
+ }
+ else {
+ legacy_te_.name = IFACE_("Strip None");
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Strip Duplicate */
+
+TreeElementSequenceStripDuplicate::TreeElementSequenceStripDuplicate(TreeElement &legacy_te,
+ Sequence &sequence)
+ : AbstractTreeElement(legacy_te), sequence_(sequence)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE_DUP);
+
+ legacy_te_.idcode = sequence.type;
+ legacy_te_.name = sequence.strip->stripdata->name;
+}
+
+Sequence &TreeElementSequenceStripDuplicate::getSequence() const
+{
+ return sequence_;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.hh b/source/blender/editors/space_outliner/tree/tree_element_seq.hh
new file mode 100644
index 00000000000..2b334b5b7fa
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_seq.hh
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+struct Sequence;
+struct Strip;
+
+namespace blender::ed::outliner {
+
+class TreeElementSequence : public AbstractTreeElement {
+ Sequence &sequence_;
+
+ public:
+ TreeElementSequence(TreeElement &legacy_te, Sequence &sequence);
+
+ bool expandPoll(const SpaceOutliner &) const override;
+ void expand(SpaceOutliner &) const override;
+
+ Sequence &getSequence() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementSequenceStrip : public AbstractTreeElement {
+ public:
+ TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip);
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementSequenceStripDuplicate : public AbstractTreeElement {
+ Sequence &sequence_;
+
+ public:
+ TreeElementSequenceStripDuplicate(TreeElement &legacy_te, Sequence &sequence);
+
+ Sequence &getSequence() const;
+};
+
+} // namespace blender::ed::outliner