1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "any_log.h"
#include "layout.h"
void layout_init(layout_t *layout, block_t *block, layout_info_t info)
{
assert(!block->hidden);
memset(layout, 0, 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) {
int x_offset = info.x_offset;
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_init(&layout->children[layout->n_children], block->group.children[i], info);
info.x_offset += layout->children[layout->n_children].width + block->group.spacing;
layout->n_children++;
}
if (layout->n_children > 0) {
layout_t *last = &layout->children[layout->n_children - 1];
layout->width = last->x + last->width - x_offset;
}
} 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;
}
if (layout->block->max_width > 0 && layout->width > layout->block->max_width)
layout->width = layout->block->max_width;
if (layout->block->min_width > 0 && layout->width < layout->block->min_width)
layout->width = layout->block->min_width;
}
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)
{
if (layout->pl != NULL)
g_object_unref(layout->pl);
for (int i = 0; i < layout->n_children; i++)
layout_free(&layout->children[i]);
free(layout->children);
}
|