aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-03-17 14:55:36 +0100
committerFederico Angelilli <code@fedang.net>2024-03-17 15:01:59 +0100
commitabacdaccb6a1ef55bd85b66e10caaa217458400b (patch)
tree029e80b94670150064b74880add4c44e318a0ca3 /src
parent8419a503313f4e734465b726f897833e094c91b3 (diff)
Add group shrink animation
Diffstat (limited to 'src')
-rw-r--r--src/animate.c48
-rw-r--r--src/animate.h4
-rw-r--r--src/comet.c36
-rw-r--r--src/draw.c4
4 files changed, 73 insertions, 19 deletions
diff --git a/src/animate.c b/src/animate.c
index 8bd09b5..313cfa7 100644
--- a/src/animate.c
+++ b/src/animate.c
@@ -129,8 +129,54 @@ Animation *animation_pulse_create(gint64 duration)
pulse->type = ANIM_PULSE;
pulse->before_func = (DrawFunc)pulse_func;
pulse->duration = duration;
+ return pulse;
+}
+
+static bool shrink_func(Animation *shrink, Layout *layout)
+{
+ g_assert_false(layout->btn->simple);
+ ButtonGroup *group = (gpointer)layout->btn;
+
+ gint64 end = shrink->start + shrink->duration;
+ gint64 now = g_get_monotonic_time();
+
+ if (now > end) {
+ // NOTE: Actually remove the buttons from the group after the animation's end
+ // This part is quite rough around the edges...
+ if (group->children->next) {
+ g_list_free(g_list_remove_link(group->children, group->children));
+ g_list_free(g_list_remove_link(layout->children, layout->children));
+ layout->width = CAST(layout->children->data, Layout)->width;
+ return true;
+ }
+
+ return false;
+ }
+
+ double t = (double)(now - shrink->start) / (end - shrink->start);
+ double pos = smoothstep(t, 0, 1);
- return (gpointer)pulse;
+ int target_w = CAST(layout->children->data, Layout)->width;
+ int width = layout->width - pos * (layout->width - target_w);
+ layout->width = width;
+
+ for (GList *it = layout->children, *next = it->next; it; it = next, next = it ? it->next : NULL) {
+ Layout *child = it->data;
+ if (child->x + child->width > layout->x + width)
+ layout->children = g_list_delete_link(layout->children, it);
+ }
+
+ return true;
+}
+
+Animation *animation_group_shrink_create(gint64 duration)
+{
+ // Note the 0 initialization
+ Animation *shrink = g_malloc0(sizeof(Animation));
+ shrink->type = ANIM_GROUP_SHRINK;
+ shrink->layout_func = (LayoutFunc)shrink_func;
+ shrink->duration = duration;
+ return shrink;
}
void animation_destroy(Animation *anim)
diff --git a/src/animate.h b/src/animate.h
index b296723..d153cda 100644
--- a/src/animate.h
+++ b/src/animate.h
@@ -15,6 +15,8 @@ struct Animation {
enum {
ANIM_SHINE,
ANIM_PULSE,
+ ANIM_GROUP_SHRINK,
+ //ANIM_GROUP_GROW,
} type;
gint64 start;
gint64 duration;
@@ -36,6 +38,8 @@ Animation *animation_shine_create(gint64 duration);
Animation *animation_pulse_create(gint64 duration);
+Animation *animation_group_shrink_create(gint64 duration);
+
void animation_destroy(Animation *anim);
#endif
diff --git a/src/comet.c b/src/comet.c
index b8cce7d..9c552f5 100644
--- a/src/comet.c
+++ b/src/comet.c
@@ -194,26 +194,32 @@ static void quit_action(Button *btn)
static void menu_action(Button *btn)
{
- ButtonSimple *sbtn = CAST(btn, ButtonSimple);
struct {
+ State *state;
ButtonGroup *group;
char *strings[2];
GList *toggled;
- State *state;
- } *menu_ctx = sbtn->data;
+ } *menu_ctx = CAST(btn, ButtonSimple)->data;
- // NOTE: To close the menu the toggle button must be inside
+ bool to_open = menu_ctx->group->children->next == NULL;
- GList *temp = menu_ctx->group->children;
- menu_ctx->group->children = menu_ctx->toggled;
- menu_ctx->toggled = temp;
+ if (to_open)
+ menu_ctx->group->children = g_list_copy(menu_ctx->toggled);
- bool closed = menu_ctx->group->children->next == NULL;
+ log_debug("%s menu", to_open ? "Opened" : "Closed");
- button_simple_set_text(btn, g_strdup(menu_ctx->strings[!closed]), sbtn->text_color);
+ button_simple_set_text(btn, g_strdup(menu_ctx->strings[to_open]), CAST(btn, ButtonSimple)->text_color);
- log_debug("%s menu", closed ? "Closed" : "Opened");
- state_request_redraw(menu_ctx->state, true);
+ if (!to_open) {
+ Animation *shrink = animation_group_shrink_create(600 * G_TIME_SPAN_MILLISECOND);
+
+ if (button_set_animation((gpointer)menu_ctx->group, shrink))
+ state_request_animation(menu_ctx->state);
+ else
+ animation_destroy(shrink);
+ } else {
+ state_request_redraw(menu_ctx->state, true);
+ }
}
static void register_buttons(State *state, Color color, Color text_color, Color line_color, int line_w)
@@ -358,11 +364,11 @@ int main(int argc, char **argv)
button_simple_set_action(child3, show_action, NULL);
struct {
+ State *state;
ButtonGroup *group;
char *strings[2];
GList *toggled;
- State *state;
- } menu_ctx = { (gpointer)group, {"", ""}, NULL, state };
+ } menu_ctx = { state, (gpointer)group, {"", ""}, NULL };
Button *menu = button_simple_create(PANGO_ALIGN_LEFT, color);
button_simple_set_text(menu, g_strdup(menu_ctx.strings[0]), text_color);
@@ -398,8 +404,8 @@ int main(int argc, char **argv)
g_source_remove(source_int);
// NOTE: Skip the first element (the open/close button)
- g_list_free_full(menu_ctx.toggled->next, (GDestroyNotify)button_destroy);
- g_free(menu_ctx.toggled);
+ //g_list_free_full(menu_ctx.toggled->next, (GDestroyNotify)button_destroy);
+ //g_free(menu_ctx.toggled);
timer_delete(date_ctx.timer);
// NOTE: Buttons are freed by state_destroy
diff --git a/src/draw.c b/src/draw.c
index 525ecd7..d351819 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -175,9 +175,7 @@ static void layout_set_text(Layout *layout, PangoFontDescription *desc, int heig
// 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 + height;
- layout->height = height;
}
static void compute_width(Drawer *draw, Window *win)
@@ -208,6 +206,7 @@ static GList *compute_group_layout(Drawer *draw, GList *btns, int bx, bool root)
layouts = g_list_prepend(layouts, layout);
layout->btn = btn;
+ layout->height = draw->height;
layout->line_w = btn->line_width;
layout->x_pad = btn->x_pad;
layout->y_pad = btn->y_pad;
@@ -234,7 +233,6 @@ retry:
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