Outliner: Add way to display warning icon for items.

While theorically fairly generic, current code is only enabled for
bledfile and liboverride views, and only used to display messages from
library IDs.

Reviewed By: Severin

Differential Revision: https://developer.blender.org/D13766
This commit is contained in:
Bastien Montagne 2022-01-12 17:59:46 +01:00 committed by Bastien Montagne
parent 5f7ad4baaa
commit a909ab984c
8 changed files with 167 additions and 12 deletions

View File

@ -79,6 +79,7 @@
#include "RNA_access.h"
#include "outliner_intern.h"
#include "tree/tree_display.h"
/* Disable - this is far too slow - campbell. */
/* #define USE_GROUP_SELECT */
@ -2143,6 +2144,80 @@ static void outliner_draw_mode_column(const bContext *C,
}
}
/* Returns `true` if some warning was drawn for that element or one of its sub-elements (if it is
* not open). */
static bool outliner_draw_warning_tree_element(uiBlock *block,
SpaceOutliner *space_outliner,
TreeElement *te,
TreeStoreElem *tselem,
const bool use_mode_column,
const int te_ys)
{
if ((te->flag & TE_HAS_WARNING) == 0) {
/* If given element has no warning, recusively try to display the first sub-elements' warning.
*/
if (!TSELEM_OPEN(tselem, space_outliner)) {
LISTBASE_FOREACH (TreeElement *, sub_te, &te->subtree) {
TreeStoreElem *sub_tselem = TREESTORE(sub_te);
if (outliner_draw_warning_tree_element(
block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) {
return true;
}
}
}
return false;
}
int icon = ICON_NONE;
const char *tip = "";
const bool has_warning = outliner_element_warnings_get(te, &icon, &tip);
BLI_assert(has_warning);
UNUSED_VARS_NDEBUG(has_warning);
/* Move the warnings a unit left in view layer mode. */
const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
UI_UNIT_X :
0;
UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
uiBut *but = uiDefIconBut(block,
UI_BTYPE_ICON_TOGGLE,
0,
icon,
mode_column_offset,
te_ys,
UI_UNIT_X,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0.0,
0.0,
tip);
/* No need for undo here, this is a pure info widget. */
UI_but_flag_disable(but, UI_BUT_UNDO);
return true;
}
static void outliner_draw_warning_column(const bContext *C,
uiBlock *block,
SpaceOutliner *space_outliner,
const bool use_mode_column,
ListBase *tree)
{
LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
outliner_draw_warning_tree_element(block, space_outliner, te, tselem, use_mode_column, te->ys);
if (TSELEM_OPEN(tselem, space_outliner)) {
outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &te->subtree);
}
}
}
/* ****************************************************** */
/* Normal Drawing... */
@ -3612,17 +3687,22 @@ static void outliner_draw_tree(bContext *C,
SpaceOutliner *space_outliner,
const float restrict_column_width,
const bool use_mode_column,
const bool use_warning_column,
TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
int starty, startx;
/* Move the tree a unit left in view layer mode */
short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
UI_UNIT_X :
0;
short columns_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
UI_UNIT_X :
0;
if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
mode_column_offset -= UI_UNIT_X;
columns_offset -= UI_UNIT_X;
}
if (use_warning_column) {
columns_offset += UI_UNIT_X;
}
GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
@ -3650,12 +3730,12 @@ static void outliner_draw_tree(bContext *C,
/* Draw hierarchy lines for collections and object children. */
starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET;
startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty);
/* Items themselves. */
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = mode_column_offset;
startx = columns_offset;
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
outliner_draw_tree_element(C,
block,
@ -3786,6 +3866,10 @@ void draw_outliner(const bContext *C)
const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
(ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
const bool use_warning_column =
ELEM(space_outliner->outlinevis, SO_LIBRARIES, SO_OVERRIDES_LIBRARY) &&
outliner_tree_display_warnings_poll(space_outliner->runtime->tree_display);
/* Draw outliner stuff (background, hierarchy lines and names). */
const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
outliner_back(region);
@ -3797,6 +3881,7 @@ void draw_outliner(const bContext *C)
space_outliner,
restrict_column_width,
use_mode_column,
use_warning_column,
&te_edit);
/* Compute outliner dimensions after it has been drawn. */
@ -3841,6 +3926,11 @@ void draw_outliner(const bContext *C)
outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
}
/* Draw warning icons */
if (use_warning_column) {
outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree);
}
UI_block_emboss_set(block, UI_EMBOSS);
/* Draw edit buttons if necessary. */

