summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-10-23 19:47:29 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-10-23 19:47:29 +0200
commit57c3e22114062dfdfe00944e93bc07476d45137f (patch)
tree906f0ab20cb30521096165c391e0f9699c361165
parentcb169a518b82993cd50ba11cb91a7aea4ef0dae2 (diff)
animation effects WIP
-rw-r--r--Makefile.am3
-rw-r--r--gtkplaylist.c118
-rw-r--r--gtkplaylist.h3
-rw-r--r--timeline.c122
-rw-r--r--timeline.h52
5 files changed, 291 insertions, 7 deletions
diff --git a/Makefile.am b/Makefile.am
index 0808d526..7bf75fb8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,7 +45,8 @@ deadbeef_SOURCES =\
session.h session.c gtksession.c\
junklib.h junklib.c utf8.c utf8.h\
optmath.h\
- vfs.c vfs.h vfs_stdio.c
+ vfs.c vfs.h vfs_stdio.c\
+ timeline.c timeline.h
sdkdir = $(pkgincludedir)
sdk_HEADERS = deadbeef.h
diff --git a/gtkplaylist.c b/gtkplaylist.c
index 5dcd6792..a4fe67c7 100644
--- a/gtkplaylist.c
+++ b/gtkplaylist.c
@@ -45,6 +45,7 @@
#include "session.h"
#include "deadbeef.h"
#include "conf.h"
+#include "timeline.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -97,6 +98,78 @@ static int header_dragging = -1;
static int header_sizing = -1;
static int header_dragpt[2];
+#define COLHDR_ANIM_TIME 0.2f
+
+typedef struct {
+ int c1;
+ int c2;
+ int x1, x2;
+ int dx1, dx2;
+ // animated values
+ int ax1, ax2;
+ timeline_t *timeline;
+ int anim_active;
+ gtkplaylist_t *pl;
+} colhdr_animator_t;
+
+static colhdr_animator_t colhdr_anim;
+
+static gboolean
+redraw_header (colhdr_animator_t *anim) {
+ gtkpl_header_draw (anim->pl);
+ gtkpl_expose_header (anim->pl, 0, 0, anim->pl->header->allocation.width, anim->pl->header->allocation.height);
+ return FALSE;
+}
+
+
+static int
+colhdr_anim_cb (float _progress, int _last, void *_ctx) {
+ colhdr_animator_t *anim = (colhdr_animator_t *)_ctx;
+ anim->ax1 = anim->x1 + (float)(anim->dx1 - anim->x1) * _progress;
+ anim->ax2 = anim->x2 + (float)(anim->dx2 - anim->x2) * _progress;
+// printf ("%f %d %d\n", _progress, anim->ax1, anim->ax2);
+ g_idle_add (redraw_header, anim);
+ if (_last) {
+ anim->anim_active = 0;
+ }
+ return 0;
+}
+
+static void
+colhdr_anim_swap (gtkplaylist_t *pl, int c1, int c2, int x1, int x2) {
+ // interrupt previous anim
+ if (!colhdr_anim.timeline) {
+ colhdr_anim.timeline = timeline_create ();
+ }
+ colhdr_anim.pl = pl;
+
+ colhdr_anim.c1 = c1;
+ colhdr_anim.c2 = c2;
+
+ // find c1 and c2 in column list and setup coords
+ // note: columns are already swapped, so their coords must be reversed,
+ // as if before swap
+ gtkpl_column_t *c;
+ int idx = 0;
+ int x = 0;
+ for (c = pl->columns; c; c = c->next, idx++) {
+ if (idx == c1) {
+ colhdr_anim.x1 = x1;
+ colhdr_anim.dx2 = x;
+ }
+ else if (idx == c2) {
+ colhdr_anim.x2 = x2;
+ colhdr_anim.dx1 = x;
+ }
+ x += c->width;
+ }
+ colhdr_anim.anim_active = 1;
+ timeline_stop (colhdr_anim.timeline, 0);
+ timeline_init (colhdr_anim.timeline, COLHDR_ANIM_TIME, 100, colhdr_anim_cb, &colhdr_anim);
+ printf ("timeline_start\n");
+ timeline_start (colhdr_anim.timeline);
+}
+
// that must be called before gtk_init
void
gtkpl_init (void) {
@@ -110,6 +183,10 @@ gtkpl_init (void) {
void
gtkpl_free (gtkplaylist_t *pl) {
+ if (colhdr_anim.timeline) {
+ timeline_free (colhdr_anim.timeline, 1);
+ colhdr_anim.timeline = 0;
+ }
while (pl->columns) {
gtkpl_column_t *next = pl->columns->next;
gtkpl_column_free (pl->columns);
@@ -1176,16 +1253,25 @@ gtkpl_header_draw (gtkplaylist_t *ps) {
int idx = 0;
for (c = ps->columns; c; c = c->next, idx++) {
w = c->width;
+ int xx = x;
+ if (colhdr_anim.anim_active) {
+ if (idx == colhdr_anim.c2) {
+ xx = colhdr_anim.ax1;
+ }
+ else if (idx == colhdr_anim.c1) {
+ xx = colhdr_anim.ax2;
+ }
+ }
if (header_dragging < 0 || idx != header_dragging) {
- if (x >= widget->allocation.width) {
+ if (xx >= widget->allocation.width) {
continue;
}
if (w > 0) {
- gtk_paint_vline (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, NULL, NULL, NULL, 0, h, x+w - 2);
+ gtk_paint_vline (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, NULL, NULL, NULL, 0, h, xx+w - 2);
GdkColor *gdkfg = &widget->style->fg[0];
float fg[3] = {(float)gdkfg->red/0xffff, (float)gdkfg->green/0xffff, (float)gdkfg->blue/0xffff};
draw_set_fg_color (fg);
- draw_text (x + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title);
+ draw_text (xx + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title);
}
}
else {
@@ -1199,6 +1285,14 @@ gtkpl_header_draw (gtkplaylist_t *ps) {
for (c = ps->columns; c; c = c->next, idx++) {
w = c->width;
if (idx == header_dragging) {
+ if (colhdr_anim.anim_active) {
+ if (idx == colhdr_anim.c2) {
+ x = colhdr_anim.ax1;
+ }
+ else if (idx == colhdr_anim.c1) {
+ x = colhdr_anim.ax2;
+ }
+ }
// draw empty slot
if (x < widget->allocation.width) {
gtk_paint_box (widget->style, ps->backbuf_header, GTK_STATE_ACTIVE, GTK_SHADOW_ETCHED_IN, NULL, NULL, "button", x, 0, w, h);
@@ -1214,6 +1308,7 @@ gtkpl_header_draw (gtkplaylist_t *ps) {
draw_set_fg_color (fg);
draw_text (x + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title);
}
+ break;
}
x += w;
}
@@ -1281,13 +1376,20 @@ on_header_motion_notify_event (GtkWidget *widget,
gtkpl_column_t *cc;
int x = 0;
int idx = 0;
+ int x1 = -1, x2 = -1;
for (cc = ps->columns; cc; cc = cc->next, idx++) {
if (x < c->movepos && x + c->width > c->movepos) {
inspos = idx;
+ x1 = x;
+ }
+ else if (idx == header_dragging) {
+ x2 = x;
}
x += cc->width;
}
if (inspos >= 0 && inspos != header_dragging) {
+ int c1 = inspos;
+ int c2 = header_dragging;
// remove c from list
if (c == ps->columns) {
ps->columns = c->next;
@@ -1318,14 +1420,18 @@ on_header_motion_notify_event (GtkWidget *widget,
}
}
}
+// colhdr_anim_swap (ps, c1, c2, x1, x2);
// force redraw of everything
- gtkpl_setup_hscrollbar (ps);
+// gtkpl_setup_hscrollbar (ps);
gtkpl_draw_playlist (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height);
gtkpl_expose (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height);
gtkpl_column_update_config (ps, c, i);
}
- gtkpl_header_draw (ps);
- gtkpl_expose_header (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height);
+ else {
+ // only redraw that if not animating
+ gtkpl_header_draw (ps);
+ gtkpl_expose_header (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height);
+ }
}
else if (header_sizing >= 0) {
// limit event rate
diff --git a/gtkplaylist.h b/gtkplaylist.h
index 9cc4bc74..d3656c29 100644
--- a/gtkplaylist.h
+++ b/gtkplaylist.h
@@ -244,4 +244,7 @@ gtkpl_column_update_config (gtkplaylist_t *pl, gtkpl_column_t *c, int idx);
void
gtkpl_column_rewrite_config (gtkplaylist_t *pl);
+void
+gtkpl_expose_header (gtkplaylist_t *ps, int x, int y, int w, int h);
+
#endif // __GTKPLAYLIST_H
diff --git a/timeline.c b/timeline.c
new file mode 100644
index 00000000..c9a40fb5
--- /dev/null
+++ b/timeline.c
@@ -0,0 +1,122 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009 Alexey Yakovenko
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <assert.h>
+#include "timeline.h"
+#include "threading.h"
+
+timeline_t *
+timeline_create (void) {
+ timeline_t *tl = malloc (sizeof (timeline_t));
+ memset (tl, 0, sizeof (timeline_t));
+ return tl;
+}
+
+void
+timeline_free (timeline_t *tl, int wait) {
+ if (tl->tid && wait) {
+ int tid = tl->tid;
+ tl->destroy = 1;
+ thread_join (tid);
+ }
+ else {
+ tl->destroy = 1;
+ }
+}
+
+void
+timeline_init (timeline_t *tl, float seconds, float fps, int (*callback)(float _progress, int _last, void *_ctx), void *ctx) {
+ tl->fps = fps;
+ tl->duration = seconds;
+ tl->progress = 0;
+ tl->callback = callback;
+ tl->callback_ctx = ctx;
+ tl->destroy = 0;
+ tl->stop = 0;
+}
+
+void
+timeline_stop (timeline_t *tl, int wait) {
+ int tid = tl->tid;
+ if (tid) {
+ tl->stop = 1;
+ if (wait) {
+ thread_join (tid);
+ }
+ }
+}
+
+void
+timeline_thread_func (uintptr_t ctx) {
+ printf ("timeline thread started\n");
+ timeline_t *tl = (timeline_t *)ctx;
+
+ for (;;) {
+ if (tl->stop || tl->destroy) {
+ tl->callback (1, 1, tl->callback_ctx);
+ break;
+ }
+ struct timeval tm;
+ gettimeofday (&tm, NULL);
+ float dt = (tm.tv_sec - tl->time.tv_sec) + (tm.tv_usec - tl->time.tv_usec) / 1000000.0;
+ float t = tl->progress;
+ tl->progress += dt;
+ memcpy (&tl->time, &tm, sizeof (tm));
+ if (t > tl->duration) {
+ tl->callback (1, 1, tl->callback_ctx);
+ break;
+ }
+ else {
+ if (tl->callback (t/tl->duration, 0, tl->callback_ctx) < 0) {
+ break;
+ }
+ }
+ printf ("progress: %f\n", tl->progress);
+
+ // sleep until next frame
+ usleep (1000000 / tl->fps);
+ }
+ tl->tid = 0;
+ if (tl->destroy) {
+ printf ("timeline %p destroyed\n", tl);
+ free (tl);
+ }
+ printf ("timeline %p thread terminated\n", tl);
+}
+
+
+void
+timeline_start (timeline_t *tl) {
+ gettimeofday (&tl->time, NULL);
+ tl->progress = 0;
+ tl->stop = 0;
+ tl->destroy = 0;
+ if (!tl->tid) {
+ tl->tid = thread_start (timeline_thread_func, (uintptr_t)tl);
+ }
+ else {
+ printf ("reusing existing thread\n");
+ }
+}
+
diff --git a/timeline.h b/timeline.h
new file mode 100644
index 00000000..68c372a0
--- /dev/null
+++ b/timeline.h
@@ -0,0 +1,52 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009 Alexey Yakovenko
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __TIMELINE_H
+#define __TIMELINE_H
+
+#include <stdint.h>
+
+typedef struct {
+ float fps;
+ float duration;
+ float progress;
+ struct timeval time;
+ intptr_t tid;
+ int stop;
+ int destroy;
+ int (*callback)(float _progress, int _last, void *_ctx);
+ void *callback_ctx;
+} timeline_t;
+
+// callback must return 0 to continue, or -1 to abort
+timeline_t *
+timeline_create (void);
+
+void
+timeline_free (timeline_t *timeline, int wait);
+
+void
+timeline_stop (timeline_t *tl, int wait);
+
+void
+timeline_init (timeline_t *timeline, float seconds, float fps, int (*callback)(float _progress, int _last, void *_ctx), void *ctx);
+
+void
+timeline_start (timeline_t *timeline);
+
+#endif // __TIMELINE_H