]> git.mdlowis.com Git - proto/labwc.git/commitdiff
menu: Dynamically adjust menu width based on widest item
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Mon, 5 Dec 2022 13:38:16 +0000 (14:38 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Tue, 6 Dec 2022 21:08:43 +0000 (21:08 +0000)
Adds two new theme vars:
- menu.width.min (menu will never be smaller than this)
- menu.width.max (menu will never be wider than this + padding)

A fixed menu width can be achieved by setting
menu.width.min == menu.width.max.

docs/labwc-theme.5.scd
include/common/scaled_font_buffer.h
include/menu/menu.h
include/theme.h
src/common/scaled_font_buffer.c
src/menu/menu.c
src/theme.c

index af431479a117aa449554d5d09cc7544690139232..0c5db0104d5632168bb845eadd8b2b874e7765a4 100644 (file)
@@ -59,6 +59,14 @@ A theme consists of a themerc file and optionally some xbm icons.
        Vertical offset in pixels between submenus and their parents. Positive
        values for downwards and negative for upwards. Default is 0.
 
+*menu.width.min*
+       Minimal width for menus. Default is 20.
+       A fixed width can be achieved by setting .min and .max to the same value.
+
+*menu.width.max*
+       Maximal width for menus. Default is 200.
+       A fixed width can be achieved by setting .min and .max to the same value.
+
 *window.active.border.color*
        Border color of active window
 
index fb5e925db0198552ca9162be8ba2ef02d3391d17..de9a365f8fdf39bacba7d372b7d995489dcd9ad8 100644 (file)
@@ -25,7 +25,7 @@ struct scaled_font_buffer {
 /**
  * Create an auto scaling font buffer, providing a wlr_scene_buffer node for
  * display. It gets destroyed automatically when the backing scaled_scene_buffer
- * is being destoyed which in turn happens automatically when the backing
+ * is being destroyed which in turn happens automatically when the backing
  * wlr_scene_buffer (or one of its parents) is being destroyed.
  *
  * To actually show some text, scaled_font_buffer_update() has to be called.
@@ -48,4 +48,12 @@ struct scaled_font_buffer *scaled_font_buffer_create(struct wlr_scene_tree *pare
 void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
        int max_width, struct font *font, float *color, const char *arrow);
 
+/**
+ * Update the max width of an existing auto scaling font buffer
+ * and force a new render.
+ *
+ * No steps are taken to detect if its actually required to render a new buffer.
+ */
+void scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width);
+
 #endif /* __LAB_COMMON_SCALED_FONT_BUFFER_H */
index bbb4905eb1eced7a88fc8c5ff66ae40c42a6e7bc..5d07fed03e56d6da2da360edd162ff51397dd875 100644 (file)
@@ -33,6 +33,7 @@ struct menuitem {
        struct menu *submenu;
        bool selectable;
        int height;
+       int native_width;
        struct wlr_scene_tree *tree;
        struct menu_scene normal;
        struct menu_scene selected;
index 359724814962f1d866571619587252450bcc2066..11386cad1a3a1fabb86765035a919cf832892fb0 100644 (file)
@@ -53,6 +53,9 @@ struct theme {
        float menu_items_active_bg_color[4];
        float menu_items_active_text_color[4];
 
+       int menu_min_width;
+       int menu_max_width;
+
        int menu_separator_line_thickness;
        int menu_separator_padding_width;
        int menu_separator_padding_height;
index ec4c61610f73d26b8b874ed5c4977f0ca6b04362..3daae5934d6cb5c02eea0201dfa92eded4e4469b 100644 (file)
@@ -90,3 +90,10 @@ scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
        /* Invalidate cache and force a new render */
        scaled_scene_buffer_invalidate_cache(self->scaled_buffer);
 }
+
+void
+scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width)
+{
+       self->max_width = max_width;
+       scaled_scene_buffer_invalidate_cache(self->scaled_buffer);
+}
index f02939ef08dc070db14e2b60e223a3f46aa2a577..306619106f62e6f9729319dfdbb78b42fbff311b 100644 (file)
 #include "common/mem.h"
 #include "common/nodename.h"
 #include "common/scaled_font_buffer.h"
+#include "common/scene-helpers.h"
 #include "common/string-helpers.h"
 #include "labwc.h"
 #include "menu/menu.h"
 #include "node.h"
 #include "theme.h"
 
-#define MENUWIDTH (110)
-
 /* state-machine variables for processing <item></item> */
 static bool in_item;
 static struct menuitem *current_item;
@@ -52,7 +51,7 @@ menu_create(struct server *server, const char *id, const char *label)
        menu->label = xstrdup(label ? label : id);
        menu->parent = current_menu;
        menu->server = server;
-       menu->size.width = MENUWIDTH;
+       menu->size.width = server->theme->menu_min_width;
        /* menu->size.height will be kept up to date by adding items */
        menu->scene_tree = wlr_scene_tree_create(server->menu_tree);
        wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
@@ -75,6 +74,59 @@ menu_get_by_id(const char *id)
        return NULL;
 }
 