View File

@ -158,6 +158,8 @@ enum {
/* Child elements of the same type in the icon-row are drawn merged as one icon.
* This flag is set for an element that is part of these merged child icons. */
TE_ICONROW_MERGED = (1 << 7),
/* This element has some warning to be displayed. */
TE_HAS_WARNING = (1 << 8),
};
/* button events */

View File

@ -74,6 +74,7 @@
#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "outliner_intern.h"
#include "tree/tree_display.h"
@ -812,6 +813,41 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
bool outliner_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
{
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type != TSE_SOME_ID) {
return false;
}
if (te->idcode != ID_LI) {
return false;
}
Library *library = (Library *)tselem->id;
if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
if (r_icon) {
*r_icon = ICON_ERROR;
}
if (r_message) {
*r_message = TIP_(
"Contains linked library overrides that need to be resynced, updating the library is "
"recommended");
}
return true;
}
if (library->id.tag & LIB_TAG_MISSING) {
if (r_icon) {
*r_icon = ICON_ERROR;
}
if (r_message) {
*r_message = TIP_("Missing library");
}
return true;
}
return false;
}
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@ -1115,6 +1151,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
}
if (outliner_element_warnings_get(te, NULL, NULL)) {
te->flag |= TE_HAS_WARNING;
}
return te;
}

View File

@ -66,3 +66,10 @@ ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceD
{
return reinterpret_cast<AbstractTreeDisplay *>(tree_display)->buildTree(*source_data);
}
bool outliner_tree_display_warnings_poll(const TreeDisplay *tree_display)
{
const AbstractTreeDisplay *abstract_tree_display = reinterpret_cast<const AbstractTreeDisplay *>(
tree_display);
return abstract_tree_display->has_warnings;
}

View File

@ -47,6 +47,16 @@ void outliner_tree_display_destroy(TreeDisplay **tree_display);
ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data);
/** Accessor to whether given tree has some warnings to display. */
bool outliner_tree_display_warnings_poll(const struct TreeDisplay *tree_display);
/** Get actual warning data of a tree element, if any.
*
* \param r_icon The icon to display as warning.
* \param r_message The message to display as warning.
* \return true if there is a warning, false otherwise. */
bool outliner_element_warnings_get(struct TreeElement *te, int *r_icon, const char **r_message);
/* The following functions are needed to build the tree. They are calls back into C; the way
* elements are created should be refactored and ported to C++ with a new design/API too. */
/**

View File

@ -65,6 +65,8 @@ class AbstractTreeDisplay {
*/
virtual ListBase buildTree(const TreeSourceData &source_data) = 0;
bool has_warnings = false;
protected:
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
SpaceOutliner &space_outliner_;
@ -105,7 +107,7 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
TreeElement *add_library_contents(Main &, ListBase &, Library *);
bool library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
@ -123,7 +125,7 @@ class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
TreeElement *add_library_contents(Main &, ListBase &, Library *);
bool override_library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};

View File

@ -104,9 +104,7 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data)
return tree;
}
TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
ListBase &lb,
Library *lib) const
TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
{
const short filter_id_type = id_filter_get();
@ -149,6 +147,9 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
if (tenlib->flag & TE_HAS_WARNING) {
has_warnings = true;
}
}
/* Create data-block list parent element on demand. */

View File

@ -112,7 +112,7 @@ ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data
TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
ListBase &lb,
Library *lib) const
Library *lib)
{
const short filter_id_type = id_filter_get();
@ -152,6 +152,9 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
if (tenlib->flag & TE_HAS_WARNING) {
has_warnings = true;
}
}
/* Create data-block list parent element on demand. */