Make activity mode progress bars animate better

Use a tick callback and move the block each frame, instead
of making it jump only when gtk_progress_bar_pulse() is called.
This commit is contained in:
Matthias Clasen 2013-11-10 01:20:27 -05:00
parent 4a789f5036
commit eae9513cbd

View File

@ -80,6 +80,11 @@ struct _GtkProgressBarPrivate
GtkOrientation orientation; GtkOrientation orientation;
guint tick_id;
gint64 pulse1;
gint64 pulse2;
gint64 frame1;
guint activity_dir : 1; guint activity_dir : 1;
guint activity_mode : 1; guint activity_mode : 1;
guint ellipsize : 3; guint ellipsize : 3;
@ -113,10 +118,10 @@ static void gtk_progress_bar_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_progress_bar_real_update (GtkProgressBar *progress);
static gboolean gtk_progress_bar_draw (GtkWidget *widget, static gboolean gtk_progress_bar_draw (GtkWidget *widget,
cairo_t *cr); cairo_t *cr);
static void gtk_progress_bar_act_mode_enter (GtkProgressBar *progress); static void gtk_progress_bar_act_mode_enter (GtkProgressBar *progress);
static void gtk_progress_bar_act_mode_leave (GtkProgressBar *progress);
static void gtk_progress_bar_finalize (GObject *object); static void gtk_progress_bar_finalize (GObject *object);
static void gtk_progress_bar_set_orientation (GtkProgressBar *progress, static void gtk_progress_bar_set_orientation (GtkProgressBar *progress,
GtkOrientation orientation); GtkOrientation orientation);
@ -407,48 +412,15 @@ gtk_progress_bar_new (void)
return pbar; return pbar;
} }
static void
gtk_progress_bar_real_update (GtkProgressBar *pbar)
{
GtkProgressBarPrivate *priv;
GtkWidget *widget;
g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
priv = pbar->priv;
widget = GTK_WIDGET (pbar);
if (priv->activity_mode)
{
/* advance the block */
if (priv->activity_dir == 0)
{
priv->activity_pos += priv->pulse_fraction;
if (priv->activity_pos > 1.0)
{
priv->activity_pos = 1.0;
priv->activity_dir = 1;
}
}
else
{
priv->activity_pos -= priv->pulse_fraction;
if (priv->activity_pos <= 0)
{
priv->activity_pos = 0;
priv->activity_dir = 0;
}
}
}
gtk_widget_queue_draw (widget);
}
static void static void
gtk_progress_bar_finalize (GObject *object) gtk_progress_bar_finalize (GObject *object)
{ {
GtkProgressBar *pbar = GTK_PROGRESS_BAR (object); GtkProgressBar *pbar = GTK_PROGRESS_BAR (object);
GtkProgressBarPrivate *priv = pbar->priv; GtkProgressBarPrivate *priv = pbar->priv;
if (priv->activity_mode)
gtk_progress_bar_act_mode_leave (pbar);
g_free (priv->text); g_free (priv->text);
G_OBJECT_CLASS (gtk_progress_bar_parent_class)->finalize (object); G_OBJECT_CLASS (gtk_progress_bar_parent_class)->finalize (object);
@ -597,6 +569,58 @@ gtk_progress_bar_get_preferred_height (GtkWidget *widget,
*minimum = *natural = MAX (min_height, height); *minimum = *natural = MAX (min_height, height);
} }
static gboolean
tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget);
GtkProgressBarPrivate *priv = pbar->priv;
gint64 frame2;
gdouble fraction;
frame2 = gdk_frame_clock_get_frame_time (frame_clock);
if (priv->frame1 == 0)
priv->frame1 = frame2 - 16667;
if (priv->pulse1 == 0)
priv->pulse1 = priv->pulse2 - 250 * 1000000;
g_assert (priv->pulse2 > priv->pulse1);
g_assert (frame2 > priv->frame1);
/* Determine the fraction to move the block from one frame
* to the next when pulse_fraction is how far the block should
* move between two calls to gtk_progress_bar_pulse().
*/
fraction = priv->pulse_fraction * (frame2 - priv->frame1) / (priv->pulse2 - priv->pulse1);
priv->frame1 = frame2;
/* advance the block */
if (priv->activity_dir == 0)
{
priv->activity_pos += fraction;
if (priv->activity_pos > 1.0)
{
priv->activity_pos = 1.0;
priv->activity_dir = 1;
}
}
else
{
priv->activity_pos -= fraction;
if (priv->activity_pos <= 0)
{
priv->activity_pos = 0;
priv->activity_dir = 0;
}
}
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void static void
gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar) gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar)
{ {
@ -648,6 +672,21 @@ gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar)
priv->activity_dir = 1; priv->activity_dir = 1;
} }
} }
priv->tick_id = gtk_widget_add_tick_callback (widget, tick_cb, NULL, NULL);
priv->pulse2 = 0;
priv->pulse1 = 0;
priv->frame1 = 0;
}
static void
gtk_progress_bar_act_mode_leave (GtkProgressBar *pbar)
{
GtkProgressBarPrivate *priv = pbar->priv;
if (priv->tick_id)
gtk_widget_remove_tick_callback (GTK_WIDGET (pbar), priv->tick_id);
priv->tick_id = 0;
} }
static void static void
@ -998,6 +1037,8 @@ gtk_progress_bar_set_activity_mode (GtkProgressBar *pbar,
if (priv->activity_mode) if (priv->activity_mode)
gtk_progress_bar_act_mode_enter (pbar); gtk_progress_bar_act_mode_enter (pbar);
else
gtk_progress_bar_act_mode_leave (pbar);
gtk_widget_queue_resize (GTK_WIDGET (pbar)); gtk_widget_queue_resize (GTK_WIDGET (pbar));
} }
@ -1022,13 +1063,22 @@ gtk_progress_bar_set_fraction (GtkProgressBar *pbar,
priv = pbar->priv; priv = pbar->priv;
priv->fraction = CLAMP(fraction, 0.0, 1.0); priv->fraction = CLAMP (fraction, 0.0, 1.0);
gtk_progress_bar_set_activity_mode (pbar, FALSE); gtk_progress_bar_set_activity_mode (pbar, FALSE);
gtk_progress_bar_real_update (pbar); gtk_widget_queue_draw (GTK_WIDGET (pbar));
g_object_notify (G_OBJECT (pbar), "fraction"); g_object_notify (G_OBJECT (pbar), "fraction");
} }
static void
gtk_progress_bar_update_pulse (GtkProgressBar *pbar)
{
GtkProgressBarPrivate *priv = pbar->priv;
priv->pulse1 = priv->pulse2;
priv->pulse2 = g_get_monotonic_time ();
}
/** /**
* gtk_progress_bar_pulse: * gtk_progress_bar_pulse:
* @pbar: a #GtkProgressBar * @pbar: a #GtkProgressBar
@ -1045,7 +1095,7 @@ gtk_progress_bar_pulse (GtkProgressBar *pbar)
g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
gtk_progress_bar_set_activity_mode (pbar, TRUE); gtk_progress_bar_set_activity_mode (pbar, TRUE);
gtk_progress_bar_real_update (pbar); gtk_progress_bar_update_pulse (pbar);
} }
/** /**