Add two new style parameters, width and pad, which apply to scrollbars.

From Michael Grant, GitHub issue 4241.
This commit is contained in:
nicm 2024-11-15 13:12:20 +00:00
parent d6883c0266
commit 350a151ee4
9 changed files with 166 additions and 61 deletions

View File

@ -291,7 +291,7 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
{
struct window_pane *wp;
struct layout_cell *lc;
int status, scrollbars, sb_pos;
int status, scrollbars, sb_pos, sb_w, sb_pad;
u_int sx, sy;
status = options_get_number(w->options, "pane-border-status");
@ -314,11 +314,26 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
}
if (window_pane_show_scrollbar(wp, scrollbars)) {
sb_w = wp->scrollbar_style.width;
sb_pad = wp->scrollbar_style.pad;
if (sb_w < 1)
sb_w = 1;
if (sb_pad < 0)
sb_pad = 0;
if (sb_pos == PANE_SCROLLBARS_LEFT) {
sx = sx - PANE_SCROLLBARS_WIDTH;
wp->xoff = wp->xoff + PANE_SCROLLBARS_WIDTH;
if ((int)sx - sb_w < PANE_MINIMUM) {
wp->xoff = wp->xoff +
(int)sx - PANE_MINIMUM;
sx = PANE_MINIMUM;
} else {
sx = sx - sb_w - sb_pad;
wp->xoff = wp->xoff + sb_w + sb_pad;
}
} else /* sb_pos == PANE_SCROLLBARS_RIGHT */
sx = sx - PANE_SCROLLBARS_WIDTH;
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
sx = PANE_MINIMUM;
else
sx = sx - sb_w - sb_pad;
wp->flags |= PANE_REDRAWSCROLLBAR;
}
@ -353,6 +368,7 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
enum layout_type type)
{
struct layout_cell *lcchild;
struct style *sb_style = &w->active->scrollbar_style;
u_int available, minimum;
int status, scrollbars;
@ -364,7 +380,8 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
if (type == LAYOUT_LEFTRIGHT) {
available = lc->sx;
if (scrollbars)
minimum = PANE_MINIMUM + PANE_SCROLLBARS_WIDTH;
minimum = PANE_MINIMUM + sb_style->width +
sb_style->pad;
else
minimum = PANE_MINIMUM;
} else {
@ -891,11 +908,12 @@ struct layout_cell *
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
int flags)
{
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
u_int sx, sy, xoff, yoff, size1, size2, minimum;
u_int new_size, saved_size, resize_first = 0;
int full_size = (flags & SPAWN_FULLSIZE), status;
int scrollbars;
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
struct style *sb_style = &wp->scrollbar_style;
u_int sx, sy, xoff, yoff, size1, size2, minimum;
u_int new_size, saved_size, resize_first = 0;
int full_size = (flags & SPAWN_FULLSIZE), status;
int scrollbars;
/*
* If full_size is specified, add a new cell at the top of the window
@ -917,9 +935,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
/* Check there is enough space for the two new panes. */
switch (type) {
case LAYOUT_LEFTRIGHT:
if (scrollbars)
minimum = PANE_MINIMUM * 2 + PANE_SCROLLBARS_WIDTH;
else
if (scrollbars) {
minimum = PANE_MINIMUM * 2 + sb_style->width +
sb_style->pad;
} else
minimum = PANE_MINIMUM * 2 + 1;
if (sx < minimum)
return (NULL);
@ -1081,6 +1100,7 @@ int
layout_spread_cell(struct window *w, struct layout_cell *parent)
{
struct layout_cell *lc;
struct style *sb_style = &w->active->scrollbar_style;
u_int number, each, size, this;
int change, changed, status, scrollbars;
@ -1094,7 +1114,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
if (parent->type == LAYOUT_LEFTRIGHT) {
if (scrollbars)
size = parent->sx - PANE_SCROLLBARS_WIDTH;
size = parent->sx - sb_style->width + sb_style->pad;
else
size = parent->sx;
}

View File

@ -1187,7 +1187,7 @@ const struct options_table_entry options_table[] = {
{ .name = "pane-scrollbars-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "bg=black,fg=white",
.default_str = "bg=black,fg=white,width=1,pad=0",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the pane scrollbar."

View File

@ -1177,6 +1177,15 @@ options_push_changes(const char *name)
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, NULL);
}
if (strcmp(name, "pane-scrollbars-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
style_set_scrollbar_style_from_option(
&wp->scrollbar_style, wp->options);
}
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, NULL);
}
if (strcmp(name, "input-buffer-size") == 0)
input_set_buffer_size(options_get_number(global_options, name));
RB_FOREACH(s, sessions, &sessions)

View File

@ -138,7 +138,7 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
/* Are scrollbars enabled? */
if (window_pane_show_scrollbar(wp, pane_scrollbars))
sb_w = PANE_SCROLLBARS_WIDTH;
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
/*
* Left/right borders. The wp->sy / 2 test is to colour only half the
@ -171,7 +171,7 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
} else {
if (sb_pos == PANE_SCROLLBARS_LEFT) {
if ((wp->xoff - sb_w == 0 || px >= wp->xoff - sb_w) &&
(px <= ex || (sb_w != 0 && px - 1 == ex))) {
(px <= ex || (sb_w != 0 && px < ex + sb_w))) {
if (wp->yoff != 0 && py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER_TOP);
if (py == ey)
@ -179,7 +179,7 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
}
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
if ((wp->xoff == 0 || px >= wp->xoff) &&
(px <= ex || (sb_w != 0 && px - 1 == ex))) {
(px <= ex || (sb_w != 0 && px < ex + sb_w))) {
if (wp->yoff != 0 && py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER_TOP);
if (py == ey)
@ -324,7 +324,7 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
int border, pane_scrollbars = ctx->pane_scrollbars;
u_int right, line;
int sb_pos = ctx->pane_scrollbars_pos;
int sb_w = PANE_SCROLLBARS_WIDTH;
int sb_w;
*wpp = NULL;
@ -374,6 +374,8 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
* pane is at the top then py == 0 to sy; if the pane
* is not at the top, then yoff to yoff + sy.
*/
sb_w = wp->scrollbar_style.width +
wp->scrollbar_style.pad;
if ((pane_status && py != line) ||
(wp->yoff == 0 && py < wp->sy) ||
(py >= wp->yoff && py < wp->yoff + wp->sy)) {
@ -944,7 +946,9 @@ screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx,
double percent_view;
u_int sb = ctx->pane_scrollbars, total_height, sb_h = wp->sy;
u_int sb_pos = ctx->pane_scrollbars_pos, slider_h, slider_y;
u_int sb_w = PANE_SCROLLBARS_WIDTH, cm_y, cm_size;
int sb_w = wp->scrollbar_style.width;
int sb_pad = wp->scrollbar_style.pad;
int cm_y, cm_size, xoff = wp->xoff, ox = ctx->ox;
int sb_x, sb_y = (int)(wp->yoff - ctx->oy); /* sb top */
if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) {
@ -967,9 +971,9 @@ screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx,
}
if (sb_pos == PANE_SCROLLBARS_LEFT)
sb_x = (int)wp->xoff - sb_w - ctx->ox;
sb_x = xoff - sb_w - sb_pad - ox;
else
sb_x = (int)wp->xoff + wp->sx - ctx->ox;
sb_x = xoff + wp->sx - ox;
if (slider_h < 1)
slider_h = 1;
@ -990,39 +994,42 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
u_int slider_h, u_int slider_y)
{
struct client *c = ctx->c;
struct window *w = wp->window;
struct tty *tty = &c->tty;
struct grid_cell gc, slgc, *gcp;
u_int i, j, sb_w = PANE_SCROLLBARS_WIDTH;
u_int pad_col = 0;
struct style *sb_style = &wp->scrollbar_style;
u_int i, j, imax, jmax;
u_int sb_w = sb_style->width, sb_pad = sb_style->pad;
int px, py, ox = ctx->ox, oy = ctx->oy;
int sb_pad = PANE_SCROLLBARS_PADDING, sx = ctx->sx;
int sy = ctx->sy, xoff = wp->xoff, yoff = wp->yoff;
/* Set up default style. */
style_apply(&gc, w->options, "pane-scrollbars-style", NULL);
utf8_set(&gc.data, ' ');
int sx = ctx->sx, sy = ctx->sy, xoff = wp->xoff;
int yoff = wp->yoff;
/* Set up style for slider. */
gc = sb_style->gc;
memcpy(&slgc, &gc, sizeof slgc);
slgc.fg = gc.bg;
slgc.bg = gc.fg;
if (sb_pad != 0) {
if (sb_pos == PANE_SCROLLBARS_RIGHT)
pad_col = 0;
else
pad_col = sb_w - 1;
}
imax = sb_w + sb_pad;
if ((int)imax + sb_x > sx)
imax = sx - sb_x;
jmax = sb_h;
if ((int)jmax + sb_y > sy)
jmax = sy - sb_y;
for (i = 0; i < sb_w; i++) {
for (j = 0; j < sb_h; j++) {
for (j = 0; j < jmax; j++) {
py = sb_y + j;
for (i = 0; i < imax; i++) {
px = sb_x + i;
py = sb_y + j;
if (px < xoff - ox - 1 || px >= sx || px < 0 ||
py < yoff - oy - 1 || py >= sy || py < 0)
if (px < xoff - ox - (int)sb_w - (int)sb_pad ||
px >= sx || px < 0 ||
py < yoff - oy - 1 ||
py >= sy || py < 0)
continue;
tty_cursor(tty, px, py);
if (sb_pad && i == pad_col) {
if ((sb_pos == PANE_SCROLLBARS_LEFT &&
i >= sb_w && i < sb_w + sb_pad) ||
(sb_pos == PANE_SCROLLBARS_RIGHT &&
i < sb_pad)) {
tty_cell(tty, &grid_default_cell,
&grid_default_cell, NULL, NULL);
} else {

View File

@ -581,7 +581,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
struct window_pane *wp, *fwp;
u_int x, y, b, sx, sy, px, py, line = 0, sb_pos;
u_int sl_top, sl_bottom, sl_mpos = 0;
int ignore = 0, sb, sb_w, pane_status;
int ignore = 0, sb, sb_w, sb_pad, pane_status;
key_code key;
struct timeval tv;
struct style_range *sr;
@ -783,10 +783,15 @@ have_event:
/* Try the scrollbar next to a pane. */
sb = options_get_number(wo, "pane-scrollbars");
if (window_pane_show_scrollbar(wp, sb))
sb_w = PANE_SCROLLBARS_WIDTH;
else
sb_pos = options_get_number(wo,
"pane-scrollbars-position");
if (window_pane_show_scrollbar(wp, sb)) {
sb_w = wp->scrollbar_style.width;
sb_pad = wp->scrollbar_style.pad;
} else {
sb_w = 0;
sb_pad = 0;
}
pane_status = options_get_number(wo,
"pane-border-status");
if (pane_status == PANE_STATUS_TOP)
@ -795,8 +800,9 @@ have_event:
line = wp->yoff + wp->sy;
/*
* Check if py could lie within a scrollbar. If the
* pane is at the top, then py is 0; if not then the
* Check if py could lie within a scrollbar
* (but not within the padding). If the pane is
* at the top, then py is 0; if not then the
* top, then yoff to yoff + sy.
*/
if ((pane_status != PANE_STATUS_OFF && py != line) ||
@ -805,11 +811,11 @@ have_event:
sb_pos = options_get_number(wo,
"pane-scrollbars-position");
if ((sb_pos == PANE_SCROLLBARS_RIGHT &&
(px >= wp->xoff + wp->sx &&
px < wp->xoff + wp->sx + sb_w)) ||
(px >= wp->xoff + wp->sx + sb_pad &&
px < wp->xoff + wp->sx + sb_pad + sb_w)) ||
(sb_pos == PANE_SCROLLBARS_LEFT &&
(px >= wp->xoff - sb_w &&
px < wp->xoff))) {
(px >= wp->xoff - sb_pad - sb_w &&
px < wp->xoff - sb_pad))) {
sl_top = wp->yoff + wp->sb_slider_y;
sl_bottom = (wp->yoff +
wp->sb_slider_y +

44
style.c
View File

@ -39,6 +39,8 @@ static struct style style_default = {
STYLE_RANGE_NONE, 0, "",
STYLE_WIDTH_DEFAULT, STYLE_PAD_DEFAULT,
STYLE_DEFAULT_BASE
};
@ -216,6 +218,16 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
if ((value = attributes_fromstring(tmp + 2)) == -1)
goto error;
sy->gc.attr &= ~value;
} else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) {
n = strtonum(tmp + 6, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->width = (int)n;
} else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) {
n = strtonum(tmp + 4, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->pad = (int)n;
} else {
if ((value = attributes_fromstring(tmp)) == -1)
goto error;
@ -326,7 +338,16 @@ style_tostring(struct style *sy)
attributes_tostring(gc->attr));
comma = ",";
}
if (sy->width >= 0) {
xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma,
sy->width);
comma = ",";
}
if (sy->pad >= 0) {
xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
sy->pad);
comma = ",";
}
if (*s == '\0')
return ("default");
return (s);
@ -381,3 +402,24 @@ style_copy(struct style *dst, struct style *src)
{
memcpy(dst, src, sizeof *dst);
}
void
style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo)
{
struct style *sy;
sy = options_string_to_style(oo, "pane-scrollbars-style", NULL);
if (sy == NULL) {
style_set(sb_style, &grid_default_cell);
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
} else {
style_copy(sb_style, sy);
if (sb_style->width < 1)
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
if (sb_style->pad < 0)
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
}
}

7
tmux.1
View File

@ -5071,7 +5071,12 @@ see the
section.
The foreground colour is used for the slider, the background for the rest of the
scrollbar.
Attributes are ignored.
The
.Ar width
attribute sets the width of the scrollbar and the
.Ar pad
attribute the padding between the scrollbar and the pane.
Other attributes are ignored.
.Pp
.It Xo Ic pane-scrollbars-position
.Op Ic left | right

18
tmux.h
View File

@ -863,6 +863,10 @@ struct style_range {
};
TAILQ_HEAD(style_ranges, style_range);
/* Default style width and pad. */
#define STYLE_WIDTH_DEFAULT -1
#define STYLE_PAD_DEFAULT -1
/* Style default. */
enum style_default_type {
STYLE_DEFAULT_BASE,
@ -883,6 +887,9 @@ struct style {
u_int range_argument;
char range_string[16];
int width;
int pad;
enum style_default_type default_type;
};
@ -1164,6 +1171,8 @@ struct window_pane {
int control_bg;
int control_fg;
struct style scrollbar_style;
TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */
TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */
RB_ENTRY(window_pane) tree_entry;
@ -1268,9 +1277,10 @@ TAILQ_HEAD(winlink_stack, winlink);
#define PANE_SCROLLBARS_RIGHT 0
#define PANE_SCROLLBARS_LEFT 1
/* Pane scrollbars width and padding. */
#define PANE_SCROLLBARS_WIDTH 1
#define PANE_SCROLLBARS_PADDING 0
/* Pane scrollbars width, padding and fill character. */
#define PANE_SCROLLBARS_DEFAULT_PADDING 0
#define PANE_SCROLLBARS_DEFAULT_WIDTH 1
#define PANE_SCROLLBARS_CHARACTER ' '
/* True if screen in alternate screen. */
#define SCREEN_IS_ALTERNATE(s) ((s)->saved_grid != NULL)
@ -3469,6 +3479,8 @@ void style_apply(struct grid_cell *, struct options *,
const char *, struct format_tree *);
void style_set(struct style *, const struct grid_cell *);
void style_copy(struct style *, struct style *);
void style_set_scrollbar_style_from_option(struct style *,
struct options *);
/* spawn.c */
struct winlink *spawn_window(struct spawn_context *, char **);

View File

@ -596,9 +596,10 @@ window_get_active_at(struct window *w, u_int x, u_int y)
if (pane_scrollbars == PANE_SCROLLBARS_ALWAYS ||
(pane_scrollbars == PANE_SCROLLBARS_MODAL &&
window_pane_mode(wp) != WINDOW_PANE_NO_MODE))
sb_w = PANE_SCROLLBARS_WIDTH;
else
window_pane_mode(wp) != WINDOW_PANE_NO_MODE)) {
sb_w = wp->scrollbar_style.width +
wp->scrollbar_style.pad;
} else
sb_w = 0;
if (sb_pos == PANE_SCROLLBARS_LEFT) {
@ -961,6 +962,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->control_bg = -1;
wp->control_fg = -1;
style_set_scrollbar_style_from_option(&wp->scrollbar_style,
wp->options);
colour_palette_init(&wp->palette);
colour_palette_from_option(&wp->palette, wp->options);