Initial Import
[profile/ivi/clutter-toys.git] / attic / woohaa / wh-slider-menu.c
1 #include <glib.h>
2 #include "wh-slider-menu.h"
3
4 #define CSW() CLUTTER_STAGE_WIDTH()
5 #define CSH() CLUTTER_STAGE_HEIGHT()
6
7 #define SELECTED_OFFSET (CLUTTER_STAGE_WIDTH()/5)
8
9 typedef struct WoohaaSliderMenuEntry
10 {
11   ClutterActor                   *actor;
12   WoohaaSliderMenuSelectedFunc    selected_func;
13   gpointer                        userdata;
14   gint                            offset;
15 }
16 WoohaaSliderMenuEntry;
17
18 #define WOOHAA_TYPE_BEHAVIOUR_SLIDER (clutter_behaviour_slider_get_type ())
19
20 #define WOOHAA_BEHAVIOUR_SLIDER(obj) \
21   (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
22   WOOHAA_TYPE_BEHAVIOUR_SLIDER, WoohaaBehaviourSlider))
23
24 #define WOOHAA_BEHAVIOUR_SLIDER_CLASS(klass) \
25   (G_TYPE_CHECK_CLASS_CAST ((klass), \
26   WOOHAA_TYPE_BEHAVIOUR_SLIDER, WoohaaBehaviourSliderClass))
27
28 #define CLUTTER_IS_BEHAVIOUR_SLIDER(obj) \
29   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
30   WOOHAA_TYPE_BEHAVIOUR_SLIDER))
31
32 #define CLUTTER_IS_BEHAVIOUR_SLIDER_CLASS(klass) \
33   (G_TYPE_CHECK_CLASS_TYPE ((klass), \
34   WOOHAA_TYPE_BEHAVIOUR_SLIDER))
35
36 #define WOOHAA_BEHAVIOUR_SLIDER_GET_CLASS(obj) \
37   (G_TYPE_INSTANCE_GET_CLASS ((obj), \
38   WOOHAA_TYPE_BEHAVIOUR_SLIDER, WoohaaBehaviourSliderClass))
39
40 typedef struct _WoohaaBehaviourSlider        WoohaaBehaviourSlider;
41 typedef struct _WoohaaBehaviourSliderClass   WoohaaBehaviourSliderClass;
42  
43 struct _WoohaaBehaviourSlider
44 {
45   ClutterBehaviour        parent;
46   WoohaaSliderMenuEntry  *old;
47   WoohaaSliderMenuEntry  *new;
48   WoohaaSliderMenu       *menu;
49 };
50
51 struct _WoohaaBehaviourSliderClass
52 {
53   ClutterBehaviourClass   parent_class;
54 };
55
56 GType clutter_behaviour_slider_get_type (void) G_GNUC_CONST;
57
58 G_DEFINE_TYPE (WoohaaBehaviourSlider, clutter_behaviour_slider, CLUTTER_TYPE_BEHAVIOUR);
59
60 static ClutterBehaviour*
61 clutter_behaviour_slider_new (WoohaaSliderMenu *menu,
62                               WoohaaSliderMenuEntry *start,
63                               WoohaaSliderMenuEntry *end);
64
65 struct _WoohaaSliderMenuPrivate
66 {
67   GList           *entrys;
68   gint             entry_height;
69   gint             menu_width;
70   gint             n_entrys;
71   gint             active_entry_num;
72   gint             offset;          /* current offset */
73   gint             unclipped_width;
74   ClutterActor    *bg;
75   ClutterActor    *entry_group;
76
77   guint            alpha_value;
78
79   ClutterTimeline        *timeline;
80   ClutterAlpha           *alpha;
81   ClutterBehaviour       *behave;
82   ClutterEffectTemplate  *effect_template;
83
84   gchar            *font;
85   ClutterColor     *font_color;
86   ClutterActor     *next, *prev;
87 };
88
89 G_DEFINE_TYPE (WoohaaSliderMenu, woohaa_slider_menu, CLUTTER_TYPE_ACTOR);
90
91 #define WOOHAA_SLIDER_MENU_GET_PRIVATE(obj) \
92     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), WOOHAA_TYPE_SLIDER_MENU, WoohaaSliderMenuPrivate))
93
94 static void
95 woohaa_slider_menu_dispose (GObject *object)
96 {
97   WoohaaSliderMenu        *self;
98   WoohaaSliderMenuPrivate *priv; 
99
100   self = WOOHAA_SLIDER_MENU(object); 
101   priv = self->priv;
102
103   G_OBJECT_CLASS (woohaa_slider_menu_parent_class)->dispose (object);
104 }
105
106 static void
107 woohaa_slider_menu_finalize (GObject *object)
108 {
109   WoohaaSliderMenu        *self;
110   WoohaaSliderMenuPrivate *priv; 
111
112   self = WOOHAA_SLIDER_MENU(object); 
113   priv = self->priv;
114
115   G_OBJECT_CLASS (woohaa_slider_menu_parent_class)->finalize (object);
116 }
117
118 static void
119 woohaa_slider_menu_paint (ClutterActor *actor)
120 {
121   WoohaaSliderMenuPrivate *priv = (WOOHAA_SLIDER_MENU (actor))->priv;
122   
123   clutter_actor_paint (priv->bg);
124   clutter_actor_paint (priv->next);
125   clutter_actor_paint (priv->prev);
126   clutter_actor_paint (priv->entry_group);
127 }
128
129 static void
130 woohaa_slider_menu_get_preferred_width  (ClutterActor *actor,
131                                          ClutterUnit   for_height,
132                                          ClutterUnit  *min_width_p,
133                                          ClutterUnit  *natural_width_p)
134 {
135   *min_width_p = CLUTTER_UNITS_FROM_INT (100);
136   *natural_width_p = CLUTTER_UNITS_FROM_INT (CSW());
137 }
138
139 static void
140 woohaa_slider_menu_get_preferred_height (ClutterActor *actor,
141                                          ClutterUnit   for_width,
142                                          ClutterUnit  *min_height_p,
143                                          ClutterUnit  *natural_height_p)
144 {
145   WoohaaSliderMenuPrivate *priv = (WOOHAA_SLIDER_MENU (actor))->priv;
146
147   *min_height_p = CLUTTER_UNITS_FROM_INT (1);
148   if (priv->entry_height)
149           *natural_height_p = CLUTTER_UNITS_FROM_INT (priv->entry_height * 2);
150   else
151           *natural_height_p = CLUTTER_UNITS_FROM_INT (200);
152 }
153
154 static void
155 woohaa_slider_menu_allocate (ClutterActor *actor, 
156                              const ClutterActorBox *box,
157                              gboolean absolute_origin_changed)
158 {
159   WoohaaSliderMenuPrivate *priv = (WOOHAA_SLIDER_MENU (actor))->priv;
160   ClutterUnit natural_width, natural_height;
161   ClutterActorBox child_box;
162   ClutterUnit focal_x, focal_y;
163   ClutterUnit entry_offset = 0, entry_width = 0;
164   WoohaaSliderMenuEntry *current, *old;
165   
166   clutter_actor_get_preferred_size (priv->bg, NULL, NULL, 
167                                     &natural_width, &natural_height);
168   child_box.x1 = 0;
169   child_box.y1 = 0;
170   child_box.x2 = natural_width;
171   child_box.y2 = natural_height;
172   clutter_actor_allocate (priv->bg, &child_box, absolute_origin_changed);
173
174   focal_x = CLUTTER_UNITS_FROM_INT(CSW()/4);
175   focal_y = 0;
176
177   if (priv->entrys)
178   {
179     current = (WOOHAA_BEHAVIOUR_SLIDER (priv->behave))->new;
180     old = (WOOHAA_BEHAVIOUR_SLIDER (priv->behave))->old;
181     
182     if (current && old)
183       {
184         entry_offset = (clutter_actor_get_xu (current->actor) - clutter_actor_get_xu (old->actor)) * 
185           ((gdouble)(priv->alpha_value) / (gdouble)CLUTTER_ALPHA_MAX_ALPHA) +
186           clutter_actor_get_xu (old->actor);
187
188         entry_width = (clutter_actor_get_widthu (current->actor) - clutter_actor_get_widthu (old->actor)) * 
189           ((gdouble)(priv->alpha_value) / (gdouble)CLUTTER_ALPHA_MAX_ALPHA) +
190           clutter_actor_get_widthu (old->actor);
191       }
192
193   }
194
195   child_box.x1 = focal_x - entry_offset;
196   child_box.y1 = focal_y;
197   child_box.x2 = natural_height/2 + child_box.x1 - entry_offset;
198   child_box.y2 = natural_height/2 + child_box.y1;
199   clutter_actor_allocate (priv->entry_group, 
200                           &child_box, 
201                           absolute_origin_changed);
202
203   if (priv->active_entry_num > 0)
204     {
205       clutter_actor_set_opacity (priv->prev, 0xAA);
206
207       child_box.x1 = focal_x - natural_height/2;
208       child_box.y1 = focal_y + natural_height/10;
209       child_box.x2 = natural_height/2 + child_box.x1;
210       child_box.y2 = natural_height/2 + child_box.y1;
211       clutter_actor_allocate (priv->prev, &child_box, absolute_origin_changed);
212     }
213   else
214     {
215       clutter_actor_set_opacity (priv->prev, 
216                                  0xff + (priv->alpha_value * (-0xff)
217                                          / CLUTTER_ALPHA_MAX_ALPHA));
218     }
219
220   if (priv->active_entry_num < priv->n_entrys - 1)
221     {
222       clutter_actor_set_opacity (priv->next, 0xAA);
223
224       child_box.x1 = focal_x + entry_width;
225       child_box.y1 = focal_y + natural_height/10;
226       child_box.x2 = natural_height/2 + child_box.x1;
227       child_box.y2 = natural_height/2 + child_box.y1;
228       clutter_actor_allocate (priv->next, &child_box, absolute_origin_changed);
229     }
230   else
231     {
232       clutter_actor_set_opacity (priv->next, 
233                                  0xff + (priv->alpha_value * (-0xff)
234                                          / CLUTTER_ALPHA_MAX_ALPHA));
235     }
236
237   CLUTTER_ACTOR_CLASS (woohaa_slider_menu_parent_class)->
238           allocate (actor, box, absolute_origin_changed);
239 }
240
241 static void
242 woohaa_slider_menu_class_init (WoohaaSliderMenuClass *klass)
243 {
244   GObjectClass *object_class     = G_OBJECT_CLASS (klass);
245   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
246
247   g_type_class_add_private (klass, sizeof (WoohaaSliderMenuPrivate));
248
249   object_class->dispose      = woohaa_slider_menu_dispose;
250   object_class->finalize     = woohaa_slider_menu_finalize;
251
252   actor_class->get_preferred_width  = woohaa_slider_menu_get_preferred_width;
253   actor_class->get_preferred_height = woohaa_slider_menu_get_preferred_height;
254   actor_class->allocate             = woohaa_slider_menu_allocate;
255   actor_class->paint                = woohaa_slider_menu_paint;
256 }
257
258 static void
259 woohaa_slider_menu_init (WoohaaSliderMenu *woohaa_slider_menu)
260 {
261   WoohaaSliderMenuPrivate   *priv;
262
263   woohaa_slider_menu->priv = priv =
264     G_TYPE_INSTANCE_GET_PRIVATE (woohaa_slider_menu,
265                                  WOOHAA_TYPE_SLIDER_MENU,
266                                  WoohaaSliderMenuPrivate);
267
268   priv->menu_width = CSW();
269
270   priv->timeline = clutter_timeline_new (30, 60);
271
272   priv->alpha = clutter_alpha_new_full (priv->timeline,
273                                         CLUTTER_ALPHA_SINE_INC,
274                                         NULL, NULL);
275
276   priv->behave = clutter_behaviour_slider_new (woohaa_slider_menu, 0, 0);
277
278   priv->effect_template 
279     = clutter_effect_template_new (clutter_timeline_new (20, 60),
280                                    CLUTTER_ALPHA_SINE_INC);
281
282   priv->font_color = g_new0(ClutterColor, 1);
283   clutter_color_parse ("#ccccccff", priv->font_color);
284
285   priv->bg = clutter_texture_new_from_file (PKGDATADIR "/header.svg", NULL);
286   if (!priv->bg) g_warning ("Unable to load heaer.svg");
287
288   clutter_actor_set_parent (priv->bg, CLUTTER_ACTOR (woohaa_slider_menu));
289
290   clutter_actor_set_width (priv->bg, CSW());
291   
292   clutter_actor_show (priv->bg);
293
294   priv->next = clutter_texture_new_from_file (PKGDATADIR "/arrow-next.svg", 
295                                               NULL);
296   if (!priv->next) g_warning ("Unable to load arror-next.svg");
297
298   clutter_actor_hide (priv->next);
299   clutter_actor_set_parent (priv->next, CLUTTER_ACTOR (woohaa_slider_menu));
300
301   priv->prev = clutter_texture_new_from_file (PKGDATADIR "/arrow-prev.svg", 
302                                               NULL);
303   if (!priv->prev) g_warning ("Unable to load arror-prev.svg");
304
305   clutter_actor_hide (priv->prev);
306   clutter_actor_set_parent (priv->prev, CLUTTER_ACTOR (woohaa_slider_menu));
307
308   priv->entry_group = clutter_group_new ();
309   clutter_actor_set_parent (priv->entry_group, 
310                             CLUTTER_ACTOR (woohaa_slider_menu));
311   clutter_actor_show (priv->entry_group);
312 }
313
314 ClutterActor*
315 woohaa_slider_menu_new (const gchar *font)
316 {
317   ClutterActor         *menu;
318   WoohaaSliderMenuPrivate  *priv;
319
320   menu = g_object_new (WOOHAA_TYPE_SLIDER_MENU, NULL);
321   priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
322   priv->font = g_strdup(font);
323
324   return menu;
325 }
326
327 void
328 woohaa_slider_menu_add_option (WoohaaSliderMenu            *menu, 
329                                const gchar                 *text,
330                                WoohaaSliderMenuSelectedFunc selected,
331                                gpointer                     userdata)
332 {
333   WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
334   WoohaaSliderMenuEntry    *entry;
335   ClutterActor             *actor;
336   gint                      pad = 0;
337
338   actor = clutter_label_new_with_text (priv->font, text);
339   clutter_label_set_color (CLUTTER_LABEL(actor), priv->font_color);
340   clutter_label_set_line_wrap (CLUTTER_LABEL(actor), FALSE);
341
342   entry = g_new0(WoohaaSliderMenuEntry, 1);
343   entry->actor = actor;
344   entry->selected_func = selected;
345   entry->userdata = userdata;
346
347   if (clutter_actor_get_height(actor) > priv->entry_height)
348     {
349       priv->entry_height = clutter_actor_get_height(actor);
350
351       clutter_actor_set_width (priv->bg, CSW());
352       clutter_actor_set_height (priv->bg, priv->entry_height
353         + (priv->entry_height/2));
354     }
355
356   if (clutter_actor_get_height(priv->next) > priv->entry_height)
357     {
358       gint w, h;
359
360       w = priv->entry_height/8;
361       h = priv->entry_height/4;
362       
363       clutter_actor_set_size (priv->next, w, h);
364       clutter_actor_set_size (priv->prev, w, h);
365     }
366
367   pad = clutter_actor_get_width (priv->next) * 2;
368
369   entry->offset = priv->unclipped_width + pad;
370
371   if (priv->entrys == NULL)
372     priv->unclipped_width += pad;
373
374   priv->unclipped_width += clutter_actor_get_width(actor) + pad;
375
376   if (priv->entrys == 0)
377     {
378       /* First Entry */
379       clutter_actor_set_opacity (actor, 0xff);
380     }
381   else
382     {
383       clutter_actor_set_opacity (actor, 0x33);
384       clutter_actor_set_scale (actor, 0.7, 0.7);
385     }
386
387   clutter_group_add (CLUTTER_GROUP (priv->entry_group), actor);
388
389   priv->entrys = g_list_append (priv->entrys, entry);
390
391   clutter_actor_set_position (actor, 
392                               entry->offset, 
393                               priv->entry_height/12);
394
395   priv->n_entrys++;
396 }
397
398 void
399 woohaa_slider_menu_activate (WoohaaSliderMenu *menu,
400                              gint              entry_num)
401 {
402   WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
403   WoohaaSliderMenuEntry *selected, *current;
404
405   if (entry_num < 0 || entry_num >= priv->n_entrys)
406       return;
407
408   if (clutter_timeline_is_playing(priv->timeline))
409     return;
410
411   current 
412     = (WoohaaSliderMenuEntry *)g_list_nth_data(priv->entrys, 
413                                                priv->active_entry_num);
414
415   selected = (WoohaaSliderMenuEntry *)g_list_nth_data(priv->entrys, 
416                                                       entry_num);
417
418   priv->active_entry_num = entry_num;
419
420   WOOHAA_BEHAVIOUR_SLIDER(priv->behave)->old = current;
421   WOOHAA_BEHAVIOUR_SLIDER(priv->behave)->new = selected;
422
423   clutter_actor_queue_relayout (CLUTTER_ACTOR (menu));
424
425   /* FIXME: Should be a signal */
426   if (selected->selected_func)
427     selected->selected_func(menu, selected->actor, selected->userdata);
428
429   clutter_timeline_start (priv->timeline);    
430 }
431
432 void
433 woohaa_slider_menu_advance (WoohaaSliderMenu *menu, gint n)
434 {
435   WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
436   woohaa_slider_menu_activate (menu, priv->active_entry_num + n);
437 }
438
439 /* Custom behaviour */
440
441 static void
442 clutter_behaviour_alpha_notify (ClutterBehaviour *behave,
443                                 guint32           alpha_value)
444 {
445   WoohaaBehaviourSlider *slide = WOOHAA_BEHAVIOUR_SLIDER(behave);
446   WoohaaSliderMenu      *menu;
447   gdouble                scale;
448   WoohaaSliderMenuPrivate  *priv;
449
450   if (!(slide->old) || !(slide->new))
451     return;
452
453   menu = slide->menu;
454   priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
455
456   priv->offset = slide->old->offset + 
457                       (((gint)alpha_value * 
458                           (slide->new->offset - slide->old->offset))
459                                / CLUTTER_ALPHA_MAX_ALPHA);
460
461   clutter_actor_set_opacity (slide->old->actor, 
462                              0xff + (alpha_value 
463                                      * (0x66 - 0xff)
464                                      / CLUTTER_ALPHA_MAX_ALPHA));
465
466   clutter_actor_set_opacity (slide->new->actor, 
467                              0x66 + (alpha_value 
468                                      * (0xff - 0x66)
469                                      / CLUTTER_ALPHA_MAX_ALPHA));
470
471   scale = (0.3 * alpha_value) / (gdouble)CLUTTER_ALPHA_MAX_ALPHA;
472
473   clutter_actor_set_scale (slide->new->actor,
474                            0.7 + scale,
475                            0.7 + scale);
476
477   if (slide->new->actor != slide->old->actor)
478     clutter_actor_set_scale (slide->old->actor,
479                              1.0 - scale,
480                              1.0 - scale);
481
482   priv->alpha_value = alpha_value;
483
484   if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(menu)))
485     clutter_actor_queue_relayout (CLUTTER_ACTOR (menu));
486 }
487
488 static void
489 clutter_behaviour_slider_class_init (WoohaaBehaviourSliderClass *klass)
490 {
491   ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
492
493   behave_class->alpha_notify = clutter_behaviour_alpha_notify;
494 }
495
496 static void
497 clutter_behaviour_slider_init (WoohaaBehaviourSlider *self)
498 {
499 }
500
501 static ClutterBehaviour*
502 clutter_behaviour_slider_new (WoohaaSliderMenu      *menu,
503                               WoohaaSliderMenuEntry *old,
504                               WoohaaSliderMenuEntry *new)
505 {
506   WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
507   WoohaaBehaviourSlider *slide_behave;
508
509   slide_behave = g_object_new (WOOHAA_TYPE_BEHAVIOUR_SLIDER, 
510                                "alpha", priv->alpha,
511                                NULL);
512
513   slide_behave->old   = old;
514   slide_behave->new   = new;
515   slide_behave->menu  = menu;
516
517   return CLUTTER_BEHAVIOUR(slide_behave);
518 }