mirror of
https://github.com/labwc/labwc.git
synced 2026-04-12 08:21:13 -04:00
Pipemenu, fix so both inline and stand alone work
This commit is contained in:
parent
3be8fe25f3
commit
1419c2bbc2
4 changed files with 114 additions and 51 deletions
|
|
@ -27,6 +27,12 @@ struct menu_scene {
|
||||||
struct scaled_font_buffer *buffer;
|
struct scaled_font_buffer *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum menuitem_type {
|
||||||
|
LAB_MENU_ITEM = 0,
|
||||||
|
LAB_MENU_SEPARATOR_LINE,
|
||||||
|
LAB_MENU_TITLE,
|
||||||
|
};
|
||||||
|
|
||||||
struct menuitem {
|
struct menuitem {
|
||||||
struct wl_list actions;
|
struct wl_list actions;
|
||||||
char *execute;
|
char *execute;
|
||||||
|
|
@ -34,6 +40,7 @@ struct menuitem {
|
||||||
struct menu *parent;
|
struct menu *parent;
|
||||||
struct menu *submenu;
|
struct menu *submenu;
|
||||||
bool selectable;
|
bool selectable;
|
||||||
|
enum menuitem_type type;
|
||||||
int height;
|
int height;
|
||||||
int native_width;
|
int native_width;
|
||||||
struct wlr_scene_tree *tree;
|
struct wlr_scene_tree *tree;
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ struct theme {
|
||||||
int menu_separator_padding_height;
|
int menu_separator_padding_height;
|
||||||
float menu_separator_color[4];
|
float menu_separator_color[4];
|
||||||
|
|
||||||
|
float menu_title_bg_color[4];
|
||||||
|
|
||||||
int osd_border_width;
|
int osd_border_width;
|
||||||
|
|
||||||
float osd_bg_color[4];
|
float osd_bg_color[4];
|
||||||
|
|
|
||||||
112
src/menu/menu.c
112
src/menu/menu.c
|
|
@ -114,17 +114,27 @@ menu_update_width(struct menu *menu)
|
||||||
wlr_scene_rect_from_node(item->normal.background),
|
wlr_scene_rect_from_node(item->normal.background),
|
||||||
menu->size.width, item->height);
|
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_set_size(
|
||||||
wlr_scene_rect_from_node(item->normal.text),
|
wlr_scene_rect_from_node(item->normal.text),
|
||||||
menu->size.width - 2 * theme->menu_separator_padding_width,
|
width, theme->menu_separator_line_thickness);
|
||||||
theme->menu_separator_line_thickness);
|
}
|
||||||
} else {
|
|
||||||
/* Usual menu item */
|
if (!item->selected.background) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
wlr_scene_rect_set_size(
|
wlr_scene_rect_set_size(
|
||||||
wlr_scene_rect_from_node(item->selected.background),
|
wlr_scene_rect_from_node(item->selected.background),
|
||||||
menu->size.width, item->height);
|
menu->size.width, item->height);
|
||||||
|
|
||||||
if (item->native_width > max_width || item->submenu || item->execute) {
|
if (item->native_width > max_width || item->submenu || item->execute) {
|
||||||
scaled_font_buffer_set_max_width(item->normal.buffer,
|
scaled_font_buffer_set_max_width(item->normal.buffer,
|
||||||
max_width);
|
max_width);
|
||||||
|
|
@ -132,7 +142,6 @@ menu_update_width(struct menu *menu)
|
||||||
max_width);
|
max_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -178,11 +187,13 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
|
||||||
struct menuitem *menuitem = znew(*menuitem);
|
struct menuitem *menuitem = znew(*menuitem);
|
||||||
menuitem->parent = menu;
|
menuitem->parent = menu;
|
||||||
menuitem->selectable = true;
|
menuitem->selectable = true;
|
||||||
|
menuitem->type = LAB_MENU_ITEM;
|
||||||
struct server *server = menu->server;
|
struct server *server = menu->server;
|
||||||
struct theme *theme = server->theme;
|
struct theme *theme = server->theme;
|
||||||
|
|
||||||
const char *arrow = show_arrow ? "›" : NULL;
|
const char *arrow = show_arrow ? "›" : NULL;
|
||||||
|
|
||||||
|
/* TODO: Consider setting this somewhere else */
|
||||||
if (!menu->item_height) {
|
if (!menu->item_height) {
|
||||||
menu->item_height = font_height(&rc.font_menuitem)
|
menu->item_height = font_height(&rc.font_menuitem)
|
||||||
+ 2 * theme->menu_item_padding_y;
|
+ 2 * theme->menu_item_padding_y;
|
||||||
|
|
@ -265,33 +276,69 @@ separator_create(struct menu *menu, const char *label)
|
||||||
struct menuitem *menuitem = znew(*menuitem);
|
struct menuitem *menuitem = znew(*menuitem);
|
||||||
menuitem->parent = menu;
|
menuitem->parent = menu;
|
||||||
menuitem->selectable = false;
|
menuitem->selectable = false;
|
||||||
|
menuitem->type = label ? LAB_MENU_TITLE : LAB_MENU_SEPARATOR_LINE;
|
||||||
struct server *server = menu->server;
|
struct server *server = menu->server;
|
||||||
struct theme *theme = server->theme;
|
struct theme *theme = server->theme;
|
||||||
|
|
||||||
|
if (!menu->item_height) {
|
||||||
|
menu->item_height = font_height(&rc.font_menuitem)
|
||||||
|
+ 2 * theme->menu_item_padding_y;
|
||||||
|
}
|
||||||
|
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 +
|
menuitem->height = theme->menu_separator_line_thickness +
|
||||||
2 * theme->menu_separator_padding_height;
|
2 * theme->menu_separator_padding_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu item root node */
|
||||||
menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
|
menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
|
||||||
node_descriptor_create(&menuitem->tree->node,
|
node_descriptor_create(&menuitem->tree->node,
|
||||||
LAB_NODE_DESC_MENUITEM, menuitem);
|
LAB_NODE_DESC_MENUITEM, menuitem);
|
||||||
|
|
||||||
|
/* Tree to hold background and text/line buffer */
|
||||||
menuitem->normal.tree = wlr_scene_tree_create(menuitem->tree);
|
menuitem->normal.tree = wlr_scene_tree_create(menuitem->tree);
|
||||||
|
|
||||||
|
/* Item background nodes */
|
||||||
|
float *bg_color = label ? theme->menu_title_bg_color : theme->menu_items_bg_color;
|
||||||
menuitem->normal.background = &wlr_scene_rect_create(
|
menuitem->normal.background = &wlr_scene_rect_create(
|
||||||
menuitem->normal.tree,
|
menuitem->normal.tree,
|
||||||
menu->size.width, menuitem->height,
|
menu->size.width, menuitem->height, bg_color)->node;
|
||||||
theme->menu_items_bg_color)->node;
|
|
||||||
|
|
||||||
int width = menu->size.width - 2 * theme->menu_separator_padding_width;
|
/* 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.text = &wlr_scene_rect_create(
|
||||||
menuitem->normal.tree,
|
menuitem->normal.tree, nominal_width,
|
||||||
width > 0 ? width : 0,
|
|
||||||
theme->menu_separator_line_thickness,
|
theme->menu_separator_line_thickness,
|
||||||
theme->menu_separator_color)->node;
|
theme->menu_separator_color)->node;
|
||||||
|
|
||||||
wlr_scene_node_set_position(&menuitem->tree->node, 0, menu->size.height);
|
wlr_scene_node_set_position(&menuitem->tree->node, 0, menu->size.height);
|
||||||
|
|
||||||
/* Vertically center-align separator line */
|
/* Vertically center-align separator line */
|
||||||
wlr_scene_node_set_position(menuitem->normal.text,
|
wlr_scene_node_set_position(menuitem->normal.text,
|
||||||
theme->menu_separator_padding_width,
|
theme->menu_separator_padding_width
|
||||||
|
+ theme->menu_item_padding_x,
|
||||||
theme->menu_separator_padding_height);
|
theme->menu_separator_padding_height);
|
||||||
|
}
|
||||||
|
wlr_scene_node_set_position(&menuitem->tree->node, 0, menu->size.height);
|
||||||
|
|
||||||
menu->size.height += menuitem->height;
|
menu->size.height += menuitem->height;
|
||||||
wl_list_append(&menu->menuitems, &menuitem->link);
|
wl_list_append(&menu->menuitems, &menuitem->link);
|
||||||
|
|
@ -507,26 +554,18 @@ handle_menu_element(xmlNode *n, struct server *server)
|
||||||
if (execute && label && id) {
|
if (execute && label && id) {
|
||||||
wlr_log(WLR_DEBUG, "pipemenu '%s:%s:%s'", id, label, execute);
|
wlr_log(WLR_DEBUG, "pipemenu '%s:%s:%s'", id, label, execute);
|
||||||
if (!current_menu) {
|
if (!current_menu) {
|
||||||
/*
|
current_menu = menu_create(server, id, label);
|
||||||
* We currently do not support pipemenus without a
|
current_menu->is_pipemenu = true;
|
||||||
* parent <item> such as the one the example below:
|
|
||||||
*
|
|
||||||
* <?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
* <openbox_menu>
|
|
||||||
* <menu id="root-menu" label="foo" execute="bar"/>
|
|
||||||
* </openbox_menu>
|
|
||||||
*
|
|
||||||
* TODO: Consider supporting this
|
|
||||||
*/
|
|
||||||
wlr_log(WLR_ERROR,
|
|
||||||
"pipemenu '%s:%s:%s' has no parent <menu>",
|
|
||||||
id, label, execute);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
current_item = item_create(current_menu, label, /* arrow */ true);
|
current_item = item_create(current_menu, label, /* arrow */ true);
|
||||||
current_item_action = NULL;
|
current_item_action = NULL;
|
||||||
current_item->execute = xstrdup(execute);
|
current_item->execute = xstrdup(execute);
|
||||||
current_item->id = xstrdup(id);
|
current_item->id = xstrdup(id);
|
||||||
|
} else {
|
||||||
|
current_item = item_create(current_menu, label, /* arrow */ true);
|
||||||
|
current_item_action = NULL;
|
||||||
|
current_item->execute = xstrdup(execute);
|
||||||
|
current_item->id = xstrdup(id);
|
||||||
|
}
|
||||||
} else if ((label && id) || is_toplevel_static_menu_definition(n, id)) {
|
} else if ((label && id) || is_toplevel_static_menu_definition(n, id)) {
|
||||||
/*
|
/*
|
||||||
* (label && id) refers to <menu id="" label=""> which is an
|
* (label && id) refers to <menu id="" label=""> which is an
|
||||||
|
|
@ -582,7 +621,16 @@ handle_menu_element(xmlNode *n, struct server *server)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct menu *menu = menu_get_by_id(server, id);
|
struct menu *menu = menu_get_by_id(server, id);
|
||||||
if (menu) {
|
if (menu && menu->is_pipemenu) {
|
||||||
|
current_item = item_create(current_menu, menu->label, true);
|
||||||
|
struct menuitem *item;
|
||||||
|
wl_list_for_each(item, &menu->menuitems, link) {
|
||||||
|
current_item->execute = xstrdup(item->execute);
|
||||||
|
char buffer[256];
|
||||||
|
sprintf(buffer, "%s%d", item->id, rand());
|
||||||
|
current_item->id = xstrdup(buffer);
|
||||||
|
}
|
||||||
|
} else if (menu) {
|
||||||
current_item = item_create(current_menu, menu->label, true);
|
current_item = item_create(current_menu, menu->label, true);
|
||||||
if (current_item) {
|
if (current_item) {
|
||||||
current_item->submenu = menu;
|
current_item->submenu = menu;
|
||||||
|
|
|
||||||
|
|
@ -526,6 +526,8 @@ theme_builtin(struct theme *theme, struct server *server)
|
||||||
theme->menu_separator_padding_height = 3;
|
theme->menu_separator_padding_height = 3;
|
||||||
parse_hexstr("#888888", theme->menu_separator_color);
|
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 = 600;
|
||||||
theme->osd_window_switcher_width_is_percent = false;
|
theme->osd_window_switcher_width_is_percent = false;
|
||||||
theme->osd_window_switcher_padding = 4;
|
theme->osd_window_switcher_padding = 4;
|
||||||
|
|
@ -755,6 +757,10 @@ entry(struct theme *theme, const char *key, const char *value)
|
||||||
parse_hexstr(value, theme->menu_separator_color);
|
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")) {
|
if (match_glob(key, "osd.bg.color")) {
|
||||||
parse_hexstr(value, theme->osd_bg_color);
|
parse_hexstr(value, theme->osd_bg_color);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue