]> git.mdlowis.com Git - proto/labwc.git/commitdiff
menu: support <separator />
authorJohan Malm <jgm323@gmail.com>
Wed, 22 Jun 2022 20:07:25 +0000 (21:07 +0100)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Sat, 25 Jun 2022 12:56:35 +0000 (14:56 +0200)
Add theme options:
- menu.separator.width
- menu.separator.padding.width
- menu.separator.padding.height
- menu.separator.color

Support separator lines defined by <separator />

Note that separator labels (with text) defined by <separator label="" />
are not supported.

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

index 875aa9fdcabdfbdd03267b4fa49556830b0abdb6..2b9d50984a5091e7f48f128ed2bced2b8683c2ab 100644 (file)
@@ -101,6 +101,18 @@ elements are not listed here, but are supported.
 *menu.items.active.text.color*
        Text color of active menu item
 
+*menu.separator.width*
+       Line thickness of menu separators. Default 1.
+
+*menu.separator.padding.width*
+       Space on the left and right side of each separator line. Default 6.
+
+*menu.separator.padding.height*
+       Space above and below each separator line. Default 3.
+
+*menu.separator.color*
+       Menu separator color. Default #888888.
+
 *osd.bg.color*
        Background color of on-screen-display
 
index 0273849f842d27f6c1e8592dbbe316f699b04728..01a58619f5898349c12da2869eed76e99a096199 100644 (file)
@@ -31,10 +31,13 @@ menu.items.bg.color: #fcfbfa
 menu.items.text.color: #000000
 menu.items.active.bg.color: #dddad6
 menu.items.active.text.color: #000000
+menu.separator.width: 1
+menu.separator.padding.width: 6
+menu.separator.padding.height: 3
+menu.separator.color: #888888
 
 # on screen display (window-cycle dialog)
 osd.bg.color: #dddda6
 osd.border.color: #000000
 osd.border.width: 1
 osd.label.text.color: #000000