+static void
+menu_update_width(struct menu *menu)
+{
+       struct menuitem *item;
+       struct theme *theme = menu->server->theme;
+       int max_width = theme->menu_min_width;
+
+       /* Get widest menu item, clamped by menu_max_width */
+       wl_list_for_each(item, &menu->menuitems, link) {
+               if (item->native_width > max_width) {
+                       max_width = item->native_width < theme->menu_max_width
+                               ? item->native_width : theme->menu_max_width;
+               }
+       }
+       menu->size.width = max_width + 2 * theme->menu_item_padding_x;
+
+       /* Update all items for the new size */
+       wl_list_for_each(item, &menu->menuitems, link) {
+               wlr_scene_rect_set_size(
+                       lab_wlr_scene_get_rect(item->normal.background),
+                       menu->size.width, item->height);
+
+               if (!item->selected.background) {
+                       /* This is a separator. They don't have a selected background. */
+                       wlr_scene_rect_set_size(
+                               lab_wlr_scene_get_rect(item->normal.text),
+                               menu->size.width - 2 * theme->menu_separator_padding_width,
+                               theme->menu_separator_line_thickness);
+               } else {
+                       /* Usual menu item */
+                       wlr_scene_rect_set_size(
+                               lab_wlr_scene_get_rect(item->selected.background),
+                               menu->size.width, item->height);
+                       if (item->native_width > max_width || item->submenu) {
+                               scaled_font_buffer_set_max_width(item->normal.buffer,
+                                       max_width);
+                               scaled_font_buffer_set_max_width(item->selected.buffer,
+                                       max_width);
+                       }
+               }
+       }
+}
+
+static void
+post_processing(struct server *server)
+{
+       struct menu *menu;
+       for (int i = 0; i < nr_menus; ++i) {
+               menu = menus + i;
+               menu_update_width(menu);
+       }
+}
+
 static struct menuitem *
 item_create(struct menu *menu, const char *text, bool show_arrow)
 {
@@ -84,6 +136,8 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
        struct server *server = menu->server;
        struct theme *theme = server->theme;
 
+       const char *arrow = show_arrow ? "›" : NULL;
+
        if (!menu->item_height) {
                menu->item_height = font_height(&rc.font_menuitem)
                        + 2 * theme->menu_item_padding_y;
@@ -91,7 +145,10 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
        menuitem->height = menu->item_height;
 
        int x, y;
-       int item_max_width = MENUWIDTH - 2 * theme->menu_item_padding_x;
+       menuitem->native_width = font_width(&rc.font_menuitem, text);
+       if (arrow) {
+               menuitem->native_width += font_width(&rc.font_menuitem, arrow);
+       }
 
        /* Menu item root node */
        menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
@@ -105,11 +162,11 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
        /* Item background nodes */
        menuitem->normal.background = &wlr_scene_rect_create(
                menuitem->normal.tree,
-               MENUWIDTH, menu->item_height,
+               menu->size.width, menu->item_height,
                theme->menu_items_bg_color)->node;
        menuitem->selected.background = &wlr_scene_rect_create(
                menuitem->selected.tree,
-               MENUWIDTH, menu->item_height,
+               menu->size.width, menu->item_height,
                theme->menu_items_active_bg_color)->node;
 
        /* Font nodes */
@@ -129,10 +186,9 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
        menuitem->selected.text = &menuitem->selected.buffer->scene_buffer->node;
 
        /* Font buffers */
-       const char *arrow = show_arrow ? "›" : NULL;
-       scaled_font_buffer_update(menuitem->normal.buffer, text, item_max_width,
+       scaled_font_buffer_update(menuitem->normal.buffer, text, menuitem->native_width,
                &rc.font_menuitem, theme->menu_items_text_color, arrow);
-       scaled_font_buffer_update(menuitem->selected.buffer, text, item_max_width,
+       scaled_font_buffer_update(menuitem->selected.buffer, text, menuitem->native_width,
                &rc.font_menuitem, theme->menu_items_active_text_color, arrow);
 
        /* Center font nodes */
@@ -173,10 +229,10 @@ separator_create(struct menu *menu, const char *label)
        menuitem->normal.tree = wlr_scene_tree_create(menuitem->tree);
        menuitem->normal.background = &wlr_scene_rect_create(
                menuitem->normal.tree,
-               MENUWIDTH, menuitem->height,
+               menu->size.width, menuitem->height,
                theme->menu_items_bg_color)->node;
 
-       int width = MENUWIDTH - 2 * theme->menu_separator_padding_width;
+       int width = menu->size.width - 2 * theme->menu_separator_padding_width;
        menuitem->normal.text = &wlr_scene_rect_create(
                menuitem->normal.tree,
                width > 0 ? width : 0,
@@ -511,7 +567,7 @@ menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
        }
 
        if (align & LAB_MENU_OPEN_LEFT) {
-               lx -= MENUWIDTH - theme->menu_overlap_x;
+               lx -= menu->size.width - theme->menu_overlap_x;
        }
        if (align & LAB_MENU_OPEN_TOP) {
                ly -= menu->size.height;
@@ -530,7 +586,7 @@ menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
                        continue;
                }
                if (align & LAB_MENU_OPEN_RIGHT) {
-                       new_lx = lx + MENUWIDTH - theme->menu_overlap_x;
+                       new_lx = lx + menu->size.width - theme->menu_overlap_x;
                } else {
                        new_lx = lx;
                }
@@ -642,6 +698,7 @@ menu_init(struct server *server)
 {
        init_rootmenu(server);
        init_windowmenu(server);
+       post_processing(server);
 }
 
 void
index 5ae471ce02a9fd87af8bcb64b757b38569d8ae80..a0518634d06b7cec5d47b318f83701aa483ecef4 100644 (file)
@@ -131,6 +131,9 @@ theme_builtin(struct theme *theme)
        theme->menu_item_padding_x = 7;
        theme->menu_item_padding_y = 4;
 
+       theme->menu_min_width = 20;
+       theme->menu_max_width = 200;
+
        theme->menu_separator_line_thickness = 1;
        theme->menu_separator_padding_width = 6;
        theme->menu_separator_padding_height = 3;
@@ -260,6 +263,13 @@ entry(struct theme *theme, const char *key, const char *value)
                        theme->window_inactive_button_close_unpressed_image_color);
        }
 
+       if (match(key, "menu.width.min")) {
+               theme->menu_min_width = atoi(value);
+       }
+       if (match(key, "menu.width.max")) {
+               theme->menu_max_width = atoi(value);
+       }
+
        if (match(key, "menu.items.bg.color")) {
                parse_hexstr(value, theme->menu_items_bg_color);
        }
@@ -488,6 +498,13 @@ post_processing(struct theme *theme)
                theme->title_height = rc.corner_radius + 1;
        }
 
+       if (theme->menu_max_width < theme->menu_min_width) {
+               wlr_log(WLR_ERROR,
+                       "Adjusting menu.width.max: .max (%d) lower than .min (%d)",
+                       theme->menu_max_width, theme->menu_min_width);
+               theme->menu_max_width = theme->menu_min_width;
+       }
+
        /* Inherit OSD settings if not set */
        if (theme->osd_bg_color[0] == FLT_MIN) {
                memcpy(theme->osd_bg_color,