aboutsummaryrefslogtreecommitdiff
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
parent748613db7a794be69def5f008e2e2eea428d8541 (diff)
Add layouts
-rw-r--r--src/block.h42
-rw-r--r--src/comet.c113
-rw-r--r--src/event.h18
-rw-r--r--src/layout.c105
-rw-r--r--src/layout.h34
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