From 3eb91efba160eff0b077a5fee902edb632f7fdca Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 11 Mar 2021 06:41:04 +0000 Subject: [PATCH] Add an "absolute-centre" alignment to use the centre of the total space instead of only the available space. From Magnus Gross in GitHub issue 2578. --- format-draw.c | 214 ++++++++++++++++++++++++++++++++++++++++++------ options-table.c | 2 +- style.c | 4 + tmux.1 | 7 +- tmux.h | 3 +- 5 files changed, 199 insertions(+), 31 deletions(-) diff --git a/format-draw.c b/format-draw.c index 67b961d9..cf0bdf5f 100644 --- a/format-draw.c +++ b/format-draw.c @@ -157,13 +157,14 @@ format_draw_put_list(struct screen_write_ctx *octx, static void format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct format_ranges *frs) + struct screen *abs_centre, struct format_ranges *frs) { - u_int width_left, width_centre, width_right; + u_int width_left, width_centre, width_right, width_abs_centre; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; /* * Try to keep as much of the left and right as possible at the expense @@ -199,23 +200,34 @@ format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx, - width_centre / 2, centre->cx / 2 - width_centre / 2, width_centre); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); } /* Draw format with list on the left. */ static void format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct screen *list, struct screen *list_left, struct screen *list_right, - struct screen *after, int focus_start, int focus_end, - struct format_ranges *frs) + struct screen *abs_centre, struct screen *list, struct screen *list_left, + struct screen *list_right, struct screen *after, int focus_start, + int focus_end, struct format_ranges *frs) { u_int width_left, width_centre, width_right; - u_int width_list, width_after; + u_int width_list, width_after, width_abs_centre; struct screen_write_ctx ctx; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; width_list = list->cx; width_after = after->cx; @@ -247,7 +259,7 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, screen_write_stop(&ctx); format_draw_none(octx, available, ocx, ocy, left, centre, - right, frs); + right, abs_centre, frs); return; } @@ -291,23 +303,34 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, focus_start = focus_end = 0; format_draw_put_list(octx, ocx, ocy, width_left, width_list, list, list_left, list_right, focus_start, focus_end, frs); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); } /* Draw format with list in the centre. */ static void format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct screen *list, struct screen *list_left, struct screen *list_right, - struct screen *after, int focus_start, int focus_end, - struct format_ranges *frs) + struct screen *abs_centre, struct screen *list, struct screen *list_left, + struct screen *list_right, struct screen *after, int focus_start, + int focus_end, struct format_ranges *frs) { - u_int width_left, width_centre, width_right; - u_int width_list, width_after, middle; + u_int width_left, width_centre, width_right, middle; + u_int width_list, width_after, width_abs_centre; struct screen_write_ctx ctx; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; width_list = list->cx; width_after = after->cx; @@ -339,7 +362,7 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, screen_write_stop(&ctx); format_draw_none(octx, available, ocx, ocy, left, centre, - right, frs); + right, abs_centre, frs); return; } @@ -388,23 +411,34 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_put_list(octx, ocx, ocy, middle - width_list / 2, width_list, list, list_left, list_right, focus_start, focus_end, frs); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); } /* Draw format with list on the right. */ static void format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, u_int ocy, struct screen *left, struct screen *centre, struct screen *right, - struct screen *list, struct screen *list_left, struct screen *list_right, - struct screen *after, int focus_start, int focus_end, - struct format_ranges *frs) + struct screen *abs_centre, struct screen *list, + struct screen *list_left, struct screen *list_right, struct screen *after, + int focus_start, int focus_end, struct format_ranges *frs) { u_int width_left, width_centre, width_right; - u_int width_list, width_after; + u_int width_list, width_after, width_abs_centre; struct screen_write_ctx ctx; width_left = left->cx; width_centre = centre->cx; width_right = right->cx; + width_abs_centre = abs_centre->cx; width_list = list->cx; width_after = after->cx; @@ -436,7 +470,7 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, screen_write_stop(&ctx); format_draw_none(octx, available, ocx, ocy, left, centre, - right, frs); + right, abs_centre, frs); return; } @@ -484,6 +518,118 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_put_list(octx, ocx, ocy, available - width_list - width_after, width_list, list, list_left, list_right, focus_start, focus_end, frs); + + /* + * Write abs_centre in the perfect centre of all horizontal space. + */ + if (width_abs_centre > available) + width_abs_centre = available; + format_draw_put(octx, ocx, ocy, abs_centre, frs, + (available - width_abs_centre) / 2, + 0, + width_abs_centre); +} + +static void +format_draw_absolute_centre(struct screen_write_ctx *octx, u_int available, + u_int ocx, u_int ocy, struct screen *left, struct screen *centre, + struct screen *right, struct screen *abs_centre, struct screen *list, + struct screen *list_left, struct screen *list_right, struct screen *after, + int focus_start, int focus_end, struct format_ranges *frs) +{ + u_int width_left, width_centre, width_right, width_abs_centre; + u_int width_list, width_after, middle, abs_centre_offset; + + width_left = left->cx; + width_centre = centre->cx; + width_right = right->cx; + width_abs_centre = abs_centre->cx; + width_list = list->cx; + width_after = after->cx; + + /* + * Trim first centre, then the right, then the left. + */ + while (width_left + + width_centre + + width_right > available) { + if (width_centre > 0) + width_centre--; + else if (width_right > 0) + width_right--; + else + width_left--; + } + + /* + * We trim list after and abs_centre independently, as we are drawing + * them over the rest. Trim first the list, then after the list, then + * abs_centre. + */ + while (width_list + width_after + width_abs_centre > available) { + if (width_list > 0) + width_list--; + else if (width_after > 0) + width_after--; + else + width_abs_centre--; + } + + /* Write left at 0. */ + format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left); + + /* Write right at available - width_right. */ + format_draw_put(octx, ocx, ocy, right, frs, + available - width_right, + right->cx - width_right, + width_right); + + /* + * Keep writing centre at the relative centre. Only the list is written + * in the absolute centre of the horizontal space. + */ + middle = (width_left + ((available - width_right) - width_left) / 2); + + /* + * Write centre at + * middle - width_centre. + */ + format_draw_put(octx, ocx, ocy, centre, frs, + middle - width_centre, + 0, + width_centre); + + /* + * If there is no focus given, keep the centre in focus. + */ + if (focus_start == -1 || focus_end == -1) + focus_start = focus_end = list->cx / 2; + + /* + * We centre abs_centre and the list together, so their shared centre is + * in the perfect centre of horizontal space. + */ + abs_centre_offset = (available - width_list - width_abs_centre) / 2; + + /* + * Write abs_centre before the list. + */ + format_draw_put(octx, ocx, ocy, abs_centre, frs, abs_centre_offset, + 0, width_abs_centre); + abs_centre_offset += width_abs_centre; + + /* + * Draw the list in the absolute centre + */ + format_draw_put_list(octx, ocx, ocy, abs_centre_offset, width_list, + list, list_left, list_right, focus_start, focus_end, frs); + abs_centre_offset += width_list; + + /* + * Write after at the end of the centre + */ + format_draw_put(octx, ocx, ocy, after, frs, abs_centre_offset, 0, + width_after); } /* Draw multiple characters. */ @@ -506,6 +652,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, enum { LEFT, CENTRE, RIGHT, + ABSOLUTE_CENTRE, LIST, LIST_LEFT, LIST_RIGHT, @@ -514,6 +661,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, const char *names[] = { "LEFT", "CENTRE", "RIGHT", + "ABSOLUTE_CENTRE", "LIST", "LIST_LEFT", "LIST_RIGHT", @@ -522,7 +670,11 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, struct screen *os = octx->s, s[TOTAL]; struct screen_write_ctx ctx[TOTAL]; u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL]; - u_int map[] = { LEFT, LEFT, CENTRE, RIGHT }; + u_int map[] = { LEFT, + LEFT, + CENTRE, + RIGHT, + ABSOLUTE_CENTRE }; int focus_start = -1, focus_end = -1; int list_state = -1, fill = -1, even; enum style_align list_align = STYLE_ALIGN_DEFAULT; @@ -789,25 +941,35 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, case STYLE_ALIGN_DEFAULT: /* No list. */ format_draw_none(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &frs); break; case STYLE_ALIGN_LEFT: /* List is part of the left. */ format_draw_left(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT], - &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); break; case STYLE_ALIGN_CENTRE: /* List is part of the centre. */ format_draw_centre(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT], - &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); break; case STYLE_ALIGN_RIGHT: /* List is part of the right. */ format_draw_right(octx, available, ocx, ocy, &s[LEFT], - &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT], - &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs); + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); + break; + case STYLE_ALIGN_ABSOLUTE_CENTRE: + /* List is in the centre of the entire horizontal space. */ + format_draw_absolute_centre(octx, available, ocx, ocy, &s[LEFT], + &s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], + &s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], + focus_start, focus_end, &frs); break; } diff --git a/options-table.c b/options-table.c index 9fc69db5..8ea56918 100644 --- a/options-table.c +++ b/options-table.c @@ -46,7 +46,7 @@ static const char *options_table_status_keys_list[] = { "emacs", "vi", NULL }; static const char *options_table_status_justify_list[] = { - "left", "centre", "right", NULL + "left", "centre", "right", "absolute-centre", NULL }; static const char *options_table_status_position_list[] = { "top", "bottom", NULL diff --git a/style.c b/style.c index 08614f9c..24b09882 100644 --- a/style.c +++ b/style.c @@ -139,6 +139,8 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->align = STYLE_ALIGN_CENTRE; else if (strcasecmp(tmp + 6, "right") == 0) sy->align = STYLE_ALIGN_RIGHT; + else if (strcasecmp(tmp + 6, "absolute-centre") == 0) + sy->align = STYLE_ALIGN_ABSOLUTE_CENTRE; else goto error; } else if (end > 5 && strncasecmp(tmp, "fill=", 5) == 0) { @@ -227,6 +229,8 @@ style_tostring(struct style *sy) tmp = "centre"; else if (sy->align == STYLE_ALIGN_RIGHT) tmp = "right"; + else if (sy->align == STYLE_ALIGN_ABSOLUTE_CENTRE) + tmp = "absolute-centre"; off += xsnprintf(s + off, sizeof s - off, "%salign=%s", comma, tmp); comma = ","; diff --git a/tmux.1 b/tmux.1 index da3c0e42..5c516fdb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3815,10 +3815,11 @@ seconds. By default, updates will occur every 15 seconds. A setting of zero disables redrawing at interval. .It Xo Ic status-justify -.Op Ic left | centre | right +.Op Ic left | centre | right | absolute-centre .Xc -Set the position of the window list component of the status line: left, centre -or right justified. +Set the position of the window list in the status line: left, centre or right. +centre puts the window list in the relative centre of the available free space; +absolute-centre uses the centre of the entire horizontal space. .It Xo Ic status-keys .Op Ic vi | emacs .Xc diff --git a/tmux.h b/tmux.h index 3a75e678..e8d2e8c3 100644 --- a/tmux.h +++ b/tmux.h @@ -740,7 +740,8 @@ enum style_align { STYLE_ALIGN_DEFAULT, STYLE_ALIGN_LEFT, STYLE_ALIGN_CENTRE, - STYLE_ALIGN_RIGHT + STYLE_ALIGN_RIGHT, + STYLE_ALIGN_ABSOLUTE_CENTRE }; /* Style list. */