Add feature: progress bar

This commit is contained in:
fwsmit 2020-11-06 14:25:04 +01:00
parent 93b52df269
commit bfcf655b1e
8 changed files with 154 additions and 7 deletions

View File

@ -6,10 +6,13 @@ struct settings defaults = {
.markup = MARKUP_NO,
.colors_norm.bg = "#1793D1",
.colors_norm.fg = "#DDDDDD",
.colors_norm.highlight = "#1745d1",
.colors_crit.bg = "#ffaaaa",
.colors_crit.fg = "#000000",
.colors_crit.highlight = "#ff6666",
.colors_low.bg = "#aaaaff",
.colors_low.fg = "#000000",
.colors_low.highlight = "#7f7fff",
.format = "%s %b", /* default format */
.timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */
@ -110,6 +113,15 @@ struct settings defaults = {
.mouse_right_click = (enum mouse_action []){MOUSE_CLOSE_ALL, -1},
.progress_bar_height = 10,
.progress_bar_min_width = 150,
.progress_bar_max_width = 300,
.progress_bar_frame_width = 1,
.no_progress_bar = false,
};
struct rule default_rules[] = {

View File

@ -23,6 +23,7 @@ struct colored_layout {
PangoLayout *l;
struct color fg;
struct color bg;
struct color highlight;
struct color frame;
char *text;
PangoAttrList *attr;
@ -166,6 +167,11 @@ static bool have_dynamic_width(void)
return (settings.geometry.width_set && settings.geometry.w == 0);
}
static bool have_progress_bar(const struct notification *n)
{
return (n->progress >= 0 && settings.no_progress_bar == false);
}
static struct dimensions calculate_dimensions(GSList *layouts)
{
struct dimensions dim = { 0 };
@ -237,6 +243,11 @@ static struct dimensions calculate_dimensions(GSList *layouts)
text_width = MAX(w, text_width);
}
if (have_progress_bar(cl->n)){
dim.h += settings.progress_bar_height + settings.padding;
dim.w = MAX(dim.w, settings.progress_bar_min_width);
}
dim.corner_radius = MIN(dim.corner_radius, h/2);
}
@ -299,6 +310,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
cl->fg = string_to_color(n->colors.fg);
cl->bg = string_to_color(n->colors.bg);
cl->highlight = string_to_color(n->colors.highlight);
cl->frame = string_to_color(n->colors.frame);
cl->n = n;
@ -354,7 +366,12 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
pango_layout_get_pixel_size(cl->l, NULL, &(n->displayed_height));
if (cl->icon) n->displayed_height = MAX(cairo_image_surface_get_height(cl->icon), n->displayed_height);
n->displayed_height = MAX(settings.notification_height, n->displayed_height + settings.padding * 2);
n->displayed_height = n->displayed_height + settings.padding * 2;
// progress bar
if (have_progress_bar(n)) n->displayed_height += settings.progress_bar_height + settings.padding;
n->displayed_height = MAX(settings.notification_height, n->displayed_height);
n->first_render = false;
return cl;
@ -397,11 +414,16 @@ static int layout_get_height(struct colored_layout *cl)
{
int h;
int h_icon = 0;
int h_progress_bar = 0;
pango_layout_get_pixel_size(cl->l, NULL, &h);
if (cl->icon)
h_icon = cairo_image_surface_get_height(cl->icon);
if (have_progress_bar(cl->n)){
h_progress_bar = settings.progress_bar_height + settings.padding;
}
return MAX(h, h_icon);
int res = MAX(h, h_icon) + h_progress_bar;
return res;
}
/* Attempt to make internal radius more organic.
@ -563,11 +585,15 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
static void render_content(cairo_t *c, struct colored_layout *cl, int width)
{
const int h = layout_get_height(cl);
int h_without_progress_bar = h;
if (have_progress_bar(cl->n)){
h_without_progress_bar -= settings.progress_bar_height + settings.padding;
}
int h_text;
pango_layout_get_pixel_size(cl->l, NULL, &h_text);
int text_x = settings.h_padding,
text_y = settings.padding + h / 2 - h_text / 2;
text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2;
// text positioning
if (cl->icon) {
@ -575,7 +601,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
if (settings.vertical_alignment == VERTICAL_TOP) {
text_y = settings.padding;
} else if (settings.vertical_alignment == VERTICAL_BOTTOM) {
text_y = h + settings.padding - h_text;
text_y = h_without_progress_bar + settings.padding - h_text;
if (text_y < 0)
text_y = settings.padding;
} // else VERTICAL_CENTER
@ -597,14 +623,14 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
unsigned int image_width = cairo_image_surface_get_width(cl->icon),
image_height = cairo_image_surface_get_height(cl->icon),
image_x = width - settings.h_padding - image_width,
image_y = settings.padding + h/2 - image_height/2;
image_y = settings.padding + h_without_progress_bar/2 - image_height/2;
// vertical alignment
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 = h_without_progress_bar + settings.padding - image_height;
if (image_y < settings.padding || image_y > h_without_progress_bar)
image_y = settings.padding;
} // else VERTICAL_CENTER
@ -618,6 +644,38 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
cairo_fill(c);
}
// progress bar positioning
if (have_progress_bar(cl->n)){
int progress = cl->n->progress;
unsigned int frame_width = settings.progress_bar_frame_width,
progress_width = MIN(width - 2 * settings.h_padding, settings.progress_bar_max_width),
progress_height = settings.progress_bar_height - frame_width,
frame_x = settings.h_padding,
frame_y = settings.padding + h - settings.progress_bar_height,
progress_width_without_frame = progress_width - 2 * frame_width,
progress_width_1 = progress_width_without_frame * progress / 100,
progress_width_2 = progress_width_without_frame - progress_width_1,
x_bar_1 = frame_x + frame_width,
x_bar_2 = x_bar_1 + progress_width_1;
double half_frame_width = frame_width / 2.0;
// draw progress bar
// Note: the bar could be drawn a bit smaller, because the frame is drawn on top
// left side
cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a);
cairo_rectangle(c, x_bar_1, frame_y, progress_width_1, progress_height);
cairo_fill(c);
// right side
cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
cairo_rectangle(c, x_bar_2, frame_y, progress_width_2, progress_height);
cairo_fill(c);
// border
cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
cairo_rectangle(c, frame_x + half_frame_width, frame_y + half_frame_width, progress_width - frame_width, progress_height);
cairo_set_line_width(c, frame_width);
cairo_stroke(c);
}
}
static struct dimensions layout_render(cairo_surface_t *srf,

View File

@ -64,6 +64,7 @@ void notification_print(const struct notification *n)
printf("\tformatted: '%s'\n", n->msg);
printf("\tfg: %s\n", n->colors.fg);
printf("\tbg: %s\n", n->colors.bg);
printf("\thighlight: %s\n", n->colors.highlight);
printf("\tframe: %s\n", n->colors.frame);
printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen));
printf("\tprogress: %d\n", n->progress);
@ -236,6 +237,7 @@ void notification_unref(struct notification *n)
g_free(n->urls);
g_free(n->colors.fg);
g_free(n->colors.bg);
g_free(n->colors.highlight);
g_free(n->colors.frame);
g_free(n->stack_tag);
g_free(n->desktop_entry);
@ -393,6 +395,8 @@ void notification_init(struct notification *n)
n->colors.fg = g_strdup(defcolors.fg);
if (!n->colors.bg)
n->colors.bg = g_strdup(defcolors.bg);
if (!n->colors.highlight)
n->colors.highlight = g_strdup(defcolors.highlight);
if (!n->colors.frame)
n->colors.frame = g_strdup(defcolors.frame);

View File

@ -33,6 +33,7 @@ struct notification_colors {
char *frame;
char *bg;
char *fg;
char *highlight;
};
struct notification {

View File

@ -38,6 +38,10 @@ void rule_apply(struct rule *r, struct notification *n)
g_free(n->colors.bg);
n->colors.bg = g_strdup(r->bg);
}
if (r->highlight) {
g_free(n->colors.highlight);
n->colors.highlight = g_strdup(r->highlight);
}
if (r->fc) {
g_free(n->colors.frame);
n->colors.frame = g_strdup(r->fc);

View File

@ -31,6 +31,7 @@ struct rule {
char *new_icon;
char *fg;
char *bg;
char *highlight;
char *fc;
const char *format;
const char *script;

View File

@ -355,6 +355,49 @@ void load_settings(char *cmdline_config_path)
"Window corner radius"
);
settings.progress_bar_height = option_get_int(
"global",
"progress_bar_height", "-progress_bar_height", defaults.progress_bar_height,
"Height of the progress bar"
);
settings.progress_bar_min_width = option_get_int(
"global",
"progress_bar_min_width", "-progress_bar_min_width", defaults.progress_bar_min_width,
"Minimum width of the progress bar"
);
settings.progress_bar_max_width = option_get_int(
"global",
"progress_bar_max_width", "-progress_bar_max_width", defaults.progress_bar_max_width,
"Maximum width of the progress bar"
);
settings.progress_bar_frame_width = option_get_int(
"global",
"progress_bar_frame_width", "-progress_bar_frame_width", defaults.progress_bar_frame_width,
"Frame width of the progress bar"
);
settings.no_progress_bar = option_get_bool(
"global",
"no_progress_bar", "-no_progress_bar", false,
"Hide the progress bar"
);
// check sanity of the progress bar options
{
if (settings.progress_bar_height < (2 * settings.progress_bar_frame_width)){
LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_height");
}
if (settings.progress_bar_max_width < (2 * settings.progress_bar_frame_width)){
LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_max_width");
}
if (settings.progress_bar_max_width < settings.progress_bar_min_width){
LOG_E("setting progress_bar_max_width is smaller than progress_bar_min_width");
}
}
{
char *c = option_get_string(
"global",
@ -584,6 +627,12 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with low urgency"
);
settings.colors_low.highlight = option_get_string(
"urgency_low",
"highlight", "-lh", defaults.colors_low.highlight,
"Highlight color for notifications with low urgency"
);
settings.colors_low.frame = option_get_string(
"urgency_low",
"frame_color", "-lfr", settings.frame_color ? settings.frame_color : defaults.colors_low.frame,
@ -614,6 +663,12 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with normal urgency"
);
settings.colors_norm.highlight = option_get_string(
"urgency_normal",
"highlight", "-nh", defaults.colors_norm.highlight,
"Highlight color for notifications with normal urgency"
);
settings.colors_norm.frame = option_get_string(
"urgency_normal",
"frame_color", "-nfr", settings.frame_color ? settings.frame_color : defaults.colors_norm.frame,
@ -644,6 +699,12 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with ciritical urgency"
);
settings.colors_crit.highlight = option_get_string(
"urgency_critical",
"highlight", "-ch", defaults.colors_crit.highlight,
"Highlight color for notifications with ciritical urgency"
);
settings.colors_crit.frame = option_get_string(
"urgency_critical",
"frame_color", "-cfr", settings.frame_color ? settings.frame_color : defaults.colors_crit.frame,
@ -756,6 +817,7 @@ void load_settings(char *cmdline_config_path)
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
r->fg = ini_get_string(cur_section, "foreground", r->fg);
r->bg = ini_get_string(cur_section, "background", r->bg);
r->bg = ini_get_string(cur_section, "highlight", r->highlight);
r->fc = ini_get_string(cur_section, "frame_color", r->fc);
r->format = ini_get_string(cur_section, "format", r->format);
r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon);

View File

@ -92,6 +92,11 @@ struct settings {
enum mouse_action *mouse_left_click;
enum mouse_action *mouse_middle_click;
enum mouse_action *mouse_right_click;
int progress_bar_height;
int progress_bar_min_width;
int progress_bar_max_width;
int progress_bar_frame_width;
bool no_progress_bar;
};
extern struct settings settings;