mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
menu: Dynamically adjust menu width based on widest item
Adds two new theme vars: - menu.width.min (menu will never be smaller than this) - menu.width.max (menu will never be wider than this + padding) A fixed menu width can be achieved by setting menu.width.min == menu.width.max.
This commit is contained in:
parent
f0666ba5c9
commit
d00327bc32
7 changed files with 115 additions and 14 deletions
|
|
@ -59,6 +59,14 @@ A theme consists of a themerc file and optionally some xbm icons.
|
|||
Vertical offset in pixels between submenus and their parents. Positive
|
||||
values for downwards and negative for upwards. Default is 0.
|
||||
|
||||
*menu.width.min*
|
||||
Minimal width for menus. Default is 20.
|
||||
A fixed width can be achieved by setting .min and .max to the same value.
|
||||
|
||||
*menu.width.max*
|
||||
Maximal width for menus. Default is 200.
|
||||
A fixed width can be achieved by setting .min and .max to the same value.
|
||||
|
||||
*window.active.border.color*
|
||||
Border color of active window
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ struct scaled_font_buffer {
|
|||
/**
|
||||
* Create an auto scaling font buffer, providing a wlr_scene_buffer node for
|
||||
* display. It gets destroyed automatically when the backing scaled_scene_buffer
|
||||
* is being destoyed which in turn happens automatically when the backing
|
||||
* is being destroyed which in turn happens automatically when the backing
|
||||
* wlr_scene_buffer (or one of its parents) is being destroyed.
|
||||
*
|
||||
* To actually show some text, scaled_font_buffer_update() has to be called.
|
||||
|
|
@ -48,4 +48,12 @@ struct scaled_font_buffer *scaled_font_buffer_create(struct wlr_scene_tree *pare
|
|||
void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
|
||||
int max_width, struct font *font, float *color, const char *arrow);
|
||||
|
||||
/**
|
||||
* Update the max width of an existing auto scaling font buffer
|
||||
* and force a new render.
|
||||
*
|
||||
* No steps are taken to detect if its actually required to render a new buffer.
|
||||
*/
|
||||
void scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width);
|
||||
|
||||
#endif /* __LAB_COMMON_SCALED_FONT_BUFFER_H */
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ struct menuitem {
|
|||
struct menu *submenu;
|
||||
bool selectable;
|
||||
int height;
|
||||
int native_width;
|
||||
struct wlr_scene_tree *tree;
|
||||
struct menu_scene normal;
|
||||
struct menu_scene selected;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ struct theme {
|
|||
float menu_items_active_bg_color[4];
|
||||
float menu_items_active_text_color[4];
|
||||
|
||||
int menu_min_width;
|
||||
int menu_max_width;
|
||||
|
||||
int menu_separator_line_thickness;
|
||||
int menu_separator_padding_width;
|
||||
int menu_separator_padding_height;
|
||||
|
|
|
|||
|
|
@ -90,3 +90,10 @@ scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
|
|||
/* Invalidate cache and force a new render */
|
||||
scaled_scene_buffer_invalidate_cache(self->scaled_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width)
|
||||
{
|
||||
self->max_width = max_width;
|
||||
scaled_scene_buffer_invalidate_cache(self->scaled_buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@
|
|||
#include "common/mem.h"
|
||||
#include "common/nodename.h"
|
||||
#include "common/scaled_font_buffer.h"
|
||||
#include "common/scene-helpers.h"
|
||||
#include "common/string-helpers.h"
|
||||
#include "labwc.h"
|
||||
#include "menu/menu.h"
|
||||
#include "node.h"
|
||||
#include "theme.h"
|
||||
|
||||
#define MENUWIDTH (110)
|
||||
|
||||
/* state-machine variables for processing <item></item> */
|
||||
static bool in_item;
|
||||
static struct menuitem *current_item;
|
||||
|
|
@ -52,7 +51,7 @@ menu_create(struct server *server, const char *id, const char *label)
|
|||
menu->label = xstrdup(label ? label : id);
|
||||
menu->parent = current_menu;
|
||||
menu->server = server;
|
||||
menu->size.width = MENUWIDTH;
|
||||
menu->size.width = server->theme->menu_min_width;
|
||||
/* menu->size.height will be kept up to date by adding items */
|
||||
menu->scene_tree = wlr_scene_tree_create(server->menu_tree);
|
||||
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
|
||||
|
|
@ -75,6 +74,59 @@ menu_get_by_id(const char *id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_update_width(struct menu *menu)
|
||||
{
|
||||
struct menuitem *item;
|
||||
struct theme *theme = menu->server->theme;
|
||||
int max_width = theme->menu_min_width;
|
||||
|
||||
/* Get widest menu item, clamped by menu_max_width */
|
||||
wl_list_for_each(item, &menu->menuitems, link) {
|
||||
if (item->native_width > max_width) {
|
||||
max_width = item->native_width < theme->menu_max_width
|
||||
? item->native_width : theme->menu_max_width;
|
||||
}
|
||||
}
|
||||
menu->size.width = max_width + 2 * theme->menu_item_padding_x;
|
||||
|
||||
/* Update all items for the new size */
|
||||
wl_list_for_each(item, &menu->menuitems, link) {
|
||||
wlr_scene_rect_set_size(
|
||||
lab_wlr_scene_get_rect(item->normal.background),
|
||||
menu->size.width, item->height);
|
||||
|
||||
if (!item->selected.background) {
|
||||
/* This is a separator. They don't have a selected background. */
|
||||
wlr_scene_rect_set_size(
|
||||
lab_wlr_scene_get_rect(item->normal.text),
|
||||
menu->size.width - 2 * theme->menu_separator_padding_width,
|
||||
theme->menu_separator_line_thickness);
|
||||
} else {
|
||||
/* Usual menu item */
|
||||
wlr_scene_rect_set_size(
|
||||
lab_wlr_scene_get_rect(item->selected.background),
|
||||
menu->size.width, item->height);
|
||||
if (item->native_width > max_width || item->submenu) {
|
||||
scaled_font_buffer_set_max_width(item->normal.buffer,
|
||||
max_width);
|
||||
scaled_font_buffer_set_max_width(item->selected.buffer,
|
||||
max_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
post_processing(struct server *server)
|
||||
{
|
||||
struct menu *menu;
|
||||
for (int i = 0; i < nr_menus; ++i) {
|
||||
menu = menus + i;
|
||||
menu_update_width(menu);
|
||||
}
|
||||
}
|
||||
|
||||
static struct menuitem *
|
||||
item_create(struct menu *menu, const char *text, bool show_arrow)
|
||||
{
|
||||
|
|
@ -84,6 +136,8 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
|
|||
struct server *server = menu->server;
|
||||
struct theme *theme = server->theme;
|
||||
|
||||
const char *arrow = show_arrow ? "›" : NULL;
|
||||
|
||||
if (!menu->item_height) {
|
||||
menu->item_height = font_height(&rc.font_menuitem)
|
||||
+ 2 * theme->menu_item_padding_y;
|
||||
|
|
@ -91,7 +145,10 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
|
|||
menuitem->height = menu->item_height;
|
||||
|
||||
int x, y;
|
||||
int item_max_width = MENUWIDTH - 2 * theme->menu_item_padding_x;
|
||||
menuitem->native_width = font_width(&rc.font_menuitem, text);
|
||||
if (arrow) {
|
||||
menuitem->native_width += font_width(&rc.font_menuitem, arrow);
|
||||
}
|
||||
|
||||
/* Menu item root node */
|
||||
menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
|
||||
|
|
@ -105,11 +162,11 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
|
|||
/* Item background nodes */
|
||||
menuitem->normal.background = &wlr_scene_rect_create(
|
||||
menuitem->normal.tree,
|
||||
MENUWIDTH, menu->item_height,
|
||||
menu->size.width, menu->item_height,
|
||||
theme->menu_items_bg_color)->node;
|
||||
menuitem->selected.background = &wlr_scene_rect_create(
|
||||
menuitem->selected.tree,
|
||||
MENUWIDTH, menu->item_height,
|
||||
menu->size.width, menu->item_height,
|
||||
theme->menu_items_active_bg_color)->node;
|
||||
|
||||
/* Font nodes */
|
||||
|
|
@ -129,10 +186,9 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
|
|||
menuitem->selected.text = &menuitem->selected.buffer->scene_buffer->node;
|
||||
|
||||
/* Font buffers */
|
||||
const char *arrow = show_arrow ? "›" : NULL;
|
||||
scaled_font_buffer_update(menuitem->normal.buffer, text, item_max_width,
|
||||
scaled_font_buffer_update(menuitem->normal.buffer, text, menuitem->native_width,
|
||||
&rc.font_menuitem, theme->menu_items_text_color, arrow);
|
||||
scaled_font_buffer_update(menuitem->selected.buffer, text, item_max_width,
|
||||
scaled_font_buffer_update(menuitem->selected.buffer, text, menuitem->native_width,
|
||||
&rc.font_menuitem, theme->menu_items_active_text_color, arrow);
|
||||
|
||||
/* Center font nodes */
|
||||
|
|
@ -173,10 +229,10 @@ separator_create(struct menu *menu, const char *label)
|
|||
menuitem->normal.tree = wlr_scene_tree_create(menuitem->tree);
|
||||
menuitem->normal.background = &wlr_scene_rect_create(
|
||||
menuitem->normal.tree,
|
||||
MENUWIDTH, menuitem->height,
|
||||
menu->size.width, menuitem->height,
|
||||
theme->menu_items_bg_color)->node;
|
||||
|
||||
int width = MENUWIDTH - 2 * theme->menu_separator_padding_width;
|
||||
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,
|
||||
|
|
@ -511,7 +567,7 @@ menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
|
|||
}
|
||||
|
||||
if (align & LAB_MENU_OPEN_LEFT) {
|
||||
lx -= MENUWIDTH - theme->menu_overlap_x;
|
||||
lx -= menu->size.width - theme->menu_overlap_x;
|
||||
}
|
||||
if (align & LAB_MENU_OPEN_TOP) {
|
||||
ly -= menu->size.height;
|
||||
|
|
@ -530,7 +586,7 @@ menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
|
|||
continue;
|
||||
}
|
||||
if (align & LAB_MENU_OPEN_RIGHT) {
|
||||
new_lx = lx + MENUWIDTH - theme->menu_overlap_x;
|
||||
new_lx = lx + menu->size.width - theme->menu_overlap_x;
|
||||
} else {
|
||||
new_lx = lx;
|
||||
}
|
||||
|
|
@ -642,6 +698,7 @@ menu_init(struct server *server)
|
|||
{
|
||||
init_rootmenu(server);
|
||||
init_windowmenu(server);
|
||||
post_processing(server);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
17
src/theme.c
17
src/theme.c
|
|
@ -131,6 +131,9 @@ theme_builtin(struct theme *theme)
|
|||
theme->menu_item_padding_x = 7;
|
||||
theme->menu_item_padding_y = 4;
|
||||
|
||||
theme->menu_min_width = 20;
|
||||
theme->menu_max_width = 200;
|
||||
|
||||
theme->menu_separator_line_thickness = 1;
|
||||
theme->menu_separator_padding_width = 6;
|
||||
theme->menu_separator_padding_height = 3;
|
||||
|
|
@ -260,6 +263,13 @@ entry(struct theme *theme, const char *key, const char *value)
|
|||
theme->window_inactive_button_close_unpressed_image_color);
|
||||
}
|
||||
|
||||
if (match(key, "menu.width.min")) {
|
||||
theme->menu_min_width = atoi(value);
|
||||
}
|
||||
if (match(key, "menu.width.max")) {
|
||||
theme->menu_max_width = atoi(value);
|
||||
}
|
||||
|
||||
if (match(key, "menu.items.bg.color")) {
|
||||
parse_hexstr(value, theme->menu_items_bg_color);
|
||||
}
|
||||
|
|
@ -488,6 +498,13 @@ post_processing(struct theme *theme)
|
|||
theme->title_height = rc.corner_radius + 1;
|
||||
}
|
||||
|
||||
if (theme->menu_max_width < theme->menu_min_width) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Adjusting menu.width.max: .max (%d) lower than .min (%d)",
|
||||
theme->menu_max_width, theme->menu_min_width);
|
||||
theme->menu_max_width = theme->menu_min_width;
|
||||
}
|
||||
|
||||
/* Inherit OSD settings if not set */
|
||||
if (theme->osd_bg_color[0] == FLT_MIN) {
|
||||
memcpy(theme->osd_bg_color,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue