mirror of
https://github.com/labwc/labwc.git
synced 2026-02-08 10:06:59 -05: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
|
Vertical offset in pixels between submenus and their parents. Positive
|
||||||
values for downwards and negative for upwards. Default is 0.
|
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*
|
*window.active.border.color*
|
||||||
Border color of active window
|
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
|
* Create an auto scaling font buffer, providing a wlr_scene_buffer node for
|
||||||
* display. It gets destroyed automatically when the backing scaled_scene_buffer
|
* 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.
|
* wlr_scene_buffer (or one of its parents) is being destroyed.
|
||||||
*
|
*
|
||||||
* To actually show some text, scaled_font_buffer_update() has to be called.
|
* 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,
|
void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
|
||||||
int max_width, struct font *font, float *color, const char *arrow);
|
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 */
|
#endif /* __LAB_COMMON_SCALED_FONT_BUFFER_H */
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ struct menuitem {
|
||||||
struct menu *submenu;
|
struct menu *submenu;
|
||||||
bool selectable;
|
bool selectable;
|
||||||
int height;
|
int height;
|
||||||
|
int native_width;
|
||||||
struct wlr_scene_tree *tree;
|
struct wlr_scene_tree *tree;
|
||||||
struct menu_scene normal;
|
struct menu_scene normal;
|
||||||
struct menu_scene selected;
|
struct menu_scene selected;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,9 @@ struct theme {
|
||||||
float menu_items_active_bg_color[4];
|
float menu_items_active_bg_color[4];
|
||||||
float menu_items_active_text_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_line_thickness;
|
||||||
int menu_separator_padding_width;
|
int menu_separator_padding_width;
|
||||||
int menu_separator_padding_height;
|
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 */
|
/* Invalidate cache and force a new render */
|
||||||
scaled_scene_buffer_invalidate_cache(self->scaled_buffer);
|
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/mem.h"
|
||||||
#include "common/nodename.h"
|
#include "common/nodename.h"
|
||||||
#include "common/scaled_font_buffer.h"
|
#include "common/scaled_font_buffer.h"
|
||||||
|
#include "common/scene-helpers.h"
|
||||||
#include "common/string-helpers.h"
|
#include "common/string-helpers.h"
|
||||||
#include "labwc.h"
|
#include "labwc.h"
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
|
||||||
#define MENUWIDTH (110)
|
|
||||||
|
|
||||||
/* state-machine variables for processing <item></item> */
|
/* state-machine variables for processing <item></item> */
|
||||||
static bool in_item;
|
static bool in_item;
|
||||||
static struct menuitem *current_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->label = xstrdup(label ? label : id);
|
||||||
menu->parent = current_menu;
|
menu->parent = current_menu;
|
||||||
menu->server = server;
|
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->size.height will be kept up to date by adding items */
|
||||||
menu->scene_tree = wlr_scene_tree_create(server->menu_tree);
|
menu->scene_tree = wlr_scene_tree_create(server->menu_tree);
|
||||||
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
|
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
|
||||||
|
|
@ -75,6 +74,59 @@ menu_get_by_id(const char *id)
|
||||||
return NULL;
|
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 *
|
static struct menuitem *
|
||||||
item_create(struct menu *menu, const char *text, bool show_arrow)
|
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 server *server = menu->server;
|
||||||
struct theme *theme = server->theme;
|
struct theme *theme = server->theme;
|
||||||
|
|
||||||
|
const char *arrow = show_arrow ? "›" : NULL;
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -91,7 +145,10 @@ item_create(struct menu *menu, const char *text, bool show_arrow)
|
||||||
menuitem->height = menu->item_height;
|
menuitem->height = menu->item_height;
|
||||||
|
|
||||||
int x, y;
|
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 */
|
/* Menu item root node */
|
||||||
menuitem->tree = wlr_scene_tree_create(menu->scene_tree);
|
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 */
|
/* Item background nodes */
|
||||||
menuitem->normal.background = &wlr_scene_rect_create(
|
menuitem->normal.background = &wlr_scene_rect_create(
|
||||||
menuitem->normal.tree,
|
menuitem->normal.tree,
|
||||||
MENUWIDTH, menu->item_height,
|
menu->size.width, menu->item_height,
|
||||||
theme->menu_items_bg_color)->node;
|
theme->menu_items_bg_color)->node;
|
||||||
menuitem->selected.background = &wlr_scene_rect_create(
|
menuitem->selected.background = &wlr_scene_rect_create(
|
||||||
menuitem->selected.tree,
|
menuitem->selected.tree,
|
||||||
MENUWIDTH, menu->item_height,
|
menu->size.width, menu->item_height,
|
||||||
theme->menu_items_active_bg_color)->node;
|
theme->menu_items_active_bg_color)->node;
|
||||||
|
|
||||||
/* Font nodes */
|
/* 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;
|
menuitem->selected.text = &menuitem->selected.buffer->scene_buffer->node;
|
||||||
|
|
||||||
/* Font buffers */
|
/* Font buffers */
|
||||||
const char *arrow = show_arrow ? "›" : NULL;
|
scaled_font_buffer_update(menuitem->normal.buffer, text, menuitem->native_width,
|
||||||
scaled_font_buffer_update(menuitem->normal.buffer, text, item_max_width,
|
|
||||||
&rc.font_menuitem, theme->menu_items_text_color, arrow);
|
&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);
|
&rc.font_menuitem, theme->menu_items_active_text_color, arrow);
|
||||||
|
|
||||||
/* Center font nodes */
|
/* 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.tree = wlr_scene_tree_create(menuitem->tree);
|
||||||
menuitem->normal.background = &wlr_scene_rect_create(
|
menuitem->normal.background = &wlr_scene_rect_create(
|
||||||
menuitem->normal.tree,
|
menuitem->normal.tree,
|
||||||
MENUWIDTH, menuitem->height,
|
menu->size.width, menuitem->height,
|
||||||
theme->menu_items_bg_color)->node;
|
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.text = &wlr_scene_rect_create(
|
||||||
menuitem->normal.tree,
|
menuitem->normal.tree,
|
||||||
width > 0 ? width : 0,
|
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) {
|
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) {
|
if (align & LAB_MENU_OPEN_TOP) {
|
||||||
ly -= menu->size.height;
|
ly -= menu->size.height;
|
||||||
|
|
@ -530,7 +586,7 @@ menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (align & LAB_MENU_OPEN_RIGHT) {
|
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 {
|
} else {
|
||||||
new_lx = lx;
|
new_lx = lx;
|
||||||
}
|
}
|
||||||
|
|
@ -642,6 +698,7 @@ menu_init(struct server *server)
|
||||||
{
|
{
|
||||||
init_rootmenu(server);
|
init_rootmenu(server);
|
||||||
init_windowmenu(server);
|
init_windowmenu(server);
|
||||||
|
post_processing(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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_x = 7;
|
||||||
theme->menu_item_padding_y = 4;
|
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_line_thickness = 1;
|
||||||
theme->menu_separator_padding_width = 6;
|
theme->menu_separator_padding_width = 6;
|
||||||
theme->menu_separator_padding_height = 3;
|
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);
|
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")) {
|
if (match(key, "menu.items.bg.color")) {
|
||||||
parse_hexstr(value, theme->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;
|
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 */
|
/* Inherit OSD settings if not set */
|
||||||
if (theme->osd_bg_color[0] == FLT_MIN) {
|
if (theme->osd_bg_color[0] == FLT_MIN) {
|
||||||
memcpy(theme->osd_bg_color,
|
memcpy(theme->osd_bg_color,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue