Skip to content

Commit 1bef426

Browse files
committed
Implement built-in clickable menu rendering
Add menu button drawing function. Update layout calculations for menu height. Integrate menu rendering into notification display. Signed-off-by: LI Qingwu <[email protected]>
1 parent fe80859 commit 1bef426

File tree

1 file changed

+164
-8
lines changed

1 file changed

+164
-8
lines changed

src/draw.c

Lines changed: 164 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "settings.h"
2222
#include "utils.h"
2323
#include "icon-lookup.h"
24+
#include "menu.h"
2425

2526
struct colored_layout {
2627
PangoLayout *l;
@@ -36,6 +37,11 @@ window win;
3637

3738
PangoFontDescription *pango_fdesc;
3839

40+
static int calculate_menu_height(const struct colored_layout *cl);
41+
static int calculate_max_button_width(const struct colored_layout *cl);
42+
static int calculate_menu_per_row(const struct colored_layout *cl);
43+
static int calculate_menu_rows(const struct colored_layout *cl);
44+
3945
// NOTE: Saves some characters
4046
#define COLOR(cl, field) (cl)->n->colors.field
4147

@@ -233,6 +239,13 @@ static bool have_progress_bar(const struct colored_layout *cl)
233239
!cl->is_xmore);
234240
}
235241

242+
static bool have_built_in_menu(const struct colored_layout *cl)
243+
{
244+
return (g_hash_table_size(cl->n->actions)>0 &&
245+
settings.built_in_menu == true &&
246+
!cl->is_xmore);
247+
}
248+
236249
static void get_text_size(PangoLayout *l, int *w, int *h, double scale) {
237250
pango_layout_get_pixel_size(l, w, h);
238251
// scale the size down, because it may be rendered at higher DPI
@@ -321,6 +334,8 @@ static struct dimensions calculate_notification_dimensions(struct colored_layout
321334
if (have_progress_bar(cl))
322335
dim.w = MAX(settings.progress_bar_min_width, dim.w);
323336

337+
dim.h += calculate_menu_height(cl);
338+
324339
dim.h = MAX(settings.height.min, dim.h);
325340
dim.h = MIN(settings.height.max, dim.h);
326341

@@ -442,6 +457,10 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
442457
g_error_free(err);
443458
}
444459

460+
if (have_built_in_menu(cl)) {
461+
menu_init(n);
462+
}
463+
445464
n->first_render = false;
446465
return cl;
447466
}
@@ -502,7 +521,7 @@ static int layout_get_height(struct colored_layout *cl, double scale)
502521

503522
return (cl->n->icon_position == ICON_TOP && cl->n->icon)
504523
? h_icon + h_text + h_progress_bar + vertical_padding
505-
: MAX(h_text, h_icon) + h_progress_bar;
524+
: MAX(h_text, h_icon) + h_progress_bar + calculate_menu_height(cl);
506525
}
507526

