From 89d7a81b9c687b7b6412e7ee951a2885e7fb15cd Mon Sep 17 00:00:00 2001 From: chronus Date: Sat, 25 Jan 2020 16:35:38 +0100 Subject: [PATCH 1/4] Adding vertical content alignment control. This adds the option `content_alignment`, which allows the user to set the vertical alignment of the notification's content (i.e. icon and text) to either top (`CONTENT_TOP`), center (`CONTENT_CENTER`, default), or bottom (`CONTENT_BOT`). The default preserves current behaviour, while the other options fulfill #486. --- src/draw.c | 61 ++++++++++++++++++++++++++++++++++----------- src/option_parser.c | 12 +++++++++ src/option_parser.h | 1 + src/settings.c | 15 +++++++++++ src/settings.h | 2 ++ 5 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/draw.c b/src/draw.c index 80468b5..a6275cc 100644 --- a/src/draw.c +++ b/src/draw.c @@ -511,32 +511,65 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) int h_text; pango_layout_get_pixel_size(cl->l, NULL, &h_text); - if (cl->icon && settings.icon_position == ICON_LEFT) { - cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, - settings.padding + h/2 - h_text/2); - } else if (cl->icon && settings.icon_position == ICON_RIGHT) { - cairo_move_to(c, settings.h_padding, settings.padding + h/2 - h_text/2); - } else { - cairo_move_to(c, settings.h_padding, settings.padding); + int text_x = settings.h_padding, + text_y = settings.padding + h / 2 - h_text / 2; + + // text positioning + if (cl->icon) { + // vertical alignment + switch (settings.content_alignment) { + case CONTENT_TOP: + text_y = settings.padding; + break; + case CONTENT_BOTTOM: + text_y = h + settings.padding - h_text; + if (text_y < 0) text_y = settings.padding; + break; + default: // CONTENT_CENTER + break; + } + // icon position + switch (settings.icon_position) { + case ICON_LEFT: + text_x = cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding; + break; + default: // ICON_RIGHT + break; + } } + cairo_move_to(c, text_x, text_y); cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b); pango_cairo_update_layout(c, cl->l); pango_cairo_show_layout(c, cl->l); + // icon positioning if (cl->icon) { unsigned int image_width = cairo_image_surface_get_width(cl->icon), image_height = cairo_image_surface_get_height(cl->icon), - image_x, + image_x = width - settings.h_padding - image_width, image_y = settings.padding + h/2 - image_height/2; - if (settings.icon_position == ICON_LEFT) { - image_x = settings.h_padding; - } else if (settings.icon_position == ICON_RIGHT){ - image_x = width - settings.h_padding - image_width; - } else { - LOG_E("Tried to draw icon but icon position is not valid. %s:%d", __FILE__, __LINE__); + // vertical alignment + switch (settings.content_alignment) { + case CONTENT_TOP: + image_y = settings.padding; + break; + case CONTENT_BOTTOM: + image_y = h + settings.padding - image_height; + if (image_y < 0 || image_y > h) image_y = settings.padding; + break; + default: // CONTENT_CENTER + break; + } + // icon position + switch (settings.icon_position) { + case ICON_LEFT: + image_x = settings.h_padding; + break; + default: // ICON_RIGHT + break; } cairo_set_source_surface(c, cl->icon, image_x, image_y); diff --git a/src/option_parser.c b/src/option_parser.c index 918be57..2b3b15b 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -103,6 +103,18 @@ bool string_parse_icon_position(const char *s, enum icon_position *ret) return false; } +bool string_parse_content_alignment(const char *s, enum content_alignment *ret) +{ + ASSERT_OR_RET(STR_FULL(s), false); + ASSERT_OR_RET(ret, false); + + STRING_PARSE_RET("top", CONTENT_TOP); + STRING_PARSE_RET("center", CONTENT_CENTER); + STRING_PARSE_RET("bottom", CONTENT_BOTTOM); + + return false; +} + bool string_parse_markup_mode(const char *s, enum markup_mode *ret) { ASSERT_OR_RET(STR_FULL(s), false); diff --git a/src/option_parser.h b/src/option_parser.h index 8d98618..d2d6d0e 100644 --- a/src/option_parser.h +++ b/src/option_parser.h @@ -14,6 +14,7 @@ bool string_parse_ellipsize(const char *s, enum ellipsize *ret); bool string_parse_follow_mode(const char *s, enum follow_mode *ret); bool string_parse_fullscreen(const char *s, enum behavior_fullscreen *ret); bool string_parse_icon_position(const char *s, enum icon_position *ret); +bool string_parse_content_alignment(const char *s, enum content_alignment *ret); bool string_parse_markup_mode(const char *s, enum markup_mode *ret); bool string_parse_mouse_action(const char *s, enum mouse_action *ret); bool string_parse_sepcolor(const char *s, struct separator_color_data *ret); diff --git a/src/settings.c b/src/settings.c index 90077fb..0d25529 100644 --- a/src/settings.c +++ b/src/settings.c @@ -423,6 +423,21 @@ void load_settings(char *cmdline_config_path) g_free(c); } + { + char *c = option_get_string( + "global", + "content_alignment", "-content_alignment", "center", + "Align icon and text top/center/bottom" + ); + if (!string_parse_content_alignment(c, &settings.content_alignment)) { + if (c) + LOG_W("Unknown content alignment: '%s'", c); + settings.content_alignment = defaults.content_alignment; + } + g_free(c); + + } + settings.min_icon_size = option_get_int( "global", "min_icon_size", "-min_icon_size", defaults.min_icon_size, diff --git a/src/settings.h b/src/settings.h index 6e541c2..0ab2d51 100644 --- a/src/settings.h +++ b/src/settings.h @@ -11,6 +11,7 @@ enum alignment { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; enum ellipsize { ELLIPSE_START, ELLIPSE_MIDDLE, ELLIPSE_END }; enum icon_position { ICON_LEFT, ICON_RIGHT, ICON_OFF }; +enum content_alignment { CONTENT_TOP, CONTENT_CENTER, CONTENT_BOTTOM }; enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM }; enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD }; enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL }; @@ -75,6 +76,7 @@ struct settings { char *browser; char **browser_cmd; enum icon_position icon_position; + enum content_alignment content_alignment; int min_icon_size; int max_icon_size; char *icon_path; From f9b6f6a066c627ffc46290d5c785cb233464a57c Mon Sep 17 00:00:00 2001 From: chronus Date: Sat, 25 Jan 2020 16:43:42 +0100 Subject: [PATCH 2/4] fixing comparison issue in bottom alignment --- src/draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.c b/src/draw.c index a6275cc..93f2e22 100644 --- a/src/draw.c +++ b/src/draw.c @@ -558,7 +558,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) break; case CONTENT_BOTTOM: image_y = h + settings.padding - image_height; - if (image_y < 0 || image_y > h) image_y = settings.padding; + if (image_y < settings.padding || image_y > h) image_y = settings.padding; break; default: // CONTENT_CENTER break; From e665eea97ef536430966457fbe0414c6ec4e759b Mon Sep 17 00:00:00 2001 From: chronus Date: Sun, 26 Jan 2020 11:44:31 +0100 Subject: [PATCH 3/4] adding `content_alignment` to config and documentation --- docs/dunst.pod | 5 +++++ dunstrc | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/docs/dunst.pod b/docs/dunst.pod index 4c25b2c..ab8e769 100644 --- a/docs/dunst.pod +++ b/docs/dunst.pod @@ -337,6 +337,11 @@ removed from the format. Defines how the text should be aligned within the notification. +=item B (values: [top/center/bottom], default: center) + +Defines how the text and icon should be aligned vertically within the +notification. If icons are disabled, this option has no effect. + =item B (default: -1) Show age of message if message is older than this time. diff --git a/dunstrc b/dunstrc index c9b149e..6175537 100644 --- a/dunstrc +++ b/dunstrc @@ -132,6 +132,10 @@ # Possible values are "left", "center" and "right". alignment = left + # Vertical alignment of message text and icon. + # Possible values are "top", "center" and "bottom". + content_alignment = center + # Show age of message if message is older than show_age_threshold # seconds. # Set to -1 to disable. From 4c09883ef687696a151be94091600d9b20108101 Mon Sep 17 00:00:00 2001 From: chronus Date: Wed, 29 Jan 2020 23:02:00 +0100 Subject: [PATCH 4/4] adding changes according to review - adding default to config.h#defaults - changing naming from content_* to vertical_* - replacing switch-case with if-else-if --- config.h | 1 + docs/dunst.pod | 2 +- dunstrc | 2 +- src/draw.c | 54 +++++++++++++++++---------------------------- src/option_parser.c | 8 +++---- src/option_parser.h | 2 +- src/settings.c | 8 +++---- src/settings.h | 4 ++-- 8 files changed, 34 insertions(+), 47 deletions(-) diff --git a/config.h b/config.h index 81f82ec..14da2c4 100644 --- a/config.h +++ b/config.h @@ -33,6 +33,7 @@ struct settings defaults = { .idle_threshold = 0, /* don't timeout notifications when idle for x seconds */ .show_age_threshold = -1, /* show age of notification, when notification is older than x seconds */ .align = ALIGN_LEFT, /* text alignment ALIGN_[LEFT|CENTER|RIGHT] */ +.vertical_alignment = VERTICAL_CENTER, /* vertical content alignment VERTICAL_[TOP|CENTER|BOTTOM] */ .sticky_history = true, .history_length = 20, /* max amount of notifications kept in history */ .show_indicators = true, diff --git a/docs/dunst.pod b/docs/dunst.pod index ab8e769..f94a7dd 100644 --- a/docs/dunst.pod +++ b/docs/dunst.pod @@ -337,7 +337,7 @@ removed from the format. Defines how the text should be aligned within the notification. -=item B (values: [top/center/bottom], default: center) +=item B (values: [top/center/bottom], default: center) Defines how the text and icon should be aligned vertically within the notification. If icons are disabled, this option has no effect. diff --git a/dunstrc b/dunstrc index 6175537..c226e9a 100644 --- a/dunstrc +++ b/dunstrc @@ -134,7 +134,7 @@ # Vertical alignment of message text and icon. # Possible values are "top", "center" and "bottom". - content_alignment = center + vertical_alignment = center # Show age of message if message is older than show_age_threshold # seconds. diff --git a/src/draw.c b/src/draw.c index 93f2e22..bdda7f3 100644 --- a/src/draw.c +++ b/src/draw.c @@ -517,25 +517,18 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) // text positioning if (cl->icon) { // vertical alignment - switch (settings.content_alignment) { - case CONTENT_TOP: + if (settings.vertical_alignment == VERTICAL_TOP) { + text_y = settings.padding; + } else if (settings.vertical_alignment == VERTICAL_BOTTOM) { + text_y = h + settings.padding - h_text; + if (text_y < 0) text_y = settings.padding; - break; - case CONTENT_BOTTOM: - text_y = h + settings.padding - h_text; - if (text_y < 0) text_y = settings.padding; - break; - default: // CONTENT_CENTER - break; - } + } // else VERTICAL_CENTER + // icon position - switch (settings.icon_position) { - case ICON_LEFT: - text_x = cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding; - break; - default: // ICON_RIGHT - break; - } + if (settings.icon_position == ICON_LEFT) { + text_x = cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding; + } // else ICON_RIGHT } cairo_move_to(c, text_x, text_y); @@ -552,25 +545,18 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) image_y = settings.padding + h/2 - image_height/2; // vertical alignment - switch (settings.content_alignment) { - case CONTENT_TOP: + if (settings.vertical_alignment == VERTICAL_TOP) { + image_y = settings.padding; + } else if (settings.vertical_alignment == VERTICAL_BOTTOM) { + image_y = h + settings.padding - image_height; + if (image_y < settings.padding || image_y > h) image_y = settings.padding; - break; - case CONTENT_BOTTOM: - image_y = h + settings.padding - image_height; - if (image_y < settings.padding || image_y > h) image_y = settings.padding; - break; - default: // CONTENT_CENTER - break; - } + } // else VERTICAL_CENTER + // icon position - switch (settings.icon_position) { - case ICON_LEFT: - image_x = settings.h_padding; - break; - default: // ICON_RIGHT - break; - } + if (settings.icon_position == ICON_LEFT) { + image_x = settings.h_padding; + } // else ICON_RIGHT cairo_set_source_surface(c, cl->icon, image_x, image_y); cairo_rectangle(c, image_x, image_y, image_width, image_height); diff --git a/src/option_parser.c b/src/option_parser.c index 2b3b15b..2a11d6c 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -103,14 +103,14 @@ bool string_parse_icon_position(const char *s, enum icon_position *ret) return false; } -bool string_parse_content_alignment(const char *s, enum content_alignment *ret) +bool string_parse_vertical_alignment(const char *s, enum vertical_alignment *ret) { ASSERT_OR_RET(STR_FULL(s), false); ASSERT_OR_RET(ret, false); - STRING_PARSE_RET("top", CONTENT_TOP); - STRING_PARSE_RET("center", CONTENT_CENTER); - STRING_PARSE_RET("bottom", CONTENT_BOTTOM); + STRING_PARSE_RET("top", VERTICAL_TOP); + STRING_PARSE_RET("center", VERTICAL_CENTER); + STRING_PARSE_RET("bottom", VERTICAL_BOTTOM); return false; } diff --git a/src/option_parser.h b/src/option_parser.h index d2d6d0e..f3861bc 100644 --- a/src/option_parser.h +++ b/src/option_parser.h @@ -14,7 +14,7 @@ bool string_parse_ellipsize(const char *s, enum ellipsize *ret); bool string_parse_follow_mode(const char *s, enum follow_mode *ret); bool string_parse_fullscreen(const char *s, enum behavior_fullscreen *ret); bool string_parse_icon_position(const char *s, enum icon_position *ret); -bool string_parse_content_alignment(const char *s, enum content_alignment *ret); +bool string_parse_vertical_alignment(const char *s, enum vertical_alignment *ret); bool string_parse_markup_mode(const char *s, enum markup_mode *ret); bool string_parse_mouse_action(const char *s, enum mouse_action *ret); bool string_parse_sepcolor(const char *s, struct separator_color_data *ret); diff --git a/src/settings.c b/src/settings.c index 0d25529..a3dbf1e 100644 --- a/src/settings.c +++ b/src/settings.c @@ -426,13 +426,13 @@ void load_settings(char *cmdline_config_path) { char *c = option_get_string( "global", - "content_alignment", "-content_alignment", "center", + "vertical_alignment", "-vertical_alignment", "center", "Align icon and text top/center/bottom" ); - if (!string_parse_content_alignment(c, &settings.content_alignment)) { + if (!string_parse_vertical_alignment(c, &settings.vertical_alignment)) { if (c) - LOG_W("Unknown content alignment: '%s'", c); - settings.content_alignment = defaults.content_alignment; + LOG_W("Unknown vertical alignment: '%s'", c); + settings.vertical_alignment = defaults.vertical_alignment; } g_free(c); diff --git a/src/settings.h b/src/settings.h index 0ab2d51..0110745 100644 --- a/src/settings.h +++ b/src/settings.h @@ -11,7 +11,7 @@ enum alignment { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; enum ellipsize { ELLIPSE_START, ELLIPSE_MIDDLE, ELLIPSE_END }; enum icon_position { ICON_LEFT, ICON_RIGHT, ICON_OFF }; -enum content_alignment { CONTENT_TOP, CONTENT_CENTER, CONTENT_BOTTOM }; +enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM }; enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM }; enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD }; enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL }; @@ -76,7 +76,7 @@ struct settings { char *browser; char **browser_cmd; enum icon_position icon_position; - enum content_alignment content_alignment; + enum vertical_alignment vertical_alignment; int min_icon_size; int max_icon_size; char *icon_path;