menu: Add fancy speech-bubble-style menus like Gnome has

This commit is contained in:
K. Lange 2021-06-23 20:58:06 +09:00
parent 7914841b4e
commit 5ec05e0925
2 changed files with 38 additions and 17 deletions

View File

@ -62,6 +62,7 @@ struct MenuList {
struct MenuList * parent; struct MenuList * parent;
struct menu_bar * _bar; struct menu_bar * _bar;
int closed; int closed;
int flags;
}; };
struct MenuSet { struct MenuSet {
@ -92,6 +93,11 @@ extern void menu_set_insert(struct MenuSet * set, char * action, struct MenuList
extern void menu_update_title(struct MenuEntry * self, char * new_title); extern void menu_update_title(struct MenuEntry * self, char * new_title);
extern void menu_force_redraw(struct MenuList * menu); extern void menu_force_redraw(struct MenuList * menu);
#define MENU_FLAG_BUBBLE_CENTER (1 << 0)
#define MENU_FLAG_BUBBLE_LEFT (1 << 1)
#define MENU_FLAG_BUBBLE_RIGHT (1 << 2)
#define MENU_FLAG_BUBBLE (MENU_FLAG_BUBBLE_LEFT | MENU_FLAG_BUBBLE_RIGHT | MENU_FLAG_BUBBLE_CENTER)
#define MENU_BAR_HEIGHT 24 #define MENU_BAR_HEIGHT 24
struct menu_bar_entries { struct menu_bar_entries {

View File

@ -356,7 +356,7 @@ static char * read_line(FILE * f, char * out, ssize_t len) {
static void _menu_calculate_dimensions(struct MenuList * menu, int * height, int * width) { static void _menu_calculate_dimensions(struct MenuList * menu, int * height, int * width) {
list_t * list = menu->entries; list_t * list = menu->entries;
*width = 0; *width = 0;
*height = 8; /* TODO top and height */ *height = (menu->flags & MENU_FLAG_BUBBLE) ? 16 : 8; /* TODO top and height */
foreach(node, list) { foreach(node, list) {
struct MenuEntry * entry = node->value; struct MenuEntry * entry = node->value;
*height += entry->height; *height += entry->height;
@ -394,6 +394,7 @@ struct MenuList * menu_create(void) {
p->_bar = NULL; p->_bar = NULL;
p->parent = NULL; p->parent = NULL;
p->closed = 1; p->closed = 1;
p->flags = 0;
return p; return p;
} }
@ -441,15 +442,8 @@ struct MenuSet * menu_set_from_description(const char * path, void (*callback)(s
if (*line == ':') { if (*line == ':') {
/* New menu */ /* New menu */
struct MenuList * p = malloc(sizeof(struct MenuList)); struct MenuList * p = menu_create();
p->entries = list_create();
p->ctx = NULL;
p->window = NULL;
p->set = _out; p->set = _out;
p->child = NULL;
p->_bar = NULL;
p->parent = NULL;
p->closed = 1;
hashmap_set(out, line+1, p); hashmap_set(out, line+1, p);
current_menu = p; current_menu = p;
} else if (*line == '#') { } else if (*line == '#') {
@ -522,16 +516,37 @@ static void _menu_redraw(yutani_window_t * menu_window, yutani_t * yctx, struct
gfx_context_t * ctx = menu->ctx; gfx_context_t * ctx = menu->ctx;
list_t * entries = menu->entries; list_t * entries = menu->entries;
/* Window background */ /* Window background */
draw_fill(ctx, MENU_BACKGROUND); if (menu->flags & MENU_FLAG_BUBBLE) {
draw_fill(ctx, rgba(0,0,0,0));
draw_rounded_rectangle(ctx, 0, 6, ctx->width, ctx->height - 6, 6, rgb(109,111,112));
draw_rounded_rectangle(ctx, 1, 7, ctx->width-2, ctx->height - 8, 5, MENU_BACKGROUND);
/* Window border */ /* Figure out where to draw the tail */
draw_line(ctx, 0, ctx->width-1, 0, 0, rgb(109,111,112)); int tail_left = 0;
draw_line(ctx, 0, 0, 0, ctx->height-1, rgb(109,111,112)); if (menu->flags & MENU_FLAG_BUBBLE_LEFT) {
draw_line(ctx, ctx->width-1, ctx->width-1, 0, ctx->height-1, rgb(109,111,112)); tail_left = 16;
draw_line(ctx, 0, ctx->width-1, ctx->height-1, ctx->height-1, rgb(109,111,112)); } else if (menu->flags & MENU_FLAG_BUBBLE_RIGHT) {
tail_left = ctx->width - 16;
} else if (menu->flags & MENU_FLAG_BUBBLE_CENTER) {
tail_left = ctx->width / 2;
}
for (int i = 1; i < 7; ++i) {
draw_line(ctx, tail_left - i, tail_left + i, i, i, MENU_BACKGROUND);
}
draw_line_aa(ctx, tail_left - 6, tail_left, 6, 0, rgb(109,111,112), 0.5);
draw_line_aa(ctx, tail_left + 6, tail_left, 6, 0, rgb(109,111,112), 0.5);
} else {
draw_fill(ctx, MENU_BACKGROUND);
/* Window border */
draw_line(ctx, 0, ctx->width-1, 0, 0, rgb(109,111,112));
draw_line(ctx, 0, 0, 0, ctx->height-1, rgb(109,111,112));
draw_line(ctx, ctx->width-1, ctx->width-1, 0, ctx->height-1, rgb(109,111,112));
draw_line(ctx, 0, ctx->width-1, ctx->height-1, ctx->height-1, rgb(109,111,112));
}
/* Draw menu entries */ /* Draw menu entries */
int offset = 4; int offset = (menu->flags & MENU_FLAG_BUBBLE) ? 12 : 4;
foreach(node, entries) { foreach(node, entries) {
struct MenuEntry * entry = node->value; struct MenuEntry * entry = node->value;
if (entry->renderer) { if (entry->renderer) {
@ -776,7 +791,7 @@ void menu_mouse_action(struct MenuList * menu, struct yutani_msg_window_mouse_ev
yutani_window_t * window = menu->window; yutani_window_t * window = menu->window;
yutani_t * yctx = window->ctx; yutani_t * yctx = window->ctx;
int offset = 4; int offset = (menu->flags & MENU_FLAG_BUBBLE) ? 12 : 4;
int changed = 0; int changed = 0;
foreach(node, menu->entries) { foreach(node, menu->entries) {
struct MenuEntry * entry = node->value; struct MenuEntry * entry = node->value;