Tizen 2.1 release
[platform/core/uifw/e17.git] / src / modules / mixer / app_mixer.c
1 #include "e_mod_main.h"
2
3 extern const char _e_mixer_Name[];
4
5 typedef struct E_Mixer_App_Dialog_Data
6 {
7    E_Mixer_System       *sys;
8    const char           *card;
9    const char           *channel_name;
10    int                   lock_sliders;
11    Eina_List            *cards;
12    Eina_List            *channels_infos;
13    struct channel_info  *channel_info;
14    E_Mixer_Channel_State state;
15
16    struct e_mixer_app_ui
17    {
18       Evas_Object *hlayout;
19       struct e_mixer_app_ui_cards
20       {
21          Evas_Object *frame;
22          Evas_Object *list;
23       } cards;
24       struct e_mixer_app_ui_channels
25       {
26          Evas_Object *frame;
27          Evas_Object *list;
28       } channels;
29       struct e_mixer_app_ui_channel_editor
30       {
31          Evas_Object *frame;
32          Evas_Object *label_card;
33          Evas_Object *card;
34          Evas_Object *label_channel;
35          Evas_Object *channel;
36          Evas_Object *label_type;
37          Evas_Object *type;
38          Evas_Object *label_left;
39          Evas_Object *left;
40          Evas_Object *label_right;
41          Evas_Object *right;
42          Evas_Object *mute;
43          Evas_Object *lock_sliders;
44       } channel_editor;
45    } ui;
46
47    struct
48    {
49       void *data;
50       void (*func)(E_Dialog *dialog, void *data);
51    } del;
52 } E_Mixer_App_Dialog_Data;
53
54 struct channel_info
55 {
56    int                      has_capture;
57    const char              *name;
58    E_Mixer_Channel         *id;
59    E_Mixer_App_Dialog_Data *app;
60 };
61
62 static void
63 _cb_changed_left(void *data, Evas_Object *obj __UNUSED__)
64 {
65    E_Mixer_App_Dialog_Data *app = data;
66    E_Mixer_Channel_State *state;
67
68    state = &app->state;
69    if (app->lock_sliders && (state->left != state->right))
70      {
71         state->right = state->left;
72         e_widget_slider_value_int_set(app->ui.channel_editor.right,
73                                       state->right);
74      }
75
76    e_mod_mixer_volume_set(app->sys, app->channel_info->id,
77                           state->left, state->right);
78 }
79
80 static void
81 _cb_changed_right(void *data, Evas_Object *obj __UNUSED__)
82 {
83    E_Mixer_App_Dialog_Data *app = data;
84    E_Mixer_Channel_State *state;
85
86    state = &app->state;
87    if (app->lock_sliders && (state->right != state->left))
88      {
89         state->left = state->right;
90         e_widget_slider_value_int_set(app->ui.channel_editor.left,
91                                       state->left);
92      }
93
94    e_mod_mixer_volume_set(app->sys, app->channel_info->id,
95                           state->left, state->right);
96 }
97
98 static void
99 _cb_changed_mute(void *data, Evas_Object *obj __UNUSED__)
100 {
101    E_Mixer_App_Dialog_Data *app = data;
102
103    e_mod_mixer_mute_set(app->sys, app->channel_info->id, app->state.mute);
104 }
105
106 static void
107 _cb_changed_lock_sliders(void *data, Evas_Object *obj __UNUSED__)
108 {
109    E_Mixer_App_Dialog_Data *app = data;
110    E_Mixer_Channel_State *state;
111
112    if (!app->lock_sliders)
113      return;
114
115    state = &app->state;
116    if (state->left == state->right)
117      return;
118
119    state->left = state->right = (state->left + state->right) / 2;
120
121    e_widget_slider_value_int_set(app->ui.channel_editor.left, state->left);
122    e_widget_slider_value_int_set(app->ui.channel_editor.right, state->right);
123    e_mod_mixer_volume_set(app->sys, app->channel_info->id,
124                           state->left, state->right);
125 }
126
127 static void
128 _update_channel_editor_state(E_Mixer_App_Dialog_Data *app, const E_Mixer_Channel_State state)
129 {
130    struct e_mixer_app_ui_channel_editor *ui = &app->ui.channel_editor;
131
132    e_widget_slider_value_int_set(ui->left, state.left);
133    e_widget_slider_value_int_set(ui->right, state.right);
134
135    if (e_mod_mixer_mutable_get(app->sys, app->channel_info->id))
136      {
137         e_widget_disabled_set(ui->mute, 0);
138         e_widget_check_checked_set(ui->mute, state.mute);
139      }
140    else
141      {
142         e_widget_disabled_set(ui->mute, 1);
143         e_widget_check_checked_set(ui->mute, 0);
144      }
145 }
146
147 static void
148 _populate_channel_editor(E_Mixer_App_Dialog_Data *app)
149 {
150    struct e_mixer_app_ui_channel_editor *ui = &app->ui.channel_editor;
151    E_Mixer_Channel_State state;
152    const char *card_name;
153
154    card_name = e_mod_mixer_card_name_get(app->card);
155    
156    if (!card_name)
157      return;
158    
159    e_widget_entry_text_set(ui->card, card_name);
160    eina_stringshare_del(card_name);
161
162    e_widget_entry_text_set(ui->channel, app->channel_name);
163
164    if (e_mod_mixer_capture_get(app->sys, app->channel_info->id))
165      e_widget_entry_text_set(ui->type, _("Capture"));
166    else
167      e_widget_entry_text_set(ui->type, _("Playback"));
168
169    e_mod_mixer_state_get(app->sys, app->channel_info->id, &state);
170    _update_channel_editor_state(app, state);
171
172    app->lock_sliders = (state.left == state.right);
173    e_widget_check_checked_set(ui->lock_sliders, app->lock_sliders);
174 }
175
176 static void
177 _cb_channel_selected(void *data)
178 {
179    struct channel_info *info = data;
180    E_Mixer_App_Dialog_Data *app;
181
182    app = info->app;
183    app->channel_info = info;
184    _populate_channel_editor(app);
185 }
186
187 static int
188 _channel_info_cmp(const void *data_a, const void *data_b)
189 {
190    const struct channel_info *a = data_a, *b = data_b;
191
192    if (a->has_capture < b->has_capture)
193      return -1;
194    else if (a->has_capture > b->has_capture)
195      return 1;
196
197    return strcmp(a->name, b->name);
198 }
199
200 static Eina_List *
201 _channels_info_new(E_Mixer_System *sys)
202 {
203    Eina_List *channels, *channels_infos, *l;
204
205    channels = e_mod_mixer_channels_get(sys);
206    channels_infos = NULL;
207    for (l = channels; l; l = l->next)
208      {
209         struct channel_info *info;
210
211         info = malloc(sizeof(*info));
212         info->id = l->data;
213         info->name = e_mod_mixer_channel_name_get(sys, info->id);
214         info->has_capture = e_mod_mixer_capture_get(sys, info->id);
215
216         channels_infos = eina_list_append(channels_infos, info);
217      }
218    e_mod_mixer_channels_free(channels);
219
220    return eina_list_sort(channels_infos, -1, _channel_info_cmp);
221 }
222
223 static void
224 _channels_info_free(Eina_List *list)
225 {
226    struct channel_info *info;
227
228    EINA_LIST_FREE(list, info)
229      {
230         eina_stringshare_del(info->name);
231         free(info);
232      }
233 }
234
235 static int
236 _cb_system_update(void *data, E_Mixer_System *sys __UNUSED__)
237 {
238    E_Mixer_App_Dialog_Data *app = data;
239    E_Mixer_Channel_State state;
240
241    if ((!app->sys) || (!app->channel_info))
242      return 1;
243
244    e_mod_mixer_state_get(app->sys, app->channel_info->id, &state);
245    _update_channel_editor_state(app, state);
246
247    return 1;
248 }
249
250 static void
251 _populate_channels(E_Mixer_App_Dialog_Data *app)
252 {
253    Eina_List *l;
254    Evas_Object *ilist;
255    int header_input;
256    int i;
257
258    ilist = app->ui.channels.list;
259    edje_freeze();
260    e_widget_ilist_freeze(ilist);
261    e_widget_ilist_clear(ilist);
262
263    if (app->sys)
264      e_mod_mixer_del(app->sys);
265    app->sys = e_mod_mixer_new(app->card);
266    if (_mixer_using_default)
267      e_mixer_system_callback_set(app->sys, _cb_system_update, app);
268
269    eina_stringshare_del(app->channel_name);
270    app->channel_name = e_mod_mixer_channel_default_name_get(app->sys);
271
272    if (app->channels_infos)
273      _channels_info_free(app->channels_infos);
274    app->channels_infos = _channels_info_new(app->sys);
275
276    if (app->channels_infos)
277      {
278         struct channel_info *info = app->channels_infos->data;
279         if (info->has_capture)
280           {
281              e_widget_ilist_header_append(ilist, NULL, _("Input"));
282              header_input = 1;
283              i = 1;
284           }
285         else
286           {
287              e_widget_ilist_header_append(ilist, NULL, _("Output"));
288              header_input = 0;
289              i = 1;
290           }
291      }
292
293    for (l = app->channels_infos; l; l = l->next, i++)
294      {
295         struct channel_info *info = l->data;
296
297         if ((!header_input) && info->has_capture)
298           {
299              e_widget_ilist_header_append(ilist, NULL, _("Input"));
300              header_input = 1;
301              i++;
302           }
303
304         info->app = app;
305         e_widget_ilist_append(ilist, NULL, info->name, _cb_channel_selected,
306                               info, info->name);
307         if (app->channel_name && info->name &&
308             (strcmp(app->channel_name, info->name) == 0))
309           {
310              e_widget_ilist_selected_set(ilist, i);
311              app->channel_info = info;
312           }
313      }
314
315    e_widget_ilist_go(ilist);
316    e_widget_ilist_thaw(ilist);
317    edje_thaw();
318 }
319
320 static void
321 select_card(E_Mixer_App_Dialog_Data *app)
322 {
323    _populate_channels(app);
324    e_widget_ilist_selected_set(app->ui.channels.list, 1);
325 }
326
327 static void
328 _cb_card_selected(void *data)
329 {
330    select_card(data);
331 }
332
333 static void
334 _create_cards(E_Dialog *dialog __UNUSED__, Evas *evas, E_Mixer_App_Dialog_Data *app)
335 {
336    struct e_mixer_app_ui_cards *ui = &app->ui.cards;
337    const char *card;
338    Eina_List *l;
339
340    app->card = e_mod_mixer_card_default_get();
341    app->cards = e_mod_mixer_cards_get();
342    if (eina_list_count(app->cards) < 2)
343      return;
344
345    ui->list = e_widget_ilist_add(evas, 32, 32, &app->card);
346    e_widget_size_min_set(ui->list, 180, 100);
347    e_widget_ilist_go(ui->list);
348    EINA_LIST_FOREACH(app->cards, l, card)
349      {
350         const char *card_name;
351
352         card_name = e_mod_mixer_card_name_get(card);
353         
354         if (!card_name)
355           continue;
356
357         e_widget_ilist_append(ui->list, NULL, card_name, _cb_card_selected,
358                               app, card);
359
360         eina_stringshare_del(card_name);
361      }
362
363    ui->frame = e_widget_framelist_add(evas, _("Cards"), 0);
364    e_widget_framelist_object_append(ui->frame, ui->list);
365    e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 0, 0.0);
366 }
367
368 static void
369 _create_channels(E_Dialog *dialog __UNUSED__, Evas *evas, E_Mixer_App_Dialog_Data *app)
370 {
371    struct e_mixer_app_ui_channels *ui = &app->ui.channels;
372    ui->list = e_widget_ilist_add(evas, 24, 24, &app->channel_name);
373    e_widget_size_min_set(ui->list, 180, 100);
374    e_widget_ilist_go(ui->list);
375
376    ui->frame = e_widget_framelist_add(evas, _("Channels"), 0);
377    e_widget_framelist_object_append(ui->frame, ui->list);
378    e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 1, 0.0);
379 }
380
381 static void
382 _create_channel_editor(E_Dialog *dialog __UNUSED__, Evas *evas, E_Mixer_App_Dialog_Data *app)
383 {
384    struct e_mixer_app_ui_channel_editor *ui = &app->ui.channel_editor;
385
386    ui->label_card = e_widget_label_add(evas, _("Card:"));
387    ui->card = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
388    e_widget_entry_readonly_set(ui->card, 1);
389
390    ui->label_channel = e_widget_label_add(evas, _("Channel:"));
391    ui->channel = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
392    e_widget_entry_readonly_set(ui->channel, 1);
393
394    ui->label_type = e_widget_label_add(evas, _("Type:"));
395    ui->type = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
396    e_widget_entry_readonly_set(ui->type, 1);
397
398    ui->label_left = e_widget_label_add(evas, _("Left:"));
399    ui->left = e_widget_slider_add(evas, 1, 0, "%3.0f", 0.0, 100.0, 10.0, 100.0,
400                                   NULL, &app->state.left, 150);
401    e_widget_on_change_hook_set(ui->left, _cb_changed_left, app);
402
403    ui->label_right = e_widget_label_add(evas, _("Right:"));
404    ui->right = e_widget_slider_add(evas, 1, 0, "%3.0f", 0.0, 100.0, 10.0, 100.0,
405                                    NULL, &app->state.right, 150);
406    e_widget_on_change_hook_set(ui->right, _cb_changed_right, app);
407
408    ui->mute = e_widget_check_add(evas, _("Mute"), &app->state.mute);
409    e_widget_on_change_hook_set(ui->mute, _cb_changed_mute, app);
410
411    ui->lock_sliders = e_widget_check_add(evas, _("Lock Sliders"),
412                                          &app->lock_sliders);
413    e_widget_on_change_hook_set(ui->lock_sliders, _cb_changed_lock_sliders, app);
414
415    ui->frame = e_widget_framelist_add(evas, _("Edit"), 0);
416    e_widget_framelist_object_append(ui->frame, ui->label_card);
417    e_widget_framelist_object_append(ui->frame, ui->card);
418    e_widget_framelist_object_append(ui->frame, ui->label_channel);
419    e_widget_framelist_object_append(ui->frame, ui->channel);
420    e_widget_framelist_object_append(ui->frame, ui->label_type);
421    e_widget_framelist_object_append(ui->frame, ui->type);
422    e_widget_framelist_object_append(ui->frame, ui->label_left);
423    e_widget_framelist_object_append(ui->frame, ui->left);
424    e_widget_framelist_object_append(ui->frame, ui->label_right);
425    e_widget_framelist_object_append(ui->frame, ui->right);
426    e_widget_framelist_object_append(ui->frame, ui->mute);
427    e_widget_framelist_object_append(ui->frame, ui->lock_sliders);
428
429    e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 1, 0.5);
430 }
431
432 static void
433 _create_ui(E_Dialog *dialog, E_Mixer_App_Dialog_Data *app)
434 {
435    struct e_mixer_app_ui *ui = &app->ui;
436    Evas *evas;
437    int mw, mh;
438
439    evas = e_win_evas_get(dialog->win);
440
441    ui->hlayout = e_widget_list_add(evas, 0, 1);
442    _create_cards(dialog, evas, app);
443    _create_channels(dialog, evas, app);
444    _create_channel_editor(dialog, evas, app);
445
446    if (ui->cards.list)
447      e_widget_ilist_selected_set(ui->cards.list, 0);
448    else
449      select_card(app);
450    e_widget_ilist_selected_set(ui->channels.list, 1);
451
452    e_widget_size_min_get(ui->hlayout, &mw, &mh);
453    if (mw < 300)
454      mw = 300;
455    if (mh < 200)
456      mh = 200;
457    e_dialog_content_set(dialog, ui->hlayout, mw, mh);
458 }
459
460 static void
461 _mixer_app_dialog_del(E_Dialog *dialog, E_Mixer_App_Dialog_Data *app)
462 {
463    if (app->del.func)
464      app->del.func(dialog, app->del.data);
465
466    eina_stringshare_del(app->card);
467    eina_stringshare_del(app->channel_name);
468    if (app->cards)
469      e_mod_mixer_cards_free(app->cards);
470    if (app->channels_infos)
471      _channels_info_free(app->channels_infos);
472    e_mod_mixer_del(app->sys);
473
474    e_util_defer_object_del(E_OBJECT(dialog));
475    dialog->data = NULL;
476    E_FREE(app);
477 }
478
479 static void
480 _cb_win_del(E_Win *win)
481 {
482    E_Dialog *dialog = win->data;
483    E_Mixer_App_Dialog_Data *app = dialog->data;
484    _mixer_app_dialog_del(dialog, app);
485 }
486
487 static void
488 _cb_dialog_dismiss(void *data, E_Dialog *dialog)
489 {
490    _mixer_app_dialog_del(dialog, data);
491 }
492
493 E_Dialog *
494 e_mixer_app_dialog_new(E_Container *con, void (*func)(E_Dialog *dialog, void *data), void *data)
495 {
496    E_Mixer_App_Dialog_Data *app;
497    E_Dialog *dialog;
498
499    dialog = e_dialog_new(con, _e_mixer_Name, "e_mixer_app_dialog");
500    if (!dialog)
501      return NULL;
502
503    app = E_NEW(E_Mixer_App_Dialog_Data, 1);
504    if (!app)
505      {
506         e_object_del(E_OBJECT(dialog));
507         return NULL;
508      }
509
510    dialog->data = app;
511    app->del.data = data;
512    app->del.func = func;
513
514    e_dialog_title_set(dialog, _(_e_mixer_Name));
515    e_dialog_resizable_set(dialog, 1);
516
517    e_win_delete_callback_set(dialog->win, _cb_win_del);
518
519    _create_ui(dialog, app);
520
521    e_dialog_button_add(dialog, _("Close"), NULL, _cb_dialog_dismiss, app);
522    e_dialog_button_focus_num(dialog, 1);
523    e_win_centered_set(dialog->win, 1);
524    e_dialog_show(dialog);
525    e_dialog_border_icon_set(dialog, "preferences-desktop-mixer");
526
527    // FIXME: what if module unloaded while mixer_app dialog up? bad!
528
529    return dialog;
530 }
531
532 static inline int
533 _find_card_by_name(E_Mixer_App_Dialog_Data *app, const char *card_name)
534 {
535    Eina_List *l;
536    int i;
537
538    if (!card_name)
539      return 0;
540    
541    for (i = 0, l = app->cards; l; i++, l = l->next)
542      if (strcmp(card_name, l->data) == 0)
543        return i;
544
545    return -1;
546 }
547
548 static inline int
549 _find_channel_by_name(E_Mixer_App_Dialog_Data *app, const char *channel_name)
550 {
551    struct channel_info *info;
552    Eina_List *l;
553    int i = 0;
554    int header_input;
555
556    if (!channel_name)
557      return 0;
558    
559    if (app->channels_infos)
560      {
561         info = app->channels_infos->data;
562
563         header_input = !!info->has_capture;
564         i = 1;
565      }
566
567    EINA_LIST_FOREACH(app->channels_infos, l, info)
568      {
569         if ((!header_input) && info->has_capture)
570           {
571              header_input = 1;
572              i++;
573           }
574
575         if (strcmp(channel_name, info->name) == 0)
576           return i;
577
578         ++i;
579      }
580
581    return -1;
582 }
583
584 int
585 e_mixer_app_dialog_select(E_Dialog *dialog, const char *card_name, const char *channel_name)
586 {
587    E_Mixer_App_Dialog_Data *app;
588    int n;
589
590    if (!dialog)
591      return 0;
592    
593    if ((!card_name) || (!channel_name))
594      return 0;
595
596    app = dialog->data;
597    if (!app)
598      return 0;
599
600    n = _find_card_by_name(app, card_name);
601    if (n < 0)
602      return 0;
603    if (app->ui.cards.list)
604      e_widget_ilist_selected_set(app->ui.cards.list, n);
605
606    n = _find_channel_by_name(app, channel_name);
607    if (n < 0)
608      return 0;
609    e_widget_ilist_selected_set(app->ui.channels.list, n);
610
611    return 1;
612 }
613