]> git.mdlowis.com Git - proto/labwc.git/commitdiff
menu: support titles
authorJohan Malm <jgm323@gmail.com>
Thu, 9 May 2024 20:20:15 +0000 (21:20 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Tue, 20 Aug 2024 17:01:22 +0000 (18:01 +0100)
...defined by `<separator label="">`.

Also add the theme option `menu.title.bg.color: #589bda`

The following will be added in separate commits
- menu.title.bg.border.color: #7cb6ec
- menu.title.text.color: #ffffff
- menu.title.text.justify: center

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

index b4688a07d51995c62a7ba2d45864729e9c2892b8..a50fa2544be3fc201635cef2246389d153ba6011 100644 (file)
@@ -25,7 +25,7 @@ The menu file must be entirely enclosed within <openbox_menu> and
   <!-- A submenu defined elsewhere -->
   <menu id="" />
 
-  <!-- Horizontal line >
+  <!-- Horizontal line -->
   <separator />
 
   <!-- An inline submenu -->
@@ -33,6 +33,9 @@ The menu file must be entirely enclosed within <openbox_menu> and
     ...some content...
   </menu>
 
+  <!-- Title -->
+  <separator label=""/>
+
   <!-- Pipemenu -->
   <menu id="" label="" execute="COMMAND"/>
 
@@ -63,6 +66,11 @@ The menu file must be entirely enclosed within <openbox_menu> and
 *menu.separator*
        Horizontal line.
 
+*menu.separator.label*
+       In a "separator" element, the label attribute transforms the separator
+       from a horizontal line to a menu title (heading) with the text specified
+       by label in it.
+
 *menu.execute*
        Command to execute for pipe menu. See details below.
 
index 5b90a962dd51f18fba5b625f117c341ce6307b3a..29a832f5881b34f58bbbeb82ec168c905aeac58e 100644 (file)
@@ -174,6 +174,10 @@ elements are not listed here, but are supported.
 *menu.separator.color*
        Menu separator color. Default #888888.
 
+*menu.title.bg.color*
+       Menu title color. Default #589bda.
+       Note: A menu title is a separator with a label.
+
 *osd.bg.color*
        Background color of on-screen-display. Inherits
        *window.active.title.bg.color* if not set.
index b2dcb2fe7a519bcd07f3fd8c85ffc421dec197e8..e54dfb96f03c7fd27951a4414486977c1ec8eb23 100644 (file)
@@ -62,6 +62,7 @@ menu.separator.width: 1
 menu.separator.padding.width: 6
 menu.separator.padding.height: 3
 menu.separator.color: #888888
+menu.title.bg.color: #589bda
 
 # on screen display (window-cycle dialog)
 osd.bg.color: #e1dedb
index 3b5fa55b3a980f493cc37f1930d79fd062e3ea23..9edf8b76eb4e5a6c8655243ffd9a816f5ab450fa 100644 (file)
@@ -27,6 +27,12 @@ struct menu_scene {
        struct scaled_font_buffer *buffer;
 };
 
+enum menuitem_type {
+       LAB_MENU_ITEM = 0,
+       LAB_MENU_SEPARATOR_LINE,
+       LAB_MENU_TITLE,
+};
+
 struct menuitem {
        struct wl_list actions;
        char *execute;
@@ -34,6 +40,7 @@ struct menuitem {
        struct menu *parent;
        struct menu *submenu;
        bool selectable;
+       enum menuitem_type type;
        int height;
        int native_width;
        struct wlr_scene_tree *tree;
index 39931840068d144565e37d4b2b65d5ea6ec9f5a0..9791f7e98423568802d4f5f4afb0f8ad99efc226 100644 (file)
@@ -75,6 +75,8 @@ struct theme {
        int menu_separator_padding_height;
        float menu_separator_color[4];
 
+       float menu_title_bg_color[4];
+
        int osd_border_width;
 
        float osd_bg_color[4];
index 23b5d2a14947164a682f3f86d5e1d31fdd207f8e..98b214ffd25e64c0801058627ea92e724eec38ca 100644 (file)
@@ -118,26 +118,42 @@ menu_update_width(struct menu *menu)
        }
        menu->size.width = max_width + 2 * theme->menu_item_padding_x;
 
+       /*
+        * TODO: This function is getting a bit unwieldy. Consider calculating
+        * the menu-window width up-front to avoid this post_processing() and
+        * second-bite-of-the-cherry stuff
+        */
+
        /* Update all items for the new size */
        wl_list_for_each(item, &menu->menuitems, link) {
                wlr_scene_rect_set_size(
                        wlr_scene_rect_from_node(item->normal.background),
                        menu->size.width, item->height);
 
-               if (!item->selected.background) {
-                       /* This is a separator. They don't have a selected background. */
+               /*
+                * Separator lines are special because they change width with
+                * the menu.
+                */
+               if (item->type == LAB_MENU_SEPARATOR_LINE) {
+                       int width = menu->size.width
+                               - 2 * theme->menu_separator_padding_width
+                               - 2 * theme->menu_item_padding_x;
                        wlr_scene_rect_set_size(
                                wlr_scene_rect_from_node(item->normal.text),
-                               menu->size.width - 2 * theme->menu_separator_padding_width,
-                               theme->menu_separator_line_thickness);
-               } else {
-                       /* Usual menu item */
+                               width, theme->menu_separator_line_thickness);
+               }
+
+               if (item->selectable) {
+                       /* Only selectable items have item->selected.background */
                        wlr_scene_rect_set_size(
                                wlr_scene_rect_from_node(item->selected.background),
                                menu->size.width, item->height);
-                       if (item->native_width > max_width || item->submenu || item->execute) {
-                               scaled_font_buffer_set_max_width(item->normal.buffer,
-                                       max_width);
+               }
+
+               if (item->native_width > max_width || item->submenu || item->execute) {
+                       scaled_font_buffer_set_max_width(item->normal.buffer,
+                               max_width);
+                       if (item->selectable) {
                                scaled_font_buffer_set_max_width(item->selected.buffer,
                                        max_width);
                        }
@@ -188,11 +204,13 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
        struct menuitem *menuitem = znew(*menuitem);
        menuitem->parent = menu;
        menuitem->selectable = true;
+       menuitem->type = LAB_MENU_ITEM;
        struct server *server = menu->server;
        struct theme *theme = server->theme;
 
        const char *arrow = show_arrow ? "›" : NULL;
 
+       /* TODO: Consider setting this somewhere else */
        if (!menu->item_height) {
                menu->item_height = font_height(&rc.font_menuitem)
                        + 2 * theme->menu_item_padding_y;
@@ -275,34 +293,68 @@ separator_create(struct menu *menu, const char *label)
        struct menuitem *menuitem = znew(*menuitem);
        menuitem->parent = menu;
        menuitem->selectable = false;
+       menuitem->type = string_null_or_empty(label) ? LAB_MENU_SEPARATOR_LINE
+               : LAB_MENU_TITLE;
        struct server *server = menu->server;
        struct theme *theme = server->theme;
-       menuitem->height = theme->menu_separator_line_thickness +
-                       2 * theme->menu_separator_padding_height;
 
+       if (menuitem->type == LAB_MENU_TITLE) {
+               menuitem->height = menu->item_height;
+               menuitem->native_width = font_width(&rc.font_menuitem, label);
+       } else if (menuitem->type == LAB_MENU_SEPARATOR_LINE) {
+               menuitem->height = theme->menu_separator_line_thickness +
+                               2 * theme->menu_separator_padding_height;
+       }
+
+       /* Menu item root node */
        menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
        node_descriptor_create(&menuitem->tree->node,
                LAB_NODE_DESC_MENUITEM, menuitem);
+
+       /* Tree to hold background and text/line buffer */
        menuitem->normal.tree = wlr_scene_tree_create(menuitem->tree);
-       menuitem->normal.background = &wlr_scene_rect_create(
-               menuitem->normal.tree,
-               menu->size.width, menuitem->height,
-               theme->menu_items_bg_color)->node;
 
-       int width = menu->size.width - 2 * theme->menu_separator_padding_width;
-       menuitem->normal.text = &wlr_scene_rect_create(
+       /* Item background nodes */
+       float *bg_color = menuitem->type == LAB_MENU_TITLE
+               ? theme->menu_title_bg_color : theme->menu_items_bg_color;
+       menuitem->normal.background = &wlr_scene_rect_create(
                menuitem->normal.tree,
-               width > 0 ? width : 0,
-               theme->menu_separator_line_thickness,
-               theme->menu_separator_color)->node;
-
+               menu->size.width, menuitem->height, bg_color)->node;
+
+       /* Draw separator line or title */
+       if (menuitem->type == LAB_MENU_TITLE) {
+               menuitem->normal.buffer = scaled_font_buffer_create(menuitem->normal.tree);
+               if (!menuitem->normal.buffer) {
+                       wlr_log(WLR_ERROR, "Failed to create menu item '%s'", label);
+                       wlr_scene_node_destroy(&menuitem->tree->node);
+                       free(menuitem);
+                       return NULL;
+               }
+               menuitem->normal.text = &menuitem->normal.buffer->scene_buffer->node;
+               /* Font buffer */
+               scaled_font_buffer_update(menuitem->normal.buffer, label,
+                       menuitem->native_width, &rc.font_menuitem,
+                       theme->menu_items_text_color, bg_color, /* arrow */ NULL);
+               /* Center font nodes */
+               int x, y;
+               x = theme->menu_item_padding_x;
+               y = (menu->item_height - menuitem->normal.buffer->height) / 2;
+               wlr_scene_node_set_position(menuitem->normal.text, x, y);
+       } else {
+               int nominal_width = theme->menu_min_width;
+               menuitem->normal.text = &wlr_scene_rect_create(
+                       menuitem->normal.tree, nominal_width,
+                       theme->menu_separator_line_thickness,
+                       theme->menu_separator_color)->node;
+               wlr_scene_node_set_position(&menuitem->tree->node, 0, menu->size.height);
+               /* Vertically center-align separator line */
+               wlr_scene_node_set_position(menuitem->normal.text,
+                       theme->menu_separator_padding_width
+                       + theme->menu_item_padding_x,
+                       theme->menu_separator_padding_height);
+       }
        wlr_scene_node_set_position(&menuitem->tree->node, 0, menu->size.height);
 
-       /* Vertically center-align separator line */
-       wlr_scene_node_set_position(menuitem->normal.text,
-               theme->menu_separator_padding_width,
-               theme->menu_separator_padding_height);
-
        menu->size.height += menuitem->height;
        wl_list_append(&menu->menuitems, &menuitem->link);
        wl_list_init(&menuitem->actions);
index d699773ede6694f06053846f91c6b0ada9224140..fe8dc115296f68ad0cf5d9f1aa98264c32d66e3c 100644 (file)
@@ -528,6 +528,8 @@ theme_builtin(struct theme *theme, struct server *server)
        theme->menu_separator_padding_height = 3;
        parse_hexstr("#888888", theme->menu_separator_color);
 
+       parse_hexstr("#589bda", theme->menu_title_bg_color);
+
        theme->osd_window_switcher_width = 600;
        theme->osd_window_switcher_width_is_percent = false;
        theme->osd_window_switcher_padding = 4;
@@ -766,6 +768,10 @@ entry(struct theme *theme, const char *key, const char *value)
                parse_hexstr(value, theme->menu_separator_color);
        }
 
+       if (match_glob(key, "menu.title.bg.color")) {
+               parse_hexstr(value, theme->menu_title_bg_color);
+       }
+
        if (match_glob(key, "osd.bg.color")) {
                parse_hexstr(value, theme->osd_bg_color);
        }