2 * Copyright (C) 2007 OpenedHand Limited
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Neil Jagdish Patel <njp@o-hand.com>
23 #include "astro-music-window.h"
27 #include <libastro-desktop/astro-defines.h>
28 #include <libastro-desktop/astro-application.h>
29 #include <libastro-desktop/astro-window.h>
30 #include <libastro-desktop/astro-behave.h>
31 #include <libastro-desktop/astro-utils.h>
33 #include "astro-reflection.h"
35 G_DEFINE_TYPE (AstroMusicWindow, astro_music_window, ASTRO_TYPE_WINDOW);
37 #define ASTRO_MUSIC_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
38 ASTRO_TYPE_MUSIC_WINDOW, AstroMusicWindowPrivate))
40 #define ALBUM_DIR PKGDATADIR"/albums"
42 struct _AstroMusicWindowPrivate
54 ClutterTimeline *timeline;
56 ClutterBehaviour *behave;
59 /* Public Functions */
61 /* Private functions */
70 ensure_layout (AstroMusicWindow *window)
72 AstroMusicWindowPrivate *priv;
79 for (c=c; c; c = c->next)
81 ClutterActor *cover = c->data;
82 CoverTrans *trans = g_object_get_data (G_OBJECT (cover), "trans");
84 if (i == priv->active)
89 else if (i > priv->active)
93 diff = i - priv->active;
94 trans->x = (CSW()/2) + ((CSW()/4)*diff);
98 trans->scale = 0.4 + (0.4 * (3-diff)/3);
104 diff = priv->active - i;
105 trans->x = (CSW()/2) - ((CSW()/4)*diff);
109 trans->scale = 0.4 + (0.4 * (3-diff)/3);
117 astro_music_window_advance (AstroMusicWindow *window, gint n)
119 AstroMusicWindowPrivate *priv;
122 g_return_if_fail (ASTRO_IS_MUSIC_WINDOW (window));
125 new_active = priv->active + n;
126 if (new_active < 0 ||
127 new_active > (clutter_group_get_n_children (CLUTTER_GROUP (priv->albums))-1))
131 ensure_layout (window);
133 if (clutter_timeline_is_playing (priv->timeline))
134 clutter_timeline_rewind (priv->timeline);
136 clutter_timeline_start (priv->timeline);
141 on_cover_active_completed (ClutterTimeline *timeline,
142 AstroReflection *reflection)
144 astro_reflection_set_active (reflection, TRUE);
146 g_signal_handlers_disconnect_by_func (timeline,
147 on_cover_active_completed,
152 on_cover_activated (AstroMusicWindow *window)
154 AstroMusicWindowPrivate *priv;
159 g_return_if_fail (ASTRO_IS_MUSIC_WINDOW (window));
162 children = priv->covers;
163 cover = g_list_nth_data (children, priv->active);
165 if (!CLUTTER_IS_ACTOR (cover))
168 trans = g_object_get_data (G_OBJECT (cover), "trans");
172 priv->activated = TRUE;
174 trans->scale = ALBUM_SCALE;
175 trans->x = (CSW()/2) - ((ALBUM_SIZE * ALBUM_SCALE) * 0.5);
177 clutter_actor_raise_top (cover);
179 if (clutter_timeline_is_playing (priv->timeline))
180 clutter_timeline_rewind (priv->timeline);
182 clutter_timeline_start (priv->timeline);
184 g_signal_connect (priv->timeline, "completed",
185 G_CALLBACK (on_cover_active_completed), cover);
189 on_cover_clicked (ClutterActor *cover,
191 AstroMusicWindow *window)
193 AstroMusicWindowPrivate *priv;
197 g_return_val_if_fail (ASTRO_IS_MUSIC_WINDOW (window), FALSE);
200 children = priv->covers;
201 n = g_list_index (children, cover);
205 if (event->button.x > CSW()/2)
207 astro_reflection_set_active (g_list_nth_data (priv->covers,
208 priv->active), FALSE);
209 priv->activated = FALSE;
211 astro_music_window_advance (window, 0);
215 if (n == priv->active)
216 on_cover_activated (window);
220 if (n > priv->active)
221 diff = (n-priv->active);
223 diff = (priv->active - n) * -1;
224 astro_music_window_advance (window, diff);
230 static ClutterActor *
231 make_cover (const gchar *filename)
234 ClutterActor *texture;
236 pixbuf = gdk_pixbuf_new_from_file_at_size (filename,
237 ALBUM_SIZE, ALBUM_SIZE,
242 texture = astro_reflection_new (pixbuf);
244 g_object_set_data (G_OBJECT (texture), "trans", g_new0 (CoverTrans, 1));
249 load_details (ClutterActor *cover, const gchar *leaf)
254 details = g_strndup (leaf, strlen (leaf)-4);
256 for (i = 0; i < strlen (details); i++)
257 if (details[i] == '_') details[i] = ' ';
259 clutter_actor_set_name (cover, details);
264 load_albums (AstroMusicWindow *window)
266 AstroMusicWindowPrivate *priv;
269 GError *error = NULL;
270 gint offset = CSW()*2;
274 dir = g_dir_open (ALBUM_DIR, 0, &error);
277 g_warning ("Cannot load albums: %s", error->message);
278 g_error_free (error);
282 while ((leaf = g_dir_read_name (dir)))
287 if (!g_str_has_suffix (leaf, ".jpg"))
290 filename = g_build_filename (ALBUM_DIR, leaf, NULL);
291 cover = make_cover (filename);
293 if (!CLUTTER_IS_ACTOR (cover))
298 load_details (cover, leaf);
299 clutter_container_add_actor (CLUTTER_CONTAINER (priv->albums), cover);
300 clutter_actor_set_position (cover, offset, 0);
301 clutter_actor_show_all (cover);
302 clutter_actor_set_reactive (cover, TRUE);
303 g_signal_connect (cover, "button-release-event",
304 G_CALLBACK (on_cover_clicked), window);
306 priv->covers = g_list_append (priv->covers, cover);
310 offset += ALBUM_SIZE * 0.9;
315 astro_music_alpha (ClutterBehaviour *behave,
317 AstroMusicWindow *window)
319 AstroMusicWindowPrivate *priv;
322 g_return_if_fail (ASTRO_IS_MUSIC_WINDOW (window));
326 for (c=c; c; c = c->next)
328 ClutterActor *cover = c->data;
329 CoverTrans *trans = g_object_get_data (G_OBJECT (cover), "trans");
330 gdouble cscale, dscale;
331 gint currentx, diffx;
333 currentx = clutter_actor_get_x (cover);
334 if (currentx > trans->x)
335 diffx = (currentx - trans->x) * -1;
337 diffx = trans->x - currentx;
339 clutter_actor_set_x (cover, currentx
340 + (gint)((diffx*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA));
342 clutter_actor_get_scale (cover, &cscale, &cscale);
343 if (cscale > trans->scale)
344 dscale = (cscale - trans->scale) * -1;
346 dscale = trans->scale - cscale;
348 clutter_actor_set_scale (cover,
349 cscale + ((dscale*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA),
350 cscale + ((dscale*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA));
355 on_main_timeline_completed (ClutterTimeline *timeline,
356 AstroMusicWindow *window)
358 AstroMusicWindowPrivate *priv;
359 const gchar *details;
362 g_return_if_fail (ASTRO_MUSIC_WINDOW (window));
365 children = priv->covers;
366 details = clutter_actor_get_name (g_list_nth_data (children, priv->active));
368 clutter_label_set_text (CLUTTER_LABEL (priv->label), details);
372 on_key_release_event (ClutterActor *actor,
374 AstroMusicWindow *window)
376 AstroMusicWindowPrivate *priv;
378 g_return_val_if_fail (ASTRO_IS_WINDOW (window), FALSE);
381 switch (event->key.keyval)
384 case CLUTTER_KP_Enter:
385 case CLUTTER_ISO_Enter:
386 on_cover_activated (window);
389 case CLUTTER_KP_Left:
392 astro_reflection_set_active (g_list_nth_data (priv->covers,
393 priv->active), FALSE);
394 priv->activated = FALSE;
396 astro_music_window_advance (window, -1);
399 case CLUTTER_KP_Right:
402 astro_reflection_set_active (g_list_nth_data (priv->covers,
403 priv->active), FALSE);
404 priv->activated = FALSE;
406 astro_music_window_advance (window, 1);
417 astro_music_window_class_init (AstroMusicWindowClass *klass)
419 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
421 g_type_class_add_private (gobject_class, sizeof (AstroMusicWindowPrivate));
425 astro_music_window_init (AstroMusicWindow *window)
427 AstroMusicWindowPrivate *priv;
428 ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
431 priv = window->priv = ASTRO_MUSIC_WINDOW_GET_PRIVATE (window);
435 priv->activated = FALSE;
437 priv->albums = clutter_group_new ();
438 clutter_container_add_actor (CLUTTER_CONTAINER (window), priv->albums);
439 clutter_actor_set_anchor_point_from_gravity (priv->albums,
440 CLUTTER_GRAVITY_WEST);
441 clutter_actor_set_position (priv->albums, 0, CSH() * 0.5);
443 load_albums (window);
445 font = g_strdup_printf ("Sans %d", CSH()/30);
446 priv->label = clutter_label_new_full (font,
447 "Jay Z - American Gangster",
449 clutter_label_set_line_wrap (CLUTTER_LABEL (priv->label), FALSE);
450 clutter_label_set_alignment (CLUTTER_LABEL (priv->label),
452 clutter_container_add_actor (CLUTTER_CONTAINER (window), priv->label);
453 clutter_actor_set_size (priv->label, CSW(), CSH()/10);
454 clutter_actor_set_anchor_point_from_gravity (priv->label,
455 CLUTTER_GRAVITY_CENTER);
456 clutter_actor_set_position (priv->label, CSW()/2, CSH()*0.95);
459 ensure_layout (window);
461 priv->timeline = clutter_timeline_new_for_duration (1200);
462 priv->alpha = clutter_alpha_new_full (priv->timeline,
463 clutter_sine_inc_func,
465 priv->behave = astro_behave_new (priv->alpha,
466 (AstroBehaveAlphaFunc)astro_music_alpha,
469 g_signal_connect (priv->timeline, "completed",
470 G_CALLBACK (on_main_timeline_completed), window);
472 clutter_timeline_start (priv->timeline);
474 g_signal_connect (window, "key-release-event",
475 G_CALLBACK (on_key_release_event), window);
476 clutter_grab_keyboard (CLUTTER_ACTOR (window));
479 clutter_actor_set_position (CLUTTER_ACTOR (window), 0, 0);
480 clutter_actor_show_all (CLUTTER_ACTOR (window));
484 astro_music_window_new (void)
486 AstroWindow *music_window = g_object_new (ASTRO_TYPE_MUSIC_WINDOW,