diff options
| author | user <user@clank> | 2026-08-16 00:38:17 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-16 00:38:17 +0200 |
| commit | 8079f982bb240d6594b060caee7a5ac6f89e39b3 (patch) | |
| tree | e316fd3504360d1123774eb3a1a35459ef5ce725 /src | |
| parent | sl0ppty: sl0ppty --check (diff) | |
| download | slosh-8079f982bb240d6594b060caee7a5ac6f89e39b3.tar.gz slosh-8079f982bb240d6594b060caee7a5ac6f89e39b3.tar.xz slosh-8079f982bb240d6594b060caee7a5ac6f89e39b3.zip | |
sl0ppty: padding, per side
padding 1 // every side
padding 0 2 // vertical, horizontal
padding 2 0 0 1 // top, right, bottom, left
One value, two, or four in CSS order, because that is the order anybody
who has written a stylesheet already knows. `pad` becomes four fields and
the content rect is deflated per side rather than symmetrically, which is
the only real change: everything downstream already worked off
`n->content`.
The units do not change with how many numbers you write. They are ROWS,
like `gap`, and a horizontal one is multiplied by `gap_aspect` on the way
out -- so `padding 1`, `padding 1 1` and `padding 1 1 1 1` are one padding
rather than three, and a ring that looks square is still one number rather
than an arithmetic problem. Anyone who wants plain cells sets
`gap_aspect 1` and gets them everywhere, which is what that knob is for.
Three values is refused with a line saying what it wanted. CSS reads it as
top/horizontal/bottom, and a line whose meaning you have to look up is a
line nobody can read -- and `sl0ppty --check` now has something to say
about it, which is the difference between refusing and ignoring.
The dump writes the shortest form that means what is in force, so `padding
0` stays `padding 0` and a dump of a dump is still the same dump.
Checked by measuring both rects: a pane's insets from its own frame, four
numbers, for every form -- including that `gap_aspect 1` turns the
horizontal ones into cells, and that a refused padding leaves the rest of
the file applied.
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.c | 22 | ||||
| -rw-r--r-- | src/config.c | 43 | ||||
| -rw-r--r-- | src/config.h | 8 |
3 files changed, 61 insertions, 12 deletions
@@ -1144,15 +1144,21 @@ static void layout_node(node_t *n, rect_t r, layout_ctx_t *ctx) { n->collapsed = false; if (n->kind == NODE_LEAF) n->hidden = false; if (n->kind == NODE_LEAF) { - /* content is the frame deflated by its border and padding; a rect too - * small for a frame gets none, and the pane takes the whole thing. */ - uint16_t bx = r.w >= 3 && r.h >= 3 ? 1 + CFG.pad * CFG.gap_aspect : 0; - uint16_t by = r.w >= 3 && r.h >= 3 ? 1 + CFG.pad : 0; + /* content is the frame deflated by its border and its padding, per side; a + * rect too small for a frame gets neither, and the pane takes the whole + * thing. Horizontal padding is aspect-corrected, like the gap: the config's + * numbers are rows, so a square-looking ring is one number rather than an + * arithmetic problem. */ + bool framed = r.w >= 3 && r.h >= 3; + uint16_t left = framed ? 1 + CFG.pad_left * CFG.gap_aspect : 0; + uint16_t right = framed ? 1 + CFG.pad_right * CFG.gap_aspect : 0; + uint16_t top = framed ? 1 + CFG.pad_top : 0; + uint16_t bottom = framed ? 1 + CFG.pad_bottom : 0; n->content = (rect_t){ - .x = (uint16_t)(r.x + bx), - .y = (uint16_t)(r.y + by), - .w = (uint16_t)(r.w > 2 * bx ? r.w - 2 * bx : 1), - .h = (uint16_t)(r.h > 2 * by ? r.h - 2 * by : 1), + .x = (uint16_t)(r.x + left), + .y = (uint16_t)(r.y + top), + .w = (uint16_t)(r.w > left + right ? r.w - left - right : 1), + .h = (uint16_t)(r.h > top + bottom ? r.h - top - bottom : 1), }; if (ctx->apply && !n->hidden) pane_resize(n->pane, n->content.w, n->content.h); diff --git a/src/config.c b/src/config.c index f01619b..4618eea 100644 --- a/src/config.c +++ b/src/config.c @@ -450,7 +450,7 @@ void config_defaults(config_t *c) { memset(c, 0, sizeof *c); c->gap = 1; c->gap_aspect = 2; - c->pad = 0; + c->pad_top = c->pad_right = c->pad_bottom = c->pad_left = 0; c->rounded = true; c->title_align = ALIGN_CENTER; c->title_inset = 2; @@ -981,7 +981,16 @@ char *config_render(const config_t *c) { cb_add(&b, "gap %u\n", c->gap); cb_add(&b, "gap_aspect %u // columns per row, so a gap looks square\n", c->gap_aspect); - cb_add(&b, "padding %u\n", c->pad); + /* The shortest form that means what is in force, because `padding 0` reads + * better than `padding 0 0 0 0` and round-trips to the same four numbers. */ + if (c->pad_top == c->pad_right && c->pad_top == c->pad_bottom && + c->pad_top == c->pad_left) + cb_add(&b, "padding %u\n", c->pad_top); + else if (c->pad_top == c->pad_bottom && c->pad_right == c->pad_left) + cb_add(&b, "padding %u %u\n", c->pad_top, c->pad_right); + else + cb_add(&b, "padding %u %u %u %u // top right bottom left\n", c->pad_top, + c->pad_right, c->pad_bottom, c->pad_left); cb_add(&b, "rounded %s\n", yesno(c->rounded)); cb_add(&b, "title_align \"%s\"\n", c->title_align == ALIGN_LEFT ? "left" @@ -1287,7 +1296,35 @@ static bool load_into(config_t *c, const char *path, int depth, char *err, c->gap = (uint16_t)kdl_arg_int(kdl_child(root, "gap"), 0, c->gap); c->gap_aspect = (uint16_t)kdl_arg_int(kdl_child(root, "gap_aspect"), 0, c->gap_aspect); - c->pad = (uint16_t)kdl_arg_int(kdl_child(root, "padding"), 0, c->pad); + /* `padding 1`, `padding 0 2`, or `padding 1 2 1 2` -- one value for every + * side, two for vertical and horizontal, four in CSS order (top, right, + * bottom, left), because that is the order everybody who has written a + * stylesheet already knows. Three is refused rather than guessed at: CSS says + * top/horizontal/bottom and a reader who has to look that up is a reader who + * cannot see what the line does. */ + { + const kdl_node_t *pn = kdl_child(root, "padding"); + if (pn) { + long v[4]; + size_t n = pn->nargs < 4 ? pn->nargs : 4; + for (size_t i = 0; i < n; i++) v[i] = kdl_arg_int(pn, i, 0); + if (pn->nargs == 1) { + c->pad_top = c->pad_right = c->pad_bottom = c->pad_left = (uint16_t)v[0]; + } else if (pn->nargs == 2) { + c->pad_top = c->pad_bottom = (uint16_t)v[0]; + c->pad_right = c->pad_left = (uint16_t)v[1]; + } else if (pn->nargs == 4) { + c->pad_top = (uint16_t)v[0]; + c->pad_right = (uint16_t)v[1]; + c->pad_bottom = (uint16_t)v[2]; + c->pad_left = (uint16_t)v[3]; + } else { + complain(c, err, errcap, pn->line, + "padding takes 1, 2 or 4 values (all, vertical horizontal, or " + "top right bottom left), not %zu", pn->nargs); + } + } + } c->rounded = kdl_arg_bool(kdl_child(root, "rounded"), 0, c->rounded); c->status_bar = kdl_arg_bool(kdl_child(root, "status_bar"), 0, c->status_bar); c->status_line = diff --git a/src/config.h b/src/config.h index e8c7f98..c0f8e2b 100644 --- a/src/config.h +++ b/src/config.h @@ -102,7 +102,13 @@ typedef enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } align_t; typedef struct { /* geometry */ - uint16_t gap, gap_aspect, pad; + uint16_t gap, gap_aspect; + /* Space between a pane's frame and its contents, per side, in the same unit + * `gap` uses: ROWS. A horizontal one is multiplied by `gap_aspect` on the way + * out, so `padding 1` is a square-looking ring rather than a squashed one — + * and so a number means the same thing wherever it appears, however many of + * them were written. Written as 1, 2 or 4 values, CSS order. */ + uint16_t pad_top, pad_right, pad_bottom, pad_left; bool rounded; align_t title_align; /* Cells between a frame's corner and the start of its title. The title |
