aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-03-16 00:13:47 +0100
committerFederico Angelilli <code@fedang.net>2024-03-16 00:13:47 +0100
commit121415c252310fe449ab24640f9312a7971305fb (patch)
tree987aaa89451453ed882405e543336f56aa2e37ee /src
parent6dab75636d1c30a6b22141d12a01eb7c09c2183f (diff)
Rewrite layout calculation
Diffstat (limited to 'src')
-rw-r--r--src/comet.c4
-rw-r--r--src/draw.c239
-rw-r--r--src/draw.h8
3 files changed, 118 insertions, 133 deletions
diff --git a/src/comet.c b/src/comet.c
index 5bcd9ac..b47c078 100644
--- a/src/comet.c
+++ b/src/comet.c
@@ -286,6 +286,7 @@ int main(int argc, char **argv)
Color background_all = { 0.3, 0.3, 0.3, 1 };
Drawer *draw = draw_create("Hack 13 Bold", height, x_padding, x_padding, y_padding);
draw_set_background(draw, background_all);
+ draw_set_separator(draw, 10);
State *state = state_create(win, draw);
@@ -353,7 +354,8 @@ int main(int argc, char **argv)
State *state;
} menu_ctx = { (gpointer)group, {"", ""}, NULL, state };
- Button *menu = button_simple_create(PANGO_ALIGN_CENTER, color);
+ // XXX: If the alignment of the group and menu button are not equal something strange happens
+ Button *menu = button_simple_create(PANGO_ALIGN_LEFT, color);
button_simple_set_text(menu, g_strdup(menu_ctx.strings[0]), text_color);
button_simple_set_action(menu, menu_action, &menu_ctx);
diff --git a/src/draw.c b/src/draw.c
index 13e9058..abdbb8e 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -8,16 +8,9 @@
#include "button.h"
#include "log.h"
-static void layout_destroy(Layout *layout)
-{
- if (layout->pl != NULL) g_object_unref(layout->pl);
- g_list_free_full(layout->children, (GDestroyNotify)layout_destroy);
- g_free(layout);
-}
-
Drawer *draw_create(const char *font, int height, int left_pad, int right_pad, int top_pad)
{
- Drawer *draw = g_malloc(sizeof(Drawer));
+ Drawer *draw = g_malloc0(sizeof(Drawer));
g_assert_nonnull(draw);
log_debug("Pango loading font description '%s'", font);
@@ -29,8 +22,6 @@ Drawer *draw_create(const char *font, int height, int left_pad, int right_pad, i
draw->right_pad = right_pad;
draw->top_pad = top_pad;
- draw->layouts = NULL;
-
log_debug("Draw context created [height=%d, left_pad=%d, right_pad=%d, top_pad=%d]",
height, left_pad, right_pad, top_pad);
@@ -38,13 +29,10 @@ Drawer *draw_create(const char *font, int height, int left_pad, int right_pad, i
}
// TODO: Remove this
-static void compute_width(Drawer *draw, Window *win, int *width, int *height)
+static void compute_width(Drawer *draw, Window *win)
{
int screen_width = win->con->screen_size->width;
- int screen_height = win->con->screen_size->height;
-
- *width = round(screen_width - draw->right_pad - draw->left_pad);
- *height = round(draw->height);
+ draw->width = round(screen_width - draw->right_pad - draw->left_pad);
}
static void paint_button(cairo_t *cr, const Layout *layout)
@@ -139,10 +127,10 @@ static void paint_button_list(cairo_t *cr, GList *layouts)
void draw_paint(Drawer *draw, Window *win)
{
- int width, height;
- compute_width(draw, win, &width, &height);
+ compute_width(draw, win);
- cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ // Back buffering
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, draw->width, draw->height);
cairo_t *cr = cairo_create(surface);
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
@@ -157,13 +145,30 @@ void draw_paint(Drawer *draw, Window *win)
cairo_destroy(cr);
window_move(win, draw->left_pad, draw->top_pad);
- window_resize(win, width, draw->height);
+ window_resize(win, draw->width, draw->height);
- window_paint_surface(win, surface, width, height);
+ window_paint_surface(win, surface, draw->width, draw->height);
cairo_surface_destroy(surface);
}
-static void layout_set_text(Layout *layout, PangoFontDescription *desc, int height, int radius)
+static void layout_destroy(Layout *layout)
+{
+ if (layout->pl != NULL) g_object_unref(layout->pl);
+ g_list_free_full(layout->children, (GDestroyNotify)layout_destroy);
+ g_free(layout);
+}
+
+static void layout_adjust(GList *start, GList *end, int off)
+{
+ // NOTE: end must be present in the list or segfault
+ for (GList *it = start; it != end; it = it->next) {
+ Layout *layout = it->data;
+ layout->x += off;
+ layout_adjust(layout->children, NULL, off);
+ }
+}
+
+static void layout_set_text(Layout *layout, PangoFontDescription *desc, int height)
{
g_assert(layout->btn->simple);
@@ -172,167 +177,132 @@ static void layout_set_text(Layout *layout, PangoFontDescription *desc, int heig
pango_layout_set_font_description(layout->pl, desc);
pango_layout_set_text(layout->pl, text, -1);
pango_layout_set_alignment(layout->pl, PANGO_ALIGN_CENTER);
-
- int text_w, text_h;
- pango_layout_get_pixel_size(layout->pl, &text_w, &text_h);
-
- layout->text_w = ceil(text_w);
- layout->text_h = ceil(text_h);
+ pango_layout_get_pixel_size(layout->pl, &layout->text_w, &layout->text_h);
// If there is only one glyph the button should be round
size_t text_l = g_utf8_strlen(text, -1);
- layout->width = text_l == 1 ? height : layout->text_w + 2 * radius;
+ layout->width = text_l == 1 ? height : layout->text_w + height;
layout->height = height;
}
-void draw_compute_layout(Drawer *draw, Window *win, GList *btns)
+static GList *compute_group_layout(Drawer *draw, Window *win, GList *btns, int bx, bool root)
{
- g_list_free_full(draw->layouts, (GDestroyNotify)layout_destroy);
- draw->layouts = NULL;
-
- int width, height;
- compute_width(draw, win, &width, &height);
-
- Button *prev = NULL;
-
- int x = 0;
- int radius = height / 2;
- int sep = 10;
-
- GList *layout_start[3] = { NULL };
- int layout_end[3] = { 0 };
-
+ GList *layouts = NULL;
for (GList *it = btns; it; it = it->next) {
Button *btn = it->data;
- Layout *layout = g_malloc(sizeof(Layout));
- layout->btn = btn;
- layout->children = NULL;
-
- if (prev != NULL && prev->align == btn->align) x += sep;
+ Layout *layout = g_malloc0(sizeof(Layout));
+ layouts = g_list_prepend(layouts, layout);
+ layout->btn = btn;
layout->line_w = btn->line_width;
layout->x_pad = btn->x_pad;
layout->y_pad = btn->y_pad;
-
- layout->x = x;
+ layout->x = bx;
layout->y = 0;
- draw->layouts = g_list_prepend(draw->layouts, layout);
-
- if (prev == NULL || prev->align != btn->align) {
- layout_start[btn->align] = draw->layouts;
- }
-
+ // TODO: Allow nested groups
if (!btn->simple) {
ButtonGroup *group = CAST(btn, ButtonGroup);
g_assert_nonnull(group->children);
// If there is only one child treat a group like a single button
if (group->children->next == NULL) {
- Button *child = group->children->data;
- g_assert_true(child->simple);
- layout->btn = child;
+ layout->btn = btn = group->children->data;
+ g_assert_true(btn->simple);
} else {
- for (GList *it = group->children; it; it = it->next) {
- Button *btn = it->data;
- // Nested groups are not allowed
- g_assert_true(btn->simple);
-
- Layout *child = g_malloc(sizeof(Layout));
- child->btn = btn;
- child->children = NULL;
- child->line_w = btn->line_width;
-
- child->x_pad = btn->x_pad;
- child->y_pad = btn->y_pad;
-
- child->x = x;
- child->y = 0;
-
- child->pl = pango_cairo_create_layout(window_get_context(win));
- layout_set_text(child, draw->desc, height, radius);
- child->width += child->line_w;
-
- layout->children = g_list_prepend(layout->children, child);
-
- x += child->width;
- if (it->next != NULL) x += sep;
- }
-
- layout->pl = NULL;
- layout->width = x - layout->x;
- layout->height = height;
+ layout->children = compute_group_layout(draw, win, group->children, bx, false);
+ g_assert_nonnull(layout->children);
- // Otherwise button_action_find will not work!
- layout->children = g_list_reverse(layout->children);
+ Layout *last = g_list_last(layout->children)->data;
+ layout->width = last->x + last->width - bx;
+ layout->height = draw->height;
// FIXME: Temporary solution to make the antialiasing (or the circles not overlapping correctly) problem less noticeable
-
- bool fix_left = CAST(g_list_first(group->children)->data, Button)->x_pad == 0;
- bool fix_right = CAST(g_list_last(group->children)->data, Button)->x_pad == 0;
-
+ bool fix_left = CAST(layout->children->data, Layout)->x_pad == 0;
if (fix_left) {
layout->x += 1;
layout->width -= 1;
}
- if (fix_right) layout->width -= 1;
+
+ bool fix_right = last->x_pad == 0;
+ if (fix_right)
+ layout->width -= 1;
}
}
- if (layout->btn->simple) {
+ // NOTE: This check is only apparently redundant because it handles the case where there
+ // there is only a single children in a group
+ if (btn->simple) {
layout->pl = pango_cairo_create_layout(window_get_context(win));
- layout_set_text(layout, draw->desc, height, radius);
-
- // TODO: make it work for groups
- if (btn->anim != NULL && btn->anim->layout_func != NULL) {
- if (btn->anim->start == 0) {
- btn->anim->start = g_get_monotonic_time();
- log_debug("Starting animation [type=%d, start=%ld, duration=%ld, button=%p]",
- btn->anim->type, btn->anim->start, btn->anim->duration, btn);
- }
+ layout_set_text(layout, draw->desc, draw->height);
+ }
- if (!btn->anim->layout_func(btn->anim, layout))
- btn->anim->layout_func = NULL;
+ // NOTE: We add half a line width on both sides
+ layout->width += layout->line_w;
+
+ if (btn->anim != NULL && btn->anim->layout_func != NULL) {
+ if (btn->anim->start == 0) {
+ btn->anim->start = g_get_monotonic_time();
+ log_debug("Starting animation [type=%d, start=%ld, duration=%ld, button=%p]",
+ btn->anim->type, btn->anim->start, btn->anim->duration, btn);
}
- layout->width += layout->line_w;
- x += layout->width;
+ if (!btn->anim->layout_func(btn->anim, layout))
+ btn->anim->layout_func = NULL;
+ }
+
+ bx += layout->width;
+ if (root) {
+ draw->layout_bx[btn->align] = bx;
+ draw->layout_end[btn->align] = layouts;
}
- prev = btn;
- layout_end[btn->align] = x;
+ if (it->next != NULL && (!root || CAST(it->next->data, Button)->align == btn->align))
+ bx += draw->sep;
}
- draw->layouts = g_list_reverse(draw->layouts);
+ // Otherwise button_action_find will not work!
+ layouts = g_list_reverse(layouts);
+ return layouts;
+}
+
+void draw_compute_layout(Drawer *draw, Window *win, GList *btns)
+{
+ compute_width(draw, win);
+
+ g_list_free_full(draw->layouts, (GDestroyNotify)layout_destroy);
+ draw->layouts = compute_group_layout(draw, win, btns, 0, true);
- int layout_width[3] = {
- layout_end[PANGO_ALIGN_LEFT],
- layout_end[PANGO_ALIGN_CENTER] - layout_end[PANGO_ALIGN_LEFT],
- layout_end[PANGO_ALIGN_RIGHT] - MAX(layout_end[PANGO_ALIGN_CENTER], layout_end[PANGO_ALIGN_LEFT]),
- };
+ draw->layout_width[PANGO_ALIGN_LEFT] = draw->layout_bx[PANGO_ALIGN_LEFT];
+ draw->layout_width[PANGO_ALIGN_CENTER] = draw->layout_bx[PANGO_ALIGN_CENTER] - draw->layout_bx[PANGO_ALIGN_LEFT];
+ draw->layout_width[PANGO_ALIGN_RIGHT] = draw->layout_bx[PANGO_ALIGN_RIGHT] - MAX(draw->layout_bx[PANGO_ALIGN_CENTER], draw->layout_bx[PANGO_ALIGN_LEFT]);
- if (layout_end[PANGO_ALIGN_RIGHT] > width) {
- log_error("Layout is bigger than the window (%d vs %d)", layout_end[PANGO_ALIGN_RIGHT], width);
+ if (draw->layout_bx[PANGO_ALIGN_RIGHT] > draw->width) {
+ log_error("Layout is bigger than the window (%d vs %d)", draw->layout_bx[PANGO_ALIGN_RIGHT], draw->width);
}
- int center = round(width / 2);
- int center_off = center - round(layout_width[PANGO_ALIGN_CENTER] / 2) - layout_end[PANGO_ALIGN_LEFT];
- log_debug("Aligning center layout [center=%d, off=%d]", center, center_off);
+ bool has_center = draw->layout_end[PANGO_ALIGN_LEFT] && draw->layout_end[PANGO_ALIGN_LEFT]->next;
+ bool has_right = draw->layout_end[PANGO_ALIGN_LEFT] && draw->layout_end[PANGO_ALIGN_CENTER]->next;
- for (GList *it = layout_start[PANGO_ALIGN_CENTER]; it != NULL && it != layout_start[PANGO_ALIGN_RIGHT]; it = it->next) {
- Layout *layout = it->data;
- layout->x += center_off;
+ GList *center_start = has_center ? draw->layout_end[PANGO_ALIGN_LEFT]->next : NULL;
+ GList *right_start = has_right ? draw->layout_end[PANGO_ALIGN_CENTER]->next : NULL;
+
+ if (has_center) {
+ int center = round(draw->width / 2);
+ int center_off = center - draw->layout_width[PANGO_ALIGN_CENTER] / 2 - draw->layout_bx[PANGO_ALIGN_LEFT];
+
+ log_debug("Aligning center layout [center=%d, off=%d]", center, center_off);
+ layout_adjust(center_start, right_start, center_off);
}
- int right = width - layout_width[PANGO_ALIGN_RIGHT];
- int right_off = right - MAX(layout_end[PANGO_ALIGN_LEFT], layout_end[PANGO_ALIGN_CENTER]);
- log_debug("Aligning right layout [x=%d, off=%d]", right, right_off);
+ if (has_right) {
+ int right = draw->width - draw->layout_width[PANGO_ALIGN_RIGHT];
+ int right_off = right - MAX(draw->layout_bx[PANGO_ALIGN_LEFT], draw->layout_bx[PANGO_ALIGN_CENTER]);
- for (GList *it = layout_start[PANGO_ALIGN_RIGHT]; it != NULL; it = it->next) {
- Layout *layout = it->data;
- layout->x += right_off;
+ log_debug("Aligning right layout [x=%d, off=%d]", right, right_off);
+ layout_adjust(right_start, NULL, right_off);
}
log_debug("Updated layouts");
@@ -343,6 +313,11 @@ void draw_set_background(Drawer *draw, Color background)
draw->background = background;
}
+void draw_set_separator(Drawer *draw, int sep)
+{
+ draw->sep = sep;
+}
+
void draw_destroy(Drawer *draw)
{
g_list_free_full(draw->layouts, (GDestroyNotify)layout_destroy);
diff --git a/src/draw.h b/src/draw.h
index f68b4ab..0b1ac95 100644
--- a/src/draw.h
+++ b/src/draw.h
@@ -16,11 +16,17 @@ typedef struct {
typedef struct {
PangoFontDescription *desc;
int height;
+ int width;
int left_pad;
int right_pad;
int top_pad;
+ int sep;
Color background;
GList *layouts;
+ // Calculated by draw_compute_layout
+ GList *layout_end[3];
+ int layout_bx[3];
+ int layout_width[3];
} Drawer;
typedef struct {
@@ -42,6 +48,8 @@ void draw_paint(Drawer *draw, Window *win);
void draw_set_background(Drawer *draw, Color background);
+void draw_set_separator(Drawer *draw, int sep);
+
void draw_destroy(Drawer *draw);
#endif