Outliner: Refactor how lazy-building of children is done
Makes the lazy-building (where children are only built when the parent isn't collapsed) more generic, so more display modes can use it. So far this was hardcoded for the "Data API" display mode. This will be used to work around a big performance issue with the Library Overrides Hierachies view in a complex production file, see following commit.
This commit is contained in:
parent
8115d31248
commit
231078441f
|
@ -3336,7 +3336,7 @@ static void outliner_draw_tree_element(bContext *C,
|
|||
/* Scene collection in view layer can't expand/collapse. */
|
||||
}
|
||||
else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) ||
|
||||
(te->flag & TE_LAZY_CLOSED)) {
|
||||
(te->flag & TE_PRETEND_HAS_CHILDREN)) {
|
||||
/* Open/close icon, only when sub-levels, except for scene. */
|
||||
int icon_x = startx;
|
||||
|
||||
|
|
|
@ -144,14 +144,10 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
|
|||
/** \name Toggle Open/Closed Operator
|
||||
* \{ */
|
||||
|
||||
void outliner_item_openclose(SpaceOutliner *space_outliner,
|
||||
TreeElement *te,
|
||||
bool open,
|
||||
bool toggle_all)
|
||||
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
|
||||
{
|
||||
/* Prevent opening leaf elements in the tree unless in the Data API display mode because in that
|
||||
* mode subtrees are empty unless expanded. */
|
||||
if (space_outliner->outlinevis != SO_DATA_API && BLI_listbase_is_empty(&te->subtree)) {
|
||||
/* Only allow opening elements with children. */
|
||||
if (!(te->flag & TE_PRETEND_HAS_CHILDREN) && BLI_listbase_is_empty(&te->subtree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -198,7 +194,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv
|
|||
|
||||
/* Only toggle openclose on the same level as the first clicked element */
|
||||
if (te->xs == data->x_location) {
|
||||
outliner_item_openclose(space_outliner, te, data->open, false);
|
||||
outliner_item_openclose(te, data->open, false);
|
||||
|
||||
outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region);
|
||||
}
|
||||
|
@ -242,7 +238,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE
|
|||
const bool open = (tselem->flag & TSE_CLOSED) ||
|
||||
(toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)));
|
||||
|
||||
outliner_item_openclose(space_outliner, te, open, toggle_all);
|
||||
outliner_item_openclose(te, open, toggle_all);
|
||||
outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region);
|
||||
|
||||
/* Only toggle once for single click toggling */
|
||||
|
|
|
@ -157,7 +157,10 @@ enum {
|
|||
/* Closed items display their children as icon within the row. TE_ICONROW is for
|
||||
* these child-items that are visible but only within the row of the closed parent. */
|
||||
TE_ICONROW = (1 << 1),
|
||||
TE_LAZY_CLOSED = (1 << 2),
|
||||
/** Treat the element as if it had children, e.g. draw an icon to un-collapse it, even if it
|
||||
* doesn't. Used where children are lazy-built only if the parent isn't collapsed (see
|
||||
* #AbstractTreeDisplay::is_lazy_built()). */
|
||||
TE_PRETEND_HAS_CHILDREN = (1 << 2),
|
||||
TE_FREE_NAME = (1 << 3),
|
||||
TE_DRAGGING = (1 << 4),
|
||||
TE_CHILD_NOT_IN_COLLECTION = (1 << 6),
|
||||
|
@ -280,11 +283,6 @@ struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outli
|
|||
|
||||
bool outliner_requires_rebuild_on_select_or_active_change(
|
||||
const struct SpaceOutliner *space_outliner);
|
||||
/**
|
||||
* Check if a display mode needs a full rebuild if the open/collapsed state changes.
|
||||
* Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
|
||||
*/
|
||||
bool outliner_requires_rebuild_on_open_change(const struct SpaceOutliner *space_outliner);
|
||||
|
||||
typedef struct IDsSelectedData {
|
||||
struct ListBase selected_array;
|
||||
|
@ -465,10 +463,7 @@ void outliner_set_coordinates(const struct ARegion *region,
|
|||
/**
|
||||
* Open or close a tree element, optionally toggling all children recursively.
|
||||
*/
|
||||
void outliner_item_openclose(struct SpaceOutliner *space_outliner,
|
||||
TreeElement *te,
|
||||
bool open,
|
||||
bool toggle_all);
|
||||
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all);
|
||||
|
||||
/* outliner_dragdrop.c */
|
||||
|
||||
|
|
|
@ -1885,7 +1885,7 @@ static TreeElement *outliner_walk_left(SpaceOutliner *space_outliner,
|
|||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (TSELEM_OPEN(tselem, space_outliner)) {
|
||||
outliner_item_openclose(space_outliner, te, false, toggle_all);
|
||||
outliner_item_openclose(te, false, toggle_all);
|
||||
}
|
||||
/* Only walk up a level if the element is closed and not toggling expand */
|
||||
else if (!toggle_all && te->parent) {
|
||||
|
@ -1906,7 +1906,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
|
|||
te = static_cast<TreeElement *>(te->subtree.first);
|
||||
}
|
||||
else {
|
||||
outliner_item_openclose(space_outliner, te, true, toggle_all);
|
||||
outliner_item_openclose(te, true, toggle_all);
|
||||
}
|
||||
|
||||
return te;
|
||||
|
|
|
@ -217,11 +217,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s
|
|||
return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner)
|
||||
{
|
||||
return ELEM(space_outliner->outlinevis, SO_DATA_API);
|
||||
}
|
||||
|
||||
/* special handling of hierarchical non-lib data */
|
||||
static void outliner_add_bone(SpaceOutliner *space_outliner,
|
||||
ListBase *lb,
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "UI_view2d.h"
|
||||
|
||||
#include "outliner_intern.hh"
|
||||
#include "tree/tree_display.hh"
|
||||
#include "tree/tree_iterator.hh"
|
||||
|
||||
using namespace blender::ed::outliner;
|
||||
|
@ -436,7 +437,7 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space
|
|||
ARegion *region)
|
||||
{
|
||||
/* Avoid rebuild if possible. */
|
||||
if (outliner_requires_rebuild_on_open_change(space_outliner)) {
|
||||
if (space_outliner->runtime->tree_display->is_lazy_built()) {
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -50,4 +50,9 @@ bool AbstractTreeDisplay::supportsModeColumn() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AbstractTreeDisplay::is_lazy_built() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::outliner
|
||||
|
|
|
@ -84,6 +84,15 @@ class AbstractTreeDisplay {
|
|||
*/
|
||||
virtual bool supportsModeColumn() const;
|
||||
|
||||
/**
|
||||
* Some trees may want to skip building children of collapsed parents. This should be done if the
|
||||
* tree type may become very complex, which could cause noticeable slowdowns.
|
||||
* Problem: This doesn't address performance issues while searching, since all elements are
|
||||
* constructed for that. Trees of this type have to be rebuilt for any change to the collapsed
|
||||
* state of any element.
|
||||
*/
|
||||
virtual bool is_lazy_built() const;
|
||||
|
||||
protected:
|
||||
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
|
||||
SpaceOutliner &space_outliner_;
|
||||
|
@ -232,6 +241,8 @@ class TreeDisplayDataAPI final : public AbstractTreeDisplay {
|
|||
TreeDisplayDataAPI(SpaceOutliner &space_outliner);
|
||||
|
||||
ListBase buildTree(const TreeSourceData &source_data) override;
|
||||
|
||||
bool is_lazy_built() const override;
|
||||
};
|
||||
|
||||
} // namespace blender::ed::outliner
|
||||
|
|
|
@ -42,4 +42,9 @@ ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data)
|
|||
return tree;
|
||||
}
|
||||
|
||||
bool TreeDisplayDataAPI::is_lazy_built() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::outliner
|
||||
|
|
|
@ -124,7 +124,7 @@ void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const
|
|||
}
|
||||
}
|
||||
else if (tot) {
|
||||
legacy_te_.flag |= TE_LAZY_CLOSED;
|
||||
legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
|
|||
&space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1);
|
||||
}
|
||||
else {
|
||||
legacy_te_.flag |= TE_LAZY_CLOSED;
|
||||
legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
|
|||
}
|
||||
}
|
||||
else if (tot) {
|
||||
legacy_te_.flag |= TE_LAZY_CLOSED;
|
||||
legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
|
||||
}
|
||||
}
|
||||
else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
|
||||
|
@ -207,7 +207,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
|
|||
}
|
||||
}
|
||||
else if (tot) {
|
||||
legacy_te_.flag |= TE_LAZY_CLOSED;
|
||||
legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue