Merge pull request 'add gradient tab rendering mode' (#1) from atagen/toes:gradient-tabs into master
Reviewed-on: #1
This commit is contained in:
commit
3a4814e1fa
4 changed files with 124 additions and 13 deletions
2
config.c
2
config.c
|
|
@ -1861,7 +1861,7 @@ parse_section_tabs(struct context *ctx)
|
|||
"enum is not 32-bit");
|
||||
return value_to_enum(
|
||||
ctx,
|
||||
(const char *[]){"rounded", "square", NULL},
|
||||
(const char *[]){"rounded", "square", "gradient", NULL},
|
||||
(int *)&conf->tabs.style);
|
||||
}
|
||||
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -475,6 +475,7 @@ struct config {
|
|||
enum {
|
||||
CONF_TABS_STYLE_ROUNDED,
|
||||
CONF_TABS_STYLE_SQUARE,
|
||||
CONF_TABS_STYLE_GRADIENT,
|
||||
} style;
|
||||
enum {
|
||||
CONF_TABS_LAYOUT_SPAN,
|
||||
|
|
|
|||
2
foot.ini
2
foot.ini
|
|
@ -178,7 +178,7 @@
|
|||
[tabs]
|
||||
enabled=yes
|
||||
position=bottom
|
||||
style=rounded
|
||||
style=rounded # rounded | square | gradient
|
||||
layout=floating
|
||||
height=26
|
||||
# tab-width=200 (max width per tab in floating mode)
|
||||
|
|
|
|||
132
render.c
132
render.c
|
|
@ -5684,6 +5684,98 @@ render_tab_label(pixman_image_t *pix, struct fcft_font *font,
|
|||
}
|
||||
}
|
||||
|
||||
/* Greyscale ramp indices for the gradient tab style.
|
||||
* The 256-color palette greyscale ramp lives at indices 232..255. */
|
||||
#define GRADIENT_BAR_BG_IDX 234
|
||||
#define GRADIENT_PILL_ACTIVE_IDX 250
|
||||
#define GRADIENT_PILL_INACTIVE_IDX 240
|
||||
#define GRADIENT_FG_ACTIVE_IDX 232
|
||||
#define GRADIENT_FG_INACTIVE_IDX 250
|
||||
|
||||
/* Hardcoded fade level masks (braille bitmasks); index = fade level (1..6).
|
||||
* Mirrors the visual progression: ⠐ ⠡ ⡐ ⢔ ⣑ ⣪ */
|
||||
static const uint8_t gradient_fade_masks[7] = {
|
||||
0x00, 0x10, 0x21, 0x50, 0x94, 0xD1, 0xEA,
|
||||
};
|
||||
|
||||
/* Braille bit (0..7) → (col, row) within the 2-col × 4-row dot grid */
|
||||
static const struct { uint8_t col, row; } gradient_dot_pos[8] = {
|
||||
{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {0, 3}, {1, 3},
|
||||
};
|
||||
|
||||
static void
|
||||
draw_gradient_pill(pixman_image_t *pix, const struct terminal *term,
|
||||
uint8_t pill_idx, uint8_t bar_bg_idx, bool gamma_correct,
|
||||
int x, int y, int w, int h, float scale)
|
||||
{
|
||||
const int n_levels = (int)ALEN(gradient_fade_masks) - 1; /* 6 */
|
||||
const int cell_w = max(2, (int)roundf(scale * 4));
|
||||
const int fade_w = n_levels * cell_w;
|
||||
|
||||
const pixman_color_t pill = color_hex_to_pixman(
|
||||
term->colors.table[pill_idx], gamma_correct);
|
||||
|
||||
if (w <= 2 * fade_w) {
|
||||
/* Tab too narrow for full fades — draw it solid */
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, &pill,
|
||||
1, &(pixman_rectangle16_t){x, y, w, h});
|
||||
return;
|
||||
}
|
||||
|
||||
/* Solid pill interior */
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, &pill,
|
||||
1, &(pixman_rectangle16_t){x + fade_w, y, w - 2 * fade_w, h});
|
||||
|
||||
const int dot_size = max(1, (int)roundf(scale));
|
||||
const float sub_w = (float)cell_w / 2.0f;
|
||||
const float sub_h = (float)h / 4.0f;
|
||||
|
||||
const int inner = (int)pill_idx - 1;
|
||||
const int outer = (int)bar_bg_idx;
|
||||
const int range = inner - outer;
|
||||
const int t_den = max(1, n_levels - 1);
|
||||
|
||||
for (int side = 0; side < 2; side++) {
|
||||
const bool left = (side == 0);
|
||||
for (int i = 1; i <= n_levels; i++) {
|
||||
/* i == 1 is the outermost cell, i == n_levels the innermost */
|
||||
const int cell_x = left
|
||||
? x + (i - 1) * cell_w
|
||||
: x + w - i * cell_w;
|
||||
|
||||
const uint8_t band_idx = (uint8_t)(
|
||||
outer + (range * (i - 1) + t_den / 2) / t_den);
|
||||
const uint8_t dot_idx = band_idx > 233 ? band_idx - 2 : 232;
|
||||
|
||||
const pixman_color_t band = color_hex_to_pixman(
|
||||
term->colors.table[band_idx], gamma_correct);
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, &band,
|
||||
1, &(pixman_rectangle16_t){cell_x, y, cell_w, h});
|
||||
|
||||
const uint8_t mask = gradient_fade_masks[i];
|
||||
const pixman_color_t dot = color_hex_to_pixman(
|
||||
term->colors.table[dot_idx], gamma_correct);
|
||||
|
||||
pixman_rectangle16_t dot_rects[8];
|
||||
int n_dots = 0;
|
||||
for (int b = 0; b < 8; b++) {
|
||||
if (!(mask & (1u << b)))
|
||||
continue;
|
||||
const int dx = (int)roundf((gradient_dot_pos[b].col + 0.5f) * sub_w)
|
||||
- dot_size / 2;
|
||||
const int dy = (int)roundf((gradient_dot_pos[b].row + 0.5f) * sub_h)
|
||||
- dot_size / 2;
|
||||
dot_rects[n_dots++] = (pixman_rectangle16_t){
|
||||
cell_x + dx, y + dy, dot_size, dot_size,
|
||||
};
|
||||
}
|
||||
if (n_dots > 0)
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, &dot,
|
||||
n_dots, dot_rects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
render_tab_bar(struct terminal *term)
|
||||
{
|
||||
|
|
@ -5712,11 +5804,15 @@ render_tab_bar(struct terminal *term)
|
|||
|
||||
const bool gamma_correct = wayl_do_linear_blending(win->term->wl, conf);
|
||||
const bool rounded = (conf->tabs.style == CONF_TABS_STYLE_ROUNDED);
|
||||
const bool gradient = (conf->tabs.style == CONF_TABS_STYLE_GRADIENT);
|
||||
const int r = rounded ? (int)roundf(scale * conf->tabs.corner_radius) : 0;
|
||||
|
||||
/* Clear buffer: transparent for floating (shows terminal behind gaps), bg for span */
|
||||
/* Clear buffer: transparent for floating (shows terminal behind gaps), bg for span.
|
||||
* Gradient style overrides the configured bar bg with a fixed greyscale ramp index. */
|
||||
const pixman_color_t transparent = {0, 0, 0, 0};
|
||||
const pixman_color_t bg_color = color_hex_to_pixman(conf->tabs.colors.bg, gamma_correct);
|
||||
const pixman_color_t bg_color = gradient
|
||||
? color_hex_to_pixman(term->colors.table[GRADIENT_BAR_BG_IDX], gamma_correct)
|
||||
: color_hex_to_pixman(conf->tabs.colors.bg, gamma_correct);
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, buf->pix[0],
|
||||
floating ? &transparent : &bg_color,
|
||||
1, &(pixman_rectangle16_t){0, 0, width, total_h});
|
||||
|
|
@ -5809,15 +5905,25 @@ render_tab_bar(struct terminal *term)
|
|||
const int x = tab_xs[i];
|
||||
const int w = tab_ws[i];
|
||||
|
||||
const pixman_color_t tab_bg = color_hex_to_pixman(
|
||||
is_active ? conf->tabs.colors.active_bg : conf->tabs.colors.bg,
|
||||
gamma_correct);
|
||||
const pixman_color_t fg_color = color_hex_to_pixman(
|
||||
is_active ? conf->tabs.colors.active_fg : conf->tabs.colors.fg,
|
||||
gamma_correct);
|
||||
const pixman_color_t fg_color = gradient
|
||||
? color_hex_to_pixman(
|
||||
term->colors.table[is_active
|
||||
? GRADIENT_FG_ACTIVE_IDX : GRADIENT_FG_INACTIVE_IDX],
|
||||
gamma_correct)
|
||||
: color_hex_to_pixman(
|
||||
is_active ? conf->tabs.colors.active_fg : conf->tabs.colors.fg,
|
||||
gamma_correct);
|
||||
|
||||
if (rounded) {
|
||||
if (gradient) {
|
||||
const uint8_t pill_idx = is_active
|
||||
? GRADIENT_PILL_ACTIVE_IDX : GRADIENT_PILL_INACTIVE_IDX;
|
||||
draw_gradient_pill(buf->pix[0], term, pill_idx, GRADIENT_BAR_BG_IDX,
|
||||
gamma_correct, x, tab_y, w, tab_h, scale);
|
||||
} else if (rounded) {
|
||||
/* Floating: all 4 corners rounded. Span: only the open edge rounded. */
|
||||
const pixman_color_t tab_bg = color_hex_to_pixman(
|
||||
is_active ? conf->tabs.colors.active_bg : conf->tabs.colors.bg,
|
||||
gamma_correct);
|
||||
unsigned corners;
|
||||
if (floating) {
|
||||
corners = 0xf; /* all corners */
|
||||
|
|
@ -5828,12 +5934,16 @@ render_tab_bar(struct terminal *term)
|
|||
}
|
||||
draw_rounded_rect(buf->pix[0], &tab_bg, x, tab_y, w, tab_h, r, corners);
|
||||
} else {
|
||||
const pixman_color_t tab_bg = color_hex_to_pixman(
|
||||
is_active ? conf->tabs.colors.active_bg : conf->tabs.colors.bg,
|
||||
gamma_correct);
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, buf->pix[0], &tab_bg,
|
||||
1, &(pixman_rectangle16_t){x, tab_y, w, tab_h});
|
||||
}
|
||||
|
||||
/* Span: separator between inactive tabs */
|
||||
if (!floating && !is_active && i + 1 < n) {
|
||||
/* Span: separator between inactive tabs (skipped for gradient — fades
|
||||
* already provide visual separation) */
|
||||
if (!floating && !is_active && i + 1 < n && !gradient) {
|
||||
const pixman_color_t sep = color_hex_to_pixman(
|
||||
conf->tabs.colors.bg, gamma_correct);
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, buf->pix[0], &sep,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue