aboutsummaryrefslogtreecommitdiff
path: root/src/layout.c
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-07-09 14:29:54 +0200
committerFederico Angelilli <code@fedang.net>2024-07-09 14:29:54 +0200
commit28adc6b395d2fb7545189636cec3651b9c2a5f73 (patch)
tree8b7124f6534beab94ba1ea163bfc86b8ff7aec41 /src/layout.c
parent748613db7a794be69def5f008e2e2eea428d8541 (diff)
Add layouts
Diffstat (limited to 'src/layout.c')
-rw-r--r--src/layout.c105
1 files changed, 105 insertions, 0 deletions
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);
+}