diff options
| author | Peter Geissler <peter@haxx.in> | 2026-09-20 19:40:05 +0200 |
|---|---|---|
| committer | Peter Geissler <peter@haxx.in> | 2026-09-20 19:40:05 +0200 |
| commit | 6c8d99cd71858955c0e9c9d93d738c855e652ce8 (patch) | |
| tree | a02b83f33773df0119a669ba697dfeefe3971a29 /src | |
| parent | tests: a pane's status is output, so write the pty, not the input decoder (diff) | |
| download | slosh-6c8d99cd71858955c0e9c9d93d738c855e652ce8.tar.gz slosh-6c8d99cd71858955c0e9c9d93d738c855e652ce8.tar.xz slosh-6c8d99cd71858955c0e9c9d93d738c855e652ce8.zip | |
tabs: air before the new-tab button, and the option to do without it
The `+` is the one entry in the strip that does not mean "go here", and it
sits at the end of a list where every other entry does. Flush against them it
is what you hit when you meant the last tab -- most easily in a sidebar, where
the target is the full width of the row and the pointer only has to be one row
low. newtab_pad is the nothing in between: blank rows in a sidebar, blank
columns on top, one by default, which is enough to make the slip a miss.
It is paint rather than layout, like tab_bar_pad: the panes' rectangle is the
same at 0 as at 5, so tuning it repaints without reflowing anyone. And it is
given up before the button is -- a strip short of room drops the spacing one
cell at a time and still draws what the spacing was protecting, because
spacing must never cost you the thing it spaces.
newtab_button false removes the button outright, for people who make tabs from
the keyboard and would rather have the row (or the columns) back. Only the
place to click it goes: the chord and the palette entry still work. Setting
newtab_mark "" already did this by omission; this says it on purpose, and says
it in --dump-config.
Diffstat (limited to 'src')
| -rw-r--r-- | src/app_draw.c | 23 | ||||
| -rw-r--r-- | src/config.c | 20 |
2 files changed, 38 insertions, 5 deletions
diff --git a/src/app_draw.c b/src/app_draw.c index 3b329bf..1dabf98 100644 --- a/src/app_draw.c +++ b/src/app_draw.c @@ -1987,10 +1987,15 @@ void draw_tab_strip(app_t *a, screen_t *s) { for (size_t i = 0; i < a->ntabs && x < right; i++) x = (uint16_t)(x + draw_tab_cell(a, s, i, x, y, 0, dragging_pane)); - { + if (CFG.newtab_button) { uint16_t bw = (uint16_t)(cells(CFG.newtab_mark) + 2); - if (bw > 2 && x + bw <= right) - draw_newtab_button(a, s, x, y, 0, dragging_pane); + /* The air before the button, in the axis this strip runs along. Given up + * before the button is, the same rule the sidebar's frame follows: + * spacing must not be what costs you the thing it is spacing. */ + uint16_t pad = CFG.newtab_pad; + while (pad && x + pad + bw > right) pad--; + if (bw > 2 && x + pad + bw <= right) + draw_newtab_button(a, s, (uint16_t)(x + pad), y, 0, dragging_pane); } } @@ -2158,8 +2163,16 @@ void draw_tab_sidebar(app_t *a, screen_t *s) { } } - if (cells(CFG.newtab_mark) && y < limit) - draw_newtab_button(a, s, cx, y, cw, dragging_pane); + if (CFG.newtab_button && cells(CFG.newtab_mark)) { + /* Blank rows between the list and the button. A sidebar tab is a target + * the full width of the strip, so the row under the last one is one slip + * of the pointer away from it -- air is what makes that slip a miss. + * Shrunk to fit rather than pushing the button off the bottom. */ + uint16_t pad = CFG.newtab_pad; + while (pad && (uint16_t)(y + pad) >= limit) pad--; + y = (uint16_t)(y + pad); + if (y < limit) draw_newtab_button(a, s, cx, y, cw, dragging_pane); + } } /* The space between two of a split's children, or false if they are flush. diff --git a/src/config.c b/src/config.c index 7166208..7c428f7 100644 --- a/src/config.c +++ b/src/config.c @@ -887,6 +887,14 @@ void config_defaults(config_t *c) { snprintf(c->close_mark, sizeof c->close_mark, "\u2715"); /* ✕ close */ snprintf(c->min_mark, sizeof c->min_mark, "\u25ac"); /* ▬ into the strip */ snprintf(c->newtab_mark, sizeof c->newtab_mark, "+"); + c->newtab_button = true; + /* One cell of nothing between the last tab and the button. The tabs are a + * list where every row (or column) does one thing and the button does a + * different one, and flush against the list it is the thing you hit when + * you meant the tab above it -- most often in a sidebar, where the target + * is a whole row and the pointer only has to be one row low. One is enough + * to make the miss a miss rather than a new tab. */ + c->newtab_pad = 1; c->bell_indicator = true; snprintf(c->bell_mark, sizeof c->bell_mark, "[!]"); c->keep_dead = KEEP_DEAD_COMMANDS; @@ -1691,6 +1699,12 @@ char *config_render(const config_t *c) { cb_qstr(&b, "close_mark", c->close_mark, NULL); cb_qstr(&b, "min_mark", c->min_mark, NULL); cb_qstr(&b, "newtab_mark", c->newtab_mark, NULL); + cb_add(&b, "newtab_button %s // the + at the end of the tab strip\n", + yesno(c->newtab_button)); + cb_add(&b, + "newtab_pad %u // air before it: rows in a sidebar, " + "columns on top\n", + c->newtab_pad); cb_qstr(&b, "bell_mark", c->bell_mark, NULL); cb_add(&b, "\n// ---- behaviour ----\n"); @@ -1964,7 +1978,9 @@ static const char *const KNOWN_TOP[] = { "multi_attach", "min_split", "modal_scrim", + "newtab_button", "newtab_mark", + "newtab_pad", "padding", "pane_buttons", "project_layout", @@ -2258,6 +2274,10 @@ static bool load_into(config_t *c, const char *path, int depth, char *err, if (mm) set_mark(c->min_mark, sizeof c->min_mark, mm); const char *nt = kdl_arg(kdl_child(root, "newtab_mark"), 0, NULL); if (nt) set_mark(c->newtab_mark, sizeof c->newtab_mark, nt); + c->newtab_button = + kdl_arg_bool(kdl_child(root, "newtab_button"), 0, c->newtab_button); + c->newtab_pad = + (uint16_t)kdl_arg_int(kdl_child(root, "newtab_pad"), 0, c->newtab_pad); { /* `commands` (the default), `all`, or `none`. `true`/`false` are taken as * `all`/`none`, because that is what they used to mean here and a config |
