From: Pierre-Luc Beaudoin Date: Sun, 22 Mar 2009 20:47:18 +0000 (+0200) Subject: Fix Bug 557641: Smooth movement to a new position X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b98671512a8e6dc20ad89f9f4e12cc3bb63fa308;p=libchamplain Fix Bug 557641: Smooth movement to a new position by introducing 2 new functions: champlain_view_go_to and champlain_view_stop_go_to. --- diff --git a/champlain/champlain-view.c b/champlain/champlain-view.c index b034480..127c3e7 100644 --- a/champlain/champlain-view.c +++ b/champlain/champlain-view.c @@ -97,6 +97,17 @@ enum #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHAMPLAIN_TYPE_VIEW, ChamplainViewPrivate)) +/* Between state values for go_to */ +typedef struct { + ChamplainView *view; + ClutterAlpha *alpha; + ClutterTimeline *timeline; + gdouble to_latitude; + gdouble to_longitude; + gdouble from_latitude; + gdouble from_longitude; +} GoToContext; + struct _ChamplainViewPrivate { ClutterActor *stage; @@ -131,6 +142,9 @@ struct _ChamplainViewPrivate ClutterActor *license_actor; /* Contains the licence info */ ChamplainState state; /* View's global state */ + + /* champlain_view_go_to's context, kept for stop_go_to */ + GoToContext *goto_context; }; G_DEFINE_TYPE (ChamplainView, champlain_view, CLUTTER_TYPE_GROUP); @@ -724,6 +738,7 @@ champlain_view_init (ChamplainView *view) priv->state = CHAMPLAIN_STATE_INIT; priv->latitude = 0.0f; priv->longitude = 0.0f; + priv->goto_context = NULL; /* Setup viewport */ priv->viewport = tidy_viewport_new (); @@ -1026,6 +1041,113 @@ champlain_view_center_on (ChamplainView *view, marker_reposition (view); } +static void +timeline_new_frame (ClutterTimeline *timeline, + gint frame_num, + GoToContext *ctx) +{ + gdouble alpha; + gdouble lat; + gdouble lon; + + alpha = (double) clutter_alpha_get_alpha (ctx->alpha) / CLUTTER_ALPHA_MAX_ALPHA; + lat = ctx->to_latitude - ctx->from_latitude; + lon = ctx->to_longitude - ctx->from_longitude; + + champlain_view_center_on (ctx->view, + ctx->from_latitude + alpha * lat, + ctx->from_longitude + alpha * lon); +} + +static void +timeline_completed (ClutterTimeline *timeline, + ChamplainView *view) +{ + champlain_view_stop_go_to (view); +} + +/** + * champlain_view_stop_go_to: + * @view: a #ChamplainView + * + * Stop the go to animation. The view will stay where it was when the + * animation was stopped. + * + * Since: 0.4 + */ +void +champlain_view_stop_go_to (ChamplainView *view) +{ + g_return_if_fail (CHAMPLAIN_IS_VIEW (view)); + + ChamplainViewPrivate *priv = GET_PRIVATE (view); + + if (priv->goto_context == NULL) + return; + + clutter_timeline_stop (priv->goto_context->timeline); + + g_object_unref (priv->goto_context->timeline); + g_object_unref (priv->goto_context->alpha); + + g_free (priv->goto_context); + priv->goto_context = NULL; +} + +/** + * champlain_view_go_to: + * @view: a #ChamplainView + * @latitude: the longitude to center the map at + * @longitude: the longitude to center the map at + * + * Move from the current position to these coordinates. All tiles in the + * intermediate view WILL be loaded! + * + * Since: 0.4 + */ +void +champlain_view_go_to (ChamplainView *view, + gdouble latitude, + gdouble longitude) +{ + g_return_if_fail (CHAMPLAIN_IS_VIEW (view)); + + gint duration; + + ChamplainViewPrivate *priv = GET_PRIVATE (view); + GoToContext *ctx = g_new0 (GoToContext, 1); + + ctx->from_latitude = priv->latitude; + ctx->from_longitude = priv->longitude; + ctx->to_latitude = latitude; + ctx->to_longitude = longitude; + ctx->view = view; + + /* We keep a reference for stop */ + priv->goto_context = ctx; + + /* A ClutterTimeline will be responsible for the animation, + * at each frame, the current position will be computer and set + * using champlain_view_center_on. Timelines skip frames if the + * computer is not fast enough, so we just need to set the duration. + * + * To have a nice animation, the duration should be longer if the zoom level + * is higher and if the points are far away + */ + duration = 100 * priv->zoom_level * + sqrt (pow (latitude - priv->latitude, 2) + pow (longitude - priv->longitude, 2)); + ctx->timeline = clutter_timeline_new_for_duration (duration); + ctx->alpha = clutter_alpha_new_full (ctx->timeline, CLUTTER_ALPHA_SINE_INC, NULL, + NULL); + + g_signal_connect (ctx->timeline, "new-frame", G_CALLBACK (timeline_new_frame), + ctx); + g_signal_connect (ctx->timeline, "completed", G_CALLBACK (timeline_completed), + view); + + clutter_timeline_start (ctx->timeline); +} + /** * champlain_view_zoom_in: * @view: a #ChamplainView diff --git a/champlain/champlain-view.h b/champlain/champlain-view.h index da909aa..8704b36 100644 --- a/champlain/champlain-view.h +++ b/champlain/champlain-view.h @@ -71,6 +71,8 @@ GType champlain_view_get_type (void); ClutterActor *champlain_view_new (void); void champlain_view_center_on (ChamplainView *view, gdouble latitude, gdouble longitude); +void champlain_view_go_to (ChamplainView *view, gdouble latitude, gdouble longitude); +void champlain_view_stop_go_to (ChamplainView *view); void champlain_view_zoom_in (ChamplainView *champlainView);