From: Carlos Garnacho Date: Fri, 4 Jan 2008 20:26:03 +0000 (+0000) Subject: Added, EvTimeline is the base object for animations. Added these files to X-Git-Tag: EVINCE_2_21_90~72 X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=commitdiff_plain;h=e2454047ecb9509ea4439ad8e0cb0d1697db260d;p=evince.git Added, EvTimeline is the base object for animations. Added these files to 2008-01-04 Carlos Garnacho * shell/ev-timeline.[ch]: Added, EvTimeline is the base object for animations. * shell/Makefile.am: Added these files to build. svn path=/trunk/; revision=2798 --- diff --git a/ChangeLog b/ChangeLog index ba54f489..867efe84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-01-04 Carlos Garnacho + + * shell/ev-timeline.[ch]: Added, EvTimeline is the base object for + animations. + * shell/Makefile.am: Added these files to build. + 2008-01-04 Carlos Garnacho * backend/pdf/ev-poppler.cc (pdf_document_get_effect): Added diff --git a/shell/Makefile.am b/shell/Makefile.am index 8a510b43..b301374b 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -80,6 +80,8 @@ evince_SOURCES= \ ev-sidebar-thumbnails.h \ ev-stock-icons.c \ ev-stock-icons.h \ + ev-timeline.c \ + ev-timeline.h \ ev-tooltip.c \ ev-tooltip.h \ main.c \ diff --git a/shell/ev-timeline.c b/shell/ev-timeline.c new file mode 100644 index 00000000..1545dff1 --- /dev/null +++ b/shell/ev-timeline.c @@ -0,0 +1,450 @@ +/* ev-timeline.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2007 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "ev-timeline.h" + +#define EV_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_TIMELINE, EvTimelinePriv)) +#define MSECS_PER_SEC 1000 +#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) +#define DEFAULT_FPS 30 + +typedef struct EvTimelinePriv EvTimelinePriv; + +struct EvTimelinePriv { + guint duration; + guint fps; + guint source_id; + + GTimer *timer; + + guint loop : 1; +}; + +enum { + PROP_0, + PROP_FPS, + PROP_DURATION, + PROP_LOOP +}; + +enum { + STARTED, + PAUSED, + FINISHED, + FRAME, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + + +G_DEFINE_TYPE (EvTimeline, ev_timeline, G_TYPE_OBJECT) + + +static void +ev_timeline_init (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + priv = EV_TIMELINE_GET_PRIV (timeline); + + priv->fps = DEFAULT_FPS; + priv->duration = 0; +} + +static void +ev_timeline_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EvTimeline *timeline; + + timeline = EV_TIMELINE (object); + + switch (prop_id) { + case PROP_FPS: + ev_timeline_set_fps (timeline, g_value_get_uint (value)); + break; + case PROP_DURATION: + ev_timeline_set_duration (timeline, g_value_get_uint (value)); + break; + case PROP_LOOP: + ev_timeline_set_loop (timeline, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ev_timeline_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EvTimeline *timeline; + EvTimelinePriv *priv; + + timeline = EV_TIMELINE (object); + priv = EV_TIMELINE_GET_PRIV (timeline); + + switch (prop_id) { + case PROP_FPS: + g_value_set_uint (value, priv->fps); + break; + case PROP_DURATION: + g_value_set_uint (value, priv->duration); + break; + case PROP_LOOP: + g_value_set_boolean (value, priv->loop); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ev_timeline_finalize (GObject *object) +{ + EvTimelinePriv *priv; + + priv = EV_TIMELINE_GET_PRIV (object); + + if (priv->source_id) { + g_source_remove (priv->source_id); + priv->source_id = 0; + } + + if (priv->timer) + g_timer_destroy (priv->timer); + + G_OBJECT_CLASS (ev_timeline_parent_class)->finalize (object); +} + +static gboolean +ev_timeline_run_frame (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + gdouble progress; + guint elapsed_time; + + GDK_THREADS_ENTER (); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); + progress = (gdouble) elapsed_time / priv->duration; + progress = CLAMP (progress, 0., 1.); + + g_signal_emit (timeline, signals [FRAME], 0, progress); + + if (progress >= 1.0) { + if (!priv->loop) { + if (priv->source_id) { + g_source_remove (priv->source_id); + priv->source_id = 0; + } + + g_signal_emit (timeline, signals [FINISHED], 0); + return FALSE; + } else { + ev_timeline_rewind (timeline); + } + } + + GDK_THREADS_LEAVE (); + + return TRUE; +} + +static void +ev_timeline_real_start (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + priv = EV_TIMELINE_GET_PRIV (timeline); + + if (!priv->source_id) { + if (priv->timer) + g_timer_continue (priv->timer); + else + priv->timer = g_timer_new (); + + /* sanity check */ + g_assert (priv->fps > 0); + + g_signal_emit (timeline, signals [STARTED], 0); + + priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps), + (GSourceFunc) ev_timeline_run_frame, + timeline); + } +} + +static void +ev_timeline_class_init (EvTimelineClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->set_property = ev_timeline_set_property; + object_class->get_property = ev_timeline_get_property; + object_class->finalize = ev_timeline_finalize; + + class->start = ev_timeline_real_start; + + g_object_class_install_property (object_class, + PROP_FPS, + g_param_spec_uint ("fps", + "FPS", + "Frames per second for the timeline", + 1, + G_MAXUINT, + DEFAULT_FPS, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_DURATION, + g_param_spec_uint ("duration", + "Animation Duration", + "Animation Duration", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_LOOP, + g_param_spec_boolean ("loop", + "Loop", + "Whether the timeline loops or not", + FALSE, + G_PARAM_READWRITE)); + signals[STARTED] = + g_signal_new ("started", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvTimelineClass, started), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[PAUSED] = + g_signal_new ("paused", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvTimelineClass, paused), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[FINISHED] = + g_signal_new ("finished", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvTimelineClass, finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[FRAME] = + g_signal_new ("frame", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvTimelineClass, frame), + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, + G_TYPE_DOUBLE); + + g_type_class_add_private (class, sizeof (EvTimelinePriv)); +} + +EvTimeline * +ev_timeline_new (guint duration) +{ + return g_object_new (EV_TYPE_TIMELINE, + "duration", duration, + NULL); +} + +void +ev_timeline_start (EvTimeline *timeline) +{ + g_return_if_fail (EV_IS_TIMELINE (timeline)); + + EV_TIMELINE_GET_CLASS (timeline)->start (timeline); +} + +void +ev_timeline_pause (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + g_return_if_fail (EV_IS_TIMELINE (timeline)); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + if (priv->source_id) { + g_source_remove (priv->source_id); + priv->source_id = 0; + g_timer_stop (priv->timer); + g_signal_emit (timeline, signals [PAUSED], 0); + } +} + +void +ev_timeline_rewind (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + g_return_if_fail (EV_IS_TIMELINE (timeline)); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + /* destroy and re-create timer if neccesary */ + if (priv->timer) { + g_timer_destroy (priv->timer); + + if (ev_timeline_is_running (timeline)) + priv->timer = g_timer_new (); + else + priv->timer = NULL; + } +} + +gboolean +ev_timeline_is_running (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + return (priv->source_id != 0); +} + +guint +ev_timeline_get_fps (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + g_return_val_if_fail (EV_IS_TIMELINE (timeline), 1); + + priv = EV_TIMELINE_GET_PRIV (timeline); + return priv->fps; +} + +void +ev_timeline_set_fps (EvTimeline *timeline, + guint fps) +{ + EvTimelinePriv *priv; + + g_return_if_fail (EV_IS_TIMELINE (timeline)); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + priv->fps = fps; + + if (ev_timeline_is_running (timeline)) { + g_source_remove (priv->source_id); + priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps), + (GSourceFunc) ev_timeline_run_frame, + timeline); + } + + g_object_notify (G_OBJECT (timeline), "fps"); +} + +gboolean +ev_timeline_get_loop (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE); + + priv = EV_TIMELINE_GET_PRIV (timeline); + return priv->loop; +} + +void +ev_timeline_set_loop (EvTimeline *timeline, + gboolean loop) +{ + EvTimelinePriv *priv; + + g_return_if_fail (EV_IS_TIMELINE (timeline)); + + priv = EV_TIMELINE_GET_PRIV (timeline); + priv->loop = loop; + + g_object_notify (G_OBJECT (timeline), "loop"); +} + +void +ev_timeline_set_duration (EvTimeline *timeline, + guint duration) +{ + EvTimelinePriv *priv; + + g_return_if_fail (EV_IS_TIMELINE (timeline)); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + priv->duration = duration; + + g_object_notify (G_OBJECT (timeline), "duration"); +} + +guint +ev_timeline_get_duration (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + + g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + return priv->duration; +} + +gdouble +ev_timeline_get_progress (EvTimeline *timeline) +{ + EvTimelinePriv *priv; + gdouble progress; + guint elapsed_time; + + g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0.0); + + priv = EV_TIMELINE_GET_PRIV (timeline); + + if (!priv->timer) + return 0.; + + elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); + progress = (gdouble) elapsed_time / priv->duration; + + return CLAMP (progress, 0., 1.); +} diff --git a/shell/ev-timeline.h b/shell/ev-timeline.h new file mode 100644 index 00000000..534e48ad --- /dev/null +++ b/shell/ev-timeline.h @@ -0,0 +1,86 @@ +/* ev-timeline.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2007 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EV_TIMELINE_H__ +#define __EV_TIMELINE_H__ + +#include + +G_BEGIN_DECLS + +#define EV_TYPE_TIMELINE (ev_timeline_get_type ()) +#define EV_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_TIMELINE, EvTimeline)) +#define EV_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_TIMELINE, EvTimelineClass)) +#define EV_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_TIMELINE)) +#define EV_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_TIMELINE)) +#define EV_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_TIMELINE, EvTimelineClass)) + +typedef struct EvTimeline EvTimeline; +typedef struct EvTimelineClass EvTimelineClass; + +struct EvTimeline { + GObject parent_instance; +}; + +struct EvTimelineClass { + GObjectClass parent_class; + + /* vmethods */ + void (* start) (EvTimeline *timeline); + + /* signals */ + void (* started) (EvTimeline *timeline); + void (* finished) (EvTimeline *timeline); + void (* paused) (EvTimeline *timeline); + + void (* frame) (EvTimeline *timeline, + gdouble progress); +}; + + +GType ev_timeline_get_type (void) G_GNUC_CONST; + +EvTimeline *ev_timeline_new (guint duration); + +void ev_timeline_start (EvTimeline *timeline); +void ev_timeline_pause (EvTimeline *timeline); +void ev_timeline_rewind (EvTimeline *timeline); + +gboolean ev_timeline_is_running (EvTimeline *timeline); + +guint ev_timeline_get_fps (EvTimeline *timeline); +void ev_timeline_set_fps (EvTimeline *timeline, + guint fps); + +gboolean ev_timeline_get_loop (EvTimeline *timeline); +void ev_timeline_set_loop (EvTimeline *timeline, + gboolean loop); + +guint ev_timeline_get_duration (EvTimeline *timeline); +void ev_timeline_set_duration (EvTimeline *timeline, + guint duration); + +gdouble ev_timeline_get_progress (EvTimeline *timeline); + + +G_END_DECLS + +#endif /* __EV_TIMELINE_H__ */