From 437230b3a0e8d0202a8e88a04e4e1b112fe921d5 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Wed, 22 Jun 2022 21:07:25 +0100 Subject: [PATCH] menu: support Add theme options: - menu.separator.width - menu.separator.padding.width - menu.separator.padding.height - menu.separator.color Support separator lines defined by Note that separator labels (with text) defined by are not supported. --- docs/labwc-theme.5.scd | 12 +++++ docs/themerc | 5 ++- include/menu/menu.h | 2 + include/theme.h | 5 +++ src/menu/menu.c | 100 +++++++++++++++++++++++++++++++++-------- src/theme.c | 18 ++++++++ 6 files changed, 123 insertions(+), 19 deletions(-) diff --git a/docs/labwc-theme.5.scd b/docs/labwc-theme.5.scd index 875aa9fd..2b9d5098 100644 --- a/docs/labwc-theme.5.scd +++ b/docs/labwc-theme.5.scd @@ -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 diff --git a/docs/themerc b/docs/themerc index 0273849f..01a58619 100644 --- a/docs/themerc +++ b/docs/themerc @@ -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 - diff --git a/include/menu/menu.h b/include/menu/menu.h index da1e2166..5586e65f 100644 --- a/include/menu/menu.h +++ b/include/menu/menu.h @@ -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; diff --git a/include/theme.h b/include/theme.h index 4858195d..9955e0d0 100644 --- a/include/theme.h +++ b/include/theme.h @@ -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]; diff --git a/src/menu/menu.c b/src/menu/menu.c index 91c9a953..bb79295e 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -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: * @@ -309,6 +352,17 @@ handle_menu_element(xmlNode *n, struct server *server) zfree(id); } +/* This can be one of and */ +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; diff --git a/src/theme.c b/src/theme.c index e552bfdf..a0c3e99e 100644 --- a/src/theme.c +++ b/src/theme.c @@ -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); } -- 2.52.0