Fix / cleanup panel category tab drawing

The panel category tabs (In the 3D view N-panel) did not look great
when zoomed in or with high DPI screens, with multiple overlapping
outlines, and roundness that didn't match elsewhere in Blender. In
addition, there was some unecessarily low-level drawing code in the
panel code.

This commit uses an existing function `UI_draw_roundbox_4fv`to draw
the tabs instead. There are some slight visual differences, though
these are easily adjusted with theme colors.

Differential Revision: https://developer.blender.org/D9045
This commit is contained in:
Yevgeny Makarov 2020-10-07 08:45:46 -05:00 committed by Hans Goudey
parent 983ad4210b
commit 13391038a5
1 changed files with 61 additions and 234 deletions

View File

@ -1324,128 +1324,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
/** \name Category Drawing (Tabs)
* \{ */
static void imm_buf_append(
float vbuf[][2], uchar cbuf[][3], float x, float y, const uchar col[3], int *index)
{
ARRAY_SET_ITEMS(vbuf[*index], x, y);
ARRAY_SET_ITEMS(cbuf[*index], UNPACK3(col));
(*index)++;
}
/* Based on UI_draw_roundbox, check on making a version which allows us to skip some sides. */
static void ui_panel_category_draw_tab(bool filled,
float minx,
float miny,
float maxx,
float maxy,
float rad,
const int roundboxtype,
const bool use_highlight,
const bool use_shadow,
const bool use_flip_x,
const uchar highlight_fade[3],
const uchar col[3])
{
float vec[4][2] = {{0.195, 0.02}, {0.55, 0.169}, {0.831, 0.45}, {0.98, 0.805}};
for (int a = 0; a < 4; a++) {
mul_v2_fl(vec[a], rad);
}
uint vert_len = 0;
if (use_highlight) {
vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 6 : 1;
vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 6 : 1;
}
if (use_highlight && !use_shadow) {
vert_len++;
}
else {
vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 6 : 1;
vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 6 : 1;
}
/* Maximum size. */
float vbuf[24][2];
uchar cbuf[24][3];
int buf_index = 0;
/* Start right-top corner. */
if (use_highlight) {
if (roundboxtype & UI_CNR_TOP_RIGHT) {
imm_buf_append(vbuf, cbuf, maxx, maxy - rad, col, &buf_index);
for (int a = 0; a < 4; a++) {
imm_buf_append(vbuf, cbuf, maxx - vec[a][1], maxy - rad + vec[a][0], col, &buf_index);
}
imm_buf_append(vbuf, cbuf, maxx - rad, maxy, col, &buf_index);
}
else {
imm_buf_append(vbuf, cbuf, maxx, maxy, col, &buf_index);
}
/* Left top-corner. */
if (roundboxtype & UI_CNR_TOP_LEFT) {
imm_buf_append(vbuf, cbuf, minx + rad, maxy, col, &buf_index);
for (int a = 0; a < 4; a++) {
imm_buf_append(vbuf, cbuf, minx + rad - vec[a][0], maxy - vec[a][1], col, &buf_index);
}
imm_buf_append(vbuf, cbuf, minx, maxy - rad, col, &buf_index);
}
else {
imm_buf_append(vbuf, cbuf, minx, maxy, col, &buf_index);
}
}
if (use_highlight && !use_shadow) {
imm_buf_append(
vbuf, cbuf, minx, miny + rad, highlight_fade ? col : highlight_fade, &buf_index);
}
else {
/* Left bottom-corner. */
if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
imm_buf_append(vbuf, cbuf, minx, miny + rad, col, &buf_index);
for (int a = 0; a < 4; a++) {
imm_buf_append(vbuf, cbuf, minx + vec[a][1], miny + rad - vec[a][0], col, &buf_index);
}
imm_buf_append(vbuf, cbuf, minx + rad, miny, col, &buf_index);
}
else {
imm_buf_append(vbuf, cbuf, minx, miny, col, &buf_index);
}
/* Right-bottom corner. */
if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
imm_buf_append(vbuf, cbuf, maxx - rad, miny, col, &buf_index);
for (int a = 0; a < 4; a++) {
imm_buf_append(vbuf, cbuf, maxx - rad + vec[a][0], miny + vec[a][1], col, &buf_index);
}
imm_buf_append(vbuf, cbuf, maxx, miny + rad, col, &buf_index);
}
else {
imm_buf_append(vbuf, cbuf, maxx, miny, col, &buf_index);
}
}
if (use_flip_x) {
const float midx = (minx + maxx) / 2.0f;
for (int i = 0; i < buf_index; i++) {
vbuf[i][0] = midx - (vbuf[i][0] - midx);
}
}
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint color = GPU_vertformat_attr_add(
format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_STRIP, vert_len);
for (int i = 0; i < buf_index; i++) {
immAttr3ubv(color, cbuf[i]);
immVertex2fv(pos, vbuf[i]);
}
immEnd();
immUnbindProgram();
}
#define TABS_PADDING_BETWEEN_FACTOR 4.0f
#define TABS_PADDING_TEXT_FACTOR 6.0f
/**
* Draw vertical tabs on the left side of the region, one tab per category.
@ -1461,17 +1341,17 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
short fstyle_points = fstyle->points;
const float aspect = ((uiBlock *)region->uiblocks.first)->aspect;
const float zoom = 1.0f / aspect;
const int px = max_ii(1, round_fl_to_int(U.pixelsize));
const int px_x_sign = is_left ? px : -px;
const int px = U.pixelsize;
const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom);
const float dpi_fac = UI_DPI_FAC;
/* Padding of tabs around text. */
const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom);
const int tab_v_pad_text = round_fl_to_int(TABS_PADDING_TEXT_FACTOR * dpi_fac * zoom) + 2 * px;
/* Padding between tabs. */
const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom);
const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom;
/* We flip the tab drawing, so always use these flags. */
const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
const int tab_v_pad = round_fl_to_int(TABS_PADDING_BETWEEN_FACTOR * dpi_fac * zoom);
bTheme *btheme = UI_GetTheme();
const float tab_curve_radius = btheme->tui.wcol_tab.roundness * U.widget_unit * zoom;
const int roundboxtype = is_left ? (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT) :
(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
bool is_alpha;
bool do_scaletabs = false;
#ifdef USE_FLAT_INACTIVE
@ -1493,28 +1373,18 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
/* Tab colors. */
uchar theme_col_tab_bg[4];
uchar theme_col_tab_active[3];
uchar theme_col_tab_inactive[3];
/* Secondary theme colors. */
uchar theme_col_tab_outline[3];
uchar theme_col_tab_divider[3]; /* Line that divides tabs from the main region. */
uchar theme_col_tab_highlight[3];
uchar theme_col_tab_highlight_inactive[3];
float theme_col_tab_active[4];
float theme_col_tab_inactive[4];
float theme_col_tab_outline[4];
UI_GetThemeColor4ubv(TH_BACK, theme_col_back);
UI_GetThemeColor3ubv(TH_TEXT, theme_col_text);
UI_GetThemeColor3ubv(TH_TEXT_HI, theme_col_text_hi);
UI_GetThemeColor4ubv(TH_TAB_BACK, theme_col_tab_bg);
UI_GetThemeColor3ubv(TH_TAB_ACTIVE, theme_col_tab_active);
UI_GetThemeColor3ubv(TH_TAB_INACTIVE, theme_col_tab_inactive);
UI_GetThemeColor3ubv(TH_TAB_OUTLINE, theme_col_tab_outline);
interp_v3_v3v3_uchar(theme_col_tab_divider, theme_col_back, theme_col_tab_outline, 0.3f);
interp_v3_v3v3_uchar(theme_col_tab_highlight, theme_col_back, theme_col_text_hi, 0.2f);
interp_v3_v3v3_uchar(
theme_col_tab_highlight_inactive, theme_col_tab_inactive, theme_col_text_hi, 0.12f);
UI_GetThemeColor4fv(TH_TAB_ACTIVE, theme_col_tab_active);
UI_GetThemeColor4fv(TH_TAB_INACTIVE, theme_col_tab_inactive);
UI_GetThemeColor4fv(TH_TAB_OUTLINE, theme_col_tab_outline);
is_alpha = (region->overlap && (theme_col_back[3] != 255));
@ -1536,7 +1406,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
/* Calculate tab rectangle and check if we need to scale down. */
LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, &region->panels_category) {
rcti *rct = &pc_dyn->rect;
const char *category_id = pc_dyn->idname;
const char *category_id_draw = IFACE_(category_id);
@ -1594,11 +1463,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
immUnbindProgram();
const int divider_xmin = is_left ? (v2d->mask.xmin + (category_tabs_width - px)) :
(v2d->mask.xmax - category_tabs_width) + px;
const int divider_xmax = is_left ? (v2d->mask.xmin + category_tabs_width) :
(v2d->mask.xmax - (category_tabs_width + px)) + px;
LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, &region->panels_category) {
const rcti *rct = &pc_dyn->rect;
const char *category_id = pc_dyn->idname;
@ -1614,109 +1478,71 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
GPU_blend(GPU_BLEND_ALPHA);
#ifdef USE_FLAT_INACTIVE
/* Draw line between inactive tabs. */
if (is_active == false && is_active_prev == false && pc_dyn->prev) {
pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3fvAlpha(theme_col_tab_outline, 0.3f);
immRecti(pos,
is_left ? v2d->mask.xmin + (category_tabs_width / 5) :
v2d->mask.xmax - (category_tabs_width / 5),
rct->ymax + px,
is_left ? (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5) :
(v2d->mask.xmax - category_tabs_width) + (category_tabs_width / 5),
rct->ymax + (px * 3));
immUnbindProgram();
}
is_active_prev = is_active;
if (is_active)
#endif
{
const bool use_flip_x = !is_left;
ui_panel_category_draw_tab(true,
rct->xmin,
rct->ymin,
rct->xmax,
rct->ymax,
tab_curve_radius - px,
roundboxtype,
true,
true,
use_flip_x,
NULL,
is_active ? theme_col_tab_active : theme_col_tab_inactive);
/* Draw filled rectangle and outline for tab. */
UI_draw_roundbox_corner_set(roundboxtype);
UI_draw_roundbox_4fv(true,
rct->xmin,
rct->ymin,
rct->xmax,
rct->ymax,
tab_curve_radius,
is_active ? theme_col_tab_active : theme_col_tab_inactive);
UI_draw_roundbox_4fv(false,
rct->xmin,
rct->ymin,
rct->xmax,
rct->ymax,
tab_curve_radius,
theme_col_tab_outline);
/* Tab outline. */
ui_panel_category_draw_tab(false,
rct->xmin - px_x_sign,
rct->ymin - px,
rct->xmax - px_x_sign,
rct->ymax + px,
tab_curve_radius,
roundboxtype,
true,
true,
use_flip_x,
NULL,
theme_col_tab_outline);
/* Tab highlight (3d look). */
ui_panel_category_draw_tab(false,
rct->xmin,
rct->ymin,
rct->xmax,
rct->ymax,
tab_curve_radius,
roundboxtype,
true,
false,
use_flip_x,
is_active ? theme_col_back : theme_col_tab_inactive,
is_active ? theme_col_tab_highlight :
theme_col_tab_highlight_inactive);
}
/* Tab black-line. */
if (!is_active) {
/* Disguise the outline on one side to join the tab to the panel. */
pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ubv(theme_col_tab_divider);
immRecti(pos, divider_xmin, rct->ymin - tab_v_pad, divider_xmax, rct->ymax + tab_v_pad);
immUniformColor4fv(is_active ? theme_col_tab_active : theme_col_tab_inactive);
immRecti(pos,
is_left ? rct->xmax - px : rct->xmin,
rct->ymin + px,
is_left ? rct->xmax : rct->xmin + px,
rct->ymax - px);
immUnbindProgram();
}
/* Tab titles. */
if (do_scaletabs) {
category_draw_len = BLF_width_to_strlen(
fontid, category_id_draw, category_draw_len, category_width, NULL);
}
BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f);
/* Tab titles. */
/* Draw white shadow to give text more depth. */
BLF_color3ubv(fontid, theme_col_text);
/* Main tab title. */
BLF_draw(fontid, category_id_draw, category_draw_len);
GPU_blend(GPU_BLEND_NONE);
/* Tab black-line remaining (last tab). */
pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
if (pc_dyn->prev == NULL) {
immUniformColor3ubv(theme_col_tab_divider);
immRecti(pos, divider_xmin, rct->ymax + px, divider_xmax, v2d->mask.ymax);
}
if (pc_dyn->next == NULL) {
immUniformColor3ubv(theme_col_tab_divider);
immRecti(pos, divider_xmin, 0, divider_xmax, rct->ymin);
}
#ifdef USE_FLAT_INACTIVE
/* Draw line between inactive tabs. */
if (is_active == false && is_active_prev == false && pc_dyn->prev) {
immUniformColor3ubv(theme_col_tab_divider);
immRecti(pos,
v2d->mask.xmin + (category_tabs_width / 5),
rct->ymax + px,
(v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5),
rct->ymax + (px * 3));
}
is_active_prev = is_active;
#endif
immUnbindProgram();
/* Not essential, but allows events to be handled right up to the region edge (T38171). */
if (is_left) {
pc_dyn->rect.xmin = v2d->mask.xmin;
@ -1733,10 +1559,11 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
#undef USE_FLAT_INACTIVE
}
#undef TABS_PADDING_BETWEEN_FACTOR
#undef TABS_PADDING_TEXT_FACTOR
/** \} */
/* -------------------------------------------------------------------- */