Outliner Filtering System + Cleanup
User notes: The outliner so far was a great system to handle the object oriented workflow we had in Blender prior to 2.8. However with the introduction of collections the bloated ammount of data we were exposed at a given time was eventually getting on the way of fully utilizing the outliner to manage collections and their objects. We hope that with this filtering system the user can put together the outliner with whichever options he or she seem fit for a given task. Features: * Collection filter: In case users are only focused on objects. * Object filter: Allow users to focus on collections only. * (Object) content filter: Modifiers, mesh, contrainst, materials, ... * (Object) children filter: Hide object children [1]. * Object State (visible, active, selected). * Compact header: hide search options under a search toggle. * Preserve scrolling position before/after filtering [2]. [1] - Note we still need to be able to tell if a children of an object is in a collection, or if the parent object is the only one in the collection. This in fact was one of the first motivations for this patch. But it is to be addressed separately now that we can at least hide children away. [2] - We look at the top-most collection in the outliner, and try to find it again after the filtering and make sure it is in the same position as before. This works nice now. But to work REALLY, REALLY nice we need to also store the previous filter options to be sure the element we try to keep on top was valid for both old and new filters. I would rather do this later though since this smell a lot like feature creeping ;) Remove no longer needed display options: * Current Scene (replaced by View Layer/Collections) * Visible (replaced by filter) * Selected (same) * Active (same) * Same Type (same-ish) How about All Scenes? I have a patch that will come next to replace the current behaviour and focus only on compositing. So basically stop showing the objects and show only view layers, their passes and collections, besides freestyle. Also, while at this I'm also reorganizing the menu to keep View Layer and Collections on top. Developer notes: * Unlike the per-object filtering, for collections we need to filter at tree creation time, to prevent duplication of objects in the outliner. Acknowledgements: Thanks Pablo Vazquez for helping testing, thinking some design questions together and pushing this to its final polished state as you see here. Thanks Sergey Sharybin and Julian Eisel for code review. Julian couldn't do a final review pass after I addressed his concerns. So blame is on me for any issue I may be introducing here. Sergey was the author of the "preserve scrolling position" idea. I'm happy with how it is working, thank you. Reviewers: sergey, Severin, venomgfx Subscribers: lichtwerk, duarteframos Differential Revision: https://developer.blender.org/D2992
This commit is contained in:
parent
76f374052c
commit
37913cf532
|
@ -28,8 +28,10 @@ class OUTLINER_HT_header(Header):
|
|||
layout = self.layout
|
||||
|
||||
space = context.space_data
|
||||
display_mode = space.display_mode
|
||||
scene = context.scene
|
||||
ks = context.scene.keying_sets.active
|
||||
support_filters = display_mode in {'COLLECTIONS', 'VIEW_LAYER'}
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.template_header()
|
||||
|
@ -38,13 +40,9 @@ class OUTLINER_HT_header(Header):
|
|||
|
||||
layout.prop(space, "display_mode", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "filter_text", icon='VIEWZOOM', text="")
|
||||
row.prop(space, "use_filter_complete", text="")
|
||||
row.prop(space, "use_filter_case_sensitive", text="")
|
||||
|
||||
if space.display_mode == 'DATABLOCKS':
|
||||
layout.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("outliner.keyingset_add_selected", icon='ZOOMIN', text="")
|
||||
row.operator("outliner.keyingset_remove_selected", icon='ZOOMOUT', text="")
|
||||
|
@ -60,6 +58,54 @@ class OUTLINER_HT_header(Header):
|
|||
row = layout.row()
|
||||
row.label(text="No Keying Set Active")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "use_filter_search", text="")
|
||||
if space.use_filter_search:
|
||||
row.prop(space, "filter_text", text="")
|
||||
row.prop(space, "use_filter_complete", text="")
|
||||
row.prop(space, "use_filter_case_sensitive", text="")
|
||||
|
||||
if support_filters:
|
||||
row.separator()
|
||||
|
||||
row.prop(space, "use_filters", text="")
|
||||
if space.use_filters:
|
||||
row.separator()
|
||||
row.prop(space, "use_filter_collection", text="")
|
||||
row.prop(space, "use_filter_object", text="")
|
||||
sub = row.row(align=True)
|
||||
sub.active = space.use_filter_object
|
||||
sub.prop(space, "use_filter_object_content", text="")
|
||||
sub.prop(space, "use_filter_children", text="")
|
||||
|
||||
sub.separator()
|
||||
sub.prop(space, "use_filter_object_type", text="")
|
||||
|
||||
if space.use_filter_object_type:
|
||||
if bpy.data.meshes:
|
||||
sub.prop(space, "use_filter_object_mesh", text="")
|
||||
if bpy.data.armatures:
|
||||
sub.prop(space, "use_filter_object_armature", text="")
|
||||
if bpy.data.lamps:
|
||||
sub.prop(space, "use_filter_object_lamp", text="")
|
||||
if bpy.data.cameras:
|
||||
sub.prop(space, "use_filter_object_camera", text="")
|
||||
|
||||
sub.prop(space, "use_filter_object_empty", text="")
|
||||
|
||||
if bpy.data.curves or \
|
||||
bpy.data.metaballs or \
|
||||
bpy.data.lightprobes or \
|
||||
bpy.data.lattices or \
|
||||
bpy.data.fonts or bpy.data.speakers:
|
||||
sub.prop(space, "use_filter_object_others", text="")
|
||||
|
||||
sub.separator()
|
||||
sub.prop(space, "use_filter_object_state", text="")
|
||||
|
||||
if space.use_filter_object_state:
|
||||
sub.prop(space, "filter_state", text="", expand=True)
|
||||
|
||||
|
||||
class OUTLINER_MT_editor_menus(Menu):
|
||||
bl_idname = "OUTLINER_MT_editor_menus"
|
||||
|
|
|
@ -2453,9 +2453,13 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
|
|||
if (sl->spacetype == SPACE_OUTLINER) {
|
||||
SpaceOops *so = (SpaceOops *)sl;
|
||||
|
||||
if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE,
|
||||
SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS,
|
||||
SO_USERDEF))
|
||||
if (!ELEM(so->outlinevis,
|
||||
SO_ALL_SCENES,
|
||||
SO_GROUPS,
|
||||
SO_LIBRARIES,
|
||||
SO_SEQUENCE,
|
||||
SO_DATABLOCKS,
|
||||
SO_USERDEF))
|
||||
{
|
||||
so->outlinevis = SO_ALL_SCENES;
|
||||
}
|
||||
|
|
|
@ -883,4 +883,37 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) {
|
||||
bScreen *sc;
|
||||
ScrArea *sa;
|
||||
SpaceLink *sl;
|
||||
|
||||
/* Update files using invalid (outdated) outlinevis Outliner values. */
|
||||
for (sc = main->screen.first; sc; sc = sc->id.next) {
|
||||
for (sa = sc->areabase.first; sa; sa = sa->next) {
|
||||
for (sl = sa->spacedata.first; sl; sl = sl->next) {
|
||||
if (sl->spacetype == SPACE_OUTLINER) {
|
||||
SpaceOops *so = (SpaceOops *)sl;
|
||||
|
||||
if (!ELEM(so->outlinevis,
|
||||
SO_ALL_SCENES,
|
||||
SO_GROUPS,
|
||||
SO_LIBRARIES,
|
||||
SO_SEQUENCE,
|
||||
SO_DATABLOCKS,
|
||||
SO_USERDEF,
|
||||
SO_ID_ORPHANS,
|
||||
SO_VIEW_LAYER,
|
||||
SO_COLLECTIONS))
|
||||
{
|
||||
so->outlinevis = SO_VIEW_LAYER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1415,7 +1415,7 @@ static void outliner_draw_tree_element(
|
|||
te->flag |= TE_ACTIVE; // for lookup in display hierarchies
|
||||
}
|
||||
|
||||
if ((soops->outlinevis == SO_COLLECTIONS) && te->parent == NULL) {
|
||||
if ((soops->outlinevis == SO_COLLECTIONS) && (tselem->type == TSE_SCENE_COLLECTION) && (te->parent == NULL)) {
|
||||
/* Master collection can't expand/collapse. */
|
||||
}
|
||||
else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
|
||||
|
@ -1720,7 +1720,9 @@ static void outliner_draw_highlights_recursive(
|
|||
int start_x, int *io_start_y)
|
||||
{
|
||||
const bool is_searching = SEARCHING_OUTLINER(soops) ||
|
||||
(soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0);
|
||||
(soops->outlinevis == SO_DATABLOCKS &&
|
||||
(soops->filter & SO_FILTER_SEARCH) &&
|
||||
soops->search_string[0] != 0);
|
||||
|
||||
for (TreeElement *te = lb->first; te; te = te->next) {
|
||||
const TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
@ -1904,7 +1906,7 @@ void draw_outliner(const bContext *C)
|
|||
TreeElement *te_edit = NULL;
|
||||
bool has_restrict_icons;
|
||||
|
||||
outliner_build_tree(mainvar, scene, view_layer, soops); // always
|
||||
outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
|
||||
|
||||
/* get extents of data */
|
||||
outliner_height(soops, &soops->tree, &sizey);
|
||||
|
|
|
@ -949,7 +949,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeEle
|
|||
}
|
||||
|
||||
/* to retrieve coordinates with redrawing the entire tree */
|
||||
static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
|
||||
void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
|
||||
{
|
||||
TreeElement *te;
|
||||
int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
|
||||
|
@ -2085,7 +2085,7 @@ static int outliner_parenting_poll(bContext *C)
|
|||
SpaceOops *soops = CTX_wm_space_outliner(C);
|
||||
|
||||
if (soops) {
|
||||
return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
|
||||
return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_GROUPS);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
/* internal exports only */
|
||||
|
||||
struct ARegion;
|
||||
struct wmOperatorType;
|
||||
struct TreeElement;
|
||||
struct TreeStoreElem;
|
||||
|
@ -154,6 +155,9 @@ typedef enum {
|
|||
#define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f)
|
||||
#define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f)
|
||||
|
||||
/* The outliner display modes that support the filter system.
|
||||
* Note: keep it synced with space_outliner.py */
|
||||
#define SUPPORT_FILTER_OUTLINER(soops_) ELEM((soops_)->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)
|
||||
|
||||
/* Outliner Searching --
|
||||
*
|
||||
|
@ -171,7 +175,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) && (sov->filter & SO_FILTER_SEARCH))
|
||||
|
||||
/* is the currrent element open? if so we also show children */
|
||||
#define TSELEM_OPEN(telm, sv) ( (telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)) )
|
||||
|
@ -183,7 +187,8 @@ void outliner_cleanup_tree(struct SpaceOops *soops);
|
|||
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree);
|
||||
void outliner_remove_treestore_element(struct SpaceOops *soops, TreeStoreElem *tselem);
|
||||
|
||||
void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOops *soops);
|
||||
void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer,
|
||||
struct SpaceOops *soops, struct ARegion *ar);
|
||||
|
||||
/* outliner_draw.c ---------------------------------------------- */
|
||||
|
||||
|
@ -265,6 +270,8 @@ void id_remap_cb(
|
|||
|
||||
TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
|
||||
|
||||
void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops);
|
||||
|
||||
/* ...................................................... */
|
||||
|
||||
void OUTLINER_OT_highlight_update(struct wmOperatorType *ot);
|
||||
|
|
|
@ -82,6 +82,8 @@
|
|||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "outliner_intern.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -1751,6 +1753,305 @@ static void outliner_sort(ListBase *lb)
|
|||
|
||||
/* Filtering ----------------------------------------------- */
|
||||
|
||||
typedef struct OutlinerTreeElementFocus {
|
||||
TreeStoreElem *tselem;
|
||||
int ys;
|
||||
} OutlinerTreeElementFocus;
|
||||
|
||||
/**
|
||||
* Bring the outliner scrolling back to where it was in relation to the original focus element
|
||||
* Caller is expected to handle redrawing of ARegion.
|
||||
*/
|
||||
static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
|
||||
{
|
||||
View2D *v2d = &ar->v2d;
|
||||
int ytop;
|
||||
|
||||
if (focus->tselem != NULL) {
|
||||
outliner_set_coordinates(ar, soops);
|
||||
|
||||
TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem);
|
||||
|
||||
if (te_new != NULL) {
|
||||
int ys_new, ys_old;
|
||||
|
||||
ys_new = te_new->ys;
|
||||
ys_old = focus->ys;
|
||||
|
||||
ytop = v2d->cur.ymax + (ys_new - ys_old) -1;
|
||||
if (ytop > 0) ytop = 0;
|
||||
|
||||
v2d->cur.ymax = (float)ytop;
|
||||
v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
soops->storeflag |= SO_TREESTORE_REDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
static bool test_collection_callback(TreeElement *te)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION);
|
||||
}
|
||||
|
||||
static bool test_object_callback(TreeElement *te)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
return ((tselem->type == 0) && (te->idcode == ID_OB));
|
||||
}
|
||||
|
||||
/**
|
||||
* See if TreeElement or any of its children pass the callback_test.
|
||||
*/
|
||||
static TreeElement *outliner_find_first_desired_element_at_y_recursive(
|
||||
const SpaceOops *soops,
|
||||
TreeElement *te,
|
||||
const float limit,
|
||||
bool (*callback_test)(TreeElement *))
|
||||
{
|
||||
if (callback_test(te)) {
|
||||
return te;
|
||||
}
|
||||
|
||||
if (TSELEM_OPEN(te->store_elem, soops)) {
|
||||
TreeElement *te_iter, *te_sub;
|
||||
for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
|
||||
te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test);
|
||||
if (te_sub != NULL) {
|
||||
return te_sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first element that passes a test starting from a reference vertical coordinate
|
||||
*
|
||||
* If the element that is in the position is not what we are looking for, keep looking for its
|
||||
* children, siblings, and eventually, aunts, cousins, disntant families, ...
|
||||
*
|
||||
* Basically we keep going up and down the outliner tree from that point forward, until we find
|
||||
* what we are looking for. If we are past the visible range and we can't find a valid element
|
||||
* we return NULL.
|
||||
*/
|
||||
static TreeElement *outliner_find_first_desired_element_at_y(
|
||||
const SpaceOops *soops,
|
||||
const float view_co,
|
||||
const float view_co_limit)
|
||||
{
|
||||
TreeElement *te, *te_sub;
|
||||
te = outliner_find_item_at_y(soops, &soops->tree, view_co);
|
||||
|
||||
bool (*callback_test)(TreeElement *);
|
||||
if (soops->filter & SO_FILTER_NO_COLLECTION) {
|
||||
callback_test = test_object_callback;
|
||||
}
|
||||
else {
|
||||
callback_test = test_collection_callback;
|
||||
}
|
||||
|
||||
while (te != NULL) {
|
||||
te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test);
|
||||
if (te_sub != NULL) {
|
||||
/* Skip the element if it was not visible to start with. */
|
||||
if (te->ys + UI_UNIT_Y > view_co_limit) {
|
||||
return te_sub;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (te->next) {
|
||||
te = te->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (te->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (te->parent) {
|
||||
if (te->parent->next) {
|
||||
te = te->parent->next;
|
||||
break;
|
||||
}
|
||||
te = te->parent;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store information of current outliner scrolling status to be restored later
|
||||
*
|
||||
* Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus
|
||||
* struct to retrieve this element later to make sure it is in the same original position as before filtering
|
||||
*/
|
||||
static void outliner_store_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
|
||||
{
|
||||
TreeElement *te;
|
||||
float limit = ar->v2d.cur.ymin;
|
||||
|
||||
outliner_set_coordinates(ar, soops);
|
||||
|
||||
te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit);
|
||||
|
||||
if (te != NULL) {
|
||||
focus->tselem = TREESTORE(te);
|
||||
focus->ys = te->ys;
|
||||
}
|
||||
else {
|
||||
focus->tselem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int outliner_exclude_filter_get(SpaceOops *soops)
|
||||
{
|
||||
int exclude_filter = soops->filter & ~(SO_FILTER_OB_STATE_VISIBLE |
|
||||
SO_FILTER_OB_STATE_SELECTED |
|
||||
SO_FILTER_OB_STATE_ACTIVE);
|
||||
|
||||
if (soops->filter & SO_FILTER_SEARCH) {
|
||||
if (soops->search_string[0] == 0) {
|
||||
exclude_filter &= ~SO_FILTER_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
/* Let's have this for the collection options at first. */
|
||||
if (!SUPPORT_FILTER_OUTLINER(soops)) {
|
||||
return (exclude_filter & SO_FILTER_SEARCH);
|
||||
}
|
||||
|
||||
if ((exclude_filter & SO_FILTER_NO_OB_ALL) == 0) {
|
||||
exclude_filter &= ~SO_FILTER_OB_TYPE;
|
||||
}
|
||||
|
||||
if (exclude_filter & SO_FILTER_OB_STATE) {
|
||||
switch (soops->filter_state) {
|
||||
case SO_FILTER_OB_VISIBLE:
|
||||
exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
|
||||
break;
|
||||
case SO_FILTER_OB_SELECTED:
|
||||
exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
|
||||
break;
|
||||
case SO_FILTER_OB_ACTIVE:
|
||||
exclude_filter |= SO_FILTER_OB_STATE_ACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((exclude_filter & SO_FILTER_ANY) == 0) {
|
||||
exclude_filter &= ~(SO_FILTER_OB_STATE);
|
||||
}
|
||||
|
||||
return exclude_filter;
|
||||
}
|
||||
|
||||
static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter)
|
||||
{
|
||||
if ((exclude_filter & SO_FILTER_ENABLE) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if ((tselem->type == 0) && (te->idcode == ID_OB)) {
|
||||
if ((exclude_filter & SO_FILTER_NO_OBJECT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *ob = (Object *)tselem->id;
|
||||
Base *base = (Base *)te->directdata;
|
||||
BLI_assert((base == NULL) || (base->object == ob));
|
||||
|
||||
if (exclude_filter & SO_FILTER_OB_TYPE) {
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
if (exclude_filter & SO_FILTER_NO_OB_MESH) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OB_ARMATURE:
|
||||
if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OB_EMPTY:
|
||||
if (exclude_filter & SO_FILTER_NO_OB_EMPTY) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OB_LAMP:
|
||||
if (exclude_filter & SO_FILTER_NO_OB_LAMP) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OB_CAMERA:
|
||||
if (exclude_filter & SO_FILTER_NO_OB_CAMERA) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (exclude_filter & SO_FILTER_NO_OB_OTHERS) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exclude_filter & SO_FILTER_OB_STATE) {
|
||||
if (base == NULL) {
|
||||
base = BKE_view_layer_base_find(view_layer, ob);
|
||||
|
||||
if (base == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
|
||||
if ((base->flag & BASE_VISIBLED) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
|
||||
if ((base->flag & BASE_SELECTED) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
|
||||
if (base != BASACT(view_layer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((te->parent != NULL) &&
|
||||
(TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB))
|
||||
{
|
||||
if (exclude_filter & SO_FILTER_NO_CHILDREN) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (te->parent != NULL &&
|
||||
TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB)
|
||||
{
|
||||
if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
|
||||
{
|
||||
int fn_flag = 0;
|
||||
|
@ -1761,18 +2062,68 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag
|
|||
return fnmatch(name, te->name, fn_flag) == 0;
|
||||
}
|
||||
|
||||
static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
|
||||
static int outliner_filter_subtree(
|
||||
SpaceOops *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter)
|
||||
{
|
||||
TreeElement *te, *ten;
|
||||
TreeElement *te, *te_next;
|
||||
TreeStoreElem *tselem;
|
||||
|
||||
for (te = lb->first; te; te = te_next) {
|
||||
te_next = te->next;
|
||||
|
||||
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
|
||||
outliner_free_tree_element(te, lb);
|
||||
continue;
|
||||
}
|
||||
else if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
|
||||
/* Filter subtree too. */
|
||||
outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
|
||||
/* item isn't something we're looking for, but...
|
||||
* - if the subtree is expanded, check if there are any matches that can be easily found
|
||||
* so that searching for "cu" in the default scene will still match the Cube
|
||||
* - otherwise, we can't see within the subtree and the item doesn't match,
|
||||
* so these can be safely ignored (i.e. the subtree can get freed)
|
||||
*/
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
/* flag as not a found item */
|
||||
tselem->flag &= ~TSE_SEARCHMATCH;
|
||||
|
||||
if ((!TSELEM_OPEN(tselem, soops)) ||
|
||||
outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0)
|
||||
{
|
||||
outliner_free_tree_element(te, lb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
/* flag as a found item - we can then highlight it */
|
||||
tselem->flag |= TSE_SEARCHMATCH;
|
||||
|
||||
/* filter subtree too */
|
||||
outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
|
||||
}
|
||||
}
|
||||
|
||||
/* if there are still items in the list, that means that there were still some matches */
|
||||
return (BLI_listbase_is_empty(lb) == false);
|
||||
}
|
||||
|
||||
static void outliner_filter_tree(SpaceOops *soops, ViewLayer *view_layer)
|
||||
{
|
||||
char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
|
||||
char *search_string;
|
||||
|
||||
/* although we don't have any search string, we return true
|
||||
* since the entire tree is ok then...
|
||||
*/
|
||||
if (soops->search_string[0] == 0)
|
||||
return 1;
|
||||
const int exclude_filter = outliner_exclude_filter_get(soops);
|
||||
|
||||
if (exclude_filter == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (soops->search_flags & SO_FIND_COMPLETE) {
|
||||
search_string = soops->search_string;
|
||||
|
@ -1783,38 +2134,7 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
|
|||
search_string = search_buff;
|
||||
}
|
||||
|
||||
for (te = lb->first; te; te = ten) {
|
||||
ten = te->next;
|
||||
|
||||
if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
|
||||
/* item isn't something we're looking for, but...
|
||||
* - if the subtree is expanded, check if there are any matches that can be easily found
|
||||
* so that searching for "cu" in the default scene will still match the Cube
|
||||
* - otherwise, we can't see within the subtree and the item doesn't match,
|
||||
* so these can be safely ignored (i.e. the subtree can get freed)
|
||||
*/
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
/* flag as not a found item */
|
||||
tselem->flag &= ~TSE_SEARCHMATCH;
|
||||
|
||||
if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) {
|
||||
outliner_free_tree_element(te, lb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
/* flag as a found item - we can then highlight it */
|
||||
tselem->flag |= TSE_SEARCHMATCH;
|
||||
|
||||
/* filter subtree too */
|
||||
outliner_filter_tree(soops, &te->subtree);
|
||||
}
|
||||
}
|
||||
|
||||
/* if there are still items in the list, that means that there were still some matches */
|
||||
return (BLI_listbase_is_empty(lb) == false);
|
||||
outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter);
|
||||
}
|
||||
|
||||
/* ======================================================= */
|
||||
|
@ -1822,7 +2142,7 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
|
|||
|
||||
/* Main entry point for building the tree data-structure that the outliner represents */
|
||||
// TODO: split each mode into its own function?
|
||||
void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops)
|
||||
void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, ARegion *ar)
|
||||
{
|
||||
TreeElement *te = NULL, *ten;
|
||||
TreeStoreElem *tselem;
|
||||
|
@ -1844,6 +2164,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
|
|||
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
|
||||
return;
|
||||
|
||||
OutlinerTreeElementFocus focus;
|
||||
outliner_store_scrolling_position(soops, ar, &focus);
|
||||
|
||||
outliner_free_tree(&soops->tree);
|
||||
outliner_storage_cleanup(soops);
|
||||
|
||||
|
@ -1921,27 +2244,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
|
|||
FOREACH_SCENE_OBJECT_END
|
||||
}
|
||||
}
|
||||
else if (soops->outlinevis == SO_CUR_SCENE) {
|
||||
|
||||
outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
|
||||
|
||||
FOREACH_SCENE_OBJECT(scene, ob)
|
||||
{
|
||||
outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END
|
||||
outliner_make_hierarchy(&soops->tree);
|
||||
}
|
||||
else if (soops->outlinevis == SO_VISIBLE) {
|
||||
FOREACH_VISIBLE_BASE(view_layer, base)
|
||||
{
|
||||
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
||||
ten->directdata = base;
|
||||
|
||||
}
|
||||
FOREACH_VISIBLE_BASE_END
|
||||
outliner_make_hierarchy(&soops->tree);
|
||||
}
|
||||
else if (soops->outlinevis == SO_GROUPS) {
|
||||
Group *group;
|
||||
for (group = mainvar->group.first; group; group = group->id.next) {
|
||||
|
@ -1949,28 +2251,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
|
|||
outliner_make_hierarchy(&te->subtree);
|
||||
}
|
||||
}
|
||||
else if (soops->outlinevis == SO_SAME_TYPE) {
|
||||
Object *ob_active = OBACT(view_layer);
|
||||
if (ob_active) {
|
||||
FOREACH_SCENE_OBJECT(scene, ob)
|
||||
{
|
||||
if (ob->type == ob_active->type) {
|
||||
outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END
|
||||
outliner_make_hierarchy(&soops->tree);
|
||||
}
|
||||
}
|
||||
else if (soops->outlinevis == SO_SELECTED) {
|
||||
FOREACH_SELECTED_BASE(view_layer, base)
|
||||
{
|
||||
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
||||
ten->directdata = base;
|
||||
}
|
||||
FOREACH_SELECTED_BASE_END
|
||||
outliner_make_hierarchy(&soops->tree);
|
||||
}
|
||||
else if (soops->outlinevis == SO_SEQUENCE) {
|
||||
Sequence *seq;
|
||||
Editing *ed = BKE_sequencer_editing_get(scene, false);
|
||||
|
@ -2023,10 +2303,29 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
|
|||
outliner_add_orphaned_datablocks(mainvar, soops);
|
||||
}
|
||||
else if (soops->outlinevis == SO_VIEW_LAYER) {
|
||||
outliner_add_view_layer(soops, scene, view_layer);
|
||||
if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) {
|
||||
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
|
||||
TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
||||
te_object->directdata = base;
|
||||
}
|
||||
outliner_make_hierarchy(&soops->tree);
|
||||
}
|
||||
else {
|
||||
outliner_add_view_layer(soops, scene, view_layer);
|
||||
}
|
||||
}
|
||||
else if (soops->outlinevis == SO_COLLECTIONS) {
|
||||
outliner_add_collections(soops, scene);
|
||||
if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) {
|
||||
FOREACH_SCENE_OBJECT(scene, ob)
|
||||
{
|
||||
outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END
|
||||
outliner_make_hierarchy(&soops->tree);
|
||||
}
|
||||
else {
|
||||
outliner_add_collections(soops, scene);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BASACT(view_layer)) {
|
||||
|
@ -2038,7 +2337,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
|
|||
if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
|
||||
outliner_sort(&soops->tree);
|
||||
}
|
||||
outliner_filter_tree(soops, &soops->tree);
|
||||
|
||||
outliner_filter_tree(soops, view_layer);
|
||||
outliner_restore_scrolling_position(soops, ar, &focus);
|
||||
|
||||
BKE_main_id_clear_newpoins(mainvar);
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
|
|||
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
||||
|
||||
if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS, SO_VIEW_LAYER, SO_COLLECTIONS)) {
|
||||
if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_GROUPS, SO_VIEW_LAYER, SO_COLLECTIONS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -266,6 +266,9 @@ typedef struct SpaceOops {
|
|||
struct TreeStoreElem search_tse;
|
||||
|
||||
short flag, outlinevis, storeflag, search_flags;
|
||||
int filter;
|
||||
char filter_state;
|
||||
char pad[3];
|
||||
|
||||
/* pointers to treestore elements, grouped by (id, type, nr) in hashtable for faster searching */
|
||||
void *treehash;
|
||||
|
@ -281,14 +284,58 @@ typedef enum eSpaceOutliner_Flag {
|
|||
SO_SKIP_SORT_ALPHA = (1 << 4),
|
||||
} eSpaceOutliner_Flag;
|
||||
|
||||
/* SpaceOops->filter */
|
||||
typedef enum eSpaceOutliner_Filter {
|
||||
SO_FILTER_SEARCH = (1 << 0),
|
||||
SO_FILTER_ENABLE = (1 << 1),
|
||||
SO_FILTER_NO_OBJECT = (1 << 2),
|
||||
SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
|
||||
SO_FILTER_NO_CHILDREN = (1 << 4),
|
||||
|
||||
SO_FILTER_OB_TYPE = (1 << 5),
|
||||
SO_FILTER_NO_OB_MESH = (1 << 6),
|
||||
SO_FILTER_NO_OB_ARMATURE = (1 << 7),
|
||||
SO_FILTER_NO_OB_EMPTY = (1 << 8),
|
||||
SO_FILTER_NO_OB_LAMP = (1 << 9),
|
||||
SO_FILTER_NO_OB_CAMERA = (1 << 10),
|
||||
SO_FILTER_NO_OB_OTHERS = (1 << 11),
|
||||
|
||||
SO_FILTER_OB_STATE = (1 << 12),
|
||||
SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_SELECTED= (1 << 14), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */
|
||||
SO_FILTER_NO_COLLECTION = (1 << 16),
|
||||
} eSpaceOutliner_Filter;
|
||||
|
||||
#define SO_FILTER_NO_OB_ALL (SO_FILTER_NO_OB_MESH | \
|
||||
SO_FILTER_NO_OB_ARMATURE | \
|
||||
SO_FILTER_NO_OB_EMPTY | \
|
||||
SO_FILTER_NO_OB_LAMP | \
|
||||
SO_FILTER_NO_OB_CAMERA | \
|
||||
SO_FILTER_NO_OB_OTHERS)
|
||||
|
||||
#define SO_FILTER_ANY (SO_FILTER_NO_OBJECT | \
|
||||
SO_FILTER_NO_OB_CONTENT | \
|
||||
SO_FILTER_NO_CHILDREN | \
|
||||
SO_FILTER_OB_TYPE | \
|
||||
SO_FILTER_OB_STATE | \
|
||||
SO_FILTER_NO_COLLECTION)
|
||||
|
||||
/* SpaceOops->filter_state */
|
||||
typedef enum eSpaceOutliner_StateFilter {
|
||||
SO_FILTER_OB_VISIBLE = 0,
|
||||
SO_FILTER_OB_SELECTED = 1,
|
||||
SO_FILTER_OB_ACTIVE = 2,
|
||||
} eSpaceOutliner_StateFilter;
|
||||
|
||||
/* SpaceOops->outlinevis */
|
||||
typedef enum eSpaceOutliner_Mode {
|
||||
SO_ALL_SCENES = 0,
|
||||
SO_CUR_SCENE = 1,
|
||||
SO_VISIBLE = 2,
|
||||
SO_SELECTED = 3,
|
||||
SO_ACTIVE = 4,
|
||||
SO_SAME_TYPE = 5,
|
||||
/* SO_CUR_SCENE = 1, */ /* deprecated! */
|
||||
/* SO_VISIBLE = 2, */ /* deprecated! */
|
||||
/* SO_SELECTED = 3, */ /* deprecated! */
|
||||
/* SO_ACTIVE = 4, */ /* deprecated! */
|
||||
/* SO_SAME_TYPE = 5, */ /* deprecated! */
|
||||
SO_GROUPS = 6,
|
||||
SO_LIBRARIES = 7,
|
||||
/* SO_VERSE_SESSION = 8, */ /* deprecated! */
|
||||
|
|
|
@ -2101,13 +2101,10 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
|||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem display_mode_items[] = {
|
||||
{SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display data-blocks in all scenes"},
|
||||
{SO_CUR_SCENE, "CURRENT_SCENE", 0, "Current Scene", "Display data-blocks in current scene"},
|
||||
{SO_VISIBLE, "VISIBLE_LAYERS", 0, "Visible Layers", "Display data-blocks in visible layers"},
|
||||
{SO_SELECTED, "SELECTED", 0, "Selected", "Display data-blocks of selected, visible objects"},
|
||||
{SO_ACTIVE, "ACTIVE", 0, "Active", "Display data-blocks of active object"},
|
||||
{SO_SAME_TYPE, "SAME_TYPES", 0, "Same Types",
|
||||
"Display data-blocks of all objects of same type as selected object"},
|
||||
{SO_VIEW_LAYER, "VIEW_LAYER", 0, "View Layer", "Display the collections of the active view layer"},
|
||||
{SO_COLLECTIONS, "COLLECTIONS", 0, "Collections", "Display all collections based on the "
|
||||
"master collection hierarchy"},
|
||||
{SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display composition related data in all scenes"},
|
||||
{SO_GROUPS, "GROUPS", 0, "Groups", "Display groups and their data-blocks"},
|
||||
{SO_SEQUENCE, "SEQUENCE", 0, "Sequence", "Display sequence data-blocks"},
|
||||
{SO_LIBRARIES, "LIBRARIES", 0, "Blender File", "Display data of current file and linked libraries"},
|
||||
|
@ -2115,9 +2112,13 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
|||
{SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"},
|
||||
{SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data",
|
||||
"Display data-blocks which are unused and/or will be lost when the file is reloaded"},
|
||||
{SO_VIEW_LAYER, "VIEW_LAYER", 0, "View Layer", "Display the collections of the active view layer"},
|
||||
{SO_COLLECTIONS, "COLLECTIONS", 0, "Collections", "Display all collections based on the "
|
||||
"master collection hierarchy"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static const EnumPropertyItem filter_state_items[] = {
|
||||
{SO_FILTER_OB_VISIBLE, "VISIBLE", ICON_RESTRICT_VIEW_OFF, "Visible", "Show visible objects"},
|
||||
{SO_FILTER_OB_SELECTED, "SELECTED", ICON_RESTRICT_SELECT_OFF, "Selected", "Show selected objects"},
|
||||
{SO_FILTER_OB_ACTIVE, "ACTIVE", ICON_LAYER_ACTIVE, "Active", "Show only the active object"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -2159,6 +2160,100 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
|||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_HIDE_RESTRICTCOLS);
|
||||
RNA_def_property_ui_text(prop, "Show Restriction Columns", "Show column");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
/* Filters. */
|
||||
prop = RNA_def_property(srna, "use_filter_search", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_SEARCH);
|
||||
RNA_def_property_ui_text(prop, "Search Name", "Filter searched elements");
|
||||
RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filters", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_ENABLE);
|
||||
RNA_def_property_ui_text(prop, "Use Filters", "Use filters");
|
||||
RNA_def_property_ui_icon(prop, ICON_FILTER, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OBJECT);
|
||||
RNA_def_property_ui_text(prop, "Filter Objects", "Show objects");
|
||||
RNA_def_property_ui_icon(prop, ICON_OBJECT_DATA, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_content", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CONTENT);
|
||||
RNA_def_property_ui_text(prop, "Filter Objects Contents", "Show what is inside the objects elements");
|
||||
RNA_def_property_ui_icon(prop, ICON_MODIFIER, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_children", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_CHILDREN);
|
||||
RNA_def_property_ui_text(prop, "Filter Objects Children", "Show children");
|
||||
RNA_def_property_ui_icon(prop, ICON_PLUS, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION);
|
||||
RNA_def_property_ui_text(prop, "Filter Collections", "Show collections");
|
||||
RNA_def_property_ui_icon(prop, ICON_COLLAPSEMENU, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
/* Filters object state. */
|
||||
prop = RNA_def_property(srna, "use_filter_object_state", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_OB_STATE);
|
||||
RNA_def_property_ui_text(prop, "Filter Object State", "Filter objects based on their state (visible, ...)."
|
||||
"This can be slow");
|
||||
RNA_def_property_ui_icon(prop, ICON_LAYER_USED, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "filter_state", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "filter_state");
|
||||
RNA_def_property_enum_items(prop, filter_state_items);
|
||||
RNA_def_property_ui_text(prop, "State Filter", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
/* Filters object type. */
|
||||
prop = RNA_def_property(srna, "use_filter_object_type", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_OB_TYPE);
|
||||
RNA_def_property_ui_text(prop, "Filter Object Type", "Show specific objects types");
|
||||
RNA_def_property_ui_icon(prop, ICON_MESH_CUBE, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_mesh", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_MESH);
|
||||
RNA_def_property_ui_text(prop, "Show Meshes", "Show mesh objects");
|
||||
RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_MESH, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_armature", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_ARMATURE);
|
||||
RNA_def_property_ui_text(prop, "Show Armatures", "Show armature objects");
|
||||
RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_ARMATURE, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_empty", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_EMPTY);
|
||||
RNA_def_property_ui_text(prop, "Show Empties", "Show empty objects");
|
||||
RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_EMPTY, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_lamp", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_LAMP);
|
||||
RNA_def_property_ui_text(prop, "Show Lamps", "Show lamps objects");
|
||||
RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_LAMP, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_camera", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CAMERA);
|
||||
RNA_def_property_ui_text(prop, "Show Cameras", "Show camera objects");
|
||||
RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_CAMERA, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_object_others", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_OTHERS);
|
||||
RNA_def_property_ui_text(prop, "Show Other Objects", "Show curves, lattices, light probes, fonts, ...");
|
||||
RNA_def_property_ui_icon(prop, ICON_ZOOMIN, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_view3d(BlenderRNA *brna)
|
||||
|
|
Loading…
Reference in New Issue