Initial Import
[profile/ivi/clutter-toys.git] / attic / astro-desktop / applications / music / astro-songs.c
1 /*
2  * Copyright (C) 2007 OpenedHand Limited
3  *
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.
8  *
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.
13  *
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.
18  *
19  * Author: Neil Jagdish Patel <njp@o-hand.com>
20  */
21
22
23 #include "astro-songs.h"
24
25 #include <libastro-desktop/astro-defines.h>
26 #include <libastro-desktop/astro-application.h>
27 #include <libastro-desktop/astro-window.h>
28
29 #include "astro-music-window.h"
30
31 G_DEFINE_TYPE (AstroSongs, astro_songs, CLUTTER_TYPE_GROUP);
32
33 #define ASTRO_SONGS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
34         ASTRO_TYPE_SONGS, AstroSongsPrivate))
35         
36 struct _AstroSongsPrivate
37 {
38   ClutterActor *group;
39   ClutterActor *events;
40
41   gboolean mousedown;
42   gint     lasty;
43   gint     starty;
44   guint32  start_time;
45   gint     endy;
46   
47   ClutterEffectTemplate *temp;
48   ClutterTimeline       *timeline;
49 };
50
51 static gchar *song_names[] = {
52   "Oh Timbaland",
53   "Give It To Me",
54   "Release",
55   "The Way I Are",
56   "Bounce",
57   "Come And Get Me",
58   "Kill Yourself",
59   "Boardmeeting",
60   "Fantasy",
61   "Screem",
62   "Miscommunication",
63   "Bombay",
64   "Throw It On Me",
65   "Time",
66   "One And Only",
67   "Apologize",
68   "2 Man Show",
69   "Hello"
70 };
71
72 static gboolean on_event (AstroSongs *songs, ClutterEvent *event);
73
74 /* Public Functions */
75 void 
76 astro_songs_set_active (AstroSongs *songs, gboolean active)
77 {
78   AstroSongsPrivate *priv;
79
80   g_return_if_fail (ASTRO_IS_SONGS (songs));
81   priv = songs->priv;
82
83   if (active)
84     {
85       g_signal_connect (songs, "event", G_CALLBACK (on_event), NULL);
86     }
87   else
88     {
89       g_signal_handlers_disconnect_by_func (songs, on_event, NULL);
90       priv->mousedown = FALSE;
91     }
92 }
93
94
95 /* Private functions */
96 static void
97 bounds_check (ClutterActor *group, AstroSongs *songs)
98 {
99   AstroSongsPrivate *priv;
100   gint y, height;
101
102   g_return_if_fail (ASTRO_IS_SONGS (songs));
103   priv = songs->priv;
104
105   height = clutter_actor_get_height (group);
106   y = clutter_actor_get_y (group);
107    
108   if (y < 0 && y < (-1*height+(ALBUM_SIZE/2)))
109   {
110     y = (-1*height) + ALBUM_SIZE/2;
111   }
112   
113   if ( y > 0 && y > (ALBUM_SIZE/2))
114     {
115       y = ALBUM_SIZE/2;
116     }
117       
118   priv->timeline = clutter_effect_move (priv->temp, priv->group,
119                                         clutter_actor_get_x (priv->group),
120                                         y, 
121                                         NULL, NULL);
122 }
123
124 static gboolean 
125 on_event (AstroSongs *songs, ClutterEvent *event)
126 {
127 #define TIMEOUT 400
128 #define SPEED_FACTOR 1.5
129   AstroSongsPrivate *priv = songs->priv;
130     
131   if (event->type == CLUTTER_BUTTON_PRESS)
132     {
133       priv->starty = priv->lasty = event->button.y;
134       
135       priv->start_time = event->button.time;
136     
137       if (clutter_timeline_is_playing (priv->timeline))
138         clutter_timeline_stop (priv->timeline);
139     
140     }
141   else if (event->type == CLUTTER_BUTTON_RELEASE)
142     {
143       gint endy = clutter_actor_get_y (priv->group);
144       guint32 time = event->button.time - priv->start_time;
145       gfloat factor;
146       
147       factor = 2.0 - (time/event->button.time);
148     
149       if (time > TIMEOUT)
150         {
151           priv->endy = endy;
152         }
153       else if (event->button.y > priv->starty)
154         {
155           /* 
156           * The mouse from left to right, so we have to *add* pixels to the
157           * current group position to make it move to the right
158           */
159           endy += (event->motion.y - priv->starty) * SPEED_FACTOR * factor;
160           priv->endy = endy;
161         }
162       else if (event->button.y < priv->starty)
163         {
164           /* 
165           * The mouse from right to left, so we have to *minus* p.yels to the
166           * current group position to make it move to the left
167           */
168           endy -= (priv->starty - event->button.y) * SPEED_FACTOR * factor;
169           priv->endy = endy;
170         }
171       else
172         {
173           /* If the click was fast, treat it as a standard 'clicked' event */
174           if (time < TIMEOUT)
175             g_debug ("Song clicked\n");
176           priv->starty = priv->lasty = 0;
177           return FALSE;
178         }
179   
180      priv->timeline = clutter_effect_move (priv->temp, priv->group,
181                                           clutter_actor_get_x (priv->group),
182                                           priv->endy, 
183                                       (ClutterEffectCompleteFunc)bounds_check, 
184                                           songs);
185
186       priv->starty =  priv->lasty = 0;
187     }
188   else if (event->type == CLUTTER_MOTION)
189     {
190       gint offset;
191
192       if (!priv->starty)
193         return FALSE;
194       if (event->motion.y > priv->lasty)
195         {
196           offset = event->motion.y - priv->lasty;
197         }
198       else
199         {
200           offset = priv->lasty - event->motion.y;
201           offset *= -1;
202         }
203       priv->lasty = event->motion.y;
204       clutter_actor_set_position (priv->group,
205                                   clutter_actor_get_x (priv->group),
206                                   clutter_actor_get_y (priv->group)+ offset);
207     }  
208   
209   return FALSE;
210 }
211
212 /* GObject stuff */
213 static void
214 astro_songs_class_init (AstroSongsClass *klass)
215 {
216   GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
217   
218   g_type_class_add_private (gobject_class, sizeof (AstroSongsPrivate));
219 }
220
221 static void
222 astro_songs_init (AstroSongs *songs)
223 {
224 #define FONT_SIZE (ALBUM_SIZE/8)
225 #define ROW_SPACING (FONT_SIZE*1.3)
226 #define PAD 2
227   AstroSongsPrivate *priv;
228   ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
229   gchar *font = NULL;
230   gint i, offset = ROW_SPACING/2;
231
232   priv = songs->priv = ASTRO_SONGS_GET_PRIVATE (songs);
233
234   priv->mousedown = FALSE;
235
236   priv->group = clutter_group_new ();
237   clutter_container_add_actor (CLUTTER_CONTAINER (songs), priv->group);
238   clutter_actor_set_position (priv->group, 0, 0);
239
240   font = g_strdup_printf ("Sans %d", FONT_SIZE);
241
242   for (i = 0; i < 10; i++)
243     {
244       ClutterActor *row;
245            
246       row = clutter_label_new_full (font, song_names[i], &white);
247       
248       clutter_container_add_actor (CLUTTER_CONTAINER (priv->group), row);
249       clutter_actor_set_anchor_point_from_gravity (row, 
250                                                    CLUTTER_GRAVITY_WEST);
251       clutter_actor_set_position (row, 10, offset);
252       clutter_actor_set_scale (row, 1/ALBUM_SCALE, 1/ALBUM_SCALE);
253       clutter_actor_set_opacity (row, i%2 ? 200: 255);
254
255       offset += ROW_SPACING;
256     }
257
258   priv->timeline = clutter_timeline_new_for_duration (1000);
259   priv->temp = clutter_effect_template_new (priv->timeline,
260                                             clutter_sine_inc_func);
261
262   clutter_actor_set_reactive (CLUTTER_ACTOR (songs), TRUE);
263   
264   clutter_actor_set_clip (CLUTTER_ACTOR (songs), 
265                           PAD, PAD, ALBUM_SIZE-(2*PAD), ALBUM_SIZE-(2*PAD));
266  
267   clutter_actor_show_all (CLUTTER_ACTOR (priv->group));
268   clutter_actor_show_all (CLUTTER_ACTOR (songs));
269   g_free (font);
270 }
271
272 ClutterActor * 
273 astro_songs_new (void)
274 {
275   ClutterActor *songs =  g_object_new (ASTRO_TYPE_SONGS,
276                                              NULL);
277
278   return songs;
279 }
280