diff --git a/docs/labwc-menu.5.scd b/docs/labwc-menu.5.scd index b4688a07..a50fa254 100644 --- a/docs/labwc-menu.5.scd +++ b/docs/labwc-menu.5.scd @@ -25,7 +25,7 @@ The menu file must be entirely enclosed within and - @@ -33,6 +33,9 @@ The menu file must be entirely enclosed within and ...some content... + + + @@ -63,6 +66,11 @@ The menu file must be entirely enclosed within 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. diff --git a/docs/labwc-theme.5.scd b/docs/labwc-theme.5.scd index 5b90a962..29a832f5 100644 --- a/docs/labwc-theme.5.scd +++ b/docs/labwc-theme.5.scd @@ -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. diff --git a/docs/themerc b/docs/themerc index b2dcb2fe..e54dfb96 100644 --- a/docs/themerc +++ b/docs/themerc @@ -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 diff --git a/include/menu/menu.h b/include/menu/menu.h index 3b5fa55b..9edf8b76 100644 --- a/include/menu/menu.h +++ b/include/menu/menu.h @@ -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; diff --git a/include/theme.h b/include/theme.h index 39931840..9791f7e9 100644 --- a/include/theme.h +++ b/include/theme.h @@ -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]; diff --git a/src/menu/menu.c b/src/menu/menu.c index 23b5d2a1..98b214ff 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -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); + + /* 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, - 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( - 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); diff --git a/src/theme.c b/src/theme.c index d699773e..fe8dc115 100644 --- a/src/theme.c +++ b/src/theme.c @@ -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); }