]> git.mdlowis.com Git - proto/labwc.git/commitdiff
theme: add button padding and spacing (#2127)
authorJens Peters <jp7677@gmail.com>
Mon, 9 Sep 2024 15:43:38 +0000 (17:43 +0200)
committerJohan Malm <johanmalm@users.noreply.github.com>
Tue, 10 Sep 2024 21:14:30 +0000 (22:14 +0100)
While at it, separate corner width from button
width. Both are independed and having them
separately improves readability.

13 files changed:
docs/labwc-theme.5.scd
docs/themerc
include/ssd.h
include/theme.h
include/view.h
src/snap.c
src/ssd/ssd-border.c
src/ssd/ssd-extents.c
src/ssd/ssd-titlebar.c
src/ssd/ssd.c
src/theme.c
src/view.c
src/xwayland.c

index 42dd04076fe0e9d6a3e148b7554bcad1254113ae..57b7aef91d7ddf8687944317dd4ed2468539fe2e 100644 (file)
@@ -47,12 +47,18 @@ labwc-config(5).
 # THEME ELEMENTS
 
 *border.width*
-       Line width (integer) of border border drawn around window frames.
+       Line width (integer) of border drawn around window frames.
        Default is 1.
 
+*padding.width*
+       Horizontal padding size, in pixels, between border and first
+       button on the left/right.
+       Default is 0.
+
 *padding.height*
-       Vertical padding size, used for spacing out elements in the window
-       decorations. Default is 3.
+       Vertical padding size, in pixels, used for spacing out elements
+       in the window decorations.
+       Default is 3.
 
 *titlebar.height*
        Window title bar height.
@@ -122,6 +128,10 @@ labwc-config(5).
        Width of a titlebar button, in pixels.
        Default is 26.
 
+*window.button.spacing*
+       Space between titlebar buttons, in pixels.
+       Default is 0.
+
 *window.active.button.unpressed.image.color*
        Color of the images in titlebar buttons in their default, unpressed,
        state. This element is for the focused window.
index 66e1d09c59f285969fdcd4823749fe4fe139d510..1e066074a74d04c12945451c6c0eb7238afc73dc 100644 (file)
@@ -7,6 +7,7 @@
 
 # general
 border.width: 1
+padding.width: 0
 padding.height: 3
 
 # The following options has no default, but fallbacks back to
@@ -29,8 +30,9 @@ window.active.label.text.color: #000000
 window.inactive.label.text.color: #000000
 window.label.text.justify: center
 
-# window button width
+# window button width and spacing
 window.button.width: 26
+window.button.spacing: 0
 
 # window buttons
 window.active.button.unpressed.image.color: #000000
index 2afd008739edcef8b1273e299203e0371b89e574..701f24eb5d0a31055e5085f1950d85c78802a3c1 100644 (file)
@@ -79,6 +79,7 @@ struct wlr_scene_node;
  */
 struct ssd *ssd_create(struct view *view, bool active);
 struct border ssd_get_margin(const struct ssd *ssd);
+int ssd_get_corner_width(void);
 void ssd_update_margin(struct ssd *ssd);
 void ssd_set_active(struct ssd *ssd, bool active);
 void ssd_update_title(struct ssd *ssd);
index 1b15af6b6b7f4c6a8afb953e01c07f12db75e7fd..4705926e6ad94107fc4ab6ec538909afbae430d6 100644 (file)
@@ -27,7 +27,14 @@ struct theme_snapping_overlay {
 
 struct theme {
        int border_width;
+
+       /*
+        * the space between title bar border and
+        * buttons on the left/right/top
+        */
+       int padding_width;
        int padding_height;
+
        int title_height;
        int menu_overlap_x;
        int menu_overlap_y;
@@ -48,6 +55,8 @@ struct theme {
 
        /* button width */
        int window_button_width;
+       /* the space between buttons */
+       int window_button_spacing;
 
        /* button colors */
        float window_active_button_menu_unpressed_image_color[4];
index 6f47f2a77ed6dc988a73e09dcddc9ef1462bdbfe..3464b4e96ba94959e2f88a6d33b895e271081113 100644 (file)
@@ -538,6 +538,7 @@ const char *view_get_string_prop(struct view *view, const char *prop);
 void view_update_title(struct view *view);
 void view_update_app_id(struct view *view);
 void view_reload_ssd(struct view *view);
+int view_get_min_width(void);
 
 void view_set_shade(struct view *view, bool shaded);
 
index 3f188f6feaf0d17129f2f87e693387e4e362f225..612d7a3fcf0e76e6b19c0497ee261f520026ea1b 100644 (file)
@@ -220,8 +220,7 @@ snap_shrink_to_next_edge(struct view *view,
 
        *geo = view->pending;
        uint32_t resize_edges;
-       int min_view_width = rc.theme->window_button_width * (
-               wl_list_length(&rc.title_buttons_left) + wl_list_length(&rc.title_buttons_right));
+       int min_width = view_get_min_width();
 
        /*
         * First shrink the view along the relevant edge. The maximum shrink
@@ -230,12 +229,12 @@ snap_shrink_to_next_edge(struct view *view,
         */
        switch (direction) {
        case VIEW_EDGE_RIGHT:
-               geo->width = MAX(geo->width / 2, min_view_width);
+               geo->width = MAX(geo->width / 2, min_width);
                geo->x = view->pending.x + view->pending.width - geo->width;
                resize_edges = WLR_EDGE_LEFT;
                break;
        case VIEW_EDGE_LEFT:
-               geo->width = MAX(geo->width / 2, min_view_width);
+               geo->width = MAX(geo->width / 2, min_width);
                resize_edges = WLR_EDGE_RIGHT;
                break;
        case VIEW_EDGE_DOWN:
index 3b7b26cb6f26fcd38590ccafe6e966051ab67254..aa7c4d5f104f501e7b17fe2ff6dd51010bee04d2 100644 (file)
@@ -22,6 +22,7 @@ ssd_border_create(struct ssd *ssd)
        int width = view->current.width;
        int height = view_effective_height(view, /* use_pending */ false);
        int full_width = width + 2 * theme->border_width;
+       int corner_width = ssd_get_corner_width();
 
        float *color;
        struct wlr_scene_tree *parent;
@@ -48,8 +49,8 @@ ssd_border_create(struct ssd *ssd)
                add_scene_rect(&subtree->parts, LAB_SSD_PART_BOTTOM, parent,
                        full_width, theme->border_width, 0, height, color);
                add_scene_rect(&subtree->parts, LAB_SSD_PART_TOP, parent,
-                       width - 2 * theme->window_button_width, theme->border_width,
-                       theme->border_width + theme->window_button_width,
+                       width - 2 * corner_width, theme->border_width,
+                       theme->border_width + corner_width,
                        -(ssd->titlebar.height + theme->border_width), color);
        } FOR_EACH_END
 
@@ -93,6 +94,7 @@ ssd_border_update(struct ssd *ssd)
        int width = view->current.width;
        int height = view_effective_height(view, /* use_pending */ false);
        int full_width = width + 2 * theme->border_width;
+       int corner_width = ssd_get_corner_width();
 
        /*
         * From here on we have to cover the following border scenarios:
@@ -121,10 +123,10 @@ ssd_border_update(struct ssd *ssd)
                : 0;
        int top_width = ssd->titlebar.height <= 0 || ssd->state.was_squared
                ? full_width
-               : width - 2 * theme->window_button_width;
+               : width - 2 * corner_width;
        int top_x = ssd->titlebar.height <= 0 || ssd->state.was_squared
                ? 0
-               : theme->border_width + theme->window_button_width;
+               : theme->border_width + corner_width;
 
        struct ssd_part *part;
        struct wlr_scene_rect *rect;
index b91cf94f9ef2efce85f603e99076713d49925cd2..1a0ed3518b34d8f5221ffa11232ecaaf0e42b068 100644 (file)
@@ -76,8 +76,9 @@ ssd_extents_update(struct ssd *ssd)
        int full_height = height + theme->border_width * 2 + ssd->titlebar.height;
        int full_width = width + 2 * theme->border_width;
        int extended_area = SSD_EXTENDED_AREA;
+       int corner_width = ssd_get_corner_width();
        int corner_size = extended_area + theme->border_width +
-               MIN(theme->window_button_width, width) / 2;
+               MIN(corner_width, width) / 2;
        int side_width = full_width + extended_area * 2 - corner_size * 2;
        int side_height = full_height + extended_area * 2 - corner_size * 2;
 
index 71864cb00ecbfd0dcc38653f5188506231de05b4..1b2f56ac1051c817f9440f21942326d0bbbcfdef 100644 (file)
@@ -116,6 +116,7 @@ ssd_titlebar_create(struct ssd *ssd)
        struct view *view = ssd->view;
        struct theme *theme = view->server->theme;
        int width = view->current.width;
+       int corner_width = ssd_get_corner_width();
 
        float *color;
        struct wlr_scene_tree *parent;
@@ -144,25 +145,25 @@ ssd_titlebar_create(struct ssd *ssd)
 
                /* Background */
                add_scene_rect(&subtree->parts, LAB_SSD_PART_TITLEBAR, parent,
-                       width - theme->window_button_width * 2, theme->title_height,
-                       theme->window_button_width, 0, color);
+                       width - corner_width * 2, theme->title_height,
+                       corner_width, 0, color);
                add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT, parent,
                        corner_top_left, -rc.theme->border_width, -rc.theme->border_width);
                add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT, parent,
-                       corner_top_right, width - theme->window_button_width,
+                       corner_top_right, width - corner_width,
                        -rc.theme->border_width);
 
                /* Buttons */
                struct title_button *b;
-               int x = 0;
+               int x = theme->padding_width;
                wl_list_for_each(b, &rc.title_buttons_left, link) {
                        add_button(ssd, subtree, b->type, x);
-                       x += theme->window_button_width;
+                       x += theme->window_button_width + theme->window_button_spacing;
                }
 
-               x = width;
+               x = width - theme->padding_width + theme->window_button_spacing;
                wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
-                       x -= theme->window_button_width;
+                       x -= theme->window_button_width + theme->window_button_spacing;
                        add_button(ssd, subtree, b->type, x);
                }
        } FOR_EACH_END
