aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-11-20 01:08:30 +0100
committerFederico Angelilli <code@fedang.net>2024-11-20 01:08:30 +0100
commit30f91d7c8769a68e4bf11ed4ff0177bcf1bc9f03 (patch)
treee666b46de81733bead5752c299b32b6c76b1dee0
parentb5cb61379978fa6dc8d6468dd2f8b412e58cf7bb (diff)
Add gradients
-rw-r--r--comet.conf5
-rw-r--r--src/block.c3
-rw-r--r--src/block.h7
-rw-r--r--src/config.c85
-rw-r--r--src/config.h1
-rw-r--r--src/layout.c49
-rw-r--r--src/util.c27
-rw-r--r--src/util.h11
8 files changed, 154 insertions, 34 deletions
diff --git a/comet.conf b/comet.conf
index 9f1caa5..22feae2 100644
--- a/comet.conf
+++ b/comet.conf
@@ -53,12 +53,15 @@
[block.disk]
type = fs
text = SSD %{used-si} / %{total} -- %{free-percentage}
- color = #18baf2
+ color = #18baf2, #00ff00
text-color = #fff
path = /
[block.date]
type = date
text = "%A %d %B %H:%M"
+ ;color = #18baf2, #ff0000
color = #18baf2
+ line-color = #fff, #000
+ line-width = 4
text-color = #fff
diff --git a/src/block.c b/src/block.c
index 44a6241..25f24cd 100644
--- a/src/block.c
+++ b/src/block.c
@@ -53,6 +53,9 @@ void block_free(block_t *block)
if (block->scheme->clean_fn != NULL)
block->scheme->clean_fn(block);
+ gradient_free(&block->bg_color);
+ gradient_free(&block->line_color);
+
free(block->label);
free(block);
}
diff --git a/src/block.h b/src/block.h
index c12cea6..e461e0d 100644
--- a/src/block.h
+++ b/src/block.h
@@ -58,11 +58,8 @@ struct block {
struct timespec update_interval;
struct timespec update_last;
block_update_t update_fn;
- // TODO
- //gradient_t bg_color;
- //gradient_t line_color;
- color_t color;
- color_t line_color;
+ gradient_t bg_color;
+ gradient_t line_color;
unsigned int line_width;
unsigned int x_padding, y_padding;
unsigned int min_width, max_width;
diff --git a/src/config.c b/src/config.c
index 32666a8..e13d9b9 100644
--- a/src/config.c
+++ b/src/config.c
@@ -31,15 +31,15 @@ static const config_entry_t bar_entries[] = {
};
static const config_entry_t block_entries[] = {
- { "hidden", CONFIG_BOOL, NULL, offsetof(block_t, hidden) },
- { "color", CONFIG_COLOR, NULL, offsetof(block_t, color) },
- { "line-color", CONFIG_COLOR, NULL, offsetof(block_t, line_color) },
- { "line-width", CONFIG_UINT, NULL, offsetof(block_t, line_width) },
- { "x-padding", CONFIG_UINT, NULL, offsetof(block_t, x_padding) },
- { "y-padding", CONFIG_UINT, NULL, offsetof(block_t, y_padding) },
- { "min-width", CONFIG_UINT, NULL, offsetof(block_t, min_width) },
- { "max-width", CONFIG_UINT, NULL, offsetof(block_t, max_width) },
- { "interval", CONFIG_TIME, NULL, offsetof(block_t, update_interval) },
+ { "hidden", CONFIG_BOOL, NULL, offsetof(block_t, hidden) },
+ { "color", CONFIG_GRADIENT, NULL, offsetof(block_t, bg_color) },
+ { "line-color", CONFIG_GRADIENT, NULL, offsetof(block_t, line_color) },
+ { "line-width", CONFIG_UINT, NULL, offsetof(block_t, line_width) },
+ { "x-padding", CONFIG_UINT, NULL, offsetof(block_t, x_padding) },
+ { "y-padding", CONFIG_UINT, NULL, offsetof(block_t, y_padding) },
+ { "min-width", CONFIG_UINT, NULL, offsetof(block_t, min_width) },
+ { "max-width", CONFIG_UINT, NULL, offsetof(block_t, max_width) },
+ { "interval", CONFIG_TIME, NULL, offsetof(block_t, update_interval) },
{ 0 },
};
@@ -173,6 +173,64 @@ static bool config_read_color(const char *value, color_t *result)
return false;
}
+static bool config_read_gradient(const char *value, gradient_t *result)
+{
+ size_t count = 0;
+ for (size_t i = 0; value[i] != '\0'; ++i)
+ count += value[i] == ',';
+
+ color_t *colors = calloc(count + 1, sizeof(color_t));
+ size_t n = 0;
+
+ char *state, *copy = strcopy(value);
+ for (char *string = copy; ; string = NULL) {
+ char *token = strtok_r(string, ",", &state);
+
+ if (token == NULL)
+ break;
+
+ while (isspace(*token)) token++;
+ char *end = token + strlen(token);
+ while (isspace(*end)) end--;
+ *end = '\0';
+
+ if (!config_read_color(token, &colors[n++])) {
+ free(copy);
+ free(colors);
+ return false;
+ }
+ }
+
+ free(copy);
+ result->colors = colors;
+ result->length = n;
+
+ if (n == 0) {
+ free(colors);
+ log_debug("Expected at least one color");
+ return false;
+ }
+
+ if (n == 1) {
+ result->cached = cairo_pattern_create_rgba(colors->r, colors->g, colors->b, colors->a);
+ return true;
+ }
+
+ result->cached = cairo_pattern_create_linear(0, 0, 1, 0);
+
+ for (size_t i = 0; i < n; i++) {
+ double offset = i * 1.0 / (n - 1);
+ cairo_pattern_add_color_stop_rgba(result->cached,
+ offset,
+ colors[i].r,
+ colors[i].g,
+ colors[i].b,
+ colors[i].a);
+ }
+
+ return true;
+}
+
static bool config_read_enum(const char *value, config_enum_t *data, int *result)
{
for (int i = 0; data[i].label != NULL; i++) {
@@ -306,6 +364,15 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
}
break;
+ case CONFIG_GRADIENT:
+ if (config_read_gradient(value, (gradient_t *)result)) {
+ char *gradient = gradient_to_string((gradient_t *)result);
+ log_debug("Set '%s.%s' to '%s'", section, key, gradient);
+ free(gradient);
+ return CONFIG_SUCCESS;
+ }
+ break;
+
case CONFIG_ENUM:
if (config_read_enum(value, (config_enum_t *)entries[i].data, (int *)result)) {
log_debug("Set '%s.%s' to '%d'", section, key, *(int *)result);
diff --git a/src/config.h b/src/config.h
index e65dbcf..3ed689c 100644
--- a/src/config.h
+++ b/src/config.h
@@ -15,6 +15,7 @@ typedef enum {
CONFIG_DOUBLE,
CONFIG_BOOL,
CONFIG_COLOR,
+ CONFIG_GRADIENT,
CONFIG_ENUM,
CONFIG_TIME,
CONFIG_LIST,
diff --git a/src/layout.c b/src/layout.c
index db707c5..3c4f13b 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -93,30 +93,41 @@ void layout_init(layout_t *layout, block_t *block, layout_info_t info)
void layout_render(layout_t *layout, cairo_t *cr)
{
- double degree = M_PI / 180.0;
+ const double degree = M_PI / 180.0;
int radius = layout->height / 2 - layout->y_padding;
int line_radius = radius - layout->block->line_width / 2;
- // Render background
- color_t color = layout->block->color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
+ // Update gradients
+ cairo_matrix_t matrix;
+ cairo_matrix_init_scale(&matrix, 1.0 / layout->width, 1.0);
+ cairo_matrix_translate(&matrix, -layout->x, 0.0);
- cairo_new_sub_path(cr);
- cairo_arc(cr, layout->x + layout->x_padding + radius, layout->y + layout->y_padding + radius, radius, 90 * degree, 270 * degree);
- cairo_arc(cr, layout->x + layout->width - layout->x_padding - radius, layout->y + layout->y_padding + radius, radius, 270 * degree, 450 * degree);
- cairo_close_path(cr);
- cairo_fill(cr);
+ // Render background
+ cairo_pattern_t *pattern = layout->block->bg_color.cached;
+ if (pattern != NULL) {
+ cairo_new_sub_path(cr);
+ cairo_arc(cr, layout->x + layout->x_padding + radius, layout->y + layout->y_padding + radius, radius, 90 * degree, 270 * degree);
+ cairo_arc(cr, layout->x + layout->width - layout->x_padding - radius, layout->y + layout->y_padding + radius, radius, 270 * degree, 450 * degree);
+ cairo_close_path(cr);
+
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_set_source(cr, pattern);
+ cairo_fill(cr);
+ }
// Render border
- color = layout->block->line_color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
- cairo_set_line_width(cr, layout->block->line_width);
-
- cairo_new_sub_path(cr);
- cairo_arc(cr, layout->x + layout->x_padding + radius, layout->y + layout->y_padding + radius, line_radius, 90 * degree, 270 * degree);
- cairo_arc(cr, layout->x + layout->width - layout->x_padding - radius, layout->y + layout->y_padding + radius, line_radius, 270 * degree, 450 * degree);
- cairo_close_path(cr);
- cairo_stroke(cr);
+ pattern = layout->block->line_color.cached;
+ if (pattern != NULL) {
+ cairo_new_sub_path(cr);
+ cairo_arc(cr, layout->x + layout->x_padding + radius, layout->y + layout->y_padding + radius, line_radius, 90 * degree, 270 * degree);
+ cairo_arc(cr, layout->x + layout->width - layout->x_padding - radius, layout->y + layout->y_padding + radius, line_radius, 270 * degree, 450 * degree);
+ cairo_close_path(cr);
+
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_set_source(cr, pattern);
+ cairo_set_line_width(cr, layout->block->line_width);
+ cairo_stroke(cr);
+ }
switch (layout->block->type) {
case BLOCK_TEXT: {
@@ -126,7 +137,7 @@ void layout_render(layout_t *layout, cairo_t *cr)
int text_x = layout->x + (layout->width - layout->text_width) / 2;
int text_y = layout->y + (layout->height - layout->text_height) / 2;
- color = text->text_color;
+ color_t color = text->text_color;
cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
cairo_move_to(cr, text_x, text_y);
diff --git a/src/util.c b/src/util.c
index b077484..2900a2f 100644
--- a/src/util.c
+++ b/src/util.c
@@ -29,6 +29,33 @@ void color_print(FILE *stream, color_t *color)
fprintf(stream, "#%02x%02x%02x%02x", r, g, b, a);
}
+char *gradient_to_string(gradient_t *gradient)
+{
+ char buffer[256];
+ const size_t max = sizeof(buffer);
+
+ int start = 0;
+ for (size_t i = 0; i < gradient->length; i++) {
+ unsigned int r = gradient->colors[i].r * 255,
+ g = gradient->colors[i].g * 255,
+ b = gradient->colors[i].b * 255,
+ a = gradient->colors[i].a * 255;
+
+ start += snprintf(buffer + start, max - start, "#%02x%02x%02x%02x", r, g, b, a);
+ if (i != gradient->length - 1)
+ start += snprintf(buffer + start, max - start, ", ");
+ }
+
+ return strslice(buffer, 0, start);
+}
+
+void gradient_free(gradient_t *gradient)
+{
+ free(gradient->colors);
+ if (gradient->cached != NULL)
+ cairo_pattern_destroy(gradient->cached);
+}
+
const struct timespec timespec_from_ms(long ms)
{
struct timespec ts = {
diff --git a/src/util.h b/src/util.h
index 8d60eb2..78dcad7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
+#include <cairo.h>
#define unreachable() log_panic("The impossible happened");
@@ -15,6 +16,12 @@ typedef struct {
double r, g, b, a;
} color_t;
+typedef struct {
+ color_t *colors;
+ size_t length;
+ cairo_pattern_t *cached;
+} gradient_t;
+
static inline color_t color_rgba(int r, int g, int b, int a)
{
color_t color = { r / 255.0, g / 255.0, b / 255.0, a / 255.0 };
@@ -35,6 +42,10 @@ char *color_to_string(color_t *color);
void color_print(FILE *stream, color_t *color);
+char *gradient_to_string(gradient_t *gradient);
+
+void gradient_free(gradient_t *gradient);
+
const struct timespec timespec_from_ms(long ms);
const long timespec_to_ms(struct timespec ts);