diff options
| -rw-r--r-- | src/block.h | 42 | ||||
| -rw-r--r-- | src/comet.c | 113 | ||||
| -rw-r--r-- | src/event.h | 18 | ||||
| -rw-r--r-- | src/layout.c | 105 | ||||
| -rw-r--r-- | src/layout.h | 34 |
5 files changed, 289 insertions, 23 deletions
diff --git a/src/block.h b/src/block.h index 3df760b..2179348 100644 --- a/src/block.h +++ b/src/block.h @@ -5,6 +5,8 @@ #include <stdbool.h> #include <time.h> +#include "event.h" + // Color representation normalized to [0, 1] // typedef struct { @@ -36,37 +38,33 @@ typedef void (*block_event_t)(block_t *block, event_t *event); // typedef void (*block_update_t)(block_t *block); -// Generic block type +// Block struct // -typedef struct block { - block_type_t type; +struct block { bool hidden; color_t color; color_t line_color; int line_width; int x_padding, y_padding; int min_width, max_width; - block_event_t event_cb; -}; - -// Block text type -// -typedef struct { - block_t block; - const char *text; - color_t text_color; - align_t text_align; - int text_width; int update_interval; struct timespec update_last; block_update_t update_cb; -} block_text_t; - -// Block group type -// -typedef struct block_group { - block_t block; - struct block_group *next; -} block_group_t; + block_event_t event_cb; + block_type_t type; + union { + struct { + const char *text; + color_t text_color; + align_t text_align; + int text_size; + } text; + struct { + int spacing; + int n_children; + struct block *children; + } group; + }; +}; #endif diff --git a/src/comet.c b/src/comet.c index 72bc3b5..d496590 100644 --- a/src/comet.c +++ b/src/comet.c @@ -1,11 +1,36 @@ #include <stdlib.h> #include <locale.h> +#include <unistd.h> #include "window.h" +#include "layout.h" #define ANY_LOG_IMPLEMENT #include "any_log.h" +cairo_surface_t *render(layout_t *layout, layout_info_t info) +{ + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, info.width, info.height); + log_value_trace("Created cairo surface", + "i:width", info.width, + "i:height", info.height); + + cairo_t *cr = cairo_create(surface); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + color_t color = layout->block->color; + cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); + cairo_paint(cr); + + layout_render(layout, cr); + log_trace("Rendered layouts"); + + cairo_destroy(cr); + return surface; +} + + int main(int argc, char **argv) { setlocale(LC_CTYPE, ""); @@ -20,7 +45,93 @@ int main(int argc, char **argv) window_move(&window, 100, 100); window_resize(&window, 1000, 1000); - while (true); + block_t blocks[2] = { + { + .hidden = false, + .color = { 0.2, 0.2, 0.2, 1 }, + .line_color = { 0 }, + .line_width = 0, + .x_padding = 0, + .y_padding = 0, + .min_width = 0, + .max_width = 0, + .update_interval = 0, + .update_last = { 0 }, + .update_cb = NULL, + .event_cb = NULL, + .type = BLOCK_TEXT, + .text = { + .text = "A", + .text_color = { 0.8, 0.9, 0.3, 1 }, + }, + }, + { + .hidden = false, + .color = { 0.2, 0.2, 0.8, 1 }, + .line_color = { 0 }, + .line_width = 0, + .x_padding = 0, + .y_padding = 0, + .min_width = 0, + .max_width = 0, + .update_interval = 0, + .update_last = { 0 }, + .update_cb = NULL, + .event_cb = NULL, + .type = BLOCK_TEXT, + .text = { + .text = "B", + .text_color = { 0.8, 0.9, 0.2, 1 }, + }, + }, + }; + + block_t top = { + .hidden = false, + .color = { 0.3, 0.2, 0.5, 1 }, + .line_color = { 0 }, + .line_width = 0, + .x_padding = 0, + .y_padding = 0, + .min_width = 0, + .max_width = 0, + .update_interval = 0, + .update_last = { 0 }, + .update_cb = NULL, + .event_cb = NULL, + .type = BLOCK_GROUP, + .group = { + .spacing = 10, + .n_children = 2, + .children = blocks, + }, + }; + + int width = 1200; + int height = 200; + int x_padding = 20; + int y_padding = 40; + + layout_info_t info = { + .fontdesc = pango_font_description_from_string("Hack 13"), + .context = pango_cairo_create_context(window.cr), + .x_offset = 0, + .height = height, + .width = width, + }; + + window_resize(&window, width, height); + window_move(&window, x_padding, y_padding); + + while (true) { + layout_t *layout = layout_create(&top, info); + cairo_surface_t *surface = render(layout, info); + window_present(&window, surface, width, height); + cairo_surface_destroy(surface); + layout_free(layout); + + sleep(1); + } window_close(&window); display_close(&display); diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..30618ac --- /dev/null +++ b/src/event.h @@ -0,0 +1,18 @@ +#ifndef COMET_EVENT_H +#define COMET_EVENT_H + +#include <stddef.h> + +typedef enum { + EVENT_LEFT_CLICK, + EVENT_MIDDLE_CLICK, + EVENT_RIGHT_CLICK, + EVENT_TRIGGER, +} event_type_t; + +typedef struct { + event_type_t type; + int x, y; +} event_t; + +#endif diff --git a/src/layout.c b/src/layout.c new file mode 100644 index 0000000..db6e435 --- /dev/null +++ b/src/layout.c @@ -0,0 +1,105 @@ +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "any_log.h" +#include "layout.h" + +layout_t *layout_create(block_t *block, layout_info_t info) +{ + assert(!block->hidden); + + layout_t *layout = calloc(1, sizeof(layout_t)); + layout->block = block; + layout->x = info.x_offset; + layout->y = 0; + layout->x_padding = block->x_padding; + layout->y_padding = block->y_padding; + layout->height = info.height; + + if (block->type == BLOCK_GROUP) { + layout->children = calloc(block->group.n_children, sizeof(layout_t)); + + for (int i = 0; i < block->group.n_children; i++) { + if (block->group.children[i].hidden) + continue; + + layout_t *child = layout_create(&block->group.children[i], info); + info.x_offset += child->width + block->group.spacing; + layout->children[layout->n_children++] = child; + } + } else if (block->type == BLOCK_TEXT) { + layout->pl = pango_layout_new(info.context); + + pango_layout_set_font_description(layout->pl, info.fontdesc); + pango_layout_set_alignment(layout->pl, block->text.text_align); + pango_layout_set_height(layout->pl, 0); + pango_layout_set_text(layout->pl, block->text.text, -1); + pango_layout_get_pixel_size(layout->pl, &layout->text_width, &layout->text_height); + + int length = strlen(block->text.text); + layout->width = info.height + (length != 1) * layout->text_width; + } + + return layout; +} + +void layout_render(layout_t *layout, cairo_t *cr) +{ + 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); + + 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 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); + + if (layout->block->type == BLOCK_GROUP) { + for (int i = 0; i < layout->n_children; i++) { + cairo_push_group(cr); + layout_render(layout->children[i], cr); + cairo_pop_group_to_source(cr); + cairo_paint(cr); + } + } else if (layout->block->type == BLOCK_TEXT) { + int text_x = layout->x + (layout->width - layout->text_width) / 2; + int text_y = layout->y + (layout->height - layout->text_height) / 2; + + color = layout->block->text.text_color; + cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); + cairo_move_to(cr, text_x, text_y); + + pango_layout_set_text(layout->pl, layout->block->text.text, -1); + pango_cairo_update_layout(cr, layout->pl); + pango_cairo_show_layout(cr, layout->pl); + } +} + +void layout_free(layout_t *layout) +{ + for (int i = 0; i < layout->n_children; i++) + layout_free(layout->children[i]); + + if (layout->pl != NULL) + g_object_unref(layout->pl); + + free(layout); +} diff --git a/src/layout.h b/src/layout.h new file mode 100644 index 0000000..4b8cddd --- /dev/null +++ b/src/layout.h @@ -0,0 +1,34 @@ +#ifndef COMET_LAYOUT_H +#define COMET_LAYOUT_H + +#include <cairo.h> +#include <pango/pangocairo.h> +#include <pango/pango-types.h> + +#include "block.h" + +typedef struct { + PangoFontDescription *fontdesc; + PangoContext *context; + int x_offset; + int width, height; +} layout_info_t; + +typedef struct layout { + block_t *block; + int x, y; + int x_padding, y_padding; + int width, height; + int text_width, text_height; + PangoLayout *pl; + int n_children; + struct layout **children; +} layout_t; + +layout_t *layout_create(block_t *block, layout_info_t info); + +void layout_render(layout_t *layout, cairo_t *cr); + +void layout_free(layout_t *layout); + +#endif |
