Add an "absolute-centre" alignment to use the centre of the total space
authornicm <nicm@openbsd.org>
Thu, 11 Mar 2021 06:41:04 +0000 (06:41 +0000)
committernicm <nicm@openbsd.org>
Thu, 11 Mar 2021 06:41:04 +0000 (06:41 +0000)
instead of only the available space. From Magnus Gross in GitHub issue 2578.

usr.bin/tmux/format-draw.c
usr.bin/tmux/options-table.c
usr.bin/tmux/style.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h

index 9f538e8..b921fc9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format-draw.c,v 1.22 2020/12/01 08:12:58 nicm Exp $ */
+/* $OpenBSD: format-draw.c,v 1.23 2021/03/11 06:41:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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;
        }
 
index eac3cb5..3330e4f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: options-table.c,v 1.139 2021/02/01 08:01:14 nicm Exp $ */
+/* $OpenBSD: options-table.c,v 1.140 2021/03/11 06:41:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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
index 9ff3ed4..a0a34c0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: style.c,v 1.28 2020/05/16 16:02:24 nicm Exp $ */
+/* $OpenBSD: style.c,v 1.29 2021/03/11 06:41:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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 = ",";
index f4b30ea..3817d0d 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.828 2021/03/11 06:31:05 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.829 2021/03/11 06:41:04 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -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
index c42b52f..7458571 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1097 2021/03/11 06:31:05 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1098 2021/03/11 06:41:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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. */