@@ -197,11 +198,12 @@ set_squared_corners(struct ssd *ssd, bool enable)
 {
        struct view *view = ssd->view;
        int width = view->current.width;
+       int corner_width = ssd_get_corner_width();
        struct theme *theme = view->server->theme;
 
        struct ssd_part *part;
        struct ssd_sub_tree *subtree;
-       int x = enable ? 0 : theme->window_button_width;
+       int x = enable ? 0 : corner_width;
 
        FOR_EACH_STATE(ssd, subtree) {
                part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
@@ -252,18 +254,23 @@ static void
 update_visible_buttons(struct ssd *ssd)
 {
        struct view *view = ssd->view;
-       int width = view->current.width;
+       int width = view->current.width - (2 * view->server->theme->padding_width);
        int button_width = view->server->theme->window_button_width;
+       int button_spacing = view->server->theme->window_button_spacing;
        int button_count_left = wl_list_length(&rc.title_buttons_left);
        int button_count_right = wl_list_length(&rc.title_buttons_right);
 
        /* Make sure infinite loop never occurs */
        assert(button_width > 0);
+
        /*
         * The corner-left button is lastly removed as it's usually a window
         * menu button (or an app icon button in the future).
         */
-       while (width < button_width * (button_count_left + button_count_right)) {
+       while (width <
+               ((button_width * (button_count_left + button_count_right)) +
+                       (MAX((button_count_right - 1), 0) * button_spacing) +
+                       (MAX((button_count_left - 1), 0) * button_spacing))) {
                if (button_count_left > button_count_right) {
                        button_count_left--;
                } else {
@@ -299,6 +306,7 @@ ssd_titlebar_update(struct ssd *ssd)
 {
        struct view *view = ssd->view;
        int width = view->current.width;
+       int corner_width = ssd_get_corner_width();
        struct theme *theme = view->server->theme;
 
        bool maximized = view->maximized == VIEW_AXIS_BOTH;
@@ -335,27 +343,29 @@ ssd_titlebar_update(struct ssd *ssd)
        struct ssd_part *part;
        struct ssd_sub_tree *subtree;
        struct title_button *b;
-       int bg_offset = maximized || squared ? 0 : theme->window_button_width;
+       int bg_offset = maximized || squared ? 0 : corner_width;
        FOR_EACH_STATE(ssd, subtree) {
                part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
                wlr_scene_rect_set_size(
                        wlr_scene_rect_from_node(part->node),
                        width - bg_offset * 2, theme->title_height);
 
-               x = 0;
+               x = theme->padding_width;
                wl_list_for_each(b, &rc.title_buttons_left, link) {
                        part = ssd_get_part(&subtree->parts, b->type);
                        wlr_scene_node_set_position(part->node, x, 0);
-                       x += theme->window_button_width;
+                       x += theme->window_button_width + theme->window_button_spacing;
                }
 
-               x = width - theme->window_button_width;
+               x = width - corner_width;
                part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT);
                wlr_scene_node_set_position(part->node, x, -rc.theme->border_width);
+
+               x = width - theme->padding_width + theme->window_button_spacing;
                wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
                        part = ssd_get_part(&subtree->parts, b->type);
+                       x -= theme->window_button_width + theme->window_button_spacing;
                        wlr_scene_node_set_position(part->node, x, 0);
-                       x -= theme->window_button_width;
                }
        } FOR_EACH_END
        ssd_update_title(ssd);
@@ -457,19 +467,23 @@ get_title_offsets(struct ssd *ssd, int *offset_left, int *offset_right)
 {
        struct ssd_sub_tree *subtree = &ssd->titlebar.active;
        int button_width = ssd->view->server->theme->window_button_width;
-       *offset_left = 0;
-       *offset_right = 0;
+       int button_spacing = ssd->view->server->theme->window_button_spacing;
+       int padding_width = ssd->view->server->theme->padding_width;
+       *offset_left = padding_width;
+       *offset_right = padding_width;
 
        struct title_button *b;
        wl_list_for_each(b, &rc.title_buttons_left, link) {
                struct ssd_part *part = ssd_get_part(&subtree->parts, b->type);
                if (part->node->enabled) {
+                       *offset_left += *offset_left > padding_width ? button_spacing : 0;
                        *offset_left += button_width;
                }
        }
        wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
                struct ssd_part *part = ssd_get_part(&subtree->parts, b->type);
                if (part->node->enabled) {
+                       *offset_right += *offset_right > padding_width ? button_spacing : 0;
                        *offset_right += button_width;
                }
        }
@@ -603,10 +617,10 @@ bool
 ssd_should_be_squared(struct ssd *ssd)
 {
        struct view *view = ssd->view;
-       int button_width = view->server->theme->window_button_width;
+       int corner_width = ssd_get_corner_width();
 
        return (view_is_tiled_and_notify_tiled(view)
-                       || view->current.width < button_width * 2)
+                       || view->current.width < corner_width * 2)
                && view->maximized != VIEW_AXIS_BOTH;
 }
 
index 0085fe3db4f0800e78cd6901544caed1cdb13a37..a54598fef14c78c29853508d8267b7e99b2a1080 100644 (file)
@@ -205,6 +205,13 @@ ssd_get_margin(const struct ssd *ssd)
        return ssd ? ssd->margin : (struct border){ 0 };
 }
 
+int
+ssd_get_corner_width(void)
+{
+       /* ensure a minimum corner width */
+       return MAX(rc.corner_radius, 5);
+}
+
 void
 ssd_update_margin(struct ssd *ssd)
 {
index 284089900534ab849256d98dcb2731abbc06b9cb..9ba21d43d96d9c19c84b45cebc7b873bd2d4a1a0 100644 (file)
@@ -566,7 +566,9 @@ theme_builtin(struct theme *theme, struct server *server)
        theme->window_label_text_justify = parse_justification("Center");
        theme->menu_title_text_justify = parse_justification("Center");
 
+       theme->padding_width = 0;
        theme->window_button_width = 26;
+       theme->window_button_spacing = 0;
 
        parse_hexstr("#000000",
                theme->window_active_button_menu_unpressed_image_color);
@@ -682,6 +684,9 @@ entry(struct theme *theme, const char *key, const char *value)
        if (match_glob(key, "border.width")) {
                theme->border_width = atoi(value);
        }
+       if (match_glob(key, "padding.width")) {
+               theme->padding_width = atoi(value);
+       }
        if (match_glob(key, "padding.height")) {
                theme->padding_height = atoi(value);
        }
@@ -745,6 +750,9 @@ entry(struct theme *theme, const char *key, const char *value)
                        theme->window_button_width = 1;
                }
        }
+       if (match_glob(key, "window.button.spacing")) {
+               theme->window_button_spacing = atoi(value);
+       }
 
        /* universal button */
        if (match_glob(key, "window.active.button.unpressed.image.color")) {
@@ -1198,10 +1206,12 @@ out:
 static void
 create_corners(struct theme *theme)
 {
+       int corner_width = ssd_get_corner_width();
+
        struct wlr_box box = {
                .x = 0,
                .y = 0,
-               .width = theme->window_button_width + theme->border_width,
+               .width = corner_width + theme->border_width,
                .height = theme->title_height + theme->border_width,
        };
 
index b1b4265a07779583f9590c1c95b296d943de3124..aeb8e7fefd9f22d4a82d20591b38dc16c57eec51 100644 (file)
@@ -617,8 +617,7 @@ view_adjust_size(struct view *view, int *w, int *h)
 {
        assert(view);
        struct view_size_hints hints = view_get_size_hints(view);
-       int min_view_width = rc.theme->window_button_width * (
-               wl_list_length(&rc.title_buttons_left) + wl_list_length(&rc.title_buttons_right));
+       int min_width = view_get_min_width();
 
        /*
         * "If a base size is not provided, the minimum size is to be
@@ -641,7 +640,7 @@ view_adjust_size(struct view *view, int *w, int *h)
         * This is currently always the case for xdg-shell views.
         */
        if (hints.min_width < 1) {
-               hints.min_width = min_view_width;
+               hints.min_width = min_width;
        }
        if (hints.min_height < 1) {
                hints.min_height = LAB_MIN_VIEW_HEIGHT;
@@ -2279,6 +2278,17 @@ view_reload_ssd(struct view *view)
        }
 }
 
+int
+view_get_min_width(void)
+{
+       int button_count_left = wl_list_length(&rc.title_buttons_left);
+       int button_count_right =  wl_list_length(&rc.title_buttons_right);
+       return (rc.theme->window_button_width * (button_count_left + button_count_right)) +
+               (rc.theme->window_button_spacing * MAX((button_count_right - 1), 0)) +
+               (rc.theme->window_button_spacing * MAX((button_count_left - 1), 0)) +
+               (2 * rc.theme->padding_width);
+}
+
 void
 view_toggle_keybinds(struct view *view)
 {
index fdc0b9e5af5986fb64731a9fd9edabc89cae3a1c..09366be2ca891de3b5aff7ccc764befa70b76899 100644 (file)
@@ -606,15 +606,15 @@ handle_map_request(struct wl_listener *listener, void *data)
 static void
 check_natural_geometry(struct view *view)
 {
+       int min_width = view_get_min_width();
+
        /*
         * Some applications (example: Thonny) don't set a reasonable
         * un-maximized size when started maximized. Try to detect this
         * and set a fallback size.
         */
-       int min_view_width = rc.theme->window_button_width * (
-               wl_list_length(&rc.title_buttons_left) + wl_list_length(&rc.title_buttons_right));
        if (!view_is_floating(view)
-                       && (view->natural_geometry.width < min_view_width
+                       && (view->natural_geometry.width < min_width
                        || view->natural_geometry.height < LAB_MIN_VIEW_HEIGHT)) {
                view_set_fallback_natural_geometry(view);
        }