Outliner: Port RNA elements to new tree-element design

Continuation of work started in 2e221de4ce and 249e4df110.

Adds new tree-element classes for RNA structs, properties and array
elements. This isn't exactly a copy and paste, even though logic should
effectively be the same. Further cleanups are included to share code in
a nice way, improve code with simple C++ features, etc.
This commit is contained in:
Julian Eisel 2022-01-26 11:44:58 +01:00
parent 1bf6a880ab
commit 9bce134e56
Notes: blender-bot 2023-02-14 05:12:59 +01:00
Referenced by commit d74c2b5c1f, Outliner: Add missing sanity checks for RNA tree-elements
6 changed files with 337 additions and 139 deletions

View File

@ -65,6 +65,7 @@ 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_view_layer.cc
@ -81,6 +82,7 @@ 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_view_layer.hh
)

View File

@ -225,7 +225,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) \

View File

@ -977,144 +977,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
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;
}
}
if (tree_element_warnings_get(te, nullptr, nullptr)) {
te->flag |= TE_HAS_WARNING;

View File

@ -33,6 +33,7 @@
#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_view_layer.hh"
@ -86,6 +87,15 @@ 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);
default:
break;
}

View File

@ -0,0 +1,249 @@
/*
* 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;
}
legacy_te_.rnaptr = rna_ptr;
}
bool TreeElementRNACommon::isExpandValid() const
{
return true;
}
bool TreeElementRNACommon::isRNAValid() const
{
return rna_ptr_.data != nullptr;
}
bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const
{
return isRNAValid();
}
/* -------------------------------------------------------------------- */
/* RNA Struct */
TreeElementRNAStruct::TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr)
: TreeElementRNACommon(legacy_te, rna_ptr)
{
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 = &legacy_te_.rnaptr;
/* 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);
/* auto open these cases */
if (!legacy_te_.parent ||
(RNA_property_type(reinterpret_cast<PropertyRNA *>(legacy_te_.parent->directdata))) ==
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,
(void *)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)
{
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);
legacy_te_.directdata = 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, (void *)&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,
(void *)&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;
}
}
}
/* -------------------------------------------------------------------- */
/* RNA Array Element */
TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te,
PointerRNA &rna_ptr,
const int index)
: TreeElementRNACommon(legacy_te, rna_ptr)
{
PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(legacy_te_.parent->directdata);
legacy_te_.directdata = prop;
legacy_te_.index = index;
char c = RNA_property_array_item_char(prop, 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;
}
} // namespace blender::ed::outliner

View File

@ -0,0 +1,75 @@
/*
* 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;
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;
};
/* -------------------------------------------------------------------- */
class TreeElementRNAArrayElement : public TreeElementRNACommon {
public:
TreeElementRNAArrayElement(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
};
} // namespace blender::ed::outliner