Initialize Tizen 2.3
[framework/uifw/elementary.git] / mobile / src / lib / elc_player.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_player.h"
4
5 #ifdef HAVE_EMOTION
6 # include <Emotion.h>
7 #endif
8
9 EAPI const char ELM_PLAYER_SMART_NAME[] = "elm_player";
10
11 static const char SIG_FORWARD_CLICKED[] = "forward,clicked";
12 static const char SIG_INFO_CLICKED[] = "info,clicked";
13 static const char SIG_NEXT_CLICKED[] = "next,clicked";
14 static const char SIG_PAUSE_CLICKED[] = "pause,clicked";
15 static const char SIG_PLAY_CLICKED[] = "play,clicked";
16 static const char SIG_PREV_CLICKED[] = "prev,clicked";
17 static const char SIG_REWIND_CLICKED[] = "rewind,clicked";
18 static const char SIG_STOP_CLICKED[] = "stop,clicked";
19 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
20    { SIG_FORWARD_CLICKED, "" },
21    { SIG_INFO_CLICKED, "" },
22    { SIG_NEXT_CLICKED, "" },
23    { SIG_PAUSE_CLICKED, "" },
24    { SIG_PLAY_CLICKED, "" },
25    { SIG_PREV_CLICKED, "" },
26    { SIG_REWIND_CLICKED, "" },
27    { SIG_STOP_CLICKED, "" },
28    { NULL, NULL }
29 };
30
31 EVAS_SMART_SUBCLASS_NEW
32   (ELM_PLAYER_SMART_NAME, _elm_player, Elm_Player_Smart_Class,
33   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
34
35 #ifdef HAVE_EMOTION
36 static Eina_Bool
37 _elm_player_smart_event(Evas_Object *obj,
38                         Evas_Object *src __UNUSED__,
39                         Evas_Callback_Type type,
40                         void *event_info)
41 {
42    Evas_Event_Key_Down *ev = event_info;
43
44    ELM_PLAYER_DATA_GET(obj, sd);
45
46    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
47    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
48    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
49    if (!sd->video) return EINA_FALSE;
50
51    if ((!strcmp(ev->keyname, "Left")) ||
52        ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string)))
53      {
54         double current, last;
55
56         current = elm_video_play_position_get(sd->video);
57         last = elm_video_play_length_get(sd->video);
58
59         if (current < last)
60           {
61              current -= last / 100;
62              elm_video_play_position_set(sd->video, current);
63           }
64
65         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
66         return EINA_TRUE;
67      }
68    if ((!strcmp(ev->keyname, "Right")) ||
69        ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string)))
70      {
71         double current, last;
72
73         current = elm_video_play_position_get(sd->video);
74         last = elm_video_play_length_get(sd->video);
75
76         if (current > 0)
77           {
78              current += last / 100;
79              if (current < 0) current = 0;
80              elm_video_play_position_set(sd->video, current);
81           }
82
83         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
84         return EINA_TRUE;
85      }
86    if (!strcmp(ev->keyname, "space"))
87      {
88         if (elm_video_is_playing_get(sd->video))
89           elm_video_pause(sd->video);
90         else
91           elm_video_play(sd->video);
92         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
93         return EINA_TRUE;
94      }
95    fprintf(stderr, "keyname: '%s' not handle\n", ev->keyname);
96
97    return EINA_FALSE;
98 }
99
100 static Eina_Bool
101 _elm_player_smart_theme(Evas_Object *obj)
102 {
103    ELM_PLAYER_DATA_GET(obj, sd);
104
105    if (!ELM_WIDGET_CLASS(_elm_player_parent_sc)->theme(obj)) return EINA_FALSE;
106
107 #define UPDATE_THEME(Target, Name)                                    \
108   if (Target)                                                         \
109     {                                                                 \
110        elm_object_style_set(Target, elm_widget_style_get(obj));       \
111        if (!elm_layout_content_set(obj, Name, Target))                \
112          evas_object_hide(Target);                                    \
113        elm_object_disabled_set(Target, elm_widget_disabled_get(obj)); \
114     }
115
116    UPDATE_THEME(sd->forward, "media_player/forward");
117    UPDATE_THEME(sd->info, "media_player/info");
118    UPDATE_THEME(sd->next, "media_player/next");
119    UPDATE_THEME(sd->pause, "media_player/pause");
120    UPDATE_THEME(sd->play, "media_player/play");
121    UPDATE_THEME(sd->prev, "media_player/prev");
122    UPDATE_THEME(sd->rewind, "media_player/rewind");
123    UPDATE_THEME(sd->next, "media_player/next");
124    UPDATE_THEME(sd->slider, "media_player/slider");
125
126    elm_layout_sizing_eval(obj);
127
128    return EINA_TRUE;
129 }
130
131 static void
132 _elm_player_smart_sizing_eval(Evas_Object *obj)
133 {
134    Evas_Coord w, h;
135
136    ELM_PLAYER_DATA_GET(obj, sd);
137
138    edje_object_size_min_get(ELM_WIDGET_DATA(sd)->resize_obj, &w, &h);
139    edje_object_size_min_restricted_calc
140      (ELM_WIDGET_DATA(sd)->resize_obj, &w, &h, w, h);
141    evas_object_size_hint_min_set(obj, w, h);
142 }
143
144 static void
145 _update_slider(void *data,
146                Evas_Object *obj __UNUSED__,
147                void *event_info __UNUSED__)
148 {
149    double pos, length;
150    Eina_Bool seekable;
151
152    ELM_PLAYER_DATA_GET(data, sd);
153
154    seekable = elm_video_is_seekable_get(sd->video);
155    length = elm_video_play_length_get(sd->video);
156    pos = elm_video_play_position_get(sd->video);
157
158    elm_object_disabled_set(sd->slider, !seekable);
159    elm_slider_min_max_set(sd->slider, 0, length);
160    elm_slider_value_set(sd->slider, pos);
161 }
162
163 static void
164 _update_position(void *data,
165                  Evas_Object *obj __UNUSED__,
166                  void *event_info __UNUSED__)
167 {
168    ELM_PLAYER_DATA_GET(data, sd);
169
170    elm_video_play_position_set(sd->video, elm_slider_value_get(sd->slider));
171 }
172
173 static void
174 _forward(void *data,
175          Evas_Object *obj __UNUSED__,
176          void *event_info __UNUSED__)
177 {
178    double pos, length;
179
180    ELM_PLAYER_DATA_GET(data, sd);
181
182    pos = elm_video_play_position_get(sd->video);
183    length = elm_video_play_length_get(sd->video);
184
185    pos += length * 0.3;
186    elm_video_play_position_set(sd->video, pos);
187
188    elm_layout_signal_emit(data, "elm,button,forward", "elm");
189    evas_object_smart_callback_call(data, SIG_FORWARD_CLICKED, NULL);
190 }
191
192 static void
193 _info(void *data,
194       Evas_Object *obj __UNUSED__,
195       void *event_info __UNUSED__)
196 {
197    elm_layout_signal_emit(data, "elm,button,info", "elm");
198    evas_object_smart_callback_call(data, SIG_INFO_CLICKED, NULL);
199 }
200
201 static void
202 _next(void *data,
203       Evas_Object *obj __UNUSED__,
204       void *event_info __UNUSED__)
205 {
206    double pos, length;
207
208    ELM_PLAYER_DATA_GET(data, sd);
209
210    pos = elm_video_play_position_get(sd->video);
211    length = elm_video_play_length_get(sd->video);
212
213    pos += length * 0.1;
214    elm_video_play_position_set(sd->video, pos);
215
216    elm_layout_signal_emit(data, "elm,button,next", "elm");
217    evas_object_smart_callback_call(data, SIG_NEXT_CLICKED, NULL);
218 }
219
220 static void
221 _pause(void *data,
222        Evas_Object *obj __UNUSED__,
223        void *event_info __UNUSED__)
224 {
225    ELM_PLAYER_DATA_GET(data, sd);
226
227    elm_layout_signal_emit(data, "elm,player,pause", "elm");
228    elm_video_pause(sd->video);
229
230    elm_layout_signal_emit(data, "elm,button,pause", "elm");
231    evas_object_smart_callback_call(data, SIG_PAUSE_CLICKED, NULL);
232 }
233
234 static void
235 _play(void *data,
236       Evas_Object *obj __UNUSED__,
237       void *event_info __UNUSED__)
238 {
239    ELM_PLAYER_DATA_GET(data, sd);
240
241    elm_video_play(sd->video);
242    elm_layout_signal_emit(data, "elm,button,play", "elm");
243    evas_object_smart_callback_call(data, SIG_PLAY_CLICKED, NULL);
244 }
245
246 static void
247 _prev(void *data,
248       Evas_Object *obj __UNUSED__,
249       void *event_info __UNUSED__)
250 {
251    double pos, length;
252
253    ELM_PLAYER_DATA_GET(data, sd);
254
255    pos = elm_video_play_position_get(sd->video);
256    length = elm_video_play_length_get(sd->video);
257
258    pos -= length * 0.1;
259    elm_video_play_position_set(sd->video, pos);
260    evas_object_smart_callback_call(data, SIG_PREV_CLICKED, NULL);
261    elm_layout_signal_emit(data, "elm,button,prev", "elm");
262 }
263
264 static void
265 _rewind(void *data,
266         Evas_Object *obj __UNUSED__,
267         void *event_info __UNUSED__)
268 {
269    ELM_PLAYER_DATA_GET(data, sd);
270
271    elm_video_play_position_set(sd->video, 0);
272    elm_layout_signal_emit(data, "elm,button,rewind", "elm");
273    evas_object_smart_callback_call(data, SIG_REWIND_CLICKED, NULL);
274 }
275
276 static void
277 _stop(void *data,
278       Evas_Object *obj __UNUSED__,
279       void *event_info __UNUSED__)
280 {
281    elm_layout_signal_emit(data, "elm,button,stop", "elm");
282    evas_object_smart_callback_call(data, SIG_STOP_CLICKED, NULL);
283 }
284
285 static void
286 _play_started(void *data,
287               Evas_Object *obj __UNUSED__,
288               void *event_info __UNUSED__)
289 {
290    elm_layout_signal_emit(data, "elm,player,play", "elm");
291 }
292
293 static void
294 _play_finished(void *data,
295                Evas_Object *obj __UNUSED__,
296                void *event_info __UNUSED__)
297 {
298    elm_layout_signal_emit(data, "elm,player,pause", "elm");
299 }
300
301 static void
302 _on_video_del(Elm_Player_Smart_Data *sd)
303 {
304    elm_object_disabled_set(sd->slider, EINA_TRUE);
305    elm_object_disabled_set(sd->forward, EINA_TRUE);
306    elm_object_disabled_set(sd->info, EINA_TRUE);
307    elm_object_disabled_set(sd->next, EINA_TRUE);
308    elm_object_disabled_set(sd->pause, EINA_TRUE);
309    elm_object_disabled_set(sd->play, EINA_TRUE);
310    elm_object_disabled_set(sd->prev, EINA_TRUE);
311    elm_object_disabled_set(sd->rewind, EINA_TRUE);
312    elm_object_disabled_set(sd->next, EINA_TRUE);
313
314    sd->video = NULL;
315    sd->emotion = NULL;
316 }
317
318 static void
319 _video_del(void *data,
320            Evas *e __UNUSED__,
321            Evas_Object *obj __UNUSED__,
322            void *event_info __UNUSED__)
323 {
324    _on_video_del(data);
325 }
326
327 static Evas_Object *
328 _player_button_add(Evas_Object *obj,
329                    const char *name,
330                    Evas_Smart_Cb func)
331 {
332    Evas_Object *ic;
333    Evas_Object *bt;
334
335    ic = elm_icon_add(obj);
336    elm_icon_standard_set(ic, name);
337    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
338
339    bt = elm_button_add(obj);
340    elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
341    elm_object_part_content_set(bt, "icon", ic);
342    evas_object_size_hint_align_set(bt, 0.0, 0.0);
343    elm_object_style_set(bt, "anchor");
344    evas_object_smart_callback_add(bt, "clicked", func, obj);
345
346    if (!elm_layout_content_set(obj, name, bt))
347      {
348         elm_widget_sub_object_add(obj, bt);
349         evas_object_hide(bt);
350      }
351
352    return bt;
353 }
354
355 static char *
356 _double_to_time(double value)
357 {
358    char buf[256];
359    int ph, pm, ps, pf;
360
361    ph = value / 3600;
362    pm = value / 60 - (ph * 60);
363    ps = value - (pm * 60);
364    pf = value * 100 - (ps * 100) - (pm * 60 * 100) - (ph * 60 * 60 * 100);
365
366    if (ph)
367      snprintf(buf, sizeof(buf), "%i:%02i:%02i.%02i",
368               ph, pm, ps, pf);
369    else if (pm)
370      snprintf(buf, sizeof(buf), "%02i:%02i.%02i",
371               pm, ps, pf);
372    else
373      snprintf(buf, sizeof(buf), "%02i.%02i",
374               ps, pf);
375
376    return (char *)eina_stringshare_add(buf);
377 }
378
379 static void
380 _str_free(char *data)
381 {
382    eina_stringshare_del(data);
383 }
384
385 /* a video object is never parented by a player one, just tracked.
386  * treating this special case here and delegating other objects to own
387  * layout */
388 static Eina_Bool
389 _elm_player_smart_content_set(Evas_Object *obj,
390                               const char *part,
391                               Evas_Object *content)
392 {
393    double pos, length;
394    Eina_Bool seekable;
395
396    if (part && strcmp(part, "video"))
397      return ELM_CONTAINER_CLASS(_elm_player_parent_sc)->content_set
398               (obj, part, content);
399
400    ELM_PLAYER_DATA_GET(obj, sd);
401
402    if (!_elm_video_check(content)) return EINA_FALSE;
403    if (sd->video == content) return EINA_TRUE;
404
405    if (sd->video) evas_object_del(sd->video);
406
407    sd->video = content;
408
409    if (!content) return EINA_TRUE;
410
411    elm_object_disabled_set(sd->slider, EINA_FALSE);
412    elm_object_disabled_set(sd->forward, EINA_FALSE);
413    elm_object_disabled_set(sd->info, EINA_FALSE);
414    elm_object_disabled_set(sd->next, EINA_FALSE);
415    elm_object_disabled_set(sd->pause, EINA_FALSE);
416    elm_object_disabled_set(sd->play, EINA_FALSE);
417    elm_object_disabled_set(sd->prev, EINA_FALSE);
418    elm_object_disabled_set(sd->rewind, EINA_FALSE);
419    elm_object_disabled_set(sd->next, EINA_FALSE);
420
421    sd->emotion = elm_video_emotion_get(sd->video);
422    emotion_object_priority_set(sd->emotion, EINA_TRUE);
423    evas_object_event_callback_add
424      (sd->video, EVAS_CALLBACK_DEL, _video_del, sd);
425
426    seekable = elm_video_is_seekable_get(sd->video);
427    length = elm_video_play_length_get(sd->video);
428    pos = elm_video_play_position_get(sd->video);
429
430    elm_object_disabled_set(sd->slider, !seekable);
431    elm_slider_min_max_set(sd->slider, 0, length);
432    elm_slider_value_set(sd->slider, pos);
433
434    if (elm_video_is_playing_get(sd->video))
435      elm_layout_signal_emit(obj, "elm,player,play", "elm");
436    else elm_layout_signal_emit(obj, "elm,player,pause", "elm");
437
438    evas_object_smart_callback_add(sd->emotion, "frame_decode",
439                                   _update_slider, obj);
440    evas_object_smart_callback_add(sd->emotion, "frame_resize",
441                                   _update_slider, obj);
442    evas_object_smart_callback_add(sd->emotion, "length_change",
443                                   _update_slider, obj);
444    evas_object_smart_callback_add(sd->emotion, "position_update",
445                                   _update_slider, obj);
446    evas_object_smart_callback_add(sd->emotion, "playback_started",
447                                   _play_started, obj);
448    evas_object_smart_callback_add(sd->emotion, "playback_finished",
449                                   _play_finished, obj);
450
451    /* FIXME: track info from video */
452
453    return EINA_TRUE;
454 }
455
456 static void
457 _elm_player_smart_add(Evas_Object *obj)
458 {
459    EVAS_SMART_DATA_ALLOC(obj, Elm_Player_Smart_Data);
460
461    ELM_WIDGET_CLASS(_elm_player_parent_sc)->base.add(obj);
462
463    elm_layout_theme_set(obj, "player", "base", elm_widget_style_get(obj));
464
465    priv->forward = _player_button_add(obj, "media_player/forward", _forward);
466    priv->info = _player_button_add(obj, "media_player/info", _info);
467    priv->next = _player_button_add(obj, "media_player/next", _next);
468    priv->pause = _player_button_add(obj, "media_player/pause", _pause);
469    priv->play = _player_button_add(obj, "media_player/play", _play);
470    priv->prev = _player_button_add(obj, "media_player/prev", _prev);
471    priv->rewind = _player_button_add(obj, "media_player/rewind", _rewind);
472    priv->stop = _player_button_add(obj, "media_player/stop", _stop);
473
474    priv->slider = elm_slider_add(obj);
475    elm_slider_indicator_format_function_set
476      (priv->slider, _double_to_time, _str_free);
477    elm_slider_units_format_function_set
478      (priv->slider, _double_to_time, _str_free);
479    elm_slider_min_max_set(priv->slider, 0, 0);
480    elm_slider_value_set(priv->slider, 0);
481    elm_object_disabled_set(priv->slider, EINA_TRUE);
482    evas_object_size_hint_align_set(priv->slider, EVAS_HINT_FILL, 0.5);
483    evas_object_size_hint_weight_set
484      (priv->slider, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
485
486    elm_layout_content_set(obj, "media_player/slider", priv->slider);
487    evas_object_smart_callback_add
488      (priv->slider, "changed", _update_position, obj);
489
490    elm_layout_sizing_eval(obj);
491    elm_widget_can_focus_set(obj, EINA_TRUE);
492 }
493
494 #endif
495
496 static void
497 _elm_player_smart_set_user(Elm_Player_Smart_Class *sc)
498 {
499 #ifdef HAVE_EMOTION
500    ELM_WIDGET_CLASS(sc)->base.add = _elm_player_smart_add;
501
502    ELM_WIDGET_CLASS(sc)->event = _elm_player_smart_event;
503    ELM_WIDGET_CLASS(sc)->theme = _elm_player_smart_theme;
504
505    ELM_CONTAINER_CLASS(sc)->content_set = _elm_player_smart_content_set;
506
507    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_player_smart_sizing_eval;
508 #else
509    (void) sc;
510 #endif
511 }
512
513 EAPI const Elm_Player_Smart_Class *
514 elm_player_smart_class_get(void)
515 {
516    static Elm_Player_Smart_Class _sc =
517      ELM_PLAYER_SMART_CLASS_INIT_NAME_VERSION(ELM_PLAYER_SMART_NAME);
518    static const Elm_Player_Smart_Class *class = NULL;
519    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
520
521    if (class)
522      return class;
523
524    _elm_player_smart_set(&_sc);
525    esc->callbacks = _smart_callbacks;
526    class = &_sc;
527
528    return class;
529 }
530
531 EAPI Evas_Object *
532 elm_player_add(Evas_Object *parent)
533 {
534 #ifdef HAVE_EMOTION
535    Evas_Object *obj;
536
537    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
538
539    obj = elm_widget_add(_elm_player_smart_class_new(), parent);
540    if (!obj) return NULL;
541
542    if (!elm_widget_sub_object_add(parent, obj))
543      ERR("could not add %p as sub object of %p", obj, parent);
544
545    return obj;
546 #else
547    (void) parent;
548    (void) _elm_player_smart_class_new;
549    return NULL;
550 #endif
551 }