Outliner: Aggregate ID types and object types together with numbers

We draw small numbers over the icon of multiple objects of the same type.
Also, we make all inlined elements to be non-clickabled.

For modifiers we still do it the old way. In this case it is more important
to see the order then the ammount.

Reviewers: brecht, campbellbarton
Subscribers: billreynish, venomgfx

Design task and mockup: T54707
Differential Revision: https://developer.blender.org/D3497
This commit is contained in:
Dalai Felinto 2018-06-21 19:40:14 +02:00
parent 42344adcd4
commit f4f6e5b665
3 changed files with 177 additions and 42 deletions

View File

@ -51,6 +51,7 @@
#include "BKE_deform.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
@ -905,7 +906,7 @@ static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg,
static void tselem_draw_icon(
uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
float alpha)
float alpha, const bool is_clickable)
{
struct DrawIconArg arg;
float aspect;
@ -926,6 +927,7 @@ static void tselem_draw_icon(
arg.y = y;
#define ICON_DRAW(_icon) UI_icon_draw_alpha(x, y, _icon, alpha)
#define ICON_CLICK_DRAW(_icon) if (!is_clickable) ICON_DRAW(_icon); else tselem_draw_icon_uibut(&arg, _icon)
if (tselem->type) {
switch (tselem->type) {
@ -1197,33 +1199,33 @@ static void tselem_draw_icon(
Object *ob = (Object *)tselem->id;
switch (ob->type) {
case OB_LAMP:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_LAMP); break;
case OB_MESH:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_MESH); break;
case OB_CAMERA:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_CAMERA); break;
case OB_CURVE:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_CURVE); break;
case OB_MBALL:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_META); break;
case OB_LATTICE:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_LATTICE); break;
case OB_ARMATURE:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_ARMATURE); break;
case OB_FONT:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_FONT); break;
case OB_SURF:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_SURFACE); break;
case OB_SPEAKER:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_SPEAKER); break;
case OB_LIGHTPROBE:
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LIGHTPROBE); break;
ICON_CLICK_DRAW(ICON_OUTLINER_OB_LIGHTPROBE); break;
case OB_EMPTY:
if (ob->dup_group) {
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_GROUP_INSTANCE);
ICON_CLICK_DRAW(ICON_OUTLINER_OB_GROUP_INSTANCE);
}
else {
tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY);
ICON_CLICK_DRAW(ICON_OUTLINER_OB_EMPTY);
}
break;
}
@ -1331,13 +1333,137 @@ static void tselem_draw_icon(
#undef ICON_DRAW
}
/**
* For icon-only children of a collapsed tree,
* Draw small number over the icon to show how many items of this type are displayed.
*/
static void outliner_draw_iconrow_number(
const uiFontStyle *fstyle,
int offsx, int ys,
const eOLDrawState active,
const int num_elements)
{
float color[4] = {0.4f, 0.4f, 0.4f, 0.9f};
copy_v3_fl(color, 0.2f);
if (active != OL_DRAWSEL_NONE) {
copy_v3_fl(color, 0.65f);
color[3] = 1.0f;
}
float ufac = 0.25f * UI_UNIT_X;
float offset_x = (float) offsx + UI_UNIT_X * 0.35f;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_aa(true,
offset_x + ufac,
(float)ys - UI_UNIT_Y * 0.2f + ufac,
offset_x + UI_UNIT_X - ufac,
(float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
(float)UI_UNIT_Y / 2.0f - ufac,
color);
/* Now the numbers. */
unsigned char text_col[4];
UI_GetThemeColor4ubv(TH_TEXT_HI, text_col);
text_col[3] = 255;
uiFontStyle fstyle_small = *fstyle;
fstyle_small.points *= 0.8f;
/* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
int num_digits = 4;
char number_text[4] = "+99\0";
if (num_elements < 100) {
BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
num_digits = num_elements < 10 ? 1 : 2;
}
UI_fontstyle_draw_simple(&fstyle_small,
(offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f),
(float)ys - UI_UNIT_Y * 0.095f + ufac,
number_text, text_col);
UI_fontstyle_set(fstyle);
glEnable(GL_BLEND); /* Roundbox and text drawing disables. */
}
static void outliner_draw_iconrow_doit(
uiBlock *block, TreeElement *te,
const uiFontStyle *fstyle,
int xmax, int *offsx, int ys, float alpha_fac,
const eOLDrawState active,
const int num_elements)
{
TreeStoreElem *tselem = TREESTORE(te);
if (active != OL_DRAWSEL_NONE) {
float ufac = UI_UNIT_X / 20.0f;
float color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
color[3] *= alpha_fac;
UI_draw_roundbox_aa(true,
(float) *offsx + 1.0f * ufac,
(float)ys + 1.0f * ufac,
(float)*offsx + UI_UNIT_X - 1.0f * ufac,
(float)ys + UI_UNIT_Y - ufac,
(float)UI_UNIT_Y / 2.0f - ufac,
color);
glEnable(GL_BLEND); /* Roundbox disables. */
}
/* No inlined icon should be clickable. */
tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac, false);
te->xs = *offsx;
te->ys = ys;
te->xend = (short)*offsx + UI_UNIT_X;
if (num_elements > 1) {
outliner_draw_iconrow_number(fstyle, *offsx, ys, active, num_elements);
}
(*offsx) += UI_UNIT_X;
}
/**
* Return the index to use based on the TreeElement ID and object type
*
* We use a continuum of indeces until we get to the object datablocks
* and we then make room for the object types.
*/
static int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
const int id_index = tselem->type == 0 ? BKE_idcode_to_index(te->idcode) : INDEX_ID_GR;
if (id_index < INDEX_ID_OB) {
return id_index;
}
else if (id_index == INDEX_ID_OB) {
const Object *ob = (Object *)tselem->id;
return INDEX_ID_OB + ob->type;
}
else {
return id_index + OB_TYPE_MAX;
}
}
static void outliner_draw_iconrow(
bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer, SpaceOops *soops,
bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, SpaceOops *soops,
ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac)
{
eOLDrawState active;
const Object *obact = OBACT(view_layer);
struct {
eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX];
int num_elements[INDEX_ID_MAX + OB_TYPE_MAX];
TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX];
} data = {
.active = {0},
.num_elements = {0},
.tree_element = {NULL},
};
for (TreeElement *te = lb->first; te; te = te->next) {
/* exit drawing early */
if ((*offsx) - UI_UNIT_X > xmax)
@ -1363,41 +1489,48 @@ static void outliner_draw_iconrow(
active = tree_element_type_active(C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
}
if (active != OL_DRAWSEL_NONE) {
float ufac = UI_UNIT_X / 20.0f;
float color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
color[3] *= alpha_fac;
UI_draw_roundbox_aa(
true,
(float) *offsx + 1.0f * ufac,
(float)ys + 1.0f * ufac,
(float)*offsx + UI_UNIT_X - 1.0f * ufac,
(float)ys + UI_UNIT_Y - ufac,
(float)UI_UNIT_Y / 2.0f - ufac,
color);
glEnable(GL_BLEND); /* roundbox disables */
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
}
else {
const int index = tree_element_id_type_to_index(te);
data.num_elements[index]++;
if ((data.tree_element[index] == NULL) ||
(active > data.active[index]))
{
data.tree_element[index] = te;
}
data.active[index] = MAX2(active, data.active[index]);
}
tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac);
te->xs = *offsx;
te->ys = ys;
te->xend = (short)*offsx + UI_UNIT_X;
te->flag |= TE_ICONROW; // for click
(*offsx) += UI_UNIT_X;
}
/* this tree element always has same amount of branches, so don't draw */
if (tselem->type != TSE_R_LAYER) {
outliner_draw_iconrow(
C, block, scene, view_layer, soops,
C, block, fstyle, scene, view_layer, soops,
&te->subtree, level + 1, xmax, offsx, ys, alpha_fac);
}
}
for (int i = 0; i < INDEX_ID_MAX; i++) {
const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1;
/* See tree_element_id_type_to_index for the index logic. */
int index_base = i;
if (i > INDEX_ID_OB){
index_base += OB_TYPE_MAX;
}
for (int j = 0; j < num_subtypes; j++) {
const int index = index_base + j;
if (data.num_elements[index] != 0) {
outliner_draw_iconrow_doit(block,
data.tree_element[index],
fstyle,
xmax, offsx, ys, alpha_fac,
data.active[index],
data.num_elements[index]);
}
}
}
}
/* closed tree element */
@ -1538,7 +1671,7 @@ static void outliner_draw_tree_element(
/* datatype icon */
if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) {
tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac);
tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true);
offsx += UI_UNIT_X + 2 * ufac;
}
else
@ -1622,7 +1755,7 @@ static void outliner_draw_tree_element(
}
outliner_draw_iconrow(
C, block, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx,
C, block, fstyle, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx,
*starty, alpha_fac);
glDisable(GL_BLEND);

View File

@ -576,6 +576,7 @@ enum {
INDEX_ID_WM,
INDEX_ID_MSK,
INDEX_ID_NULL,
INDEX_ID_MAX,
};
#ifdef __cplusplus

View File

@ -367,6 +367,7 @@ enum {
/* 23 and 24 are for life and sector (old file compat.) */
OB_ARMATURE = 25,
OB_TYPE_MAX,
};
/* ObjectDisplay.flag */