508527
/* Attempt to make internal radius more organic.
@@ -699,6 +718,132 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int
699718
cairo_close_path(c);
700719
}
701720

721+
722+
static int calculate_max_button_width(const struct colored_layout *cl)
723+
{
724+
int buttons = menu_get_count(cl->n);
725+
if (buttons == 0) {
726+
return 0;
727+
}
728+
const PangoFontDescription *desc = pango_layout_get_font_description(cl->l);
729+
const int fontsize = pango_font_description_get_size(desc) / PANGO_SCALE;
730+
int max_text_width = 0;
731+
for (int i = 0; i < buttons; i++) {
732+
char *label = menu_get_label(cl->n, i);
733+
if (!label) {
734+
continue;
735+
}
736+
int text_width = strlen(label) * fontsize;
737+
if (text_width > max_text_width) {
738+
max_text_width = text_width;
739+
}
740+
}
741+
max_text_width = MAX(settings.menu_min_width, max_text_width);
742+
max_text_width = MIN(settings.menu_max_width, max_text_width);
743+
return max_text_width;
744+
}
745+
746+
static int calculate_menu_per_row(const struct colored_layout *cl)
747+
{
748+
int menu_width = calculate_max_button_width(cl);
749+
if (menu_width <= 0) {
750+
return 0;
751+
}
752+
753+
int menu_count = 300 / menu_width;
754+
menu_count = MIN(settings.menu_max_per_row, menu_count);
755+
return menu_count;
756+
}
757+
758+
static int calculate_menu_rows(const struct colored_layout *cl)
759+
{
760+
int buttons = menu_get_count(cl->n);
761+
if (buttons <= 0) {
762+
return 0;
763+
}
764+
765+
int max_per_row = calculate_menu_per_row(cl);
766+
if (max_per_row < 1) {
767+
max_per_row = 1;
768+
}
769+
770+
int needed_rows = (buttons + max_per_row - 1) / max_per_row;
771+
return MIN(needed_rows, settings.menu_max_rows);
772+
}
773+
774+
static int calculate_menu_height(const struct colored_layout *cl)
775+
{
776+
if (have_built_in_menu(cl)) {
777+
int rows = calculate_menu_rows(cl);
778+
return settings.menu_height * rows + settings.padding * rows;
779+
} else {
780+
return 0;
781+
}
782+
}
783+
784+
static void draw_built_in_menu(cairo_t *c, struct colored_layout *cl, int area_x, int area_y, int area_width,
785+
int area_height, double scale)
786+
{
787+
if (!have_built_in_menu(cl))
788+
return;
789+
790+
int buttons = menu_get_count(cl->n);
791+
if (buttons == 0) {
792+
return;
793+
}
794+
795+
int max_per_row = calculate_menu_per_row(cl);
796+
int rows = calculate_menu_rows(cl);
797+
int base_button_width = calculate_max_button_width(cl);
798+
799+
pango_layout_set_attributes(cl->l, NULL);
800+
pango_layout_set_font_description(cl->l, NULL);
801+
pango_layout_set_font_description(cl->l, pango_fdesc);
802+
PangoAttrList *attr = pango_attr_list_new();
803+
pango_layout_set_attributes(cl->l, attr);
804+
805+
for (int row = 0; row < rows; row++) {
806+
int buttons_in_row = MIN(buttons - row * max_per_row, max_per_row);
807+
base_button_width = (area_width - settings.padding * (buttons_in_row + 1)) / buttons_in_row;
808+
809+
for (int col = 0; col < buttons_in_row; col++) {
810+
int button_index = row * max_per_row + col;
811+
if (button_index >= buttons)
812+
break;
813+
814+
char *label = menu_get_label(cl->n, button_index);
815+
if (!label)
816+
continue;
817+
818+
int x = area_x + settings.padding + col * (base_button_width + settings.padding);
819+
int y = area_y + row * (settings.menu_height + settings.padding);
820+
menu_set_position(cl->n, button_index, x, y, base_button_width, settings.menu_height);
821+
822+
cairo_set_source_rgb(c, settings.menu_frame_color.r, settings.menu_frame_color.g,
823+
settings.menu_frame_color.b);
824+
cairo_set_line_width(c, settings.menu_frame_width);
825+
draw_rect(c, x, y, base_button_width, settings.menu_height, scale);
826+
827+
if (settings.menu_frame_fill)
828+
cairo_fill(c);
829+
else
830+
cairo_stroke(c);
831+
832+
pango_layout_set_text(cl->l, label, -1);
833+
834+
int text_width, text_height;
835+
pango_layout_get_pixel_size(cl->l, &text_width, &text_height);
836+
double text_x = x + (base_button_width - text_width) / 2;
837+
double text_y = y + (settings.menu_height - text_height) / 2;
838+
839+
cairo_set_source_rgba(c, COLOR(cl, fg.r), COLOR(cl, fg.g), COLOR(cl, fg.b), COLOR(cl, fg.a));
840+
cairo_move_to(c, text_x, text_y);
841+
pango_cairo_show_layout(c, cl->l);
842+
}
843+
}
844+
pango_attr_list_unref(attr);
845+
}
846+
702847
static cairo_surface_t *render_background(cairo_surface_t *srf,
703848
struct colored_layout *cl,
704849
struct colored_layout *cl_next,
@@ -784,10 +929,12 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, int
784929
layout_setup(cl, width, height, scale);
785930

786931
// NOTE: Includes paddings!
787-
int h_without_progress_bar = height;
788-
if (have_progress_bar(cl)) {
789-
h_without_progress_bar -= settings.progress_bar_height + settings.padding;
790-
}
932+
int h_text_and_icon = height;
933+
if (have_progress_bar(cl))
934+
h_text_and_icon -= settings.progress_bar_height + settings.padding;
935+
936+
if (have_built_in_menu(cl))
937+
h_text_and_icon -= calculate_menu_height(cl);
791938

792939
int text_h = 0;
793940
if (!cl->n->hide_text) {
@@ -799,9 +946,9 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, int
799946
text_y = settings.padding;
800947

801948
if (settings.vertical_alignment == VERTICAL_CENTER) {
802-
text_y = h_without_progress_bar / 2 - text_h / 2;
949+
text_y = h_text_and_icon / 2 - text_h / 2;
803950
} else if (settings.vertical_alignment == VERTICAL_BOTTOM) {
804-
text_y = h_without_progress_bar - settings.padding - text_h;
951+
text_y = h_text_and_icon - settings.padding - text_h;
805952
if (text_y < 0) text_y = settings.padding;
806953
} // else VERTICAL_TOP
807954

@@ -867,7 +1014,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, int
8671014
unsigned int frame_width = settings.progress_bar_frame_width,
8681015
progress_width = MIN(width - 2 * settings.h_padding, settings.progress_bar_max_width),
8691016
progress_height = settings.progress_bar_height - frame_width,
870-
frame_y = h_without_progress_bar,
1017+
frame_y = h_text_and_icon,
8711018
progress_width_without_frame = progress_width - 2 * frame_width,
8721019
progress_width_1 = progress_width_without_frame * progress / 100,
8731020
progress_width_2 = progress_width_without_frame - 1;
@@ -922,6 +1069,15 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, int
9221069
scale, settings.progress_bar_corners);
9231070
cairo_stroke(c);
9241071
}
1072+
1073+
if (have_built_in_menu(cl)) {
1074+
int y = h_text_and_icon;
1075+
if (have_progress_bar(cl)) {
1076+
y += settings.progress_bar_height + settings.padding;
1077+
}
1078+
draw_built_in_menu(c, cl, 0, y, width, height, scale);
1079+
}
1080+
9251081
}
9261082

9271083
static struct dimensions layout_render(cairo_surface_t *srf,

0 commit comments

Comments
 (0)