/* * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "i18n.h" #include "bar.h" #include "engine.h" #include "defs.h" #include "dbg.h" #define STYLE_TITLE "title" #define STYLE_VIDEO "video" #define STYLE_AUDIO "audio" #define STYLE_ALBUM "album" #define STYLE_COMMON "common" #define DEFAULT_TITLE "No Information" #define UNKNOWN_DEVICE "Unknown device" #define MESSAGE_DELETE "Are you sure you want to delete the" #define MESSAGE_HISTORY_BANNER "Your history has been cleared" #define KEY_DBAR_ITEM "dbar.item" #define ICON_PIN "pin" #define ICON_LOCK "lock" #define ASPECT_RATIO ((double)198 / (double)(166)) #define LABEL_BUFMAX 512 #define DBAR_PADDING 10 #define FUNCS_PADDING 3 #define BUF_DELIMITER 2 #define BUF_STRING 128 #define IMG_FUNCS_FAVORITE IMAGEDIR"/ico_favorite_channel_nor.png" #define IMG_FUNCS_PIN IMAGEDIR"/ico_pin_channel_nor.png" #define IMG_FUNCS_LOCK IMAGEDIR"/ico_locked_channel_nor.png" enum _dbar_state { DBAR_STATE_HIDE, DBAR_STATE_DBAR, DBAR_STATE_XBAR }; struct _dbar_item; struct _dbar_data { Evas_Object *base; Evas_Object *ly; Evas_Object *scr; Evas_Object *tbl; Eina_List *list; struct _dbar_item *cur; struct bar_cb focus_cb; int tbl_idx; int content_column; enum _dbar_state state; }; struct _dbar_item { Evas_Object *eo; struct engine_dbar_item *it; struct _dbar_data *bar; struct bar_info *xbar; Eina_Bool focus; }; struct _dbar_item_loader { enum engine_dbar_item_style style; Evas_Object *(*loader)(Evas_Object *p, struct engine_dbar_item *it, Eina_Bool *fill); }; static void _bring_in_middle(Evas_Object *scr, Evas_Object *obj) { Evas_Coord y, h, sy, sh, rx, ry, rw, rh, my, smy, ch; if (!scr || !obj) return; evas_object_geometry_get(obj, NULL, &y, NULL, &h); evas_object_geometry_get(scr, NULL, &sy, NULL, &sh); elm_scroller_region_get(scr, &rx, &ry, &rw, &rh); elm_scroller_child_size_get(scr, NULL, &ch); my = y + (h >> 1); smy = sy + (sh >> 1); ry = ry - smy + my; if (ry < 0) ry = 0; else if (ry + rh > ch) ry = ch - rh; elm_scroller_region_bring_in(scr, rx, ry, rw, rh); } static void _focused(void *data, Evas_Object *obj, void *ei) { struct _dbar_item *foc; struct _dbar_data *bar; Eina_Bool r; Evas_Object *eo; if (!data) return; foc = data; bar = foc->bar; if (!foc->xbar) { r = bar->focus_cb.func(bar->focus_cb.data, foc->eo); if (r) _bring_in_middle(bar->scr, foc->eo); bar->cur = foc; bar->state = DBAR_STATE_DBAR; return; } switch (bar->state) { case DBAR_STATE_XBAR: eo = bar->cur->xbar->ops->get_object(bar->cur->xbar); if (eo) elm_object_signal_emit(eo, SIG_UNFOCUS_TO_DBAR, SRC_PROG); elm_object_signal_emit(foc->eo, SIG_UNFOCUS_FROM_XBAR, SRC_PROG); if (foc != bar->cur) { elm_object_signal_emit(bar->cur->eo, SIG_HIDE, SRC_PROG); bar->cur->xbar->ops->hide(bar->cur->xbar); foc->xbar->ops->update(foc->xbar, foc->it, foc->eo); foc->xbar->ops->show(foc->xbar); } break; case DBAR_STATE_HIDE: eo = foc->xbar->ops->get_object(foc->xbar); if (eo) elm_object_signal_emit(eo, SIG_SHOW, SRC_PROG); r = bar->focus_cb.func(bar->focus_cb.data, foc->eo); if (r) _bring_in_middle(bar->scr, foc->eo); foc->xbar->ops->update(foc->xbar, foc->it, foc->eo); break; case DBAR_STATE_DBAR: eo = foc->xbar->ops->get_object(foc->xbar); if (eo) elm_object_signal_emit(eo, SIG_SHOW, SRC_PROG); r = bar->focus_cb.func(bar->focus_cb.data, foc->eo); if (r) _bring_in_middle(bar->scr, foc->eo); if (foc != bar->cur && bar->cur->xbar) bar->cur->xbar->ops->hide(bar->cur->xbar); foc->xbar->ops->update(foc->xbar, foc->it, foc->eo); break; default: return; } bar->cur = foc; bar->state = DBAR_STATE_DBAR; } static void _mouse_over(void *data, Evas *e, Evas_Object *obj, void *ei) { struct _dbar_item *item; if (!data) { _ERR("Invalide argument"); return; } item = data; if (elm_object_focus_get(item->eo)) return; elm_object_focus_set(item->eo, EINA_TRUE); } static void _clicked(void *data, Evas *e, Evas_Object *obj, void *ei) { struct _dbar_item *item; Evas_Event_Mouse_Up *ev; Evas_Coord x, y, w, h; if (!data || !ei) return; ev = ei; evas_object_geometry_get(obj, &x, &y, &w, &h); if (ev->canvas.x < x || ev->canvas.x > x + w || ev->canvas.y < y || ev->canvas.y > y + h) return; item = data; engine_dbar_item_launch(item->it); } static int _launch_app(struct bar_info *info) { struct _dbar_data *bar; struct _dbar_item *item; if (!info) return EINA_FALSE; bar = info->data; item = bar->cur; if (!item) { _ERR("Invalid argument"); return -1; } return engine_dbar_item_launch(item->it); } static inline Evas_Object *_load_bg(Evas_Object *base, struct engine_dbar_item *it) { Evas_Object *bg; int r, g, b; if (!base || !it) return NULL; bg = evas_object_rectangle_add(evas_object_evas_get(base)); if (!bg) { _ERR("bg add failed"); return NULL; } r = 128; g = 128; b = 128; engine_dbar_item_get_color(it, &r, &g, &b); evas_object_color_set(bg, r, g, b, 255); return bg; } static Evas_Object *_load_title(Evas_Object *p, struct engine_dbar_item *it, Eina_Bool *fill) { Evas_Object *ly; const char *name; if (!p || !it) return NULL; name = engine_dbar_item_get_name(it); if (!name) name = ""; ly = elm_layout_add(p); if (!ly) { _ERR("layout add failed"); return NULL; } elm_layout_file_set(ly, EDJEFILE, GRP_DBAR_LABEL); elm_object_part_text_set(ly, PART_TITLE, engine_dbar_item_get_name(it)); if (fill) *fill = EINA_TRUE; return ly; } static Evas_Object *_load_ly(Evas_Object *p, struct engine_dbar_item *it, const char *group) { Evas_Object *ly; Evas_Object *bg; if (!p || !it || !group) return NULL; ly = elm_layout_add(p); if (!ly) { _ERR("layout add failed"); return NULL; } elm_layout_file_set(ly, EDJEFILE, group); bg = _load_bg(ly, it); if (!bg) { evas_object_del(ly); return NULL; } elm_object_part_content_set(ly, PART_BG, bg); return ly; } static const char *_trim(char *str) { int i; if (!str) return str; i = strlen(str); i--; while (i > 0) { if (isspace(str[i])) str[i] = '\0'; else break; i++; } return str; } static void _put_icon(Evas_Object *ly, const char *file, const char *part, const char *def_sig, const char *def_src, Eina_Bool make_thumbnail) { Evas_Object *ic; if (file && strlen(file) > 0) { ic = elm_icon_add(ly); if (ic) { if (make_thumbnail) { elm_need_ethumb(); elm_icon_thumb_set(ic, file, NULL); } else { elm_image_file_set(ic, file, NULL); } elm_image_fill_outside_set(ic, EINA_TRUE); elm_object_part_content_set(ly, part, ic); return; } _ERR("icon add failed"); } elm_object_signal_emit(ly, def_sig, def_src); } static void _lbl_start_slide(void *data, Evas_Object *obj, void *ei) { elm_label_ellipsis_set(data, EINA_FALSE); elm_label_slide_mode_set(data, ELM_LABEL_SLIDE_MODE_AUTO); elm_label_slide_go(data); } static void _lbl_stop_slide(void *data, Evas_Object *obj, void *ei) { elm_label_ellipsis_set(data, EINA_TRUE); elm_label_slide_mode_set(data, ELM_LABEL_SLIDE_MODE_NONE); elm_label_slide_go(data); } static Evas_Object *_add_icon(Evas_Object *box, const char *file) { Evas_Object *ic; if (!box || !file) { _ERR("Invalid argument"); return NULL; } ic = elm_icon_add(box); if (!ic) { _ERR("icon add failed"); return NULL; } elm_image_file_set(ic, file, NULL); elm_image_no_scale_set(ic, EINA_TRUE); evas_object_show(ic); elm_box_pack_end(box, ic); return ic; } static void _load_funcs(const char *icon, Evas_Object *p) { Evas_Object *box, *ic; int padding; char delimiter[BUF_DELIMITER] = ","; char *iter; char str[BUF_STRING]; bool lock, pin; if (!icon || !p) { _ERR("Invalid argument"); return; } padding = elm_config_scale_get() * FUNCS_PADDING; box = elm_box_add(p); if (!box) { _ERR("box add failed"); return; } elm_object_part_content_set(p, PART_FUNCS, box); elm_box_padding_set(box, padding, padding); elm_box_horizontal_set(box, EINA_TRUE); strcpy(str, icon); iter = NULL; lock = false; pin = false; iter = strtok(str, delimiter); while (iter) { if (!strcmp(iter, ICON_PIN)) pin = true; else if (!strcmp(iter, ICON_LOCK)) lock = true; iter = strtok(NULL, delimiter); } if (pin) { ic = _add_icon(box, IMG_FUNCS_PIN); if (!ic) { _ERR("icon add failed"); evas_object_del(box); return; } } if (lock) { ic = _add_icon(box, IMG_FUNCS_LOCK); if (!ic) { _ERR("icon add failed"); evas_object_del(box); return; } } } static Evas_Object *_add_label(Evas_Object *ly, const char *style, const char *name) { Evas_Object *lbl; if (!ly || !style || !name) { _ERR("Invalid argument"); return NULL; } lbl = elm_label_add(ly); if (!lbl) { _ERR("failed to create label"); return NULL; } elm_object_style_set(lbl, style); elm_object_text_set(lbl, name); evas_object_show(lbl); return lbl; } static Evas_Object *_add_slide_label(Evas_Object *ly, const char *name, const char *style) { Evas_Object *lbl; const char *s; if (!ly || !name || !style) { _ERR("Invalid argument"); return NULL; } lbl = _add_label(ly, style, name); if (!lbl) { evas_object_del(ly); return NULL; } elm_label_ellipsis_set(lbl, EINA_TRUE); s = edje_object_data_get(elm_layout_edje_get(ly), DATA_TITLE_WIDTH); if (s) elm_label_wrap_width_set(lbl, atoi(s)); else _ERR("No title width exist"); elm_label_slide_speed_set(lbl, LABEL_SLIDE_SPEED); evas_object_smart_callback_add(ly, "focused", _lbl_start_slide, lbl); evas_object_smart_callback_add(ly, "unfocused", _lbl_stop_slide, lbl); return lbl; } static Evas_Object *_load_content_broadcast(Evas_Object *p, const char *style, struct engine_dbar_item_content *ctnt, struct engine_dbar_item *it) { Evas_Object *ly, *lbl; const char *channel, *progname, *progtime, *icon; if (!p || !style || !ctnt || !it) { _ERR("Invalid argument"); return NULL; } ly = _load_ly(p, it, style); if (!ly) return NULL; channel = engine_dbar_item_get_content_subtitle(ctnt); _trim((char *)channel); progname = engine_dbar_item_get_content_description(ctnt); _trim((char *)progname); progtime = engine_dbar_item_get_content_detail(ctnt); _trim((char *)progtime); icon = engine_dbar_item_get_content_icon(ctnt); if (icon && strlen(icon) != 0) _load_funcs(_trim((char *)icon), ly); lbl = _add_label(ly, STYLE_LABEL_SLIDE_CENTER_40, _trim((char *)engine_dbar_item_get_name(it))); if (!lbl) goto err; elm_object_part_content_set(ly, PART_NUMBER, lbl); if (!progname || strlen(progname) <= 0) { if (!channel || strlen(channel) <= 0) channel = _(DEFAULT_TITLE); lbl = _add_slide_label(ly, channel, STYLE_LABEL_SLIDE_LEFT_32); if (!lbl) goto err; elm_object_part_content_set(ly, PART_PROGRAM, lbl); return ly; } lbl = _add_slide_label(ly, progname, STYLE_LABEL_SLIDE_LEFT_32); if (!lbl) goto err; elm_object_part_content_set(ly, PART_PROGRAM, lbl); lbl = _add_label(ly, STYLE_LABEL_SLIDE_LEFT_20, channel); if (!lbl) goto err; elm_object_part_content_set(ly, PART_CHANNEL, lbl); lbl = _add_label(ly, STYLE_LABEL_SLIDE_LEFT_20, progtime); if (!lbl) goto err; elm_object_part_content_set(ly, PART_DURATION, lbl); return ly; err: _ERR("failed to create label"); evas_object_del(ly); return NULL; } static Evas_Object *_load_content_history(Evas_Object *p, const char *style, struct engine_dbar_item_content *ctnt, struct engine_dbar_item *it) { Evas_Object *ly; const char *name; Evas_Object *bg; ly = _load_ly(p, it, style); if (!ly) return NULL; bg = _load_bg(ly, it); if (!bg) { evas_object_del(ly); return NULL; } elm_object_part_content_set(ly, PART_BG2, bg); name = engine_dbar_item_get_name(it); _trim((char *)name); if (!name || strlen(name) <= 0) name = _(DEFAULT_TITLE); _put_icon(ly, engine_dbar_item_get_content_icon(ctnt), PART_ICON, SIG_SHOW_DEFAULT_ICON, SRC_PROG, EINA_FALSE); elm_object_part_text_set(ly, PART_TITLE, name); return ly; } static Evas_Object *_load_content_common(Evas_Object *p, const char *style, struct engine_dbar_item_content *ctnt, struct engine_dbar_item *it) { Evas_Object *ly; const char *name; ly = _load_ly(p, it, style); if (!ly) return NULL; name = engine_dbar_item_get_name(it); _trim((char *)name); if (!name || strlen(name) <= 0) name = _(DEFAULT_TITLE); _put_icon(ly, engine_dbar_item_get_content_thumbnail(ctnt), PART_THUMB, SIG_SHOW_DEFAULT_THUMB, SRC_PROG, EINA_FALSE); _put_icon(ly, engine_dbar_item_get_content_icon(ctnt), PART_ICON, SIG_SHOW_DEFAULT_ICON, SRC_PROG, EINA_FALSE); elm_object_part_text_set(ly, PART_TITLE, name); elm_object_part_text_set(ly, PART_SUBTITLE, _trim((char *) engine_dbar_item_get_content_subtitle(ctnt))); return ly; } static Evas_Object *_load_content_music(Evas_Object *p, const char *style, struct engine_dbar_item_content *ctnt, struct engine_dbar_item *it) { Evas_Object *ly; Evas_Object *lbl; const char *name; ly = _load_ly(p, it, style); if (!ly) return NULL; name = engine_dbar_item_get_name(it); _trim((char *)name); if (!name || strlen(name) <= 0) name = _(DEFAULT_TITLE); _put_icon(ly, engine_dbar_item_get_content_thumbnail(ctnt), PART_THUMB, SIG_SHOW_DEFAULT_THUMB, SRC_PROG, EINA_TRUE); _put_icon(ly, engine_dbar_item_get_content_icon(ctnt), PART_ICON, SIG_SHOW_DEFAULT_ICON, SRC_PROG, EINA_FALSE); lbl = _add_slide_label(ly, name, STYLE_LABEL_SLIDE_LEFT); if (!lbl) { evas_object_del(ly); return NULL; } elm_object_part_content_set(ly, PART_TITLE, lbl); elm_object_part_text_set(ly, PART_SUBTITLE, _trim((char *) engine_dbar_item_get_content_subtitle(ctnt))); return ly; } static Evas_Object *_load_content_source(Evas_Object *p, const char *style, struct engine_dbar_item_content *ctnt, struct engine_dbar_item *it) { Evas_Object *ly; const char *name; ly = _load_ly(p, it, style); if (!ly) return NULL; _put_icon(ly, engine_dbar_item_get_content_thumbnail(ctnt), PART_THUMB, SIG_SHOW_DEFAULT_THUMB, SRC_PROG, EINA_FALSE); name = engine_dbar_item_get_name(it); _trim((char *)name); if (!name || strlen(name) <= 0) name = _(UNKNOWN_DEVICE); elm_object_part_text_set(ly, PART_TITLE, name); elm_object_part_text_set(ly, PART_SUBTITLE, _trim((char *) engine_dbar_item_get_content_subtitle(ctnt))); return ly; } static Evas_Object *_load_content_notification(Evas_Object *p, const char *style, struct engine_dbar_item_content *ctnt, struct engine_dbar_item *it) { Evas_Object *ly; const char *title, *subtitle, *icon, *description; Evas_Object *bg; icon = engine_dbar_item_get_content_icon(ctnt); title = engine_dbar_item_get_name(it); subtitle = engine_dbar_item_get_content_subtitle(ctnt); description = engine_dbar_item_get_content_description(ctnt); ly = _load_ly(p, it, GRP_DBAR_NOTIFICATION); if (!ly) return NULL; bg = _load_bg(ly, it); if (!bg) { evas_object_del(ly); return NULL; } elm_object_part_content_set(ly, PART_BG2, bg); if (title) elm_object_part_text_set(ly, PART_TITLE, title); if (subtitle) elm_object_part_text_set(ly, PART_SUBTITLE, subtitle); if (description) elm_object_part_text_set(ly, PART_DESCRIPTION, description); if (icon) _put_icon(ly, icon, PART_THUMB, SIG_SHOW_DEFAULT_THUMB, SRC_PROG, EINA_FALSE); elm_object_focus_allow_set(ly, EINA_TRUE); return ly; } static Evas_Object *_load_content(Evas_Object *p, struct engine_dbar_item *it, Eina_Bool *fill) { struct engine_dbar_item_content *ctnt; const Eina_List *ctnts; Evas_Object *eo; ctnts = engine_dbar_item_get_contents(it); if (!ctnts) return NULL; ctnt = eina_list_data_get(ctnts); if (!ctnt) return NULL; eo = NULL; switch (engine_dbar_item_get_content_type(ctnt)) { case ENGINE_DBAR_CONTENT_TYPE_IMAGE: case ENGINE_DBAR_CONTENT_TYPE_VIDEO: eo = _load_content_common(p, GRP_DBAR_COMMON, ctnt, it); if (eo && fill) *fill = EINA_TRUE; break; case ENGINE_DBAR_CONTENT_TYPE_BROADCAST: eo = _load_content_broadcast(p, GRP_DBAR_BROADCAST, ctnt, it); if (eo && fill) *fill = EINA_TRUE; break; case ENGINE_DBAR_CONTENT_TYPE_APP: eo = _load_content_common(p, GRP_DBAR_APP, ctnt, it); if (eo && fill) *fill = EINA_TRUE; break; case ENGINE_DBAR_CONTENT_TYPE_MUSIC: eo = _load_content_music(p, GRP_DBAR_MUSIC, ctnt, it); if (eo && fill) *fill = EINA_FALSE; break; case ENGINE_DBAR_CONTENT_TYPE_SOURCE: eo = _load_content_source(p, GRP_DBAR_SOURCE, ctnt, it); if (eo && fill) *fill = EINA_FALSE; break; case ENGINE_DBAR_CONTENT_TYPE_NOTIFICATION_ONGOING: case ENGINE_DBAR_CONTENT_TYPE_NOTIFICATION_NOTI: eo = _load_content_notification(p, NULL, ctnt, it); if (eo && fill) *fill = EINA_TRUE; break; case ENGINE_DBAR_CONTENT_TYPE_HISTORY: eo = _load_content_history(p, GRP_DBAR_HISTORY, ctnt, it); if (eo && fill) *fill = EINA_TRUE; break; default: eo = _load_content_common(p, GRP_DBAR_COMMON, ctnt, it); if (eo && fill) *fill = EINA_TRUE; break; } return eo; } static void _img_resized(void *data, Evas *e, Evas_Object *obj, void *ei) { Evas_Coord w, h; evas_object_geometry_get(obj, NULL, NULL, &w, &h); evas_object_image_fill_set(obj, 0, 0, w, h); } static Evas_Object *_load_album_thumb(Evas_Object *p, const Eina_List *ctnts) { Evas_Object *ly; Evas_Object *ic; Eina_List *l; int ctnt_cnt; int i; const char *thumb; const char *sig; const char * const parts[] = { PART_THUMB_1, PART_THUMB_2, PART_THUMB_3, PART_THUMB_4, PART_THUMB_5, PART_THUMB_6 }; const char * const sig_video[] = { SIG_SHOW_THUMB1_VIDEO, SIG_SHOW_THUMB2_VIDEO, SIG_SHOW_THUMB3_VIDEO, SIG_SHOW_THUMB4_VIDEO, SIG_SHOW_THUMB5_VIDEO, SIG_SHOW_THUMB6_VIDEO }; struct engine_dbar_item_content *ctnt; if (!p || !ctnts) { _ERR("Invalid argument"); return NULL; } ly = elm_layout_add(p); if (!ly) { _ERR("icon add failed"); return NULL; } elm_layout_file_set(ly, EDJEFILE, GRP_ALBUM_THUMB); ctnt_cnt = eina_list_count(ctnts); if (ctnt_cnt >= 6) { ctnt_cnt = 6; sig = SIG_THUMB_6; } else if (ctnt_cnt >= 3) { ctnt_cnt = 3; sig = SIG_THUMB_3; } else { ctnt_cnt = 1; sig = NULL; } l = (Eina_List *)ctnts; /* TODO, show default photo/video icon */ for (i = 0; i < ctnt_cnt; i++) { ctnt = eina_list_data_get(l); thumb = engine_dbar_item_get_content_thumbnail(ctnt); ic = evas_object_image_add(evas_object_evas_get(ly)); if (!ic) { evas_object_del(ly); return NULL; } evas_object_image_preload(ic, EINA_TRUE); evas_object_image_file_set(ic, thumb, NULL); evas_object_event_callback_add(ic, EVAS_CALLBACK_RESIZE, _img_resized, NULL); elm_object_part_content_set(ly, parts[i], ic); if (engine_dbar_item_get_content_type(ctnt) == ENGINE_DBAR_CONTENT_TYPE_VIDEO) elm_object_signal_emit(ly, sig_video[i], SRC_PROG); l = eina_list_next(l); if (!l) break; } if (sig) elm_object_signal_emit(ly, sig, SRC_PROG); return ly; } static Evas_Object *_load_album(Evas_Object *p, struct engine_dbar_item *it, Eina_Bool *fill) { Evas_Object *ly; Evas_Object *ly2; const char *name; ly = _load_ly(p, it, GRP_DBAR_ALBUM); if (!ly) return NULL; name = engine_dbar_item_get_name(it); if (!name) name = "No Title"; ly2 = _load_album_thumb(ly, engine_dbar_item_get_contents(it)); if (!ly2) { evas_object_del(ly); return NULL; } elm_object_part_content_set(ly, PART_THUMB, ly2); elm_object_part_text_set(ly, PART_TITLE, name); if (fill) *fill = EINA_TRUE; return ly; } Evas_Object *_item_load(Evas_Object *p, struct engine_dbar_item *it, Eina_Bool *fill, Eina_Bool *focus) { static struct _dbar_item_loader loaders[] = { { .style = ENGINE_DBAR_ITEM_STYLE_CONTENT, .loader = _load_content }, { .style = ENGINE_DBAR_ITEM_STYLE_LABEL, .loader = _load_title }, { .style = ENGINE_DBAR_ITEM_STYLE_ALBUM, .loader = _load_album }, }; Evas_Object *eo; enum engine_dbar_item_style style; int i; if (!it) { _ERR("Invalid argument"); return NULL; } style = engine_dbar_item_get_style(it); if (style >= ENGINE_DBAR_ITEM_STYLE_MAX) style = ENGINE_DBAR_ITEM_STYLE_CONTENT; for (i = 0; i < sizeof(loaders) / sizeof(*loaders); i++) { if (loaders[i].style == style) { eo = loaders[i].loader(p, it, fill); if (!eo) return NULL; if (style == ENGINE_DBAR_ITEM_STYLE_LABEL) *focus = EINA_FALSE; else *focus = EINA_TRUE; return eo; } } _ERR("cannot find style: %d", style); return NULL; } static int _add_bar(struct bar_info *info, Evas_Object *base) { Evas_Object *ly, *scr, *tbl, *bx; struct _dbar_data *bar; int padding; if (!base || !info || !info->data) { _ERR("Invalid argument"); return -1; } bar = info->data; padding = elm_config_scale_get() * DBAR_PADDING; ly = elm_layout_add(base); if (!ly) { _ERR("layout add failed"); return -1; } elm_layout_file_set(ly, EDJEFILE, GRP_DBAR_ITEM); scr = elm_scroller_add(ly); if (!scr) { _ERR("scroller add failed"); evas_object_del(ly); return -1; } elm_scroller_policy_set(scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF); bx = elm_box_add(scr); if (!bx) { _ERR("box add failed"); evas_object_del(ly); return -1; } tbl = elm_table_add(bx); if (!tbl) { _ERR("table add failed"); evas_object_del(ly); return -1; } evas_object_size_hint_align_set(tbl, 0.5, 0.0); evas_object_size_hint_weight_set(tbl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_table_homogeneous_set(tbl, EINA_FALSE); elm_table_padding_set(tbl, padding, padding); evas_object_show(tbl); evas_object_show(bx); elm_box_pack_end(bx, tbl); elm_object_content_set(scr, bx); elm_object_part_content_set(ly, PART_CONTENT, scr); bar->base = base; bar->ly = ly; bar->scr = scr; bar->tbl = tbl; return 0; } static inline int _get_dbar_row_col(struct _dbar_data *bar, Eina_Bool fill, int *row, int *col) { int r; if (!bar || !row || !col || bar->content_column <= 0) return -1; *row = bar->tbl_idx / bar->content_column; *col = bar->tbl_idx % bar->content_column; if (!fill) return 1; if (bar->content_column > 1 && *col > 0) { *col = 0; *row = *row + 1; } r = bar->content_column - *col; return r; } static Eina_Bool _xbar_focused(void *data, Evas_Object *foc) { struct _dbar_data *bar; struct _dbar_item *cur; if (!data || !foc) { _ERR("Invalid argument"); return EINA_FALSE; } bar = data; if (!bar->cur) { _ERR("There is no dbar item"); return EINA_FALSE; } cur = bar->cur; switch (bar->state) { case DBAR_STATE_DBAR: elm_object_signal_emit(foc, SIG_INITIAL_FOCUS, SRC_PROG); elm_object_signal_emit(cur->eo, SIG_UNFOCUS_TO_XBAR, SRC_PROG); break; default: return EINA_FALSE; } bar->state = DBAR_STATE_XBAR; return EINA_TRUE; } static int _init_child_bars(struct _dbar_item *item) { struct bar_info *xbar; int r; if (!item) { _ERR("Invalid argument"); return -1; } xbar = calloc(1, sizeof(*xbar)); if (!xbar) { _ERR("failed to calloc xbar"); return -1; } xbar->cb.func = _xbar_focused; xbar->cb.data = item->bar; r = init_delete_bar(xbar); if (r < 0) { free(xbar); return -1; } item->xbar = xbar; return 0; } static void _unfocused(void *data, Evas_Object *obj, const char *emission, const char *source) { struct _dbar_item *cur; struct _dbar_data *bar; if (!data) { _ERR("Invalid argument"); return; } cur = data; bar = cur->bar; bar->state = DBAR_STATE_HIDE; if (!cur->xbar) return; cur->xbar->ops->hide(cur->xbar); } static void _cancel_delete_popup(void *data, Evas_Object *obj, const char *emission, const char *source) { struct _dbar_item *cur; if (!data) { _ERR("Invalid argument"); return; } cur = data; if (cur->eo) elm_object_focus_set(cur->eo, EINA_TRUE); } static struct _dbar_item *_pack_item(struct _dbar_data *bar, struct engine_dbar_item *it) { Evas_Object *eo; struct _dbar_item *item; Eina_Bool fill; Eina_Bool focus; int row, col; int step; int r; enum engine_dbar_content_type type; struct engine_dbar_item_content *ctnt; if (!bar || !it) return NULL; item = calloc(1, sizeof(*item)); if (!item) { _ERR("Calloc failed"); return NULL; } fill = EINA_FALSE; focus = EINA_FALSE; eo = _item_load(bar->tbl, it, &fill, &focus); if (!eo) { free(item); return NULL; } step = _get_dbar_row_col(bar, fill, &row, &col); if (step <= 0) { evas_object_del(eo); free(item); return NULL; } evas_object_size_hint_align_set(eo, EVAS_HINT_FILL, 0.0); elm_table_pack(bar->tbl, eo, col, row, fill ? bar->content_column : 1, 1); evas_object_show(eo); bar->tbl_idx += step; bar->state = DBAR_STATE_HIDE; item->eo = eo; item->it = it; item->bar = bar; item->focus = focus; evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_MOVE, _mouse_over, item); evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_UP, _clicked, item); evas_object_smart_callback_add(eo, "focused", _focused, item); elm_object_signal_callback_add(eo, SIG_UNFOCUS_TO_HBAR, SRC_PROG, _unfocused, item); ctnt = eina_list_data_get(engine_dbar_item_get_contents(it)); if (!ctnt) { _ERR("failed to get ci"); return item; } type = engine_dbar_item_get_content_type(ctnt); if ((type == ENGINE_DBAR_CONTENT_TYPE_NOTIFICATION_NOTI || type == ENGINE_DBAR_CONTENT_TYPE_HISTORY) && item->focus) { r = _init_child_bars(item); if (r < 0) { free(item->xbar); item->xbar = NULL; } r = item->xbar->ops->add_bar(item->xbar, bar->base); if (r < 0) { item->xbar->ops->release(item->xbar); free(item->xbar); item->xbar = NULL; } eo = item->xbar->ops->get_object(item->xbar); if (eo) elm_object_signal_callback_add(eo, SIG_CANCEL_CLICKED, SRC_PROG, _cancel_delete_popup, item); } return item; } static int _update(struct bar_info *info, void *eng, void *data) { struct _dbar_data *bar; const Eina_List *list; Eina_List *l; struct engine_dbar_item *it; struct _dbar_item *item; const char *noctnt_title; const char *noctnt_desc; int cnt; if (!info || !info->data) { _ERR("Invalid argument"); return -1; } bar = info->data; elm_table_clear(bar->tbl, EINA_TRUE); bar->tbl_idx = 0; EINA_LIST_FREE(bar->list, item) { if (item->xbar) item->xbar->ops->release(item->xbar); evas_object_del(item->eo); free(item); } bar->cur = NULL; bar->list = NULL; engine_bar_item_get_content_column(eng, &bar->content_column); cnt = 0; list = engine_get_dbar_items(eng); if (!list) { noctnt_title = engine_bar_item_get_noctnt_title(eng); noctnt_desc = engine_bar_item_get_noctnt_desc(eng); elm_object_part_text_set(bar->ly, PART_DEFAULT_TITLE, noctnt_title ? noctnt_title : ""); elm_object_part_text_set(bar->ly, PART_DEFAULT_DESC, noctnt_desc ? noctnt_desc : ""); return cnt; } elm_object_part_text_set(bar->ly, PART_DEFAULT_TITLE, ""); elm_object_part_text_set(bar->ly, PART_DEFAULT_DESC, ""); EINA_LIST_FOREACH((Eina_List *)list, l, it) { item = _pack_item(bar, it); if (!item) continue; bar->list = eina_list_append(bar->list, item); cnt++; } return cnt; } static Evas_Object *_get_object(struct bar_info *info) { struct _dbar_data *bar; if (!info || !info->data) { _ERR("Invalid argument"); return NULL; } bar = info->data; return bar->ly; } static Evas_Object *_get_item(struct bar_info *info) { struct _dbar_data *bar; struct _dbar_item *item; Eina_List *l; if (!info || !info->data) { _ERR("Invalid argument"); return NULL; } bar = info->data; if (bar->cur) return bar->cur->eo; EINA_LIST_FOREACH(bar->list, l, item) { if (elm_object_focus_allow_get(item->eo)) { bar->cur = item; return bar->cur->eo; } } return NULL; } static void _show(struct bar_info *info) { struct _dbar_data *bar; struct _dbar_item *item; Eina_List *l; if (!info || !info->data) { _ERR("Invalid argument"); return; } bar = info->data; EINA_LIST_FOREACH(bar->list, l, item) { if (item->focus) elm_object_focus_allow_set(item->eo, EINA_TRUE); } elm_object_signal_emit(bar->ly, SIG_SHOW, SRC_PROG); } static void _hide(struct bar_info *info) { struct _dbar_data *bar; struct _dbar_item *item; Eina_List *l; if (!info || !info->data) { _ERR("Invalid argument"); return; } bar = info->data; EINA_LIST_FOREACH(bar->list, l, item) { elm_object_signal_emit(item->eo, SIG_HIDE, SRC_PROG); elm_object_focus_allow_set(item->eo, EINA_FALSE); if (item->xbar) item->xbar->ops->hide(item->xbar); } elm_object_signal_emit(bar->ly, SIG_HIDE, SRC_PROG); } static Eina_Bool _is_move(struct bar_info *info, int dir) { struct _dbar_data *bar; struct _dbar_item *item; struct _dbar_item *_item; Eina_List *l; int x; if (!info || !info->data) { _ERR("Invalid argument"); return EINA_FALSE; } bar = info->data; item = bar->cur; if (!item) return EINA_FALSE; if (bar->content_column == 1) return EINA_TRUE; elm_table_pack_get(item->eo, &x, NULL, NULL, NULL); switch (dir) { case BAR_DIR_LEFT: if (x > 0) return EINA_FALSE; break; case BAR_DIR_RIGHT: if (x > 0) return EINA_TRUE; l = eina_list_last(bar->list); _item = eina_list_data_get(l); if (item->eo != _item->eo) return EINA_FALSE; break; default: return EINA_FALSE; } return EINA_TRUE; } static Eina_Bool _move(struct bar_info *info) { struct _dbar_data *bar; struct _dbar_item *item; Eina_List *l; if (!info || !info->data) { _ERR("Invalid argument"); return EINA_FALSE; } bar = info->data; item = bar->cur; if (!item) { EINA_LIST_FOREACH(bar->list, l, item) { if (elm_object_focus_allow_get(item->eo)) break; } if (!item) return EINA_FALSE; } elm_object_focus_set(item->eo, EINA_TRUE); return EINA_TRUE; } static enum bar_event _enter(struct bar_info *info) { Eina_Bool r; struct _dbar_data *bar; if (!info) { _ERR("Invalid argument"); return BAR_EVENT_ERROR; } bar = info->data; r = EINA_FALSE; switch (bar->state) { case DBAR_STATE_DBAR: r = _launch_app(info); break; default: return BAR_EVENT_DONE; } return r ? BAR_EVENT_DONE : BAR_EVENT_PASS; } static enum bar_event _move_right(struct bar_info *info) { Eina_Bool r; struct _dbar_data *bar; if (!info) { _ERR("Invalid argument"); return BAR_EVENT_ERROR; } bar = info->data; r = EINA_FALSE; switch (bar->state) { case DBAR_STATE_DBAR: if (_is_move(info, BAR_DIR_RIGHT)) { if (bar->cur->xbar) r = bar->cur->xbar->ops->move(bar->cur->xbar); } break; default: return BAR_EVENT_ERROR; } return r ? BAR_EVENT_DONE : BAR_EVENT_PASS; } static enum bar_event _move_left(struct bar_info *info) { struct _dbar_data *bar; if (!info) { _ERR("Invalid argument"); return BAR_EVENT_ERROR; } bar = info->data; switch (bar->state) { case DBAR_STATE_XBAR: break; case DBAR_STATE_DBAR: if (_is_move(info, BAR_DIR_LEFT)) { if (bar->cur->xbar) { bar->cur->xbar->ops->hide(bar->cur->xbar); bar->state = DBAR_STATE_HIDE; } return BAR_EVENT_MOVE; } break; default: return BAR_EVENT_ERROR; } return BAR_EVENT_PASS; } static enum bar_event _key_event(struct bar_info *info, void *ei) { Ecore_Event_Key *ev; enum bar_event r; if (!info || !ei) return BAR_EVENT_ERROR; ev = ei; if (!strcmp(ev->keyname, KEY_ENTER)) r = _enter(info); else if (!strcmp(ev->keyname, KEY_RIGHT)) r = _move_right(info); else if (!strcmp(ev->keyname, KEY_LEFT) || !strcmp(ev->keyname, KEY_BACK)) r = _move_left(info); else r = BAR_EVENT_PASS; return r; } static enum bar_event _bar_event(struct bar_info *info, void *ei, enum bar_event ev) { struct _dbar_data *bar; enum bar_event r; if (!info || !ei) return BAR_EVENT_ERROR; bar = info->data; switch (ev) { case BAR_EVENT_DONE: case BAR_EVENT_ERROR: return ev; case BAR_EVENT_PASS: r = _key_event(info, ei); break; case BAR_EVENT_MOVE: if (bar->state == DBAR_STATE_XBAR) _move(info); r = BAR_EVENT_DONE; break; default: r = BAR_EVENT_PASS; break; } return r; } static enum bar_event _key_down(struct bar_info *info, void *ei) { struct _dbar_data *bar; struct _dbar_item *item; enum bar_event r; if (!info || !ei) return BAR_EVENT_ERROR; bar = info->data; item = bar->cur; if (!item) return BAR_EVENT_ERROR; r = BAR_EVENT_PASS; switch (bar->state) { case DBAR_STATE_HIDE: case DBAR_STATE_DBAR: r = BAR_EVENT_PASS; break; case DBAR_STATE_XBAR: if (!bar->cur->xbar) break; r = bar->cur->xbar->ops->key_down(bar->cur->xbar, ei); break; default: return BAR_EVENT_ERROR; } return _bar_event(info, ei, r); } static void _release(struct bar_info *info) { struct _dbar_data *bar; struct _dbar_item *item; if (!info) { _ERR("Invalid argument"); return; } bar = info->data; _hide(info); if (bar) { EINA_LIST_FREE(bar->list, item) { if (item->xbar) item->xbar->ops->release(item->xbar); evas_object_del(item->eo); free(item); } evas_object_del(bar->ly); free(bar); bar = NULL; } free(info); info = NULL; } static struct bar_ops dbar_ops = { .add_bar = _add_bar, .update = _update, .get_object = _get_object, .get_item = _get_item, .is_move = _is_move, .move = _move, .show = _show, .hide = _hide, .key_down = _key_down, .release = _release, }; int init_dynamic_bar(struct bar_info *info) { struct _dbar_data *bar; if (!info) return -1; bar = calloc(1, sizeof(*bar)); if (!bar) { _ERR("calloc failed"); return -1; } info->data = bar; info->ops = &dbar_ops; if (!info->cb.func) { _ERR("invalid callback function"); free(bar); return -1; } bar->focus_cb = info->cb; return 0; }