-
index da1e2166e96fe2456d0c94436e09beb122c2e295..5586e65f2bae9f79005069d34d177d755b779229 100644 (file)
@@ -31,6 +31,8 @@ struct menuitem {
        struct wl_list actions;
        struct menu *parent;
        struct menu *submenu;
+       bool selectable;
+       int height;
        struct wlr_scene_tree *tree;
        struct menu_scene normal;
        struct menu_scene selected;
index 4858195d04a354cbd4edd7a8d07abb36b38be7c2..9955e0d0c5cb20a3b328c734e0e9190a197f901e 100644 (file)
@@ -50,6 +50,11 @@ struct theme {
        float menu_items_active_bg_color[4];
        float menu_items_active_text_color[4];
 
+       int menu_separator_width;
+       int menu_separator_padding_width;
+       int menu_separator_padding_height;
+       float menu_separator_color[4];
+
        int osd_border_width;
        float osd_bg_color[4];
        float osd_border_color[4];
index 91c9a9535c903189d79520b88bd3fd95d425c006..bb79295e33ae74c1ccd39a012069e4d24858091b 100644 (file)
@@ -85,6 +85,7 @@ item_create(struct menu *menu, const char *text)
                return NULL;
        }
        menuitem->parent = menu;
+       menuitem->selectable = true;
        struct server *server = menu->server;
        struct theme *theme = server->theme;
        struct font font = {
@@ -95,6 +96,7 @@ item_create(struct menu *menu, const char *text)
        if (!menu->item_height) {
                menu->item_height = font_height(&font) + 2 * MENU_ITEM_PADDING_Y;
        }
+       menuitem->height = menu->item_height;
 
        int x, y;
        int item_max_width = MENUWIDTH - 2 * MENU_ITEM_PADDING_X;
@@ -148,21 +150,62 @@ item_create(struct menu *menu, const char *text)
        wlr_scene_node_set_position(menuitem->selected.text, x, y);
 
        /* Position the item in relation to its menu */
-       int item_count = wl_list_length(&menu->menuitems);
-       y = item_count * menu->item_height;
-       wlr_scene_node_set_position(&menuitem->tree->node, 0, y);
+       wlr_scene_node_set_position(&menuitem->tree->node, 0, menu->size.height);
 
        /* Hide selected state */
        wlr_scene_node_set_enabled(&menuitem->selected.tree->node, false);
 
        /* Update menu extents */
-       menu->size.height = (item_count + 1) * menu->item_height;
+       menu->size.height += menuitem->height;
 
        wl_list_insert(&menu->menuitems, &menuitem->link);
        wl_list_init(&menuitem->actions);
        return menuitem;
 }
 
+static struct menuitem *
+separator_create(struct menu *menu, const char *label)
+{
+       struct menuitem *menuitem = calloc(1, sizeof(struct menuitem));
+       if (!menuitem) {
+               return NULL;
+       }
+       menuitem->parent = menu;
+       menuitem->selectable = false;
+       struct server *server = menu->server;
+       struct theme *theme = server->theme;
+       menuitem->height = theme->menu_separator_width +
+                       2 * theme->menu_separator_padding_height;
+
+       menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
+       node_descriptor_create(&menuitem->tree->node,
+               LAB_NODE_DESC_MENUITEM, menuitem);
+       menuitem->normal.tree = wlr_scene_tree_create(menuitem->tree);
+       menuitem->normal.background = &wlr_scene_rect_create(
+               menuitem->normal.tree,
+               MENUWIDTH, menuitem->height,
+               theme->menu_items_bg_color)->node;
+
+       /* theme->menu_separator_width is the line-thickness (so height here) */
+       menuitem->normal.text = &wlr_scene_rect_create(
+               menuitem->normal.tree,
+               MENUWIDTH - 2 * theme->menu_separator_padding_width,
+               theme->menu_separator_width,
+               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_separator_padding_height);
+
+       menu->size.height += menuitem->height;
+       wl_list_insert(&menu->menuitems, &menuitem->link);
+       wl_list_init(&menuitem->actions);
+       return menuitem;
+}
+
 /*
  * Handle the following:
  * <item label="">
@@ -309,6 +352,17 @@ handle_menu_element(xmlNode *n, struct server *server)
        zfree(id);
 }
 
+/* This can be one of <separator> and <separator label=""> */
+static void
+handle_separator_element(xmlNode *n)
+{
+       char *label = (char *)xmlGetProp(n, (const xmlChar *)"label");
+       current_item = separator_create(current_menu, label);
+       if (label) {
+               free(label);
+       }
+}
+
 static void
 xml_tree_walk(xmlNode *node, struct server *server)
 {
@@ -320,6 +374,10 @@ xml_tree_walk(xmlNode *node, struct server *server)
                        handle_menu_element(n, server);
                        continue;
                }
+               if (!strcasecmp((char *)n->name, "separator")) {
+                       handle_separator_element(n);
+                       continue;
+               }
                if (!strcasecmp((char *)n->name, "item")) {
                        in_item = true;
                        traverse(n, server);
@@ -468,24 +526,24 @@ menu_hide_submenu(const char *id)
        }
        for (int i = 0; i < nr_menus; ++i) {
                menu = menus + i;
-               size_t item_index = 0;
-               size_t items_destroyed = 0;
-               struct menuitem *item, *item_tmp;
-               wl_list_for_each_reverse_safe(item, item_tmp, &menu->menuitems, link) {
+               bool should_reposition = false;
+               struct menuitem *item, *next;
+               wl_list_for_each_reverse_safe(item, next, &menu->menuitems, link) {
                        if (item->submenu == hide_menu) {
                                item_destroy(item);
-                               items_destroyed++;
-                               item_index++;
-                               continue;
+                               should_reposition = true;
                        }
-                       if (items_destroyed) {
-                               int y = (item_index - items_destroyed) * menu->item_height;
-                               wlr_scene_node_set_position(&item->tree->node, 0, y);
-                       }
-                       item_index++;
                }
-               if (items_destroyed) {
-                       menu->size.height -= items_destroyed * menu->item_height;
+
+               if (!should_reposition) {
+                       continue;
+               }
+               /* Re-position items vertically */
+               menu->size.height = 0;
+               wl_list_for_each_reverse(item, &menu->menuitems, link) {
+                       wlr_scene_node_set_position(&item->tree->node, 0,
+                               menu->size.height);
+                       menu->size.height += item->height;
                }
        }
 }
@@ -645,6 +703,12 @@ menu_process_cursor_motion(struct wlr_scene_node *node)
        assert(node && node->data);
        struct menuitem *item = node_menuitem_from_node(node);
 
+       /* This function shall only be called for menu nodes */
+       assert(item);
+
+       if (!item->selectable) {
+               return;
+       }
        if (node == &item->selected.tree->node) {
                /* We are on an already selected item */
                return;
index e552bfdf8b8b63d71d04d179826f2a023860833a..a0c3e99edb828384a1b57749b795bb4f64cb0cc0 100644 (file)
@@ -128,6 +128,11 @@ theme_builtin(struct theme *theme)
        parse_hexstr("#dddad6", theme->menu_items_active_bg_color);
        parse_hexstr("#000000", theme->menu_items_active_text_color);
 
+       theme->menu_separator_width = 1;
+       theme->menu_separator_padding_width = 6;
+       theme->menu_separator_padding_height = 3;
+       parse_hexstr("#888888", theme->menu_separator_color);
+
        /* inherit settings in post_processing() if not set elsewhere */
        theme->osd_bg_color[0] = FLT_MIN;
        theme->osd_border_width = INT_MIN;
@@ -259,6 +264,19 @@ entry(struct theme *theme, const char *key, const char *value)
                parse_hexstr(value, theme->menu_items_active_text_color);
        }
 
+       if (match(key, "menu.separator.width")) {
+               theme->menu_separator_width = atoi(value);
+       }
+       if (match(key, "menu.separator.padding.width")) {
+               theme->menu_separator_padding_width = atoi(value);
+       }
+       if (match(key, "menu.separator.padding.height")) {
+               theme->menu_separator_padding_height = atoi(value);
+       }
+       if (match(key, "menu.separator.color")) {
+               parse_hexstr(value, theme->menu_separator_color);
+       }
+
        if (match(key, "osd.bg.color")) {
                parse_hexstr(value, theme->osd_bg_color);
        }